summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/Makefile68
-rw-r--r--usr.bin/apply/apply.12
-rw-r--r--usr.bin/apply/apply.c4
-rw-r--r--usr.bin/ar/Makefile12
-rw-r--r--usr.bin/ar/append.c4
-rw-r--r--usr.bin/ar/ar.194
-rw-r--r--usr.bin/ar/ar.1aout318
-rw-r--r--usr.bin/ar/ar.5146
-rw-r--r--usr.bin/ar/ar.c32
-rw-r--r--usr.bin/ar/archive.c20
-rw-r--r--usr.bin/ar/contents.c11
-rw-r--r--usr.bin/ar/delete.c2
-rw-r--r--usr.bin/ar/extract.c2
-rw-r--r--usr.bin/ar/misc.c15
-rw-r--r--usr.bin/ar/move.c4
-rw-r--r--usr.bin/ar/replace.c14
-rw-r--r--usr.bin/at/LEGAL29
-rw-r--r--usr.bin/at/Makefile33
-rw-r--r--usr.bin/at/Makefile.inc19
-rw-r--r--usr.bin/at/at.c773
-rw-r--r--usr.bin/at/at.h31
-rw-r--r--usr.bin/at/at.man268
-rw-r--r--usr.bin/at/panic.c80
-rw-r--r--usr.bin/at/panic.h44
-rw-r--r--usr.bin/at/parsetime.c621
-rw-r--r--usr.bin/at/parsetime.h26
-rw-r--r--usr.bin/at/perm.c123
-rw-r--r--usr.bin/at/perm.h26
-rw-r--r--usr.bin/at/privs.h111
-rw-r--r--usr.bin/banner/Makefile2
-rw-r--r--usr.bin/banner/banner.c1860
-rw-r--r--usr.bin/basename/basename.13
-rw-r--r--usr.bin/basename/basename.c2
-rw-r--r--usr.bin/biff/biff.15
-rw-r--r--usr.bin/biff/biff.c15
-rw-r--r--usr.bin/brandelf/Makefile3
-rw-r--r--usr.bin/brandelf/brandelf.184
-rw-r--r--usr.bin/brandelf/brandelf.c120
-rw-r--r--usr.bin/cal/cal.13
-rw-r--r--usr.bin/cal/cal.c30
-rw-r--r--usr.bin/calendar/Makefile13
-rw-r--r--usr.bin/calendar/calendar.1127
-rw-r--r--usr.bin/calendar/calendar.c353
-rw-r--r--usr.bin/calendar/calendar.h73
-rw-r--r--usr.bin/calendar/calendars/calendar.all16
-rw-r--r--usr.bin/calendar/calendars/calendar.birthday28
-rw-r--r--usr.bin/calendar/calendars/calendar.christian36
-rw-r--r--usr.bin/calendar/calendars/calendar.computer11
-rw-r--r--usr.bin/calendar/calendars/calendar.croatian12
-rw-r--r--usr.bin/calendar/calendars/calendar.german12
-rw-r--r--usr.bin/calendar/calendars/calendar.history39
-rw-r--r--usr.bin/calendar/calendars/calendar.holiday73
-rw-r--r--usr.bin/calendar/calendars/calendar.judaic11
-rw-r--r--usr.bin/calendar/calendars/calendar.music18
-rw-r--r--usr.bin/calendar/calendars/calendar.russian12
-rw-r--r--usr.bin/calendar/calendars/calendar.usholiday35
-rw-r--r--usr.bin/calendar/calendars/calendar.world18
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.all17
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag42
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte197
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.kirche32
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.literatur36
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.musik25
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft19
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.all17
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.feiertag42
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.geschichte197
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.kirche32
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.literatur36
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.musik25
-rw-r--r--usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.wissenschaft19
-rw-r--r--usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.all12
-rw-r--r--usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici37
-rw-r--r--usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.all12
-rw-r--r--usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.praznici37
-rw-r--r--usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all15
-rw-r--r--usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.common24
-rw-r--r--usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk16
-rw-r--r--usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox34
-rw-r--r--usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.pagan42
-rw-r--r--usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.all15
-rw-r--r--usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.common24
-rw-r--r--usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.msk16
-rw-r--r--usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.orthodox34
-rw-r--r--usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.pagan42
-rw-r--r--usr.bin/calendar/day.c487
-rw-r--r--usr.bin/calendar/io.c356
-rw-r--r--usr.bin/calendar/ostern.c124
-rw-r--r--usr.bin/calendar/paskha.c93
-rw-r--r--usr.bin/calendar/pathnames.h1
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.17
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.c17
-rw-r--r--usr.bin/chat/Example5
-rw-r--r--usr.bin/chat/Makefile8
-rw-r--r--usr.bin/chat/README169
-rw-r--r--usr.bin/chat/chat.8315
-rw-r--r--usr.bin/chat/chat.c1348
-rwxr-xr-xusr.bin/chat/connect-ppp129
-rwxr-xr-xusr.bin/chat/ppp-off5
-rwxr-xr-xusr.bin/chat/ppp-on35
-rwxr-xr-xusr.bin/chat/unlock23
-rw-r--r--usr.bin/checknr/checknr.16
-rw-r--r--usr.bin/checknr/checknr.c120
-rw-r--r--usr.bin/chflags/Makefile2
-rw-r--r--usr.bin/chflags/chflags.125
-rw-r--r--usr.bin/chflags/chflags.c4
-rw-r--r--usr.bin/chkey/Makefile14
-rw-r--r--usr.bin/chkey/chkey.121
-rw-r--r--usr.bin/chkey/chkey.c288
-rw-r--r--usr.bin/chpass/Makefile54
-rw-r--r--usr.bin/chpass/chpass.1201
-rw-r--r--usr.bin/chpass/chpass.c119
-rw-r--r--usr.bin/chpass/edit.c67
-rw-r--r--usr.bin/chpass/field.c23
-rw-r--r--usr.bin/chpass/pw_copy.c41
-rw-r--r--usr.bin/chpass/pw_yp.c521
-rw-r--r--usr.bin/chpass/pw_yp.h126
-rw-r--r--usr.bin/chpass/table.c4
-rw-r--r--usr.bin/chpass/util.c45
-rw-r--r--usr.bin/cksum/cksum.110
-rw-r--r--usr.bin/cksum/cksum.c19
-rw-r--r--usr.bin/cmp/cmp.112
-rw-r--r--usr.bin/cmp/cmp.c36
-rw-r--r--usr.bin/cmp/regular.c17
-rw-r--r--usr.bin/cmp/special.c2
-rw-r--r--usr.bin/col/col.13
-rw-r--r--usr.bin/col/col.c31
-rw-r--r--usr.bin/colcrt/colcrt.14
-rw-r--r--usr.bin/colcrt/colcrt.c20
-rw-r--r--usr.bin/colldef/Makefile13
-rw-r--r--usr.bin/colldef/colldef.1252
-rw-r--r--usr.bin/colldef/data/Makefile72
-rw-r--r--usr.bin/colldef/data/de_DE.ISO_8859-1.src38
-rw-r--r--usr.bin/colldef/data/es_ES.ISO_8859-1.src38
-rw-r--r--usr.bin/colldef/data/is_IS.ISO_8859-1.src38
-rw-r--r--usr.bin/colldef/data/lt_LN.ASCII.src6
-rw-r--r--usr.bin/colldef/data/lt_LN.ISO_8859-1.src38
-rw-r--r--usr.bin/colldef/data/lt_LN.ISO_8859-2.src36
-rw-r--r--usr.bin/colldef/data/map.CP866174
-rw-r--r--usr.bin/colldef/data/map.ISO_8859-1174
-rw-r--r--usr.bin/colldef/data/map.ISO_8859-2174
-rw-r--r--usr.bin/colldef/data/map.KOI8-R174
-rw-r--r--usr.bin/colldef/data/ru_SU.CP866.src39
-rw-r--r--usr.bin/colldef/data/ru_SU.KOI8-R.src39
-rw-r--r--usr.bin/colldef/en_DK.example3073
-rw-r--r--usr.bin/colldef/parse.y289
-rw-r--r--usr.bin/colldef/scan.l293
-rw-r--r--usr.bin/colrm/colrm.c45
-rw-r--r--usr.bin/column/column.c4
-rw-r--r--usr.bin/comm/comm.15
-rw-r--r--usr.bin/comm/comm.c14
-rw-r--r--usr.bin/compile_et/Makefile17
-rw-r--r--usr.bin/compile_et/compile_et.178
-rw-r--r--usr.bin/compile_et/compile_et.c276
-rw-r--r--usr.bin/compile_et/compiler.h19
-rw-r--r--usr.bin/compile_et/error_table.y237
-rw-r--r--usr.bin/compile_et/et_lex.lex.l26
-rw-r--r--usr.bin/compile_et/mit-sipb-copyright.h19
-rw-r--r--usr.bin/compress/Makefile7
-rw-r--r--usr.bin/compress/compress.12
-rw-r--r--usr.bin/compress/compress.c6
-rw-r--r--usr.bin/compress/zopen.35
-rw-r--r--usr.bin/compress/zopen.c7
-rw-r--r--usr.bin/compress/zopen.h34
-rw-r--r--usr.bin/cpp/Makefile8
-rw-r--r--usr.bin/cpp/cpp.notraditional.sh4
-rw-r--r--usr.bin/cpp/cpp.sh9
-rw-r--r--usr.bin/ctags/ctags.c19
-rw-r--r--usr.bin/cut/cut.16
-rw-r--r--usr.bin/cut/cut.c52
-rw-r--r--usr.bin/dig/Makefile12
-rw-r--r--usr.bin/dirname/dirname.c4
-rw-r--r--usr.bin/dnsquery/Makefile10
-rw-r--r--usr.bin/du/du.128
-rw-r--r--usr.bin/du/du.c45
-rw-r--r--usr.bin/ee/Artistic117
-rw-r--r--usr.bin/ee/Makefile27
-rw-r--r--usr.bin/ee/README116
-rw-r--r--usr.bin/ee/ee.1529
-rw-r--r--usr.bin/ee/ee.c5128
-rw-r--r--usr.bin/ee/ee.i18n.guide141
-rw-r--r--usr.bin/ee/ee.msg179
-rw-r--r--usr.bin/ee/new_curse.c3574
-rw-r--r--usr.bin/ee/new_curse.h255
-rw-r--r--usr.bin/ee/nls/de_DE.ISO8859-1/ee.msg182
-rw-r--r--usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg182
-rw-r--r--usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg182
-rw-r--r--usr.bin/ee/nls/en_US.US-ASCII/ee.msg182
-rw-r--r--usr.bin/ee/nls/fr_FR.ISO8859-1/ee.msg182
-rw-r--r--usr.bin/ee/nls/fr_FR.ISO_8859-1/ee.msg182
-rw-r--r--usr.bin/env/env.c16
-rw-r--r--usr.bin/error/error.12
-rw-r--r--usr.bin/error/error.h6
-rw-r--r--usr.bin/error/input.c14
-rw-r--r--usr.bin/error/main.c4
-rw-r--r--usr.bin/error/pi.c6
-rw-r--r--usr.bin/error/subr.c6
-rw-r--r--usr.bin/error/touch.c12
-rw-r--r--usr.bin/expand/expand.c56
-rw-r--r--usr.bin/f2c/Makefile35
-rw-r--r--usr.bin/f2c/Notice23
-rw-r--r--usr.bin/f2c/README168
-rw-r--r--usr.bin/f2c/cds.c195
-rw-r--r--usr.bin/f2c/data.c493
-rw-r--r--usr.bin/f2c/defines.h300
-rw-r--r--usr.bin/f2c/defs.h1055
-rw-r--r--usr.bin/f2c/equiv.c413
-rw-r--r--usr.bin/f2c/error.c347
-rw-r--r--usr.bin/f2c/exec.c934
-rw-r--r--usr.bin/f2c/expr.c3436
-rw-r--r--usr.bin/f2c/f2c.1301
-rw-r--r--usr.bin/f2c/f2c.h223
-rw-r--r--usr.bin/f2c/format.c2524
-rw-r--r--usr.bin/f2c/format.h12
-rw-r--r--usr.bin/f2c/formatdata.c1166
-rw-r--r--usr.bin/f2c/ftypes.h51
-rw-r--r--usr.bin/f2c/gram.dcl416
-rw-r--r--usr.bin/f2c/gram.exec143
-rw-r--r--usr.bin/f2c/gram.expr142
-rw-r--r--usr.bin/f2c/gram.head291
-rw-r--r--usr.bin/f2c/gram.io173
-rw-r--r--usr.bin/f2c/init.c517
-rw-r--r--usr.bin/f2c/intr.c977
-rw-r--r--usr.bin/f2c/io.c1508
-rw-r--r--usr.bin/f2c/iob.h26
-rw-r--r--usr.bin/f2c/lex.c1707
-rw-r--r--usr.bin/f2c/machdefs.h31
-rw-r--r--usr.bin/f2c/main.c708
-rw-r--r--usr.bin/f2c/malloc.c165
-rw-r--r--usr.bin/f2c/mem.c268
-rw-r--r--usr.bin/f2c/memset.c66
-rw-r--r--usr.bin/f2c/misc.c1329
-rw-r--r--usr.bin/f2c/names.c835
-rw-r--r--usr.bin/f2c/names.h19
-rw-r--r--usr.bin/f2c/niceprintf.c441
-rw-r--r--usr.bin/f2c/niceprintf.h16
-rw-r--r--usr.bin/f2c/output.c1709
-rw-r--r--usr.bin/f2c/output.h64
-rw-r--r--usr.bin/f2c/p1defs.h158
-rw-r--r--usr.bin/f2c/p1output.c723
-rw-r--r--usr.bin/f2c/parse.h47
-rw-r--r--usr.bin/f2c/parse_args.c557
-rw-r--r--usr.bin/f2c/pccdefs.h64
-rw-r--r--usr.bin/f2c/pread.c990
-rw-r--r--usr.bin/f2c/proc.c1821
-rw-r--r--usr.bin/f2c/put.c441
-rw-r--r--usr.bin/f2c/putpcc.c2075
-rw-r--r--usr.bin/f2c/sysdep.c519
-rw-r--r--usr.bin/f2c/sysdep.h98
-rw-r--r--usr.bin/f2c/tokens100
-rw-r--r--usr.bin/f2c/usignal.h7
-rw-r--r--usr.bin/f2c/vax.c570
-rw-r--r--usr.bin/f2c/version.c2
-rw-r--r--usr.bin/fetch/Makefile9
-rw-r--r--usr.bin/fetch/fetch.1303
-rw-r--r--usr.bin/fetch/fetch.h89
-rw-r--r--usr.bin/fetch/file.c144
-rw-r--r--usr.bin/fetch/ftp.c427
-rw-r--r--usr.bin/fetch/http.c1605
-rw-r--r--usr.bin/fetch/main.c353
-rw-r--r--usr.bin/fetch/uri.c122
-rw-r--r--usr.bin/fetch/util.c332
-rw-r--r--usr.bin/file/LEGAL.NOTICE31
-rw-r--r--usr.bin/file/MAINT33
-rw-r--r--usr.bin/file/Magdir/Header5
-rw-r--r--usr.bin/file/Magdir/Localstuff7
-rw-r--r--usr.bin/file/Magdir/alliant17
-rw-r--r--usr.bin/file/Magdir/alpha21
-rw-r--r--usr.bin/file/Magdir/amanda7
-rw-r--r--usr.bin/file/Magdir/amigaos10
-rw-r--r--usr.bin/file/Magdir/animation58
-rw-r--r--usr.bin/file/Magdir/apl6
-rw-r--r--usr.bin/file/Magdir/apple10
-rw-r--r--usr.bin/file/Magdir/ar104
-rw-r--r--usr.bin/file/Magdir/arc3
-rw-r--r--usr.bin/file/Magdir/archive210
-rw-r--r--usr.bin/file/Magdir/asterix17
-rw-r--r--usr.bin/file/Magdir/att3b39
-rw-r--r--usr.bin/file/Magdir/audio96
-rw-r--r--usr.bin/file/Magdir/blit19
-rw-r--r--usr.bin/file/Magdir/bsdi7
-rw-r--r--usr.bin/file/Magdir/bzip14
-rw-r--r--usr.bin/file/Magdir/c-lang13
-rw-r--r--usr.bin/file/Magdir/chi7
-rw-r--r--usr.bin/file/Magdir/clipper64
-rw-r--r--usr.bin/file/Magdir/commands75
-rw-r--r--usr.bin/file/Magdir/compress92
-rw-r--r--usr.bin/file/Magdir/convex69
-rw-r--r--usr.bin/file/Magdir/cpio16
-rw-r--r--usr.bin/file/Magdir/database38
-rw-r--r--usr.bin/file/Magdir/diamond11
-rw-r--r--usr.bin/file/Magdir/diff8
-rw-r--r--usr.bin/file/Magdir/digital41
-rw-r--r--usr.bin/file/Magdir/ditroff4
-rw-r--r--usr.bin/file/Magdir/dump81
-rw-r--r--usr.bin/file/Magdir/elf76
-rw-r--r--usr.bin/file/Magdir/encore21
-rw-r--r--usr.bin/file/Magdir/figlet9
-rw-r--r--usr.bin/file/Magdir/filesystems6
-rw-r--r--usr.bin/file/Magdir/floppy.raw1
-rw-r--r--usr.bin/file/Magdir/fonts26
-rw-r--r--usr.bin/file/Magdir/frame37
-rw-r--r--usr.bin/file/Magdir/freebsd130
-rw-r--r--usr.bin/file/Magdir/gzip21
-rw-r--r--usr.bin/file/Magdir/hp228
-rw-r--r--usr.bin/file/Magdir/ibm37047
-rw-r--r--usr.bin/file/Magdir/ibm600017
-rw-r--r--usr.bin/file/Magdir/iff28
-rw-r--r--usr.bin/file/Magdir/imagen14
-rw-r--r--usr.bin/file/Magdir/images236
-rw-r--r--usr.bin/file/Magdir/intel35
-rw-r--r--usr.bin/file/Magdir/interleaf8
-rw-r--r--usr.bin/file/Magdir/iris57
-rw-r--r--usr.bin/file/Magdir/island9
-rw-r--r--usr.bin/file/Magdir/ispell54
-rw-r--r--usr.bin/file/Magdir/java13
-rw-r--r--usr.bin/file/Magdir/karma8
-rw-r--r--usr.bin/file/Magdir/lex11
-rw-r--r--usr.bin/file/Magdir/lif7
-rw-r--r--usr.bin/file/Magdir/linux73
-rw-r--r--usr.bin/file/Magdir/lisp10
-rw-r--r--usr.bin/file/Magdir/mach38
-rw-r--r--usr.bin/file/Magdir/magic5
-rw-r--r--usr.bin/file/Magdir/mail.news21
-rw-r--r--usr.bin/file/Magdir/microsoft72
-rw-r--r--usr.bin/file/Magdir/mips8
-rw-r--r--usr.bin/file/Magdir/mirage7
-rw-r--r--usr.bin/file/Magdir/mkid10
-rw-r--r--usr.bin/file/Magdir/mmdf5
-rw-r--r--usr.bin/file/Magdir/motorola32
-rw-r--r--usr.bin/file/Magdir/ms-dos73
-rw-r--r--usr.bin/file/Magdir/ncr48
-rw-r--r--usr.bin/file/Magdir/netbsd209
-rw-r--r--usr.bin/file/Magdir/news12
-rw-r--r--usr.bin/file/Magdir/osf110
-rw-r--r--usr.bin/file/Magdir/pbm7
-rw-r--r--usr.bin/file/Magdir/pdf7
-rw-r--r--usr.bin/file/Magdir/pdp25
-rw-r--r--usr.bin/file/Magdir/pgp13
-rw-r--r--usr.bin/file/Magdir/pjl5
-rw-r--r--usr.bin/file/Magdir/pkgadd5
-rw-r--r--usr.bin/file/Magdir/plus517
-rw-r--r--usr.bin/file/Magdir/postscript20
-rw-r--r--usr.bin/file/Magdir/printer55
-rw-r--r--usr.bin/file/Magdir/psdbms7
-rw-r--r--usr.bin/file/Magdir/pyramid11
-rw-r--r--usr.bin/file/Magdir/rle19
-rw-r--r--usr.bin/file/Magdir/rpm17
-rw-r--r--usr.bin/file/Magdir/rtf12
-rw-r--r--usr.bin/file/Magdir/sc5
-rw-r--r--usr.bin/file/Magdir/sccs21
-rw-r--r--usr.bin/file/Magdir/sendmail10
-rw-r--r--usr.bin/file/Magdir/sequent34
-rw-r--r--usr.bin/file/Magdir/sgi170
-rw-r--r--usr.bin/file/Magdir/sgml21
-rw-r--r--usr.bin/file/Magdir/sniffer63
-rw-r--r--usr.bin/file/Magdir/softquad30
-rw-r--r--usr.bin/file/Magdir/sun110
-rw-r--r--usr.bin/file/Magdir/sunraster12
-rw-r--r--usr.bin/file/Magdir/terminfo9
-rw-r--r--usr.bin/file/Magdir/tex36
-rw-r--r--usr.bin/file/Magdir/timezone12
-rw-r--r--usr.bin/file/Magdir/troff27
-rw-r--r--usr.bin/file/Magdir/typeset7
-rw-r--r--usr.bin/file/Magdir/unknown36
-rw-r--r--usr.bin/file/Magdir/uuencode30
-rw-r--r--usr.bin/file/Magdir/varied.out18
-rw-r--r--usr.bin/file/Magdir/vax34
-rw-r--r--usr.bin/file/Magdir/visx31
-rw-r--r--usr.bin/file/Magdir/vms27
-rw-r--r--usr.bin/file/Magdir/x1111
-rw-r--r--usr.bin/file/Magdir/xenix72
-rw-r--r--usr.bin/file/Magdir/zilog11
-rw-r--r--usr.bin/file/Magdir/zyxel16
-rw-r--r--usr.bin/file/Makefile56
-rw-r--r--usr.bin/file/PORTING76
-rw-r--r--usr.bin/file/README91
-rw-r--r--usr.bin/file/apprentice.c621
-rw-r--r--usr.bin/file/ascmagic.c124
-rw-r--r--usr.bin/file/compress.c122
-rw-r--r--usr.bin/file/cvsimport.sh18
-rw-r--r--usr.bin/file/file.1366
-rw-r--r--usr.bin/file/file.c398
-rw-r--r--usr.bin/file/file.h151
-rw-r--r--usr.bin/file/fsmagic.c181
-rw-r--r--usr.bin/file/internat.c72
-rw-r--r--usr.bin/file/is_tar.c100
-rw-r--r--usr.bin/file/magic.5206
-rw-r--r--usr.bin/file/names.h99
-rw-r--r--usr.bin/file/patchlevel.h146
-rw-r--r--usr.bin/file/print.c204
-rw-r--r--usr.bin/file/readelf.c318
-rw-r--r--usr.bin/file/readelf.h167
-rw-r--r--usr.bin/file/softmagic.c513
-rw-r--r--usr.bin/file/tar.h179
-rw-r--r--usr.bin/file2c/Makefile6
-rw-r--r--usr.bin/file2c/file2c.146
-rw-r--r--usr.bin/file2c/file2c.c46
-rw-r--r--usr.bin/find/Makefile1
-rw-r--r--usr.bin/find/extern.h2
-rw-r--r--usr.bin/find/find.130
-rw-r--r--usr.bin/find/find.c10
-rw-r--r--usr.bin/find/find.h1
-rw-r--r--usr.bin/find/function.c238
-rw-r--r--usr.bin/find/ls.c8
-rw-r--r--usr.bin/find/main.c16
-rw-r--r--usr.bin/find/misc.c4
-rw-r--r--usr.bin/find/operator.c38
-rw-r--r--usr.bin/find/option.c2
-rw-r--r--usr.bin/finger/extern.h1
-rw-r--r--usr.bin/finger/finger.157
-rw-r--r--usr.bin/finger/finger.c107
-rw-r--r--usr.bin/finger/finger.h2
-rw-r--r--usr.bin/finger/lprint.c44
-rw-r--r--usr.bin/finger/net.c76
-rw-r--r--usr.bin/finger/sprint.c73
-rw-r--r--usr.bin/finger/util.c54
-rw-r--r--usr.bin/fmt/fmt.114
-rw-r--r--usr.bin/fmt/fmt.c149
-rw-r--r--usr.bin/fold/fold.c2
-rw-r--r--usr.bin/from/from.18
-rw-r--r--usr.bin/from/from.c31
-rw-r--r--usr.bin/fsplit/fsplit.c8
-rw-r--r--usr.bin/fstat/fstat.112
-rw-r--r--usr.bin/fstat/fstat.c84
-rw-r--r--usr.bin/ftp/Makefile13
-rw-r--r--usr.bin/ftp/cmds.c1001
-rw-r--r--usr.bin/ftp/cmdtab.c203
-rw-r--r--usr.bin/ftp/complete.c367
-rw-r--r--usr.bin/ftp/domacro.c38
-rw-r--r--usr.bin/ftp/extern.h83
-rw-r--r--usr.bin/ftp/fetch.c608
-rw-r--r--usr.bin/ftp/ftp.1506
-rw-r--r--usr.bin/ftp/ftp.c784
-rw-r--r--usr.bin/ftp/ftp_var.h61
-rw-r--r--usr.bin/ftp/main.c414
-rw-r--r--usr.bin/ftp/pathnames.h6
-rw-r--r--usr.bin/ftp/ruserpass.c61
-rw-r--r--usr.bin/ftp/util.c779
-rw-r--r--usr.bin/gcore/Makefile9
-rw-r--r--usr.bin/gcore/aoutcore.c314
-rw-r--r--usr.bin/gcore/gcore.113
-rw-r--r--usr.bin/gcore/gcore.c37
-rw-r--r--usr.bin/gcore/md-sparc.c2
-rw-r--r--usr.bin/gencat/Makefile9
-rw-r--r--usr.bin/gencat/gencat.c255
-rw-r--r--usr.bin/gencat/gencat.h107
-rw-r--r--usr.bin/gencat/genlib.c896
-rw-r--r--usr.bin/getopt/Makefile7
-rw-r--r--usr.bin/getopt/README57
-rw-r--r--usr.bin/getopt/getopt.1103
-rw-r--r--usr.bin/getopt/getopt.c30
-rw-r--r--usr.bin/global/HISTORY161
-rw-r--r--usr.bin/global/MANIFEST17
-rw-r--r--usr.bin/global/Makefile3
-rw-r--r--usr.bin/global/Makefile.inc1
-rw-r--r--usr.bin/global/README527
-rw-r--r--usr.bin/global/VERSION1
-rw-r--r--usr.bin/global/btreeop/Makefile5
-rw-r--r--usr.bin/global/btreeop/btreeop.1168
-rw-r--r--usr.bin/global/btreeop/btreeop.c370
-rw-r--r--usr.bin/global/gctags/C.c840
-rw-r--r--usr.bin/global/gctags/Makefile7
-rw-r--r--usr.bin/global/gctags/ctags.c404
-rw-r--r--usr.bin/global/gctags/ctags.h110
-rw-r--r--usr.bin/global/gctags/fortran.c168
-rw-r--r--usr.bin/global/gctags/gctags.1227
-rw-r--r--usr.bin/global/gctags/lisp.c105
-rw-r--r--usr.bin/global/gctags/print.c122
-rw-r--r--usr.bin/global/gctags/test/ctags.test67
-rw-r--r--usr.bin/global/gctags/tree.c145
-rw-r--r--usr.bin/global/gctags/yacc.c151
-rw-r--r--usr.bin/global/global/Makefile9
-rw-r--r--usr.bin/global/global/global.1136
-rw-r--r--usr.bin/global/global/global.pl232
-rw-r--r--usr.bin/global/gtags/Makefile9
-rw-r--r--usr.bin/global/gtags/gtags.186
-rw-r--r--usr.bin/global/gtags/gtags.sh98
-rw-r--r--usr.bin/global/htags/Makefile9
-rw-r--r--usr.bin/global/htags/htags.1117
-rwxr-xr-xusr.bin/global/htags/htags.pl1082
-rw-r--r--usr.bin/global/systags/Makefile7
-rwxr-xr-xusr.bin/global/systags/systags.sh83
-rw-r--r--usr.bin/gprof/Makefile2
-rw-r--r--usr.bin/gprof/amd64.c11
-rw-r--r--usr.bin/gprof/amd64.h44
-rw-r--r--usr.bin/gprof/arcs.c10
-rw-r--r--usr.bin/gprof/dfn.c4
-rw-r--r--usr.bin/gprof/gprof.124
-rw-r--r--usr.bin/gprof/gprof.c39
-rw-r--r--usr.bin/gprof/gprof.h6
-rw-r--r--usr.bin/gprof/lookup.c2
-rw-r--r--usr.bin/gprof/printgprof.c35
-rw-r--r--usr.bin/gprof/tahoe.c8
-rw-r--r--usr.bin/gprof/tahoe.h2
-rw-r--r--usr.bin/gprof/vax.c8
-rw-r--r--usr.bin/gprof/vax.h2
-rw-r--r--usr.bin/gprof4/Makefile14
-rw-r--r--usr.bin/grep/egrep/Makefile17
-rw-r--r--usr.bin/head/head.15
-rw-r--r--usr.bin/head/head.c57
-rw-r--r--usr.bin/hexdump/Makefile4
-rw-r--r--usr.bin/hexdump/hexdump.125
-rw-r--r--usr.bin/hexdump/hexsyntax.c16
-rw-r--r--usr.bin/hexdump/od.110
-rw-r--r--usr.bin/hexdump/odsyntax.c4
-rw-r--r--usr.bin/host/Makefile10
-rw-r--r--usr.bin/id/Makefile13
-rw-r--r--usr.bin/id/groups.12
-rw-r--r--usr.bin/id/groups.sh6
-rw-r--r--usr.bin/id/id.142
-rw-r--r--usr.bin/id/id.c28
-rw-r--r--usr.bin/id/whoami.12
-rw-r--r--usr.bin/id/whoami.sh6
-rw-r--r--usr.bin/indent/indent.116
-rw-r--r--usr.bin/indent/io.c52
-rw-r--r--usr.bin/indent/lexi.c4
-rw-r--r--usr.bin/indent/parse.c22
-rw-r--r--usr.bin/ipcrm/Makefile5
-rw-r--r--usr.bin/ipcrm/ipcrm.183
-rw-r--r--usr.bin/ipcrm/ipcrm.c172
-rw-r--r--usr.bin/ipcs/Makefile9
-rw-r--r--usr.bin/ipcs/ipcs.1151
-rw-r--r--usr.bin/ipcs/ipcs.c493
-rw-r--r--usr.bin/join/join.c13
-rw-r--r--usr.bin/jot/jot.c21
-rw-r--r--usr.bin/kdump/Makefile2
-rw-r--r--usr.bin/kdump/kdump.118
-rw-r--r--usr.bin/kdump/kdump.c167
-rw-r--r--usr.bin/kdump/mkioctls47
-rw-r--r--usr.bin/key/Makefile13
-rw-r--r--usr.bin/key/key.149
-rw-r--r--usr.bin/key/skey.c129
-rw-r--r--usr.bin/keyinfo/Makefile12
-rw-r--r--usr.bin/keyinfo/keyinfo.150
-rw-r--r--usr.bin/keyinfo/keyinfo.pl27
-rw-r--r--usr.bin/keyinit/Makefile15
-rw-r--r--usr.bin/keyinit/keyinit.164
-rw-r--r--usr.bin/keyinit/skeyinit.c191
-rw-r--r--usr.bin/keylogin/Makefile10
-rw-r--r--usr.bin/keylogin/keylogin.125
-rw-r--r--usr.bin/keylogin/keylogin.c80
-rw-r--r--usr.bin/keylogout/Makefile10
-rw-r--r--usr.bin/keylogout/keylogout.144
-rw-r--r--usr.bin/keylogout/keylogout.c68
-rw-r--r--usr.bin/killall/Makefile7
-rw-r--r--usr.bin/killall/killall.1134
-rwxr-xr-xusr.bin/killall/killall.pl117
-rw-r--r--usr.bin/ktrace/Makefile4
-rw-r--r--usr.bin/ktrace/ktrace.126
-rw-r--r--usr.bin/ktrace/ktrace.c32
-rw-r--r--usr.bin/ktrace/ktrace.h2
-rw-r--r--usr.bin/ktrace/subr.c9
-rw-r--r--usr.bin/kzip/Makefile6
-rw-r--r--usr.bin/kzip/kzip.873
-rw-r--r--usr.bin/kzip/kzip.c348
-rw-r--r--usr.bin/last/last.15
-rw-r--r--usr.bin/last/last.c191
-rw-r--r--usr.bin/lastcomm/lastcomm.154
-rw-r--r--usr.bin/lastcomm/lastcomm.c110
-rw-r--r--usr.bin/ldd/Makefile7
-rw-r--r--usr.bin/ldd/ldd.147
-rw-r--r--usr.bin/ldd/ldd.c170
-rw-r--r--usr.bin/ldd/sods.c505
-rw-r--r--usr.bin/lex/COPYING38
-rw-r--r--usr.bin/lex/FlexLexer.h185
-rw-r--r--usr.bin/lex/Makefile59
-rw-r--r--usr.bin/lex/NEWS1233
-rw-r--r--usr.bin/lex/README60
-rw-r--r--usr.bin/lex/ccl.c149
-rw-r--r--usr.bin/lex/config.h26
-rw-r--r--usr.bin/lex/dfa.c1095
-rw-r--r--usr.bin/lex/ecs.c225
-rw-r--r--usr.bin/lex/flex.skl1541
-rw-r--r--usr.bin/lex/flexdef.h1048
-rw-r--r--usr.bin/lex/gen.c1625
-rw-r--r--usr.bin/lex/initscan.c3697
-rw-r--r--usr.bin/lex/lex.14062
-rw-r--r--usr.bin/lex/lib/Makefile16
-rw-r--r--usr.bin/lex/lib/libmain.c15
-rw-r--r--usr.bin/lex/lib/libyywrap.c8
-rw-r--r--usr.bin/lex/main.c1177
-rw-r--r--usr.bin/lex/misc.c886
-rwxr-xr-xusr.bin/lex/mkskel.sh16
-rw-r--r--usr.bin/lex/nfa.c709
-rw-r--r--usr.bin/lex/parse.y913
-rw-r--r--usr.bin/lex/scan.l710
-rw-r--r--usr.bin/lex/skel.c1548
-rw-r--r--usr.bin/lex/sym.c262
-rw-r--r--usr.bin/lex/tblcmp.c887
-rw-r--r--usr.bin/lex/version.h1
-rw-r--r--usr.bin/lex/yylex.c216
-rw-r--r--usr.bin/limits/Makefile13
-rw-r--r--usr.bin/limits/limits.1304
-rw-r--r--usr.bin/limits/limits.c630
-rw-r--r--usr.bin/locate/Makefile1
-rw-r--r--usr.bin/locate/Makefile.inc3
-rw-r--r--usr.bin/locate/bigram/Makefile4
-rw-r--r--usr.bin/locate/bigram/locate.bigram.c70
-rw-r--r--usr.bin/locate/code/Makefile5
-rw-r--r--usr.bin/locate/code/locate.code.c131
-rw-r--r--usr.bin/locate/locate/Makefile19
-rw-r--r--usr.bin/locate/locate/concatdb.sh72
-rw-r--r--usr.bin/locate/locate/fastfind.c332
-rw-r--r--usr.bin/locate/locate/locate.1200
-rw-r--r--usr.bin/locate/locate/locate.c407
-rw-r--r--usr.bin/locate/locate/locate.h31
-rw-r--r--usr.bin/locate/locate/locate.rc26
-rw-r--r--usr.bin/locate/locate/locate.updatedb.864
-rw-r--r--usr.bin/locate/locate/mklocatedb.sh74
-rw-r--r--usr.bin/locate/locate/updatedb.sh85
-rw-r--r--usr.bin/locate/locate/util.c279
-rw-r--r--usr.bin/lock/Makefile2
-rw-r--r--usr.bin/lock/lock.13
-rw-r--r--usr.bin/lock/lock.c38
-rw-r--r--usr.bin/lockf/Makefile6
-rw-r--r--usr.bin/lockf/lockf.1112
-rw-r--r--usr.bin/lockf/lockf.c213
-rw-r--r--usr.bin/logger/logger.c3
-rw-r--r--usr.bin/login/Makefile31
-rw-r--r--usr.bin/login/README20
-rw-r--r--usr.bin/login/klogin.c22
-rw-r--r--usr.bin/login/login.141
-rw-r--r--usr.bin/login/login.access.550
-rw-r--r--usr.bin/login/login.c667
-rw-r--r--usr.bin/login/login_access.c239
-rw-r--r--usr.bin/login/login_fbtab.c153
-rw-r--r--usr.bin/login/pathnames.h8
-rw-r--r--usr.bin/logname/logname.117
-rw-r--r--usr.bin/logname/logname.c2
-rw-r--r--usr.bin/look/look.13
-rw-r--r--usr.bin/look/look.c100
-rw-r--r--usr.bin/lorder/Makefile16
-rw-r--r--usr.bin/lorder/lorder.14
-rw-r--r--usr.bin/lsvfs/Makefile4
-rw-r--r--usr.bin/lsvfs/lsvfs.155
-rw-r--r--usr.bin/lsvfs/lsvfs.c99
-rw-r--r--usr.bin/m4/Makefile10
-rw-r--r--usr.bin/m4/NOTES64
-rw-r--r--usr.bin/m4/PSD.doc/Makefile11
-rw-r--r--usr.bin/m4/TEST/ack.m4 (renamed from usr.bin/mkdep/mkdep.ultrix)100
-rw-r--r--usr.bin/m4/TEST/hanoi.m4 (renamed from usr.bin/locate/locate/updatedb.csh)48
-rw-r--r--usr.bin/m4/TEST/hash.m457
-rw-r--r--usr.bin/m4/TEST/sqroot.m447
-rw-r--r--usr.bin/m4/TEST/string.m4 (renamed from usr.bin/mkdep/mkdep.append)102
-rw-r--r--usr.bin/m4/TEST/test.m4245
-rw-r--r--usr.bin/m4/eval.c803
-rw-r--r--usr.bin/m4/expr.c574
-rw-r--r--usr.bin/m4/extern.h96
-rw-r--r--usr.bin/m4/look.c145
-rw-r--r--usr.bin/m4/m4.1181
-rw-r--r--usr.bin/m4/main.c425
-rw-r--r--usr.bin/m4/mdef.h176
-rw-r--r--usr.bin/m4/misc.c270
-rw-r--r--usr.bin/m4/pathnames.h60
-rw-r--r--usr.bin/m4/stdd.h56
-rw-r--r--usr.bin/mail/Makefile5
-rw-r--r--usr.bin/mail/USD.doc/mail1.nr4
-rw-r--r--usr.bin/mail/USD.doc/mail5.nr2
-rw-r--r--usr.bin/mail/USD.doc/mail6.nr2
-rw-r--r--usr.bin/mail/USD.doc/mail8.nr2
-rw-r--r--usr.bin/mail/aux.c8
-rw-r--r--usr.bin/mail/cmd2.c4
-rw-r--r--usr.bin/mail/cmdtab.c2
-rw-r--r--usr.bin/mail/def.h6
-rw-r--r--usr.bin/mail/extern.h2
-rw-r--r--usr.bin/mail/lex.c11
-rw-r--r--usr.bin/mail/list.c6
-rw-r--r--usr.bin/mail/mail.145
-rw-r--r--usr.bin/mail/main.c31
-rw-r--r--usr.bin/mail/misc/mail.help2
-rw-r--r--usr.bin/mail/misc/mail.rc2
-rw-r--r--usr.bin/mail/names.c2
-rw-r--r--usr.bin/mail/pathnames.h2
-rw-r--r--usr.bin/mail/send.c2
-rw-r--r--usr.bin/mail/temp.c2
-rw-r--r--usr.bin/mail/tty.c28
-rw-r--r--usr.bin/mail/v7.local.c7
-rw-r--r--usr.bin/make/Makefile15
-rw-r--r--usr.bin/make/PSD.doc/Makefile8
-rw-r--r--usr.bin/make/PSD.doc/tutorial.ms3744
-rw-r--r--usr.bin/make/arch.c1234
-rw-r--r--usr.bin/make/buf.c463
-rw-r--r--usr.bin/make/buf.h82
-rw-r--r--usr.bin/make/compat.c654
-rw-r--r--usr.bin/make/cond.c1256
-rw-r--r--usr.bin/make/config.h117
-rw-r--r--usr.bin/make/dir.c1276
-rw-r--r--usr.bin/make/dir.h71
-rw-r--r--usr.bin/make/for.c301
-rw-r--r--usr.bin/make/hash.c420
-rw-r--r--usr.bin/make/hash.h117
-rw-r--r--usr.bin/make/job.c3107
-rw-r--r--usr.bin/make/job.h234
-rw-r--r--usr.bin/make/list.h299
-rw-r--r--usr.bin/make/lst.h165
-rw-r--r--usr.bin/make/lst.lib/lstAppend.c115
-rw-r--r--usr.bin/make/lst.lib/lstAtEnd.c72
-rw-r--r--usr.bin/make/lst.lib/lstAtFront.c73
-rw-r--r--usr.bin/make/lst.lib/lstClose.c79
-rw-r--r--usr.bin/make/lst.lib/lstConcat.c178
-rw-r--r--usr.bin/make/lst.lib/lstDatum.c73
-rw-r--r--usr.bin/make/lst.lib/lstDeQueue.c83
-rw-r--r--usr.bin/make/lst.lib/lstDestroy.c104
-rw-r--r--usr.bin/make/lst.lib/lstDupl.c101
-rw-r--r--usr.bin/make/lst.lib/lstEnQueue.c75
-rw-r--r--usr.bin/make/lst.lib/lstFind.c72
-rw-r--r--usr.bin/make/lst.lib/lstFindFrom.c96
-rw-r--r--usr.bin/make/lst.lib/lstFirst.c73
-rw-r--r--usr.bin/make/lst.lib/lstForEach.c74
-rw-r--r--usr.bin/make/lst.lib/lstForEachFrom.c114
-rw-r--r--usr.bin/make/lst.lib/lstInit.c78
-rw-r--r--usr.bin/make/lst.lib/lstInsert.c115
-rw-r--r--usr.bin/make/lst.lib/lstInt.h112
-rw-r--r--usr.bin/make/lst.lib/lstIsAtEnd.c83
-rw-r--r--usr.bin/make/lst.lib/lstIsEmpty.c71
-rw-r--r--usr.bin/make/lst.lib/lstLast.c73
-rw-r--r--usr.bin/make/lst.lib/lstMember.c71
-rw-r--r--usr.bin/make/lst.lib/lstNext.c116
-rw-r--r--usr.bin/make/lst.lib/lstOpen.c83
-rw-r--r--usr.bin/make/lst.lib/lstRemove.c133
-rw-r--r--usr.bin/make/lst.lib/lstReplace.c75
-rw-r--r--usr.bin/make/lst.lib/lstSucc.c75
-rw-r--r--usr.bin/make/main.c1255
-rw-r--r--usr.bin/make/make.1966
-rw-r--r--usr.bin/make/make.c912
-rw-r--r--usr.bin/make/make.h372
-rw-r--r--usr.bin/make/nonints.h145
-rw-r--r--usr.bin/make/parse.c2596
-rw-r--r--usr.bin/make/pathnames.h (renamed from usr.bin/tip/pathnames.h)19
-rw-r--r--usr.bin/make/sprite.h (renamed from usr.bin/make/bit.h)100
-rw-r--r--usr.bin/make/str.c492
-rw-r--r--usr.bin/make/suff.c2449
-rw-r--r--usr.bin/make/targ.c660
-rw-r--r--usr.bin/make/util.c349
-rw-r--r--usr.bin/make/var.c2044
-rw-r--r--usr.bin/makewhatis/makewhatis.local.870
-rw-r--r--usr.bin/makewhatis/makewhatis.local.sh58
-rw-r--r--usr.bin/mesg/mesg.15
-rw-r--r--usr.bin/mesg/mesg.c2
-rw-r--r--usr.bin/mk_cmds/Makefile16
-rw-r--r--usr.bin/mk_cmds/cmd_tbl.l79
-rw-r--r--usr.bin/mk_cmds/copyright.h19
-rw-r--r--usr.bin/mk_cmds/ct.y77
-rw-r--r--usr.bin/mk_cmds/mk_cmds.c97
-rw-r--r--usr.bin/mk_cmds/options.c32
-rw-r--r--usr.bin/mk_cmds/utils.c135
-rw-r--r--usr.bin/mkdep/Makefile13
-rw-r--r--usr.bin/mkdep/mkdep.gcc.sh55
-rw-r--r--usr.bin/mkdep/mkdep.old.compiler143
-rw-r--r--usr.bin/mkfifo/mkfifo.127
-rw-r--r--usr.bin/mkfifo/mkfifo.c2
-rw-r--r--usr.bin/mklocale/Makefile2
-rw-r--r--usr.bin/mklocale/README.locale_name7
-rw-r--r--usr.bin/mklocale/data/Makefile50
-rw-r--r--usr.bin/mklocale/data/ja_JP.EUC.src158
-rw-r--r--usr.bin/mklocale/data/ko_KR.EUC.src119
-rw-r--r--usr.bin/mklocale/data/lt_LN.ASCII.src (renamed from usr.bin/mklocale/POSIX)13
-rw-r--r--usr.bin/mklocale/data/lt_LN.ISO_8859-1.src39
-rw-r--r--usr.bin/mklocale/data/lt_LN.ISO_8859-2.src79
-rw-r--r--usr.bin/mklocale/data/ru_SU.CP866.src42
-rw-r--r--usr.bin/mklocale/data/ru_SU.KOI8-R.src39
-rw-r--r--usr.bin/mklocale/ldef.h4
-rw-r--r--usr.bin/mklocale/mklocale.13
-rw-r--r--usr.bin/mklocale/yacc.y32
-rw-r--r--usr.bin/mkstr/mkstr.16
-rw-r--r--usr.bin/modstat/Makefile42
-rw-r--r--usr.bin/modstat/modstat.869
-rw-r--r--usr.bin/modstat/modstat.c180
-rw-r--r--usr.bin/modstat/pathnames.h3
-rw-r--r--usr.bin/more/Makefile11
-rw-r--r--usr.bin/more/ch.c14
-rw-r--r--usr.bin/more/command.c32
-rw-r--r--usr.bin/more/input.c4
-rw-r--r--usr.bin/more/less.h2
-rw-r--r--usr.bin/more/line.c78
-rw-r--r--usr.bin/more/linenum.c6
-rw-r--r--usr.bin/more/main.c13
-rw-r--r--usr.bin/more/more.112
-rw-r--r--usr.bin/more/option.c2
-rw-r--r--usr.bin/more/output.c40
-rw-r--r--usr.bin/more/position.c2
-rw-r--r--usr.bin/more/prim.c155
-rw-r--r--usr.bin/more/screen.c47
-rw-r--r--usr.bin/more/tags.c6
-rw-r--r--usr.bin/more/ttyin.c2
-rw-r--r--usr.bin/msgs/Makefile7
-rw-r--r--usr.bin/msgs/msgs.114
-rw-r--r--usr.bin/msgs/msgs.c29
-rw-r--r--usr.bin/mt/mt.1104
-rw-r--r--usr.bin/mt/mt.c201
-rw-r--r--usr.bin/netstat/Makefile13
-rw-r--r--usr.bin/netstat/atalk.c285
-rw-r--r--usr.bin/netstat/if.c314
-rw-r--r--usr.bin/netstat/inet.c273
-rw-r--r--usr.bin/netstat/ipx.c364
-rw-r--r--usr.bin/netstat/iso.c5
-rw-r--r--usr.bin/netstat/main.c169
-rw-r--r--usr.bin/netstat/mbuf.c42
-rw-r--r--usr.bin/netstat/mroute.c126
-rw-r--r--usr.bin/netstat/netstat.148
-rw-r--r--usr.bin/netstat/netstat.h18
-rw-r--r--usr.bin/netstat/route.c269
-rw-r--r--usr.bin/netstat/unix.c11
-rw-r--r--usr.bin/newkey/Makefile13
-rw-r--r--usr.bin/newkey/generic.c135
-rw-r--r--usr.bin/newkey/newkey.857
-rw-r--r--usr.bin/newkey/newkey.c235
-rw-r--r--usr.bin/newkey/update.c356
-rw-r--r--usr.bin/nfsstat/nfsstat.121
-rw-r--r--usr.bin/nfsstat/nfsstat.c15
-rw-r--r--usr.bin/nice/nice.143
-rw-r--r--usr.bin/nice/nice.c13
-rw-r--r--usr.bin/nm/nm.115
-rw-r--r--usr.bin/nm/nm.1aout126
-rw-r--r--usr.bin/nm/nm.c146
-rw-r--r--usr.bin/opieinfo/Makefile16
-rw-r--r--usr.bin/opiekey/Makefile16
-rw-r--r--usr.bin/opiepasswd/Makefile16
-rw-r--r--usr.bin/pagesize/Makefile16
-rw-r--r--usr.bin/pagesize/pagesize.14
-rw-r--r--usr.bin/pagesize/pagesize.sh6
-rw-r--r--usr.bin/passwd/Makefile80
-rw-r--r--usr.bin/passwd/extern.h5
-rw-r--r--usr.bin/passwd/local_passwd.c100
-rw-r--r--usr.bin/passwd/passwd.1111
-rw-r--r--usr.bin/passwd/passwd.c161
-rw-r--r--usr.bin/passwd/yp_passwd.c188
-rw-r--r--usr.bin/paste/paste.c2
-rw-r--r--usr.bin/patch/Makefile6
-rw-r--r--usr.bin/patch/README79
-rw-r--r--usr.bin/patch/common.h138
-rw-r--r--usr.bin/patch/inp.c313
-rw-r--r--usr.bin/patch/inp.h18
-rw-r--r--usr.bin/patch/patch.1446
-rw-r--r--usr.bin/patch/patch.c800
-rw-r--r--usr.bin/patch/pch.c1108
-rw-r--r--usr.bin/patch/pch.h36
-rw-r--r--usr.bin/patch/util.c339
-rw-r--r--usr.bin/patch/util.h74
-rw-r--r--usr.bin/pr/pr.16
-rw-r--r--usr.bin/pr/pr.c111
-rw-r--r--usr.bin/printenv/printenv.c2
-rw-r--r--usr.bin/printf/printf.12
-rw-r--r--usr.bin/printf/printf.c71
-rw-r--r--usr.bin/quota/Makefile3
-rw-r--r--usr.bin/quota/quota.120
-rw-r--r--usr.bin/quota/quota.c424
-rw-r--r--usr.bin/ranlib/Makefile10
-rw-r--r--usr.bin/ranlib/build.c23
-rw-r--r--usr.bin/ranlib/misc.c12
-rw-r--r--usr.bin/ranlib/ranlib.16
-rw-r--r--usr.bin/ranlib/ranlib.1aout89
-rw-r--r--usr.bin/ranlib/ranlib.570
-rw-r--r--usr.bin/ranlib/ranlib.c13
-rw-r--r--usr.bin/ranlib/touch.c9
-rw-r--r--usr.bin/rdist/Makefile18
-rw-r--r--usr.bin/rdist/defs.h16
-rw-r--r--usr.bin/rdist/docmd.c89
-rw-r--r--usr.bin/rdist/expand.c32
-rw-r--r--usr.bin/rdist/gram.y27
-rw-r--r--usr.bin/rdist/lookup.c9
-rw-r--r--usr.bin/rdist/main.c14
-rw-r--r--usr.bin/rdist/pathnames.h1
-rw-r--r--usr.bin/rdist/rdist.119
-rw-r--r--usr.bin/rdist/rshrcmd.c124
-rw-r--r--usr.bin/rdist/server.c118
-rw-r--r--usr.bin/renice/Makefile1
-rw-r--r--usr.bin/renice/renice.c2
-rw-r--r--usr.bin/rev/rev.c2
-rw-r--r--usr.bin/rlogin/Makefile9
-rw-r--r--usr.bin/rlogin/kcmd.c23
-rw-r--r--usr.bin/rlogin/krb.h13
-rw-r--r--usr.bin/rlogin/krcmd.c8
-rw-r--r--usr.bin/rlogin/rlogin.137
-rw-r--r--usr.bin/rlogin/rlogin.c401
-rw-r--r--usr.bin/rpcgen/Makefile13
-rw-r--r--usr.bin/rpcgen/rpc_clntout.c330
-rw-r--r--usr.bin/rpcgen/rpc_cout.c758
-rw-r--r--usr.bin/rpcgen/rpc_hout.c599
-rw-r--r--usr.bin/rpcgen/rpc_main.c1388
-rw-r--r--usr.bin/rpcgen/rpc_parse.c656
-rw-r--r--usr.bin/rpcgen/rpc_parse.h197
-rw-r--r--usr.bin/rpcgen/rpc_sample.c312
-rw-r--r--usr.bin/rpcgen/rpc_scan.c517
-rw-r--r--usr.bin/rpcgen/rpc_scan.h133
-rw-r--r--usr.bin/rpcgen/rpc_svcout.c1086
-rw-r--r--usr.bin/rpcgen/rpc_tblout.c172
-rw-r--r--usr.bin/rpcgen/rpc_util.c517
-rw-r--r--usr.bin/rpcgen/rpc_util.h213
-rw-r--r--usr.bin/rpcgen/rpcgen.1552
-rw-r--r--usr.bin/rpcinfo/Makefile8
-rw-r--r--usr.bin/rpcinfo/rpcinfo.8166
-rw-r--r--usr.bin/rpcinfo/rpcinfo.c666
-rw-r--r--usr.bin/rs/rs.c9
-rw-r--r--usr.bin/rsh/Makefile9
-rw-r--r--usr.bin/rsh/rsh.126
-rw-r--r--usr.bin/rsh/rsh.c66
-rw-r--r--usr.bin/rup/Makefile9
-rw-r--r--usr.bin/rup/rup.194
-rw-r--r--usr.bin/rup/rup.c231
-rw-r--r--usr.bin/ruptime/ruptime.13
-rw-r--r--usr.bin/ruptime/ruptime.c29
-rw-r--r--usr.bin/rusers/Makefile9
-rw-r--r--usr.bin/rusers/rusers.193
-rw-r--r--usr.bin/rusers/rusers.c252
-rw-r--r--usr.bin/rwall/Makefile9
-rw-r--r--usr.bin/rwall/rwall.179
-rw-r--r--usr.bin/rwall/rwall.c177
-rw-r--r--usr.bin/rwho/rwho.12
-rw-r--r--usr.bin/rwho/rwho.c38
-rw-r--r--usr.bin/sasc/INSTALL86
-rw-r--r--usr.bin/sasc/Makefile5
-rw-r--r--usr.bin/sasc/README9
-rw-r--r--usr.bin/sasc/sasc.194
-rw-r--r--usr.bin/sasc/sasc.c197
-rw-r--r--usr.bin/script/script.c19
-rw-r--r--usr.bin/sed/TEST/sed.test4
-rw-r--r--usr.bin/sed/compile.c101
-rw-r--r--usr.bin/sed/defs.h1
-rw-r--r--usr.bin/sed/main.c11
-rw-r--r--usr.bin/sed/process.c48
-rw-r--r--usr.bin/sed/sed.16
-rw-r--r--usr.bin/sgmlfmt/Makefile9
-rw-r--r--usr.bin/sgmlfmt/sgmlfmt.1172
-rwxr-xr-xusr.bin/sgmlfmt/sgmlfmt.pl749
-rw-r--r--usr.bin/sgmls/LICENSE43
-rw-r--r--usr.bin/sgmls/Makefile9
-rw-r--r--usr.bin/sgmls/Makefile.inc16
-rw-r--r--usr.bin/sgmls/README138
-rwxr-xr-xusr.bin/sgmls/configure617
-rw-r--r--usr.bin/sgmls/instant/Makefile15
-rw-r--r--usr.bin/sgmls/instant/README150
-rw-r--r--usr.bin/sgmls/instant/browse.c462
-rw-r--r--usr.bin/sgmls/instant/general.h329
-rw-r--r--usr.bin/sgmls/instant/hyper.c100
-rw-r--r--usr.bin/sgmls/instant/info.c300
-rw-r--r--usr.bin/sgmls/instant/instant.1183
-rw-r--r--usr.bin/sgmls/instant/main.c710
-rw-r--r--usr.bin/sgmls/instant/tables.c2013
-rw-r--r--usr.bin/sgmls/instant/traninit.c577
-rw-r--r--usr.bin/sgmls/instant/translate.c881
-rw-r--r--usr.bin/sgmls/instant/translate.h153
-rw-r--r--usr.bin/sgmls/instant/transpec.5528
-rw-r--r--usr.bin/sgmls/instant/tranvar.c763
-rw-r--r--usr.bin/sgmls/instant/util.c1109
-rw-r--r--usr.bin/sgmls/libsgmls/Makefile17
-rw-r--r--usr.bin/sgmls/libsgmls/sgmls.c1032
-rw-r--r--usr.bin/sgmls/libsgmls/sgmls.h127
-rwxr-xr-xusr.bin/sgmls/sgmls.pl247
-rw-r--r--usr.bin/sgmls/sgmls/Makefile19
-rw-r--r--usr.bin/sgmls/sgmls/action.h180
-rw-r--r--usr.bin/sgmls/sgmls/adl.h118
-rw-r--r--usr.bin/sgmls/sgmls/alloc.h8
-rw-r--r--usr.bin/sgmls/sgmls/ambig.c438
-rw-r--r--usr.bin/sgmls/sgmls/appl.h31
-rw-r--r--usr.bin/sgmls/sgmls/catalog.c925
-rw-r--r--usr.bin/sgmls/sgmls/catalog.h45
-rw-r--r--usr.bin/sgmls/sgmls/config.h158
-rw-r--r--usr.bin/sgmls/sgmls/context.c451
-rw-r--r--usr.bin/sgmls/sgmls/context.h19
-rw-r--r--usr.bin/sgmls/sgmls/dosproc.c40
-rw-r--r--usr.bin/sgmls/sgmls/ebcdic.c42
-rw-r--r--usr.bin/sgmls/sgmls/ebcdic.h25
-rw-r--r--usr.bin/sgmls/sgmls/entgen.c517
-rw-r--r--usr.bin/sgmls/sgmls/entity.h192
-rw-r--r--usr.bin/sgmls/sgmls/error.h61
-rw-r--r--usr.bin/sgmls/sgmls/etype.h93
-rw-r--r--usr.bin/sgmls/sgmls/exclude.c121
-rw-r--r--usr.bin/sgmls/sgmls/genlex.c140
-rw-r--r--usr.bin/sgmls/sgmls/getopt.c166
-rw-r--r--usr.bin/sgmls/sgmls/getopt.h11
-rw-r--r--usr.bin/sgmls/sgmls/keyword.h22
-rw-r--r--usr.bin/sgmls/sgmls/latin1.h37
-rw-r--r--usr.bin/sgmls/sgmls/lexcode.h12
-rw-r--r--usr.bin/sgmls/sgmls/lexrf.c125
-rw-r--r--usr.bin/sgmls/sgmls/lextaba.c750
-rw-r--r--usr.bin/sgmls/sgmls/lextabe.c357
-rw-r--r--usr.bin/sgmls/sgmls/lextoke.h10
-rw-r--r--usr.bin/sgmls/sgmls/lineout.c656
-rw-r--r--usr.bin/sgmls/sgmls/lineout.h23
-rw-r--r--usr.bin/sgmls/sgmls/main.c650
-rw-r--r--usr.bin/sgmls/sgmls/md1.c866
-rw-r--r--usr.bin/sgmls/sgmls/md2.c792
-rw-r--r--usr.bin/sgmls/sgmls/msg.h258
-rw-r--r--usr.bin/sgmls/sgmls/msgcat.c840
-rw-r--r--usr.bin/sgmls/sgmls/msgcat.h13
-rw-r--r--usr.bin/sgmls/sgmls/pars1.c984
-rw-r--r--usr.bin/sgmls/sgmls/pars2.c1333
-rw-r--r--usr.bin/sgmls/sgmls/pcbrf.c1351
-rw-r--r--usr.bin/sgmls/sgmls/portproc.c105
-rw-r--r--usr.bin/sgmls/sgmls/serv.c299
-rw-r--r--usr.bin/sgmls/sgmls/sgml1.c485
-rw-r--r--usr.bin/sgmls/sgmls/sgml2.c522
-rw-r--r--usr.bin/sgmls/sgmls/sgmlaux.h72
-rw-r--r--usr.bin/sgmls/sgmls/sgmldecl.c1804
-rw-r--r--usr.bin/sgmls/sgmls/sgmldecl.h90
-rw-r--r--usr.bin/sgmls/sgmls/sgmlfnsm.h130
-rw-r--r--usr.bin/sgmls/sgmls/sgmlincl.h20
-rw-r--r--usr.bin/sgmls/sgmls/sgmlio.c384
-rw-r--r--usr.bin/sgmls/sgmls/sgmlmain.h101
-rw-r--r--usr.bin/sgmls/sgmls/sgmlmsg.c514
-rw-r--r--usr.bin/sgmls/sgmls/sgmls.1970
-rw-r--r--usr.bin/sgmls/sgmls/sgmlxtrn.c225
-rw-r--r--usr.bin/sgmls/sgmls/sgmlxtrn.h123
-rw-r--r--usr.bin/sgmls/sgmls/source.h114
-rw-r--r--usr.bin/sgmls/sgmls/std.h110
-rw-r--r--usr.bin/sgmls/sgmls/stklen.c2
-rw-r--r--usr.bin/sgmls/sgmls/strerror.c36
-rw-r--r--usr.bin/sgmls/sgmls/synrf.c72
-rw-r--r--usr.bin/sgmls/sgmls/synxtrn.h154
-rw-r--r--usr.bin/sgmls/sgmls/tools.h76
-rw-r--r--usr.bin/sgmls/sgmls/trace.h113
-rw-r--r--usr.bin/sgmls/sgmls/traceset.c462
-rw-r--r--usr.bin/sgmls/sgmls/unix.cfg147
-rw-r--r--usr.bin/sgmls/sgmls/unixproc.c98
-rw-r--r--usr.bin/sgmls/sgmls/version.c1
-rw-r--r--usr.bin/sgmls/sgmls/xfprintf.c564
-rw-r--r--usr.bin/sgmls/unix.cfg165
-rw-r--r--usr.bin/shar/Makefile13
-rw-r--r--usr.bin/shar/shar.130
-rw-r--r--usr.bin/showmount/Makefile3
-rw-r--r--usr.bin/showmount/showmount.89
-rw-r--r--usr.bin/showmount/showmount.c57
-rw-r--r--usr.bin/size/size.13
-rw-r--r--usr.bin/size/size.1aout61
-rw-r--r--usr.bin/size/size.c2
-rw-r--r--usr.bin/sort/sort.1310
-rw-r--r--usr.bin/split/split.c4
-rw-r--r--usr.bin/strings/strings.1aout96
-rw-r--r--usr.bin/strings/strings.c11
-rw-r--r--usr.bin/strip/Makefile18
-rw-r--r--usr.bin/strip/strip.16
-rw-r--r--usr.bin/strip/strip.1aout73
-rw-r--r--usr.bin/strip/strip.c104
-rw-r--r--usr.bin/su/Makefile30
-rw-r--r--usr.bin/su/su.152
-rw-r--r--usr.bin/su/su.c295
-rw-r--r--usr.bin/symorder/Makefile5
-rw-r--r--usr.bin/symorder/symorder.196
-rw-r--r--usr.bin/symorder/symorder.c354
-rw-r--r--usr.bin/systat/Makefile4
-rw-r--r--usr.bin/systat/cmds.c6
-rw-r--r--usr.bin/systat/disks.c32
-rw-r--r--usr.bin/systat/extern.h1
-rw-r--r--usr.bin/systat/fetch.c2
-rw-r--r--usr.bin/systat/iostat.c23
-rw-r--r--usr.bin/systat/main.c26
-rw-r--r--usr.bin/systat/mbufs.c73
-rw-r--r--usr.bin/systat/netcmds.c6
-rw-r--r--usr.bin/systat/netstat.c30
-rw-r--r--usr.bin/systat/pigs.c4
-rw-r--r--usr.bin/systat/swap.c161
-rw-r--r--usr.bin/systat/systat.131
-rw-r--r--usr.bin/systat/vmstat.c187
-rw-r--r--usr.bin/tail/extern.h5
-rw-r--r--usr.bin/tail/forward.c30
-rw-r--r--usr.bin/tail/misc.c37
-rw-r--r--usr.bin/tail/read.c21
-rw-r--r--usr.bin/tail/reverse.c20
-rw-r--r--usr.bin/tail/tail.c11
-rw-r--r--usr.bin/talk/Makefile10
-rw-r--r--usr.bin/talk/ctl.c9
-rw-r--r--usr.bin/talk/ctl_transact.c16
-rw-r--r--usr.bin/talk/display.c61
-rw-r--r--usr.bin/talk/get_addrs.c33
-rw-r--r--usr.bin/talk/get_iface.c99
-rw-r--r--usr.bin/talk/get_names.c12
-rw-r--r--usr.bin/talk/init_disp.c75
-rw-r--r--usr.bin/talk/invite.c16
-rw-r--r--usr.bin/talk/io.c39
-rw-r--r--usr.bin/talk/look_up.c9
-rw-r--r--usr.bin/talk/msgs.c8
-rw-r--r--usr.bin/talk/talk.16
-rw-r--r--usr.bin/talk/talk.c17
-rw-r--r--usr.bin/talk/talk.h36
-rw-r--r--usr.bin/tclsh/Makefile20
-rw-r--r--usr.bin/tconv/Makefile12
-rw-r--r--usr.bin/tconv/quit.c72
-rw-r--r--usr.bin/tconv/tconv.1179
-rw-r--r--usr.bin/tconv/tconv.c1384
-rw-r--r--usr.bin/tcopy/tcopy.c71
-rw-r--r--usr.bin/tee/tee.c2
-rw-r--r--usr.bin/telnet/Makefile24
-rw-r--r--usr.bin/telnet/authenc.c10
-rw-r--r--usr.bin/telnet/commands.c299
-rw-r--r--usr.bin/telnet/externs.h16
-rw-r--r--usr.bin/telnet/main.c17
-rw-r--r--usr.bin/telnet/network.c4
-rw-r--r--usr.bin/telnet/ring.c53
-rw-r--r--usr.bin/telnet/ring.h9
-rw-r--r--usr.bin/telnet/sys_bsd.c73
-rw-r--r--usr.bin/telnet/telnet.120
-rw-r--r--usr.bin/telnet/telnet.c118
-rw-r--r--usr.bin/telnet/terminal.c19
-rw-r--r--usr.bin/telnet/utilities.c72
-rw-r--r--usr.bin/tftp/main.c27
-rw-r--r--usr.bin/time/time.18
-rw-r--r--usr.bin/time/time.c41
-rw-r--r--usr.bin/tip/Makefile53
-rw-r--r--usr.bin/tip/Makefile.inc5
-rw-r--r--usr.bin/tip/NEWS65
-rw-r--r--usr.bin/tip/README63
-rw-r--r--usr.bin/tip/TODO38
-rw-r--r--usr.bin/tip/libacu/Makefile12
-rw-r--r--usr.bin/tip/libacu/acucommon.c190
-rw-r--r--usr.bin/tip/libacu/acucommon.h6
-rw-r--r--usr.bin/tip/libacu/biz22.c188
-rw-r--r--usr.bin/tip/libacu/biz31.c249
-rw-r--r--usr.bin/tip/libacu/courier.c334
-rw-r--r--usr.bin/tip/libacu/df.c129
-rw-r--r--usr.bin/tip/libacu/dn11.c154
-rw-r--r--usr.bin/tip/libacu/hayes.c306
-rw-r--r--usr.bin/tip/libacu/multitech.c402
-rw-r--r--usr.bin/tip/libacu/t3000.c350
-rw-r--r--usr.bin/tip/libacu/tod.c107
-rw-r--r--usr.bin/tip/libacu/tod.h9
-rw-r--r--usr.bin/tip/libacu/unidialer.c800
-rw-r--r--usr.bin/tip/libacu/v3451.c215
-rw-r--r--usr.bin/tip/libacu/v831.c272
-rw-r--r--usr.bin/tip/libacu/ventel.c252
-rw-r--r--usr.bin/tip/tip/Makefile25
-rw-r--r--usr.bin/tip/tip/acu.c206
-rw-r--r--usr.bin/tip/tip/acutab.c114
-rw-r--r--usr.bin/tip/tip/cmds.c1042
-rw-r--r--usr.bin/tip/tip/cmdtab.c65
-rw-r--r--usr.bin/tip/tip/cu.c136
-rwxr-xr-xusr.bin/tip/tip/dial.sh21
-rw-r--r--usr.bin/tip/tip/hunt.c (renamed from usr.bin/tip/uucplock.c)127
-rw-r--r--usr.bin/tip/tip/log.c87
-rw-r--r--usr.bin/tip/tip/modems.5140
-rw-r--r--usr.bin/tip/tip/partab.c58
-rw-r--r--usr.bin/tip/tip/pathnames.h58
-rw-r--r--usr.bin/tip/tip/remcap.c426
-rw-r--r--usr.bin/tip/tip/remote.c286
-rw-r--r--usr.bin/tip/tip/tip.1442
-rw-r--r--usr.bin/tip/tip/tip.c (renamed from usr.bin/tip/tip.c)113
-rw-r--r--usr.bin/tip/tip/tip.h (renamed from usr.bin/tip/tip.h)102
-rw-r--r--usr.bin/tip/tip/tipconf.h124
-rw-r--r--usr.bin/tip/tip/tipout.c (renamed from usr.bin/tip/tipout.c)12
-rw-r--r--usr.bin/tip/tip/value.c353
-rw-r--r--usr.bin/tip/tip/vars.c117
-rw-r--r--usr.bin/tn3270/Makefile16
-rw-r--r--usr.bin/tn3270/api/asc_ebc.c2
-rw-r--r--usr.bin/tn3270/ascii/map3270.c2
-rw-r--r--usr.bin/tn3270/ascii/mset.c4
-rw-r--r--usr.bin/tn3270/ctlr/api.c9
-rw-r--r--usr.bin/tn3270/ctlr/api.h4
-rw-r--r--usr.bin/tn3270/ctlr/inbound.c2
-rw-r--r--usr.bin/tn3270/distribution/makefile_4.24
-rw-r--r--usr.bin/tn3270/distribution/sys_dos/system.c5
-rw-r--r--usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c4
-rw-r--r--usr.bin/tn3270/general/general.h2
-rw-r--r--usr.bin/tn3270/mset/Makefile20
-rw-r--r--usr.bin/tn3270/sys_curses/system.c5
-rw-r--r--usr.bin/tn3270/sys_curses/termout.c29
-rw-r--r--usr.bin/tn3270/tn3270/Makefile54
-rw-r--r--usr.bin/tn3270/tn3270/tn3270.12
-rw-r--r--usr.bin/tn3270/tools/mkastods/Makefile2
-rw-r--r--usr.bin/tn3270/tools/mkastosc/Makefile2
-rw-r--r--usr.bin/tn3270/tools/mkastosc/mkastosc.c2
-rw-r--r--usr.bin/tn3270/tools/mkdctype/Makefile2
-rw-r--r--usr.bin/tn3270/tools/mkdstoas/Makefile2
-rw-r--r--usr.bin/tn3270/tools/mkhits/Makefile2
-rw-r--r--usr.bin/tn3270/tools/mkhits/dohits.c3
-rw-r--r--usr.bin/top/Makefile28
-rw-r--r--usr.bin/top/machine.c935
-rw-r--r--usr.bin/top/sigdesc.h42
-rw-r--r--usr.bin/top/top.local.147
-rw-r--r--usr.bin/top/top.local.h68
-rw-r--r--usr.bin/touch/touch.110
-rw-r--r--usr.bin/touch/touch.c8
-rw-r--r--usr.bin/tput/Makefile4
-rw-r--r--usr.bin/tput/tput.157
-rw-r--r--usr.bin/tput/tput.c46
-rw-r--r--usr.bin/tr/str.c39
-rw-r--r--usr.bin/tr/tr.c7
-rw-r--r--usr.bin/true/true.14
-rw-r--r--usr.bin/tset/extern.h12
-rw-r--r--usr.bin/tset/map.c41
-rw-r--r--usr.bin/tset/misc.c4
-rw-r--r--usr.bin/tset/set.c6
-rw-r--r--usr.bin/tset/tset.c22
-rw-r--r--usr.bin/tsort/tsort.18
-rw-r--r--usr.bin/tsort/tsort.c25
-rw-r--r--usr.bin/tty/tty.16
-rw-r--r--usr.bin/tty/tty.c2
-rw-r--r--usr.bin/ul/ul.111
-rw-r--r--usr.bin/ul/ul.c4
-rw-r--r--usr.bin/uname/uname.19
-rw-r--r--usr.bin/uname/uname.c2
-rw-r--r--usr.bin/uniq/uniq.c2
-rw-r--r--usr.bin/units/Makefile9
-rw-r--r--usr.bin/units/README18
-rw-r--r--usr.bin/units/pathnames.h33
-rw-r--r--usr.bin/units/units.1158
-rw-r--r--usr.bin/units/units.c708
-rw-r--r--usr.bin/units/units.lib610
-rw-r--r--usr.bin/unvis/unvis.12
-rw-r--r--usr.bin/unvis/unvis.c2
-rw-r--r--usr.bin/users/users.14
-rw-r--r--usr.bin/users/users.c2
-rw-r--r--usr.bin/uucp/acucntrl/Makefile10
-rw-r--r--usr.bin/uucp/acucntrl/acucntrl.8165
-rw-r--r--usr.bin/uucp/uupoll/Makefile10
-rw-r--r--usr.bin/uucp/uusnap/Makefile8
-rw-r--r--usr.bin/uudecode/uudecode.c100
-rw-r--r--usr.bin/uuencode/Makefile7
-rw-r--r--usr.bin/uuencode/uuencode.131
-rw-r--r--usr.bin/uuencode/uuencode.c2
-rw-r--r--usr.bin/uuencode/uuencode.format.516
-rw-r--r--usr.bin/vacation/Makefile5
-rw-r--r--usr.bin/vacation/vacation.118
-rw-r--r--usr.bin/vacation/vacation.c108
-rw-r--r--usr.bin/vgrind/Makefile24
-rw-r--r--usr.bin/vgrind/regexp.c25
-rw-r--r--usr.bin/vgrind/vfontedpr.c47
-rw-r--r--usr.bin/vgrind/vgrind.124
-rw-r--r--usr.bin/vgrind/vgrind.sh20
-rw-r--r--usr.bin/vgrind/vgrindefs.515
-rw-r--r--usr.bin/vgrind/vgrindefs.src17
-rw-r--r--usr.bin/vi/Makefile202
-rw-r--r--usr.bin/vi/config.h194
-rw-r--r--usr.bin/vi/pathnames.h45
-rw-r--r--usr.bin/vi/port.h185
-rw-r--r--usr.bin/vis/foldit.c2
-rw-r--r--usr.bin/vis/vis.14
-rw-r--r--usr.bin/vis/vis.c19
-rw-r--r--usr.bin/vmstat/Makefile6
-rw-r--r--usr.bin/vmstat/names.c31
-rw-r--r--usr.bin/vmstat/vmstat.8269
-rw-r--r--usr.bin/vmstat/vmstat.c169
-rw-r--r--usr.bin/w/Makefile4
-rw-r--r--usr.bin/w/extern.h2
-rw-r--r--usr.bin/w/pr_time.c31
-rw-r--r--usr.bin/w/uptime.14
-rw-r--r--usr.bin/w/w.15
-rw-r--r--usr.bin/w/w.c76
-rw-r--r--usr.bin/wall/wall.c21
-rw-r--r--usr.bin/wc/wc.16
-rw-r--r--usr.bin/wc/wc.c116
-rw-r--r--usr.bin/what/what.17
-rw-r--r--usr.bin/what/what.c2
-rw-r--r--usr.bin/whereis/Makefile6
-rw-r--r--usr.bin/whereis/whereis.1137
-rw-r--r--usr.bin/whereis/whereis.pl243
-rw-r--r--usr.bin/which/Makefile9
-rw-r--r--usr.bin/which/which.165
-rwxr-xr-xusr.bin/which/which.pl55
-rw-r--r--usr.bin/who/who.13
-rw-r--r--usr.bin/who/who.c14
-rw-r--r--usr.bin/whois/Makefile7
-rw-r--r--usr.bin/whois/whois.14
-rw-r--r--usr.bin/whois/whois.c10
-rw-r--r--usr.bin/window/Makefile3
-rw-r--r--usr.bin/window/char.c74
-rw-r--r--usr.bin/window/char.h14
-rw-r--r--usr.bin/window/cmd.c2
-rw-r--r--usr.bin/window/cmd1.c2
-rw-r--r--usr.bin/window/compress.c1
-rw-r--r--usr.bin/window/main.c2
-rw-r--r--usr.bin/window/mystring.h65
-rw-r--r--usr.bin/window/scanner.c45
-rw-r--r--usr.bin/window/ttgeneric.c2
-rw-r--r--usr.bin/window/ttinit.c1
-rw-r--r--usr.bin/window/window.112
-rw-r--r--usr.bin/window/ww.h4
-rw-r--r--usr.bin/window/wwclreol.c2
-rw-r--r--usr.bin/window/wwend.c2
-rw-r--r--usr.bin/window/wwgets.c9
-rw-r--r--usr.bin/window/wwinit.c33
-rw-r--r--usr.bin/window/wwinschar.c2
-rw-r--r--usr.bin/window/wwlabel.c14
-rw-r--r--usr.bin/window/wwopen.c5
-rw-r--r--usr.bin/window/wwwrite.c6
-rw-r--r--usr.bin/window/xx.c1
-rw-r--r--usr.bin/write/write.18
-rw-r--r--usr.bin/write/write.c106
-rw-r--r--usr.bin/xargs/xargs.111
-rw-r--r--usr.bin/xargs/xargs.c33
-rw-r--r--usr.bin/xinstall/Makefile4
-rw-r--r--usr.bin/xinstall/install.163
-rw-r--r--usr.bin/xinstall/xinstall.c525
-rw-r--r--usr.bin/xlint/Makefile5
-rw-r--r--usr.bin/xlint/lint1/Makefile19
-rw-r--r--usr.bin/xlint/lint1/cgram.y1686
-rw-r--r--usr.bin/xlint/lint1/decl.c3135
-rw-r--r--usr.bin/xlint/lint1/emit.c241
-rw-r--r--usr.bin/xlint/lint1/emit1.c587
-rw-r--r--usr.bin/xlint/lint1/err.c543
-rw-r--r--usr.bin/xlint/lint1/externs.h56
-rw-r--r--usr.bin/xlint/lint1/externs1.h281
-rw-r--r--usr.bin/xlint/lint1/func.c1261
-rw-r--r--usr.bin/xlint/lint1/init.c513
-rw-r--r--usr.bin/xlint/lint1/lint.h118
-rw-r--r--usr.bin/xlint/lint1/lint1.h380
-rw-r--r--usr.bin/xlint/lint1/main1.c183
-rw-r--r--usr.bin/xlint/lint1/mem.c91
-rw-r--r--usr.bin/xlint/lint1/mem1.c358
-rw-r--r--usr.bin/xlint/lint1/op.h120
-rw-r--r--usr.bin/xlint/lint1/param.h120
-rw-r--r--usr.bin/xlint/lint1/scan.l1427
-rw-r--r--usr.bin/xlint/lint1/tree.c3927
-rw-r--r--usr.bin/xlint/lint2/Makefile13
-rw-r--r--usr.bin/xlint/lint2/chk.c1462
-rw-r--r--usr.bin/xlint/lint2/emit2.c236
-rw-r--r--usr.bin/xlint/lint2/externs2.h87
-rw-r--r--usr.bin/xlint/lint2/hash.c123
-rw-r--r--usr.bin/xlint/lint2/lint2.h177
-rw-r--r--usr.bin/xlint/lint2/main2.c190
-rw-r--r--usr.bin/xlint/lint2/mem2.c97
-rw-r--r--usr.bin/xlint/lint2/msg.c157
-rw-r--r--usr.bin/xlint/lint2/read.c1135
-rw-r--r--usr.bin/xlint/llib/Makefile21
-rw-r--r--usr.bin/xlint/llib/llib-lposix311
-rw-r--r--usr.bin/xlint/llib/llib-lstdc252
-rw-r--r--usr.bin/xlint/xlint/Makefile17
-rw-r--r--usr.bin/xlint/xlint/lint.1509
-rw-r--r--usr.bin/xlint/xlint/pathnames.h38
-rw-r--r--usr.bin/xlint/xlint/xlint.c771
-rw-r--r--usr.bin/xstr/xstr.c6
-rw-r--r--usr.bin/yacc/Makefile7
-rw-r--r--usr.bin/yacc/closure.c21
-rw-r--r--usr.bin/yacc/defs.h69
-rw-r--r--usr.bin/yacc/error.c37
-rw-r--r--usr.bin/yacc/lalr.c43
-rw-r--r--usr.bin/yacc/lr0.c46
-rw-r--r--usr.bin/yacc/main.c97
-rw-r--r--usr.bin/yacc/mkpar.c44
-rw-r--r--usr.bin/yacc/output.c97
-rw-r--r--usr.bin/yacc/reader.c102
-rw-r--r--usr.bin/yacc/skeleton.c62
-rw-r--r--usr.bin/yacc/symtab.c14
-rw-r--r--usr.bin/yacc/test/ftp.tab.c2
-rw-r--r--usr.bin/yacc/verbose.c29
-rw-r--r--usr.bin/yacc/warshall.c8
-rw-r--r--usr.bin/yacc/yacc.113
-rw-r--r--usr.bin/yacc/yyfix.116
-rw-r--r--usr.bin/ypcat/Makefile6
-rw-r--r--usr.bin/ypcat/ypcat.170
-rw-r--r--usr.bin/ypcat/ypcat.c143
-rw-r--r--usr.bin/ypmatch/Makefile6
-rw-r--r--usr.bin/ypmatch/ypmatch.171
-rw-r--r--usr.bin/ypmatch/ypmatch.c135
-rw-r--r--usr.bin/ypwhich/Makefile7
-rw-r--r--usr.bin/ypwhich/ypwhich.c256
1346 files changed, 236155 insertions, 9261 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index f6028ca..5f9e8a2 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -1,28 +1,58 @@
-# @(#)Makefile 8.3 (Berkeley) 1/7/94
+# From: @(#)Makefile 8.3 (Berkeley) 1/7/94
+# $Id: Makefile,v 1.85 1997/05/29 15:03:32 wpaul Exp $
-SUBDIR= apply apropos ar at banner basename bc bdes biff cal calendar \
- cap_mkdb checknr chflags chpass cksum col colcrt colrm column \
- comm compress cpp ctags cut dc deroff diction diff dirname du \
- env error ex expand false file find finger fmt fold fpr from \
- fsplit fstat ftp gcore gprof graph grep head hexdump id indent \
- join jot kdump ktrace lam last lastcomm learn leave locate \
- lock logger login logname lorder m4 mail make man mesg mkdep \
- mkfifo mklocale mkstr more msgs mt netstat nfsstat nice nm nohup \
- pagesize passwd paste patch plot pr printenv printf ptx quota \
- ranlib rdist renice rev rlogin rs rsh ruptime rwho sccs \
- script sed shar showmount size soelim sort spell spline split \
- strings strip struct su talk tcopy tee telnet tftp time tip \
- tn3270 touch tput tr true tset tsort tty ul uname unexpand \
- unifdef uniq units unvis users uucp uudecode uuencode vacation \
- vgrind vis w wall wc what whatis whereis who whois window write \
- xargs xinstall xsend xstr yacc yes
+# XXX MISSING: deroff diction graph learn plot
+# spell spline struct units xsend
+# XXX Use GNU versions: apropos bc dc diff grep ld man patch ptx uucp whatis
+# Moved to secure: bdes
+#
+SUBDIR= apply ar at banner basename biff brandelf cal calendar \
+ cap_mkdb chat checknr chflags chpass cksum col colcrt colldef colrm \
+ column comm compile_et compress chkey cpp ctags cut dig \
+ dirname dnsquery du ee env error expand f2c false fetch file file2c \
+ find finger fmt fold fpr from fsplit fstat ftp gcore gencat getopt \
+ global gprof head hexdump host id indent ipcrm ipcs \
+ join jot kdump ktrace key keyinfo keyinit keylogin keylogout killall \
+ lam last lastcomm leave lex limits locate lock lockf logger login \
+ logname lorder lsvfs m4 mail make mesg mkdep mkfifo mklocale mkstr \
+ mk_cmds modstat more msgs mt netstat newkey nfsstat nice \
+ nm nohup opieinfo opiekey opiepasswd pagesize passwd paste pr printenv \
+ printf quota ranlib rdist renice rev rlogin rpcgen \
+ rpcinfo rs rsh rup ruptime rusers rwall \
+ rwho script sed sgmlfmt sgmls shar showmount size soelim split \
+ strings strip su symorder talk tconv tcopy tee tftp time \
+ tip tn3270 top touch tput tr true tset tsort tty ul uname \
+ unexpand unifdef uniq units unvis users uudecode uuencode vacation \
+ vgrind vi vis w wall wc what whereis which who whois window \
+ write xargs xinstall xlint xstr yacc yes ypcat ypmatch ypwhich
+SUBDIR+=gprof4
+
+.if !defined(NOTCL) && exists (${.CURDIR}/../contrib/tcl) && \
+ exists(${.CURDIR}/tclsh) && exists (${.CURDIR}/../lib/libtcl)
+SUBDIR+=tclsh
+.endif
+
+.if !exists(${.CURDIR}/../eBones) || defined(NOSECURE) || !defined(MAKE_EBONES)
+SUBDIR+=telnet
+.else
+.if defined(RELEASEDIR)
+# releases do need both
+SUBDIR+=telnet
+.endif
+SUBDIR+= ../eBones/usr.bin/telnet
+.endif
# Cmp, look and tail all use mmap, so new-VM only.
# F77 and pascal are VAX/Tahoe only.
-.if ${MACHINE} == "hp300"
+.if make(clean) || make(cleandir)
+# XXX Should have `f77', `pascal' & `vmstat.sparc' judging by the
+# machine dependant lines, but we don't have them
+SUBDIR+=cmp kzip look sasc systat tail vmstat
+.elif ${MACHINE} == "hp300"
SUBDIR+=cmp ld look systat tail vmstat
.elif ${MACHINE} == "i386"
-SUBDIR+=cmp ld look systat tail vmstat
+SUBDIR+=cmp kzip look sasc systat tail vmstat
+# XXX Use gnu/usr.bin/ld for now
.elif ${MACHINE} == "luna68k"
SUBDIR+=cmp ld look systat tail vmstat
.elif ${MACHINE} == "mips"
diff --git a/usr.bin/apply/apply.1 b/usr.bin/apply/apply.1
index dd7a9ee..9ab0a07 100644
--- a/usr.bin/apply/apply.1
+++ b/usr.bin/apply/apply.1
@@ -80,7 +80,7 @@ is run, without arguments, once for each
If any sequences of
.Dq Li \&%d
occur in command, the
-.Fl n
+.Fl #
option is ignored.
.It Fl a Ns Ar c
The use of the character
diff --git a/usr.bin/apply/apply.c b/usr.bin/apply/apply.c
index a8634a9..78e9062 100644
--- a/usr.bin/apply/apply.c
+++ b/usr.bin/apply/apply.c
@@ -63,7 +63,7 @@ main(argc, argv)
debug = 0;
magic = '%'; /* Default magic char is `%'. */
nargs = -1;
- while ((ch = getopt(argc, argv, "a:d0123456789")) != EOF)
+ while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
switch (ch) {
case 'a':
if (optarg[1] != '\0')
@@ -111,7 +111,7 @@ main(argc, argv)
if ((cmd = malloc(sizeof("exec ") - 1 +
strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1)) == NULL)
err(1, NULL);
-
+
if (n == 0) {
/* If nargs not set, default to a single argument. */
if (nargs == -1)
diff --git a/usr.bin/ar/Makefile b/usr.bin/ar/Makefile
index f79edaa..94bb84f 100644
--- a/usr.bin/ar/Makefile
+++ b/usr.bin/ar/Makefile
@@ -3,14 +3,8 @@
PROG= ar
CFLAGS+=-I${.CURDIR}
SRCS= append.c ar.c archive.c contents.c delete.c extract.c misc.c \
- move.c print.c replace.c
-MAN1= ar.0
-CLEANFILES=ar.5.0
-
-ar.0: ar.5.0
-
-afterinstall:
- install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} ar.5.0 \
- ${DESTDIR}${MANDIR}5/ar.0
+ move.c print.c replace.c
+MAN1= ar.1
+MAN5= ar.5
.include <bsd.prog.mk>
diff --git a/usr.bin/ar/append.c b/usr.bin/ar/append.c
index 89db986..ea2e04c 100644
--- a/usr.bin/ar/append.c
+++ b/usr.bin/ar/append.c
@@ -71,7 +71,7 @@ append(argv)
/* Read from disk, write to an archive; pad on write. */
SETCF(0, 0, afd, archive, WPAD);
- for (eval = 0; file = *argv++;) {
+ for (eval = 0; (file = *argv++); ) {
if ((fd = open(file, O_RDONLY)) < 0) {
warn("%s", file);
eval = 1;
@@ -85,5 +85,5 @@ append(argv)
(void)close(fd);
}
close_archive(afd);
- return (eval);
+ return (eval);
}
diff --git a/usr.bin/ar/ar.1 b/usr.bin/ar/ar.1
index fd5ce4f..e9118e7 100644
--- a/usr.bin/ar/ar.1
+++ b/usr.bin/ar/ar.1
@@ -32,32 +32,31 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)ar.1 8.4 (Berkeley) 4/28/95
+.\" @(#)ar.1 8.1 (Berkeley) 6/29/93
+.\" $Id: ar.1,v 1.4 1997/02/22 19:54:01 peter Exp $
.\"
-.Dd "April 28, 1995"
-.Dt AR 1
-.Os
+.Dd June 29, 1993
+.Dt AR 1
.Sh NAME
-.Nm ar
+.Nm ar
.Nd create and maintain library archives
.Sh SYNOPSIS
.Nm ar
-.Fl d
-.Op Fl \Tv
+.Fl d
+.Op Fl \Tv
.Ar archive file ...
.Nm ar
.Fl m
-.Op Fl \Tv
+.Op Fl \Tv
.Ar archive file ...
.Nm ar
.Fl m
-.Op Fl abiTv
+.Op Fl abiTv
.Ar position archive file ...
.Nm ar
.Fl p
.Op Fl \Tv
-.Ar archive
-.Op Ar file ...
+.Ar archive [file ...]
.Nm ar
.Fl q
.Op Fl cTv
@@ -73,13 +72,11 @@
.Nm ar
.Fl t
.Op Fl \Tv
-.Ar archive
-.Op Ar file ...
+.Ar archive [file ...]
.Nm ar
.Fl x
.Op Fl ouTv
-.Ar archive
-.Op Ar file ...
+.Ar archive [file ...]
.Sh DESCRIPTION
The
.Nm ar
@@ -104,14 +101,14 @@ The normal use of
.Nm ar
is for the creation and maintenance of libraries suitable for use with
the loader (see
-.Xr ld 1 ),
+.Xr ld 1 )
although it is not restricted to this purpose.
The options are as follows:
.Bl -tag -width indent
.It Fl a
-A positioning modifier used with the options
-.Fl r
-and
+A positioning modifier used with the options
+.Fl r
+and
.Fl m .
The files are entered or moved
.Em after
@@ -120,8 +117,8 @@ the archive member
which must be specified.
.It Fl b
A positioning modifier used with the options
-.Fl r
-and
+.Fl r
+and
.Fl m .
The files are entered or moved
.Em before
@@ -131,7 +128,7 @@ which must be specified.
.It Fl c
Whenever an archive is created, an informational message to that effect
is written to standard error.
-If the
+If the
.Fl c
option is specified,
.Nm ar
@@ -139,17 +136,18 @@ creates the archive silently.
.It Fl d
Delete the specified archive files.
.It Fl i
-Identical to the
+Identical to the
.Fl b
option.
.It Fl m
Move the specified archive files within the archive.
-If one of the options
-.Fl a ,
-.Fl b
-or
+If one of the options
+.Fl a ,
+.Fl b
+or
.Fl i
-is specified, the files are moved before or after the
+is specified, the files are moved
+before or after the
.Ar position
file in the archive.
If none of those options are specified, the files are moved
@@ -166,7 +164,7 @@ are written in the order they appear in the archive.
.It Fl q
(Quickly) append the specified files to the archive.
If the archive does not exist a new archive file is created.
-Much faster than the
+Much faster than the
.Fl r
option, when creating a large archive
piece-by-piece, as no checking is done to see if the files already
@@ -176,10 +174,10 @@ Replace or add the specified files to the archive.
If the archive does not exist a new archive file is created.
Files that replace existing files do not change the order of the files
within the archive.
-New files are appended to the archive unless one of the options
+New files are appended to the archive unless one of the options
.Fl a ,
.Fl b
-or
+or
.Fl i
is specified.
.It Fl T
@@ -201,30 +199,30 @@ each on a separate line.
If no files are specified, all files in the archive are listed.
.It Fl u
Update files.
-When used with the
+When used with the
.Fl r
option, files in the archive will be replaced
only if the disk file has a newer modification time than the file in
the archive.
-When used with the
+When used with the
.Fl x
option, files in the archive will be extracted
only if the archive file has a newer modification time than the file
on disk.
.It Fl v
Provide verbose output.
-When used with the
-.Fl d ,
-.Fl m ,
-.Fl q
-or
+When used with the
+.Fl d ,
+.Fl m ,
+.Fl q
+or
.Fl x
options,
.Nm ar
gives a file-by-file description of the archive modification.
This description consists of three, white-space separated fields: the
option letter, a dash (``-'') and the file name.
-When used with the
+When used with the
.Fl r
option,
.Nm ar
@@ -232,8 +230,8 @@ displays the description as above, but the initial letter is an ``a'' if
the file is added to the archive and an ``r'' if the file replaces a file
already in the archive.
.Pp
-When used with the
-.Fl p
+When used with the
+.Fl p
option,
the name of each printed file,
enclosed in less-than (``<'') and greater-than (``>'') characters,
@@ -242,7 +240,7 @@ the contents of the file;
it is preceded by a single newline character, and
followed by two newline characters.
.Pp
-When used with the
+When used with the
.Fl t
option,
.Nm ar
@@ -251,7 +249,7 @@ the archive.
This listing consists of eight, white-space separated fields:
the file permissions (see
.Xr strmode 3 ),
-the decimal user and group ID's separated by a single slash (``/''),
+the decimal user and group ID's, separated by a single slash (``/''),
the file size (in bytes), the file modification time (in the
.Xr date 1
format ``%b %e %H:%M %Y''), and the name of the file.
@@ -264,7 +262,7 @@ the current directory.
If the file does not exist, it is created; if it does exist, the owner
and group will be unchanged.
The file access and modification times are the time of the extraction
-(but see the
+(but see the
.Fl o
option).
The file permissions will be set to those of the file when it was entered
@@ -297,20 +295,20 @@ This implementation of
.Nm ar
is backward compatible with previous versions of
.Nm ar
-in that it can read and write (using the
+in that it can read and write (using the
.Fl T
option) historic archives.
-The
+The
.Fl T
option is provided for compatibility only, and will be deleted
in a future release.
See
.Xr ar 5
for more information.
-.SH STANDARDS
+.Sh STANDARDS
The
.Nm ar
-utility is expected to offer a superset of the
+utility is expected to offer a superset of the
.St -p1003.2
functionality.
.Sh SEE ALSO
diff --git a/usr.bin/ar/ar.1aout b/usr.bin/ar/ar.1aout
new file mode 100644
index 0000000..e9118e7
--- /dev/null
+++ b/usr.bin/ar/ar.1aout
@@ -0,0 +1,318 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Hugh Smith at The University of Guelph.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ar.1 8.1 (Berkeley) 6/29/93
+.\" $Id: ar.1,v 1.4 1997/02/22 19:54:01 peter Exp $
+.\"
+.Dd June 29, 1993
+.Dt AR 1
+.Sh NAME
+.Nm ar
+.Nd create and maintain library archives
+.Sh SYNOPSIS
+.Nm ar
+.Fl d
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl abiTv
+.Ar position archive file ...
+.Nm ar
+.Fl p
+.Op Fl \Tv
+.Ar archive [file ...]
+.Nm ar
+.Fl q
+.Op Fl cTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl cuTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl abciuTv
+.Ar position archive file ...
+.Nm ar
+.Fl t
+.Op Fl \Tv
+.Ar archive [file ...]
+.Nm ar
+.Fl x
+.Op Fl ouTv
+.Ar archive [file ...]
+.Sh DESCRIPTION
+The
+.Nm ar
+utility creates and maintains groups of files combined into an archive.
+Once an archive has been created, new files can be added and existing
+files can be extracted, deleted, or replaced.
+.Pp
+Files are named in the archive by a single component, i.e., if a file
+referenced by a path containing a slash (``/'') is archived it will be
+named by the last component of that path.
+When matching paths listed on the command line against file names stored
+in the archive, only the last component of the path will be compared.
+.Pp
+All informational and error messages use the path listed on the command
+line, if any was specified; otherwise the name in the archive is used.
+If multiple files in the archive have the same name, and paths are listed
+on the command line to ``select'' archive files for an operation, only the
+.Em first
+file with a matching name will be selected.
+.Pp
+The normal use of
+.Nm ar
+is for the creation and maintenance of libraries suitable for use with
+the loader (see
+.Xr ld 1 )
+although it is not restricted to this purpose.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
+The files are entered or moved
+.Em after
+the archive member
+.Ar position ,
+which must be specified.
+.It Fl b
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
+The files are entered or moved
+.Em before
+the archive member
+.Ar position ,
+which must be specified.
+.It Fl c
+Whenever an archive is created, an informational message to that effect
+is written to standard error.
+If the
+.Fl c
+option is specified,
+.Nm ar
+creates the archive silently.
+.It Fl d
+Delete the specified archive files.
+.It Fl i
+Identical to the
+.Fl b
+option.
+.It Fl m
+Move the specified archive files within the archive.
+If one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified, the files are moved
+before or after the
+.Ar position
+file in the archive.
+If none of those options are specified, the files are moved
+to the end of the archive.
+.It Fl o
+Set the access and modification times of extracted files to the
+modification time of the file when it was entered into the archive.
+This will fail if the user is not the owner of the extracted file
+or the super-user.
+.It Fl p
+Write the contents of the specified archive files to the standard output.
+If no files are specified, the contents of all the files in the archive
+are written in the order they appear in the archive.
+.It Fl q
+(Quickly) append the specified files to the archive.
+If the archive does not exist a new archive file is created.
+Much faster than the
+.Fl r
+option, when creating a large archive
+piece-by-piece, as no checking is done to see if the files already
+exist in the archive.
+.It Fl r
+Replace or add the specified files to the archive.
+If the archive does not exist a new archive file is created.
+Files that replace existing files do not change the order of the files
+within the archive.
+New files are appended to the archive unless one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified.
+.It Fl T
+Select and/or name archive members using only the first fifteen characters
+of the archive member or command line file name.
+The historic archive format had sixteen bytes for the name, but some
+historic archiver and loader implementations were unable to handle names
+that used the entire space.
+This means that file names that are not unique in their first fifteen
+characters can subsequently be confused.
+A warning message is printed to the standard error output if any file
+names are truncated.
+(See
+.Xr ar 5
+for more information.)
+.It Fl t
+List the specified files in the order in which they appear in the archive,
+each on a separate line.
+If no files are specified, all files in the archive are listed.
+.It Fl u
+Update files.
+When used with the
+.Fl r
+option, files in the archive will be replaced
+only if the disk file has a newer modification time than the file in
+the archive.
+When used with the
+.Fl x
+option, files in the archive will be extracted
+only if the archive file has a newer modification time than the file
+on disk.
+.It Fl v
+Provide verbose output.
+When used with the
+.Fl d ,
+.Fl m ,
+.Fl q
+or
+.Fl x
+options,
+.Nm ar
+gives a file-by-file description of the archive modification.
+This description consists of three, white-space separated fields: the
+option letter, a dash (``-'') and the file name.
+When used with the
+.Fl r
+option,
+.Nm ar
+displays the description as above, but the initial letter is an ``a'' if
+the file is added to the archive and an ``r'' if the file replaces a file
+already in the archive.
+.Pp
+When used with the
+.Fl p
+option,
+the name of each printed file,
+enclosed in less-than (``<'') and greater-than (``>'') characters,
+is written to the standard output before
+the contents of the file;
+it is preceded by a single newline character, and
+followed by two newline characters.
+.Pp
+When used with the
+.Fl t
+option,
+.Nm ar
+displays an ``ls -l'' style listing of information about the members of
+the archive.
+This listing consists of eight, white-space separated fields:
+the file permissions (see
+.Xr strmode 3 ),
+the decimal user and group ID's, separated by a single slash (``/''),
+the file size (in bytes), the file modification time (in the
+.Xr date 1
+format ``%b %e %H:%M %Y''), and the name of the file.
+.It Fl x
+Extract the specified archive members into the files named by the command
+line arguments.
+If no members are specified, all the members of the archive are extracted into
+the current directory.
+.Pp
+If the file does not exist, it is created; if it does exist, the owner
+and group will be unchanged.
+The file access and modification times are the time of the extraction
+(but see the
+.Fl o
+option).
+The file permissions will be set to those of the file when it was entered
+into the archive; this will fail if the user is not the owner of the
+extracted file or the super-user.
+.El
+.Pp
+The
+.Nm ar
+utility exits 0 on success, and >0 if an error occurs.
+.Sh ENVIRONMENT
+.Bl -tag -width indent -compact
+.It Ev TMPDIR
+The pathname of the directory to use when creating temporary files.
+.El
+.Sh FILES
+.Bl -tag -width indent -compact
+.It Pa /tmp
+default temporary file directory
+.It Pa ar.XXXXXX
+temporary file names
+.El
+.Sh COMPATIBILITY
+By default,
+.Nm ar
+writes archives that may be incompatible with historic archives, as
+the format used for storing archive members with names longer than
+fifteen characters has changed.
+This implementation of
+.Nm ar
+is backward compatible with previous versions of
+.Nm ar
+in that it can read and write (using the
+.Fl T
+option) historic archives.
+The
+.Fl T
+option is provided for compatibility only, and will be deleted
+in a future release.
+See
+.Xr ar 5
+for more information.
+.Sh STANDARDS
+The
+.Nm ar
+utility is expected to offer a superset of the
+.St -p1003.2
+functionality.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ranlib 1 ,
+.Xr strmode 3 ,
+.Xr ar 5
diff --git a/usr.bin/ar/ar.5 b/usr.bin/ar/ar.5
new file mode 100644
index 0000000..b5d3258
--- /dev/null
+++ b/usr.bin/ar/ar.5
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ar.5.5 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt AR 5
+.Os
+.Sh NAME
+.Nm ar
+.Nd archive (library) file format
+.Sh SYNOPSIS
+.Fd #include <ar.h>
+.Sh DESCRIPTION
+The archive command
+.Nm ar
+combines several files into one.
+Archives are mainly used as libraries of object files intended to be
+loaded using the link-editor
+.Xr ld 1 .
+.Pp
+A file created with
+.Nm ar
+begins with the ``magic'' string "!<arch>\en".
+The rest of the archive is made up of objects, each of which is composed
+of a header for a file, a possible file name, and the file contents.
+The header is portable between machine architectures, and, if the file
+contents are printable, the archive is itself printable.
+.Pp
+The header is made up of six variable length
+.Tn ASCII
+fields, followed by a
+two character trailer.
+The fields are the object name (16 characters), the file last modification
+time (12 characters), the user and group id's (each 6 characters), the file
+mode (8 characters) and the file size (10 characters).
+All numeric fields are in decimal, except for the file mode which is in
+octal.
+.Pp
+The modification time is the file
+.Fa st_mtime
+field, i.e.,
+.Dv CUT
+seconds since
+the epoch.
+The user and group id's are the file
+.Fa st_uid
+and
+.Fa st_gid
+fields.
+The file mode is the file
+.Fa st_mode
+field.
+The file size is the file
+.Fa st_size
+field.
+The two-byte trailer is the string "\`\en".
+.Pp
+Only the name field has any provision for overflow.
+If any file name is more than 16 characters in length or contains an
+embedded space, the string "#1/" followed by the
+.Tn ASCII
+length of the
+name is written in the name field.
+The file size (stored in the archive header) is incremented by the length
+of the name.
+The name is then written immediately following the archive header.
+.Pp
+Any unused characters in any of these fields are written as space
+characters.
+If any fields are their particular maximum number of characters in
+length, there will be no separation between the fields.
+.Pp
+Objects in the archive are always an even number of bytes long; files
+which are an odd number of bytes long are padded with a newline (``\en'')
+character, although the size in the header does not reflect this.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr stat 2
+.Sh HISTORY
+There have been at least four
+.Nm ar
+formats.
+The first was denoted by the leading ``magic'' number 0177555 (stored as
+type int).
+These archives were almost certainly created on a 16-bit machine, and
+contain headers made up of five fields.
+The fields are the object name (8 characters), the file last modification
+time (type long), the user id (type char), the file mode (type char) and
+the file size (type unsigned int).
+Files were padded to an even number of bytes.
+.Pp
+The second was denoted by the leading ``magic'' number 0177545 (stored as
+type int).
+These archives may have been created on either 16 or 32-bit machines, and
+contain headers made up of six fields.
+The fields are the object name (14 characters), the file last modification
+time (type long), the user and group id's (each type char), the file mode
+(type int) and the file size (type long).
+Files were padded to an even number of bytes.
+.\" For more information on converting from this format see
+.\" .Xr arcv 8 .
+.Pp
+The current archive format (without support for long character names and
+names with embedded spaces) was introduced in
+.Bx 4.0 .
+The headers were the same as the current format, with the exception that
+names longer than 16 characters were truncated, and names with embedded
+spaces (and often trailing spaces) were not supported.
+It has been extended for these reasons,
+as described above.
+This format first appeared in
+.Bx 4.4 .
+.Sh COMPATIBILITY
+No archive format is currently specified by any standard.
+.At V
+has historically distributed archives in a different format from
+all of the above.
diff --git a/usr.bin/ar/ar.c b/usr.bin/ar/ar.c
index 38089e8..f27ff84 100644
--- a/usr.bin/ar/ar.c
+++ b/usr.bin/ar/ar.c
@@ -32,6 +32,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
@@ -54,6 +56,7 @@ static char sccsid[] = "@(#)ar.c 8.3 (Berkeley) 4/2/94";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <locale.h>
#include "archive.h"
#include "extern.h"
@@ -79,6 +82,8 @@ main(argc, argv)
char *p;
int (*fcall) __P((char **));
+ (void) setlocale(LC_TIME, "");;
+
if (argc < 3)
usage();
@@ -94,7 +99,7 @@ main(argc, argv)
argv[1] = p;
}
- while ((c = getopt(argc, argv, "abcdilmopqrTtuvx")) != EOF) {
+ while ((c = getopt(argc, argv, "abcdilmopqrTtuvx")) != -1) {
switch(c) {
case 'a':
options |= AR_A;
@@ -202,8 +207,8 @@ main(argc, argv)
usage();
}
- /* -dmqr require a list of archive elements. */
- if (options & (AR_D|AR_M|AR_Q|AR_R) && !*argv) {
+ /* -dmr require a list of archive elements. */
+ if (options & (AR_D|AR_M|AR_R) && !*argv) {
warnx("no archive members specified");
usage();
}
@@ -224,14 +229,15 @@ static void
usage()
{
- (void)fprintf(stderr, "usage: ar -d [-Tv] archive file ...\n");
- (void)fprintf(stderr, "\tar -m [-Tv] archive file ...\n");
- (void)fprintf(stderr, "\tar -m [-abiTv] position archive file ...\n");
- (void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
- (void)fprintf(stderr, "\tar -q [-cTv] archive file ...\n");
- (void)fprintf(stderr, "\tar -r [-cuTv] archive file ...\n");
- (void)fprintf(stderr, "\tar -r [-abciuTv] position archive file ...\n");
- (void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
- (void)fprintf(stderr, "\tar -x [-ouTv] archive [file ...]\n");
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: ar -d [-Tv] archive file ...",
+ " ar -m [-Tv] archive file ...",
+ " ar -m [-abiTv] position archive file ...",
+ " ar -p [-Tv] archive [file ...]",
+ " ar -q [-cTv] archive file ...",
+ " ar -r [-cuTv] archive file ...",
+ " ar -r [-abciuTv] position archive file ...",
+ " ar -t [-Tv] archive [file ...]",
+ " ar -x [-ouTv] archive [file ...]");
exit(1);
-}
+}
diff --git a/usr.bin/ar/archive.c b/usr.bin/ar/archive.c
index 9dd6b20..8ab1111 100644
--- a/usr.bin/ar/archive.c
+++ b/usr.bin/ar/archive.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)archive.c 8.4 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)archive.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/param.h>
@@ -63,7 +63,7 @@ open_archive(mode)
{
int created, fd, nr;
char buf[SARMAG];
-
+
created = 0;
if (mode & O_CREAT) {
mode |= O_EXCL;
@@ -81,14 +81,14 @@ open_archive(mode)
if ((fd = open(archive, mode, DEFFILEMODE)) < 0)
error(archive);
- /*
- * Attempt to place a lock on the opened file - if we get an
+ /*
+ * Attempt to place a lock on the opened file - if we get an
* error then someone is already working on this library (or
* it's going across NFS).
*/
opened: if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP)
error(archive);
-
+
/*
* If not created, O_RDONLY|O_RDWR indicates that it has to be
* in archive format.
@@ -225,17 +225,17 @@ put_arobj(cfp, sb)
name, OLDARMAXNAME, name);
(void)fflush(stderr);
}
- (void)sprintf(hb, HDR3, name, sb->st_mtimespec.ts_sec,
+ (void)sprintf(hb, HDR3, name, sb->st_mtimespec.tv_sec,
sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
ARFMAG);
lname = 0;
} else if (lname > sizeof(hdr->ar_name) || strchr(name, ' '))
(void)sprintf(hb, HDR1, AR_EFMT1, lname,
- sb->st_mtimespec.ts_sec, sb->st_uid, sb->st_gid,
+ sb->st_mtimespec.tv_sec, sb->st_uid, sb->st_gid,
sb->st_mode, sb->st_size + lname, ARFMAG);
else {
lname = 0;
- (void)sprintf(hb, HDR2, name, sb->st_mtimespec.ts_sec,
+ (void)sprintf(hb, HDR2, name, sb->st_mtimespec.tv_sec,
sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
ARFMAG);
}
@@ -280,7 +280,7 @@ copy_ar(cfp, size)
off_t sz;
int from, nr, nw, off, to;
char buf[8*1024];
-
+
if (!(sz = size))
return;
@@ -320,7 +320,7 @@ skip_arobj(fd)
{
off_t len;
- len = chdr.size + (chdr.size + chdr.lname & 1);
+ len = chdr.size + ( (chdr.size + chdr.lname) & 1);
if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
error(archive);
}
diff --git a/usr.bin/ar/contents.c b/usr.bin/ar/contents.c
index b2db77a..e000d535d 100644
--- a/usr.bin/ar/contents.c
+++ b/usr.bin/ar/contents.c
@@ -47,7 +47,6 @@ static char sccsid[] = "@(#)contents.c 8.3 (Berkeley) 4/2/94";
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
-#include <tzfile.h>
#include <unistd.h>
#include "archive.h"
@@ -65,7 +64,7 @@ contents(argv)
int afd, all;
struct tm *tp;
char *file, buf[25];
-
+
afd = open_archive(O_RDONLY);
for (all = !*argv; get_arobj(afd);) {
@@ -78,14 +77,16 @@ contents(argv)
(void)printf("%s %6d/%-6d %8qd ",
buf + 1, chdr.uid, chdr.gid, chdr.size);
tp = localtime(&chdr.date);
- (void)strftime(buf, sizeof(buf), "%b %e %H:%M %Y", tp);
- (void)printf("%s %s\n", buf, file);
+ (void)strftime(buf, sizeof(buf), "%c", tp);
+ buf[16] = '\0';
+ buf[24] = '\0';
+ (void)printf("%s %s %s\n", buf + 4, buf + 20, file);
} else
(void)printf("%s\n", file);
if (!all && !*argv)
break;
next: skip_arobj(afd);
- }
+ }
close_archive(afd);
if (*argv) {
diff --git a/usr.bin/ar/delete.c b/usr.bin/ar/delete.c
index 1ef332f..5824b61 100644
--- a/usr.bin/ar/delete.c
+++ b/usr.bin/ar/delete.c
@@ -93,4 +93,4 @@ delete(argv)
return (1);
}
return (0);
-}
+}
diff --git a/usr.bin/ar/extract.c b/usr.bin/ar/extract.c
index 2cc1ea0..c80e37c 100644
--- a/usr.bin/ar/extract.c
+++ b/usr.bin/ar/extract.c
@@ -125,4 +125,4 @@ extract(argv)
return (1);
}
return (0);
-}
+}
diff --git a/usr.bin/ar/misc.c b/usr.bin/ar/misc.c
index f9c0d14..bcd9711 100644
--- a/usr.bin/ar/misc.c
+++ b/usr.bin/ar/misc.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)misc.c 8.4 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/param.h>
@@ -73,7 +73,7 @@ tmp()
(void)sprintf(path, "%s/%s", envtmp, _NAME_ARTMP);
else
strcpy(path, _PATH_ARTMP);
-
+
sigfillset(&set);
(void)sigprocmask(SIG_BLOCK, &set, &oset);
if ((fd = mkstemp(path)) == -1)
@@ -97,7 +97,7 @@ files(argv)
for (list = argv; *list; ++list)
if (compare(*list)) {
p = *list;
- for (; list[0] = list[1]; ++list)
+ for (; (list[0] = list[1]); ++list)
continue;
return (p);
}
@@ -126,18 +126,15 @@ int
compare(dest)
char *dest;
{
-
- if (options & AR_TR)
- return (!strncmp(chdr.name, rname(dest), OLDARMAXNAME));
- return (!strcmp(chdr.name, rname(dest)));
+ int maxname = (options & AR_TR) ? OLDARMAXNAME : MAXNAMLEN;
+ return (!strncmp(chdr.name, rname(dest), maxname));
}
void
badfmt()
{
- errno = EFTYPE;
- err(1, "%s", archive);
+ errx(1, "%s: %s", archive, strerror(EFTYPE));
}
void
diff --git a/usr.bin/ar/move.c b/usr.bin/ar/move.c
index 1bbdef4..c2dba36 100644
--- a/usr.bin/ar/move.c
+++ b/usr.bin/ar/move.c
@@ -85,7 +85,7 @@ move(argv)
/* Read and write to an archive; pad on both. */
SETCF(afd, archive, 0, tname, RPAD|WPAD);
- for (curfd = tfd1; get_arobj(afd);) {
+ for (curfd = tfd1; get_arobj(afd);) {
if (*argv && (file = files(argv))) {
if (options & AR_V)
(void)printf("m - %s\n", file);
@@ -137,4 +137,4 @@ move(argv)
return (1);
}
return (0);
-}
+}
diff --git a/usr.bin/ar/replace.c b/usr.bin/ar/replace.c
index 4500b90..b9a6cc6 100644
--- a/usr.bin/ar/replace.c
+++ b/usr.bin/ar/replace.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)replace.c 8.4 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)replace.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/param.h>
@@ -55,7 +55,7 @@ static char sccsid[] = "@(#)replace.c 8.4 (Berkeley) 4/27/95";
/*
* replace --
* Replace or add named members to archive. Entries already in the
- * archive are swapped in place. Others are added before or after
+ * archive are swapped in place. Others are added before or after
* the key entry, based on the a, b and i options. If the u option
* is specified, modification dates select for replacement.
*/
@@ -81,7 +81,7 @@ replace(argv)
tfd1 = -1;
tfd2 = tmp();
goto append;
- }
+ }
tfd1 = tmp(); /* Files before key file. */
tfd2 = tmp(); /* Files after key file. */
@@ -103,7 +103,7 @@ replace(argv)
}
(void)fstat(sfd, &sb);
if (options & AR_U && sb.st_mtime <= chdr.date) {
- (void)close(sfd);
+ (void) close(sfd);
goto useold;
}
@@ -141,7 +141,7 @@ useold: SETCF(afd, archive, curfd, tname, RPAD|WPAD);
}
/* Append any left-over arguments to the end of the after file. */
-append: while (file = *argv++) {
+append: while ( (file = *argv++) ) {
if (options & AR_V)
(void)printf("a - %s\n", file);
if ((sfd = open(file, O_RDONLY)) < 0) {
@@ -156,7 +156,7 @@ append: while (file = *argv++) {
put_arobj(&cf, &sb);
(void)close(sfd);
}
-
+
(void)lseek(afd, (off_t)SARMAG, SEEK_SET);
SETCF(tfd1, tname, afd, archive, NOPAD);
@@ -175,4 +175,4 @@ append: while (file = *argv++) {
(void)ftruncate(afd, tsize + SARMAG);
close_archive(afd);
return (errflg);
-}
+}
diff --git a/usr.bin/at/LEGAL b/usr.bin/at/LEGAL
new file mode 100644
index 0000000..92b1b49
--- /dev/null
+++ b/usr.bin/at/LEGAL
@@ -0,0 +1,29 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+
+Sorry for the long wait, but there still were a few things to
+be ironed out in at, which I've finally done :-)
+
+The FreeBSD team does have my permission to use at, version 2.9,
+under the BSD license.
+
+You'll find it on sunsite.unc.edu's Incoming, hopefully; the
+md5 checksum is
+
+3ba2ca3c0e87e1a04feae2c6c1376b0d at-2.9.tgz
+
+Best regards
+ Thomas
+- --
+Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet.
+The joy of engineering is to find a straight line on a double
+logarithmic diagram.
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2i
+
+iQCVAwUBMCjVrPBu+cbJcKCVAQFNiQP/dpWP57s/E8plVGUD3zfgOXDmKUvg8U7a
+VwRzJrIMuSgnSJs0wkpvcomc3NLicipfX7hhWLh/xatPM2YbF7O5HZoNdvWvexD2
+1Y67zJ+0HFb1mPnSBOrS5RFiQAe3KqmGec6E14Rih/qNoFQZBVRFXZ4xxuwP+0Rs
+e2U+TVTUz6A=
+=TvyW
+-----END PGP SIGNATURE-----
diff --git a/usr.bin/at/Makefile b/usr.bin/at/Makefile
new file mode 100644
index 0000000..6e1581c
--- /dev/null
+++ b/usr.bin/at/Makefile
@@ -0,0 +1,33 @@
+# $Id$
+
+.include "${.CURDIR}/Makefile.inc"
+
+PROG= at
+SRCS= at.c panic.c parsetime.c perm.c
+LINKS= ${BINDIR}/at ${BINDIR}/atq \
+ ${BINDIR}/at ${BINDIR}/atrm \
+ ${BINDIR}/at ${BINDIR}/batch
+MLINKS= at.1 batch.1 \
+ at.1 atq.1 \
+ at.1 atrm.1
+
+BINOWN= root
+BINMODE= 4555
+MANSRC= .
+CLEANFILES += ${MAN1}
+MANDEPEND = ${MAN1}
+
+.include <bsd.prog.mk>
+
+${MAN1}: at.man
+ @${ECHO} Making ${.TARGET:T} from ${.ALLSRC:T}; \
+ sed -e \
+ "s@_ATSPOOL_DIR@$(ATSPOOL_DIR)@g; \
+ s@_ATJOB_DIR@$(ATJOB_DIR)@g; \
+ s@_DEFAULT_BATCH_QUEUE@$(DEFAULT_BATCH_QUEUE)@g; \
+ s@_DEFAULT_AT_QUEUE@$(DEFAULT_AT_QUEUE)@g; \
+ s@_LOADAVG_MX@$(LOADAVG_MX)@g; \
+ s@_PERM_PATH@$(PERM_PATH)@g; \
+ s@_LOCKFILE@$(LOCKFILE)@g" \
+ < $? > $@
+
diff --git a/usr.bin/at/Makefile.inc b/usr.bin/at/Makefile.inc
new file mode 100644
index 0000000..ec44e1f
--- /dev/null
+++ b/usr.bin/at/Makefile.inc
@@ -0,0 +1,19 @@
+VERSION= 2.9
+LOCKFILE = .lockfile
+ATSPOOL_DIR=/var/at/spool
+ATJOB_DIR=/var/at/jobs
+ATLIB_DIR=/usr/libexec
+LOADAVG_MX=1.5
+DAEMON_GID=1
+DAEMON_UID=1
+DEFAULT_BATCH_QUEUE=E
+DEFAULT_AT_QUEUE=c
+PERM_PATH=/var/at
+
+CFLAGS += -DATJOB_DIR=\"$(ATJOB_DIR)/\" \
+ -DLFILE=\"$(ATJOB_DIR)/$(LOCKFILE)\" \
+ -DLOADAVG_MX=$(LOADAVG_MX) -DATSPOOL_DIR=\"$(ATSPOOL_DIR)\" \
+ -DVERSION=\"$(VERSION)\" -DDAEMON_UID=$(DAEMON_UID) -DDAEMON_GID=$(DAEMON_GID) \
+ -DDEFAULT_BATCH_QUEUE=\'$(DEFAULT_BATCH_QUEUE)\' \
+ -DDEFAULT_AT_QUEUE=\'$(DEFAULT_AT_QUEUE)\' -DPERM_PATH=\"$(PERM_PATH)/\"
+
diff --git a/usr.bin/at/at.c b/usr.bin/at/at.c
new file mode 100644
index 0000000..2dea501
--- /dev/null
+++ b/usr.bin/at/at.c
@@ -0,0 +1,773 @@
+/*
+ * at.c : Put file into atrun queue
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * Atrun & Atq modifications
+ * Copyright (C) 1993 David Parsons
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _USE_BSD 1
+
+/* System Headers */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#else
+#include <locale.h>
+#endif
+
+#if (MAXLOGNAME-1) > UT_NAMESIZE
+#define LOGNAMESIZE UT_NAMESIZE
+#else
+#define LOGNAMESIZE (MAXLOGNAME-1)
+#endif
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "parsetime.h"
+#include "perm.h"
+
+#define MAIN
+#include "privs.h"
+
+/* Macros */
+
+#ifndef ATJOB_DIR
+#define ATJOB_DIR "/usr/spool/atjobs/"
+#endif
+
+#ifndef LFILE
+#define LFILE ATJOB_DIR ".lockfile"
+#endif
+
+#ifndef ATJOB_MX
+#define ATJOB_MX 255
+#endif
+
+#define ALARMC 10 /* Number of seconds to wait for timeout */
+
+#define SIZE 255
+#define TIMESIZE 50
+
+enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */
+
+/* File scope variables */
+
+static char rcsid[] = "$Id: at.c,v 1.12 1997/03/03 07:58:00 ache Exp $";
+char *no_export[] =
+{
+ "TERM", "TERMCAP", "DISPLAY", "_"
+} ;
+static send_mail = 0;
+
+/* External variables */
+
+extern char **environ;
+int fcreated;
+char *namep;
+char atfile[] = ATJOB_DIR "12345678901234";
+
+char *atinput = (char*)0; /* where to get input from */
+char atqueue = 0; /* which queue to examine for jobs (atq) */
+char atverify = 0; /* verify time instead of queuing job */
+
+/* Function declarations */
+
+static void sigc(int signo);
+static void alarmc(int signo);
+static char *cwdname(void);
+static void writefile(time_t runtimer, char queue);
+static void list_jobs(void);
+
+/* Signal catching functions */
+
+static void sigc(int signo)
+{
+/* If the user presses ^C, remove the spool file and exit
+ */
+ if (fcreated)
+ {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+static void alarmc(int signo)
+{
+/* Time out after some seconds
+ */
+ panic("File locking timed out");
+}
+
+/* Local functions */
+
+static char *cwdname(void)
+{
+/* Read in the current directory; the name will be overwritten on
+ * subsequent calls.
+ */
+ static char *ptr = NULL;
+ static size_t size = SIZE;
+
+ if (ptr == NULL)
+ ptr = (char *) mymalloc(size);
+
+ while (1)
+ {
+ if (ptr == NULL)
+ panic("Out of memory");
+
+ if (getcwd(ptr, size-1) != NULL)
+ return ptr;
+
+ if (errno != ERANGE)
+ perr("Cannot get directory");
+
+ free (ptr);
+ size += SIZE;
+ ptr = (char *) mymalloc(size);
+ }
+}
+
+static long
+nextjob()
+{
+ long jobno;
+ FILE *fid;
+
+ if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != (FILE*)0) {
+ if (fscanf(fid, "%5lx", &jobno) == 1) {
+ rewind(fid);
+ jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */
+ fprintf(fid, "%05lx\n", jobno);
+ }
+ else
+ jobno = EOF;
+ fclose(fid);
+ return jobno;
+ }
+ else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != (FILE*)0) {
+ fprintf(fid, "%05lx\n", jobno = 1);
+ fclose(fid);
+ return 1;
+ }
+ return EOF;
+}
+
+static void
+writefile(time_t runtimer, char queue)
+{
+/* This does most of the work if at or batch are invoked for writing a job.
+ */
+ long jobno;
+ char *ap, *ppos, *mailname;
+ struct passwd *pass_entry;
+ struct stat statbuf;
+ int fdes, lockdes, fd2;
+ FILE *fp, *fpin;
+ struct sigaction act;
+ char **atenv;
+ int ch;
+ mode_t cmask;
+ struct flock lock;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_TIME, "");
+#endif
+
+/* Install the signal handler for SIGINT; terminate after removing the
+ * spool file if necessary
+ */
+ act.sa_handler = sigc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ sigaction(SIGINT, &act, NULL);
+
+ ppos = atfile + strlen(ATJOB_DIR);
+
+ /* Loop over all possible file names for running something at this
+ * particular time, see if a file is there; the first empty slot at any
+ * particular time is used. Lock the file LFILE first to make sure
+ * we're alone when doing this.
+ */
+
+ PRIV_START
+
+ if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
+ perr("Cannot open lockfile " LFILE);
+
+ lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+
+ act.sa_handler = alarmc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ /* Set an alarm so a timeout occurs after ALARMC seconds, in case
+ * something is seriously broken.
+ */
+ sigaction(SIGALRM, &act, NULL);
+ alarm(ALARMC);
+ fcntl(lockdes, F_SETLKW, &lock);
+ alarm(0);
+
+ if ((jobno = nextjob()) == EOF)
+ perr("Cannot generate job number");
+
+ sprintf(ppos, "%c%5lx%8lx", queue,
+ jobno, (unsigned long) (runtimer/60));
+
+ for(ap=ppos; *ap != '\0'; ap ++)
+ if (*ap == ' ')
+ *ap = '0';
+
+ if (stat(atfile, &statbuf) != 0)
+ if (errno != ENOENT)
+ perr("Cannot access " ATJOB_DIR);
+
+ /* Create the file. The x bit is only going to be set after it has
+ * been completely written out, to make sure it is not executed in the
+ * meantime. To make sure they do not get deleted, turn off their r
+ * bit. Yes, this is a kluge.
+ */
+ cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
+ if ((fdes = creat(atfile, O_WRONLY)) == -1)
+ perr("Cannot create atjob file");
+
+ if ((fd2 = dup(fdes)) <0)
+ perr("Error in dup() of job file");
+
+ if(fchown(fd2, real_uid, real_gid) != 0)
+ perr("Cannot give away file");
+
+ PRIV_END
+
+ /* We no longer need suid root; now we just need to be able to write
+ * to the directory, if necessary.
+ */
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ /* We've successfully created the file; let's set the flag so it
+ * gets removed in case of an interrupt or error.
+ */
+ fcreated = 1;
+
+ /* Now we can release the lock, so other people can access it
+ */
+ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+ fcntl(lockdes, F_SETLKW, &lock);
+ close(lockdes);
+
+ if((fp = fdopen(fdes, "w")) == NULL)
+ panic("Cannot reopen atjob file");
+
+ /* Get the userid to mail to, first by trying getlogin(), which reads
+ * /etc/utmp, then from LOGNAME, finally from getpwuid().
+ */
+ mailname = getlogin();
+ if (mailname == NULL)
+ mailname = getenv("LOGNAME");
+
+ if ((mailname == NULL) || (mailname[0] == '\0')
+ || (strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname)==NULL))
+ {
+ pass_entry = getpwuid(real_uid);
+ if (pass_entry != NULL)
+ mailname = pass_entry->pw_name;
+ }
+
+ if (atinput != (char *) NULL)
+ {
+ fpin = freopen(atinput, "r", stdin);
+ if (fpin == NULL)
+ perr("Cannot open input file");
+ }
+ fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n",
+ (long) real_uid, (long) real_gid, LOGNAMESIZE, mailname, send_mail);
+
+ /* Write out the umask at the time of invocation
+ */
+ fprintf(fp, "umask %lo\n", (unsigned long) cmask);
+
+ /* Write out the environment. Anything that may look like a
+ * special character to the shell is quoted, except for \n, which is
+ * done with a pair of "'s. Dont't export the no_export list (such
+ * as TERM or DISPLAY) because we don't want these.
+ */
+ for (atenv= environ; *atenv != NULL; atenv++)
+ {
+ int export = 1;
+ char *eqp;
+
+ eqp = strchr(*atenv, '=');
+ if (ap == NULL)
+ eqp = *atenv;
+ else
+ {
+ int i;
+ for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++)
+ {
+ export = export
+ && (strncmp(*atenv, no_export[i],
+ (size_t) (eqp-*atenv)) != 0);
+ }
+ eqp++;
+ }
+
+ if (export)
+ {
+ fwrite(*atenv, sizeof(char), eqp-*atenv, fp);
+ for(ap = eqp;*ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (!isalnum(*ap)) {
+ switch (*ap) {
+ case '%': case '/': case '{': case '[':
+ case ']': case '=': case '}': case '@':
+ case '+': case '#': case ',': case '.':
+ case ':': case '-': case '_':
+ break;
+ default:
+ fputc('\\', fp);
+ break;
+ }
+ }
+ fputc(*ap, fp);
+ }
+ }
+ fputs("; export ", fp);
+ fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp);
+ fputc('\n', fp);
+
+ }
+ }
+ /* Cd to the directory at the time and write out all the
+ * commands the user supplies from stdin.
+ */
+ fprintf(fp, "cd ");
+ for (ap = cwdname(); *ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (*ap != '/' && !isalnum(*ap))
+ fputc('\\', fp);
+
+ fputc(*ap, fp);
+ }
+ }
+ /* Test cd's exit status: die if the original directory has been
+ * removed, become unreadable or whatever
+ */
+ fprintf(fp, " || {\n\t echo 'Execution directory "
+ "inaccessible' >&2\n\t exit 1\n}\n");
+
+ while((ch = getchar()) != EOF)
+ fputc(ch, fp);
+
+ fprintf(fp, "\n");
+ if (ferror(fp))
+ panic("Output error");
+
+ if (ferror(stdin))
+ panic("Input error");
+
+ fclose(fp);
+
+ /* Set the x bit so that we're ready to start executing
+ */
+
+ if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
+ perr("Cannot give away file");
+
+ close(fd2);
+ fprintf(stderr, "Job %ld will be executed using /bin/sh\n", jobno);
+}
+
+static void
+list_jobs()
+{
+ /* List all a user's jobs in the queue, by looping through ATJOB_DIR,
+ * or everybody's if we are root
+ */
+ struct passwd *pw;
+ DIR *spool;
+ struct dirent *dirent;
+ struct stat buf;
+ struct tm runtime;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+ time_t runtimer;
+ char timestr[TIMESIZE];
+ int first=1;
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("Cannot change to " ATJOB_DIR);
+
+ if ((spool = opendir(".")) == NULL)
+ perr("Cannot open " ATJOB_DIR);
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+ if (stat(dirent->d_name, &buf) != 0)
+ perr("Cannot stat in " ATJOB_DIR);
+
+ /* See it's a regular file and has its x bit turned on and
+ * is the user's
+ */
+ if (!S_ISREG(buf.st_mode)
+ || ((buf.st_uid != real_uid) && ! (real_uid == 0))
+ || !(S_IXUSR & buf.st_mode || atverify))
+ continue;
+
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+
+ if (atqueue && (queue != atqueue))
+ continue;
+
+ runtimer = 60*(time_t) ctm;
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%X %x", &runtime);
+ if (first) {
+ printf("Date\t\t\tOwner\tQueue\tJob#\n");
+ first=0;
+ }
+ pw = getpwuid(buf.st_uid);
+
+ printf("%s\t%s\t%c%s\t%ld\n",
+ timestr,
+ pw ? pw->pw_name : "???",
+ queue,
+ (S_IXUSR & buf.st_mode) ? "":"(done)",
+ jobno);
+ }
+ PRIV_END
+}
+
+static void
+process_jobs(int argc, char **argv, int what)
+{
+ /* Delete every argument (job - ID) given
+ */
+ int i;
+ struct stat buf;
+ DIR *spool;
+ struct dirent *dirent;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("Cannot change to " ATJOB_DIR);
+
+ if ((spool = opendir(".")) == NULL)
+ perr("Cannot open " ATJOB_DIR);
+
+ PRIV_END
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+
+ PRIV_START
+ if (stat(dirent->d_name, &buf) != 0)
+ perr("Cannot stat in " ATJOB_DIR);
+ PRIV_END
+
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+
+ for (i=optind; i < argc; i++) {
+ if (atoi(argv[i]) == jobno) {
+ if ((buf.st_uid != real_uid) && !(real_uid == 0)) {
+ fprintf(stderr, "%s: Not owner\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ switch (what) {
+ case ATRM:
+
+ PRIV_START
+
+ if (unlink(dirent->d_name) != 0)
+ perr(dirent->d_name);
+
+ PRIV_END
+
+ break;
+
+ case CAT:
+ {
+ FILE *fp;
+ int ch;
+
+ PRIV_START
+
+ fp = fopen(dirent->d_name,"r");
+
+ PRIV_END
+
+ if (!fp) {
+ perr("Cannot open file");
+ }
+ while((ch = getc(fp)) != EOF) {
+ putchar(ch);
+ }
+ }
+ break;
+
+ default:
+ fprintf(stderr,
+ "Internal error, process_jobs = %d\n",what);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ }
+ }
+} /* delete_jobs */
+
+/* Global functions */
+
+void *
+mymalloc(size_t n)
+{
+ void *p;
+ if ((p=malloc(n))==(void *)0)
+ {
+ fprintf(stderr,"Virtual memory exhausted\n");
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ char queue = DEFAULT_AT_QUEUE;
+ char queue_set = 0;
+ char *pgm;
+
+ enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */
+ int program = AT; /* our default program */
+ char *options = "q:f:mvldbVc"; /* default options for at */
+ int disp_version = 0;
+ time_t timer;
+
+ RELINQUISH_PRIVS
+
+ /* Eat any leading paths
+ */
+ if ((pgm = strrchr(argv[0], '/')) == NULL)
+ pgm = argv[0];
+ else
+ pgm++;
+
+ namep = pgm;
+
+ /* find out what this program is supposed to do
+ */
+ if (strcmp(pgm, "atq") == 0) {
+ program = ATQ;
+ options = "q:vV";
+ }
+ else if (strcmp(pgm, "atrm") == 0) {
+ program = ATRM;
+ options = "V";
+ }
+ else if (strcmp(pgm, "batch") == 0) {
+ program = BATCH;
+ options = "f:q:mvV";
+ }
+
+ /* process whatever options we can process
+ */
+ opterr=1;
+ while ((c=getopt(argc, argv, options)) != -1)
+ switch (c) {
+ case 'v': /* verify time settings */
+ atverify = 1;
+ break;
+
+ case 'm': /* send mail when job is complete */
+ send_mail = 1;
+ break;
+
+ case 'f':
+ atinput = optarg;
+ break;
+
+ case 'q': /* specify queue */
+ if (strlen(optarg) > 1)
+ usage();
+
+ atqueue = queue = *optarg;
+ if (!(islower(queue)||isupper(queue)))
+ usage();
+
+ queue_set = 1;
+ break;
+
+ case 'd':
+ if (program != AT)
+ usage();
+
+ program = ATRM;
+ options = "V";
+ break;
+
+ case 'l':
+ if (program != AT)
+ usage();
+
+ program = ATQ;
+ options = "q:vV";
+ break;
+
+ case 'b':
+ if (program != AT)
+ usage();
+
+ program = BATCH;
+ options = "f:q:mvV";
+ break;
+
+ case 'V':
+ disp_version = 1;
+ break;
+
+ case 'c':
+ program = CAT;
+ options = "";
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ /* end of options eating
+ */
+
+ if (disp_version)
+ fprintf(stderr, "at version " VERSION "\n"
+ "Bug reports to: ig25@rz.uni-karlsruhe.de (Thomas Koenig)\n");
+
+ /* select our program
+ */
+ if(!check_permission())
+ {
+ fprintf(stderr, "You do not have permission to use %s.\n",namep);
+ exit(EXIT_FAILURE);
+ }
+ switch (program) {
+ case ATQ:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ list_jobs();
+ break;
+
+ case ATRM:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ process_jobs(argc, argv, ATRM);
+ break;
+
+ case CAT:
+
+ process_jobs(argc, argv, CAT);
+ break;
+
+ case AT:
+ timer = parsetime(argc, argv);
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+ writefile(timer, queue);
+ break;
+
+ case BATCH:
+ if (queue_set)
+ queue = toupper(queue);
+ else
+ queue = DEFAULT_BATCH_QUEUE;
+
+ if (argc > optind)
+ timer = parsetime(argc, argv);
+ else
+ timer = time(NULL);
+
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+
+ writefile(timer, queue);
+ break;
+
+ default:
+ panic("Internal error");
+ break;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/usr.bin/at/at.h b/usr.bin/at/at.h
new file mode 100644
index 0000000..40a5a6f
--- /dev/null
+++ b/usr.bin/at/at.h
@@ -0,0 +1,31 @@
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+extern int fcreated;
+extern char *namep;
+extern char atfile[];
+extern char atverify;
+
+void *mymalloc(size_t n);
diff --git a/usr.bin/at/at.man b/usr.bin/at/at.man
new file mode 100644
index 0000000..daffd0a
--- /dev/null
+++ b/usr.bin/at/at.man
@@ -0,0 +1,268 @@
+.\" $Id$
+.Dd April 12, 1995
+.Dt "AT" 1
+.Os "FreeBSD 2.1"
+.Sh NAME
+.Nm at, batch, atq, atrm
+.Nd queue, examine or delete jobs for later execution
+.Sh SYNOPSIS
+.Nm at
+.Op Fl V
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mldbv
+.Ar time
+.Pp
+.Nm at
+.Op Fl V
+.Fl c Ar job Op Ar job ...
+.Pp
+.Nm atq
+.Op Fl V
+.Op Fl q Ar queue
+.Op Fl v
+.Pp
+.Nm atrm
+.Op Fl V
+.Ar job
+.Op Ar job ...
+.Pp
+.Nm batch
+.Op Fl V
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mv
+.Op Ar time
+.Sh DESCRIPTION
+.Nm At
+and
+.Nm batch
+read commands from standard input or a specified file which are to
+be executed at a later time, using
+.Xr sh 1 .
+.Bl -tag -width indent
+.It Nm at
+executes commands at a specified time;
+.It Nm atq
+lists the user's pending jobs, unless the user is the superuser; in that
+case, everybody's jobs are listed;
+.It Nm atrm
+deletes jobs;
+.It Nm batch
+executes commands when system load levels permit; in other words, when the load average
+drops below _LOADAVG_MX, or the value specified in the invocation of
+.Nm atrun .
+.El
+.Pp
+.Nm At
+allows some moderately complex
+.Ar time
+specifications. It accepts times of the form
+.Ar HHMM
+or
+.Ar HH:MM
+to run a job at a specific time of day.
+(If that time is already past, the next day is assumed.)
+You may also specify
+.Nm midnight ,
+.Nm noon ,
+or
+.Nm teatime
+(4pm)
+and you can have a time-of-day suffixed with
+.Nm AM
+or
+.Nm PM
+for running in the morning or the evening.
+You can also say what day the job will be run,
+by giving a date in the form
+.Ar \%month-name day
+with an optional
+.Ar year ,
+or giving a date of the form
+.Ar MMDDYY
+or
+.Ar MM/DD/YY
+or
+.Ar DD.MM.YY .
+The specification of a date must follow the specification of
+the time of day.
+You can also give times like
+.Op Nm now
+.Nm + Ar count \%time-units ,
+where the time-units can be
+.Nm minutes ,
+.Nm hours ,
+.Nm days ,
+or
+.Nm weeks
+and you can tell
+.Nm at
+to run the job today by suffixing the time with
+.Nm today
+and to run the job tomorrow by suffixing the time with
+.Nm tomorrow.
+.Pp
+For example, to run a job at 4pm three days from now, you would do
+.Nm at 4pm + 3 days ,
+to run a job at 10:00am on July 31, you would do
+.Nm at 10am Jul 31
+and to run a job at 1am tomorrow, you would do
+.Nm at 1am tomorrow.
+.Pp
+For both
+.Nm at
+and
+.Nm batch ,
+commands are read from standard input or the file specified
+with the
+.Fl f
+option and executed.
+The working directory, the environment (except for the variables
+.Nm TERM ,
+.Nm TERMCAP ,
+.Nm DISPLAY
+and
+.Nm _ )
+and the
+.Ar umask
+are retained from the time of invocation.
+An
+.Nm at
+or
+.Nm batch
+command invoked from a
+.Xr su 1
+shell will retain the current userid.
+The user will be mailed standard error and standard output from his
+commands, if any. Mail will be sent using the command
+.Xr sendmail 8 .
+If
+.Nm at
+is executed from a
+.Xr su 1
+shell, the owner of the login shell will receive the mail.
+.Pp
+The superuser may use these commands in any case.
+For other users, permission to use at is determined by the files
+.Pa _PERM_PATH/at.allow
+and
+.Pa _PERM_PATH/at.deny .
+.Pp
+If the file
+.Pa _PERM_PATH/at.allow
+exists, only usernames mentioned in it are allowed to use
+.Nm at .
+.Pp
+If
+.Pa _PERM_PATH/at.allow
+does not exist,
+.Pa _PERM_PATH/at.deny
+is checked, every username not mentioned in it is then allowed
+to use
+.Nm at .
+.Pp
+If neither exists, only the superuser is allowed use of
+.Nm at .
+This is the default configuration.
+.Pp
+An empty
+.Pa _PERM_PATH/at.deny
+means that every user is allowed use these commands.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl V
+prints the version number to standard error.
+.It Fl q Ar queue
+uses the specified queue.
+A queue designation consists of a single letter; valid queue designations
+range from
+.Nm a
+to
+.Nm z .
+and
+.Nm A
+to
+.Nm Z .
+The
+.Nm _DEFAULT_AT_QUEUE
+queue is the default for
+.Nm at
+and the
+.Nm _DEFAULT_BATCH_QUEUE
+queue for
+.Nm batch .
+Queues with higher letters run with increased niceness.
+If a job is submitted to a queue designated with an uppercase letter, it
+is treated as if it had been submitted to batch at that time.
+If
+.Nm atq
+is given a specific queue, it will only show jobs pending in that queue.
+.It Fl m
+Send mail to the user when the job has completed even if there was no
+output.
+.It Fl f Ar file
+Reads the job from
+.Ar file
+rather than standard input.
+.It Fl l
+Is an alias for
+.Nm atq.
+.It Fl d
+Is an alias for
+.Nm atrm.
+.It Fl b
+Is an alias for
+.Nm batch.
+.It Fl v
+For
+.Nm atq ,
+shows completed but not yet deleted jobs in the queue; otherwise
+shows the time the job will be executed.
+.It Fl c
+Cats the jobs listed on the command line to standart output.
+.Sh FILES
+.Bl -tag -width _ATJOB_DIR/_LOCKFILE -compact
+.It Pa _ATJOB_DIR
+Directory containing job files
+.It Pa _ATSPOOL_DIR
+Directory containing output spool files
+.It Pa /var/run/utmp
+Login records
+.It Pa _PERM_PATH/at.allow
+Allow permission control
+.It Pa _PERM_PATH/at.deny
+Deny permission control
+.It Pa _ATJOB_DIR/_LOCKFILE
+Job-creation lock file.
+.Sh SEE ALSO
+.Xr cron 8 ,
+.Xr nice 1 ,
+.Xr umask 2 ,
+.Xr sh 1 ,
+.Xr sendmail 8 ,
+.Xr atrun 8 .
+.El
+.Sh BUGS
+.Pp
+If the file
+.Pa /var/run/utmp
+is not available or corrupted, or if the user is not logged on at the
+time
+.Nm at
+is invoked, the mail is sent to the userid found
+in the environment variable
+.Nm LOGNAME .
+If that is undefined or empty, the current userid is assumed.
+.Pp
+.Nm At
+and
+.Nm batch
+as presently implemented are not suitable when users are competing for
+resources.
+If this is the case for your site, you might want to consider another
+batch system, such as
+.Nm nqs .
+.Sh AUTHOR
+At was mostly written by Thomas Koenig, ig25@rz.uni-karlsruhe.de.
+The time parsing routines are by David Parsons, orc@pell.chi.il.us.
diff --git a/usr.bin/at/panic.c b/usr.bin/at/panic.c
new file mode 100644
index 0000000..7ef0e15d
--- /dev/null
+++ b/usr.bin/at/panic.c
@@ -0,0 +1,80 @@
+/*
+ * panic.c - terminate fast in case of error
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* System Headers */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "panic.h"
+#include "at.h"
+
+/* File scope variables */
+
+static char rcsid[] = "$Id: panic.c,v 1.6 1997/02/22 19:54:06 peter Exp $";
+
+/* External variables */
+
+/* Global functions */
+
+void
+panic(char *a)
+{
+/* Something fatal has happened, print error message and exit.
+ */
+ fprintf(stderr,"%s: %s\n",namep,a);
+ if (fcreated)
+ unlink(atfile);
+
+ exit (EXIT_FAILURE);
+}
+
+void
+perr(char *a)
+{
+/* Some operating system error; print error message and exit.
+ */
+ perror(a);
+ if (fcreated)
+ unlink(atfile);
+
+ exit(EXIT_FAILURE);
+}
+
+void
+usage(void)
+{
+ /* Print usage and exit. */
+ fprintf(stderr, "usage: at [-V] [-q x] [-f file] [-m] time\n"
+ " at [-V] -c job [job ...]\n"
+ " atq [-V] [-q x] [-v]\n"
+ " atrm [-V] job [job ...]\n"
+ " batch [-V] [-f file] [-m]\n");
+ exit(EXIT_FAILURE);
+}
diff --git a/usr.bin/at/panic.h b/usr.bin/at/panic.h
new file mode 100644
index 0000000..a809b8a
--- /dev/null
+++ b/usr.bin/at/panic.h
@@ -0,0 +1,44 @@
+/*
+ * panic.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __FreeBSD__
+#define __NORETURN
+#endif
+
+void
+#ifdef __GNUC__
+__NORETURN
+#endif
+panic(char *a);
+void
+#ifdef __GNUC__
+__NORETURN
+#endif
+perr(char *a);
+void
+#ifdef __GNUC__
+__NORETURN
+#endif
+usage(void);
diff --git a/usr.bin/at/parsetime.c b/usr.bin/at/parsetime.c
new file mode 100644
index 0000000..6e64f1f
--- /dev/null
+++ b/usr.bin/at/parsetime.c
@@ -0,0 +1,621 @@
+/*
+ * parsetime.c - parse time for at(1)
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * modifications for english-language times
+ * Copyright (C) 1993 David Parsons
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS
+ * /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \
+ * |NOON | |[TOMORROW] |
+ * |MIDNIGHT | |[DAY OF WEEK] |
+ * \TEATIME / |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+
+/* System Headers */
+
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#endif
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+
+
+/* Structures and unions */
+
+enum { /* symbols */
+ MIDNIGHT, NOON, TEATIME,
+ PM, AM, TOMORROW, TODAY, NOW,
+ MINUTES, HOURS, DAYS, WEEKS,
+ NUMBER, PLUS, DOT, SLASH, ID, JUNK,
+ JAN, FEB, MAR, APR, MAY, JUN,
+ JUL, AUG, SEP, OCT, NOV, DEC,
+ SUN, MON, TUE, WED, THU, FRI, SAT
+ };
+
+/* parse translation table - table driven parsers can be your FRIEND!
+ */
+struct {
+ char *name; /* token name */
+ int value; /* token id */
+ int plural; /* is this plural? */
+} Specials[] = {
+ { "midnight", MIDNIGHT,0 }, /* 00:00:00 of today or tomorrow */
+ { "noon", NOON,0 }, /* 12:00:00 of today or tomorrow */
+ { "teatime", TEATIME,0 }, /* 16:00:00 of today or tomorrow */
+ { "am", AM,0 }, /* morning times for 0-12 clock */
+ { "pm", PM,0 }, /* evening times for 0-12 clock */
+ { "tomorrow", TOMORROW,0 }, /* execute 24 hours from time */
+ { "today", TODAY, 0 }, /* execute today - don't advance time */
+ { "now", NOW,0 }, /* opt prefix for PLUS */
+
+ { "minute", MINUTES,0 }, /* minutes multiplier */
+ { "minutes", MINUTES,1 }, /* (pluralized) */
+ { "hour", HOURS,0 }, /* hours ... */
+ { "hours", HOURS,1 }, /* (pluralized) */
+ { "day", DAYS,0 }, /* days ... */
+ { "days", DAYS,1 }, /* (pluralized) */
+ { "week", WEEKS,0 }, /* week ... */
+ { "weeks", WEEKS,1 }, /* (pluralized) */
+ { "jan", JAN,0 },
+ { "feb", FEB,0 },
+ { "mar", MAR,0 },
+ { "apr", APR,0 },
+ { "may", MAY,0 },
+ { "jun", JUN,0 },
+ { "jul", JUL,0 },
+ { "aug", AUG,0 },
+ { "sep", SEP,0 },
+ { "oct", OCT,0 },
+ { "nov", NOV,0 },
+ { "dec", DEC,0 },
+ { "sunday", SUN, 0 },
+ { "sun", SUN, 0 },
+ { "monday", MON, 0 },
+ { "mon", MON, 0 },
+ { "tuesday", TUE, 0 },
+ { "tue", TUE, 0 },
+ { "wednesday", WED, 0 },
+ { "wed", WED, 0 },
+ { "thursday", THU, 0 },
+ { "thu", THU, 0 },
+ { "friday", FRI, 0 },
+ { "fri", FRI, 0 },
+ { "saturday", SAT, 0 },
+ { "sat", SAT, 0 },
+} ;
+
+/* File scope variables */
+
+static char **scp; /* scanner - pointer at arglist */
+static char scc; /* scanner - count of remaining arguments */
+static char *sct; /* scanner - next char pointer in current argument */
+static int need; /* scanner - need to advance to next argument */
+
+static char *sc_token; /* scanner - token buffer */
+static size_t sc_len; /* scanner - lenght of token buffer */
+static int sc_tokid; /* scanner - token id */
+static int sc_tokplur; /* scanner - is token plural? */
+
+static char rcsid[] = "$Id: parsetime.c,v 1.10 1997/06/23 06:44:18 charnier Exp $";
+
+/* Local functions */
+
+/*
+ * parse a token, checking if it's something special to us
+ */
+static int
+parse_token(char *arg)
+{
+ int i;
+
+ for (i=0; i<(sizeof Specials/sizeof Specials[0]); i++)
+ if (strcasecmp(Specials[i].name, arg) == 0) {
+ sc_tokplur = Specials[i].plural;
+ return sc_tokid = Specials[i].value;
+ }
+
+ /* not special - must be some random id */
+ return ID;
+} /* parse_token */
+
+
+/*
+ * init_scanner() sets up the scanner to eat arguments
+ */
+static void
+init_scanner(int argc, char **argv)
+{
+ scp = argv;
+ scc = argc;
+ need = 1;
+ sc_len = 1;
+ while (argc-- > 0)
+ sc_len += strlen(*argv++);
+
+ sc_token = (char *) mymalloc(sc_len);
+} /* init_scanner */
+
+/*
+ * token() fetches a token from the input stream
+ */
+static int
+token()
+{
+ int idx;
+
+ while (1) {
+ memset(sc_token, 0, sc_len);
+ sc_tokid = EOF;
+ sc_tokplur = 0;
+ idx = 0;
+
+ /* if we need to read another argument, walk along the argument list;
+ * when we fall off the arglist, we'll just return EOF forever
+ */
+ if (need) {
+ if (scc < 1)
+ return sc_tokid;
+ sct = *scp;
+ scp++;
+ scc--;
+ need = 0;
+ }
+ /* eat whitespace now - if we walk off the end of the argument,
+ * we'll continue, which puts us up at the top of the while loop
+ * to fetch the next argument in
+ */
+ while (isspace(*sct))
+ ++sct;
+ if (!*sct) {
+ need = 1;
+ continue;
+ }
+
+ /* preserve the first character of the new token
+ */
+ sc_token[0] = *sct++;
+
+ /* then see what it is
+ */
+ if (isdigit(sc_token[0])) {
+ while (isdigit(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return sc_tokid = NUMBER;
+ }
+ else if (isalpha(sc_token[0])) {
+ while (isalpha(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return parse_token(sc_token);
+ }
+ else if (sc_token[0] == ':' || sc_token[0] == '.')
+ return sc_tokid = DOT;
+ else if (sc_token[0] == '+')
+ return sc_tokid = PLUS;
+ else if (sc_token[0] == '/')
+ return sc_tokid = SLASH;
+ else
+ return sc_tokid = JUNK;
+ } /* while (1) */
+} /* token */
+
+
+/*
+ * plonk() gives an appropriate error message if a token is incorrect
+ */
+static void
+plonk(int tok)
+{
+ panic((tok == EOF) ? "incomplete time"
+ : "garbled time");
+} /* plonk */
+
+
+/*
+ * expect() gets a token and dies most horribly if it's not the token we want
+ */
+static void
+expect(int desired)
+{
+ if (token() != desired)
+ plonk(sc_tokid); /* and we die here... */
+} /* expect */
+
+
+/*
+ * dateadd() adds a number of minutes to a date. It is extraordinarily
+ * stupid regarding day-of-month overflow, and will most likely not
+ * work properly
+ */
+static void
+dateadd(int minutes, struct tm *tm)
+{
+ /* increment days */
+
+ while (minutes > 24*60) {
+ minutes -= 24*60;
+ tm->tm_mday++;
+ }
+
+ /* increment hours */
+ while (minutes > 60) {
+ minutes -= 60;
+ tm->tm_hour++;
+ if (tm->tm_hour > 23) {
+ tm->tm_mday++;
+ tm->tm_hour = 0;
+ }
+ }
+
+ /* increment minutes */
+ tm->tm_min += minutes;
+
+ if (tm->tm_min > 59) {
+ tm->tm_hour++;
+ tm->tm_min -= 60;
+
+ if (tm->tm_hour > 23) {
+ tm->tm_mday++;
+ tm->tm_hour = 0;
+ }
+ }
+} /* dateadd */
+
+
+/*
+ * plus() parses a now + time
+ *
+ * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS]
+ *
+ */
+static void
+plus(struct tm *tm)
+{
+ int delay;
+ int expectplur;
+
+ expect(NUMBER);
+
+ delay = atoi(sc_token);
+ expectplur = (delay != 1) ? 1 : 0;
+
+ switch (token()) {
+ case WEEKS:
+ delay *= 7;
+ case DAYS:
+ delay *= 24;
+ case HOURS:
+ delay *= 60;
+ case MINUTES:
+ if (expectplur != sc_tokplur)
+ warnx("pluralization is wrong");
+ dateadd(delay, tm);
+ return;
+ }
+ plonk(sc_tokid);
+} /* plus */
+
+
+/*
+ * tod() computes the time of day
+ * [NUMBER [DOT NUMBER] [AM|PM]]
+ */
+static void
+tod(struct tm *tm)
+{
+ int hour, minute = 0;
+ int tlen;
+
+ hour = atoi(sc_token);
+ tlen = strlen(sc_token);
+
+ /* first pick out the time of day - if it's 4 digits, we assume
+ * a HHMM time, otherwise it's HH DOT MM time
+ */
+ if (token() == DOT) {
+ expect(NUMBER);
+ minute = atoi(sc_token);
+ if (minute > 59)
+ panic("garbled time");
+ token();
+ }
+ else if (tlen == 4) {
+ minute = hour%100;
+ if (minute > 59)
+ panic("garbeld time");
+ hour = hour/100;
+ }
+
+ /* check if an AM or PM specifier was given
+ */
+ if (sc_tokid == AM || sc_tokid == PM) {
+ if (hour > 12)
+ panic("garbled time");
+
+ if (sc_tokid == PM) {
+ if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
+ hour += 12;
+ } else {
+ if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
+ hour = 0;
+ }
+ token();
+ }
+ else if (hour > 23)
+ panic("garbled time");
+
+ /* if we specify an absolute time, we don't want to bump the day even
+ * if we've gone past that time - but if we're specifying a time plus
+ * a relative offset, it's okay to bump things
+ */
+ if ((sc_tokid == EOF || sc_tokid == PLUS) && tm->tm_hour > hour) {
+ tm->tm_mday++;
+ tm->tm_wday++;
+ }
+
+ tm->tm_hour = hour;
+ tm->tm_min = minute;
+ if (tm->tm_hour == 24) {
+ tm->tm_hour = 0;
+ tm->tm_mday++;
+ }
+} /* tod */
+
+
+/*
+ * assign_date() assigns a date, wrapping to next year if needed
+ */
+static void
+assign_date(struct tm *tm, long mday, long mon, long year)
+{
+ if (year > 99) {
+ if (year > 1899)
+ year -= 1900;
+ else
+ panic("garbled time");
+ }
+
+ if (year < 0 &&
+ (tm->tm_mon > mon ||(tm->tm_mon == mon && tm->tm_mday > mday)))
+ year = tm->tm_year + 1;
+
+ tm->tm_mday = mday;
+ tm->tm_mon = mon;
+
+ if (year >= 0)
+ tm->tm_year = year;
+} /* assign_date */
+
+
+/*
+ * month() picks apart a month specification
+ *
+ * /[<month> NUMBER [NUMBER]] \
+ * |[TOMORROW] |
+ * |[DAY OF WEEK] |
+ * |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+static void
+month(struct tm *tm)
+{
+ long year= (-1);
+ long mday, wday, mon;
+ int tlen;
+
+ switch (sc_tokid) {
+ case PLUS:
+ plus(tm);
+ break;
+
+ case TOMORROW:
+ /* do something tomorrow */
+ tm->tm_mday ++;
+ tm->tm_wday ++;
+ case TODAY: /* force ourselves to stay in today - no further processing */
+ token();
+ break;
+
+ case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
+ case JUL: case AUG: case SEP: case OCT: case NOV: case DEC:
+ /* do month mday [year]
+ */
+ mon = (sc_tokid-JAN);
+ expect(NUMBER);
+ mday = atol(sc_token);
+ if (token() == NUMBER) {
+ year = atol(sc_token);
+ token();
+ }
+ assign_date(tm, mday, mon, year);
+ break;
+
+ case SUN: case MON: case TUE:
+ case WED: case THU: case FRI:
+ case SAT:
+ /* do a particular day of the week
+ */
+ wday = (sc_tokid-SUN);
+
+ mday = tm->tm_mday;
+
+ /* if this day is < today, then roll to next week
+ */
+ if (wday < tm->tm_wday)
+ mday += 7 - (tm->tm_wday - wday);
+ else
+ mday += (wday - tm->tm_wday);
+
+ tm->tm_wday = wday;
+
+ assign_date(tm, mday, tm->tm_mon, tm->tm_year);
+ break;
+
+ case NUMBER:
+ /* get numeric MMDDYY, mm/dd/yy, or dd.mm.yy
+ */
+ tlen = strlen(sc_token);
+ mon = atol(sc_token);
+ token();
+
+ if (sc_tokid == SLASH || sc_tokid == DOT) {
+ int sep;
+
+ sep = sc_tokid;
+ expect(NUMBER);
+ mday = atol(sc_token);
+ if (token() == sep) {
+ expect(NUMBER);
+ year = atol(sc_token);
+ token();
+ }
+
+ /* flip months and days for european timing
+ */
+ if (sep == DOT) {
+ int x = mday;
+ mday = mon;
+ mon = x;
+ }
+ }
+ else if (tlen == 6 || tlen == 8) {
+ if (tlen == 8) {
+ year = (mon % 10000) - 1900;
+ mon /= 10000;
+ }
+ else {
+ year = mon % 100;
+ mon /= 100;
+ }
+ mday = mon % 100;
+ mon /= 100;
+ }
+ else
+ panic("garbled time");
+
+ mon--;
+ if (mon < 0 || mon > 11 || mday < 1 || mday > 31)
+ panic("garbled time");
+
+ assign_date(tm, mday, mon, year);
+ break;
+ } /* case */
+} /* month */
+
+
+/* Global functions */
+
+time_t
+parsetime(int argc, char **argv)
+{
+/* Do the argument parsing, die if necessary, and return the time the job
+ * should be run.
+ */
+ time_t nowtimer, runtimer;
+ struct tm nowtime, runtime;
+ int hr = 0;
+ /* this MUST be initialized to zero for midnight/noon/teatime */
+
+ nowtimer = time(NULL);
+ nowtime = *localtime(&nowtimer);
+
+ runtime = nowtime;
+ runtime.tm_sec = 0;
+ runtime.tm_isdst = 0;
+
+ if (argc <= optind)
+ usage();
+
+ init_scanner(argc-optind, argv+optind);
+
+ switch (token()) {
+ case NOW: /* now is optional prefix for PLUS tree */
+ expect(PLUS);
+ case PLUS:
+ plus(&runtime);
+ break;
+
+ case NUMBER:
+ tod(&runtime);
+ month(&runtime);
+ break;
+
+ /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialised
+ * hr to zero up above, then fall into this case in such a
+ * way so we add +12 +4 hours to it for teatime, +12 hours
+ * to it for noon, and nothing at all for midnight, then
+ * set our runtime to that hour before leaping into the
+ * month scanner
+ */
+ case TEATIME:
+ hr += 4;
+ case NOON:
+ hr += 12;
+ case MIDNIGHT:
+ if (runtime.tm_hour >= hr) {
+ runtime.tm_mday++;
+ runtime.tm_wday++;
+ }
+ runtime.tm_hour = hr;
+ runtime.tm_min = 0;
+ token();
+ /* fall through to month setting */
+ default:
+ month(&runtime);
+ break;
+ } /* ugly case statement */
+ expect(EOF);
+
+ /* adjust for daylight savings time
+ */
+ runtime.tm_isdst = -1;
+ runtimer = mktime(&runtime);
+ if (runtime.tm_isdst > 0) {
+ runtimer -= 3600;
+ runtimer = mktime(&runtime);
+ }
+
+ if (runtimer < 0)
+ panic("garbled time");
+
+ if (nowtimer > runtimer)
+ panic("Trying to travel back in time");
+
+ return runtimer;
+} /* parsetime */
diff --git a/usr.bin/at/parsetime.h b/usr.bin/at/parsetime.h
new file mode 100644
index 0000000..30c3f20
--- /dev/null
+++ b/usr.bin/at/parsetime.h
@@ -0,0 +1,26 @@
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+time_t parsetime(int argc, char **argv);
diff --git a/usr.bin/at/perm.c b/usr.bin/at/perm.c
new file mode 100644
index 0000000..d52fd3d
--- /dev/null
+++ b/usr.bin/at/perm.c
@@ -0,0 +1,123 @@
+/*
+ * perm.c - check user permission for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* System Headers */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "privs.h"
+#include "at.h"
+
+/* Macros */
+
+#define MAXUSERID 10
+
+/* Structures and unions */
+
+
+/* File scope variables */
+
+static char rcsid[] = "$Id$";
+
+/* Function declarations */
+
+static int check_for_user(FILE *fp,const char *name);
+
+/* Local functions */
+
+static int check_for_user(FILE *fp,const char *name)
+{
+ char *buffer;
+ size_t len;
+ int found = 0;
+
+ len = strlen(name);
+ buffer = mymalloc(len+2);
+
+ while(fgets(buffer, len+2, fp) != NULL)
+ {
+ if ((strncmp(name, buffer, len) == 0) &&
+ (buffer[len] == '\n'))
+ {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ free(buffer);
+ return found;
+}
+/* Global functions */
+int check_permission()
+{
+ FILE *fp;
+ uid_t uid = geteuid();
+ struct passwd *pentry;
+
+ if (uid==0)
+ return 1;
+
+ if ((pentry = getpwuid(uid)) == NULL)
+ {
+ perror("Cannot access user database");
+ exit(EXIT_FAILURE);
+ }
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.allow","r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return check_for_user(fp, pentry->pw_name);
+ }
+ else
+ {
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.deny", "r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return !check_for_user(fp, pentry->pw_name);
+ }
+ perror("at.deny");
+ }
+ return 0;
+}
diff --git a/usr.bin/at/perm.h b/usr.bin/at/perm.h
new file mode 100644
index 0000000..0a12a90
--- /dev/null
+++ b/usr.bin/at/perm.h
@@ -0,0 +1,26 @@
+/*
+ * perm.h - header for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int check_permission();
diff --git a/usr.bin/at/privs.h b/usr.bin/at/privs.h
new file mode 100644
index 0000000..2108efb
--- /dev/null
+++ b/usr.bin/at/privs.h
@@ -0,0 +1,111 @@
+/*
+ * privs.h - header for privileged operations
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PRIVS_H
+#define _PRIVS_H
+
+#ifndef _USE_BSD
+#define _USE_BSD 1
+#include <unistd.h>
+#undef _USE_BSD
+#else
+#include <unistd.h>
+#endif
+
+/* Relinquish privileges temporarily for a setuid or setgid program
+ * with the option of getting them back later. This is done by swapping
+ * the real and effective userid BSD style. Call RELINQUISH_PRIVS once
+ * at the beginning of the main program. This will cause all operatons
+ * to be executed with the real userid. When you need the privileges
+ * of the setuid/setgid invocation, call PRIV_START; when you no longer
+ * need it, call PRIV_END. Note that it is an error to call PRIV_START
+ * and not PRIV_END within the same function.
+ *
+ * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running
+ * as root, and you want to drop back the effective userid to a
+ * and the effective group id to b, with the option to get them back
+ * later.
+ *
+ * If you no longer need root privileges, but those of some other
+ * userid/groupid, you can call REDUCE_PRIV(a,b) when your effective
+ * is the user's.
+ *
+ * Problems: Do not use return between PRIV_START and PRIV_END; this
+ * will cause the program to continue running in an unprivileged
+ * state.
+ *
+ * It is NOT safe to call exec(), system() or popen() with a user-
+ * supplied program (i.e. without carefully checking PATH and any
+ * library load paths) with relinquished privileges; the called program
+ * can aquire them just as easily. Set both effective and real userid
+ * to the real userid before calling any of them.
+ */
+
+#ifndef MAIN
+extern
+#endif
+uid_t real_uid, effective_uid;
+
+#ifndef MAIN
+extern
+#endif
+gid_t real_gid, effective_gid;
+
+#define RELINQUISH_PRIVS { \
+ real_uid = getuid(); \
+ effective_uid = geteuid(); \
+ real_gid = getgid(); \
+ effective_gid = getegid(); \
+ setreuid(effective_uid, real_uid); \
+ setregid(effective_gid, real_gid); \
+ }
+
+#define RELINQUISH_PRIVS_ROOT(a,b) { \
+ real_uid = (a); \
+ effective_uid = geteuid(); \
+ real_gid = (b); \
+ effective_gid = getegid(); \
+ setregid(effective_gid, real_gid); \
+ setreuid(effective_uid, real_uid); \
+ }
+
+#define PRIV_START {\
+ setreuid(real_uid, effective_uid); \
+ setregid(real_gid, effective_gid);
+
+#define PRIV_END \
+ setregid(effective_gid, real_gid); \
+ setreuid(effective_uid, real_uid); \
+ }
+
+#define REDUCE_PRIV(a,b) {\
+ setreuid(real_uid, effective_uid); \
+ setregid(real_gid, effective_gid); \
+ effective_uid = (a); \
+ effective_gid = (b); \
+ setregid(effective_gid, real_gid); \
+ setreuid(effective_uid, real_uid); \
+ }
+#endif
diff --git a/usr.bin/banner/Makefile b/usr.bin/banner/Makefile
index 468368e..54a3ad5 100644
--- a/usr.bin/banner/Makefile
+++ b/usr.bin/banner/Makefile
@@ -1,6 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= banner
-MAN6= banner.0
+MAN6= banner.6
.include <bsd.prog.mk>
diff --git a/usr.bin/banner/banner.c b/usr.bin/banner/banner.c
index 559f056..13a2849 100644
--- a/usr.bin/banner/banner.c
+++ b/usr.bin/banner/banner.c
@@ -87,933 +87,933 @@ int asc_ptr[NCHARS] = {
*/
char data_table[NBYTES] = {
/* 0 1 2 3 4 5 6 7 8 9 */
-/* 0 */ 129, 227, 130, 34, 6, 90, 19, 129, 32, 10,
-/* 10 */ 74, 40, 129, 31, 12, 64, 53, 129, 30, 14,
-/* 20 */ 54, 65, 129, 30, 14, 53, 67, 129, 30, 14,
-/* 30 */ 54, 65, 129, 31, 12, 64, 53, 129, 32, 10,
-/* 40 */ 74, 40, 129, 34, 6, 90, 19, 129, 194, 130,
-/* 50 */ 99, 9, 129, 97, 14, 129, 96, 18, 129, 95,
-/* 60 */ 22, 129, 95, 16, 117, 2, 129, 95, 14, 129,
-/* 70 */ 96, 11, 129, 97, 9, 129, 99, 6, 129, 194,
-/* 80 */ 129, 87, 4, 101, 4, 131, 82, 28, 131, 87,
-/* 90 */ 4, 101, 4, 133, 82, 28, 131, 87, 4, 101,
-/* 100 */ 4, 131, 193, 129, 39, 1, 84, 27, 129, 38,
-/* 110 */ 3, 81, 32, 129, 37, 5, 79, 35, 129, 36,
-/* 120 */ 5, 77, 38, 129, 35, 5, 76, 40, 129, 34,
-/* 130 */ 5, 75, 21, 103, 14, 129, 33, 5, 74, 19,
-/* 140 */ 107, 11, 129, 32, 5, 73, 17, 110, 9, 129,
-/* 150 */ 32, 4, 73, 16, 112, 7, 129, 31, 4, 72,
-/* 160 */ 15, 114, 6, 129, 31, 4, 72, 14, 115, 5,
-/* 170 */ 129, 30, 4, 71, 15, 116, 5, 129, 27, 97,
-/* 180 */ 131, 30, 4, 69, 14, 117, 4, 129, 30, 4,
-/* 190 */ 68, 15, 117, 4, 132, 30, 4, 68, 14, 117,
-/* 200 */ 4, 129, 27, 97, 131, 30, 5, 65, 15, 116,
-/* 210 */ 5, 129, 31, 4, 65, 14, 116, 4, 129, 31,
-/* 220 */ 6, 64, 15, 116, 4, 129, 32, 7, 62, 16,
-/* 230 */ 115, 4, 129, 32, 9, 61, 17, 114, 5, 129,
-/* 240 */ 33, 11, 58, 19, 113, 5, 129, 34, 14, 55,
-/* 250 */ 21, 112, 5, 129, 35, 40, 111, 5, 129, 36,
-/* 260 */ 38, 110, 5, 129, 37, 35, 109, 5, 129, 38,
-/* 270 */ 32, 110, 3, 129, 40, 27, 111, 1, 129, 193,
-/* 280 */ 129, 30, 4, 103, 9, 129, 30, 7, 100, 15,
-/* 290 */ 129, 30, 10, 99, 17, 129, 33, 10, 97, 6,
-/* 300 */ 112, 6, 129, 36, 10, 96, 5, 114, 5, 129,
-/* 310 */ 39, 10, 96, 4, 115, 4, 129, 42, 10, 95,
-/* 320 */ 4, 116, 4, 129, 45, 10, 95, 3, 117, 3,
-/* 330 */ 129, 48, 10, 95, 3, 117, 3, 129, 51, 10,
-/* 340 */ 95, 4, 116, 4, 129, 54, 10, 96, 4, 115,
-/* 350 */ 4, 129, 57, 10, 96, 5, 114, 5, 129, 60,
-/* 360 */ 10, 97, 6, 112, 6, 129, 63, 10, 99, 17,
-/* 370 */ 129, 66, 10, 100, 15, 129, 69, 10, 103, 9,
-/* 380 */ 129, 39, 9, 72, 10, 129, 36, 15, 75, 10,
-/* 390 */ 129, 35, 17, 78, 10, 129, 33, 6, 48, 6,
-/* 400 */ 81, 10, 129, 32, 5, 50, 5, 84, 10, 129,
-/* 410 */ 32, 4, 51, 4, 87, 10, 129, 31, 4, 52,
-/* 420 */ 4, 90, 10, 129, 31, 3, 53, 3, 93, 10,
-/* 430 */ 129, 31, 3, 53, 3, 96, 10, 129, 31, 4,
-/* 440 */ 52, 4, 99, 10, 129, 32, 4, 51, 4, 102,
-/* 450 */ 10, 129, 32, 5, 50, 5, 105, 10, 129, 33,
-/* 460 */ 6, 48, 6, 108, 10, 129, 35, 17, 111, 10,
-/* 470 */ 129, 36, 15, 114, 7, 129, 40, 9, 118, 4,
-/* 480 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
-/* 490 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
-/* 500 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
-/* 510 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
-/* 520 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
-/* 530 */ 5, 79, 5, 129, 20, 74, 132, 30, 4, 80,
-/* 540 */ 4, 129, 31, 3, 79, 4, 129, 31, 4, 79,
-/* 550 */ 4, 129, 32, 3, 78, 4, 129, 32, 4, 76,
-/* 560 */ 6, 129, 33, 4, 74, 7, 129, 34, 4, 72,
-/* 570 */ 8, 129, 35, 5, 72, 7, 129, 37, 5, 73,
-/* 580 */ 4, 129, 39, 4, 74, 1, 129, 129, 193, 130,
-/* 590 */ 111, 6, 129, 109, 10, 129, 108, 12, 129, 107,
-/* 600 */ 14, 129, 97, 2, 105, 16, 129, 99, 22, 129,
-/* 610 */ 102, 18, 129, 105, 14, 129, 108, 9, 129, 194,
-/* 620 */ 130, 63, 25, 129, 57, 37, 129, 52, 47, 129,
-/* 630 */ 48, 55, 129, 44, 63, 129, 41, 69, 129, 38,
-/* 640 */ 75, 129, 36, 79, 129, 34, 83, 129, 33, 28,
-/* 650 */ 90, 28, 129, 32, 23, 96, 23, 129, 32, 17,
-/* 660 */ 102, 17, 129, 31, 13, 107, 13, 129, 30, 9,
-/* 670 */ 112, 9, 129, 30, 5, 116, 5, 129, 30, 1,
-/* 680 */ 120, 1, 129, 194, 130, 30, 1, 120, 1, 129,
-/* 690 */ 30, 5, 116, 5, 129, 30, 9, 112, 9, 129,
-/* 700 */ 31, 13, 107, 13, 129, 32, 17, 102, 17, 129,
-/* 710 */ 32, 23, 96, 23, 129, 33, 28, 90, 28, 129,
-/* 720 */ 34, 83, 129, 36, 79, 129, 38, 75, 129, 41,
-/* 730 */ 69, 129, 44, 63, 129, 48, 55, 129, 52, 47,
-/* 740 */ 129, 57, 37, 129, 63, 25, 129, 194, 129, 80,
-/* 750 */ 4, 130, 80, 4, 129, 68, 2, 80, 4, 94,
-/* 760 */ 2, 129, 66, 6, 80, 4, 92, 6, 129, 67,
-/* 770 */ 7, 80, 4, 90, 7, 129, 69, 7, 80, 4,
-/* 780 */ 88, 7, 129, 71, 6, 80, 4, 87, 6, 129,
-/* 790 */ 72, 20, 129, 74, 16, 129, 76, 12, 129, 62,
-/* 800 */ 40, 131, 76, 12, 129, 74, 16, 129, 72, 20,
-/* 810 */ 129, 71, 6, 80, 4, 87, 6, 129, 69, 7,
-/* 820 */ 80, 4, 88, 7, 129, 67, 7, 80, 4, 90,
-/* 830 */ 7, 129, 66, 6, 80, 4, 92, 6, 129, 68,
-/* 840 */ 2, 80, 4, 94, 2, 129, 80, 4, 130, 193,
-/* 850 */ 129, 60, 4, 139, 41, 42, 131, 60, 4, 139,
-/* 860 */ 193, 130, 34, 6, 129, 32, 10, 129, 31, 12,
-/* 870 */ 129, 30, 14, 129, 20, 2, 28, 16, 129, 22,
-/* 880 */ 22, 129, 24, 19, 129, 27, 15, 129, 31, 9,
-/* 890 */ 129, 194, 129, 60, 4, 152, 193, 130, 34, 6,
-/* 900 */ 129, 32, 10, 129, 31, 12, 129, 30, 14, 131,
-/* 910 */ 31, 12, 129, 32, 10, 129, 34, 6, 129, 194,
-/* 920 */ 129, 30, 4, 129, 30, 7, 129, 30, 10, 129,
-/* 930 */ 33, 10, 129, 36, 10, 129, 39, 10, 129, 42,
-/* 940 */ 10, 129, 45, 10, 129, 48, 10, 129, 51, 10,
-/* 950 */ 129, 54, 10, 129, 57, 10, 129, 60, 10, 129,
-/* 960 */ 63, 10, 129, 66, 10, 129, 69, 10, 129, 72,
-/* 970 */ 10, 129, 75, 10, 129, 78, 10, 129, 81, 10,
-/* 980 */ 129, 84, 10, 129, 87, 10, 129, 90, 10, 129,
-/* 990 */ 93, 10, 129, 96, 10, 129, 99, 10, 129, 102,
-/* 1000 */ 10, 129, 105, 10, 129, 108, 10, 129, 111, 10,
-/* 1010 */ 129, 114, 7, 129, 117, 4, 129, 193, 129, 60,
-/* 1020 */ 31, 129, 53, 45, 129, 49, 53, 129, 46, 59,
-/* 1030 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
-/* 1040 */ 37, 77, 129, 36, 79, 129, 35, 15, 101, 15,
-/* 1050 */ 129, 34, 11, 106, 11, 129, 33, 9, 109, 9,
-/* 1060 */ 129, 32, 7, 112, 7, 129, 31, 6, 114, 6,
-/* 1070 */ 129, 31, 5, 115, 5, 129, 30, 5, 116, 5,
-/* 1080 */ 129, 30, 4, 117, 4, 132, 30, 5, 116, 5,
-/* 1090 */ 129, 31, 5, 115, 5, 129, 31, 6, 114, 6,
-/* 1100 */ 129, 32, 7, 112, 7, 129, 33, 9, 109, 9,
-/* 1110 */ 129, 34, 11, 106, 11, 129, 35, 15, 101, 15,
-/* 1120 */ 129, 36, 79, 129, 37, 77, 129, 39, 73, 129,
-/* 1130 */ 41, 69, 129, 43, 65, 129, 46, 59, 129, 49,
-/* 1140 */ 53, 129, 53, 45, 129, 60, 31, 129, 193, 129,
-/* 1150 */ 30, 4, 129, 30, 4, 100, 1, 129, 30, 4,
-/* 1160 */ 100, 3, 129, 30, 4, 100, 5, 129, 30, 76,
-/* 1170 */ 129, 30, 78, 129, 30, 80, 129, 30, 82, 129,
-/* 1180 */ 30, 83, 129, 30, 85, 129, 30, 87, 129, 30,
-/* 1190 */ 89, 129, 30, 91, 129, 30, 4, 132, 193, 129,
-/* 1200 */ 30, 3, 129, 30, 7, 129, 30, 10, 112, 1,
-/* 1210 */ 129, 30, 13, 112, 2, 129, 30, 16, 112, 3,
-/* 1220 */ 129, 30, 18, 111, 5, 129, 30, 21, 111, 6,
-/* 1230 */ 129, 30, 23, 112, 6, 129, 30, 14, 47, 8,
-/* 1240 */ 113, 6, 129, 30, 14, 49, 8, 114, 5, 129,
-/* 1250 */ 30, 14, 51, 8, 115, 5, 129, 30, 14, 53,
-/* 1260 */ 8, 116, 4, 129, 30, 14, 55, 8, 116, 5,
-/* 1270 */ 129, 30, 14, 56, 9, 117, 4, 129, 30, 14,
-/* 1280 */ 57, 9, 117, 4, 129, 30, 14, 58, 10, 117,
-/* 1290 */ 4, 129, 30, 14, 59, 10, 117, 4, 129, 30,
-/* 1300 */ 14, 60, 11, 117, 4, 129, 30, 14, 61, 11,
-/* 1310 */ 116, 5, 129, 30, 14, 62, 11, 116, 5, 129,
-/* 1320 */ 30, 14, 63, 12, 115, 6, 129, 30, 14, 64,
-/* 1330 */ 13, 114, 7, 129, 30, 14, 65, 13, 113, 8,
-/* 1340 */ 129, 30, 14, 65, 15, 111, 9, 129, 30, 14,
-/* 1350 */ 66, 16, 109, 11, 129, 30, 14, 67, 17, 107,
-/* 1360 */ 12, 129, 30, 14, 68, 20, 103, 16, 129, 30,
-/* 1370 */ 14, 69, 49, 129, 30, 14, 70, 47, 129, 30,
-/* 1380 */ 14, 71, 45, 129, 30, 14, 73, 42, 129, 30,
-/* 1390 */ 15, 75, 38, 129, 33, 12, 77, 34, 129, 36,
-/* 1400 */ 10, 79, 30, 129, 40, 6, 82, 23, 129, 44,
-/* 1410 */ 3, 86, 15, 129, 47, 1, 129, 193, 129, 129,
-/* 1420 */ 38, 3, 129, 37, 5, 111, 1, 129, 36, 7,
-/* 1430 */ 111, 2, 129, 35, 9, 110, 5, 129, 34, 8,
-/* 1440 */ 110, 6, 129, 33, 7, 109, 8, 129, 32, 7,
-/* 1450 */ 110, 8, 129, 32, 6, 112, 7, 129, 31, 6,
-/* 1460 */ 113, 6, 129, 31, 5, 114, 6, 129, 30, 5,
-/* 1470 */ 115, 5, 129, 30, 5, 116, 4, 129, 30, 4,
-/* 1480 */ 117, 4, 131, 30, 4, 117, 4, 129, 30, 4,
-/* 1490 */ 79, 2, 117, 4, 129, 30, 5, 78, 4, 117,
-/* 1500 */ 4, 129, 30, 5, 77, 6, 116, 5, 129, 30,
-/* 1510 */ 6, 76, 8, 115, 6, 129, 30, 7, 75, 11,
-/* 1520 */ 114, 6, 129, 30, 8, 73, 15, 112, 8, 129,
-/* 1530 */ 31, 9, 71, 19, 110, 9, 129, 31, 11, 68,
-/* 1540 */ 26, 107, 12, 129, 32, 13, 65, 14, 82, 36,
-/* 1550 */ 129, 32, 16, 61, 17, 83, 34, 129, 33, 44,
-/* 1560 */ 84, 32, 129, 34, 42, 85, 30, 129, 35, 40,
-/* 1570 */ 87, 27, 129, 36, 38, 89, 23, 129, 38, 34,
-/* 1580 */ 92, 17, 129, 40, 30, 95, 11, 129, 42, 26,
-/* 1590 */ 129, 45, 20, 129, 49, 11, 129, 193, 129, 49,
-/* 1600 */ 1, 129, 49, 4, 129, 49, 6, 129, 49, 8,
-/* 1610 */ 129, 49, 10, 129, 49, 12, 129, 49, 14, 129,
-/* 1620 */ 49, 17, 129, 49, 19, 129, 49, 21, 129, 49,
-/* 1630 */ 23, 129, 49, 14, 65, 9, 129, 49, 14, 67,
-/* 1640 */ 9, 129, 49, 14, 69, 9, 129, 49, 14, 71,
-/* 1650 */ 10, 129, 49, 14, 74, 9, 129, 49, 14, 76,
-/* 1660 */ 9, 129, 49, 14, 78, 9, 129, 49, 14, 80,
-/* 1670 */ 9, 129, 49, 14, 82, 9, 129, 49, 14, 84,
-/* 1680 */ 9, 129, 30, 4, 49, 14, 86, 10, 129, 30,
-/* 1690 */ 4, 49, 14, 89, 9, 129, 30, 4, 49, 14,
-/* 1700 */ 91, 9, 129, 30, 4, 49, 14, 93, 9, 129,
-/* 1710 */ 30, 74, 129, 30, 76, 129, 30, 78, 129, 30,
-/* 1720 */ 81, 129, 30, 83, 129, 30, 85, 129, 30, 87,
-/* 1730 */ 129, 30, 89, 129, 30, 91, 129, 30, 4, 49,
-/* 1740 */ 14, 132, 193, 129, 37, 1, 129, 36, 3, 77,
-/* 1750 */ 3, 129, 35, 5, 78, 11, 129, 34, 7, 78,
-/* 1760 */ 21, 129, 33, 7, 79, 29, 129, 32, 7, 79,
-/* 1770 */ 38, 129, 32, 6, 80, 4, 92, 29, 129, 31,
-/* 1780 */ 6, 80, 5, 102, 19, 129, 31, 5, 80, 6,
-/* 1790 */ 107, 14, 129, 31, 4, 81, 5, 107, 14, 129,
-/* 1800 */ 30, 5, 81, 6, 107, 14, 129, 30, 4, 81,
-/* 1810 */ 6, 107, 14, 130, 30, 4, 81, 7, 107, 14,
-/* 1820 */ 129, 30, 4, 80, 8, 107, 14, 130, 30, 5,
-/* 1830 */ 80, 8, 107, 14, 129, 30, 5, 79, 9, 107,
-/* 1840 */ 14, 129, 31, 5, 79, 9, 107, 14, 129, 31,
-/* 1850 */ 6, 78, 10, 107, 14, 129, 32, 6, 76, 11,
-/* 1860 */ 107, 14, 129, 32, 8, 74, 13, 107, 14, 129,
-/* 1870 */ 33, 10, 71, 16, 107, 14, 129, 33, 15, 67,
-/* 1880 */ 19, 107, 14, 129, 34, 51, 107, 14, 129, 35,
-/* 1890 */ 49, 107, 14, 129, 36, 47, 107, 14, 129, 37,
-/* 1900 */ 45, 107, 14, 129, 39, 41, 107, 14, 129, 41,
-/* 1910 */ 37, 107, 14, 129, 44, 32, 107, 14, 129, 47,
-/* 1920 */ 25, 111, 10, 129, 51, 16, 115, 6, 129, 119,
-/* 1930 */ 2, 129, 193, 129, 56, 39, 129, 51, 49, 129,
-/* 1940 */ 47, 57, 129, 44, 63, 129, 42, 67, 129, 40,
-/* 1950 */ 71, 129, 38, 75, 129, 37, 77, 129, 35, 81,
-/* 1960 */ 129, 34, 16, 74, 5, 101, 16, 129, 33, 11,
-/* 1970 */ 76, 5, 107, 11, 129, 32, 9, 77, 5, 110,
-/* 1980 */ 9, 129, 32, 7, 79, 4, 112, 7, 129, 31,
-/* 1990 */ 6, 80, 4, 114, 6, 129, 31, 5, 81, 4,
-/* 2000 */ 115, 5, 129, 30, 5, 82, 4, 116, 5, 129,
-/* 2010 */ 30, 4, 82, 4, 116, 5, 129, 30, 4, 82,
-/* 2020 */ 5, 117, 4, 131, 30, 5, 82, 5, 117, 4,
-/* 2030 */ 129, 31, 5, 81, 6, 117, 4, 129, 31, 6,
-/* 2040 */ 80, 7, 117, 4, 129, 32, 7, 79, 8, 117,
-/* 2050 */ 4, 129, 32, 9, 77, 9, 116, 5, 129, 33,
-/* 2060 */ 11, 75, 11, 116, 4, 129, 34, 16, 69, 16,
-/* 2070 */ 115, 5, 129, 35, 49, 114, 5, 129, 37, 46,
-/* 2080 */ 113, 5, 129, 38, 44, 112, 6, 129, 40, 41,
-/* 2090 */ 112, 5, 129, 42, 37, 113, 3, 129, 44, 33,
-/* 2100 */ 114, 1, 129, 47, 27, 129, 51, 17, 129, 193,
-/* 2110 */ 129, 103, 2, 129, 103, 6, 129, 104, 9, 129,
-/* 2120 */ 105, 12, 129, 106, 15, 129, 107, 14, 135, 30,
-/* 2130 */ 10, 107, 14, 129, 30, 17, 107, 14, 129, 30,
-/* 2140 */ 25, 107, 14, 129, 30, 31, 107, 14, 129, 30,
-/* 2150 */ 37, 107, 14, 129, 30, 42, 107, 14, 129, 30,
-/* 2160 */ 46, 107, 14, 129, 30, 50, 107, 14, 129, 30,
-/* 2170 */ 54, 107, 14, 129, 30, 58, 107, 14, 129, 59,
-/* 2180 */ 32, 107, 14, 129, 64, 30, 107, 14, 129, 74,
-/* 2190 */ 23, 107, 14, 129, 81, 18, 107, 14, 129, 86,
-/* 2200 */ 16, 107, 14, 129, 91, 14, 107, 14, 129, 96,
-/* 2210 */ 25, 129, 100, 21, 129, 104, 17, 129, 107, 14,
-/* 2220 */ 129, 111, 10, 129, 114, 7, 129, 117, 4, 129,
-/* 2230 */ 120, 1, 129, 193, 129, 48, 13, 129, 44, 21,
-/* 2240 */ 129, 42, 26, 129, 40, 30, 92, 12, 129, 38,
-/* 2250 */ 34, 88, 20, 129, 36, 37, 86, 25, 129, 35,
-/* 2260 */ 39, 84, 29, 129, 34, 13, 63, 12, 82, 33,
-/* 2270 */ 129, 33, 11, 67, 9, 80, 36, 129, 32, 9,
-/* 2280 */ 70, 7, 79, 38, 129, 31, 8, 72, 46, 129,
-/* 2290 */ 30, 7, 74, 22, 108, 11, 129, 30, 6, 75,
-/* 2300 */ 19, 111, 9, 129, 30, 5, 75, 17, 113, 7,
-/* 2310 */ 129, 30, 5, 74, 16, 114, 6, 129, 30, 4,
-/* 2320 */ 73, 16, 115, 6, 129, 30, 4, 72, 16, 116,
-/* 2330 */ 5, 129, 30, 4, 72, 15, 117, 4, 129, 30,
-/* 2340 */ 4, 71, 16, 117, 4, 129, 30, 5, 70, 16,
-/* 2350 */ 117, 4, 129, 30, 5, 70, 15, 117, 4, 129,
-/* 2360 */ 30, 6, 69, 15, 116, 5, 129, 30, 7, 68,
-/* 2370 */ 17, 115, 5, 129, 30, 9, 67, 19, 114, 6,
-/* 2380 */ 129, 30, 10, 65, 22, 113, 6, 129, 31, 12,
-/* 2390 */ 63, 27, 110, 9, 129, 32, 14, 60, 21, 84,
-/* 2400 */ 9, 106, 12, 129, 33, 47, 85, 32, 129, 34,
-/* 2410 */ 45, 86, 30, 129, 35, 43, 88, 26, 129, 36,
-/* 2420 */ 40, 90, 22, 129, 38, 36, 93, 17, 129, 40,
-/* 2430 */ 32, 96, 10, 129, 42, 28, 129, 44, 23, 129,
-/* 2440 */ 48, 15, 129, 193, 129, 83, 17, 129, 77, 27,
-/* 2450 */ 129, 36, 1, 74, 33, 129, 35, 3, 72, 37,
-/* 2460 */ 129, 34, 5, 70, 41, 129, 33, 6, 69, 44,
-/* 2470 */ 129, 33, 5, 68, 46, 129, 32, 5, 67, 49,
-/* 2480 */ 129, 31, 5, 66, 17, 101, 16, 129, 31, 5,
-/* 2490 */ 66, 11, 108, 10, 129, 30, 4, 65, 9, 110,
-/* 2500 */ 9, 129, 30, 4, 64, 8, 112, 7, 129, 30,
-/* 2510 */ 4, 64, 7, 114, 6, 129, 30, 4, 64, 6,
-/* 2520 */ 115, 5, 129, 30, 4, 64, 5, 116, 5, 129,
-/* 2530 */ 30, 4, 64, 5, 117, 4, 131, 30, 4, 65,
-/* 2540 */ 4, 117, 4, 129, 30, 5, 65, 4, 116, 5,
-/* 2550 */ 129, 31, 5, 66, 4, 115, 5, 129, 31, 6,
-/* 2560 */ 67, 4, 114, 6, 129, 32, 7, 68, 4, 112,
-/* 2570 */ 7, 129, 32, 9, 69, 5, 110, 9, 129, 33,
-/* 2580 */ 11, 70, 5, 107, 11, 129, 34, 16, 72, 5,
-/* 2590 */ 101, 16, 129, 35, 81, 129, 37, 77, 129, 38,
-/* 2600 */ 75, 129, 40, 71, 129, 42, 67, 129, 44, 63,
-/* 2610 */ 129, 47, 57, 129, 51, 49, 129, 56, 39, 129,
-/* 2620 */ 193, 130, 34, 6, 74, 6, 129, 32, 10, 72,
-/* 2630 */ 10, 129, 31, 12, 71, 12, 129, 30, 14, 70,
-/* 2640 */ 14, 131, 31, 12, 71, 12, 129, 32, 10, 72,
-/* 2650 */ 10, 129, 34, 6, 74, 6, 129, 194, 130, 34,
-/* 2660 */ 6, 74, 6, 129, 32, 10, 72, 10, 129, 31,
-/* 2670 */ 12, 71, 12, 129, 30, 14, 70, 14, 129, 20,
-/* 2680 */ 2, 28, 16, 70, 14, 129, 22, 22, 70, 14,
-/* 2690 */ 129, 24, 19, 71, 12, 129, 27, 15, 72, 10,
-/* 2700 */ 129, 31, 9, 74, 6, 129, 194, 129, 53, 4,
-/* 2710 */ 63, 4, 152, 193, 130, 99, 7, 129, 97, 13,
-/* 2720 */ 129, 96, 16, 129, 96, 18, 129, 96, 19, 129,
-/* 2730 */ 97, 19, 129, 99, 6, 110, 7, 129, 112, 6,
-/* 2740 */ 129, 114, 5, 129, 34, 6, 57, 5, 115, 4,
-/* 2750 */ 129, 32, 10, 54, 12, 116, 4, 129, 31, 12,
-/* 2760 */ 53, 16, 117, 3, 129, 30, 14, 52, 20, 117,
-/* 2770 */ 4, 129, 30, 14, 52, 23, 117, 4, 129, 30,
-/* 2780 */ 14, 52, 25, 117, 4, 129, 31, 12, 52, 27,
-/* 2790 */ 117, 4, 129, 32, 10, 53, 10, 70, 11, 116,
-/* 2800 */ 5, 129, 34, 6, 55, 5, 73, 10, 115, 6,
-/* 2810 */ 129, 74, 11, 114, 7, 129, 75, 12, 112, 9,
-/* 2820 */ 129, 76, 13, 110, 10, 129, 77, 16, 106, 14,
-/* 2830 */ 129, 78, 41, 129, 80, 38, 129, 81, 36, 129,
-/* 2840 */ 82, 34, 129, 84, 30, 129, 86, 26, 129, 88,
-/* 2850 */ 22, 129, 92, 14, 129, 194, 129, 55, 15, 129,
-/* 2860 */ 50, 25, 129, 47, 32, 129, 45, 13, 70, 12,
-/* 2870 */ 129, 43, 9, 76, 10, 129, 42, 6, 79, 8,
-/* 2880 */ 129, 41, 5, 81, 7, 129, 40, 4, 84, 6,
-/* 2890 */ 129, 39, 4, 59, 12, 85, 6, 129, 38, 4,
-/* 2900 */ 55, 19, 87, 5, 129, 37, 4, 53, 23, 88,
-/* 2910 */ 4, 129, 36, 4, 51, 8, 71, 6, 89, 4,
-/* 2920 */ 129, 36, 4, 51, 6, 73, 4, 89, 4, 129,
-/* 2930 */ 36, 4, 50, 6, 74, 4, 90, 3, 129, 35,
-/* 2940 */ 4, 50, 5, 75, 3, 90, 4, 129, 35, 4,
-/* 2950 */ 50, 4, 75, 4, 90, 4, 131, 35, 4, 50,
-/* 2960 */ 5, 75, 4, 90, 4, 129, 36, 4, 51, 5,
-/* 2970 */ 75, 4, 90, 4, 129, 36, 4, 51, 6, 75,
-/* 2980 */ 4, 90, 4, 129, 36, 4, 53, 26, 90, 4,
-/* 2990 */ 129, 37, 4, 54, 25, 90, 4, 129, 37, 4,
-/* 3000 */ 52, 27, 90, 3, 129, 38, 4, 52, 4, 89,
-/* 3010 */ 4, 129, 39, 4, 51, 4, 88, 4, 129, 40,
-/* 3020 */ 4, 50, 4, 87, 5, 129, 41, 4, 50, 4,
-/* 3030 */ 86, 5, 129, 42, 4, 50, 4, 85, 5, 129,
-/* 3040 */ 43, 3, 50, 4, 83, 6, 129, 44, 2, 51,
-/* 3050 */ 5, 80, 7, 129, 46, 1, 52, 6, 76, 9,
-/* 3060 */ 129, 54, 28, 129, 56, 23, 129, 60, 16, 129,
-/* 3070 */ 193, 129, 30, 4, 132, 30, 5, 129, 30, 8,
-/* 3080 */ 129, 30, 12, 129, 30, 16, 129, 30, 4, 37,
-/* 3090 */ 12, 129, 30, 4, 41, 12, 129, 30, 4, 44,
-/* 3100 */ 13, 129, 30, 4, 48, 13, 129, 52, 13, 129,
-/* 3110 */ 56, 12, 129, 58, 14, 129, 58, 4, 64, 12,
-/* 3120 */ 129, 58, 4, 68, 12, 129, 58, 4, 72, 12,
-/* 3130 */ 129, 58, 4, 75, 13, 129, 58, 4, 79, 13,
-/* 3140 */ 129, 58, 4, 83, 13, 129, 58, 4, 87, 13,
-/* 3150 */ 129, 58, 4, 91, 12, 129, 58, 4, 95, 12,
-/* 3160 */ 129, 58, 4, 96, 15, 129, 58, 4, 93, 22,
-/* 3170 */ 129, 58, 4, 89, 30, 129, 58, 4, 85, 36,
-/* 3180 */ 129, 58, 4, 81, 38, 129, 58, 4, 77, 38,
-/* 3190 */ 129, 58, 4, 73, 38, 129, 58, 4, 70, 37,
-/* 3200 */ 129, 58, 4, 66, 37, 129, 58, 41, 129, 58,
-/* 3210 */ 37, 129, 54, 38, 129, 30, 4, 50, 38, 129,
-/* 3220 */ 30, 4, 46, 38, 129, 30, 4, 42, 38, 129,
-/* 3230 */ 30, 4, 38, 39, 129, 30, 43, 129, 30, 39,
-/* 3240 */ 129, 30, 35, 129, 30, 31, 129, 30, 27, 129,
-/* 3250 */ 30, 24, 129, 30, 20, 129, 30, 16, 129, 30,
-/* 3260 */ 12, 129, 30, 8, 129, 30, 5, 129, 30, 4,
-/* 3270 */ 132, 193, 129, 30, 4, 117, 4, 132, 30, 91,
-/* 3280 */ 137, 30, 4, 80, 4, 117, 4, 138, 30, 4,
-/* 3290 */ 80, 5, 116, 5, 129, 30, 5, 79, 6, 116,
-/* 3300 */ 5, 130, 30, 6, 78, 8, 115, 6, 129, 31,
-/* 3310 */ 6, 77, 9, 115, 6, 129, 31, 7, 76, 11,
-/* 3320 */ 114, 6, 129, 31, 8, 75, 14, 112, 8, 129,
-/* 3330 */ 32, 8, 74, 16, 111, 9, 129, 32, 9, 73,
-/* 3340 */ 19, 109, 10, 129, 33, 10, 71, 24, 106, 13,
-/* 3350 */ 129, 33, 13, 68, 12, 83, 35, 129, 34, 16,
-/* 3360 */ 64, 15, 84, 33, 129, 35, 43, 85, 31, 129,
-/* 3370 */ 36, 41, 86, 29, 129, 37, 39, 88, 25, 129,
-/* 3380 */ 38, 37, 90, 21, 129, 40, 33, 93, 15, 129,
-/* 3390 */ 42, 29, 96, 9, 129, 45, 24, 129, 49, 16,
-/* 3400 */ 129, 193, 129, 63, 25, 129, 57, 37, 129, 53,
-/* 3410 */ 45, 129, 50, 51, 129, 47, 57, 129, 45, 61,
-/* 3420 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
-/* 3430 */ 38, 25, 92, 21, 129, 36, 21, 97, 18, 129,
-/* 3440 */ 35, 18, 102, 14, 129, 34, 16, 106, 11, 129,
-/* 3450 */ 33, 14, 108, 10, 129, 32, 12, 111, 8, 129,
-/* 3460 */ 32, 10, 113, 6, 129, 31, 10, 114, 6, 129,
-/* 3470 */ 31, 8, 115, 5, 129, 30, 8, 116, 5, 129,
-/* 3480 */ 30, 7, 116, 5, 129, 30, 6, 117, 4, 130,
-/* 3490 */ 30, 5, 117, 4, 131, 31, 4, 116, 5, 129,
-/* 3500 */ 32, 4, 116, 4, 129, 32, 5, 115, 5, 129,
-/* 3510 */ 33, 4, 114, 5, 129, 34, 4, 112, 6, 129,
-/* 3520 */ 35, 4, 110, 7, 129, 37, 4, 107, 9, 129,
-/* 3530 */ 39, 4, 103, 12, 129, 41, 4, 103, 18, 129,
-/* 3540 */ 43, 4, 103, 18, 129, 45, 5, 103, 18, 129,
-/* 3550 */ 48, 5, 103, 18, 129, 51, 1, 129, 193, 129,
-/* 3560 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
-/* 3570 */ 117, 4, 135, 30, 5, 116, 5, 130, 30, 6,
-/* 3580 */ 115, 6, 130, 31, 6, 114, 6, 129, 31, 7,
-/* 3590 */ 113, 7, 129, 32, 7, 112, 7, 129, 32, 8,
-/* 3600 */ 111, 8, 129, 33, 9, 109, 9, 129, 33, 12,
-/* 3610 */ 106, 12, 129, 34, 13, 104, 13, 129, 35, 15,
-/* 3620 */ 101, 15, 129, 36, 19, 96, 19, 129, 37, 24,
-/* 3630 */ 90, 24, 129, 39, 73, 129, 40, 71, 129, 42,
-/* 3640 */ 67, 129, 44, 63, 129, 46, 59, 129, 49, 53,
-/* 3650 */ 129, 52, 47, 129, 56, 39, 129, 61, 29, 129,
-/* 3660 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 137,
-/* 3670 */ 30, 4, 80, 4, 117, 4, 140, 30, 4, 79,
-/* 3680 */ 6, 117, 4, 129, 30, 4, 77, 10, 117, 4,
-/* 3690 */ 129, 30, 4, 73, 18, 117, 4, 132, 30, 4,
-/* 3700 */ 117, 4, 130, 30, 5, 116, 5, 130, 30, 7,
-/* 3710 */ 114, 7, 129, 30, 8, 113, 8, 129, 30, 11,
-/* 3720 */ 110, 11, 129, 30, 18, 103, 18, 132, 193, 129,
-/* 3730 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
-/* 3740 */ 80, 4, 117, 4, 132, 80, 4, 117, 4, 136,
-/* 3750 */ 79, 6, 117, 4, 129, 77, 10, 117, 4, 129,
-/* 3760 */ 73, 18, 117, 4, 132, 117, 4, 130, 116, 5,
-/* 3770 */ 130, 114, 7, 129, 113, 8, 129, 110, 11, 129,
-/* 3780 */ 103, 18, 132, 193, 129, 63, 25, 129, 57, 37,
-/* 3790 */ 129, 53, 45, 129, 50, 51, 129, 47, 57, 129,
-/* 3800 */ 45, 61, 129, 43, 65, 129, 41, 69, 129, 39,
-/* 3810 */ 73, 129, 38, 25, 92, 21, 129, 36, 21, 97,
-/* 3820 */ 18, 129, 35, 18, 102, 14, 129, 34, 16, 106,
-/* 3830 */ 11, 129, 33, 14, 108, 10, 129, 32, 12, 111,
-/* 3840 */ 8, 129, 32, 10, 113, 6, 129, 31, 10, 114,
-/* 3850 */ 6, 129, 31, 8, 115, 5, 129, 30, 8, 116,
-/* 3860 */ 5, 129, 30, 7, 116, 5, 129, 30, 6, 117,
-/* 3870 */ 4, 130, 30, 5, 117, 4, 131, 30, 5, 75,
-/* 3880 */ 4, 116, 5, 129, 31, 5, 75, 4, 116, 4,
-/* 3890 */ 129, 31, 6, 75, 4, 115, 5, 129, 32, 7,
-/* 3900 */ 75, 4, 114, 5, 129, 32, 9, 75, 4, 112,
-/* 3910 */ 6, 129, 33, 11, 75, 4, 110, 7, 129, 34,
-/* 3920 */ 15, 75, 4, 107, 9, 129, 35, 44, 103, 12,
-/* 3930 */ 129, 36, 43, 103, 18, 129, 38, 41, 103, 18,
-/* 3940 */ 129, 39, 40, 103, 18, 129, 41, 38, 103, 18,
-/* 3950 */ 129, 44, 35, 129, 48, 31, 129, 52, 27, 129,
-/* 3960 */ 61, 18, 129, 193, 129, 30, 4, 117, 4, 132,
-/* 3970 */ 30, 91, 137, 30, 4, 80, 4, 117, 4, 132,
-/* 3980 */ 80, 4, 140, 30, 4, 80, 4, 117, 4, 132,
-/* 3990 */ 30, 91, 137, 30, 4, 117, 4, 132, 193, 129,
-/* 4000 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
-/* 4010 */ 117, 4, 132, 193, 129, 44, 7, 129, 40, 13,
-/* 4020 */ 129, 37, 17, 129, 35, 20, 129, 34, 22, 129,
-/* 4030 */ 33, 23, 129, 32, 24, 129, 32, 23, 129, 31,
-/* 4040 */ 6, 41, 13, 129, 31, 5, 42, 11, 129, 30,
-/* 4050 */ 5, 44, 7, 129, 30, 4, 132, 30, 5, 130,
-/* 4060 */ 31, 5, 129, 31, 6, 117, 4, 129, 31, 8,
-/* 4070 */ 117, 4, 129, 32, 9, 117, 4, 129, 33, 11,
-/* 4080 */ 117, 4, 129, 34, 87, 129, 35, 86, 129, 36,
-/* 4090 */ 85, 129, 37, 84, 129, 38, 83, 129, 40, 81,
-/* 4100 */ 129, 42, 79, 129, 45, 76, 129, 50, 71, 129,
-/* 4110 */ 117, 4, 132, 193, 129, 30, 4, 117, 4, 132,
-/* 4120 */ 30, 91, 137, 30, 4, 76, 8, 117, 4, 129,
-/* 4130 */ 30, 4, 73, 13, 117, 4, 129, 30, 4, 70,
-/* 4140 */ 18, 117, 4, 129, 30, 4, 67, 23, 117, 4,
-/* 4150 */ 129, 65, 26, 129, 62, 31, 129, 59, 35, 129,
-/* 4160 */ 56, 29, 89, 7, 129, 53, 29, 91, 7, 129,
-/* 4170 */ 50, 29, 93, 7, 129, 47, 29, 95, 6, 129,
-/* 4180 */ 30, 4, 45, 29, 96, 7, 129, 30, 4, 42,
-/* 4190 */ 29, 98, 7, 129, 30, 4, 39, 30, 100, 6,
-/* 4200 */ 129, 30, 4, 36, 30, 101, 7, 129, 30, 33,
-/* 4210 */ 103, 7, 117, 4, 129, 30, 30, 105, 6, 117,
-/* 4220 */ 4, 129, 30, 27, 106, 7, 117, 4, 129, 30,
-/* 4230 */ 25, 108, 7, 117, 4, 129, 30, 22, 110, 11,
-/* 4240 */ 129, 30, 19, 111, 10, 129, 30, 16, 113, 8,
-/* 4250 */ 129, 30, 13, 115, 6, 129, 30, 11, 116, 5,
-/* 4260 */ 129, 30, 8, 117, 4, 129, 30, 5, 117, 4,
-/* 4270 */ 129, 30, 4, 117, 4, 130, 30, 4, 130, 193,
-/* 4280 */ 129, 30, 4, 117, 4, 132, 30, 91, 137, 30,
-/* 4290 */ 4, 117, 4, 132, 30, 4, 144, 30, 5, 130,
-/* 4300 */ 30, 7, 129, 30, 8, 129, 30, 11, 129, 30,
-/* 4310 */ 18, 132, 193, 129, 30, 4, 117, 4, 132, 30,
-/* 4320 */ 91, 132, 30, 4, 103, 18, 129, 30, 4, 97,
-/* 4330 */ 24, 129, 30, 4, 92, 29, 129, 30, 4, 87,
-/* 4340 */ 34, 129, 81, 40, 129, 76, 45, 129, 70, 49,
-/* 4350 */ 129, 65, 49, 129, 60, 49, 129, 55, 49, 129,
-/* 4360 */ 50, 48, 129, 44, 49, 129, 39, 48, 129, 33,
-/* 4370 */ 49, 129, 30, 47, 129, 34, 37, 129, 40, 26,
-/* 4380 */ 129, 46, 19, 129, 52, 19, 129, 58, 19, 129,
-/* 4390 */ 64, 19, 129, 70, 19, 129, 76, 19, 129, 82,
-/* 4400 */ 19, 129, 30, 4, 88, 18, 129, 30, 4, 94,
-/* 4410 */ 18, 129, 30, 4, 100, 18, 129, 30, 4, 106,
-/* 4420 */ 15, 129, 30, 91, 137, 30, 4, 117, 4, 132,
-/* 4430 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 132,
-/* 4440 */ 30, 4, 107, 14, 129, 30, 4, 104, 17, 129,
-/* 4450 */ 30, 4, 101, 20, 129, 30, 4, 99, 22, 129,
-/* 4460 */ 96, 25, 129, 93, 28, 129, 91, 28, 129, 88,
-/* 4470 */ 29, 129, 85, 29, 129, 82, 29, 129, 79, 29,
-/* 4480 */ 129, 76, 29, 129, 74, 29, 129, 71, 29, 129,
-/* 4490 */ 68, 29, 129, 65, 29, 129, 62, 29, 129, 60,
-/* 4500 */ 29, 129, 57, 29, 129, 54, 29, 129, 51, 29,
-/* 4510 */ 129, 49, 28, 129, 46, 29, 129, 43, 29, 129,
-/* 4520 */ 40, 29, 117, 4, 129, 37, 29, 117, 4, 129,
-/* 4530 */ 35, 29, 117, 4, 129, 32, 29, 117, 4, 129,
-/* 4540 */ 30, 91, 132, 117, 4, 132, 193, 129, 63, 25,
-/* 4550 */ 129, 57, 37, 129, 53, 45, 129, 50, 51, 129,
-/* 4560 */ 47, 57, 129, 45, 61, 129, 43, 65, 129, 41,
-/* 4570 */ 69, 129, 39, 73, 129, 38, 21, 92, 21, 129,
-/* 4580 */ 36, 18, 97, 18, 129, 35, 14, 102, 14, 129,
-/* 4590 */ 34, 11, 106, 11, 129, 33, 10, 108, 10, 129,
-/* 4600 */ 32, 8, 111, 8, 129, 32, 6, 113, 6, 129,
-/* 4610 */ 31, 6, 114, 6, 129, 31, 5, 115, 5, 129,
-/* 4620 */ 30, 5, 116, 5, 130, 30, 4, 117, 4, 132,
-/* 4630 */ 30, 5, 116, 5, 130, 31, 5, 115, 5, 129,
-/* 4640 */ 31, 6, 114, 6, 129, 32, 6, 113, 6, 129,
-/* 4650 */ 32, 8, 111, 8, 129, 33, 10, 108, 10, 129,
-/* 4660 */ 34, 11, 106, 11, 129, 35, 14, 102, 14, 129,
-/* 4670 */ 36, 18, 97, 18, 129, 38, 21, 92, 21, 129,
-/* 4680 */ 39, 73, 129, 41, 69, 129, 43, 65, 129, 45,
-/* 4690 */ 61, 129, 47, 57, 129, 50, 51, 129, 53, 45,
-/* 4700 */ 129, 57, 37, 129, 63, 25, 129, 193, 129, 30,
-/* 4710 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 80,
-/* 4720 */ 4, 117, 4, 132, 80, 4, 117, 4, 134, 80,
-/* 4730 */ 5, 116, 5, 131, 80, 6, 115, 6, 130, 81,
-/* 4740 */ 6, 114, 6, 129, 81, 8, 112, 8, 129, 81,
-/* 4750 */ 9, 111, 9, 129, 82, 10, 109, 10, 129, 82,
-/* 4760 */ 13, 106, 13, 129, 83, 35, 129, 84, 33, 129,
-/* 4770 */ 85, 31, 129, 86, 29, 129, 88, 25, 129, 90,
-/* 4780 */ 21, 129, 93, 15, 129, 96, 9, 129, 193, 129,
-/* 4790 */ 63, 25, 129, 57, 37, 129, 53, 45, 129, 50,
-/* 4800 */ 51, 129, 47, 57, 129, 45, 61, 129, 43, 65,
-/* 4810 */ 129, 41, 69, 129, 39, 73, 129, 38, 21, 92,
-/* 4820 */ 21, 129, 36, 18, 97, 18, 129, 35, 14, 102,
-/* 4830 */ 14, 129, 34, 11, 106, 11, 129, 33, 10, 108,
-/* 4840 */ 10, 129, 32, 8, 111, 8, 129, 32, 6, 113,
-/* 4850 */ 6, 129, 31, 6, 114, 6, 129, 31, 5, 115,
-/* 4860 */ 5, 129, 30, 5, 116, 5, 130, 30, 4, 39,
-/* 4870 */ 2, 117, 4, 129, 30, 4, 40, 4, 117, 4,
-/* 4880 */ 129, 30, 4, 41, 5, 117, 4, 129, 30, 4,
-/* 4890 */ 41, 6, 117, 4, 129, 30, 5, 40, 8, 116,
-/* 4900 */ 5, 129, 30, 5, 39, 10, 116, 5, 129, 31,
-/* 4910 */ 5, 38, 11, 115, 5, 129, 31, 18, 114, 6,
-/* 4920 */ 129, 32, 17, 113, 6, 129, 32, 16, 111, 8,
-/* 4930 */ 129, 33, 15, 108, 10, 129, 33, 14, 106, 11,
-/* 4940 */ 129, 32, 17, 102, 14, 129, 31, 23, 97, 18,
-/* 4950 */ 129, 31, 28, 92, 21, 129, 30, 82, 129, 30,
-/* 4960 */ 80, 129, 30, 11, 43, 65, 129, 30, 10, 45,
-/* 4970 */ 61, 129, 31, 8, 47, 57, 129, 32, 6, 50,
-/* 4980 */ 51, 129, 33, 5, 53, 45, 129, 35, 4, 57,
-/* 4990 */ 37, 129, 38, 2, 63, 25, 129, 193, 129, 30,
-/* 5000 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 76,
-/* 5010 */ 8, 117, 4, 129, 30, 4, 73, 11, 117, 4,
-/* 5020 */ 129, 30, 4, 70, 14, 117, 4, 129, 30, 4,
-/* 5030 */ 67, 17, 117, 4, 129, 65, 19, 117, 4, 129,
-/* 5040 */ 62, 22, 117, 4, 129, 59, 25, 117, 4, 129,
-/* 5050 */ 56, 28, 117, 4, 129, 53, 31, 117, 4, 129,
-/* 5060 */ 50, 34, 117, 4, 129, 47, 29, 80, 5, 116,
-/* 5070 */ 5, 129, 30, 4, 45, 29, 80, 5, 116, 5,
-/* 5080 */ 129, 30, 4, 42, 29, 80, 5, 116, 5, 129,
-/* 5090 */ 30, 4, 39, 30, 80, 6, 115, 6, 129, 30,
-/* 5100 */ 4, 36, 30, 80, 6, 115, 6, 129, 30, 33,
-/* 5110 */ 81, 6, 114, 6, 129, 30, 30, 81, 8, 112,
-/* 5120 */ 8, 129, 30, 27, 81, 9, 111, 9, 129, 30,
-/* 5130 */ 25, 82, 10, 109, 10, 129, 30, 22, 82, 13,
-/* 5140 */ 106, 13, 129, 30, 19, 83, 35, 129, 30, 16,
-/* 5150 */ 84, 33, 129, 30, 13, 85, 31, 129, 30, 11,
-/* 5160 */ 86, 29, 129, 30, 8, 88, 25, 129, 30, 5,
-/* 5170 */ 90, 21, 129, 30, 4, 93, 15, 129, 30, 4,
-/* 5180 */ 96, 9, 129, 30, 4, 130, 193, 129, 30, 18,
-/* 5190 */ 130, 30, 18, 89, 15, 129, 30, 18, 85, 23,
-/* 5200 */ 129, 34, 11, 83, 27, 129, 34, 9, 81, 31,
-/* 5210 */ 129, 33, 8, 79, 35, 129, 33, 6, 78, 16,
-/* 5220 */ 106, 9, 129, 32, 6, 77, 15, 109, 7, 129,
-/* 5230 */ 32, 5, 76, 14, 111, 6, 129, 31, 5, 75,
-/* 5240 */ 14, 113, 5, 129, 31, 4, 74, 15, 114, 5,
-/* 5250 */ 129, 31, 4, 74, 14, 115, 4, 129, 30, 4,
-/* 5260 */ 73, 15, 116, 4, 129, 30, 4, 73, 14, 116,
-/* 5270 */ 4, 129, 30, 4, 73, 14, 117, 4, 129, 30,
-/* 5280 */ 4, 72, 15, 117, 4, 130, 30, 4, 71, 15,
-/* 5290 */ 117, 4, 130, 30, 4, 70, 15, 117, 4, 129,
-/* 5300 */ 30, 5, 70, 15, 117, 4, 129, 30, 5, 69,
-/* 5310 */ 15, 116, 5, 129, 30, 6, 68, 16, 115, 5,
-/* 5320 */ 129, 31, 6, 67, 16, 114, 6, 129, 31, 7,
-/* 5330 */ 66, 17, 113, 6, 129, 32, 7, 64, 18, 111,
-/* 5340 */ 8, 129, 32, 8, 62, 19, 109, 9, 129, 33,
-/* 5350 */ 9, 60, 20, 107, 10, 129, 34, 11, 57, 22,
-/* 5360 */ 103, 13, 129, 35, 43, 103, 18, 129, 36, 41,
-/* 5370 */ 103, 18, 129, 38, 38, 103, 18, 129, 39, 35,
-/* 5380 */ 103, 18, 129, 41, 31, 129, 43, 27, 129, 46,
-/* 5390 */ 22, 129, 49, 14, 129, 193, 129, 103, 18, 132,
-/* 5400 */ 110, 11, 129, 113, 8, 129, 114, 7, 129, 116,
-/* 5410 */ 5, 130, 117, 4, 132, 30, 4, 117, 4, 132,
-/* 5420 */ 30, 91, 137, 30, 4, 117, 4, 132, 117, 4,
-/* 5430 */ 132, 116, 5, 130, 114, 7, 129, 113, 8, 129,
-/* 5440 */ 110, 11, 129, 103, 18, 132, 193, 129, 117, 4,
-/* 5450 */ 132, 56, 65, 129, 50, 71, 129, 46, 75, 129,
-/* 5460 */ 44, 77, 129, 42, 79, 129, 40, 81, 129, 38,
-/* 5470 */ 83, 129, 36, 85, 129, 35, 86, 129, 34, 20,
-/* 5480 */ 117, 4, 129, 33, 17, 117, 4, 129, 32, 15,
-/* 5490 */ 117, 4, 129, 32, 13, 117, 4, 129, 31, 12,
-/* 5500 */ 129, 31, 10, 129, 31, 9, 129, 30, 9, 129,
-/* 5510 */ 30, 8, 130, 30, 7, 132, 31, 6, 130, 31,
-/* 5520 */ 7, 129, 32, 6, 129, 32, 7, 129, 33, 7,
-/* 5530 */ 129, 34, 7, 129, 35, 8, 129, 36, 9, 117,
-/* 5540 */ 4, 129, 38, 9, 117, 4, 129, 40, 10, 117,
-/* 5550 */ 4, 129, 42, 12, 117, 4, 129, 44, 77, 129,
-/* 5560 */ 46, 75, 129, 50, 71, 129, 56, 43, 100, 21,
-/* 5570 */ 129, 117, 4, 132, 193, 129, 117, 4, 132, 115,
-/* 5580 */ 6, 129, 110, 11, 129, 105, 16, 129, 101, 20,
-/* 5590 */ 129, 96, 25, 129, 92, 29, 129, 87, 34, 129,
-/* 5600 */ 83, 38, 129, 78, 43, 129, 74, 47, 129, 70,
-/* 5610 */ 42, 117, 4, 129, 65, 42, 117, 4, 129, 60,
-/* 5620 */ 43, 117, 4, 129, 56, 42, 129, 51, 42, 129,
-/* 5630 */ 46, 43, 129, 42, 43, 129, 37, 44, 129, 33,
-/* 5640 */ 43, 129, 30, 42, 129, 33, 34, 129, 38, 25,
-/* 5650 */ 129, 42, 16, 129, 47, 15, 129, 52, 15, 129,
-/* 5660 */ 57, 15, 129, 61, 16, 129, 66, 16, 129, 71,
-/* 5670 */ 16, 129, 76, 16, 129, 80, 16, 129, 85, 16,
-/* 5680 */ 117, 4, 129, 90, 16, 117, 4, 129, 95, 16,
-/* 5690 */ 117, 4, 129, 100, 21, 129, 105, 16, 129, 110,
-/* 5700 */ 11, 129, 114, 7, 129, 117, 4, 132, 193, 129,
-/* 5710 */ 117, 4, 132, 115, 6, 129, 110, 11, 129, 105,
-/* 5720 */ 16, 129, 101, 20, 129, 96, 25, 129, 92, 29,
-/* 5730 */ 129, 87, 34, 129, 83, 38, 129, 78, 43, 129,
-/* 5740 */ 74, 47, 129, 70, 42, 117, 4, 129, 65, 42,
-/* 5750 */ 117, 4, 129, 60, 43, 117, 4, 129, 56, 42,
-/* 5760 */ 129, 51, 42, 129, 46, 43, 129, 42, 43, 129,
-/* 5770 */ 37, 44, 129, 33, 43, 129, 30, 42, 129, 33,
-/* 5780 */ 34, 129, 38, 25, 129, 42, 16, 129, 47, 15,
-/* 5790 */ 129, 52, 15, 129, 57, 15, 129, 61, 16, 129,
-/* 5800 */ 65, 17, 129, 60, 27, 129, 56, 36, 129, 51,
-/* 5810 */ 42, 129, 46, 43, 129, 42, 43, 129, 37, 44,
-/* 5820 */ 129, 33, 43, 129, 30, 42, 129, 33, 34, 129,
-/* 5830 */ 38, 25, 129, 42, 16, 129, 47, 15, 129, 52,
-/* 5840 */ 15, 129, 57, 15, 129, 61, 16, 129, 66, 16,
-/* 5850 */ 129, 71, 16, 129, 76, 16, 129, 80, 16, 129,
-/* 5860 */ 85, 16, 117, 4, 129, 90, 16, 117, 4, 129,
-/* 5870 */ 95, 16, 117, 4, 129, 100, 21, 129, 105, 16,
-/* 5880 */ 129, 110, 11, 129, 114, 7, 129, 117, 4, 132,
-/* 5890 */ 193, 129, 30, 4, 117, 4, 132, 30, 4, 115,
-/* 5900 */ 6, 129, 30, 4, 112, 9, 129, 30, 6, 109,
-/* 5910 */ 12, 129, 30, 9, 106, 15, 129, 30, 11, 103,
-/* 5920 */ 18, 129, 30, 14, 100, 21, 129, 30, 4, 38,
-/* 5930 */ 9, 98, 23, 129, 30, 4, 40, 10, 95, 26,
-/* 5940 */ 129, 30, 4, 43, 9, 92, 29, 129, 46, 9,
-/* 5950 */ 89, 32, 129, 49, 8, 86, 28, 117, 4, 129,
-/* 5960 */ 51, 9, 83, 28, 117, 4, 129, 54, 9, 80,
-/* 5970 */ 28, 117, 4, 129, 57, 8, 77, 28, 117, 4,
-/* 5980 */ 129, 59, 9, 74, 28, 129, 62, 37, 129, 64,
-/* 5990 */ 33, 129, 66, 28, 129, 63, 28, 129, 60, 28,
-/* 6000 */ 129, 57, 28, 129, 54, 33, 129, 51, 39, 129,
-/* 6010 */ 48, 29, 83, 9, 129, 30, 4, 45, 29, 86,
-/* 6020 */ 9, 129, 30, 4, 42, 29, 89, 9, 129, 30,
-/* 6030 */ 4, 39, 29, 92, 8, 129, 30, 4, 36, 29,
-/* 6040 */ 94, 9, 129, 30, 32, 97, 9, 129, 30, 29,
-/* 6050 */ 100, 8, 117, 4, 129, 30, 26, 103, 8, 117,
-/* 6060 */ 4, 129, 30, 23, 105, 9, 117, 4, 129, 30,
-/* 6070 */ 20, 108, 13, 129, 30, 18, 111, 10, 129, 30,
-/* 6080 */ 15, 113, 8, 129, 30, 12, 116, 5, 129, 30,
-/* 6090 */ 9, 117, 4, 129, 30, 6, 117, 4, 129, 30,
-/* 6100 */ 4, 117, 4, 132, 193, 129, 117, 4, 132, 114,
-/* 6110 */ 7, 129, 111, 10, 129, 108, 13, 129, 105, 16,
-/* 6120 */ 129, 102, 19, 129, 100, 21, 129, 96, 25, 129,
-/* 6130 */ 93, 28, 129, 90, 31, 129, 87, 34, 129, 84,
-/* 6140 */ 30, 117, 4, 129, 30, 4, 81, 30, 117, 4,
-/* 6150 */ 129, 30, 4, 78, 30, 117, 4, 129, 30, 4,
-/* 6160 */ 75, 30, 117, 4, 129, 30, 4, 72, 30, 129,
-/* 6170 */ 30, 69, 129, 30, 66, 129, 30, 63, 129, 30,
-/* 6180 */ 60, 129, 30, 57, 129, 30, 54, 129, 30, 51,
-/* 6190 */ 129, 30, 48, 129, 30, 51, 129, 30, 4, 73,
-/* 6200 */ 12, 129, 30, 4, 76, 12, 129, 30, 4, 80,
-/* 6210 */ 12, 129, 30, 4, 83, 12, 129, 87, 12, 129,
-/* 6220 */ 90, 12, 117, 4, 129, 94, 11, 117, 4, 129,
-/* 6230 */ 97, 12, 117, 4, 129, 101, 12, 117, 4, 129,
-/* 6240 */ 104, 17, 129, 108, 13, 129, 111, 10, 129, 115,
-/* 6250 */ 6, 129, 117, 4, 134, 193, 129, 30, 1, 103,
-/* 6260 */ 18, 129, 30, 4, 103, 18, 129, 30, 7, 103,
-/* 6270 */ 18, 129, 30, 9, 103, 18, 129, 30, 12, 110,
-/* 6280 */ 11, 129, 30, 15, 113, 8, 129, 30, 18, 114,
-/* 6290 */ 7, 129, 30, 21, 116, 5, 129, 30, 24, 116,
-/* 6300 */ 5, 129, 30, 27, 117, 4, 129, 30, 30, 117,
-/* 6310 */ 4, 129, 30, 33, 117, 4, 129, 30, 4, 37,
-/* 6320 */ 28, 117, 4, 129, 30, 4, 40, 28, 117, 4,
-/* 6330 */ 129, 30, 4, 42, 29, 117, 4, 129, 30, 4,
-/* 6340 */ 45, 29, 117, 4, 129, 30, 4, 48, 29, 117,
-/* 6350 */ 4, 129, 30, 4, 51, 29, 117, 4, 129, 30,
-/* 6360 */ 4, 54, 29, 117, 4, 129, 30, 4, 57, 29,
-/* 6370 */ 117, 4, 129, 30, 4, 59, 30, 117, 4, 129,
-/* 6380 */ 30, 4, 62, 30, 117, 4, 129, 30, 4, 65,
-/* 6390 */ 30, 117, 4, 129, 30, 4, 68, 30, 117, 4,
-/* 6400 */ 129, 30, 4, 71, 30, 117, 4, 129, 30, 4,
-/* 6410 */ 74, 30, 117, 4, 129, 30, 4, 77, 30, 117,
-/* 6420 */ 4, 129, 30, 4, 80, 30, 117, 4, 129, 30,
-/* 6430 */ 4, 83, 30, 117, 4, 129, 30, 4, 86, 35,
-/* 6440 */ 129, 30, 4, 89, 32, 129, 30, 4, 91, 30,
-/* 6450 */ 129, 30, 4, 94, 27, 129, 30, 5, 97, 24,
-/* 6460 */ 129, 30, 5, 100, 21, 129, 30, 7, 103, 18,
-/* 6470 */ 129, 30, 8, 106, 15, 129, 30, 11, 109, 12,
-/* 6480 */ 129, 30, 18, 112, 9, 129, 30, 18, 115, 6,
-/* 6490 */ 129, 30, 18, 117, 4, 129, 30, 18, 120, 1,
-/* 6500 */ 129, 193, 129, 42, 8, 129, 38, 16, 129, 36,
-/* 6510 */ 20, 129, 34, 24, 71, 5, 129, 33, 26, 69,
-/* 6520 */ 10, 129, 32, 28, 68, 13, 129, 31, 30, 68,
-/* 6530 */ 14, 129, 31, 9, 52, 9, 68, 15, 129, 30,
-/* 6540 */ 8, 54, 8, 69, 14, 129, 30, 7, 55, 7,
-/* 6550 */ 71, 4, 78, 6, 129, 30, 6, 56, 6, 79,
-/* 6560 */ 5, 129, 30, 6, 56, 6, 80, 4, 130, 31,
-/* 6570 */ 5, 56, 5, 80, 4, 129, 31, 5, 56, 5,
-/* 6580 */ 79, 5, 129, 32, 5, 55, 5, 78, 6, 129,
-/* 6590 */ 33, 5, 54, 5, 77, 7, 129, 34, 6, 52,
-/* 6600 */ 6, 74, 9, 129, 35, 48, 129, 33, 49, 129,
-/* 6610 */ 32, 49, 129, 31, 49, 129, 30, 49, 129, 30,
-/* 6620 */ 47, 129, 30, 45, 129, 30, 41, 129, 30, 6,
-/* 6630 */ 129, 30, 4, 129, 30, 3, 129, 30, 2, 129,
-/* 6640 */ 193, 129, 30, 4, 117, 4, 130, 31, 90, 136,
-/* 6650 */ 37, 5, 72, 5, 129, 35, 5, 74, 5, 129,
-/* 6660 */ 33, 5, 76, 5, 129, 32, 5, 77, 5, 129,
-/* 6670 */ 31, 5, 78, 5, 129, 31, 4, 79, 4, 129,
-/* 6680 */ 30, 5, 79, 5, 131, 30, 6, 78, 6, 129,
-/* 6690 */ 30, 7, 77, 7, 129, 31, 8, 75, 8, 129,
-/* 6700 */ 31, 11, 72, 11, 129, 32, 15, 67, 15, 129,
-/* 6710 */ 33, 48, 129, 34, 46, 129, 35, 44, 129, 37,
-/* 6720 */ 40, 129, 39, 36, 129, 42, 30, 129, 46, 22,
-/* 6730 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
-/* 6740 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
-/* 6750 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
-/* 6760 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
-/* 6770 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
-/* 6780 */ 5, 79, 5, 129, 30, 4, 80, 4, 133, 31,
-/* 6790 */ 3, 79, 4, 129, 31, 4, 79, 4, 129, 32,
-/* 6800 */ 3, 78, 4, 129, 32, 4, 76, 6, 129, 33,
-/* 6810 */ 4, 74, 7, 129, 34, 4, 72, 8, 129, 35,
-/* 6820 */ 5, 72, 7, 129, 37, 5, 73, 4, 129, 39,
-/* 6830 */ 4, 74, 1, 129, 129, 193, 129, 46, 22, 129,
-/* 6840 */ 42, 30, 129, 39, 36, 129, 37, 40, 129, 35,
-/* 6850 */ 44, 129, 34, 46, 129, 33, 48, 129, 32, 15,
-/* 6860 */ 67, 15, 129, 31, 11, 72, 11, 129, 31, 8,
-/* 6870 */ 75, 8, 129, 30, 7, 77, 7, 129, 30, 6,
-/* 6880 */ 78, 6, 129, 30, 5, 79, 5, 131, 31, 4,
-/* 6890 */ 79, 4, 129, 31, 5, 78, 5, 129, 32, 5,
-/* 6900 */ 77, 5, 129, 33, 5, 76, 5, 129, 35, 5,
-/* 6910 */ 74, 5, 117, 4, 129, 37, 5, 72, 5, 117,
-/* 6920 */ 4, 129, 30, 91, 136, 30, 4, 130, 193, 129,
-/* 6930 */ 48, 18, 129, 43, 28, 129, 41, 32, 129, 39,
-/* 6940 */ 36, 129, 37, 40, 129, 35, 44, 129, 34, 46,
-/* 6950 */ 129, 33, 13, 55, 4, 68, 13, 129, 32, 9,
-/* 6960 */ 55, 4, 73, 9, 129, 32, 7, 55, 4, 75,
-/* 6970 */ 7, 129, 31, 6, 55, 4, 77, 6, 129, 31,
-/* 6980 */ 5, 55, 4, 78, 5, 129, 30, 5, 55, 4,
-/* 6990 */ 79, 5, 129, 30, 4, 55, 4, 80, 4, 132,
-/* 7000 */ 30, 4, 55, 4, 79, 5, 129, 31, 3, 55,
-/* 7010 */ 4, 78, 5, 129, 31, 4, 55, 4, 77, 6,
-/* 7020 */ 129, 32, 3, 55, 4, 75, 7, 129, 32, 4,
-/* 7030 */ 55, 4, 73, 9, 129, 33, 4, 55, 4, 68,
-/* 7040 */ 13, 129, 34, 4, 55, 25, 129, 35, 5, 55,
-/* 7050 */ 24, 129, 37, 5, 55, 22, 129, 39, 4, 55,
-/* 7060 */ 20, 129, 55, 18, 129, 55, 16, 129, 55, 11,
-/* 7070 */ 129, 193, 129, 80, 4, 129, 30, 4, 80, 4,
-/* 7080 */ 130, 30, 78, 129, 30, 82, 129, 30, 85, 129,
-/* 7090 */ 30, 87, 129, 30, 88, 129, 30, 89, 129, 30,
-/* 7100 */ 90, 130, 30, 4, 80, 4, 115, 6, 129, 30,
-/* 7110 */ 4, 80, 4, 117, 4, 129, 80, 4, 105, 6,
-/* 7120 */ 117, 4, 129, 80, 4, 103, 10, 116, 5, 129,
-/* 7130 */ 80, 4, 102, 19, 129, 80, 4, 101, 19, 129,
-/* 7140 */ 101, 19, 129, 101, 18, 129, 102, 16, 129, 103,
-/* 7150 */ 12, 129, 105, 6, 129, 193, 129, 12, 10, 59,
-/* 7160 */ 11, 129, 9, 16, 55, 19, 129, 7, 20, 53,
-/* 7170 */ 23, 129, 6, 7, 23, 5, 32, 6, 51, 27,
-/* 7180 */ 129, 4, 7, 25, 16, 50, 29, 129, 3, 6,
-/* 7190 */ 27, 16, 49, 31, 129, 2, 6, 28, 16, 48,
-/* 7200 */ 33, 129, 1, 6, 27, 18, 47, 35, 129, 1,
-/* 7210 */ 6, 27, 31, 71, 12, 129, 1, 5, 26, 15,
-/* 7220 */ 44, 10, 75, 8, 129, 1, 5, 25, 14, 45,
-/* 7230 */ 7, 77, 7, 129, 1, 5, 25, 13, 45, 5,
-/* 7240 */ 79, 5, 129, 1, 5, 24, 14, 45, 4, 80,
-/* 7250 */ 4, 129, 1, 5, 24, 13, 45, 4, 80, 4,
-/* 7260 */ 129, 1, 5, 23, 14, 45, 4, 80, 4, 129,
-/* 7270 */ 1, 5, 23, 13, 45, 4, 80, 4, 129, 1,
-/* 7280 */ 6, 22, 13, 45, 5, 79, 5, 129, 1, 6,
-/* 7290 */ 21, 14, 45, 7, 77, 7, 129, 1, 7, 21,
-/* 7300 */ 13, 46, 8, 75, 8, 129, 1, 8, 20, 13,
-/* 7310 */ 46, 12, 71, 12, 129, 1, 10, 18, 15, 47,
-/* 7320 */ 35, 129, 2, 30, 48, 33, 129, 3, 29, 49,
-/* 7330 */ 32, 129, 4, 27, 50, 31, 129, 5, 25, 51,
-/* 7340 */ 27, 80, 2, 86, 4, 129, 7, 21, 53, 23,
-/* 7350 */ 80, 3, 85, 6, 129, 9, 17, 55, 19, 80,
-/* 7360 */ 12, 129, 12, 12, 59, 11, 81, 11, 129, 82,
-/* 7370 */ 10, 129, 84, 7, 129, 86, 4, 129, 193, 129,
-/* 7380 */ 30, 4, 117, 4, 130, 30, 91, 136, 30, 4,
-/* 7390 */ 72, 5, 129, 30, 4, 74, 5, 129, 75, 5,
-/* 7400 */ 129, 76, 5, 129, 76, 6, 129, 77, 6, 130,
-/* 7410 */ 77, 7, 130, 76, 8, 129, 30, 4, 75, 9,
-/* 7420 */ 129, 30, 4, 72, 12, 129, 30, 54, 129, 30,
-/* 7430 */ 53, 130, 30, 52, 129, 30, 51, 129, 30, 49,
-/* 7440 */ 129, 30, 46, 129, 30, 42, 129, 30, 4, 130,
-/* 7450 */ 193, 129, 30, 4, 80, 4, 129, 30, 4, 80,
-/* 7460 */ 4, 100, 6, 129, 30, 54, 98, 10, 129, 30,
-/* 7470 */ 54, 97, 12, 129, 30, 54, 96, 14, 131, 30,
-/* 7480 */ 54, 97, 12, 129, 30, 54, 98, 10, 129, 30,
-/* 7490 */ 54, 100, 6, 129, 30, 4, 130, 193, 129, 7,
-/* 7500 */ 6, 129, 4, 11, 129, 3, 13, 129, 2, 14,
-/* 7510 */ 129, 1, 15, 130, 1, 3, 6, 9, 129, 1,
-/* 7520 */ 3, 7, 6, 129, 1, 3, 130, 1, 4, 129,
-/* 7530 */ 1, 5, 80, 4, 129, 1, 7, 80, 4, 100,
-/* 7540 */ 6, 129, 2, 82, 98, 10, 129, 3, 81, 97,
-/* 7550 */ 12, 129, 4, 80, 96, 14, 129, 5, 79, 96,
-/* 7560 */ 14, 129, 7, 77, 96, 14, 129, 10, 74, 97,
-/* 7570 */ 12, 129, 14, 70, 98, 10, 129, 19, 65, 100,
-/* 7580 */ 6, 129, 193, 129, 30, 4, 117, 4, 130, 30,
-/* 7590 */ 91, 136, 30, 4, 57, 9, 129, 30, 4, 55,
-/* 7600 */ 12, 129, 52, 17, 129, 50, 20, 129, 48, 24,
-/* 7610 */ 129, 46, 27, 129, 44, 21, 69, 6, 129, 41,
-/* 7620 */ 22, 70, 6, 80, 4, 129, 30, 4, 39, 21,
-/* 7630 */ 72, 6, 80, 4, 129, 30, 4, 36, 22, 73,
-/* 7640 */ 11, 129, 30, 26, 75, 9, 129, 30, 23, 76,
-/* 7650 */ 8, 129, 30, 21, 78, 6, 129, 30, 19, 79,
-/* 7660 */ 5, 129, 30, 16, 80, 4, 129, 30, 14, 80,
-/* 7670 */ 4, 129, 30, 12, 129, 30, 10, 129, 30, 7,
-/* 7680 */ 129, 30, 5, 129, 30, 4, 130, 193, 129, 30,
-/* 7690 */ 4, 117, 4, 130, 30, 91, 136, 30, 4, 130,
-/* 7700 */ 193, 129, 30, 4, 80, 4, 130, 30, 54, 136,
-/* 7710 */ 30, 4, 72, 5, 129, 30, 4, 74, 5, 129,
-/* 7720 */ 75, 5, 129, 76, 5, 129, 30, 4, 75, 7,
-/* 7730 */ 129, 30, 4, 74, 9, 129, 30, 54, 132, 30,
-/* 7740 */ 53, 129, 30, 52, 129, 30, 51, 129, 30, 48,
-/* 7750 */ 129, 30, 4, 72, 5, 129, 30, 4, 74, 5,
-/* 7760 */ 129, 75, 5, 129, 76, 5, 129, 30, 4, 75,
-/* 7770 */ 7, 129, 30, 4, 74, 9, 129, 30, 54, 132,
-/* 7780 */ 30, 53, 129, 30, 52, 129, 30, 51, 129, 30,
-/* 7790 */ 48, 129, 30, 4, 130, 193, 129, 30, 4, 80,
-/* 7800 */ 4, 130, 30, 54, 136, 30, 4, 72, 5, 129,
-/* 7810 */ 30, 4, 74, 5, 129, 75, 5, 129, 76, 5,
-/* 7820 */ 129, 76, 6, 129, 77, 6, 130, 77, 7, 130,
-/* 7830 */ 76, 8, 129, 30, 4, 75, 9, 129, 30, 4,
-/* 7840 */ 72, 12, 129, 30, 54, 129, 30, 53, 130, 30,
-/* 7850 */ 52, 129, 30, 51, 129, 30, 49, 129, 30, 46,
-/* 7860 */ 129, 30, 42, 129, 30, 4, 130, 193, 129, 48,
-/* 7870 */ 18, 129, 43, 28, 129, 41, 32, 129, 39, 36,
-/* 7880 */ 129, 37, 40, 129, 35, 44, 129, 34, 46, 129,
-/* 7890 */ 33, 13, 68, 13, 129, 32, 9, 73, 9, 129,
-/* 7900 */ 32, 7, 75, 7, 129, 31, 6, 77, 6, 129,
-/* 7910 */ 31, 5, 78, 5, 129, 30, 5, 79, 5, 129,
-/* 7920 */ 30, 4, 80, 4, 132, 30, 5, 79, 5, 130,
-/* 7930 */ 31, 5, 78, 5, 129, 31, 6, 77, 6, 129,
-/* 7940 */ 32, 7, 75, 7, 129, 32, 9, 73, 9, 129,
-/* 7950 */ 33, 13, 68, 13, 129, 34, 46, 129, 35, 44,
-/* 7960 */ 129, 37, 40, 129, 39, 36, 129, 41, 32, 129,
-/* 7970 */ 43, 28, 129, 48, 18, 129, 193, 129, 1, 3,
-/* 7980 */ 80, 4, 130, 1, 83, 137, 37, 5, 72, 5,
-/* 7990 */ 129, 35, 5, 74, 5, 129, 33, 5, 76, 5,
-/* 8000 */ 129, 32, 5, 77, 5, 129, 31, 5, 78, 5,
-/* 8010 */ 129, 31, 4, 79, 4, 129, 30, 5, 79, 5,
-/* 8020 */ 131, 30, 6, 78, 6, 129, 30, 7, 77, 7,
-/* 8030 */ 129, 31, 8, 75, 8, 129, 31, 11, 72, 11,
-/* 8040 */ 129, 32, 15, 67, 15, 129, 33, 48, 129, 34,
-/* 8050 */ 46, 129, 35, 44, 129, 37, 40, 129, 39, 36,
-/* 8060 */ 129, 42, 30, 129, 46, 22, 129, 193, 129, 46,
-/* 8070 */ 22, 129, 42, 30, 129, 39, 36, 129, 37, 40,
-/* 8080 */ 129, 35, 44, 129, 34, 46, 129, 33, 48, 129,
-/* 8090 */ 32, 15, 67, 15, 129, 31, 11, 72, 11, 129,
-/* 8100 */ 31, 8, 75, 8, 129, 30, 7, 77, 7, 129,
-/* 8110 */ 30, 6, 78, 6, 129, 30, 5, 79, 5, 131,
-/* 8120 */ 31, 4, 79, 4, 129, 31, 5, 78, 5, 129,
-/* 8130 */ 32, 5, 77, 5, 129, 33, 5, 76, 5, 129,
-/* 8140 */ 35, 5, 74, 5, 129, 37, 5, 72, 5, 129,
-/* 8150 */ 1, 83, 136, 1, 3, 80, 4, 130, 193, 129,
-/* 8160 */ 30, 4, 80, 4, 130, 30, 54, 136, 30, 4,
-/* 8170 */ 68, 6, 129, 30, 4, 70, 6, 129, 71, 7,
-/* 8180 */ 129, 72, 7, 129, 73, 7, 129, 74, 7, 129,
-/* 8190 */ 74, 8, 129, 75, 8, 130, 69, 15, 129, 67,
-/* 8200 */ 17, 129, 66, 18, 129, 65, 19, 130, 65, 18,
-/* 8210 */ 130, 66, 16, 129, 67, 13, 129, 69, 8, 129,
-/* 8220 */ 193, 129, 30, 13, 64, 8, 129, 30, 13, 61,
-/* 8230 */ 14, 129, 30, 13, 59, 18, 129, 30, 13, 57,
-/* 8240 */ 22, 129, 33, 8, 56, 24, 129, 32, 7, 55,
-/* 8250 */ 26, 129, 32, 6, 54, 28, 129, 31, 6, 53,
-/* 8260 */ 16, 77, 6, 129, 31, 5, 53, 14, 79, 4,
-/* 8270 */ 129, 30, 5, 52, 14, 80, 4, 129, 30, 5,
-/* 8280 */ 52, 13, 80, 4, 129, 30, 4, 52, 13, 80,
-/* 8290 */ 4, 129, 30, 4, 52, 12, 80, 4, 129, 30,
-/* 8300 */ 4, 51, 13, 80, 4, 130, 30, 4, 50, 13,
-/* 8310 */ 79, 5, 129, 30, 4, 50, 13, 78, 5, 129,
-/* 8320 */ 30, 5, 49, 14, 77, 6, 129, 31, 4, 49,
-/* 8330 */ 13, 76, 6, 129, 31, 5, 48, 14, 75, 7,
-/* 8340 */ 129, 32, 5, 47, 14, 73, 8, 129, 32, 6,
-/* 8350 */ 45, 16, 71, 13, 129, 33, 27, 71, 13, 129,
-/* 8360 */ 34, 26, 71, 13, 129, 35, 24, 71, 13, 129,
-/* 8370 */ 37, 20, 129, 39, 16, 129, 43, 9, 129, 193,
-/* 8380 */ 129, 80, 4, 131, 41, 56, 129, 37, 60, 129,
-/* 8390 */ 35, 62, 129, 33, 64, 129, 32, 65, 129, 31,
-/* 8400 */ 66, 129, 30, 67, 130, 30, 11, 80, 4, 129,
-/* 8410 */ 30, 9, 80, 4, 129, 30, 8, 80, 4, 129,
-/* 8420 */ 31, 7, 80, 4, 129, 31, 6, 129, 32, 5,
-/* 8430 */ 129, 33, 5, 129, 35, 4, 129, 38, 3, 129,
-/* 8440 */ 193, 129, 80, 4, 130, 42, 42, 129, 38, 46,
-/* 8450 */ 129, 35, 49, 129, 33, 51, 129, 32, 52, 129,
-/* 8460 */ 31, 53, 130, 30, 54, 129, 30, 12, 129, 30,
-/* 8470 */ 9, 129, 30, 8, 129, 30, 7, 130, 31, 6,
-/* 8480 */ 130, 32, 6, 129, 33, 5, 129, 34, 5, 129,
-/* 8490 */ 35, 5, 80, 4, 129, 37, 5, 80, 4, 129,
-/* 8500 */ 30, 54, 136, 30, 4, 130, 193, 129, 80, 4,
-/* 8510 */ 130, 77, 7, 129, 74, 10, 129, 70, 14, 129,
-/* 8520 */ 66, 18, 129, 62, 22, 129, 59, 25, 129, 55,
-/* 8530 */ 29, 129, 51, 33, 129, 47, 37, 129, 44, 32,
-/* 8540 */ 80, 4, 129, 40, 32, 80, 4, 129, 36, 32,
-/* 8550 */ 129, 32, 33, 129, 30, 31, 129, 33, 24, 129,
-/* 8560 */ 36, 17, 129, 40, 12, 129, 44, 12, 129, 48,
-/* 8570 */ 12, 129, 51, 13, 129, 55, 13, 129, 59, 13,
-/* 8580 */ 80, 4, 129, 63, 13, 80, 4, 129, 67, 17,
-/* 8590 */ 129, 71, 13, 129, 74, 10, 129, 78, 6, 129,
-/* 8600 */ 80, 4, 131, 193, 129, 80, 4, 130, 77, 7,
-/* 8610 */ 129, 74, 10, 129, 70, 14, 129, 66, 18, 129,
-/* 8620 */ 62, 22, 129, 59, 25, 129, 55, 29, 129, 51,
-/* 8630 */ 33, 129, 47, 37, 129, 44, 32, 80, 4, 129,
-/* 8640 */ 40, 32, 80, 4, 129, 36, 32, 129, 32, 33,
-/* 8650 */ 129, 30, 31, 129, 33, 24, 129, 36, 17, 129,
-/* 8660 */ 40, 12, 129, 44, 12, 129, 47, 13, 129, 44,
-/* 8670 */ 20, 129, 40, 28, 129, 36, 31, 129, 32, 32,
-/* 8680 */ 129, 30, 30, 129, 33, 24, 129, 36, 17, 129,
-/* 8690 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
-/* 8700 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
-/* 8710 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
-/* 8720 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
-/* 8730 */ 193, 129, 30, 4, 80, 4, 130, 30, 4, 79,
-/* 8740 */ 5, 129, 30, 5, 77, 7, 129, 30, 6, 74,
-/* 8750 */ 10, 129, 30, 8, 72, 12, 129, 30, 11, 69,
-/* 8760 */ 15, 129, 30, 13, 67, 17, 129, 30, 4, 37,
-/* 8770 */ 8, 64, 20, 129, 30, 4, 39, 8, 62, 22,
-/* 8780 */ 129, 41, 8, 59, 25, 129, 43, 8, 57, 27,
-/* 8790 */ 129, 45, 8, 55, 22, 80, 4, 129, 47, 27,
-/* 8800 */ 80, 4, 129, 49, 23, 129, 47, 22, 129, 44,
-/* 8810 */ 23, 129, 42, 22, 129, 30, 4, 39, 27, 129,
-/* 8820 */ 30, 4, 37, 31, 129, 30, 27, 62, 8, 129,
-/* 8830 */ 30, 25, 64, 8, 129, 30, 22, 66, 8, 80,
-/* 8840 */ 4, 129, 30, 20, 68, 8, 80, 4, 129, 30,
-/* 8850 */ 17, 70, 8, 80, 4, 129, 30, 15, 73, 11,
-/* 8860 */ 129, 30, 12, 75, 9, 129, 30, 10, 77, 7,
-/* 8870 */ 129, 30, 7, 79, 5, 129, 30, 5, 80, 4,
-/* 8880 */ 129, 30, 4, 80, 4, 130, 193, 129, 4, 5,
-/* 8890 */ 80, 4, 129, 2, 9, 80, 4, 129, 1, 11,
-/* 8900 */ 77, 7, 129, 1, 12, 74, 10, 129, 1, 12,
-/* 8910 */ 70, 14, 129, 1, 12, 66, 18, 129, 1, 11,
-/* 8920 */ 62, 22, 129, 2, 9, 59, 25, 129, 4, 11,
-/* 8930 */ 55, 29, 129, 7, 12, 51, 33, 129, 10, 12,
-/* 8940 */ 47, 37, 129, 14, 12, 44, 32, 80, 4, 129,
-/* 8950 */ 17, 13, 40, 32, 80, 4, 129, 21, 13, 36,
-/* 8960 */ 32, 129, 25, 40, 129, 29, 32, 129, 33, 24,
-/* 8970 */ 129, 36, 17, 129, 40, 12, 129, 44, 12, 129,
-/* 8980 */ 48, 12, 129, 51, 13, 129, 55, 13, 129, 59,
-/* 8990 */ 13, 80, 4, 129, 63, 13, 80, 4, 129, 67,
-/* 9000 */ 17, 129, 71, 13, 129, 74, 10, 129, 78, 6,
-/* 9010 */ 129, 80, 4, 131, 193, 129, 30, 1, 71, 13,
-/* 9020 */ 129, 30, 3, 71, 13, 129, 30, 6, 71, 13,
-/* 9030 */ 129, 30, 9, 75, 9, 129, 30, 11, 77, 7,
-/* 9040 */ 129, 30, 14, 79, 5, 129, 30, 17, 79, 5,
-/* 9050 */ 129, 30, 19, 80, 4, 129, 30, 22, 80, 4,
-/* 9060 */ 129, 30, 25, 80, 4, 129, 30, 27, 80, 4,
-/* 9070 */ 129, 30, 4, 36, 24, 80, 4, 129, 30, 4,
-/* 9080 */ 38, 25, 80, 4, 129, 30, 4, 41, 24, 80,
-/* 9090 */ 4, 129, 30, 4, 44, 24, 80, 4, 129, 30,
-/* 9100 */ 4, 46, 25, 80, 4, 129, 30, 4, 49, 25,
-/* 9110 */ 80, 4, 129, 30, 4, 52, 24, 80, 4, 129,
-/* 9120 */ 30, 4, 54, 30, 129, 30, 4, 57, 27, 129,
-/* 9130 */ 30, 4, 59, 25, 129, 30, 4, 62, 22, 129,
-/* 9140 */ 30, 4, 65, 19, 129, 30, 5, 67, 17, 129,
-/* 9150 */ 30, 5, 70, 14, 129, 30, 7, 73, 11, 129,
-/* 9160 */ 30, 9, 76, 8, 129, 30, 13, 78, 6, 129,
-/* 9170 */ 30, 13, 81, 3, 129, 30, 13, 129, 193, 2,
-/* 9180 */ 9, 59, 25, 129, 4, 11, 55, 29, 129, 7,
-/* 9190 */ 12, 51, 33, 129, 10, 12, 47, 37, 129, 14,
-/* 9200 */ 12, 44, 32, 80, 4, 129, 17, 13, 40, 32,
-/* 9210 */ 80, 4, 129, 21, 13, 36, 32, 129, 25, 40,
-/* 9220 */ 129, 29, 32, 129, 33, 24, 129, 36, 17, 129,
-/* 9230 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
-/* 9240 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
-/* 9250 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
-/* 9260 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
+/* 0 */ 129, 227, 130, 34, 6, 90, 19, 129, 32, 10,
+/* 10 */ 74, 40, 129, 31, 12, 64, 53, 129, 30, 14,
+/* 20 */ 54, 65, 129, 30, 14, 53, 67, 129, 30, 14,
+/* 30 */ 54, 65, 129, 31, 12, 64, 53, 129, 32, 10,
+/* 40 */ 74, 40, 129, 34, 6, 90, 19, 129, 194, 130,
+/* 50 */ 99, 9, 129, 97, 14, 129, 96, 18, 129, 95,
+/* 60 */ 22, 129, 95, 16, 117, 2, 129, 95, 14, 129,
+/* 70 */ 96, 11, 129, 97, 9, 129, 99, 6, 129, 194,
+/* 80 */ 129, 87, 4, 101, 4, 131, 82, 28, 131, 87,
+/* 90 */ 4, 101, 4, 133, 82, 28, 131, 87, 4, 101,
+/* 100 */ 4, 131, 193, 129, 39, 1, 84, 27, 129, 38,
+/* 110 */ 3, 81, 32, 129, 37, 5, 79, 35, 129, 36,
+/* 120 */ 5, 77, 38, 129, 35, 5, 76, 40, 129, 34,
+/* 130 */ 5, 75, 21, 103, 14, 129, 33, 5, 74, 19,
+/* 140 */ 107, 11, 129, 32, 5, 73, 17, 110, 9, 129,
+/* 150 */ 32, 4, 73, 16, 112, 7, 129, 31, 4, 72,
+/* 160 */ 15, 114, 6, 129, 31, 4, 72, 14, 115, 5,
+/* 170 */ 129, 30, 4, 71, 15, 116, 5, 129, 27, 97,
+/* 180 */ 131, 30, 4, 69, 14, 117, 4, 129, 30, 4,
+/* 190 */ 68, 15, 117, 4, 132, 30, 4, 68, 14, 117,
+/* 200 */ 4, 129, 27, 97, 131, 30, 5, 65, 15, 116,
+/* 210 */ 5, 129, 31, 4, 65, 14, 116, 4, 129, 31,
+/* 220 */ 6, 64, 15, 116, 4, 129, 32, 7, 62, 16,
+/* 230 */ 115, 4, 129, 32, 9, 61, 17, 114, 5, 129,
+/* 240 */ 33, 11, 58, 19, 113, 5, 129, 34, 14, 55,
+/* 250 */ 21, 112, 5, 129, 35, 40, 111, 5, 129, 36,
+/* 260 */ 38, 110, 5, 129, 37, 35, 109, 5, 129, 38,
+/* 270 */ 32, 110, 3, 129, 40, 27, 111, 1, 129, 193,
+/* 280 */ 129, 30, 4, 103, 9, 129, 30, 7, 100, 15,
+/* 290 */ 129, 30, 10, 99, 17, 129, 33, 10, 97, 6,
+/* 300 */ 112, 6, 129, 36, 10, 96, 5, 114, 5, 129,
+/* 310 */ 39, 10, 96, 4, 115, 4, 129, 42, 10, 95,
+/* 320 */ 4, 116, 4, 129, 45, 10, 95, 3, 117, 3,
+/* 330 */ 129, 48, 10, 95, 3, 117, 3, 129, 51, 10,
+/* 340 */ 95, 4, 116, 4, 129, 54, 10, 96, 4, 115,
+/* 350 */ 4, 129, 57, 10, 96, 5, 114, 5, 129, 60,
+/* 360 */ 10, 97, 6, 112, 6, 129, 63, 10, 99, 17,
+/* 370 */ 129, 66, 10, 100, 15, 129, 69, 10, 103, 9,
+/* 380 */ 129, 39, 9, 72, 10, 129, 36, 15, 75, 10,
+/* 390 */ 129, 35, 17, 78, 10, 129, 33, 6, 48, 6,
+/* 400 */ 81, 10, 129, 32, 5, 50, 5, 84, 10, 129,
+/* 410 */ 32, 4, 51, 4, 87, 10, 129, 31, 4, 52,
+/* 420 */ 4, 90, 10, 129, 31, 3, 53, 3, 93, 10,
+/* 430 */ 129, 31, 3, 53, 3, 96, 10, 129, 31, 4,
+/* 440 */ 52, 4, 99, 10, 129, 32, 4, 51, 4, 102,
+/* 450 */ 10, 129, 32, 5, 50, 5, 105, 10, 129, 33,
+/* 460 */ 6, 48, 6, 108, 10, 129, 35, 17, 111, 10,
+/* 470 */ 129, 36, 15, 114, 7, 129, 40, 9, 118, 4,
+/* 480 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
+/* 490 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
+/* 500 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
+/* 510 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
+/* 520 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
+/* 530 */ 5, 79, 5, 129, 20, 74, 132, 30, 4, 80,
+/* 540 */ 4, 129, 31, 3, 79, 4, 129, 31, 4, 79,
+/* 550 */ 4, 129, 32, 3, 78, 4, 129, 32, 4, 76,
+/* 560 */ 6, 129, 33, 4, 74, 7, 129, 34, 4, 72,
+/* 570 */ 8, 129, 35, 5, 72, 7, 129, 37, 5, 73,
+/* 580 */ 4, 129, 39, 4, 74, 1, 129, 129, 193, 130,
+/* 590 */ 111, 6, 129, 109, 10, 129, 108, 12, 129, 107,
+/* 600 */ 14, 129, 97, 2, 105, 16, 129, 99, 22, 129,
+/* 610 */ 102, 18, 129, 105, 14, 129, 108, 9, 129, 194,
+/* 620 */ 130, 63, 25, 129, 57, 37, 129, 52, 47, 129,
+/* 630 */ 48, 55, 129, 44, 63, 129, 41, 69, 129, 38,
+/* 640 */ 75, 129, 36, 79, 129, 34, 83, 129, 33, 28,
+/* 650 */ 90, 28, 129, 32, 23, 96, 23, 129, 32, 17,
+/* 660 */ 102, 17, 129, 31, 13, 107, 13, 129, 30, 9,
+/* 670 */ 112, 9, 129, 30, 5, 116, 5, 129, 30, 1,
+/* 680 */ 120, 1, 129, 194, 130, 30, 1, 120, 1, 129,
+/* 690 */ 30, 5, 116, 5, 129, 30, 9, 112, 9, 129,
+/* 700 */ 31, 13, 107, 13, 129, 32, 17, 102, 17, 129,
+/* 710 */ 32, 23, 96, 23, 129, 33, 28, 90, 28, 129,
+/* 720 */ 34, 83, 129, 36, 79, 129, 38, 75, 129, 41,
+/* 730 */ 69, 129, 44, 63, 129, 48, 55, 129, 52, 47,
+/* 740 */ 129, 57, 37, 129, 63, 25, 129, 194, 129, 80,
+/* 750 */ 4, 130, 80, 4, 129, 68, 2, 80, 4, 94,
+/* 760 */ 2, 129, 66, 6, 80, 4, 92, 6, 129, 67,
+/* 770 */ 7, 80, 4, 90, 7, 129, 69, 7, 80, 4,
+/* 780 */ 88, 7, 129, 71, 6, 80, 4, 87, 6, 129,
+/* 790 */ 72, 20, 129, 74, 16, 129, 76, 12, 129, 62,
+/* 800 */ 40, 131, 76, 12, 129, 74, 16, 129, 72, 20,
+/* 810 */ 129, 71, 6, 80, 4, 87, 6, 129, 69, 7,
+/* 820 */ 80, 4, 88, 7, 129, 67, 7, 80, 4, 90,
+/* 830 */ 7, 129, 66, 6, 80, 4, 92, 6, 129, 68,
+/* 840 */ 2, 80, 4, 94, 2, 129, 80, 4, 130, 193,
+/* 850 */ 129, 60, 4, 139, 41, 42, 131, 60, 4, 139,
+/* 860 */ 193, 130, 34, 6, 129, 32, 10, 129, 31, 12,
+/* 870 */ 129, 30, 14, 129, 20, 2, 28, 16, 129, 22,
+/* 880 */ 22, 129, 24, 19, 129, 27, 15, 129, 31, 9,
+/* 890 */ 129, 194, 129, 60, 4, 152, 193, 130, 34, 6,
+/* 900 */ 129, 32, 10, 129, 31, 12, 129, 30, 14, 131,
+/* 910 */ 31, 12, 129, 32, 10, 129, 34, 6, 129, 194,
+/* 920 */ 129, 30, 4, 129, 30, 7, 129, 30, 10, 129,
+/* 930 */ 33, 10, 129, 36, 10, 129, 39, 10, 129, 42,
+/* 940 */ 10, 129, 45, 10, 129, 48, 10, 129, 51, 10,
+/* 950 */ 129, 54, 10, 129, 57, 10, 129, 60, 10, 129,
+/* 960 */ 63, 10, 129, 66, 10, 129, 69, 10, 129, 72,
+/* 970 */ 10, 129, 75, 10, 129, 78, 10, 129, 81, 10,
+/* 980 */ 129, 84, 10, 129, 87, 10, 129, 90, 10, 129,
+/* 990 */ 93, 10, 129, 96, 10, 129, 99, 10, 129, 102,
+/* 1000 */ 10, 129, 105, 10, 129, 108, 10, 129, 111, 10,
+/* 1010 */ 129, 114, 7, 129, 117, 4, 129, 193, 129, 60,
+/* 1020 */ 31, 129, 53, 45, 129, 49, 53, 129, 46, 59,
+/* 1030 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
+/* 1040 */ 37, 77, 129, 36, 79, 129, 35, 15, 101, 15,
+/* 1050 */ 129, 34, 11, 106, 11, 129, 33, 9, 109, 9,
+/* 1060 */ 129, 32, 7, 112, 7, 129, 31, 6, 114, 6,
+/* 1070 */ 129, 31, 5, 115, 5, 129, 30, 5, 116, 5,
+/* 1080 */ 129, 30, 4, 117, 4, 132, 30, 5, 116, 5,
+/* 1090 */ 129, 31, 5, 115, 5, 129, 31, 6, 114, 6,
+/* 1100 */ 129, 32, 7, 112, 7, 129, 33, 9, 109, 9,
+/* 1110 */ 129, 34, 11, 106, 11, 129, 35, 15, 101, 15,
+/* 1120 */ 129, 36, 79, 129, 37, 77, 129, 39, 73, 129,
+/* 1130 */ 41, 69, 129, 43, 65, 129, 46, 59, 129, 49,
+/* 1140 */ 53, 129, 53, 45, 129, 60, 31, 129, 193, 129,
+/* 1150 */ 30, 4, 129, 30, 4, 100, 1, 129, 30, 4,
+/* 1160 */ 100, 3, 129, 30, 4, 100, 5, 129, 30, 76,
+/* 1170 */ 129, 30, 78, 129, 30, 80, 129, 30, 82, 129,
+/* 1180 */ 30, 83, 129, 30, 85, 129, 30, 87, 129, 30,
+/* 1190 */ 89, 129, 30, 91, 129, 30, 4, 132, 193, 129,
+/* 1200 */ 30, 3, 129, 30, 7, 129, 30, 10, 112, 1,
+/* 1210 */ 129, 30, 13, 112, 2, 129, 30, 16, 112, 3,
+/* 1220 */ 129, 30, 18, 111, 5, 129, 30, 21, 111, 6,
+/* 1230 */ 129, 30, 23, 112, 6, 129, 30, 14, 47, 8,
+/* 1240 */ 113, 6, 129, 30, 14, 49, 8, 114, 5, 129,
+/* 1250 */ 30, 14, 51, 8, 115, 5, 129, 30, 14, 53,
+/* 1260 */ 8, 116, 4, 129, 30, 14, 55, 8, 116, 5,
+/* 1270 */ 129, 30, 14, 56, 9, 117, 4, 129, 30, 14,
+/* 1280 */ 57, 9, 117, 4, 129, 30, 14, 58, 10, 117,
+/* 1290 */ 4, 129, 30, 14, 59, 10, 117, 4, 129, 30,
+/* 1300 */ 14, 60, 11, 117, 4, 129, 30, 14, 61, 11,
+/* 1310 */ 116, 5, 129, 30, 14, 62, 11, 116, 5, 129,
+/* 1320 */ 30, 14, 63, 12, 115, 6, 129, 30, 14, 64,
+/* 1330 */ 13, 114, 7, 129, 30, 14, 65, 13, 113, 8,
+/* 1340 */ 129, 30, 14, 65, 15, 111, 9, 129, 30, 14,
+/* 1350 */ 66, 16, 109, 11, 129, 30, 14, 67, 17, 107,
+/* 1360 */ 12, 129, 30, 14, 68, 20, 103, 16, 129, 30,
+/* 1370 */ 14, 69, 49, 129, 30, 14, 70, 47, 129, 30,
+/* 1380 */ 14, 71, 45, 129, 30, 14, 73, 42, 129, 30,
+/* 1390 */ 15, 75, 38, 129, 33, 12, 77, 34, 129, 36,
+/* 1400 */ 10, 79, 30, 129, 40, 6, 82, 23, 129, 44,
+/* 1410 */ 3, 86, 15, 129, 47, 1, 129, 193, 129, 129,
+/* 1420 */ 38, 3, 129, 37, 5, 111, 1, 129, 36, 7,
+/* 1430 */ 111, 2, 129, 35, 9, 110, 5, 129, 34, 8,
+/* 1440 */ 110, 6, 129, 33, 7, 109, 8, 129, 32, 7,
+/* 1450 */ 110, 8, 129, 32, 6, 112, 7, 129, 31, 6,
+/* 1460 */ 113, 6, 129, 31, 5, 114, 6, 129, 30, 5,
+/* 1470 */ 115, 5, 129, 30, 5, 116, 4, 129, 30, 4,
+/* 1480 */ 117, 4, 131, 30, 4, 117, 4, 129, 30, 4,
+/* 1490 */ 79, 2, 117, 4, 129, 30, 5, 78, 4, 117,
+/* 1500 */ 4, 129, 30, 5, 77, 6, 116, 5, 129, 30,
+/* 1510 */ 6, 76, 8, 115, 6, 129, 30, 7, 75, 11,
+/* 1520 */ 114, 6, 129, 30, 8, 73, 15, 112, 8, 129,
+/* 1530 */ 31, 9, 71, 19, 110, 9, 129, 31, 11, 68,
+/* 1540 */ 26, 107, 12, 129, 32, 13, 65, 14, 82, 36,
+/* 1550 */ 129, 32, 16, 61, 17, 83, 34, 129, 33, 44,
+/* 1560 */ 84, 32, 129, 34, 42, 85, 30, 129, 35, 40,
+/* 1570 */ 87, 27, 129, 36, 38, 89, 23, 129, 38, 34,
+/* 1580 */ 92, 17, 129, 40, 30, 95, 11, 129, 42, 26,
+/* 1590 */ 129, 45, 20, 129, 49, 11, 129, 193, 129, 49,
+/* 1600 */ 1, 129, 49, 4, 129, 49, 6, 129, 49, 8,
+/* 1610 */ 129, 49, 10, 129, 49, 12, 129, 49, 14, 129,
+/* 1620 */ 49, 17, 129, 49, 19, 129, 49, 21, 129, 49,
+/* 1630 */ 23, 129, 49, 14, 65, 9, 129, 49, 14, 67,
+/* 1640 */ 9, 129, 49, 14, 69, 9, 129, 49, 14, 71,
+/* 1650 */ 10, 129, 49, 14, 74, 9, 129, 49, 14, 76,
+/* 1660 */ 9, 129, 49, 14, 78, 9, 129, 49, 14, 80,
+/* 1670 */ 9, 129, 49, 14, 82, 9, 129, 49, 14, 84,
+/* 1680 */ 9, 129, 30, 4, 49, 14, 86, 10, 129, 30,
+/* 1690 */ 4, 49, 14, 89, 9, 129, 30, 4, 49, 14,
+/* 1700 */ 91, 9, 129, 30, 4, 49, 14, 93, 9, 129,
+/* 1710 */ 30, 74, 129, 30, 76, 129, 30, 78, 129, 30,
+/* 1720 */ 81, 129, 30, 83, 129, 30, 85, 129, 30, 87,
+/* 1730 */ 129, 30, 89, 129, 30, 91, 129, 30, 4, 49,
+/* 1740 */ 14, 132, 193, 129, 37, 1, 129, 36, 3, 77,
+/* 1750 */ 3, 129, 35, 5, 78, 11, 129, 34, 7, 78,
+/* 1760 */ 21, 129, 33, 7, 79, 29, 129, 32, 7, 79,
+/* 1770 */ 38, 129, 32, 6, 80, 4, 92, 29, 129, 31,
+/* 1780 */ 6, 80, 5, 102, 19, 129, 31, 5, 80, 6,
+/* 1790 */ 107, 14, 129, 31, 4, 81, 5, 107, 14, 129,
+/* 1800 */ 30, 5, 81, 6, 107, 14, 129, 30, 4, 81,
+/* 1810 */ 6, 107, 14, 130, 30, 4, 81, 7, 107, 14,
+/* 1820 */ 129, 30, 4, 80, 8, 107, 14, 130, 30, 5,
+/* 1830 */ 80, 8, 107, 14, 129, 30, 5, 79, 9, 107,
+/* 1840 */ 14, 129, 31, 5, 79, 9, 107, 14, 129, 31,
+/* 1850 */ 6, 78, 10, 107, 14, 129, 32, 6, 76, 11,
+/* 1860 */ 107, 14, 129, 32, 8, 74, 13, 107, 14, 129,
+/* 1870 */ 33, 10, 71, 16, 107, 14, 129, 33, 15, 67,
+/* 1880 */ 19, 107, 14, 129, 34, 51, 107, 14, 129, 35,
+/* 1890 */ 49, 107, 14, 129, 36, 47, 107, 14, 129, 37,
+/* 1900 */ 45, 107, 14, 129, 39, 41, 107, 14, 129, 41,
+/* 1910 */ 37, 107, 14, 129, 44, 32, 107, 14, 129, 47,
+/* 1920 */ 25, 111, 10, 129, 51, 16, 115, 6, 129, 119,
+/* 1930 */ 2, 129, 193, 129, 56, 39, 129, 51, 49, 129,
+/* 1940 */ 47, 57, 129, 44, 63, 129, 42, 67, 129, 40,
+/* 1950 */ 71, 129, 38, 75, 129, 37, 77, 129, 35, 81,
+/* 1960 */ 129, 34, 16, 74, 5, 101, 16, 129, 33, 11,
+/* 1970 */ 76, 5, 107, 11, 129, 32, 9, 77, 5, 110,
+/* 1980 */ 9, 129, 32, 7, 79, 4, 112, 7, 129, 31,
+/* 1990 */ 6, 80, 4, 114, 6, 129, 31, 5, 81, 4,
+/* 2000 */ 115, 5, 129, 30, 5, 82, 4, 116, 5, 129,
+/* 2010 */ 30, 4, 82, 4, 116, 5, 129, 30, 4, 82,
+/* 2020 */ 5, 117, 4, 131, 30, 5, 82, 5, 117, 4,
+/* 2030 */ 129, 31, 5, 81, 6, 117, 4, 129, 31, 6,
+/* 2040 */ 80, 7, 117, 4, 129, 32, 7, 79, 8, 117,
+/* 2050 */ 4, 129, 32, 9, 77, 9, 116, 5, 129, 33,
+/* 2060 */ 11, 75, 11, 116, 4, 129, 34, 16, 69, 16,
+/* 2070 */ 115, 5, 129, 35, 49, 114, 5, 129, 37, 46,
+/* 2080 */ 113, 5, 129, 38, 44, 112, 6, 129, 40, 41,
+/* 2090 */ 112, 5, 129, 42, 37, 113, 3, 129, 44, 33,
+/* 2100 */ 114, 1, 129, 47, 27, 129, 51, 17, 129, 193,
+/* 2110 */ 129, 103, 2, 129, 103, 6, 129, 104, 9, 129,
+/* 2120 */ 105, 12, 129, 106, 15, 129, 107, 14, 135, 30,
+/* 2130 */ 10, 107, 14, 129, 30, 17, 107, 14, 129, 30,
+/* 2140 */ 25, 107, 14, 129, 30, 31, 107, 14, 129, 30,
+/* 2150 */ 37, 107, 14, 129, 30, 42, 107, 14, 129, 30,
+/* 2160 */ 46, 107, 14, 129, 30, 50, 107, 14, 129, 30,
+/* 2170 */ 54, 107, 14, 129, 30, 58, 107, 14, 129, 59,
+/* 2180 */ 32, 107, 14, 129, 64, 30, 107, 14, 129, 74,
+/* 2190 */ 23, 107, 14, 129, 81, 18, 107, 14, 129, 86,
+/* 2200 */ 16, 107, 14, 129, 91, 14, 107, 14, 129, 96,
+/* 2210 */ 25, 129, 100, 21, 129, 104, 17, 129, 107, 14,
+/* 2220 */ 129, 111, 10, 129, 114, 7, 129, 117, 4, 129,
+/* 2230 */ 120, 1, 129, 193, 129, 48, 13, 129, 44, 21,
+/* 2240 */ 129, 42, 26, 129, 40, 30, 92, 12, 129, 38,
+/* 2250 */ 34, 88, 20, 129, 36, 37, 86, 25, 129, 35,
+/* 2260 */ 39, 84, 29, 129, 34, 13, 63, 12, 82, 33,
+/* 2270 */ 129, 33, 11, 67, 9, 80, 36, 129, 32, 9,
+/* 2280 */ 70, 7, 79, 38, 129, 31, 8, 72, 46, 129,
+/* 2290 */ 30, 7, 74, 22, 108, 11, 129, 30, 6, 75,
+/* 2300 */ 19, 111, 9, 129, 30, 5, 75, 17, 113, 7,
+/* 2310 */ 129, 30, 5, 74, 16, 114, 6, 129, 30, 4,
+/* 2320 */ 73, 16, 115, 6, 129, 30, 4, 72, 16, 116,
+/* 2330 */ 5, 129, 30, 4, 72, 15, 117, 4, 129, 30,
+/* 2340 */ 4, 71, 16, 117, 4, 129, 30, 5, 70, 16,
+/* 2350 */ 117, 4, 129, 30, 5, 70, 15, 117, 4, 129,
+/* 2360 */ 30, 6, 69, 15, 116, 5, 129, 30, 7, 68,
+/* 2370 */ 17, 115, 5, 129, 30, 9, 67, 19, 114, 6,
+/* 2380 */ 129, 30, 10, 65, 22, 113, 6, 129, 31, 12,
+/* 2390 */ 63, 27, 110, 9, 129, 32, 14, 60, 21, 84,
+/* 2400 */ 9, 106, 12, 129, 33, 47, 85, 32, 129, 34,
+/* 2410 */ 45, 86, 30, 129, 35, 43, 88, 26, 129, 36,
+/* 2420 */ 40, 90, 22, 129, 38, 36, 93, 17, 129, 40,
+/* 2430 */ 32, 96, 10, 129, 42, 28, 129, 44, 23, 129,
+/* 2440 */ 48, 15, 129, 193, 129, 83, 17, 129, 77, 27,
+/* 2450 */ 129, 36, 1, 74, 33, 129, 35, 3, 72, 37,
+/* 2460 */ 129, 34, 5, 70, 41, 129, 33, 6, 69, 44,
+/* 2470 */ 129, 33, 5, 68, 46, 129, 32, 5, 67, 49,
+/* 2480 */ 129, 31, 5, 66, 17, 101, 16, 129, 31, 5,
+/* 2490 */ 66, 11, 108, 10, 129, 30, 4, 65, 9, 110,
+/* 2500 */ 9, 129, 30, 4, 64, 8, 112, 7, 129, 30,
+/* 2510 */ 4, 64, 7, 114, 6, 129, 30, 4, 64, 6,
+/* 2520 */ 115, 5, 129, 30, 4, 64, 5, 116, 5, 129,
+/* 2530 */ 30, 4, 64, 5, 117, 4, 131, 30, 4, 65,
+/* 2540 */ 4, 117, 4, 129, 30, 5, 65, 4, 116, 5,
+/* 2550 */ 129, 31, 5, 66, 4, 115, 5, 129, 31, 6,
+/* 2560 */ 67, 4, 114, 6, 129, 32, 7, 68, 4, 112,
+/* 2570 */ 7, 129, 32, 9, 69, 5, 110, 9, 129, 33,
+/* 2580 */ 11, 70, 5, 107, 11, 129, 34, 16, 72, 5,
+/* 2590 */ 101, 16, 129, 35, 81, 129, 37, 77, 129, 38,
+/* 2600 */ 75, 129, 40, 71, 129, 42, 67, 129, 44, 63,
+/* 2610 */ 129, 47, 57, 129, 51, 49, 129, 56, 39, 129,
+/* 2620 */ 193, 130, 34, 6, 74, 6, 129, 32, 10, 72,
+/* 2630 */ 10, 129, 31, 12, 71, 12, 129, 30, 14, 70,
+/* 2640 */ 14, 131, 31, 12, 71, 12, 129, 32, 10, 72,
+/* 2650 */ 10, 129, 34, 6, 74, 6, 129, 194, 130, 34,
+/* 2660 */ 6, 74, 6, 129, 32, 10, 72, 10, 129, 31,
+/* 2670 */ 12, 71, 12, 129, 30, 14, 70, 14, 129, 20,
+/* 2680 */ 2, 28, 16, 70, 14, 129, 22, 22, 70, 14,
+/* 2690 */ 129, 24, 19, 71, 12, 129, 27, 15, 72, 10,
+/* 2700 */ 129, 31, 9, 74, 6, 129, 194, 129, 53, 4,
+/* 2710 */ 63, 4, 152, 193, 130, 99, 7, 129, 97, 13,
+/* 2720 */ 129, 96, 16, 129, 96, 18, 129, 96, 19, 129,
+/* 2730 */ 97, 19, 129, 99, 6, 110, 7, 129, 112, 6,
+/* 2740 */ 129, 114, 5, 129, 34, 6, 57, 5, 115, 4,
+/* 2750 */ 129, 32, 10, 54, 12, 116, 4, 129, 31, 12,
+/* 2760 */ 53, 16, 117, 3, 129, 30, 14, 52, 20, 117,
+/* 2770 */ 4, 129, 30, 14, 52, 23, 117, 4, 129, 30,
+/* 2780 */ 14, 52, 25, 117, 4, 129, 31, 12, 52, 27,
+/* 2790 */ 117, 4, 129, 32, 10, 53, 10, 70, 11, 116,
+/* 2800 */ 5, 129, 34, 6, 55, 5, 73, 10, 115, 6,
+/* 2810 */ 129, 74, 11, 114, 7, 129, 75, 12, 112, 9,
+/* 2820 */ 129, 76, 13, 110, 10, 129, 77, 16, 106, 14,
+/* 2830 */ 129, 78, 41, 129, 80, 38, 129, 81, 36, 129,
+/* 2840 */ 82, 34, 129, 84, 30, 129, 86, 26, 129, 88,
+/* 2850 */ 22, 129, 92, 14, 129, 194, 129, 55, 15, 129,
+/* 2860 */ 50, 25, 129, 47, 32, 129, 45, 13, 70, 12,
+/* 2870 */ 129, 43, 9, 76, 10, 129, 42, 6, 79, 8,
+/* 2880 */ 129, 41, 5, 81, 7, 129, 40, 4, 84, 6,
+/* 2890 */ 129, 39, 4, 59, 12, 85, 6, 129, 38, 4,
+/* 2900 */ 55, 19, 87, 5, 129, 37, 4, 53, 23, 88,
+/* 2910 */ 4, 129, 36, 4, 51, 8, 71, 6, 89, 4,
+/* 2920 */ 129, 36, 4, 51, 6, 73, 4, 89, 4, 129,
+/* 2930 */ 36, 4, 50, 6, 74, 4, 90, 3, 129, 35,
+/* 2940 */ 4, 50, 5, 75, 3, 90, 4, 129, 35, 4,
+/* 2950 */ 50, 4, 75, 4, 90, 4, 131, 35, 4, 50,
+/* 2960 */ 5, 75, 4, 90, 4, 129, 36, 4, 51, 5,
+/* 2970 */ 75, 4, 90, 4, 129, 36, 4, 51, 6, 75,
+/* 2980 */ 4, 90, 4, 129, 36, 4, 53, 26, 90, 4,
+/* 2990 */ 129, 37, 4, 54, 25, 90, 4, 129, 37, 4,
+/* 3000 */ 52, 27, 90, 3, 129, 38, 4, 52, 4, 89,
+/* 3010 */ 4, 129, 39, 4, 51, 4, 88, 4, 129, 40,
+/* 3020 */ 4, 50, 4, 87, 5, 129, 41, 4, 50, 4,
+/* 3030 */ 86, 5, 129, 42, 4, 50, 4, 85, 5, 129,
+/* 3040 */ 43, 3, 50, 4, 83, 6, 129, 44, 2, 51,
+/* 3050 */ 5, 80, 7, 129, 46, 1, 52, 6, 76, 9,
+/* 3060 */ 129, 54, 28, 129, 56, 23, 129, 60, 16, 129,
+/* 3070 */ 193, 129, 30, 4, 132, 30, 5, 129, 30, 8,
+/* 3080 */ 129, 30, 12, 129, 30, 16, 129, 30, 4, 37,
+/* 3090 */ 12, 129, 30, 4, 41, 12, 129, 30, 4, 44,
+/* 3100 */ 13, 129, 30, 4, 48, 13, 129, 52, 13, 129,
+/* 3110 */ 56, 12, 129, 58, 14, 129, 58, 4, 64, 12,
+/* 3120 */ 129, 58, 4, 68, 12, 129, 58, 4, 72, 12,
+/* 3130 */ 129, 58, 4, 75, 13, 129, 58, 4, 79, 13,
+/* 3140 */ 129, 58, 4, 83, 13, 129, 58, 4, 87, 13,
+/* 3150 */ 129, 58, 4, 91, 12, 129, 58, 4, 95, 12,
+/* 3160 */ 129, 58, 4, 96, 15, 129, 58, 4, 93, 22,
+/* 3170 */ 129, 58, 4, 89, 30, 129, 58, 4, 85, 36,
+/* 3180 */ 129, 58, 4, 81, 38, 129, 58, 4, 77, 38,
+/* 3190 */ 129, 58, 4, 73, 38, 129, 58, 4, 70, 37,
+/* 3200 */ 129, 58, 4, 66, 37, 129, 58, 41, 129, 58,
+/* 3210 */ 37, 129, 54, 38, 129, 30, 4, 50, 38, 129,
+/* 3220 */ 30, 4, 46, 38, 129, 30, 4, 42, 38, 129,
+/* 3230 */ 30, 4, 38, 39, 129, 30, 43, 129, 30, 39,
+/* 3240 */ 129, 30, 35, 129, 30, 31, 129, 30, 27, 129,
+/* 3250 */ 30, 24, 129, 30, 20, 129, 30, 16, 129, 30,
+/* 3260 */ 12, 129, 30, 8, 129, 30, 5, 129, 30, 4,
+/* 3270 */ 132, 193, 129, 30, 4, 117, 4, 132, 30, 91,
+/* 3280 */ 137, 30, 4, 80, 4, 117, 4, 138, 30, 4,
+/* 3290 */ 80, 5, 116, 5, 129, 30, 5, 79, 6, 116,
+/* 3300 */ 5, 130, 30, 6, 78, 8, 115, 6, 129, 31,
+/* 3310 */ 6, 77, 9, 115, 6, 129, 31, 7, 76, 11,
+/* 3320 */ 114, 6, 129, 31, 8, 75, 14, 112, 8, 129,
+/* 3330 */ 32, 8, 74, 16, 111, 9, 129, 32, 9, 73,
+/* 3340 */ 19, 109, 10, 129, 33, 10, 71, 24, 106, 13,
+/* 3350 */ 129, 33, 13, 68, 12, 83, 35, 129, 34, 16,
+/* 3360 */ 64, 15, 84, 33, 129, 35, 43, 85, 31, 129,
+/* 3370 */ 36, 41, 86, 29, 129, 37, 39, 88, 25, 129,
+/* 3380 */ 38, 37, 90, 21, 129, 40, 33, 93, 15, 129,
+/* 3390 */ 42, 29, 96, 9, 129, 45, 24, 129, 49, 16,
+/* 3400 */ 129, 193, 129, 63, 25, 129, 57, 37, 129, 53,
+/* 3410 */ 45, 129, 50, 51, 129, 47, 57, 129, 45, 61,
+/* 3420 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
+/* 3430 */ 38, 25, 92, 21, 129, 36, 21, 97, 18, 129,
+/* 3440 */ 35, 18, 102, 14, 129, 34, 16, 106, 11, 129,
+/* 3450 */ 33, 14, 108, 10, 129, 32, 12, 111, 8, 129,
+/* 3460 */ 32, 10, 113, 6, 129, 31, 10, 114, 6, 129,
+/* 3470 */ 31, 8, 115, 5, 129, 30, 8, 116, 5, 129,
+/* 3480 */ 30, 7, 116, 5, 129, 30, 6, 117, 4, 130,
+/* 3490 */ 30, 5, 117, 4, 131, 31, 4, 116, 5, 129,
+/* 3500 */ 32, 4, 116, 4, 129, 32, 5, 115, 5, 129,
+/* 3510 */ 33, 4, 114, 5, 129, 34, 4, 112, 6, 129,
+/* 3520 */ 35, 4, 110, 7, 129, 37, 4, 107, 9, 129,
+/* 3530 */ 39, 4, 103, 12, 129, 41, 4, 103, 18, 129,
+/* 3540 */ 43, 4, 103, 18, 129, 45, 5, 103, 18, 129,
+/* 3550 */ 48, 5, 103, 18, 129, 51, 1, 129, 193, 129,
+/* 3560 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 3570 */ 117, 4, 135, 30, 5, 116, 5, 130, 30, 6,
+/* 3580 */ 115, 6, 130, 31, 6, 114, 6, 129, 31, 7,
+/* 3590 */ 113, 7, 129, 32, 7, 112, 7, 129, 32, 8,
+/* 3600 */ 111, 8, 129, 33, 9, 109, 9, 129, 33, 12,
+/* 3610 */ 106, 12, 129, 34, 13, 104, 13, 129, 35, 15,
+/* 3620 */ 101, 15, 129, 36, 19, 96, 19, 129, 37, 24,
+/* 3630 */ 90, 24, 129, 39, 73, 129, 40, 71, 129, 42,
+/* 3640 */ 67, 129, 44, 63, 129, 46, 59, 129, 49, 53,
+/* 3650 */ 129, 52, 47, 129, 56, 39, 129, 61, 29, 129,
+/* 3660 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 137,
+/* 3670 */ 30, 4, 80, 4, 117, 4, 140, 30, 4, 79,
+/* 3680 */ 6, 117, 4, 129, 30, 4, 77, 10, 117, 4,
+/* 3690 */ 129, 30, 4, 73, 18, 117, 4, 132, 30, 4,
+/* 3700 */ 117, 4, 130, 30, 5, 116, 5, 130, 30, 7,
+/* 3710 */ 114, 7, 129, 30, 8, 113, 8, 129, 30, 11,
+/* 3720 */ 110, 11, 129, 30, 18, 103, 18, 132, 193, 129,
+/* 3730 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 3740 */ 80, 4, 117, 4, 132, 80, 4, 117, 4, 136,
+/* 3750 */ 79, 6, 117, 4, 129, 77, 10, 117, 4, 129,
+/* 3760 */ 73, 18, 117, 4, 132, 117, 4, 130, 116, 5,
+/* 3770 */ 130, 114, 7, 129, 113, 8, 129, 110, 11, 129,
+/* 3780 */ 103, 18, 132, 193, 129, 63, 25, 129, 57, 37,
+/* 3790 */ 129, 53, 45, 129, 50, 51, 129, 47, 57, 129,
+/* 3800 */ 45, 61, 129, 43, 65, 129, 41, 69, 129, 39,
+/* 3810 */ 73, 129, 38, 25, 92, 21, 129, 36, 21, 97,
+/* 3820 */ 18, 129, 35, 18, 102, 14, 129, 34, 16, 106,
+/* 3830 */ 11, 129, 33, 14, 108, 10, 129, 32, 12, 111,
+/* 3840 */ 8, 129, 32, 10, 113, 6, 129, 31, 10, 114,
+/* 3850 */ 6, 129, 31, 8, 115, 5, 129, 30, 8, 116,
+/* 3860 */ 5, 129, 30, 7, 116, 5, 129, 30, 6, 117,
+/* 3870 */ 4, 130, 30, 5, 117, 4, 131, 30, 5, 75,
+/* 3880 */ 4, 116, 5, 129, 31, 5, 75, 4, 116, 4,
+/* 3890 */ 129, 31, 6, 75, 4, 115, 5, 129, 32, 7,
+/* 3900 */ 75, 4, 114, 5, 129, 32, 9, 75, 4, 112,
+/* 3910 */ 6, 129, 33, 11, 75, 4, 110, 7, 129, 34,
+/* 3920 */ 15, 75, 4, 107, 9, 129, 35, 44, 103, 12,
+/* 3930 */ 129, 36, 43, 103, 18, 129, 38, 41, 103, 18,
+/* 3940 */ 129, 39, 40, 103, 18, 129, 41, 38, 103, 18,
+/* 3950 */ 129, 44, 35, 129, 48, 31, 129, 52, 27, 129,
+/* 3960 */ 61, 18, 129, 193, 129, 30, 4, 117, 4, 132,
+/* 3970 */ 30, 91, 137, 30, 4, 80, 4, 117, 4, 132,
+/* 3980 */ 80, 4, 140, 30, 4, 80, 4, 117, 4, 132,
+/* 3990 */ 30, 91, 137, 30, 4, 117, 4, 132, 193, 129,
+/* 4000 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 4010 */ 117, 4, 132, 193, 129, 44, 7, 129, 40, 13,
+/* 4020 */ 129, 37, 17, 129, 35, 20, 129, 34, 22, 129,
+/* 4030 */ 33, 23, 129, 32, 24, 129, 32, 23, 129, 31,
+/* 4040 */ 6, 41, 13, 129, 31, 5, 42, 11, 129, 30,
+/* 4050 */ 5, 44, 7, 129, 30, 4, 132, 30, 5, 130,
+/* 4060 */ 31, 5, 129, 31, 6, 117, 4, 129, 31, 8,
+/* 4070 */ 117, 4, 129, 32, 9, 117, 4, 129, 33, 11,
+/* 4080 */ 117, 4, 129, 34, 87, 129, 35, 86, 129, 36,
+/* 4090 */ 85, 129, 37, 84, 129, 38, 83, 129, 40, 81,
+/* 4100 */ 129, 42, 79, 129, 45, 76, 129, 50, 71, 129,
+/* 4110 */ 117, 4, 132, 193, 129, 30, 4, 117, 4, 132,
+/* 4120 */ 30, 91, 137, 30, 4, 76, 8, 117, 4, 129,
+/* 4130 */ 30, 4, 73, 13, 117, 4, 129, 30, 4, 70,
+/* 4140 */ 18, 117, 4, 129, 30, 4, 67, 23, 117, 4,
+/* 4150 */ 129, 65, 26, 129, 62, 31, 129, 59, 35, 129,
+/* 4160 */ 56, 29, 89, 7, 129, 53, 29, 91, 7, 129,
+/* 4170 */ 50, 29, 93, 7, 129, 47, 29, 95, 6, 129,
+/* 4180 */ 30, 4, 45, 29, 96, 7, 129, 30, 4, 42,
+/* 4190 */ 29, 98, 7, 129, 30, 4, 39, 30, 100, 6,
+/* 4200 */ 129, 30, 4, 36, 30, 101, 7, 129, 30, 33,
+/* 4210 */ 103, 7, 117, 4, 129, 30, 30, 105, 6, 117,
+/* 4220 */ 4, 129, 30, 27, 106, 7, 117, 4, 129, 30,
+/* 4230 */ 25, 108, 7, 117, 4, 129, 30, 22, 110, 11,
+/* 4240 */ 129, 30, 19, 111, 10, 129, 30, 16, 113, 8,
+/* 4250 */ 129, 30, 13, 115, 6, 129, 30, 11, 116, 5,
+/* 4260 */ 129, 30, 8, 117, 4, 129, 30, 5, 117, 4,
+/* 4270 */ 129, 30, 4, 117, 4, 130, 30, 4, 130, 193,
+/* 4280 */ 129, 30, 4, 117, 4, 132, 30, 91, 137, 30,
+/* 4290 */ 4, 117, 4, 132, 30, 4, 144, 30, 5, 130,
+/* 4300 */ 30, 7, 129, 30, 8, 129, 30, 11, 129, 30,
+/* 4310 */ 18, 132, 193, 129, 30, 4, 117, 4, 132, 30,
+/* 4320 */ 91, 132, 30, 4, 103, 18, 129, 30, 4, 97,
+/* 4330 */ 24, 129, 30, 4, 92, 29, 129, 30, 4, 87,
+/* 4340 */ 34, 129, 81, 40, 129, 76, 45, 129, 70, 49,
+/* 4350 */ 129, 65, 49, 129, 60, 49, 129, 55, 49, 129,
+/* 4360 */ 50, 48, 129, 44, 49, 129, 39, 48, 129, 33,
+/* 4370 */ 49, 129, 30, 47, 129, 34, 37, 129, 40, 26,
+/* 4380 */ 129, 46, 19, 129, 52, 19, 129, 58, 19, 129,
+/* 4390 */ 64, 19, 129, 70, 19, 129, 76, 19, 129, 82,
+/* 4400 */ 19, 129, 30, 4, 88, 18, 129, 30, 4, 94,
+/* 4410 */ 18, 129, 30, 4, 100, 18, 129, 30, 4, 106,
+/* 4420 */ 15, 129, 30, 91, 137, 30, 4, 117, 4, 132,
+/* 4430 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 132,
+/* 4440 */ 30, 4, 107, 14, 129, 30, 4, 104, 17, 129,
+/* 4450 */ 30, 4, 101, 20, 129, 30, 4, 99, 22, 129,
+/* 4460 */ 96, 25, 129, 93, 28, 129, 91, 28, 129, 88,
+/* 4470 */ 29, 129, 85, 29, 129, 82, 29, 129, 79, 29,
+/* 4480 */ 129, 76, 29, 129, 74, 29, 129, 71, 29, 129,
+/* 4490 */ 68, 29, 129, 65, 29, 129, 62, 29, 129, 60,
+/* 4500 */ 29, 129, 57, 29, 129, 54, 29, 129, 51, 29,
+/* 4510 */ 129, 49, 28, 129, 46, 29, 129, 43, 29, 129,
+/* 4520 */ 40, 29, 117, 4, 129, 37, 29, 117, 4, 129,
+/* 4530 */ 35, 29, 117, 4, 129, 32, 29, 117, 4, 129,
+/* 4540 */ 30, 91, 132, 117, 4, 132, 193, 129, 63, 25,
+/* 4550 */ 129, 57, 37, 129, 53, 45, 129, 50, 51, 129,
+/* 4560 */ 47, 57, 129, 45, 61, 129, 43, 65, 129, 41,
+/* 4570 */ 69, 129, 39, 73, 129, 38, 21, 92, 21, 129,
+/* 4580 */ 36, 18, 97, 18, 129, 35, 14, 102, 14, 129,
+/* 4590 */ 34, 11, 106, 11, 129, 33, 10, 108, 10, 129,
+/* 4600 */ 32, 8, 111, 8, 129, 32, 6, 113, 6, 129,
+/* 4610 */ 31, 6, 114, 6, 129, 31, 5, 115, 5, 129,
+/* 4620 */ 30, 5, 116, 5, 130, 30, 4, 117, 4, 132,
+/* 4630 */ 30, 5, 116, 5, 130, 31, 5, 115, 5, 129,
+/* 4640 */ 31, 6, 114, 6, 129, 32, 6, 113, 6, 129,
+/* 4650 */ 32, 8, 111, 8, 129, 33, 10, 108, 10, 129,
+/* 4660 */ 34, 11, 106, 11, 129, 35, 14, 102, 14, 129,
+/* 4670 */ 36, 18, 97, 18, 129, 38, 21, 92, 21, 129,
+/* 4680 */ 39, 73, 129, 41, 69, 129, 43, 65, 129, 45,
+/* 4690 */ 61, 129, 47, 57, 129, 50, 51, 129, 53, 45,
+/* 4700 */ 129, 57, 37, 129, 63, 25, 129, 193, 129, 30,
+/* 4710 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 80,
+/* 4720 */ 4, 117, 4, 132, 80, 4, 117, 4, 134, 80,
+/* 4730 */ 5, 116, 5, 131, 80, 6, 115, 6, 130, 81,
+/* 4740 */ 6, 114, 6, 129, 81, 8, 112, 8, 129, 81,
+/* 4750 */ 9, 111, 9, 129, 82, 10, 109, 10, 129, 82,
+/* 4760 */ 13, 106, 13, 129, 83, 35, 129, 84, 33, 129,
+/* 4770 */ 85, 31, 129, 86, 29, 129, 88, 25, 129, 90,
+/* 4780 */ 21, 129, 93, 15, 129, 96, 9, 129, 193, 129,
+/* 4790 */ 63, 25, 129, 57, 37, 129, 53, 45, 129, 50,
+/* 4800 */ 51, 129, 47, 57, 129, 45, 61, 129, 43, 65,
+/* 4810 */ 129, 41, 69, 129, 39, 73, 129, 38, 21, 92,
+/* 4820 */ 21, 129, 36, 18, 97, 18, 129, 35, 14, 102,
+/* 4830 */ 14, 129, 34, 11, 106, 11, 129, 33, 10, 108,
+/* 4840 */ 10, 129, 32, 8, 111, 8, 129, 32, 6, 113,
+/* 4850 */ 6, 129, 31, 6, 114, 6, 129, 31, 5, 115,
+/* 4860 */ 5, 129, 30, 5, 116, 5, 130, 30, 4, 39,
+/* 4870 */ 2, 117, 4, 129, 30, 4, 40, 4, 117, 4,
+/* 4880 */ 129, 30, 4, 41, 5, 117, 4, 129, 30, 4,
+/* 4890 */ 41, 6, 117, 4, 129, 30, 5, 40, 8, 116,
+/* 4900 */ 5, 129, 30, 5, 39, 10, 116, 5, 129, 31,
+/* 4910 */ 5, 38, 11, 115, 5, 129, 31, 18, 114, 6,
+/* 4920 */ 129, 32, 17, 113, 6, 129, 32, 16, 111, 8,
+/* 4930 */ 129, 33, 15, 108, 10, 129, 33, 14, 106, 11,
+/* 4940 */ 129, 32, 17, 102, 14, 129, 31, 23, 97, 18,
+/* 4950 */ 129, 31, 28, 92, 21, 129, 30, 82, 129, 30,
+/* 4960 */ 80, 129, 30, 11, 43, 65, 129, 30, 10, 45,
+/* 4970 */ 61, 129, 31, 8, 47, 57, 129, 32, 6, 50,
+/* 4980 */ 51, 129, 33, 5, 53, 45, 129, 35, 4, 57,
+/* 4990 */ 37, 129, 38, 2, 63, 25, 129, 193, 129, 30,
+/* 5000 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 76,
+/* 5010 */ 8, 117, 4, 129, 30, 4, 73, 11, 117, 4,
+/* 5020 */ 129, 30, 4, 70, 14, 117, 4, 129, 30, 4,
+/* 5030 */ 67, 17, 117, 4, 129, 65, 19, 117, 4, 129,
+/* 5040 */ 62, 22, 117, 4, 129, 59, 25, 117, 4, 129,
+/* 5050 */ 56, 28, 117, 4, 129, 53, 31, 117, 4, 129,
+/* 5060 */ 50, 34, 117, 4, 129, 47, 29, 80, 5, 116,
+/* 5070 */ 5, 129, 30, 4, 45, 29, 80, 5, 116, 5,
+/* 5080 */ 129, 30, 4, 42, 29, 80, 5, 116, 5, 129,
+/* 5090 */ 30, 4, 39, 30, 80, 6, 115, 6, 129, 30,
+/* 5100 */ 4, 36, 30, 80, 6, 115, 6, 129, 30, 33,
+/* 5110 */ 81, 6, 114, 6, 129, 30, 30, 81, 8, 112,
+/* 5120 */ 8, 129, 30, 27, 81, 9, 111, 9, 129, 30,
+/* 5130 */ 25, 82, 10, 109, 10, 129, 30, 22, 82, 13,
+/* 5140 */ 106, 13, 129, 30, 19, 83, 35, 129, 30, 16,
+/* 5150 */ 84, 33, 129, 30, 13, 85, 31, 129, 30, 11,
+/* 5160 */ 86, 29, 129, 30, 8, 88, 25, 129, 30, 5,
+/* 5170 */ 90, 21, 129, 30, 4, 93, 15, 129, 30, 4,
+/* 5180 */ 96, 9, 129, 30, 4, 130, 193, 129, 30, 18,
+/* 5190 */ 130, 30, 18, 89, 15, 129, 30, 18, 85, 23,
+/* 5200 */ 129, 34, 11, 83, 27, 129, 34, 9, 81, 31,
+/* 5210 */ 129, 33, 8, 79, 35, 129, 33, 6, 78, 16,
+/* 5220 */ 106, 9, 129, 32, 6, 77, 15, 109, 7, 129,
+/* 5230 */ 32, 5, 76, 14, 111, 6, 129, 31, 5, 75,
+/* 5240 */ 14, 113, 5, 129, 31, 4, 74, 15, 114, 5,
+/* 5250 */ 129, 31, 4, 74, 14, 115, 4, 129, 30, 4,
+/* 5260 */ 73, 15, 116, 4, 129, 30, 4, 73, 14, 116,
+/* 5270 */ 4, 129, 30, 4, 73, 14, 117, 4, 129, 30,
+/* 5280 */ 4, 72, 15, 117, 4, 130, 30, 4, 71, 15,
+/* 5290 */ 117, 4, 130, 30, 4, 70, 15, 117, 4, 129,
+/* 5300 */ 30, 5, 70, 15, 117, 4, 129, 30, 5, 69,
+/* 5310 */ 15, 116, 5, 129, 30, 6, 68, 16, 115, 5,
+/* 5320 */ 129, 31, 6, 67, 16, 114, 6, 129, 31, 7,
+/* 5330 */ 66, 17, 113, 6, 129, 32, 7, 64, 18, 111,
+/* 5340 */ 8, 129, 32, 8, 62, 19, 109, 9, 129, 33,
+/* 5350 */ 9, 60, 20, 107, 10, 129, 34, 11, 57, 22,
+/* 5360 */ 103, 13, 129, 35, 43, 103, 18, 129, 36, 41,
+/* 5370 */ 103, 18, 129, 38, 38, 103, 18, 129, 39, 35,
+/* 5380 */ 103, 18, 129, 41, 31, 129, 43, 27, 129, 46,
+/* 5390 */ 22, 129, 49, 14, 129, 193, 129, 103, 18, 132,
+/* 5400 */ 110, 11, 129, 113, 8, 129, 114, 7, 129, 116,
+/* 5410 */ 5, 130, 117, 4, 132, 30, 4, 117, 4, 132,
+/* 5420 */ 30, 91, 137, 30, 4, 117, 4, 132, 117, 4,
+/* 5430 */ 132, 116, 5, 130, 114, 7, 129, 113, 8, 129,
+/* 5440 */ 110, 11, 129, 103, 18, 132, 193, 129, 117, 4,
+/* 5450 */ 132, 56, 65, 129, 50, 71, 129, 46, 75, 129,
+/* 5460 */ 44, 77, 129, 42, 79, 129, 40, 81, 129, 38,
+/* 5470 */ 83, 129, 36, 85, 129, 35, 86, 129, 34, 20,
+/* 5480 */ 117, 4, 129, 33, 17, 117, 4, 129, 32, 15,
+/* 5490 */ 117, 4, 129, 32, 13, 117, 4, 129, 31, 12,
+/* 5500 */ 129, 31, 10, 129, 31, 9, 129, 30, 9, 129,
+/* 5510 */ 30, 8, 130, 30, 7, 132, 31, 6, 130, 31,
+/* 5520 */ 7, 129, 32, 6, 129, 32, 7, 129, 33, 7,
+/* 5530 */ 129, 34, 7, 129, 35, 8, 129, 36, 9, 117,
+/* 5540 */ 4, 129, 38, 9, 117, 4, 129, 40, 10, 117,
+/* 5550 */ 4, 129, 42, 12, 117, 4, 129, 44, 77, 129,
+/* 5560 */ 46, 75, 129, 50, 71, 129, 56, 43, 100, 21,
+/* 5570 */ 129, 117, 4, 132, 193, 129, 117, 4, 132, 115,
+/* 5580 */ 6, 129, 110, 11, 129, 105, 16, 129, 101, 20,
+/* 5590 */ 129, 96, 25, 129, 92, 29, 129, 87, 34, 129,
+/* 5600 */ 83, 38, 129, 78, 43, 129, 74, 47, 129, 70,
+/* 5610 */ 42, 117, 4, 129, 65, 42, 117, 4, 129, 60,
+/* 5620 */ 43, 117, 4, 129, 56, 42, 129, 51, 42, 129,
+/* 5630 */ 46, 43, 129, 42, 43, 129, 37, 44, 129, 33,
+/* 5640 */ 43, 129, 30, 42, 129, 33, 34, 129, 38, 25,
+/* 5650 */ 129, 42, 16, 129, 47, 15, 129, 52, 15, 129,
+/* 5660 */ 57, 15, 129, 61, 16, 129, 66, 16, 129, 71,
+/* 5670 */ 16, 129, 76, 16, 129, 80, 16, 129, 85, 16,
+/* 5680 */ 117, 4, 129, 90, 16, 117, 4, 129, 95, 16,
+/* 5690 */ 117, 4, 129, 100, 21, 129, 105, 16, 129, 110,
+/* 5700 */ 11, 129, 114, 7, 129, 117, 4, 132, 193, 129,
+/* 5710 */ 117, 4, 132, 115, 6, 129, 110, 11, 129, 105,
+/* 5720 */ 16, 129, 101, 20, 129, 96, 25, 129, 92, 29,
+/* 5730 */ 129, 87, 34, 129, 83, 38, 129, 78, 43, 129,
+/* 5740 */ 74, 47, 129, 70, 42, 117, 4, 129, 65, 42,
+/* 5750 */ 117, 4, 129, 60, 43, 117, 4, 129, 56, 42,
+/* 5760 */ 129, 51, 42, 129, 46, 43, 129, 42, 43, 129,
+/* 5770 */ 37, 44, 129, 33, 43, 129, 30, 42, 129, 33,
+/* 5780 */ 34, 129, 38, 25, 129, 42, 16, 129, 47, 15,
+/* 5790 */ 129, 52, 15, 129, 57, 15, 129, 61, 16, 129,
+/* 5800 */ 65, 17, 129, 60, 27, 129, 56, 36, 129, 51,
+/* 5810 */ 42, 129, 46, 43, 129, 42, 43, 129, 37, 44,
+/* 5820 */ 129, 33, 43, 129, 30, 42, 129, 33, 34, 129,
+/* 5830 */ 38, 25, 129, 42, 16, 129, 47, 15, 129, 52,
+/* 5840 */ 15, 129, 57, 15, 129, 61, 16, 129, 66, 16,
+/* 5850 */ 129, 71, 16, 129, 76, 16, 129, 80, 16, 129,
+/* 5860 */ 85, 16, 117, 4, 129, 90, 16, 117, 4, 129,
+/* 5870 */ 95, 16, 117, 4, 129, 100, 21, 129, 105, 16,
+/* 5880 */ 129, 110, 11, 129, 114, 7, 129, 117, 4, 132,
+/* 5890 */ 193, 129, 30, 4, 117, 4, 132, 30, 4, 115,
+/* 5900 */ 6, 129, 30, 4, 112, 9, 129, 30, 6, 109,
+/* 5910 */ 12, 129, 30, 9, 106, 15, 129, 30, 11, 103,
+/* 5920 */ 18, 129, 30, 14, 100, 21, 129, 30, 4, 38,
+/* 5930 */ 9, 98, 23, 129, 30, 4, 40, 10, 95, 26,
+/* 5940 */ 129, 30, 4, 43, 9, 92, 29, 129, 46, 9,
+/* 5950 */ 89, 32, 129, 49, 8, 86, 28, 117, 4, 129,
+/* 5960 */ 51, 9, 83, 28, 117, 4, 129, 54, 9, 80,
+/* 5970 */ 28, 117, 4, 129, 57, 8, 77, 28, 117, 4,
+/* 5980 */ 129, 59, 9, 74, 28, 129, 62, 37, 129, 64,
+/* 5990 */ 33, 129, 66, 28, 129, 63, 28, 129, 60, 28,
+/* 6000 */ 129, 57, 28, 129, 54, 33, 129, 51, 39, 129,
+/* 6010 */ 48, 29, 83, 9, 129, 30, 4, 45, 29, 86,
+/* 6020 */ 9, 129, 30, 4, 42, 29, 89, 9, 129, 30,
+/* 6030 */ 4, 39, 29, 92, 8, 129, 30, 4, 36, 29,
+/* 6040 */ 94, 9, 129, 30, 32, 97, 9, 129, 30, 29,
+/* 6050 */ 100, 8, 117, 4, 129, 30, 26, 103, 8, 117,
+/* 6060 */ 4, 129, 30, 23, 105, 9, 117, 4, 129, 30,
+/* 6070 */ 20, 108, 13, 129, 30, 18, 111, 10, 129, 30,
+/* 6080 */ 15, 113, 8, 129, 30, 12, 116, 5, 129, 30,
+/* 6090 */ 9, 117, 4, 129, 30, 6, 117, 4, 129, 30,
+/* 6100 */ 4, 117, 4, 132, 193, 129, 117, 4, 132, 114,
+/* 6110 */ 7, 129, 111, 10, 129, 108, 13, 129, 105, 16,
+/* 6120 */ 129, 102, 19, 129, 100, 21, 129, 96, 25, 129,
+/* 6130 */ 93, 28, 129, 90, 31, 129, 87, 34, 129, 84,
+/* 6140 */ 30, 117, 4, 129, 30, 4, 81, 30, 117, 4,
+/* 6150 */ 129, 30, 4, 78, 30, 117, 4, 129, 30, 4,
+/* 6160 */ 75, 30, 117, 4, 129, 30, 4, 72, 30, 129,
+/* 6170 */ 30, 69, 129, 30, 66, 129, 30, 63, 129, 30,
+/* 6180 */ 60, 129, 30, 57, 129, 30, 54, 129, 30, 51,
+/* 6190 */ 129, 30, 48, 129, 30, 51, 129, 30, 4, 73,
+/* 6200 */ 12, 129, 30, 4, 76, 12, 129, 30, 4, 80,
+/* 6210 */ 12, 129, 30, 4, 83, 12, 129, 87, 12, 129,
+/* 6220 */ 90, 12, 117, 4, 129, 94, 11, 117, 4, 129,
+/* 6230 */ 97, 12, 117, 4, 129, 101, 12, 117, 4, 129,
+/* 6240 */ 104, 17, 129, 108, 13, 129, 111, 10, 129, 115,
+/* 6250 */ 6, 129, 117, 4, 134, 193, 129, 30, 1, 103,
+/* 6260 */ 18, 129, 30, 4, 103, 18, 129, 30, 7, 103,
+/* 6270 */ 18, 129, 30, 9, 103, 18, 129, 30, 12, 110,
+/* 6280 */ 11, 129, 30, 15, 113, 8, 129, 30, 18, 114,
+/* 6290 */ 7, 129, 30, 21, 116, 5, 129, 30, 24, 116,
+/* 6300 */ 5, 129, 30, 27, 117, 4, 129, 30, 30, 117,
+/* 6310 */ 4, 129, 30, 33, 117, 4, 129, 30, 4, 37,
+/* 6320 */ 28, 117, 4, 129, 30, 4, 40, 28, 117, 4,
+/* 6330 */ 129, 30, 4, 42, 29, 117, 4, 129, 30, 4,
+/* 6340 */ 45, 29, 117, 4, 129, 30, 4, 48, 29, 117,
+/* 6350 */ 4, 129, 30, 4, 51, 29, 117, 4, 129, 30,
+/* 6360 */ 4, 54, 29, 117, 4, 129, 30, 4, 57, 29,
+/* 6370 */ 117, 4, 129, 30, 4, 59, 30, 117, 4, 129,
+/* 6380 */ 30, 4, 62, 30, 117, 4, 129, 30, 4, 65,
+/* 6390 */ 30, 117, 4, 129, 30, 4, 68, 30, 117, 4,
+/* 6400 */ 129, 30, 4, 71, 30, 117, 4, 129, 30, 4,
+/* 6410 */ 74, 30, 117, 4, 129, 30, 4, 77, 30, 117,
+/* 6420 */ 4, 129, 30, 4, 80, 30, 117, 4, 129, 30,
+/* 6430 */ 4, 83, 30, 117, 4, 129, 30, 4, 86, 35,
+/* 6440 */ 129, 30, 4, 89, 32, 129, 30, 4, 91, 30,
+/* 6450 */ 129, 30, 4, 94, 27, 129, 30, 5, 97, 24,
+/* 6460 */ 129, 30, 5, 100, 21, 129, 30, 7, 103, 18,
+/* 6470 */ 129, 30, 8, 106, 15, 129, 30, 11, 109, 12,
+/* 6480 */ 129, 30, 18, 112, 9, 129, 30, 18, 115, 6,
+/* 6490 */ 129, 30, 18, 117, 4, 129, 30, 18, 120, 1,
+/* 6500 */ 129, 193, 129, 42, 8, 129, 38, 16, 129, 36,
+/* 6510 */ 20, 129, 34, 24, 71, 5, 129, 33, 26, 69,
+/* 6520 */ 10, 129, 32, 28, 68, 13, 129, 31, 30, 68,
+/* 6530 */ 14, 129, 31, 9, 52, 9, 68, 15, 129, 30,
+/* 6540 */ 8, 54, 8, 69, 14, 129, 30, 7, 55, 7,
+/* 6550 */ 71, 4, 78, 6, 129, 30, 6, 56, 6, 79,
+/* 6560 */ 5, 129, 30, 6, 56, 6, 80, 4, 130, 31,
+/* 6570 */ 5, 56, 5, 80, 4, 129, 31, 5, 56, 5,
+/* 6580 */ 79, 5, 129, 32, 5, 55, 5, 78, 6, 129,
+/* 6590 */ 33, 5, 54, 5, 77, 7, 129, 34, 6, 52,
+/* 6600 */ 6, 74, 9, 129, 35, 48, 129, 33, 49, 129,
+/* 6610 */ 32, 49, 129, 31, 49, 129, 30, 49, 129, 30,
+/* 6620 */ 47, 129, 30, 45, 129, 30, 41, 129, 30, 6,
+/* 6630 */ 129, 30, 4, 129, 30, 3, 129, 30, 2, 129,
+/* 6640 */ 193, 129, 30, 4, 117, 4, 130, 31, 90, 136,
+/* 6650 */ 37, 5, 72, 5, 129, 35, 5, 74, 5, 129,
+/* 6660 */ 33, 5, 76, 5, 129, 32, 5, 77, 5, 129,
+/* 6670 */ 31, 5, 78, 5, 129, 31, 4, 79, 4, 129,
+/* 6680 */ 30, 5, 79, 5, 131, 30, 6, 78, 6, 129,
+/* 6690 */ 30, 7, 77, 7, 129, 31, 8, 75, 8, 129,
+/* 6700 */ 31, 11, 72, 11, 129, 32, 15, 67, 15, 129,
+/* 6710 */ 33, 48, 129, 34, 46, 129, 35, 44, 129, 37,
+/* 6720 */ 40, 129, 39, 36, 129, 42, 30, 129, 46, 22,
+/* 6730 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
+/* 6740 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
+/* 6750 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
+/* 6760 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
+/* 6770 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
+/* 6780 */ 5, 79, 5, 129, 30, 4, 80, 4, 133, 31,
+/* 6790 */ 3, 79, 4, 129, 31, 4, 79, 4, 129, 32,
+/* 6800 */ 3, 78, 4, 129, 32, 4, 76, 6, 129, 33,
+/* 6810 */ 4, 74, 7, 129, 34, 4, 72, 8, 129, 35,
+/* 6820 */ 5, 72, 7, 129, 37, 5, 73, 4, 129, 39,
+/* 6830 */ 4, 74, 1, 129, 129, 193, 129, 46, 22, 129,
+/* 6840 */ 42, 30, 129, 39, 36, 129, 37, 40, 129, 35,
+/* 6850 */ 44, 129, 34, 46, 129, 33, 48, 129, 32, 15,
+/* 6860 */ 67, 15, 129, 31, 11, 72, 11, 129, 31, 8,
+/* 6870 */ 75, 8, 129, 30, 7, 77, 7, 129, 30, 6,
+/* 6880 */ 78, 6, 129, 30, 5, 79, 5, 131, 31, 4,
+/* 6890 */ 79, 4, 129, 31, 5, 78, 5, 129, 32, 5,
+/* 6900 */ 77, 5, 129, 33, 5, 76, 5, 129, 35, 5,
+/* 6910 */ 74, 5, 117, 4, 129, 37, 5, 72, 5, 117,
+/* 6920 */ 4, 129, 30, 91, 136, 30, 4, 130, 193, 129,
+/* 6930 */ 48, 18, 129, 43, 28, 129, 41, 32, 129, 39,
+/* 6940 */ 36, 129, 37, 40, 129, 35, 44, 129, 34, 46,
+/* 6950 */ 129, 33, 13, 55, 4, 68, 13, 129, 32, 9,
+/* 6960 */ 55, 4, 73, 9, 129, 32, 7, 55, 4, 75,
+/* 6970 */ 7, 129, 31, 6, 55, 4, 77, 6, 129, 31,
+/* 6980 */ 5, 55, 4, 78, 5, 129, 30, 5, 55, 4,
+/* 6990 */ 79, 5, 129, 30, 4, 55, 4, 80, 4, 132,
+/* 7000 */ 30, 4, 55, 4, 79, 5, 129, 31, 3, 55,
+/* 7010 */ 4, 78, 5, 129, 31, 4, 55, 4, 77, 6,
+/* 7020 */ 129, 32, 3, 55, 4, 75, 7, 129, 32, 4,
+/* 7030 */ 55, 4, 73, 9, 129, 33, 4, 55, 4, 68,
+/* 7040 */ 13, 129, 34, 4, 55, 25, 129, 35, 5, 55,
+/* 7050 */ 24, 129, 37, 5, 55, 22, 129, 39, 4, 55,
+/* 7060 */ 20, 129, 55, 18, 129, 55, 16, 129, 55, 11,
+/* 7070 */ 129, 193, 129, 80, 4, 129, 30, 4, 80, 4,
+/* 7080 */ 130, 30, 78, 129, 30, 82, 129, 30, 85, 129,
+/* 7090 */ 30, 87, 129, 30, 88, 129, 30, 89, 129, 30,
+/* 7100 */ 90, 130, 30, 4, 80, 4, 115, 6, 129, 30,
+/* 7110 */ 4, 80, 4, 117, 4, 129, 80, 4, 105, 6,
+/* 7120 */ 117, 4, 129, 80, 4, 103, 10, 116, 5, 129,
+/* 7130 */ 80, 4, 102, 19, 129, 80, 4, 101, 19, 129,
+/* 7140 */ 101, 19, 129, 101, 18, 129, 102, 16, 129, 103,
+/* 7150 */ 12, 129, 105, 6, 129, 193, 129, 12, 10, 59,
+/* 7160 */ 11, 129, 9, 16, 55, 19, 129, 7, 20, 53,
+/* 7170 */ 23, 129, 6, 7, 23, 5, 32, 6, 51, 27,
+/* 7180 */ 129, 4, 7, 25, 16, 50, 29, 129, 3, 6,
+/* 7190 */ 27, 16, 49, 31, 129, 2, 6, 28, 16, 48,
+/* 7200 */ 33, 129, 1, 6, 27, 18, 47, 35, 129, 1,
+/* 7210 */ 6, 27, 31, 71, 12, 129, 1, 5, 26, 15,
+/* 7220 */ 44, 10, 75, 8, 129, 1, 5, 25, 14, 45,
+/* 7230 */ 7, 77, 7, 129, 1, 5, 25, 13, 45, 5,
+/* 7240 */ 79, 5, 129, 1, 5, 24, 14, 45, 4, 80,
+/* 7250 */ 4, 129, 1, 5, 24, 13, 45, 4, 80, 4,
+/* 7260 */ 129, 1, 5, 23, 14, 45, 4, 80, 4, 129,
+/* 7270 */ 1, 5, 23, 13, 45, 4, 80, 4, 129, 1,
+/* 7280 */ 6, 22, 13, 45, 5, 79, 5, 129, 1, 6,
+/* 7290 */ 21, 14, 45, 7, 77, 7, 129, 1, 7, 21,
+/* 7300 */ 13, 46, 8, 75, 8, 129, 1, 8, 20, 13,
+/* 7310 */ 46, 12, 71, 12, 129, 1, 10, 18, 15, 47,
+/* 7320 */ 35, 129, 2, 30, 48, 33, 129, 3, 29, 49,
+/* 7330 */ 32, 129, 4, 27, 50, 31, 129, 5, 25, 51,
+/* 7340 */ 27, 80, 2, 86, 4, 129, 7, 21, 53, 23,
+/* 7350 */ 80, 3, 85, 6, 129, 9, 17, 55, 19, 80,
+/* 7360 */ 12, 129, 12, 12, 59, 11, 81, 11, 129, 82,
+/* 7370 */ 10, 129, 84, 7, 129, 86, 4, 129, 193, 129,
+/* 7380 */ 30, 4, 117, 4, 130, 30, 91, 136, 30, 4,
+/* 7390 */ 72, 5, 129, 30, 4, 74, 5, 129, 75, 5,
+/* 7400 */ 129, 76, 5, 129, 76, 6, 129, 77, 6, 130,
+/* 7410 */ 77, 7, 130, 76, 8, 129, 30, 4, 75, 9,
+/* 7420 */ 129, 30, 4, 72, 12, 129, 30, 54, 129, 30,
+/* 7430 */ 53, 130, 30, 52, 129, 30, 51, 129, 30, 49,
+/* 7440 */ 129, 30, 46, 129, 30, 42, 129, 30, 4, 130,
+/* 7450 */ 193, 129, 30, 4, 80, 4, 129, 30, 4, 80,
+/* 7460 */ 4, 100, 6, 129, 30, 54, 98, 10, 129, 30,
+/* 7470 */ 54, 97, 12, 129, 30, 54, 96, 14, 131, 30,
+/* 7480 */ 54, 97, 12, 129, 30, 54, 98, 10, 129, 30,
+/* 7490 */ 54, 100, 6, 129, 30, 4, 130, 193, 129, 7,
+/* 7500 */ 6, 129, 4, 11, 129, 3, 13, 129, 2, 14,
+/* 7510 */ 129, 1, 15, 130, 1, 3, 6, 9, 129, 1,
+/* 7520 */ 3, 7, 6, 129, 1, 3, 130, 1, 4, 129,
+/* 7530 */ 1, 5, 80, 4, 129, 1, 7, 80, 4, 100,
+/* 7540 */ 6, 129, 2, 82, 98, 10, 129, 3, 81, 97,
+/* 7550 */ 12, 129, 4, 80, 96, 14, 129, 5, 79, 96,
+/* 7560 */ 14, 129, 7, 77, 96, 14, 129, 10, 74, 97,
+/* 7570 */ 12, 129, 14, 70, 98, 10, 129, 19, 65, 100,
+/* 7580 */ 6, 129, 193, 129, 30, 4, 117, 4, 130, 30,
+/* 7590 */ 91, 136, 30, 4, 57, 9, 129, 30, 4, 55,
+/* 7600 */ 12, 129, 52, 17, 129, 50, 20, 129, 48, 24,
+/* 7610 */ 129, 46, 27, 129, 44, 21, 69, 6, 129, 41,
+/* 7620 */ 22, 70, 6, 80, 4, 129, 30, 4, 39, 21,
+/* 7630 */ 72, 6, 80, 4, 129, 30, 4, 36, 22, 73,
+/* 7640 */ 11, 129, 30, 26, 75, 9, 129, 30, 23, 76,
+/* 7650 */ 8, 129, 30, 21, 78, 6, 129, 30, 19, 79,
+/* 7660 */ 5, 129, 30, 16, 80, 4, 129, 30, 14, 80,
+/* 7670 */ 4, 129, 30, 12, 129, 30, 10, 129, 30, 7,
+/* 7680 */ 129, 30, 5, 129, 30, 4, 130, 193, 129, 30,
+/* 7690 */ 4, 117, 4, 130, 30, 91, 136, 30, 4, 130,
+/* 7700 */ 193, 129, 30, 4, 80, 4, 130, 30, 54, 136,
+/* 7710 */ 30, 4, 72, 5, 129, 30, 4, 74, 5, 129,
+/* 7720 */ 75, 5, 129, 76, 5, 129, 30, 4, 75, 7,
+/* 7730 */ 129, 30, 4, 74, 9, 129, 30, 54, 132, 30,
+/* 7740 */ 53, 129, 30, 52, 129, 30, 51, 129, 30, 48,
+/* 7750 */ 129, 30, 4, 72, 5, 129, 30, 4, 74, 5,
+/* 7760 */ 129, 75, 5, 129, 76, 5, 129, 30, 4, 75,
+/* 7770 */ 7, 129, 30, 4, 74, 9, 129, 30, 54, 132,
+/* 7780 */ 30, 53, 129, 30, 52, 129, 30, 51, 129, 30,
+/* 7790 */ 48, 129, 30, 4, 130, 193, 129, 30, 4, 80,
+/* 7800 */ 4, 130, 30, 54, 136, 30, 4, 72, 5, 129,
+/* 7810 */ 30, 4, 74, 5, 129, 75, 5, 129, 76, 5,
+/* 7820 */ 129, 76, 6, 129, 77, 6, 130, 77, 7, 130,
+/* 7830 */ 76, 8, 129, 30, 4, 75, 9, 129, 30, 4,
+/* 7840 */ 72, 12, 129, 30, 54, 129, 30, 53, 130, 30,
+/* 7850 */ 52, 129, 30, 51, 129, 30, 49, 129, 30, 46,
+/* 7860 */ 129, 30, 42, 129, 30, 4, 130, 193, 129, 48,
+/* 7870 */ 18, 129, 43, 28, 129, 41, 32, 129, 39, 36,
+/* 7880 */ 129, 37, 40, 129, 35, 44, 129, 34, 46, 129,
+/* 7890 */ 33, 13, 68, 13, 129, 32, 9, 73, 9, 129,
+/* 7900 */ 32, 7, 75, 7, 129, 31, 6, 77, 6, 129,
+/* 7910 */ 31, 5, 78, 5, 129, 30, 5, 79, 5, 129,
+/* 7920 */ 30, 4, 80, 4, 132, 30, 5, 79, 5, 130,
+/* 7930 */ 31, 5, 78, 5, 129, 31, 6, 77, 6, 129,
+/* 7940 */ 32, 7, 75, 7, 129, 32, 9, 73, 9, 129,
+/* 7950 */ 33, 13, 68, 13, 129, 34, 46, 129, 35, 44,
+/* 7960 */ 129, 37, 40, 129, 39, 36, 129, 41, 32, 129,
+/* 7970 */ 43, 28, 129, 48, 18, 129, 193, 129, 1, 3,
+/* 7980 */ 80, 4, 130, 1, 83, 137, 37, 5, 72, 5,
+/* 7990 */ 129, 35, 5, 74, 5, 129, 33, 5, 76, 5,
+/* 8000 */ 129, 32, 5, 77, 5, 129, 31, 5, 78, 5,
+/* 8010 */ 129, 31, 4, 79, 4, 129, 30, 5, 79, 5,
+/* 8020 */ 131, 30, 6, 78, 6, 129, 30, 7, 77, 7,
+/* 8030 */ 129, 31, 8, 75, 8, 129, 31, 11, 72, 11,
+/* 8040 */ 129, 32, 15, 67, 15, 129, 33, 48, 129, 34,
+/* 8050 */ 46, 129, 35, 44, 129, 37, 40, 129, 39, 36,
+/* 8060 */ 129, 42, 30, 129, 46, 22, 129, 193, 129, 46,
+/* 8070 */ 22, 129, 42, 30, 129, 39, 36, 129, 37, 40,
+/* 8080 */ 129, 35, 44, 129, 34, 46, 129, 33, 48, 129,
+/* 8090 */ 32, 15, 67, 15, 129, 31, 11, 72, 11, 129,
+/* 8100 */ 31, 8, 75, 8, 129, 30, 7, 77, 7, 129,
+/* 8110 */ 30, 6, 78, 6, 129, 30, 5, 79, 5, 131,
+/* 8120 */ 31, 4, 79, 4, 129, 31, 5, 78, 5, 129,
+/* 8130 */ 32, 5, 77, 5, 129, 33, 5, 76, 5, 129,
+/* 8140 */ 35, 5, 74, 5, 129, 37, 5, 72, 5, 129,
+/* 8150 */ 1, 83, 136, 1, 3, 80, 4, 130, 193, 129,
+/* 8160 */ 30, 4, 80, 4, 130, 30, 54, 136, 30, 4,
+/* 8170 */ 68, 6, 129, 30, 4, 70, 6, 129, 71, 7,
+/* 8180 */ 129, 72, 7, 129, 73, 7, 129, 74, 7, 129,
+/* 8190 */ 74, 8, 129, 75, 8, 130, 69, 15, 129, 67,
+/* 8200 */ 17, 129, 66, 18, 129, 65, 19, 130, 65, 18,
+/* 8210 */ 130, 66, 16, 129, 67, 13, 129, 69, 8, 129,
+/* 8220 */ 193, 129, 30, 13, 64, 8, 129, 30, 13, 61,
+/* 8230 */ 14, 129, 30, 13, 59, 18, 129, 30, 13, 57,
+/* 8240 */ 22, 129, 33, 8, 56, 24, 129, 32, 7, 55,
+/* 8250 */ 26, 129, 32, 6, 54, 28, 129, 31, 6, 53,
+/* 8260 */ 16, 77, 6, 129, 31, 5, 53, 14, 79, 4,
+/* 8270 */ 129, 30, 5, 52, 14, 80, 4, 129, 30, 5,
+/* 8280 */ 52, 13, 80, 4, 129, 30, 4, 52, 13, 80,
+/* 8290 */ 4, 129, 30, 4, 52, 12, 80, 4, 129, 30,
+/* 8300 */ 4, 51, 13, 80, 4, 130, 30, 4, 50, 13,
+/* 8310 */ 79, 5, 129, 30, 4, 50, 13, 78, 5, 129,
+/* 8320 */ 30, 5, 49, 14, 77, 6, 129, 31, 4, 49,
+/* 8330 */ 13, 76, 6, 129, 31, 5, 48, 14, 75, 7,
+/* 8340 */ 129, 32, 5, 47, 14, 73, 8, 129, 32, 6,
+/* 8350 */ 45, 16, 71, 13, 129, 33, 27, 71, 13, 129,
+/* 8360 */ 34, 26, 71, 13, 129, 35, 24, 71, 13, 129,
+/* 8370 */ 37, 20, 129, 39, 16, 129, 43, 9, 129, 193,
+/* 8380 */ 129, 80, 4, 131, 41, 56, 129, 37, 60, 129,
+/* 8390 */ 35, 62, 129, 33, 64, 129, 32, 65, 129, 31,
+/* 8400 */ 66, 129, 30, 67, 130, 30, 11, 80, 4, 129,
+/* 8410 */ 30, 9, 80, 4, 129, 30, 8, 80, 4, 129,
+/* 8420 */ 31, 7, 80, 4, 129, 31, 6, 129, 32, 5,
+/* 8430 */ 129, 33, 5, 129, 35, 4, 129, 38, 3, 129,
+/* 8440 */ 193, 129, 80, 4, 130, 42, 42, 129, 38, 46,
+/* 8450 */ 129, 35, 49, 129, 33, 51, 129, 32, 52, 129,
+/* 8460 */ 31, 53, 130, 30, 54, 129, 30, 12, 129, 30,
+/* 8470 */ 9, 129, 30, 8, 129, 30, 7, 130, 31, 6,
+/* 8480 */ 130, 32, 6, 129, 33, 5, 129, 34, 5, 129,
+/* 8490 */ 35, 5, 80, 4, 129, 37, 5, 80, 4, 129,
+/* 8500 */ 30, 54, 136, 30, 4, 130, 193, 129, 80, 4,
+/* 8510 */ 130, 77, 7, 129, 74, 10, 129, 70, 14, 129,
+/* 8520 */ 66, 18, 129, 62, 22, 129, 59, 25, 129, 55,
+/* 8530 */ 29, 129, 51, 33, 129, 47, 37, 129, 44, 32,
+/* 8540 */ 80, 4, 129, 40, 32, 80, 4, 129, 36, 32,
+/* 8550 */ 129, 32, 33, 129, 30, 31, 129, 33, 24, 129,
+/* 8560 */ 36, 17, 129, 40, 12, 129, 44, 12, 129, 48,
+/* 8570 */ 12, 129, 51, 13, 129, 55, 13, 129, 59, 13,
+/* 8580 */ 80, 4, 129, 63, 13, 80, 4, 129, 67, 17,
+/* 8590 */ 129, 71, 13, 129, 74, 10, 129, 78, 6, 129,
+/* 8600 */ 80, 4, 131, 193, 129, 80, 4, 130, 77, 7,
+/* 8610 */ 129, 74, 10, 129, 70, 14, 129, 66, 18, 129,
+/* 8620 */ 62, 22, 129, 59, 25, 129, 55, 29, 129, 51,
+/* 8630 */ 33, 129, 47, 37, 129, 44, 32, 80, 4, 129,
+/* 8640 */ 40, 32, 80, 4, 129, 36, 32, 129, 32, 33,
+/* 8650 */ 129, 30, 31, 129, 33, 24, 129, 36, 17, 129,
+/* 8660 */ 40, 12, 129, 44, 12, 129, 47, 13, 129, 44,
+/* 8670 */ 20, 129, 40, 28, 129, 36, 31, 129, 32, 32,
+/* 8680 */ 129, 30, 30, 129, 33, 24, 129, 36, 17, 129,
+/* 8690 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
+/* 8700 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
+/* 8710 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
+/* 8720 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
+/* 8730 */ 193, 129, 30, 4, 80, 4, 130, 30, 4, 79,
+/* 8740 */ 5, 129, 30, 5, 77, 7, 129, 30, 6, 74,
+/* 8750 */ 10, 129, 30, 8, 72, 12, 129, 30, 11, 69,
+/* 8760 */ 15, 129, 30, 13, 67, 17, 129, 30, 4, 37,
+/* 8770 */ 8, 64, 20, 129, 30, 4, 39, 8, 62, 22,
+/* 8780 */ 129, 41, 8, 59, 25, 129, 43, 8, 57, 27,
+/* 8790 */ 129, 45, 8, 55, 22, 80, 4, 129, 47, 27,
+/* 8800 */ 80, 4, 129, 49, 23, 129, 47, 22, 129, 44,
+/* 8810 */ 23, 129, 42, 22, 129, 30, 4, 39, 27, 129,
+/* 8820 */ 30, 4, 37, 31, 129, 30, 27, 62, 8, 129,
+/* 8830 */ 30, 25, 64, 8, 129, 30, 22, 66, 8, 80,
+/* 8840 */ 4, 129, 30, 20, 68, 8, 80, 4, 129, 30,
+/* 8850 */ 17, 70, 8, 80, 4, 129, 30, 15, 73, 11,
+/* 8860 */ 129, 30, 12, 75, 9, 129, 30, 10, 77, 7,
+/* 8870 */ 129, 30, 7, 79, 5, 129, 30, 5, 80, 4,
+/* 8880 */ 129, 30, 4, 80, 4, 130, 193, 129, 4, 5,
+/* 8890 */ 80, 4, 129, 2, 9, 80, 4, 129, 1, 11,
+/* 8900 */ 77, 7, 129, 1, 12, 74, 10, 129, 1, 12,
+/* 8910 */ 70, 14, 129, 1, 12, 66, 18, 129, 1, 11,
+/* 8920 */ 62, 22, 129, 2, 9, 59, 25, 129, 4, 11,
+/* 8930 */ 55, 29, 129, 7, 12, 51, 33, 129, 10, 12,
+/* 8940 */ 47, 37, 129, 14, 12, 44, 32, 80, 4, 129,
+/* 8950 */ 17, 13, 40, 32, 80, 4, 129, 21, 13, 36,
+/* 8960 */ 32, 129, 25, 40, 129, 29, 32, 129, 33, 24,
+/* 8970 */ 129, 36, 17, 129, 40, 12, 129, 44, 12, 129,
+/* 8980 */ 48, 12, 129, 51, 13, 129, 55, 13, 129, 59,
+/* 8990 */ 13, 80, 4, 129, 63, 13, 80, 4, 129, 67,
+/* 9000 */ 17, 129, 71, 13, 129, 74, 10, 129, 78, 6,
+/* 9010 */ 129, 80, 4, 131, 193, 129, 30, 1, 71, 13,
+/* 9020 */ 129, 30, 3, 71, 13, 129, 30, 6, 71, 13,
+/* 9030 */ 129, 30, 9, 75, 9, 129, 30, 11, 77, 7,
+/* 9040 */ 129, 30, 14, 79, 5, 129, 30, 17, 79, 5,
+/* 9050 */ 129, 30, 19, 80, 4, 129, 30, 22, 80, 4,
+/* 9060 */ 129, 30, 25, 80, 4, 129, 30, 27, 80, 4,
+/* 9070 */ 129, 30, 4, 36, 24, 80, 4, 129, 30, 4,
+/* 9080 */ 38, 25, 80, 4, 129, 30, 4, 41, 24, 80,
+/* 9090 */ 4, 129, 30, 4, 44, 24, 80, 4, 129, 30,
+/* 9100 */ 4, 46, 25, 80, 4, 129, 30, 4, 49, 25,
+/* 9110 */ 80, 4, 129, 30, 4, 52, 24, 80, 4, 129,
+/* 9120 */ 30, 4, 54, 30, 129, 30, 4, 57, 27, 129,
+/* 9130 */ 30, 4, 59, 25, 129, 30, 4, 62, 22, 129,
+/* 9140 */ 30, 4, 65, 19, 129, 30, 5, 67, 17, 129,
+/* 9150 */ 30, 5, 70, 14, 129, 30, 7, 73, 11, 129,
+/* 9160 */ 30, 9, 76, 8, 129, 30, 13, 78, 6, 129,
+/* 9170 */ 30, 13, 81, 3, 129, 30, 13, 129, 193, 2,
+/* 9180 */ 9, 59, 25, 129, 4, 11, 55, 29, 129, 7,
+/* 9190 */ 12, 51, 33, 129, 10, 12, 47, 37, 129, 14,
+/* 9200 */ 12, 44, 32, 80, 4, 129, 17, 13, 40, 32,
+/* 9210 */ 80, 4, 129, 21, 13, 36, 32, 129, 25, 40,
+/* 9220 */ 129, 29, 32, 129, 33, 24, 129, 36, 17, 129,
+/* 9230 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
+/* 9240 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
+/* 9250 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
+/* 9260 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
/* 9270 */ 193
};
@@ -1027,10 +1027,10 @@ int
main(argc, argv)
int argc;
char *argv[];
-{
+{
int ch;
- while ((ch = getopt(argc, argv, "w:td")) != EOF)
+ while ((ch = getopt(argc, argv, "w:td")) != -1)
switch (ch) {
case 'd':
debug = 1;
@@ -1085,7 +1085,7 @@ main(argc, argv)
printf(" */\n");
for (i = 0; i < NBYTES; i += 10) {
printf("/* %4d */ ",i);
- for (j = i; j < i+10; j++) {
+ for (j = i; j < i+10; j++) {
x = data_table[j] & 0377;
printf(" %3d, ",x);
}
diff --git a/usr.bin/basename/basename.1 b/usr.bin/basename/basename.1
index be0963c..796bb6b 100644
--- a/usr.bin/basename/basename.1
+++ b/usr.bin/basename/basename.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)basename.1 8.2 (Berkeley) 4/18/94
+.\" $Id$
.\"
.Dd April 18, 1994
.Dt BASENAME 1
@@ -87,7 +88,7 @@ and
.Nm dirname
exit 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
-.Xr csh 1
+.Xr csh 1 ,
.Xr sh 1
.Sh STANDARDS
The
diff --git a/usr.bin/basename/basename.c b/usr.bin/basename/basename.c
index 4925b27..5964013 100644
--- a/usr.bin/basename/basename.c
+++ b/usr.bin/basename/basename.c
@@ -56,7 +56,7 @@ main(argc, argv)
char *p;
int ch;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/biff/biff.1 b/usr.bin/biff/biff.1
index 89d560c..c0caf75 100644
--- a/usr.bin/biff/biff.1
+++ b/usr.bin/biff/biff.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)biff.1 8.1 (Berkeley) 6/6/93
+.\" $Id: biff.1,v 1.4 1997/02/22 19:54:13 peter Exp $
.\"
.Dd June 6, 1993
.Dt BIFF 1
@@ -39,7 +40,7 @@
.Nd "be notified if mail arrives and who it is from"
.Sh SYNOPSIS
.Nm biff
-.Op Cm ny
+.Op Cm n | y
.Sh DESCRIPTION
.Nm Biff
informs the system whether you want to be notified when mail arrives
@@ -84,3 +85,5 @@ The
.Nm
command appeared in
.Bx 4.0 .
+It was name after the dog of Heidi Stettner. He died
+in August 1993, at 15.
diff --git a/usr.bin/biff/biff.c b/usr.bin/biff/biff.c
index 0c5fd33..a3e450c 100644
--- a/usr.bin/biff/biff.c
+++ b/usr.bin/biff/biff.c
@@ -29,6 +29,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
@@ -38,22 +40,20 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)biff.c 8.2 (Berkeley) 4/29/95";
+static char sccsid[] = "@(#)biff.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
-
-#include <err.h>
#include <errno.h>
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include <err.h>
static void usage __P((void));
-int
main(argc, argv)
int argc;
char *argv[];
@@ -62,7 +62,8 @@ main(argc, argv)
int ch;
char *name;
- while ((ch = getopt(argc, argv, "")) != EOF)
+
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
@@ -72,7 +73,7 @@ main(argc, argv)
argv += optind;
if ((name = ttyname(STDERR_FILENO)) == NULL)
- err(2, "tty");
+ err(2, "unknown tty");
if (stat(name, &sb))
err(2, "stat");
diff --git a/usr.bin/brandelf/Makefile b/usr.bin/brandelf/Makefile
new file mode 100644
index 0000000..3561ec0
--- /dev/null
+++ b/usr.bin/brandelf/Makefile
@@ -0,0 +1,3 @@
+PROG= brandelf
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/brandelf/brandelf.1 b/usr.bin/brandelf/brandelf.1
new file mode 100644
index 0000000..3ebfe27
--- /dev/null
+++ b/usr.bin/brandelf/brandelf.1
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1997
+.\" John-Mark Gurney. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY John-Mark Gurney AND CONTRIBUTORS ``AS IS''
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"
+.Dd February 6, 1997
+.Dt BRANDELF 1
+.Os FreeBSD
+.Sh NAME
+.Nm brandelf
+.Nd mark an ELF binary for a specific ABI
+.Sh SYNOPSIS
+.Nm brandelf
+.Op Fl v
+.Op Fl t Ar string
+.Ar file ...
+.Sh DESCRIPTION
+This command marks an ELF binary to be run under a certain ABI for
+.Tn FreeBSD .
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl v
+turns on verbose reporting
+.It Fl t Ar string
+Brands the given ELF binaries with
+.Ar string
+as the ABI type. Currently supported ABI's are
+.Dq Tn FreeBSD
+and
+.Dq Linux .
+.It Ar file
+If
+.Fl t Ar string
+is given it will brand
+.Ar file
+with
+.Ar string ,
+otherwise it will simply display the branding of
+.Ar file .
+.El
+.Sh EXAMPLES
+The following is an example of a typical usage
+of the
+.Nm
+command:
+.Pp
+.Dl % brandelf file
+.Dl % brandelf -t Linux file
+.Sh DIAGNOSTICS
+Exit status is 0 on success, and 1 if the command
+fails if a file doesn't exist, is too short, or fails to brand properly.
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 2.2 .
+.Sh AUTHOR
+This
+manual page was written by John-Mark Gurney
+.Aq gurney_j@efn.org .
diff --git a/usr.bin/brandelf/brandelf.c b/usr.bin/brandelf/brandelf.c
new file mode 100644
index 0000000..86519aa
--- /dev/null
+++ b/usr.bin/brandelf/brandelf.c
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1996 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: brandelf.c,v 1.6 1997/05/21 23:07:17 jdp Exp $
+ */
+
+#include <elf.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+static void usage __P((void));
+
+int
+main(int argc, char **argv)
+{
+
+ const char *type = "FreeBSD";
+ int retval = 0;
+ int ch, change = 0, verbose = 0;
+
+ while ((ch = getopt(argc, argv, "t:v")) != -1)
+ switch (ch) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ change = 1;
+ type = optarg;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (!argc)
+ errx(1, "no file(s) specified");
+ while (argc) {
+ int fd;
+ char buffer[EI_NIDENT];
+ char string[(EI_NIDENT-EI_BRAND)+1];
+
+ if ((fd = open(argv[0], O_RDWR, 0)) < 0) {
+ warnx("no such file %s", argv[0]);
+ retval = 1;
+ goto fail;
+
+ }
+ if (read(fd, buffer, EI_NIDENT) < EI_NIDENT) {
+ warnx("file '%s' too short", argv[0]);
+ retval = 1;
+ goto fail;
+ }
+ if (buffer[0] != ELFMAG0 || buffer[1] != ELFMAG1 ||
+ buffer[2] != ELFMAG2 || buffer[3] != ELFMAG3) {
+ warnx("file '%s' is not ELF format", argv[0]);
+ retval = 1;
+ goto fail;
+ }
+ if (!change) {
+ bzero(string, sizeof(string));
+ strncpy(string, &buffer[EI_BRAND], EI_NIDENT-EI_BRAND);
+ if (strlen(string)) {
+ fprintf(stdout, "File '%s' is of brand '%s'.\n",
+ argv[0], string);
+ }
+ else
+ fprintf(stdout, "File '%s' has no branding.\n",
+ argv[0]);
+ }
+ else {
+ strncpy(&buffer[EI_BRAND], type, EI_NIDENT-EI_BRAND);
+ lseek(fd, 0, SEEK_SET);
+ if (write(fd, buffer, EI_NIDENT) != EI_NIDENT) {
+ warnx("error writing %s", argv[0]);
+ retval = 1;
+ goto fail;
+ }
+ }
+fail:
+ argc--;
+ argv++;
+ }
+
+ return retval;
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: brandelf [-t string] file ...\n");
+ exit(1);
+}
diff --git a/usr.bin/cal/cal.1 b/usr.bin/cal/cal.1
index f1b5a91..7fff6cb 100644
--- a/usr.bin/cal/cal.1
+++ b/usr.bin/cal/cal.1
@@ -78,4 +78,5 @@ calendar for that month is a bit unusual.
.Sh HISTORY
A
.Nm
-command appeared in Version 6 AT&T UNIX.
+command appeared in
+.At v6 .
diff --git a/usr.bin/cal/cal.c b/usr.bin/cal/cal.c
index 88d2538..fbd58ee 100644
--- a/usr.bin/cal/cal.c
+++ b/usr.bin/cal/cal.c
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94";
#include <ctype.h>
#include <err.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -91,13 +92,10 @@ int sep1752[MAXDAYS] = {
SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
};
-char *month_names[12] = {
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December",
-};
+char *month_names[12];
-char *day_headings = " S M Tu W Th F S";
-char *j_day_headings = " S M Tu W Th F S";
+char day_headings[] = " ";
+char j_day_headings[] = " ";
/* leap year -- account for gregorian reformation in 1752 */
#define leap_year(yr) \
@@ -135,11 +133,15 @@ main(argc, argv)
char **argv;
{
struct tm *local_time;
+ static struct tm zero_tm;
time_t now;
- int ch, month, year, yflag;
+ int ch, month, year, yflag, i;
+ char buf[40];
+
+ (void) setlocale(LC_TIME, "");
yflag = 0;
- while ((ch = getopt(argc, argv, "jy")) != EOF)
+ while ((ch = getopt(argc, argv, "jy")) != -1)
switch(ch) {
case 'j':
julian = 1;
@@ -175,6 +177,18 @@ main(argc, argv)
usage();
}
+ for (i = 0; i < 12; i++) {
+ zero_tm.tm_mon = i;
+ strftime(buf, sizeof(buf), "%B", &zero_tm);
+ month_names[i] = strdup(buf);
+ }
+ for (i = 0; i < 7; i++) {
+ zero_tm.tm_wday = i;
+ strftime(buf, sizeof(buf), "%a", &zero_tm);
+ strncpy(day_headings + i * 3, buf, 2);
+ strncpy(j_day_headings + i * 4 + 1, buf, 2);
+ }
+
if (month)
monthly(month, year);
else if (julian)
diff --git a/usr.bin/calendar/Makefile b/usr.bin/calendar/Makefile
index afa891e..ad577f4 100644
--- a/usr.bin/calendar/Makefile
+++ b/usr.bin/calendar/Makefile
@@ -1,9 +1,18 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= calendar
+SRCS= calendar.c io.c day.c ostern.c paskha.c
+CFLAGS+= -Wall
+INTER= de_DE.ISO_8859-1 hr_HR.ISO_8859-2 ru_SU.KOI8-R
+TEXTMODE?= 444
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
- ${.CURDIR}/calendars/calendar.* ${DESTDIR}/usr/share/calendar
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${TEXTMODE} \
+ ${.CURDIR}/calendars/calendar.* ${DESTDIR}${SHAREDIR}/calendar
+.for lang in ${INTER}
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${TEXTMODE} \
+ ${.CURDIR}/calendars/${lang}/calendar.* \
+ ${DESTDIR}${SHAREDIR}/calendar/${lang};
+.endfor
.include <bsd.prog.mk>
diff --git a/usr.bin/calendar/calendar.1 b/usr.bin/calendar/calendar.1
index 1ffa5e5..b8d13a6 100644
--- a/usr.bin/calendar/calendar.1
+++ b/usr.bin/calendar/calendar.1
@@ -1,5 +1,5 @@
.\" Copyright (c) 1989, 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
+.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -11,8 +11,8 @@
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
+.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
.\"
.Dd June 29, 1993
.Dt CALENDAR 1
@@ -40,6 +40,14 @@
.Sh SYNOPSIS
.Nm calendar
.Op Fl a
+.Op Fl A Ar num
+.Op Fl B Ar num
+.Oo Fl t Ar dd
+.Sm off
+.Op . Ar mm Op . Ar year
+.Sm on
+.Oc
+.Op Fl f Ar calendarfile
.Sh DESCRIPTION
.Nm Calendar
checks the current directory for a file named
@@ -54,20 +62,66 @@ The following options are available:
Process the ``calendar'' files of all users and mail the results
to them.
This requires super-user privileges.
+.It Fl A Ar num
+Print lines from today and the next
+.Ar num
+days (forward, future).
+.It Fl B Ar num
+Print lines from today and the previous
+.Ar num
+days (backward, past).
+.It Fl f Pa calendarfile
+Use
+.Pa calendarfile
+as the default calendar file.
+.It Xo Fl t
+.Sm off
+.Ar dd
+.Op . Ar mm Op . Ar year
+.Sm on
+.Xc
+For test purposes only: set date directly to argument values.
.El
.Pp
-Lines should begin with a month and day.
+To handle calendars in your national code table you can specify
+.Dq LANG=<locale_name>
+in the calendar file as early as possible. To handle national Easter
+names in the calendars
+.Dq Easter=<national_name>
+(for Catholic Easter) or
+.Dq Paskha=<national_name>
+(for Orthodox Easter) can be used.
+.Pp
+Other lines should begin with a month and day.
They may be entered in almost any format, either numeric or as character
strings.
+If the proper locale is set, national month and weekday
+names can be used.
A single asterisk (``*'') matches every month.
A day without a month matches that day of every week.
A month without a day matches the first of that month.
Two numbers default to the month followed by the day.
Lines with leading tabs default to the last entered date, allowing
multiple line specifications for a single date.
+.Pp
+``Easter'', is Easter for this year, and may be followed by a positive
+or negative integer.
+.Pp
+``Paskha'', is Orthodox Easter for this year, and may be followed by a
+positive or negative integer.
+.Pp
+Weekdays may be followed by ``-4'' ... ``+5'' (aliases for
+last, first, second, third, fourth) for moving events like
+``the last Monday in April''
+.Pp
By convention, dates followed by an asterisk are not fixed, i.e., change
from year to year.
.Pp
+Day descriptions start after the first <tab> character in the line;
+if the line does not contain a <tab> character, it is not displayed.
+If the first character in the line is a <tab> character, it is treated as
+a continuation of the previous line.
+.Pp
The ``calendar'' file is preprocessed by
.Xr cpp 1 ,
allowing the inclusion of shared files such as company holidays or
@@ -81,19 +135,46 @@ Empty lines and lines protected by the C commenting syntax
.Pq Li /* ... */
are ignored.
.Pp
-Some possible calendar entries:
+Some possible calendar entries (<tab> characters highlighted by
+\fB\et\fR sequence)
.Bd -unfilled -offset indent
-#include <calendar.usholiday>
-#include <calendar.birthday>
+LANG=C
+Easter=Ostern
+
+#include <calendar.usholiday>
+#include <calendar.birthday>
+
+6/15\fB\et\fRJune 15 (if ambiguous, will default to month/day).
+Jun. 15\fB\et\fRJune 15.
+15 June\fB\et\fRJune 15.
+Thursday\fB\et\fREvery Thursday.
+June\fB\et\fREvery June 1st.
+15 *\fB\et\fR15th of every month.
+
+May Sun+2\fB\et\fRsecond Sunday in May (Muttertag)
+04/SunLast\fB\et\fRlast Sunday in April,
+\fB\et\fRsummer time in Europe
+Easter\fB\et\fREaster
+Ostern-2\fB\et\fRGood Friday (2 days before Easter)
+Paskha\fB\et\fROrthodox Easter
-6/15 ... June 15 (if ambiguous, will default to month/day).
-Jun. 15 ... June 15.
-15 June ... June 15.
-Thursday ... Every Thursday.
-June ... Every June 1st.
-15 * ... 15th of every month.
.Ed
.Sh FILES
+.Pp
+.Bl -tag -width calendar.christian -compact
+.It Pa calendar
+file in current directory
+.It Pa ~/.calendar
+.Pa calendar
+HOME directory.
+.Nm calendar
+does a chdir into this directory if it exists.
+.It Pa ~/.calendar/calendar
+calendar file to use if no calendar file exists in the current directory.
+.It Pa ~/.calendar/nomail
+do not send mail if this file exists.
+.El
+.Pp
The following default calendar files are provided:
.Pp
.Bl -tag -width calendar.christian -compact
@@ -106,9 +187,9 @@ so that roving holidays are set correctly for the current year.
.It Pa calendar.computer
Days of special significance to computer people.
.It Pa calendar.history
-Everything else, mostly U. S. historical events.
+Everything else, mostly U.S. historical events.
.It Pa calendar.holiday
-Other holidays, including the not-well-known, obscure, and
+Other holidays, including the not-well-known, obscure, and
.Em really
obscure.
.It Pa calendar.judaic
@@ -122,24 +203,28 @@ Strongly oriented toward rock 'n' roll.
U.S. holidays.
This calendar should be updated yearly by the local system administrator
so that roving holidays are set correctly for the current year.
+.It Pa calendar.german
+German calendar.
+.It Pa calendar.russian
+Russian calendar.
.El
.Sh SEE ALSO
.Xr at 1 ,
.Xr cpp 1 ,
-.Xr cron 8
.Xr mail 1 ,
+.Xr cron 8
.Sh COMPATIBILITY
The
.Nm calendar
program previously selected lines which had the correct date anywhere
in the line.
This is no longer true, the date is only recognized when it occurs
-first on the line.
+at the beginning of a line.
.Sh HISTORY
A
.Nm
-command appeared in Version 7 AT&T UNIX.
+command appeared in
+.At v7 .
.Sh BUGS
.Nm Calendar
-doesn't handle events that move around from year to year, i.e.,
-``the last Monday in April''.
+doesn't handle Jewish holidays and moon phases.
diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c
index 248d97d..64b5f6b 100644
--- a/usr.bin/calendar/calendar.c
+++ b/usr.bin/calendar/calendar.c
@@ -32,46 +32,33 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95";
+static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
#endif /* not lint */
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-
-#include <ctype.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
+#include <locale.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <tzfile.h>
+#include <time.h>
#include <unistd.h>
#include "pathnames.h"
+#include "calendar.h"
struct passwd *pw;
-int doall;
+int doall = 0;
+time_t f_time = 0;
-void cal __P((void));
-void closecal __P((FILE *));
-int getday __P((char *));
-int getfield __P((char *, char **, int *));
-int getmonth __P((char *));
-int isnow __P((char *));
-FILE *opencal __P((void));
-void settime __P((void));
-void usage __P((void));
+int f_dayAfter = 0; /* days after current date */
+int f_dayBefore = 0; /* days before current date */
int
main(argc, argv)
@@ -81,7 +68,9 @@ main(argc, argv)
extern int optind;
int ch;
- while ((ch = getopt(argc, argv, "-a")) != EOF)
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "?-af:t:A:B:")) != -1)
switch (ch) {
case '-': /* backward contemptible */
case 'a':
@@ -91,6 +80,24 @@ main(argc, argv)
}
doall = 1;
break;
+
+
+ case 'f': /* other calendar file */
+ calendarFile = optarg;
+ break;
+
+ case 't': /* other date, undocumented, for tests */
+ f_time = Mktime (optarg);
+ break;
+
+ case 'A': /* days after current date */
+ f_dayAfter = atoi(optarg);
+ break;
+
+ case 'B': /* days before current date */
+ f_dayBefore = atoi(optarg);
+ break;
+
case '?':
default:
usage();
@@ -101,10 +108,16 @@ main(argc, argv)
if (argc)
usage();
- settime();
+ /* use current time */
+ if (f_time <= 0)
+ (void)time(&f_time);
+
+ settime(f_time);
+
if (doall)
while ((pw = getpwent()) != NULL) {
(void)setegid(pw->pw_gid);
+ (void)initgroups(pw->pw_name, pw->pw_gid);
(void)seteuid(pw->pw_uid);
if (!chdir(pw->pw_dir))
cal();
@@ -115,297 +128,13 @@ main(argc, argv)
exit(0);
}
-void
-cal()
-{
- register int printing;
- register char *p;
- FILE *fp;
- int ch;
- char buf[2048 + 1];
-
- if ((fp = opencal()) == NULL)
- return;
- for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
- if ((p = strchr(buf, '\n')) != NULL)
- *p = '\0';
- else
- while ((ch = getchar()) != '\n' && ch != EOF);
- if (buf[0] == '\0')
- continue;
- if (buf[0] != '\t')
- printing = isnow(buf) ? 1 : 0;
- if (printing)
- (void)fprintf(fp, "%s\n", buf);
- }
- closecal(fp);
-}
-
-struct iovec header[] = {
- "From: ", 6,
- NULL, 0,
- " (Reminder Service)\nTo: ", 24,
- NULL, 0,
- "\nSubject: ", 10,
- NULL, 0,
- "'s Calendar\nPrecedence: bulk\n\n", 30,
-};
-
-/* 1-based month, 0-based days, cumulative */
-int daytab[][14] = {
- 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364,
- 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
-};
-struct tm *tp;
-int *cumdays, offset, yrdays;
-char dayname[10];
-
-void
-settime()
-{
- time_t now;
-
- (void)time(&now);
- tp = localtime(&now);
- if (isleap(tp->tm_year + 1900)) {
- yrdays = DAYSPERLYEAR;
- cumdays = daytab[1];
- } else {
- yrdays = DAYSPERNYEAR;
- cumdays = daytab[0];
- }
- /* Friday displays Monday's events */
- offset = tp->tm_wday == 5 ? 3 : 1;
- header[5].iov_base = dayname;
- header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
-}
-
-/*
- * Possible date formats include any combination of:
- * 3-charmonth (January, Jan, Jan)
- * 3-charweekday (Friday, Monday, mon.)
- * numeric month or day (1, 2, 04)
- *
- * Any character may separate them, or they may not be separated. Any line,
- * following a line that is matched, that starts with "whitespace", is shown
- * along with the matched line.
- */
-int
-isnow(endp)
- char *endp;
-{
- int day, flags, month, v1, v2;
-
-#define F_ISMONTH 0x01
-#define F_ISDAY 0x02
- flags = 0;
- /* didn't recognize anything, skip it */
- if (!(v1 = getfield(endp, &endp, &flags)))
- return (0);
- if (flags & F_ISDAY || v1 > 12) {
- /* found a day */
- day = v1;
- /* if no recognizable month, assume just a day alone */
- if (!(month = getfield(endp, &endp, &flags)))
- month = tp->tm_mon + 1;
- } else if (flags & F_ISMONTH) {
- month = v1;
- /* if no recognizable day, assume the first */
- if (!(day = getfield(endp, &endp, &flags)))
- day = 1;
- } else {
- v2 = getfield(endp, &endp, &flags);
- if (flags & F_ISMONTH) {
- day = v1;
- month = v2;
- } else {
- /* F_ISDAY set, v2 > 12, or no way to tell */
- month = v1;
- /* if no recognizable day, assume the first */
- day = v2 ? v2 : 1;
- }
- }
- if (flags & F_ISDAY)
- day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
- day = cumdays[month] + day;
-
- /* if today or today + offset days */
- if (day >= tp->tm_yday && day <= tp->tm_yday + offset)
- return (1);
- /* if number of days left in this year + days to event in next year */
- if (yrdays - tp->tm_yday + day <= offset)
- return (1);
- return (0);
-}
-
-int
-getfield(p, endp, flags)
- char *p, **endp;
- int *flags;
-{
- int val;
- char *start, savech;
-
- for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
- if (*p == '*') { /* `*' is current month */
- *flags |= F_ISMONTH;
- *endp = p+1;
- return (tp->tm_mon + 1);
- }
- if (isdigit(*p)) {
- val = strtol(p, &p, 10); /* if 0, it's failure */
- for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
- *endp = p;
- return (val);
- }
- for (start = p; isalpha(*++p););
- savech = *p;
- *p = '\0';
- if ((val = getmonth(start)) != 0)
- *flags |= F_ISMONTH;
- else if ((val = getday(start)) != 0)
- *flags |= F_ISDAY;
- else {
- *p = savech;
- return (0);
- }
- for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
- *endp = p;
- return (val);
-}
-
-char path[MAXPATHLEN + 1];
-
-FILE *
-opencal()
-{
- int fd, pdes[2];
-
- /* open up calendar file as stdin */
- if (!freopen("calendar", "r", stdin)) {
- if (doall)
- return (NULL);
- errx(1, "no calendar file.");
- }
- if (pipe(pdes) < 0)
- return (NULL);
- switch (vfork()) {
- case -1: /* error */
- (void)close(pdes[0]);
- (void)close(pdes[1]);
- return (NULL);
- case 0:
- /* child -- stdin already setup, set stdout to pipe input */
- if (pdes[1] != STDOUT_FILENO) {
- (void)dup2(pdes[1], STDOUT_FILENO);
- (void)close(pdes[1]);
- }
- (void)close(pdes[0]);
- execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
- (void)fprintf(stderr,
- "calendar: execl: %s: %s.\n", _PATH_CPP, strerror(errno));
- _exit(1);
- }
- /* parent -- set stdin to pipe output */
- (void)dup2(pdes[0], STDIN_FILENO);
- (void)close(pdes[0]);
- (void)close(pdes[1]);
-
- /* not reading all calendar files, just set output to stdout */
- if (!doall)
- return (stdout);
-
- /* set output to a temporary file, so if no output don't send mail */
- (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
- if ((fd = mkstemp(path)) < 0)
- return (NULL);
- return (fdopen(fd, "w+"));
-}
-
-void
-closecal(fp)
- FILE *fp;
-{
- struct stat sbuf;
- int nread, pdes[2], status;
- char buf[1024];
-
- if (!doall)
- return;
-
- (void)rewind(fp);
- if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
- goto done;
- if (pipe(pdes) < 0)
- goto done;
- switch (vfork()) {
- case -1: /* error */
- (void)close(pdes[0]);
- (void)close(pdes[1]);
- goto done;
- case 0:
- /* child -- set stdin to pipe output */
- if (pdes[0] != STDIN_FILENO) {
- (void)dup2(pdes[0], STDIN_FILENO);
- (void)close(pdes[0]);
- }
- (void)close(pdes[1]);
- execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
- "\"Reminder Service\"", "-f", "root", NULL);
- (void)fprintf(stderr,
- "calendar: %s: %s.\n", _PATH_SENDMAIL, strerror(errno));
- _exit(1);
- }
- /* parent -- write to pipe input */
- (void)close(pdes[0]);
-
- header[1].iov_base = header[3].iov_base = pw->pw_name;
- header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
- writev(pdes[1], header, 7);
- while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
- (void)write(pdes[1], buf, nread);
- (void)close(pdes[1]);
-done: (void)fclose(fp);
- (void)unlink(path);
- while (wait(&status) >= 0);
-}
-
-static char *months[] = {
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec", NULL,
-};
-
-int
-getmonth(s)
- register char *s;
-{
- register char **p;
-
- for (p = months; *p; ++p)
- if (!strncasecmp(s, *p, 3))
- return ((p - months) + 1);
- return (0);
-}
-
-static char *days[] = {
- "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
-};
-
-int
-getday(s)
- register char *s;
-{
- register char **p;
-
- for (p = days; *p; ++p)
- if (!strncasecmp(s, *p, 3))
- return ((p - days) + 1);
- return (0);
-}
void
usage()
{
- (void)fprintf(stderr, "usage: calendar [-a]\n");
+ (void)fprintf(stderr,
+ "usage: calendar [-a] [-A days] [-B days] [-f calendarfile]\n");
exit(1);
}
+
+
diff --git a/usr.bin/calendar/calendar.h b/usr.bin/calendar/calendar.h
new file mode 100644
index 0000000..6579e11
--- /dev/null
+++ b/usr.bin/calendar/calendar.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+extern struct passwd *pw;
+extern int doall;
+extern struct iovec header[];
+extern struct tm *tp;
+extern char *calendarFile;
+extern char *optarg;
+
+void cal __P((void));
+void closecal __P((FILE *));
+int getday __P((char *));
+int getdayvar __P((char *));
+int getfield __P((char *, char **, int *));
+int getmonth __P((char *));
+int geteaster __P((char *, int));
+int getpaskha __P((char *, int));
+int easter __P((int));
+int isnow __P((char *, int *, int *, int *));
+FILE *opencal __P((void));
+void settime __P((time_t));
+time_t Mktime __P((char *));
+void usage __P((void));
+void setnnames __P((void));
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+/* some flags */
+#define F_ISMONTH 0x01 /* month (Januar ...) */
+#define F_ISDAY 0x02 /* day of week (Sun, Mon, ...) */
+#define F_ISDAYVAR 0x04 /* variables day of week, like SundayLast */
+#define F_EASTER 0x08 /* Easter or easter depending days */
+
+extern f_dayAfter; /* days after current date */
+extern f_dayBefore; /* days bevore current date */
+
+struct fixs {
+ char *name;
+ int len;
+};
+
diff --git a/usr.bin/calendar/calendars/calendar.all b/usr.bin/calendar/calendars/calendar.all
new file mode 100644
index 0000000..35a40cc
--- /dev/null
+++ b/usr.bin/calendar/calendars/calendar.all
@@ -0,0 +1,16 @@
+/*
+ * International and national calendar files
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_all_
+#define _calendar_all_
+
+#include <calendar.world>
+#include <calendar.german>
+#include <calendar.usholiday>
+#include <calendar.croatian>
+#include <calendar.russian>
+
+#endif /* !_calendar_all_ */
diff --git a/usr.bin/calendar/calendars/calendar.birthday b/usr.bin/calendar/calendars/calendar.birthday
index 0cb8cab..99922af 100644
--- a/usr.bin/calendar/calendars/calendar.birthday
+++ b/usr.bin/calendar/calendars/calendar.birthday
@@ -1,3 +1,12 @@
+/*
+ * Birthday
+ *
+ * $Id: calendar.birthday,v 1.6 1997/02/25 01:20:23 mpp Exp $
+ */
+
+#ifndef _calendar_birthday_
+#define _calendar_birthday_
+
01/01 J.D. Salinger born, 1919
01/01 Paul Revere born in Boston, 1735
01/02 Isaac Asimov born in Petrovichi, Russian SFSR (now part of USSR), 1920
@@ -81,10 +90,13 @@
03/14 Giovanni Virginia Schiaparelli born, 1835, astronomer;
named Mars "canals"
03/14 Jean Baptiste Joseph Fourier born, 1768, mathematician & physicist
+03/15 J.J. Robert's Birthday in Liberia
+03/15 Julius Caesar assassinated by Brutus; Ides of March, 44BC
03/16 George Clymer born, 1739
03/16 James Madison born, 1751
03/24 Harry Houdini born, 1874
03/26 Benjamin Thompson born, 1753, Count Rumford; physicist
+03/26 David Packard died, 1996; age of 83
03/27 Wilhelm Conrad Roentgen born, 1845, discoverer of X-rays
03/28 Pierre Simon de Laplace born, 1749, mathematician & astronomer
03/30 Francisco Jose de Goya born, 1746
@@ -134,6 +146,7 @@
06/03 Henry James born, 1811
06/07 (Eugene Henri) Paul Gaugin born, 1848
06/07 George Bryan "Beau" Brummel born, 1778
+06/07 Alan Mathison Turing died, 1954
06/08 Frank Lloyd Wright born in Richland Center, Wisconsin, 1869
06/13 Alexander the Great dies (323BC)
06/15 Edward (Edvard Hagerup) Grieg born in Bergen, Norway, 1843
@@ -141,10 +154,12 @@
06/18 M.C. Escher born, 1898
06/22 Carl Hubbell born, 1903
06/22 Meryl Streep born in Summit, New Jersey, 1949
+06/23 Alan Mathison Turing born, 1912
06/25 Eric Arthur Blair (a.k.a. George Orwell) born, 1903
06/27 Helen Keller born, 1880
07/03 Franz Kafka born, 1883
07/04 Nathaniel Hawthorne born in Salem, Massachusetts, 1804
+07/04 John Adams and Thomas Jefferson die on same day, 1826
07/06 (Helen) Beatrix Potter born, 1866
07/06 John Paul Jones born, 1747
07/07 P.T. Barnum dies, 1891
@@ -152,6 +167,7 @@
07/10 John Calvin born, 1509
07/11 John Quincy Adams born, 1767
07/12 Henry David Thoreau born, 1817
+07/12 Thoreau's Birthday, 1817
07/15 Clement Clarke Moore born, 1779, author of "A Visit from
Saint Nicholas"
07/18 Brian Auger is born in London, 1939
@@ -162,10 +178,12 @@
08/01 Herman Melville born, 1819
08/03 Lenny Bruce dies of a morphine overdose, 1966
08/08 Dustin Hoffman born in Los Angeles, 1937
+08/12 Thomas Mann's Death, 1955
08/13 Annie Oakley born, 1860
08/13 Fidel Castro born, 1927
08/17 Mae West born, 1892
08/18 Meriwether Lewis born, 1927
+08/20 Leon Trotsky assassinated, 1940
08/23 Gene Kelly born, 1912
08/27 Lyndon B. Johnson born, 1908
08/29 Oliver Wendell Holmes born, 1809, physician & father of the jurist
@@ -243,15 +261,13 @@
12/12 E.G. Robinson born, 1893
12/14 George Washington dies, 1799
12/17 William Safire (Safir) born, 1929
+12/19 Konrad Zuse died, 1995
+12/20 Carl Sagan died, 1996
12/21 Benjamin Disraeli born, 1804
12/22 Giacomo Puccini born, 1858
12/23 Joseph Smith born, 1805
12/25 Isaac Newton (Sir) born in Grantham, England, 1642
12/26 Chas. Babbage born, 1791
12/28 John von Neumann born, 1903
-03/15 J.J. Robert's Birthday in Liberia
-03/15 Julius Caesar assassinated by Brutus; Ides of March, 44BC
-07/04 John Adams and Thomas Jefferson die on same day, 1826
-07/12 Thoreau's Birthday, 1817
-08/12 Thomas Mann's Death, 1955
-08/20 Leon Trotsky assassinated, 1940
+
+#endif /* !_calendar_birthday_ */
diff --git a/usr.bin/calendar/calendars/calendar.christian b/usr.bin/calendar/calendars/calendar.christian
index 7f565d6..e238918 100644
--- a/usr.bin/calendar/calendars/calendar.christian
+++ b/usr.bin/calendar/calendars/calendar.christian
@@ -1,16 +1,28 @@
+/*
+ * Christian
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_christian_
+#define _calendar_christian_
+
01/06* Epiphany
-02/11* Shrove Tuesday / Mardi Gras (day before Ash Wednesday)
-02/08* Ash Wednesday (First day of Lent)
-03/19* Palm Sunday (7 days before Easter)
-03/23* Maundy Thursday (3 days before Easter)
-03/24* Good Friday (2 days before Easter)
-03/26* Easter Sunday
-05/04* Ascension Day (10 days before Pentecost)
-05/14* Pentecost (Whitsunday)
-05/15* Whitmonday
-05/21* Trinity Sunday (7 days after Pentecost)
-05/25* Corpus Christi (11 days after Pentecost)
+Easter-47 Shrove Tuesday / Mardi Gras (day before Ash Wednesday)
+Easter-46 Ash Wednesday (First day of Lent)
+Easter-7 Palm Sunday (7 days before Easter)
+Easter-3 Maundy Thursday (3 days before Easter)
+Easter-2 Good Friday (2 days before Easter)
+Easter Easter Sunday
+Easter+39 Ascension Day (10 days before Pentecost)
+Easter+49 Pentecost (Whitsunday)
+Easter+50 Whitmonday
+Easter+56 Trinity Sunday (7 days after Pentecost)
+Easter+60 Corpus Christi (11 days after Pentecost)
05/28* Rogation Sunday
10/18 Feast Day of St. Luke
-12/03* First Sunday of Advent (4th Sunday before Christmas)
+11/SunLast First Sunday of Advent (4th Sunday before Christmas)
+12/SunFirst First Sunday of Advent (4th Sunday before Christmas)
12/06 St. Nicholas' Day
+
+#endif /* !_calendar_christian_ */
diff --git a/usr.bin/calendar/calendars/calendar.computer b/usr.bin/calendar/calendars/calendar.computer
index cd0d85d..6c6ab17 100644
--- a/usr.bin/calendar/calendars/calendar.computer
+++ b/usr.bin/calendar/calendars/calendar.computer
@@ -1,3 +1,12 @@
+/*
+ * Computer
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_computer_
+#define _calendar_computer_
+
01/01 AT&T officially divests its local Bell companies, 1984
01/01 The Epoch (Time 0 for UNIX systems, Midnight GMT, 1970)
01/03 Apple Computer founded, 1977
@@ -60,3 +69,5 @@
10/25 DEC announces VAX-11/780
11/04 UNIVAC I program predicts Eisenhower victory based on 7% of votes, 1952
12/08 First Ph.D. awarded by Computer Science Dept, Univ. of Penna, 1965
+
+#endif /* !_calendar_computer_ */
diff --git a/usr.bin/calendar/calendars/calendar.croatian b/usr.bin/calendar/calendars/calendar.croatian
new file mode 100644
index 0000000..187a0c7
--- /dev/null
+++ b/usr.bin/calendar/calendars/calendar.croatian
@@ -0,0 +1,12 @@
+/*
+ * Croatian calendar files
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_croatian_
+#define _calendar_croatian_
+
+#include <hr_HR.ISO_8859-2/calendar.all>
+
+#endif /* !_calendar_croatian_ */
diff --git a/usr.bin/calendar/calendars/calendar.german b/usr.bin/calendar/calendars/calendar.german
new file mode 100644
index 0000000..7ee93eb
--- /dev/null
+++ b/usr.bin/calendar/calendars/calendar.german
@@ -0,0 +1,12 @@
+/*
+ * German calendar file(s)
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_german_
+#define _calendar_german_
+
+#include <de_DE.ISO_8859-1/calendar.all>
+
+#endif /* !_calendar_german_ */
diff --git a/usr.bin/calendar/calendars/calendar.history b/usr.bin/calendar/calendars/calendar.history
index 9fb2189..961f429 100644
--- a/usr.bin/calendar/calendars/calendar.history
+++ b/usr.bin/calendar/calendars/calendar.history
@@ -1,5 +1,14 @@
+/*
+ * History
+ *
+ * $Id: calendar.history,v 1.6 1997/02/22 19:28:21 peter Exp $
+ */
+
+#ifndef _calendar_history_
+#define _calendar_history_
+
01/01 Anniversary of the Triumph of the Revolution in Cuba
-01/01 Castro expells Cuban President Batista, 1959
+01/01 Castro expels Cuban President Batista, 1959
01/01 Churchill delivers his "Iron Curtain" speech, 1947
01/01 First Rose Bowl; Michigan 49 - Stanford 0, 1902
01/04 Quadrantid meteor shower (look north)
@@ -26,7 +35,7 @@
01/20 St. Agnes Eve (Ah, bitter chill it was...)
01/24 Eskimo Pie patented by Christian Nelson, 1922
01/24 Gold discovered in California at Sutter's Mill, 1848
-01/26 Sydney Aust. settled, 1778
+01/26 Sydney Aust. settled, 1788
01/27 Grissom, White and Chaffe burned to death in Apollo 1, 1967
01/27 Vietnam War cease-fire signed, 1973
01/28 First ski tow, Woodstock VT, 1914
@@ -41,7 +50,7 @@
02/01 First TV soap: Secret Storm, 1954
02/01 Forces lead by Khomeini take over Iran, 1979
02/04 Cybernet inaugurated, 1969
-02/04 Patricia Hearst kidnapped by Symbionese Liberation Army, 1974
+02/04 Patricia Hearst kidnaped by Symbionese Liberation Army, 1974
02/07 Fellowship leaves Lorien (LOTR)
02/08 1963 Revolution Anniversary in Iraq
02/09 -51 degrees F, Vanderbilt MI, 1934
@@ -76,6 +85,7 @@
03/08 Deaths of Denethor & Theoden (LOTR)
03/13 "Striptease" introduced, Paris, 1894
03/14 Teddy Roosevelt excludes Japanese laborers from continental US, 1907
+03/15 Day of the 1848 revolution in Hungary
03/15 Buzzards return to Hinckley OH
03/15 France assumes protectorate over Vietnam, 1874
03/15 Watts, Los Angeles, riots kill two, injure 25, 1966
@@ -125,9 +135,9 @@
04/21 Lyrid meteor shower
04/23 Crowning of King Ellesar (LOTR)
04/23 Hank Aaron hits his first home run, 1954
-04/26 William Shakespeare baptised in Stratford-on-Avon, England, 1564,
+04/26 William Shakespeare baptized in Stratford-on-Avon, England, 1564,
birthdate unknown
-04/27 Magellan killed in Phillippines, 1521
+04/27 Magellan killed in Philippines, 1521
04/29 Zipper patented by Gideon Sindback, 1913
05/01 Beltaine; Feast of the god Bel, sun god
05/03 Anti-war protest disrupts business in Washington, 1971
@@ -162,7 +172,7 @@
05/30 US Marines sent to Nicaragua, 1912
06/02 Native Americans "granted" citizenship, 1924
06/04 Roquefort cheese developed, 1070
-06/05 Robert Kennedy assasinated, 1968
+06/05 Robert Kennedy assassinated, 1968
06/05 US leaves the Gold Standard, 1933
06/06 First drive-in movie, 1933
06/06 Normandy landing, 1944
@@ -259,7 +269,7 @@
08/13 Li'l Abner debut, 1934
08/14 Social Security begins in U.S., 1935
08/15 Gandhi's movement obtains independence for Pakistan and India, 1947
-08/15 Hurricane hits Plimoth Plantation, 1635
+08/15 Hurricane hits Plymouth Plantation, 1635
08/16 Roller Coaster patented, 1898
08/17 First public bath opened in N.Y., 1891
08/18 Anti-Cigarette League of America formed
@@ -331,9 +341,9 @@
09/20 The Roxy Theater opens in Hollywood, 1973
09/22 Allied forces form the independent nation West Germany, 1953
09/22 President Lincoln issues the Emancipation Proclamation, 1862
-09/22 Special prosecutor Leon Jeworski subpoenaes President Nixon, 1974
+09/22 Special prosecutor Leon Jeworski subpoenas President Nixon, 1974
09/22 The first Soviet atomic bomb explodes, 1949
-09/23 Phillippine President Ferdinand Marcos declares martial law, 1972
+09/23 Philippine President Ferdinand Marcos declares martial law, 1972
09/23 The New York Knickerbockers becomes the first U.S. Baseball club, 1845
09/23 V.P. Nixon denies campaign fund fraud with his "Checkers" speech, 1952
09/25 Sandra Day O'Connor becomes first woman on US Supreme Court, 1981
@@ -383,7 +393,7 @@
10/16 Boromir reaches Rivendell (LOTR)
10/17 Council of Elrond (LOTR)
10/18 Boston Shoemakers form first U.S. labor org., 1648
-10/18 Soviets anounce their probe took photos of the Moon's far side, 1959
+10/18 Soviets announce their probe took photos of the Moon's far side, 1959
10/19 Mao Tse-tung establishes the People's Republic of China, 1949
10/19 Napoleon's beaten army begins the long retreat from Moscow, 1812
10/20 "Saturday Night Massacre", 1973
@@ -391,6 +401,7 @@
10/21 Edison makes the first practical incandescent lamp, 1879
10/21 Guggenheim Museum opens, 1959
10/23 Battle of Leyte Gulf begins, 1944
+10/23 Day of the 1956 revolution in Hungary
10/23 Earth created at 6:30 AM, 4004BC.
10/23 Swallows leave Capistrano
10/25 End of War of the Ring (LOTR)
@@ -405,13 +416,13 @@
10/29 Stock Market Crash, 1929
10/30 Orson Welles' "War of the Worlds" broadcast, 1938
10/31 Luther nails 95 Theses to door of Castle Church, Wittenberg, 1517
-11/01 Austria-Hungary become two seperate nations, 1918
+11/01 Austria-Hungary become two separate nations, 1918
11/01 Puerto Rican nationalists try to kill Truman at the Blair House, 1950
11/02 Luftwaffe completes 57 consecutive nights of bombing of London, 1940
11/02 Two Frenchmen make the first free hot air balloon flight, 1783
11/03 Beef rises to 3 cents a pound, IL, 1837
11/03 Linus Pauling wins Nobel Chemistry Prize, 1954
-11/03 Sputnik II launched, 1957, bearing spacedog Laika
+11/03 Sputnik II launched, 1957, bearing space dog Laika
11/04 Iranian militants seize US embassy personnel in Teheran, 1979
11/04 Soviet forces crush the anti-communist revolt in Hungary, 1956
11/05 Guy Fawkes' Plot, 1605
@@ -423,7 +434,7 @@
11/09 Jack the Ripper kills fifth and final victim, Jane Kelly, 1888
11/09 Margaret Sanger forms American Birth Control League, 1921
11/09 Roosevelt establishes the Civil Works Administration, 1933
-11/10 41 Women arrested in suffragette demonstartions near White House, 1917
+11/10 41 Women arrested in suffragette demonstrations near White House, 1917
11/10 Cpt. Wirz, commandant of Andersonville Prison hanged, 1865
11/10 Henry Stanley asks David Livingston, "Dr. Livingston, I presume?", 1871
11/11 Washington becomes the 42nd state, 1889
@@ -484,3 +495,5 @@
12/30 First Los Angeles freeway dedicated, 1940
12/31 St. Sylvester in Switzerland
12/31 Winterland closes its doors, 1978
+
+#endif /* !_calendar_history_ */
diff --git a/usr.bin/calendar/calendars/calendar.holiday b/usr.bin/calendar/calendars/calendar.holiday
index c39ca41..6da2a1a 100644
--- a/usr.bin/calendar/calendars/calendar.holiday
+++ b/usr.bin/calendar/calendars/calendar.holiday
@@ -1,3 +1,12 @@
+/*
+ * Holiday
+ *
+ * $Id: calendar.holiday,v 1.6 1997/02/22 19:28:22 peter Exp $
+ */
+
+#ifndef _calendar_holiday_
+#define _calendar_holiday_
+
01/01 Independence Day in Haiti, Sudan
01/01 Universal Fraternity Day in Mozambique
01/02 Ancestry Day in Haiti
@@ -23,11 +32,10 @@
01/19 Nameday of Archbishop Makarios in Cyprus
01/20 Army Day in Mali
01/20 National Heroes Day in Guinea-Bissau
-01/20* Lee-Jackson Day in Virginia (3rd Monday)
-01/20* Martin Luther King Day in New York (3rd Sunday)
-01/20* Robert E. Lee's Birthday in Alabama & Mississippi (3rd Monday)
+01/SunThird Martin Luther King Day in New York (3rd Sunday)
+01/MonThird Robert E. Lee's Birthday in Alabama & Mississippi (3rd Monday)
+01/MonThird Lee-Jackson Day in Virginia (3rd Monday)
01/21 Our Lady of Altagracia in Dominican Republic
-01/21* Lee-Jackson Day in Virginia (3rd Monday)
01/23 Feast of St. Ildefonsus
01/23 National Handwriting Day
01/24 Economic Liberation Day in Togo
@@ -91,7 +99,7 @@
03/25 Lady Day (a.k.a. the Feast of the Annunciation)
03/25 Maryland Day in Maryland
03/25 National Holiday in Greece
-03/25* Seward's Day in Alaska (last Monday)
+03/MonLast Seward's Day in Alaska (last Monday)
03/26 Independence Day in Bangladesh
03/26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
03/27 Armed Forces Day in Burma
@@ -115,7 +123,7 @@
04/13 Songkron Day in Thailand
04/14 Day of the Americas in Honduras
04/15 Bengali New Year in Bangladesh
-04/15* Patriot's Day in Maine & Massachusetts (3rd Monday)
+04/MonThird Patriot's Day in Maine & Massachusetts (3rd Monday)
04/16 De Diego's Birthday (celebrated in Puerto Rico)
04/16 Holy Week (5 days) in Venezuela
04/16 Tourist Week (5 days) in Uruguay
@@ -134,8 +142,8 @@
04/26 Confederate Memorial Day in Florida & Georgia
04/26 Union Day in Tanzania
04/27 Independence Day in Togo
-04/28* Arbor Day in Wyoming (last Monday)
-04/28* Confederate Memorial Day in Alabama & Mississippi (last Monday)
+04/MonLast Arbor Day in Wyoming (last Monday)
+04/MonLast Confederate Memorial Day in Alabama & Mississippi (last Monday)
04/30 The Workers Day in Uruguay
05/01 Labor Day in many places
05/01 Law Day (decl. by Eisenhower)
@@ -152,7 +160,7 @@
05/09 Liberation Day in Czechoslovakia
05/09 Victory Day in Poland, U.S.S.R.
05/10 Confederate Memorial Day in South Carolina
-05/10 Mothers Day in Guatamala
+05/10 Mothers Day in Guatemala
05/11 Minnesota Day in Minnesota
05/14 Buddhist Holiday (Waisak 2528) in Indonesia
05/14 Independence Day (2 days) in Paraguay
@@ -165,11 +173,10 @@
05/18 Flag Day in Haiti
05/18 Prayer Day in Denmark
05/19 Youth and Sports Day in Turkey
-05/19* Memorial Day in Michigan (3rd Monday)
+05/MonThird Memorial Day in Michigan (3rd Monday)
05/20 Mecklenburg Independence Day in North Carolina
05/20 National Day in Cameroon
05/20 Victoria Day in Canada
-05/20* Memorial Day in Michigan (3rd Monday)
05/22 National Heroes Day in Sri Lanka
05/23 Commonwealth Day in Jamaica, Belize
05/23 National Labor Day in Jamaica
@@ -241,16 +248,16 @@
07/14 Bastille Day
07/14 National Holiday in Monaco
07/15 St. Swithin's Day
-07/16 Presidents Day in Botswanna
+07/16 Presidents Day in Botswana
07/17 Constitution Day in South Korea
-07/17 Public Holiday in Botswanna
+07/17 Public Holiday in Botswana
07/18 Constitution Day in Uruguay
07/18 Liberation Day in Nicaragua
07/19 Martyrs Day in Burma
07/20 Independence Day in Colombia
07/21 National Holiday in Belgium
07/22 National Day in Poland
-07/23 Eqyptian National Day in Syrian Arab Republic
+07/23 Egyptian National Day in Syrian Arab Republic
07/23 Remembrance Day in Papua, New Guinea
07/24 Pioneer Day in Utah
07/24 Simon Bolivar's Day in Ecuador, Venezuela
@@ -286,7 +293,7 @@
08/15 Independence Day in India
08/15 Liberation Day in South Korea
08/15 National Day in Congo
-08/15* Admission Day in Hawaii, 1984 (3rd Friday)
+08/FriThird Admission Day in Hawaii, 1984 (3rd Friday)
08/16 Bennington Battle Day in Vermont
08/16 Independence Days (3 days) in Gabon
08/16 Restoration Day in Dominican Republic
@@ -297,7 +304,7 @@
08/24 National Flag Day in Liberia
08/25 Constitution Day in Paragual
08/25 Independence Day in Uruguay
-08/26 Susan B. Anthony Day in Massachussetts
+08/26 Susan B. Anthony Day in Massachusetts
08/26* Bank Holiday in England and Wales
08/27 Liberation Day in Hong Kong
08/28 Heroes Day in Philippines
@@ -334,18 +341,19 @@
09/24 Republic Day in Trinidad, Tobago
09/25 Army Day in Mozambique
09/25 Referendum Day in Rwanda
-09/26 National Day in Maldives, Yemem Deomcratic Republic
-09/26 Revoluation Anniversary Day in Yemen Arab
-09/28 Confucious' Day in Taiwan
-09/30 Botswanna Day in Botswanna
+09/26 National Day in Maldives, Yemem Democratic Republic
+09/26 Revolution Anniversary Day in Yemen Arab
+09/28 Confucius' Day in Taiwan
+09/30 Botswana Day in Botswana
09/30 First Day of Sukkot
10/01 Armed Forces Day in South Korea
10/01 Independence Day in Nigeria
10/01 Labor Day in Australia
10/01 National Liberation Day (2 days) in China
-10/01 Public Holiday in Botswanna
+10/01 Public Holiday in Botswana
10/03 National Foundation Day in South Korea
-10/03 U.N. Day in Varbados
+10/03 U.N. Day in Barbados
+10/03 German Reunification Day in Germany
10/04 Independence Day in Lesotho
10/06 National Sports Day in Lesotho
10/07 National Heroes Day in Jamaica
@@ -368,7 +376,7 @@
10/12 Our Lady Aparecida Day in Brazil
10/12 Pan American Day in Belize
10/13 St. Edward's Day - Patron saint of England
-10/14 National Day in Yemen Arab Repyblic
+10/14 National Day in Yemen Arab Republic
10/14 Young People's Day in Zaire
10/14* Thanksgiving Day in Canada
10/15 Evacuation Day in Tunisia
@@ -378,7 +386,7 @@
10/20 Kenyatta Day in Kenya
10/21 Armed Forces Day in Honduras
10/21 Revolution Days (2 days) in Somalia
-10/23 Chulalongkron's Day in Thsailand
+10/23 Chulalongkron's Day in Thailand
10/24 Independence Day in Zambia
10/24 United Nations Day
10/25 Labor Day in New Zealand
@@ -402,7 +410,7 @@
11/07 National Revolution Day
11/07 October Revolution Day in Hungary
11/11 Independence Day in Angola
-11/11 Rememberance Day in Canada
+11/11 Remembrance Day in Canada
11/11 Republic Day in Maldives
11/15 Dynasty Day in Belgium
11/17 Army Day in Zaire
@@ -420,11 +428,12 @@
11/29 Goodwill Day in Liberia
11/29 Liberation Day in Albania
11/29 National Day in Burma
-11/30 Independence Day in Barbados, Yemen Deomcratic Republic
+11/30 Independence Day in Barbados, Yemen Democratic Republic
11/30 National Day in Benin
11/30 National Heroes Day in Philippines
11/30 St. Andrew's Day
12/01 Independence Day in Central African Republic
+12/01 World AIDS Day
12/02 National Holiday in United Arab Emirates
12/03 National Holiday in Laos
12/06 Independence Day in Finland
@@ -442,7 +451,7 @@
12/16 Constitution Day in Nepal
12/16 Day of the Covenant in South Africa
12/16 National Day in Bahrain
-12/16 Victry Day in Bangladesh
+12/16 Victory Day in Bangladesh
12/17 National Day in Bhutan
12/18 Republic Day in Niger
12/23 Victory Day in Egypt
@@ -468,14 +477,14 @@
05/05 Battle of Puebla in Mexico
05/08 Buddha's Birthday in South Korea
05/08 Elections for the National Assembly in Philippines
-05/14 Anniversary of the Founding of Guinean Deomcratic Party in Guinea
+05/14 Anniversary of the Founding of Guinean Democratic Party in Guinea
05/25 Anniversary of the Revolution of 1810 in Argentina
05/25 Revolution in the Sudan in Libyan Arab Republic
05/27 Afghanistan attains sovereignty, 1921
06/02 Corpus Christi in Paraguay
-06/03 Jefferson Davis's Birthday in Alabama & Mississippi (1st Monday)
-06/03 Jefferson Davis's Birthday in Florida, Georgia, & S. Carolina
+06/MonFirst Jefferson Davis's Birthday in Alabama & Mississippi (1st Monday)
+06/MonFirst Jefferson Davis's Birthday in Florida, Georgia, & S. Carolina
06/04 Queen's Birthday in New Zealand
06/06 His Majesty, Yang Di-Pertuan Agong's Birthday in Malaysia
06/11 Queen's Birthday
@@ -514,7 +523,7 @@
08/17 Anniversary of the Death of General San Martin in Argentina
09/09 Anniversary of the Socialist Revolution (2 days) in Bulgaria
09/10 Moon Festival in Taiwan
-09/11 Aniversary of military coup in Chile
+09/11 Anniversary of military coup in Chile
09/11 Ethiopian New Year in Ethiopia
09/12 Amilcar Cabral's Birthday in Guinea-Bissau
09/14 Battle of San Jacinto in Nicaragua
@@ -566,3 +575,5 @@
12/29 His Majesty, the King's Birthday in Nepal
12/30 Anniversary of the Democratic Republic of Madagascar in Madagascar
12/31 Proclamation of the Republic in Congo
+
+#endif /* !_calendar_holiday_ */
diff --git a/usr.bin/calendar/calendars/calendar.judaic b/usr.bin/calendar/calendars/calendar.judaic
index df39ad5..f162872 100644
--- a/usr.bin/calendar/calendars/calendar.judaic
+++ b/usr.bin/calendar/calendars/calendar.judaic
@@ -1,3 +1,12 @@
+/*
+ * Judaic
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_judaic_
+#define _calendar_judaic_
+
03/08* Fast of Esther (Battle of Purim; 1 day before Purim; fast day)
03/11* Purim (Feast of Lots; 30 days before Pesach)
03/12* Purim (Feast of Lots)
@@ -28,3 +37,5 @@
10/12* Shmini Atzeres/Simchas Torah (Rejoicing of the Law; sabbatical)
12/12* First Day of Chanukah
12/27* Fast of Asara B'Tevet (Babylonians put siege on Jerusalem; fast day)
+
+#endif /* !_calendar_judaic_ */
diff --git a/usr.bin/calendar/calendars/calendar.music b/usr.bin/calendar/calendars/calendar.music
index 8609e3f..5a60e59 100644
--- a/usr.bin/calendar/calendars/calendar.music
+++ b/usr.bin/calendar/calendars/calendar.music
@@ -1,10 +1,20 @@
+/*
+ * Music
+ *
+ * $Id: calendar.music,v 1.6 1997/02/22 19:28:23 peter Exp $
+ */
+
+#ifndef _calendar_music_
+#define _calendar_music_
+
01/01 Country Joe McDonald is born in El Monte, California, 1942
01/03 Steven Stills is born in Dallas, 1945
01/04 Jazz great Charlie Mingus dies at 57 in Cuernavaca, Mexico, 1979
+01/08 Elvis Presley born, 1935
01/08 David Bowie (then David Robert Jones) is born in London, 1947
01/09 James Patrick Page (Led Zeppelin) is born in Middlesex, England, 1945
01/10 Blues guitarist Howlin' Wolf dies in Chicago, 1976
-01/10 Jim Croce is born in Phildelphia, 1943
+01/10 Jim Croce is born in Philadelphia, 1943
01/10 Pat Benatar is born in Long Island, 1952
01/10 Rod Stewart is born in Glasgow, Scotland, 1945
01/13 Eric Clapton plays the "Rainbow Concert" in London, 1973
@@ -83,7 +93,7 @@
06/07 Blind Faith debuts in concert at London's Hyde Park, 1969
06/09 Les Paul (Lester Polfus) is born in Waukesha, Wisconsin, 1923
06/10 Howlin' Wolf (Chester Burnett) is born in West Point, Mississippi, 1910
-06/10 Judy Garlnad born, 1922
+06/10 Judy Garland born, 1922
06/15 Harry Nilsson is born in Brooklyn, 1941
06/16 The Monterey Pop festival opens, 1967
06/18 Paul McCartney born in Liverpool, England, 1942
@@ -98,7 +108,7 @@
07/14 Woodie Guthrie born, 1912
07/16 Cream forms in the U.K., 1966
07/16 Harry Chapin dies on Long Island Expressway, 1981
-07/17 "Yellow Submarine" premieres at the London Pavilon, 1968
+07/17 "Yellow Submarine" premieres at the London Pavilion, 1968
07/20 Carlos Santana is born in Autlan, Mexico, 1947
07/25 Bob Dylan goes electric at the Newport Folk Festival, 1965
07/25 Crosby, Stills, Nash & Young debut at the Fillmore East, 1969
@@ -176,3 +186,5 @@
12/23 First G&S collaboration, Thespis, 1871
12/28 Edgar Winter is born in Beaumont, Texas, 1946
12/31 Jimi Hendrix introduces the Band of Gypsies at the Fillmore East, 1969
+
+#endif /* !_calendar_music_ */
diff --git a/usr.bin/calendar/calendars/calendar.russian b/usr.bin/calendar/calendars/calendar.russian
new file mode 100644
index 0000000..ce192a0
--- /dev/null
+++ b/usr.bin/calendar/calendars/calendar.russian
@@ -0,0 +1,12 @@
+/*
+ * Russian calendar files
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_russian_
+#define _calendar_russian_
+
+#include <ru_SU.KOI8-R/calendar.all>
+
+#endif /* !_calendar_russian_ */
diff --git a/usr.bin/calendar/calendars/calendar.usholiday b/usr.bin/calendar/calendars/calendar.usholiday
index f799d0b..1d3e45d 100644
--- a/usr.bin/calendar/calendars/calendar.usholiday
+++ b/usr.bin/calendar/calendars/calendar.usholiday
@@ -1,31 +1,42 @@
+/*
+ * USA holiday
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_usholiday_
+#define _calendar_usholiday_
+
01/01 New Year's Day
01/14 Julian Calendar New Year's Day
02/02 Groundhog Day
02/14 St. Valentine's Day
-02/20* President's Day (3rd Monday of February)
+02/MonThird President's Day (3rd Monday of February)
03/05 Mother-in-Law Day
03/17 St. Patrick's Day
03/20* Vernal Equinox
04/01 April Fool's Day
04/15 Income Tax Day
-04/03* Daylight Savings Time begins; clocks move forward (1st Sunday of April)
+04/SunFirst Daylight Savings Time begins; clocks move forward (1st Sunday of April)
04/28* Arbor Day (varies from state to state)
-05/14* Mother's Day (2nd Sunday of May)
-05/20* Armed Forces Day (3rd Saturday of May)
-05/29* Memorial Day (Last Monday of May)
-06/18* Father's Day (3rd Sunday of June)
+05/SunSecond Mother's Day (2nd Sunday of May)
+05/SatThird Armed Forces Day (3rd Saturday of May)
+05/MonLast Memorial Day (Last Monday of May)
+06/SunThird Father's Day (3rd Sunday of June)
06/21* Summer Solstice
07/04 Independence Day
-09/04* Labor Day (1st Monday of September)
-09/09* Grandparent's Day (2nd Sunday of September; varies from state to state)
+09/MonFirst Labor Day (1st Monday of September)
+09/SunSecond Grandparent's Day (2nd Sunday of September; varies from state to state)
09/22* Autumnal Equinox
-10/09* Columbus Day (2nd Monday of October)
-10/29* Daylight Savings Time ends; clocks move back (Last Sunday in October)
+10/MonSecond Columbus Day (2nd Monday of October)
+10/SunLast Daylight Savings Time ends; clocks move back (Last Sunday in October)
10/31 All Hallows Eve (Halloween)
-11/06* Election Day (1st Tuesday after 1st Monday for even years)
+11/05* Election Day (1st Tuesday after 1st Monday for even years)
11/11 Veterans' Day
-11/29 Thanksgiving Day (Last Thursday in November)
+11/ThuFourth Thanksgiving Day (4th Thursday in November)
12/21* Winter Solstice
12/24 Christmas Eve
12/25 Christmas
12/31 New Year's Eve
+
+#endif /* !_calendar_usholiday_ */
diff --git a/usr.bin/calendar/calendars/calendar.world b/usr.bin/calendar/calendars/calendar.world
new file mode 100644
index 0000000..8720139
--- /dev/null
+++ b/usr.bin/calendar/calendars/calendar.world
@@ -0,0 +1,18 @@
+/*
+ * World wide calendar files, except national calendars
+ *
+ * $Id$
+ */
+
+#ifndef _calendar_world_
+#define _calendar_world_
+
+#include <calendar.birthday>
+#include <calendar.christian>
+#include <calendar.computer>
+#include <calendar.history>
+#include <calendar.holiday>
+#include <calendar.judaic>
+#include <calendar.music>
+
+#endif /* !_calendar_world_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.all b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.all
new file mode 100644
index 0000000..72068aa
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.all
@@ -0,0 +1,17 @@
+/*
+ * deutscher Kalender
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_all_
+#define _de_DE_ISO_8859_1_all_
+
+#include <de_DE.ISO_8859-1/calendar.feiertag>
+#include <de_DE.ISO_8859-1/calendar.geschichte>
+#include <de_DE.ISO_8859-1/calendar.kirche>
+#include <de_DE.ISO_8859-1/calendar.literatur>
+#include <de_DE.ISO_8859-1/calendar.musik>
+#include <de_DE.ISO_8859-1/calendar.wissenschaft>
+
+#endif /* !_de_DE.ISO_8859-1_all_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag
new file mode 100644
index 0000000..d723afa
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag
@@ -0,0 +1,42 @@
+/*
+ * Feiertage
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_feiertag_
+#define _de_DE_ISO_8859_1_feiertag_
+
+LANG=de_DE.ISO_8859-1
+
+/* arbeitsfreie staatliche Feiertage */
+01/01 Neujahr
+05/01 Maifeiertag
+10/03 Tag der deutschen Einheit
+
+/* arbeitsfreie christliche Feiertage */
+Easter-2 Karfreitag
+Easter Ostersonntag
+Easter+1 Ostermontag
+Easter+49 Pfingstsonntag
+Easter+50 Pfingstmontag
+Easter+39 Christi Himmelfahrt
+
+/* Gedenktage - nicht arbeitsfreie Feiertage :-( */
+06/17 Arbeiteraufstand am 17. Juni 1953
+/* ??/?? Befreiung des KZs Auschwitz */
+
+/* Jahreszeiten */
+03/21* Frühlingsanfang
+06/21* Sommeranfang
+09/21* Herbstanfang
+12/21* Winteranfang
+
+/* Sommer- und Winterzeit */
+03/SundayLast Anfang der Sommerzeit
+10/SundayLast Ende der Sommerzeit
+
+/* Blumenverkäufer */
+May Sun+2 Muttertag
+
+#endif /*! _de_DE_ISO_8859_1_feiertag_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte
new file mode 100644
index 0000000..6a2a25e
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte
@@ -0,0 +1,197 @@
+/*
+ * deutsche Geschichte
+ *
+ *
+ * Die Angaben wurden überwiegend entnommen aus dem Buch:
+ *
+ * Fragen an die deutsch Geschichte, Ideen, Kräfte, Entscheidungen von
+ * 1800 bis zur Gegenwart; historische Ausstellung im Reichstagsgebäude
+ * in Berlin; Katalog, 16. Auflage, Sonderausgabe - Bonn: Deutscher
+ * Bundestag, Referat Öffentlichkeitsarbeit, 1990
+ *
+ * English Title: Question on German history
+ *
+ * ISBN 3-924521-59-X
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_geschichte_
+#define _de_DE_ISO_8859_1_geschichte_
+
+LANG=de_DE.ISO_8859-1
+
+/* 1800-1933 */
+07/11 Gründung der Rheinbundes, 1806
+10/14 Doppelschlacht bei Jena und Auerstedt, 1806
+10/16 Völkerschlacht bei Leipzig, 1813
+06/18 Niederlage Napoleons bei Waterloo, 1815
+10/18 Wartburgfest der Deutschen Burschenschaften, 1817
+01/01 Inkrafttreten des Vertrages über den deutschen. Zollverein, 1834
+12/07 erste deutsche Eisenbahn zwischen Nürnberg und Fürth, 1835
+06 Aufstand der schlesischen Weber, 1844
+12/21 Verabschiedung des Gesetzes über die Grundrechte des deutschen
+ Volkes durch die Frankfurter Nationalversammlung, 1848
+03/27 Annahme der deutschen Reichsverfassung in der Frankfurter
+ Paulskirche, Wahl von Friedrich Wilhelm IV von Preußen zum
+ deutschen Kaiser, 1849
+04/28 Ablehnung der deutschen Kaiserkrone durch den preußichen König, 1849
+07/03 Schlacht von Königgrätz
+07/13 Emser Depesche, 1870
+07/18 Verkündung des Dogmas von der päpstlichen Unfehlbarkeit
+ durch das I. Vatikanische Konzil
+01/18 Proklamation des deutschen Kaiserreiches in Versailles, 1871
+10/18 Verabschiedung des Sozialistengesetzes durch den Reichstag, 1878
+03/20 Entlassung von Bismarck als Reichskanzler und
+ preußischer Ministerpräsident, 1890
+06/21 Eröffnung des Nord-Ostsee-Kanals, 1895
+01/07 Billigung des Bürgerlichen Gesetzbuches (BGB) durch den Reichstag, 1896
+01/01 Bürgerliches Gesetzbuches tritt in Kraft, 1900
+06/28 Ermordung des österreichischen Thronfolgers Erzherzog Franz
+ Ferdinand durch serbische Nationalisten in Sarajewo, 1914
+07/28 Kriegserklärung Österreich-Ungarns an Serbien, 1914
+08/01 Deutsche Mobilmachung und Kriegserklärung an Rußland, 1914
+08/03 Deutsche Kriegserklärung an Frankreich, 1914
+08/04 Kriegserklärung Großbritaniens an Deutschland, 1914
+08/04 Bewilligung der Kriegskredite im Reichstag, 1914
+08/26 Schlacht bei Tannenberg, 1914
+02/21 Schlacht um Verdun, 1916
+03/08 Ausbruch der Revolution in Rußland, Abdankung von Zar Nikolaus II, 1917
+04/06 Kriegserklärung der USA an Deutschland
+12/15 Waffenstillstand zwisch Rußland und Deutschland, 1917
+03/03 Frieden von Brest-Litowsk, 1918
+11/03 Matrosenaufstand in Kiel, 1918
+11/09 Ausrufung der Republik durch Scheidemann (SPD), 1918
+02/11 Friedrich Ebert wird Reichspräsident, Weimar 1919
+06/28 Unterzeichnung des Versailler Vertrages, 1919
+03/21 Volksabstimmung in Oberschlesien, 1921
+04/16 Vertrag von Rapallo, 1922
+06/24 Ermordung von Reichsaußenminister Rathenau, 1922
+01/11 Besetzung des Ruhrgebietes durch Frankreich+Belgien, 1923
+09/10 Eintritt Deutschlands in den Völkerbund, 1926
+10/25 Schwarzer Freitag in New York, Beginn der Weltwirtschaftskrise, 1929
+
+
+/* II. Weltkrieg */
+10/14 Austritt auf dem Völkerbund, 1933
+03/16 Wiedereinführung der allgemeinen Wehrpflicht, 1935
+10/25 Deutsch-italienischer Vertrag, Achse Berlin-Rom, 1936
+11/25 Antikominternpakt zwischen Deutschland und Japan, 1936
+01/13 Volksabstimmung im Saargebiet über die Rückführung ins Reich, 1935
+03/12 Einmarsch deutscher Truppen in Österreich, 1938
+09/29 Münchner Abkommen, 1938
+03/15 Einmarsch deutscher Truppen in die Tschechoslowakei, 1939
+03/23 Rückgabe des Memelgebietes an Deutschland, 1939
+08/23 Abschluß des Hitler-Stalin-Paktes, 1939
+09/03 Kriegserklärung Großbritaniens und Frankreichs an Deutschland, 1939
+04/09 Besetzung Dänemarks, Invasion in Norwegen, 1940
+05/10 Deutscher Angriff auf Belgien, die Niederlande, Luxemburg
+ und Frankreich, 1940
+06/22 Angriff gegen die Sowjetunion, 1941
+12/11 Kriegserklärung Deutschlands an die USA, 1941
+01/14 Konferenz von Casablanca, 1943
+01/31 Kapitulation der 6. deutschen Armee in Stalingrad, 1943
+06/06 Alliierte Landung in Nordwestfrankreich, 1944
+02/04 Konferenz von Jalta, 4.-11.2. 1945
+04/25 Zusammentreffen von amerikanischen und sowjetischer Truppen
+ bei Torgau an der Elbe, 1945
+05/08 Bedingungslose Kapitulation von Deutschland, 1945
+07/01 Rückzug der britischen und amerikanischen Truppen aus
+ Sachsen, Thüringen und Mecklenburg, Einmarsch westlicher
+ Truppen in Berlin, 1945
+07/17 Potsdammer Konferenz, 1945
+09/01 Überfall auf Polen, Beginn des 2. Weltkrieges, 1939
+10/01 Verkündigung der Urteile im Nürnberger
+ Hauptkriegsverbrecherprozeß, 1946
+02/25 Auflösung der Landes Preußen durch den Kontrollrat, 1947
+08/06 erster Atombombenabwurf auf Hiroshima, 1945
+08/08 Atombombenabwurf auf Nagasaki, 1945
+04/19 Warschauer Ghetto Aufstand, 1943
+12/07 Japan bombardiert Pearl Harbor, 1941
+
+/* Deutschland nach dem 2. Weltkrieg */
+04/11 Attentat auf Dutschke, Studentenunruhen, 1958
+04/26 GAU in Tschernobyl
+05/05 Natobeitritt, Wiederbewaffnung, Souveränität der Bundesrepublik, 1955
+05/06 Rücktritt von Brandt, 1974
+05/16 Wahl von Schmidt (SPD) zum Bundeskanzler, 1974
+05/23 Verkündung des Grundgesetzes
+05/23 Wahl von Richard von Weizäcker zum Bundespräsidenten, 1984
+06/05 Marshallplan, 1947
+06/20 Währungsreform in den Westzonen, 1948
+06/24 Beginn der Berliner Blockade, 1948
+07/01 Wahl von Heinrich Lübke zum Bundespräsidenten, 1959
+07/01 Währungs- und Währungsunion, 1990
+08/12 deutsch-sowjetischer Gewaltverzichtsvertrag, Moskau 1970
+08/14 Wahl zum ersten deutschen Bundestag, 1949
+09/03 Vier-Mächte-Abkommen über Berlin, 1971
+09/05 Entführung und Ermordung von Arbeitgeberpräsident Schleyer, Entführung einer Lufthansa-Maschine nach Mogadischu, 1977
+09/07 DDR-Staatsratsvorsitzender Honecker in der Bundesrepublik, 1987
+09/12 Wahl von Theodor Heuss (FDP) zum Bundespräsidenten, 1949
+09/15 Wahl von Konrad Adenauer (CDU) zum Bundeskanzler, 1949
+09/17 Bruch der Sozialliberalen Koalition, 1982
+09/18 Aufnahme von Bundesrepublik und DDR in die UNO, 1993
+10/01 Ablösung von Bundeskanzler Schmidt durch Kohl, 1982
+10/23 Volksabstimmung im Saargebiet, 1955
+12/02 Washingtoner Abkommen über Bi-Zone, 1946
+12/07 deutsch-polnischer Vertrag, Warschau 1970
+12/10 Friedensnobelpreis für Brandt, 1971
+12/12 Nachrüstungsbeschluß des NATO-Ministerates, 1979
+12/21 Grundlagenvertrag zwischen DDR und Bundesrepublik, 1972
+
+
+/* Nationalsozialismus */
+11/09 Hitler-Putsch in München/Marsch auf die Feldherrenhalle, 1923
+11/09 Reichskristallnacht, 1938
+09/14 Reichstagswahl: Erdrutsch zugunsten der NSDAP, 1930
+07/31 Reichstagswahl: NSDAP wird stärkste Fraktion, 1932
+11/06 Reichstagswahl: Rückgang der NSDAP, 1932
+01/30 Ernennung von Hitler zum Reichskanzler, 1933
+02/27 Reichstagsbrand, 1933
+03/05 Reichstagswahl: Mehrheit für NSDAP+DNVP, 1933
+03/23 Annahme des Ermächtigungsgesetzes, 1933
+03/31 Erstes Gesetz zur Gleichschaltung der Länder, 1933
+04/01 Organisierter Boykott jüdischer Geschäfte, 1933
+04/07 Zweites Gesetz zur Gleichschaltung der Länder, 1933
+05/02 Auflösung der Gewerkschaften, 1933
+06 Auflösung aller Parteien außer NSDAP, 1933
+07/20 Konkordat zwischen Deutschland und dem Vatikan, 1933
+06/30 Röhm-Putsch, Ausschaltung der SA-Führung, 1934
+09/15 Nürnberger Gesetze, 1935
+01/08 Eröffnung der olympischen Spiele in Berlin, 1936
+01/20 Wannseekonferenz, 1942
+04/30 Selbstmord Hitlers, 1945
+07/29 Mussolini geboren, 1883
+
+/* Sozialismus */
+01/21 Lenin gestorben, 1924
+06 Gründung des Bundes der Kommunisten in London durch Marx+Engels, 1847
+05/23 Gründung des Allgemeinen Deutschen Arbeitervereins in Leipzig
+ unter Führung von Ferdinand Lassalles, 1863
+08/07 Gründung der Sozialdemokratischen Arbeiterpartei in Eisenach
+ unter der Führung von August Begel und Wilhelm Liebknecht, 1869
+04/06 Gründung der Unabhängigen Sozialdemokratischen Partei, Gotha 1917
+11/07 Oktoberrevolution in Rußland, Putsch der Bolschewisten, 1917
+12/31 Gründung der KPD, 1918
+01/15 Ermordung von Rosa Luxemburg und Karl Liebknecht, 1919
+03/05 Tod Stalins, 1953
+03/18 Erste demokratische Volkskammerwahl, 1990
+04/21 Zwangsvereinigung von KPD und SPD zur SED, 1946
+05/14 Gründung der Warschauer Paktes, 1955
+06/17 Arbeiteraufstand am 17. Juni 1953
+06/25 Begin der Korea-Krieges, 1950
+08/13 Bau der Berliner Mauer, 1961
+08/21 Einmarsch des Warschauer Pakts in die Tschechoslowakei, 1968
+10/03 Offizielles Ende der DDR :-)
+10/07 Gründung der DDR 1949
+10/09 Massendemonstration in Leipzig, 1989
+10/14 Kuba-Krise, 1962
+10/18 Ablösung von Erich Honecker als SED-Generalsekretär, 1989
+11/09 Fall der Berliner Mauer, 1989
+09/09 Mao Tse-Tung gestorben im Alter von 82 Jahren, 1976
+11/10 Sowjetischer Präsident Leonid Breschnew gestorben, Alter 75, 1982
+03/27 Chruschtschow wird sowjetischer Präsident, 1958
+10/12 Chruschtschow schlägt während einer Rede in der UNO mit den
+ Schuhen auf den Tisch, 1960
+
+#endif /* _de_DE_ISO_8859_1_geschichte_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.kirche b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.kirche
new file mode 100644
index 0000000..efa7324
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.kirche
@@ -0,0 +1,32 @@
+/*
+ * Kirche in Deutschland
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_kirche_
+#define _de_DE_ISO_8859_1_kirche_
+
+LANG=de_DE.ISO_8859-1
+
+Easter-46 Aschermittwoch
+Easter-48 Rosenmontag
+Easter-7 Palmsonntag
+
+11/Sun-3 Volkstrauertag (maybe)
+11/Sun-2 Volkstrauertag oder Totensonntag
+11/Sun-1 1. Advent oder Totensonntag
+12/Sun+1 1. oder 2. Advent
+12/Sun+2 2. oder 3. Advent
+12/Sun+3 3. oder 4. Advent
+12/Sun+4 4. Advent (maybe)
+
+12/06 Nikolaus
+12/25 1. Weihnachtstag
+12/26 2. Weihnachtstag
+
+/* Evangelische Kirche */
+11/10 Martin Luther geboren in Eisleben, 1483
+10/31 95 Thesen von Luther, Wittenberg, 1517
+
+#endif /* !_de_DE_ISO_8859_1_kirche_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.literatur b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.literatur
new file mode 100644
index 0000000..865e88e
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.literatur
@@ -0,0 +1,36 @@
+/*
+ * Literatur
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_literatur_
+#define _de_DE_ISO_8859_1_literatur_
+
+LANG=de_DE.ISO_8859-1
+
+/* Schriftsteller
+
+ Fontane
+ Goethe
+ Grass
+ Hegel
+ Heine
+ Schiller
+ */
+
+01/04 Jakob Grimm geboren, 1785
+04/22 Kant geboren, 1724
+07/03 Franz Kafka geboren, 1883
+08/12 Thomas Mann gestorben, 1955
+
+
+/* Verlage */
+03/09 "die tageszeitung" als erste täglich aktualisierte deutsche
+ Tageszeitung im WWW, 1995, Betatest, vollständige Ausgabe
+05/05 Schweriner Volkszeitung als erste deutsche Tageszeitung im WWW, 1995
+05/12 "die tageszeitung" offiziell im WWW, 1995
+08/31 Hitler stellt Frankfurter Zeitung ein, 1943
+11/01 Frankfurter Allgemeine Zeitung in Leben gerufen, 1949
+
+#endif /* !_de_DE_ISO_8859_1_literatur_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.musik b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.musik
new file mode 100644
index 0000000..d08fcd7
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.musik
@@ -0,0 +1,25 @@
+/*
+ * Musik
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_musik_
+#define _de_DE_ISO_8859_1_musik_
+
+LANG=de_DE.ISO_8859-1
+
+/* Klassik */
+02/23 Händel geboren, 1685
+03/21 J.S. Bach geboren, 1685
+05/07 Johannes Brahms geboren in Hamburg, 1833
+05/22 Johann Sebastian Bach geboren in Eisenach, 1665
+07/28 Bach gestorben, 1750
+10/22 Franz Liszt geboren, 1811
+12/05 Mozart gestorben, 1791
+12/16 Beethoven gestorben, 1770
+
+/* Pop */
+09/18 Jimi Hendrix gestorben
+
+#endif /* !_de_DE_ISO_8859_1_musik_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft
new file mode 100644
index 0000000..87f9c72
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft
@@ -0,0 +1,19 @@
+/*
+ * Wissenschaft
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_wissenschaft_
+#define _de_DE_ISO_8859_1_wissenschaft_
+
+LANG=de_DE.ISO_8859-1
+
+04/12 erster Mann im All, Juri Gagarin, 1961
+04/18 Einstein gestorben, 1955
+06/22 Konrad Zuse geboren, 1919, Berlin
+10/04 Sputnik 1, erster Satellit im Weltraum, 1957
+12/18 Konrad Zuse gestorben, 1995, Hünfeld
+
+
+#endif /* ! _de_DE_ISO_8859_1_wissenschaft_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.all b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.all
new file mode 100644
index 0000000..72068aa
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.all
@@ -0,0 +1,17 @@
+/*
+ * deutscher Kalender
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_all_
+#define _de_DE_ISO_8859_1_all_
+
+#include <de_DE.ISO_8859-1/calendar.feiertag>
+#include <de_DE.ISO_8859-1/calendar.geschichte>
+#include <de_DE.ISO_8859-1/calendar.kirche>
+#include <de_DE.ISO_8859-1/calendar.literatur>
+#include <de_DE.ISO_8859-1/calendar.musik>
+#include <de_DE.ISO_8859-1/calendar.wissenschaft>
+
+#endif /* !_de_DE.ISO_8859-1_all_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.feiertag b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.feiertag
new file mode 100644
index 0000000..d723afa
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.feiertag
@@ -0,0 +1,42 @@
+/*
+ * Feiertage
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_feiertag_
+#define _de_DE_ISO_8859_1_feiertag_
+
+LANG=de_DE.ISO_8859-1
+
+/* arbeitsfreie staatliche Feiertage */
+01/01 Neujahr
+05/01 Maifeiertag
+10/03 Tag der deutschen Einheit
+
+/* arbeitsfreie christliche Feiertage */
+Easter-2 Karfreitag
+Easter Ostersonntag
+Easter+1 Ostermontag
+Easter+49 Pfingstsonntag
+Easter+50 Pfingstmontag
+Easter+39 Christi Himmelfahrt
+
+/* Gedenktage - nicht arbeitsfreie Feiertage :-( */
+06/17 Arbeiteraufstand am 17. Juni 1953
+/* ??/?? Befreiung des KZs Auschwitz */
+
+/* Jahreszeiten */
+03/21* Frühlingsanfang
+06/21* Sommeranfang
+09/21* Herbstanfang
+12/21* Winteranfang
+
+/* Sommer- und Winterzeit */
+03/SundayLast Anfang der Sommerzeit
+10/SundayLast Ende der Sommerzeit
+
+/* Blumenverkäufer */
+May Sun+2 Muttertag
+
+#endif /*! _de_DE_ISO_8859_1_feiertag_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.geschichte b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.geschichte
new file mode 100644
index 0000000..6a2a25e
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.geschichte
@@ -0,0 +1,197 @@
+/*
+ * deutsche Geschichte
+ *
+ *
+ * Die Angaben wurden überwiegend entnommen aus dem Buch:
+ *
+ * Fragen an die deutsch Geschichte, Ideen, Kräfte, Entscheidungen von
+ * 1800 bis zur Gegenwart; historische Ausstellung im Reichstagsgebäude
+ * in Berlin; Katalog, 16. Auflage, Sonderausgabe - Bonn: Deutscher
+ * Bundestag, Referat Öffentlichkeitsarbeit, 1990
+ *
+ * English Title: Question on German history
+ *
+ * ISBN 3-924521-59-X
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_geschichte_
+#define _de_DE_ISO_8859_1_geschichte_
+
+LANG=de_DE.ISO_8859-1
+
+/* 1800-1933 */
+07/11 Gründung der Rheinbundes, 1806
+10/14 Doppelschlacht bei Jena und Auerstedt, 1806
+10/16 Völkerschlacht bei Leipzig, 1813
+06/18 Niederlage Napoleons bei Waterloo, 1815
+10/18 Wartburgfest der Deutschen Burschenschaften, 1817
+01/01 Inkrafttreten des Vertrages über den deutschen. Zollverein, 1834
+12/07 erste deutsche Eisenbahn zwischen Nürnberg und Fürth, 1835
+06 Aufstand der schlesischen Weber, 1844
+12/21 Verabschiedung des Gesetzes über die Grundrechte des deutschen
+ Volkes durch die Frankfurter Nationalversammlung, 1848
+03/27 Annahme der deutschen Reichsverfassung in der Frankfurter
+ Paulskirche, Wahl von Friedrich Wilhelm IV von Preußen zum
+ deutschen Kaiser, 1849
+04/28 Ablehnung der deutschen Kaiserkrone durch den preußichen König, 1849
+07/03 Schlacht von Königgrätz
+07/13 Emser Depesche, 1870
+07/18 Verkündung des Dogmas von der päpstlichen Unfehlbarkeit
+ durch das I. Vatikanische Konzil
+01/18 Proklamation des deutschen Kaiserreiches in Versailles, 1871
+10/18 Verabschiedung des Sozialistengesetzes durch den Reichstag, 1878
+03/20 Entlassung von Bismarck als Reichskanzler und
+ preußischer Ministerpräsident, 1890
+06/21 Eröffnung des Nord-Ostsee-Kanals, 1895
+01/07 Billigung des Bürgerlichen Gesetzbuches (BGB) durch den Reichstag, 1896
+01/01 Bürgerliches Gesetzbuches tritt in Kraft, 1900
+06/28 Ermordung des österreichischen Thronfolgers Erzherzog Franz
+ Ferdinand durch serbische Nationalisten in Sarajewo, 1914
+07/28 Kriegserklärung Österreich-Ungarns an Serbien, 1914
+08/01 Deutsche Mobilmachung und Kriegserklärung an Rußland, 1914
+08/03 Deutsche Kriegserklärung an Frankreich, 1914
+08/04 Kriegserklärung Großbritaniens an Deutschland, 1914
+08/04 Bewilligung der Kriegskredite im Reichstag, 1914
+08/26 Schlacht bei Tannenberg, 1914
+02/21 Schlacht um Verdun, 1916
+03/08 Ausbruch der Revolution in Rußland, Abdankung von Zar Nikolaus II, 1917
+04/06 Kriegserklärung der USA an Deutschland
+12/15 Waffenstillstand zwisch Rußland und Deutschland, 1917
+03/03 Frieden von Brest-Litowsk, 1918
+11/03 Matrosenaufstand in Kiel, 1918
+11/09 Ausrufung der Republik durch Scheidemann (SPD), 1918
+02/11 Friedrich Ebert wird Reichspräsident, Weimar 1919
+06/28 Unterzeichnung des Versailler Vertrages, 1919
+03/21 Volksabstimmung in Oberschlesien, 1921
+04/16 Vertrag von Rapallo, 1922
+06/24 Ermordung von Reichsaußenminister Rathenau, 1922
+01/11 Besetzung des Ruhrgebietes durch Frankreich+Belgien, 1923
+09/10 Eintritt Deutschlands in den Völkerbund, 1926
+10/25 Schwarzer Freitag in New York, Beginn der Weltwirtschaftskrise, 1929
+
+
+/* II. Weltkrieg */
+10/14 Austritt auf dem Völkerbund, 1933
+03/16 Wiedereinführung der allgemeinen Wehrpflicht, 1935
+10/25 Deutsch-italienischer Vertrag, Achse Berlin-Rom, 1936
+11/25 Antikominternpakt zwischen Deutschland und Japan, 1936
+01/13 Volksabstimmung im Saargebiet über die Rückführung ins Reich, 1935
+03/12 Einmarsch deutscher Truppen in Österreich, 1938
+09/29 Münchner Abkommen, 1938
+03/15 Einmarsch deutscher Truppen in die Tschechoslowakei, 1939
+03/23 Rückgabe des Memelgebietes an Deutschland, 1939
+08/23 Abschluß des Hitler-Stalin-Paktes, 1939
+09/03 Kriegserklärung Großbritaniens und Frankreichs an Deutschland, 1939
+04/09 Besetzung Dänemarks, Invasion in Norwegen, 1940
+05/10 Deutscher Angriff auf Belgien, die Niederlande, Luxemburg
+ und Frankreich, 1940
+06/22 Angriff gegen die Sowjetunion, 1941
+12/11 Kriegserklärung Deutschlands an die USA, 1941
+01/14 Konferenz von Casablanca, 1943
+01/31 Kapitulation der 6. deutschen Armee in Stalingrad, 1943
+06/06 Alliierte Landung in Nordwestfrankreich, 1944
+02/04 Konferenz von Jalta, 4.-11.2. 1945
+04/25 Zusammentreffen von amerikanischen und sowjetischer Truppen
+ bei Torgau an der Elbe, 1945
+05/08 Bedingungslose Kapitulation von Deutschland, 1945
+07/01 Rückzug der britischen und amerikanischen Truppen aus
+ Sachsen, Thüringen und Mecklenburg, Einmarsch westlicher
+ Truppen in Berlin, 1945
+07/17 Potsdammer Konferenz, 1945
+09/01 Überfall auf Polen, Beginn des 2. Weltkrieges, 1939
+10/01 Verkündigung der Urteile im Nürnberger
+ Hauptkriegsverbrecherprozeß, 1946
+02/25 Auflösung der Landes Preußen durch den Kontrollrat, 1947
+08/06 erster Atombombenabwurf auf Hiroshima, 1945
+08/08 Atombombenabwurf auf Nagasaki, 1945
+04/19 Warschauer Ghetto Aufstand, 1943
+12/07 Japan bombardiert Pearl Harbor, 1941
+
+/* Deutschland nach dem 2. Weltkrieg */
+04/11 Attentat auf Dutschke, Studentenunruhen, 1958
+04/26 GAU in Tschernobyl
+05/05 Natobeitritt, Wiederbewaffnung, Souveränität der Bundesrepublik, 1955
+05/06 Rücktritt von Brandt, 1974
+05/16 Wahl von Schmidt (SPD) zum Bundeskanzler, 1974
+05/23 Verkündung des Grundgesetzes
+05/23 Wahl von Richard von Weizäcker zum Bundespräsidenten, 1984
+06/05 Marshallplan, 1947
+06/20 Währungsreform in den Westzonen, 1948
+06/24 Beginn der Berliner Blockade, 1948
+07/01 Wahl von Heinrich Lübke zum Bundespräsidenten, 1959
+07/01 Währungs- und Währungsunion, 1990
+08/12 deutsch-sowjetischer Gewaltverzichtsvertrag, Moskau 1970
+08/14 Wahl zum ersten deutschen Bundestag, 1949
+09/03 Vier-Mächte-Abkommen über Berlin, 1971
+09/05 Entführung und Ermordung von Arbeitgeberpräsident Schleyer, Entführung einer Lufthansa-Maschine nach Mogadischu, 1977
+09/07 DDR-Staatsratsvorsitzender Honecker in der Bundesrepublik, 1987
+09/12 Wahl von Theodor Heuss (FDP) zum Bundespräsidenten, 1949
+09/15 Wahl von Konrad Adenauer (CDU) zum Bundeskanzler, 1949
+09/17 Bruch der Sozialliberalen Koalition, 1982
+09/18 Aufnahme von Bundesrepublik und DDR in die UNO, 1993
+10/01 Ablösung von Bundeskanzler Schmidt durch Kohl, 1982
+10/23 Volksabstimmung im Saargebiet, 1955
+12/02 Washingtoner Abkommen über Bi-Zone, 1946
+12/07 deutsch-polnischer Vertrag, Warschau 1970
+12/10 Friedensnobelpreis für Brandt, 1971
+12/12 Nachrüstungsbeschluß des NATO-Ministerates, 1979
+12/21 Grundlagenvertrag zwischen DDR und Bundesrepublik, 1972
+
+
+/* Nationalsozialismus */
+11/09 Hitler-Putsch in München/Marsch auf die Feldherrenhalle, 1923
+11/09 Reichskristallnacht, 1938
+09/14 Reichstagswahl: Erdrutsch zugunsten der NSDAP, 1930
+07/31 Reichstagswahl: NSDAP wird stärkste Fraktion, 1932
+11/06 Reichstagswahl: Rückgang der NSDAP, 1932
+01/30 Ernennung von Hitler zum Reichskanzler, 1933
+02/27 Reichstagsbrand, 1933
+03/05 Reichstagswahl: Mehrheit für NSDAP+DNVP, 1933
+03/23 Annahme des Ermächtigungsgesetzes, 1933
+03/31 Erstes Gesetz zur Gleichschaltung der Länder, 1933
+04/01 Organisierter Boykott jüdischer Geschäfte, 1933
+04/07 Zweites Gesetz zur Gleichschaltung der Länder, 1933
+05/02 Auflösung der Gewerkschaften, 1933
+06 Auflösung aller Parteien außer NSDAP, 1933
+07/20 Konkordat zwischen Deutschland und dem Vatikan, 1933
+06/30 Röhm-Putsch, Ausschaltung der SA-Führung, 1934
+09/15 Nürnberger Gesetze, 1935
+01/08 Eröffnung der olympischen Spiele in Berlin, 1936
+01/20 Wannseekonferenz, 1942
+04/30 Selbstmord Hitlers, 1945
+07/29 Mussolini geboren, 1883
+
+/* Sozialismus */
+01/21 Lenin gestorben, 1924
+06 Gründung des Bundes der Kommunisten in London durch Marx+Engels, 1847
+05/23 Gründung des Allgemeinen Deutschen Arbeitervereins in Leipzig
+ unter Führung von Ferdinand Lassalles, 1863
+08/07 Gründung der Sozialdemokratischen Arbeiterpartei in Eisenach
+ unter der Führung von August Begel und Wilhelm Liebknecht, 1869
+04/06 Gründung der Unabhängigen Sozialdemokratischen Partei, Gotha 1917
+11/07 Oktoberrevolution in Rußland, Putsch der Bolschewisten, 1917
+12/31 Gründung der KPD, 1918
+01/15 Ermordung von Rosa Luxemburg und Karl Liebknecht, 1919
+03/05 Tod Stalins, 1953
+03/18 Erste demokratische Volkskammerwahl, 1990
+04/21 Zwangsvereinigung von KPD und SPD zur SED, 1946
+05/14 Gründung der Warschauer Paktes, 1955
+06/17 Arbeiteraufstand am 17. Juni 1953
+06/25 Begin der Korea-Krieges, 1950
+08/13 Bau der Berliner Mauer, 1961
+08/21 Einmarsch des Warschauer Pakts in die Tschechoslowakei, 1968
+10/03 Offizielles Ende der DDR :-)
+10/07 Gründung der DDR 1949
+10/09 Massendemonstration in Leipzig, 1989
+10/14 Kuba-Krise, 1962
+10/18 Ablösung von Erich Honecker als SED-Generalsekretär, 1989
+11/09 Fall der Berliner Mauer, 1989
+09/09 Mao Tse-Tung gestorben im Alter von 82 Jahren, 1976
+11/10 Sowjetischer Präsident Leonid Breschnew gestorben, Alter 75, 1982
+03/27 Chruschtschow wird sowjetischer Präsident, 1958
+10/12 Chruschtschow schlägt während einer Rede in der UNO mit den
+ Schuhen auf den Tisch, 1960
+
+#endif /* _de_DE_ISO_8859_1_geschichte_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.kirche b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.kirche
new file mode 100644
index 0000000..efa7324
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.kirche
@@ -0,0 +1,32 @@
+/*
+ * Kirche in Deutschland
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_kirche_
+#define _de_DE_ISO_8859_1_kirche_
+
+LANG=de_DE.ISO_8859-1
+
+Easter-46 Aschermittwoch
+Easter-48 Rosenmontag
+Easter-7 Palmsonntag
+
+11/Sun-3 Volkstrauertag (maybe)
+11/Sun-2 Volkstrauertag oder Totensonntag
+11/Sun-1 1. Advent oder Totensonntag
+12/Sun+1 1. oder 2. Advent
+12/Sun+2 2. oder 3. Advent
+12/Sun+3 3. oder 4. Advent
+12/Sun+4 4. Advent (maybe)
+
+12/06 Nikolaus
+12/25 1. Weihnachtstag
+12/26 2. Weihnachtstag
+
+/* Evangelische Kirche */
+11/10 Martin Luther geboren in Eisleben, 1483
+10/31 95 Thesen von Luther, Wittenberg, 1517
+
+#endif /* !_de_DE_ISO_8859_1_kirche_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.literatur b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.literatur
new file mode 100644
index 0000000..865e88e
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.literatur
@@ -0,0 +1,36 @@
+/*
+ * Literatur
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_literatur_
+#define _de_DE_ISO_8859_1_literatur_
+
+LANG=de_DE.ISO_8859-1
+
+/* Schriftsteller
+
+ Fontane
+ Goethe
+ Grass
+ Hegel
+ Heine
+ Schiller
+ */
+
+01/04 Jakob Grimm geboren, 1785
+04/22 Kant geboren, 1724
+07/03 Franz Kafka geboren, 1883
+08/12 Thomas Mann gestorben, 1955
+
+
+/* Verlage */
+03/09 "die tageszeitung" als erste täglich aktualisierte deutsche
+ Tageszeitung im WWW, 1995, Betatest, vollständige Ausgabe
+05/05 Schweriner Volkszeitung als erste deutsche Tageszeitung im WWW, 1995
+05/12 "die tageszeitung" offiziell im WWW, 1995
+08/31 Hitler stellt Frankfurter Zeitung ein, 1943
+11/01 Frankfurter Allgemeine Zeitung in Leben gerufen, 1949
+
+#endif /* !_de_DE_ISO_8859_1_literatur_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.musik b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.musik
new file mode 100644
index 0000000..d08fcd7
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.musik
@@ -0,0 +1,25 @@
+/*
+ * Musik
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_musik_
+#define _de_DE_ISO_8859_1_musik_
+
+LANG=de_DE.ISO_8859-1
+
+/* Klassik */
+02/23 Händel geboren, 1685
+03/21 J.S. Bach geboren, 1685
+05/07 Johannes Brahms geboren in Hamburg, 1833
+05/22 Johann Sebastian Bach geboren in Eisenach, 1665
+07/28 Bach gestorben, 1750
+10/22 Franz Liszt geboren, 1811
+12/05 Mozart gestorben, 1791
+12/16 Beethoven gestorben, 1770
+
+/* Pop */
+09/18 Jimi Hendrix gestorben
+
+#endif /* !_de_DE_ISO_8859_1_musik_ */
diff --git a/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.wissenschaft b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.wissenschaft
new file mode 100644
index 0000000..87f9c72
--- /dev/null
+++ b/usr.bin/calendar/calendars/de_DE.ISO_8859-1/calendar.wissenschaft
@@ -0,0 +1,19 @@
+/*
+ * Wissenschaft
+ *
+ * $Id$
+ */
+
+#ifndef _de_DE_ISO_8859_1_wissenschaft_
+#define _de_DE_ISO_8859_1_wissenschaft_
+
+LANG=de_DE.ISO_8859-1
+
+04/12 erster Mann im All, Juri Gagarin, 1961
+04/18 Einstein gestorben, 1955
+06/22 Konrad Zuse geboren, 1919, Berlin
+10/04 Sputnik 1, erster Satellit im Weltraum, 1957
+12/18 Konrad Zuse gestorben, 1995, Hünfeld
+
+
+#endif /* ! _de_DE_ISO_8859_1_wissenschaft_ */
diff --git a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.all b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.all
new file mode 100644
index 0000000..17285bd
--- /dev/null
+++ b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.all
@@ -0,0 +1,12 @@
+/*
+ * hrvatski calendar
+ *
+ * $Id$
+ */
+
+#ifndef _hr_HR_ISO_8859_2_all
+#define _hr_HR_ISO_8859_2_all
+
+#include <hr_HR.ISO_8859-2/calendar.praznici>
+
+#endif /* !_hr_HR_ISO_8859_2_all */
diff --git a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici
new file mode 100644
index 0000000..4c978d6
--- /dev/null
+++ b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici
@@ -0,0 +1,37 @@
+/*
+ * hrvatski praznici
+ *
+ * $Id$
+ */
+
+#ifndef _hr_HR_ISO_8859_2_praznici
+#define _hr_HR_ISO_8859_2_praznici
+
+LANG=hr_HR.ISO_8859-2
+
+/* slobodni dr¾avni praznici */
+01/01 Nova godina
+05/01 Prvi maj
+
+
+/* slobodni kr¹æanski praznici */
+Easter-2 Veliki petak
+Easter Uskrs
+Easter+1 Uskrsni ponedjeljak
+Easter+49 Duhovi
+Easter+50 Duhovni ponedjeljak
+Easter+39 Uza¹a¹æe
+12/25 Bo¾iæ
+12/26 Stjepandan
+
+/* godi¹nja doba */
+03/21* Poèetak proljeæa
+06/21* Poèetak ljeta
+09/21* Poèetak jesena
+12/21* Poèetak zime
+
+/* ljetno vrijeme */
+03/SundayLast Poèetak ljetnog vremena
+10/SundayLast Kraj ljetnog vremena
+
+#endif /* !_hr_HR_ISO_8859_2_praznici */
diff --git a/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.all b/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.all
new file mode 100644
index 0000000..17285bd
--- /dev/null
+++ b/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.all
@@ -0,0 +1,12 @@
+/*
+ * hrvatski calendar
+ *
+ * $Id$
+ */
+
+#ifndef _hr_HR_ISO_8859_2_all
+#define _hr_HR_ISO_8859_2_all
+
+#include <hr_HR.ISO_8859-2/calendar.praznici>
+
+#endif /* !_hr_HR_ISO_8859_2_all */
diff --git a/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.praznici b/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.praznici
new file mode 100644
index 0000000..4c978d6
--- /dev/null
+++ b/usr.bin/calendar/calendars/hr_HR.ISO_8859-2/calendar.praznici
@@ -0,0 +1,37 @@
+/*
+ * hrvatski praznici
+ *
+ * $Id$
+ */
+
+#ifndef _hr_HR_ISO_8859_2_praznici
+#define _hr_HR_ISO_8859_2_praznici
+
+LANG=hr_HR.ISO_8859-2
+
+/* slobodni dr¾avni praznici */
+01/01 Nova godina
+05/01 Prvi maj
+
+
+/* slobodni kr¹æanski praznici */
+Easter-2 Veliki petak
+Easter Uskrs
+Easter+1 Uskrsni ponedjeljak
+Easter+49 Duhovi
+Easter+50 Duhovni ponedjeljak
+Easter+39 Uza¹a¹æe
+12/25 Bo¾iæ
+12/26 Stjepandan
+
+/* godi¹nja doba */
+03/21* Poèetak proljeæa
+06/21* Poèetak ljeta
+09/21* Poèetak jesena
+12/21* Poèetak zime
+
+/* ljetno vrijeme */
+03/SundayLast Poèetak ljetnog vremena
+10/SundayLast Kraj ljetnog vremena
+
+#endif /* !_hr_HR_ISO_8859_2_praznici */
diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all
new file mode 100644
index 0000000..89548e8
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all
@@ -0,0 +1,15 @@
+/*
+ * òÕÓÓËÉÊ ËÁÌÅÎÄÁÒØ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_all
+#define _ru_SU_KOI8_R_all
+
+#include <ru_SU.KOI8-R/calendar.common>
+#include <ru_SU.KOI8-R/calendar.msk>
+#include <ru_SU.KOI8-R/calendar.pagan>
+#include <ru_SU.KOI8-R/calendar.orthodox>
+
+#endif /* !_ru_SU_KOI8_R_all */
diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.common b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.common
new file mode 100644
index 0000000..6bd7764
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.common
@@ -0,0 +1,24 @@
+/*
+ * òÕÓÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id: calendar.common,v 1.6 1997/05/01 14:39:55 ache Exp $
+ */
+
+#ifndef _ru_SU_KOI8_R_common_
+#define _ru_SU_KOI8_R_common_
+
+LANG=ru_SU.KOI8-R
+
+ 1 ÑÎ× îÏ×ÙÊ çÏÄ
+14 ÑÎ× óÔÁÒÙÊ îÏ×ÙÊ çÏÄ
+23 ÆÅ× äÅÎØ úÁÝÉÔÎÉËÁ ïÔÅÞÅÓÔ×Á
+ 8 ÍÁÒ íÅÖÄÕÎÁÒÏÄÎÙÊ öÅÎÓËÉÊ äÅÎØ
+ 1 ÁÐÒ äÅÎØ óÍÅÈÁ
+ 1 ÍÁÊ ðÒÁÚÄÎÉË ×ÅÓÎÙ É ÔÒÕÄÁ
+ 9 ÍÁÊ äÅÎØ ðÏÂÅÄÙ
+ 1 ÉÀÎ äÅÎØ úÁÝÉÔÙ äÅÔÅÊ
+12 ÉÀÎ äÅÎØ îÅÚÁ×ÉÓÉÍÏÓÔÉ òÏÓÓÉÉ
+ 1 ÓÅÎ äÅÎØ úÎÁÎÉÊ
+
+#endif /* !_ru_SU_KOI8_R_common_ */
+
diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk
new file mode 100644
index 0000000..25c0eef
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk
@@ -0,0 +1,16 @@
+/*
+ * ðÅÒÅ×ÏÄ ÞÁÓÏ× ÄÌÑ ÍÏÓËÏ×ÓËÏÊ ×ÒÅÍÅÎÎÏÊ ÚÏÎÙ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_msk_
+#define _ru_SU_KOI8_R_msk_
+
+LANG=ru_SU.KOI8-R
+
+03/SunLast îÁÞÁÌÏ ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ×ÐÅÒÅÄ
+10/SunLast ëÏÎÅà ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ÎÁÚÁÄ
+
+#endif /* !_ru_SU_KOI8_R_msk_ */
+
diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox
new file mode 100644
index 0000000..51ef35b
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox
@@ -0,0 +1,34 @@
+/*
+ * ðÒÁ×ÏÓÌÁ×ÎÙÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_orthodox_
+#define _ru_SU_KOI8_R_orthodox_
+
+LANG=ru_SU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÓÅÎ òÏÖÄÅÓÔ×Ï ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+28 ÓÅÎ ÷ÏÚÄ×ÉÖÅÎÉÅ ëÒÅÓÔÁ çÏÓÐÏÄÎÑ
+14 ÏËÔ ðÏËÒÏ× ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 4 ÄÅË ÷×ÅÄÅÎÉÅ ×Ï ÈÒÁÍ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 7 ÑÎ× òÏÖÄÅÓÔ×Ï èÒÉÓÔÏ×Ï
+19 ÑÎ× âÏÇÏÑ×ÌÅÎÉÅ ÉÌÉ ëÒÅÝÅÎÉÅ çÏÓÐÏÄÎÅ
+15 ÆÅ× óÒÅÔÅÎÉÅ çÏÓÐÏÄÎÅ
+ðÁÓÈÁ-46 ÷ÅÌÉËÉÊ ðÏÓÔ
+ðÁÓÈÁ-7 ÷ÅÒÂÎÏÅ ÷ÏÓËÒÅÓÅÎØÅ
+ðÁÓÈÁ-3 ÷ÅÌÉËÉÊ þÅÔ×ÅÒÇ
+ðÁÓÈÁ-2 óÔÒÁÓÔÎÁÑ ðÑÔÎÉÃÁ
+ðÁÓÈÁ ÷ÏÓËÒÅÓÅÎÉÅ èÒÉÓÔÏ×Ï
+ðÁÓÈÁ+39 ÷ÏÚÎÅÓÅÎÉÅ
+ðÁÓÈÁ+49 ðÑÔÉÄÅÓÑÔÎÉÃÁ
+ðÁÓÈÁ+56 ôÒÏÉÃÉÎ äÅÎØ
+ðÁÓÈÁ+60 ðÒÁÚÄÎÉË ôÅÌÁ èÒÉÓÔÏ×Á
+ 7 ÁÐÒ âÌÁÇÏ×ÅÝÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+19 Á×Ç ðÒÅÏÂÒÁÖÅÎÉÅ çÏÓÐÏÄÎÅ
+28 Á×Ç õÓÐÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+
+#endif /* !_ru_SU_KOI8_R_orthodox_ */
+
diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.pagan b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.pagan
new file mode 100644
index 0000000..993a32d
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.pagan
@@ -0,0 +1,42 @@
+/*
+ * ñÚÙÞÅÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_pagan_
+#define _ru_SU_KOI8_R_pagan_
+
+LANG=ru_SU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÄÅË* úÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+25 ÄÅË ëÏÌÑÄÁ (ÓÄ×ÉÎÕÔÏÅ ÚÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+31 ÄÅË îÅÄÅÌÑ ðÒÁÏÔÃÏ×
+ 6 ÑÎ× äÅÎØ ëÁÝÅÑ É ÷ÅÌÅÓÁ, ÐÏÓÔ
+24 ÆÅ× äÅÎØ ÷ÅÌÅÓÁ
+29 ÆÅ× äÅÎØ ëÁÝÅÑ
+ 1 ÍÁÒ äÅÎØ íÁÒÅÎÙ
+14 ÍÁÒ îÏ×ÙÊ çÏÄ, ï×ÓÅÎØ ÍÁÌÙÊ
+ðÁÓÈÁ-47 íÁÓÌÅÎÉÃÁ
+ðÁÓÈÁ+7 ëÒÁÓÎÁÑ çÏÒËÁ
+ðÁÓÈÁ+16 òÁÄÕÎÉÃÁ
+20 ÍÁÒ* ÷ÅÓÅÎÎÉÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ
+ 7 ÁÐÒ äÅÎØ íÁÒÅÎÙ (ÓÄ×ÉÎÕÔÏÅ ×ÅÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+ 6 ÍÁÊ äÅÎØ äÁÖØÂÏÇÁ, ï×ÓÅÎØ ÂÏÌØÛÏÊ
+22 ÍÁÊ ñÒÉÌÉÎ äÅÎØ
+21 ÉÀÎ* ìÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+ 1 ÉÀÌ òÕÓÁÌØÎÁÑ îÅÄÅÌÑ
+ 7 ÉÀÌ ëÕÐÁÌÁ (ÓÄ×ÉÎÕÔÏÅ ÌÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+27 ÉÀÌ ïÔÂÏÒ ÖÅÒÔ× ðÅÒÕÎÕ, ÒÕÓÁÌÉÉ
+ 2 Á×Ç ðÅÒÕÎÏ× äÅÎØ
+21 Á×Ç äÅÎØ óÔÒÉÂÏÇÁ
+28 Á×Ç õÓÐÅÎÉÅ úÌÁÔÏÇÏÒËÉ
+14 ÓÅÎ äÅÎØ ÷ÏÌÈÁ úÍÅÅ×ÉÞÁ
+22 ÓÅÎ* ðÏ×ÏÒÏÔ Ë ÚÉÍÅ (ÏÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+10 ÎÏÑ äÅÎØ íÁËÏÛÉ
+21 ÎÏÑ äÅÎØ ó×ÁÒÏÇÁ É óÅÍÁÒÇÌÁ
+ 9 ÄÅË äÅÎØ äÁÖØÂÏÇÁ É íÁÒÅÎÙ
+
+#endif /* !_ru_SU_KOI8_R_pagan_ */
+
diff --git a/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.all b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.all
new file mode 100644
index 0000000..89548e8
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.all
@@ -0,0 +1,15 @@
+/*
+ * òÕÓÓËÉÊ ËÁÌÅÎÄÁÒØ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_all
+#define _ru_SU_KOI8_R_all
+
+#include <ru_SU.KOI8-R/calendar.common>
+#include <ru_SU.KOI8-R/calendar.msk>
+#include <ru_SU.KOI8-R/calendar.pagan>
+#include <ru_SU.KOI8-R/calendar.orthodox>
+
+#endif /* !_ru_SU_KOI8_R_all */
diff --git a/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.common b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.common
new file mode 100644
index 0000000..6bd7764
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.common
@@ -0,0 +1,24 @@
+/*
+ * òÕÓÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id: calendar.common,v 1.6 1997/05/01 14:39:55 ache Exp $
+ */
+
+#ifndef _ru_SU_KOI8_R_common_
+#define _ru_SU_KOI8_R_common_
+
+LANG=ru_SU.KOI8-R
+
+ 1 ÑÎ× îÏ×ÙÊ çÏÄ
+14 ÑÎ× óÔÁÒÙÊ îÏ×ÙÊ çÏÄ
+23 ÆÅ× äÅÎØ úÁÝÉÔÎÉËÁ ïÔÅÞÅÓÔ×Á
+ 8 ÍÁÒ íÅÖÄÕÎÁÒÏÄÎÙÊ öÅÎÓËÉÊ äÅÎØ
+ 1 ÁÐÒ äÅÎØ óÍÅÈÁ
+ 1 ÍÁÊ ðÒÁÚÄÎÉË ×ÅÓÎÙ É ÔÒÕÄÁ
+ 9 ÍÁÊ äÅÎØ ðÏÂÅÄÙ
+ 1 ÉÀÎ äÅÎØ úÁÝÉÔÙ äÅÔÅÊ
+12 ÉÀÎ äÅÎØ îÅÚÁ×ÉÓÉÍÏÓÔÉ òÏÓÓÉÉ
+ 1 ÓÅÎ äÅÎØ úÎÁÎÉÊ
+
+#endif /* !_ru_SU_KOI8_R_common_ */
+
diff --git a/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.msk b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.msk
new file mode 100644
index 0000000..25c0eef
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.msk
@@ -0,0 +1,16 @@
+/*
+ * ðÅÒÅ×ÏÄ ÞÁÓÏ× ÄÌÑ ÍÏÓËÏ×ÓËÏÊ ×ÒÅÍÅÎÎÏÊ ÚÏÎÙ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_msk_
+#define _ru_SU_KOI8_R_msk_
+
+LANG=ru_SU.KOI8-R
+
+03/SunLast îÁÞÁÌÏ ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ×ÐÅÒÅÄ
+10/SunLast ëÏÎÅà ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ÎÁÚÁÄ
+
+#endif /* !_ru_SU_KOI8_R_msk_ */
+
diff --git a/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.orthodox b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.orthodox
new file mode 100644
index 0000000..51ef35b
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.orthodox
@@ -0,0 +1,34 @@
+/*
+ * ðÒÁ×ÏÓÌÁ×ÎÙÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_orthodox_
+#define _ru_SU_KOI8_R_orthodox_
+
+LANG=ru_SU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÓÅÎ òÏÖÄÅÓÔ×Ï ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+28 ÓÅÎ ÷ÏÚÄ×ÉÖÅÎÉÅ ëÒÅÓÔÁ çÏÓÐÏÄÎÑ
+14 ÏËÔ ðÏËÒÏ× ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 4 ÄÅË ÷×ÅÄÅÎÉÅ ×Ï ÈÒÁÍ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 7 ÑÎ× òÏÖÄÅÓÔ×Ï èÒÉÓÔÏ×Ï
+19 ÑÎ× âÏÇÏÑ×ÌÅÎÉÅ ÉÌÉ ëÒÅÝÅÎÉÅ çÏÓÐÏÄÎÅ
+15 ÆÅ× óÒÅÔÅÎÉÅ çÏÓÐÏÄÎÅ
+ðÁÓÈÁ-46 ÷ÅÌÉËÉÊ ðÏÓÔ
+ðÁÓÈÁ-7 ÷ÅÒÂÎÏÅ ÷ÏÓËÒÅÓÅÎØÅ
+ðÁÓÈÁ-3 ÷ÅÌÉËÉÊ þÅÔ×ÅÒÇ
+ðÁÓÈÁ-2 óÔÒÁÓÔÎÁÑ ðÑÔÎÉÃÁ
+ðÁÓÈÁ ÷ÏÓËÒÅÓÅÎÉÅ èÒÉÓÔÏ×Ï
+ðÁÓÈÁ+39 ÷ÏÚÎÅÓÅÎÉÅ
+ðÁÓÈÁ+49 ðÑÔÉÄÅÓÑÔÎÉÃÁ
+ðÁÓÈÁ+56 ôÒÏÉÃÉÎ äÅÎØ
+ðÁÓÈÁ+60 ðÒÁÚÄÎÉË ôÅÌÁ èÒÉÓÔÏ×Á
+ 7 ÁÐÒ âÌÁÇÏ×ÅÝÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+19 Á×Ç ðÒÅÏÂÒÁÖÅÎÉÅ çÏÓÐÏÄÎÅ
+28 Á×Ç õÓÐÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+
+#endif /* !_ru_SU_KOI8_R_orthodox_ */
+
diff --git a/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.pagan b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.pagan
new file mode 100644
index 0000000..993a32d
--- /dev/null
+++ b/usr.bin/calendar/calendars/ru_SU.KOI8-R/calendar.pagan
@@ -0,0 +1,42 @@
+/*
+ * ñÚÙÞÅÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $Id$
+ */
+
+#ifndef _ru_SU_KOI8_R_pagan_
+#define _ru_SU_KOI8_R_pagan_
+
+LANG=ru_SU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÄÅË* úÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+25 ÄÅË ëÏÌÑÄÁ (ÓÄ×ÉÎÕÔÏÅ ÚÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+31 ÄÅË îÅÄÅÌÑ ðÒÁÏÔÃÏ×
+ 6 ÑÎ× äÅÎØ ëÁÝÅÑ É ÷ÅÌÅÓÁ, ÐÏÓÔ
+24 ÆÅ× äÅÎØ ÷ÅÌÅÓÁ
+29 ÆÅ× äÅÎØ ëÁÝÅÑ
+ 1 ÍÁÒ äÅÎØ íÁÒÅÎÙ
+14 ÍÁÒ îÏ×ÙÊ çÏÄ, ï×ÓÅÎØ ÍÁÌÙÊ
+ðÁÓÈÁ-47 íÁÓÌÅÎÉÃÁ
+ðÁÓÈÁ+7 ëÒÁÓÎÁÑ çÏÒËÁ
+ðÁÓÈÁ+16 òÁÄÕÎÉÃÁ
+20 ÍÁÒ* ÷ÅÓÅÎÎÉÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ
+ 7 ÁÐÒ äÅÎØ íÁÒÅÎÙ (ÓÄ×ÉÎÕÔÏÅ ×ÅÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+ 6 ÍÁÊ äÅÎØ äÁÖØÂÏÇÁ, ï×ÓÅÎØ ÂÏÌØÛÏÊ
+22 ÍÁÊ ñÒÉÌÉÎ äÅÎØ
+21 ÉÀÎ* ìÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+ 1 ÉÀÌ òÕÓÁÌØÎÁÑ îÅÄÅÌÑ
+ 7 ÉÀÌ ëÕÐÁÌÁ (ÓÄ×ÉÎÕÔÏÅ ÌÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+27 ÉÀÌ ïÔÂÏÒ ÖÅÒÔ× ðÅÒÕÎÕ, ÒÕÓÁÌÉÉ
+ 2 Á×Ç ðÅÒÕÎÏ× äÅÎØ
+21 Á×Ç äÅÎØ óÔÒÉÂÏÇÁ
+28 Á×Ç õÓÐÅÎÉÅ úÌÁÔÏÇÏÒËÉ
+14 ÓÅÎ äÅÎØ ÷ÏÌÈÁ úÍÅÅ×ÉÞÁ
+22 ÓÅÎ* ðÏ×ÏÒÏÔ Ë ÚÉÍÅ (ÏÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+10 ÎÏÑ äÅÎØ íÁËÏÛÉ
+21 ÎÏÑ äÅÎØ ó×ÁÒÏÇÁ É óÅÍÁÒÇÌÁ
+ 9 ÄÅË äÅÎØ äÁÖØÂÏÇÁ É íÁÒÅÎÙ
+
+#endif /* !_ru_SU_KOI8_R_pagan_ */
+
diff --git a/usr.bin/calendar/day.c b/usr.bin/calendar/day.c
new file mode 100644
index 0000000..91b3731
--- /dev/null
+++ b/usr.bin/calendar/day.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+
+#include "pathnames.h"
+#include "calendar.h"
+
+struct tm *tp;
+int *cumdays, offset, yrdays;
+char dayname[10];
+
+
+/* 1-based month, 0-based days, cumulative */
+int daytab[][14] = {
+ { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
+ { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+};
+
+static char *days[] = {
+ "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
+};
+
+static char *months[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec", NULL,
+};
+
+static struct fixs fndays[8]; /* full national days names */
+static struct fixs ndays[8]; /* short national days names */
+
+static struct fixs fnmonths[13]; /* full national months names */
+static struct fixs nmonths[13]; /* short national month names */
+
+
+void setnnames(void)
+{
+ char buf[80];
+ int i, l;
+ struct tm tm;
+
+ for (i = 0; i < 7; i++) {
+ tm.tm_wday = i;
+ strftime(buf, sizeof(buf), "%a", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (ndays[i].name != NULL)
+ free(ndays[i].name);
+ if ((ndays[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ ndays[i].len = strlen(buf);
+
+ strftime(buf, sizeof(buf), "%A", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (fndays[i].name != NULL)
+ free(fndays[i].name);
+ if ((fndays[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ fndays[i].len = strlen(buf);
+ }
+
+ for (i = 0; i < 12; i++) {
+ tm.tm_mon = i;
+ strftime(buf, sizeof(buf), "%b", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (nmonths[i].name != NULL)
+ free(nmonths[i].name);
+ if ((nmonths[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ nmonths[i].len = strlen(buf);
+
+ strftime(buf, sizeof(buf), "%B", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (fnmonths[i].name != NULL)
+ free(fnmonths[i].name);
+ if ((fnmonths[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ fnmonths[i].len = strlen(buf);
+ }
+}
+
+void
+settime(now)
+ time_t now;
+{
+ tp = localtime(&now);
+ if ( isleap(tp->tm_year + 1900) ) {
+ yrdays = 366;
+ cumdays = daytab[1];
+ } else {
+ yrdays = 365;
+ cumdays = daytab[0];
+ }
+ /* Friday displays Monday's events */
+ offset = tp->tm_wday == 5 ? 3 : 1;
+ header[5].iov_base = dayname;
+
+ (void) setlocale(LC_TIME, "C");
+ header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
+ (void) setlocale(LC_TIME, "");
+
+ setnnames();
+}
+
+/* convert Day[/Month][/Year] into unix time (since 1970)
+ * Day: two digits, Month: two digits, Year: digits
+ */
+time_t Mktime (dp)
+ char *dp;
+{
+ char *date;
+ time_t t;
+ int len;
+ struct tm tm;
+
+ if ((date = strdup(dp)) == NULL)
+ errx(1, "strdup failed in Mktime");
+ (void)time(&t);
+ tp = localtime(&t);
+
+ len = strlen(date);
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+ tm.tm_wday = 0;
+ tm.tm_mday = tp->tm_mday;
+ tm.tm_mon = tp->tm_mon;
+ tm.tm_year = tp->tm_year;
+
+
+ /* day */
+ *(date+2) = NULL;
+ tm.tm_mday = atoi(date);
+
+ /* month */
+ if (len >= 4) {
+ *(date+5) = NULL;
+ tm.tm_mon = atoi(date+3) - 1;
+ }
+
+ /* Year */
+ if (len >= 7) {
+ tm.tm_year = atoi(date+6);
+
+ /* tm_year up 1900 ... */
+ if (tm.tm_year > 1900)
+ tm.tm_year -= 1900;
+ }
+
+#if DEBUG
+ printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
+ asctime(&tm));
+#endif
+ free(date);
+ return(mktime(&tm));
+}
+
+/*
+ * Possible date formats include any combination of:
+ * 3-charmonth (January, Jan, Jan)
+ * 3-charweekday (Friday, Monday, mon.)
+ * numeric month or day (1, 2, 04)
+ *
+ * Any character may separate them, or they may not be separated. Any line,
+ * following a line that is matched, that starts with "whitespace", is shown
+ * along with the matched line.
+ */
+int
+isnow(endp, monthp, dayp, varp)
+ char *endp;
+ int *monthp;
+ int *dayp;
+ int *varp;
+{
+ int day, flags, month = 0, v1, v2;
+
+ /*
+ * CONVENTION
+ *
+ * Month: 1-12
+ * Monthname: Jan .. Dec
+ * Day: 1-31
+ * Weekday: Mon-Sun
+ *
+ */
+
+ flags = 0;
+
+ /* read first field */
+ /* didn't recognize anything, skip it */
+ if (!(v1 = getfield(endp, &endp, &flags)))
+ return (0);
+
+ /* Easter or Easter depending days */
+ if (flags & F_EASTER)
+ day = v1 - 1; /* days since January 1 [0-365] */
+
+ /*
+ * 1. {Weekday,Day} XYZ ...
+ *
+ * where Day is > 12
+ */
+ else if (flags & F_ISDAY || v1 > 12) {
+
+ /* found a day; day: 1-31 or weekday: 1-7 */
+ day = v1;
+
+ /* {Day,Weekday} {Month,Monthname} ... */
+ /* if no recognizable month, assume just a day alone
+ * in other words, find month or use current month */
+ if (!(month = getfield(endp, &endp, &flags)))
+ month = tp->tm_mon + 1;
+ }
+
+ /* 2. {Monthname} XYZ ... */
+ else if (flags & F_ISMONTH) {
+ month = v1;
+
+ /* Monthname {day,weekday} */
+ /* if no recognizable day, assume the first day in month */
+ if (!(day = getfield(endp, &endp, &flags)))
+ day = 1;
+ }
+
+ /* Hm ... */
+ else {
+ v2 = getfield(endp, &endp, &flags);
+
+ /*
+ * {Day} {Monthname} ...
+ * where Day <= 12
+ */
+ if (flags & F_ISMONTH) {
+ day = v1;
+ month = v2;
+ *varp = 0;
+ }
+
+ /* {Month} {Weekday,Day} ... */
+ else {
+ /* F_ISDAY set, v2 > 12, or no way to tell */
+ month = v1;
+ /* if no recognizable day, assume the first */
+ day = v2 ? v2 : 1;
+ *varp = 0;
+ }
+ }
+
+ /* convert Weekday into *next* Day,
+ * e.g.: 'Sunday' -> 22
+ * 'SunayLast' -> ??
+ */
+ if (flags & F_ISDAY) {
+#if DEBUG
+ fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
+#endif
+
+ *varp = 1;
+ /* variable weekday, SundayLast, MondayFirst ... */
+ if (day < 0 || day >= 10) {
+
+ /* negative offset; last, -4 .. -1 */
+ if (day < 0) {
+ v1 = day/10 - 1; /* offset -4 ... -1 */
+ day = 10 + (day % 10); /* day 1 ... 7 */
+
+ /* day, eg '22th' */
+ v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+
+ /* (month length - day) / 7 + 1 */
+ if (((int)((cumdays[month+1] -
+ cumdays[month] - v2) / 7) + 1) == -v1)
+ /* bingo ! */
+ day = v2;
+
+ /* set to yesterday */
+ else {
+ day = tp->tm_mday - 1;
+ if (day == 0)
+ return (0);
+ }
+ }
+
+ /* first, second ... +1 ... +5 */
+ else {
+ v1 = day/10; /* offset: +1 (first Sunday) ... */
+ day = day % 10;
+
+ /* day, eg '22th' */
+ v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+
+ /* Hurrah! matched */
+ if ( ((v2 - 1 + 7) / 7) == v1 )
+ day = v2;
+
+ /* set to yesterday */
+ else {
+ day = tp->tm_mday - 1;
+ if (day == 0)
+ return (0);
+ }
+ }
+ }
+
+ /* wired */
+ else {
+ day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+ *varp = 1;
+ }
+ }
+
+ if (!(flags & F_EASTER)) {
+ *monthp = month;
+ *dayp = day;
+ day = cumdays[month] + day;
+ }
+ else {
+ for (v1 = 0; day > cumdays[v1]; v1++)
+ ;
+ *monthp = v1 - 1;
+ *dayp = day - cumdays[v1 - 1];
+ *varp = 1;
+ }
+
+#if DEBUG
+ fprintf(stderr, "day2: day %d(%d) yday %d\n", *dayp, day, tp->tm_yday);
+#endif
+ /* if today or today + offset days */
+ if (day >= tp->tm_yday - f_dayBefore &&
+ day <= tp->tm_yday + offset + f_dayAfter)
+ return (1);
+
+ /* if number of days left in this year + days to event in next year */
+ if (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||
+ /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */
+ tp->tm_yday + day - f_dayBefore < 0
+ )
+ return (1);
+ return (0);
+}
+
+
+int
+getmonth(s)
+ register char *s;
+{
+ register char **p;
+ struct fixs *n;
+
+ for (n = fnmonths; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - fnmonths) + 1);
+ for (n = nmonths; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - nmonths) + 1);
+ for (p = months; *p; ++p)
+ if (!strncasecmp(s, *p, 3))
+ return ((p - months) + 1);
+ return (0);
+}
+
+
+int
+getday(s)
+ register char *s;
+{
+ register char **p;
+ struct fixs *n;
+
+ for (n = fndays; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - fndays) + 1);
+ for (n = ndays; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - ndays) + 1);
+ for (p = days; *p; ++p)
+ if (!strncasecmp(s, *p, 3))
+ return ((p - days) + 1);
+ return (0);
+}
+
+/* return offset for variable weekdays
+ * -1 -> last weekday in month
+ * +1 -> first weekday in month
+ * ... etc ...
+ */
+int
+getdayvar(s)
+ register char *s;
+{
+ register int offset;
+
+
+ offset = strlen(s);
+
+
+ /* Sun+1 or Wednesday-2
+ * ^ ^ */
+
+ /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
+ switch(*(s + offset - 2)) {
+ case '-':
+ return(-(atoi(s + offset - 1)));
+ break;
+ case '+':
+ return(atoi(s + offset - 1));
+ break;
+ }
+
+
+ /*
+ * some aliases: last, first, second, third, fourth
+ */
+
+ /* last */
+ if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
+ return(-1);
+ else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
+ return(+1);
+ else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
+ return(+2);
+ else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
+ return(+3);
+ else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
+ return(+4);
+
+
+ /* no offset detected */
+ return(0);
+}
diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c
new file mode 100644
index 0000000..9634dac
--- /dev/null
+++ b/usr.bin/calendar/io.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/wait.h>
+
+#include "pathnames.h"
+#include "calendar.h"
+
+
+char *calendarFile = "calendar"; /* default calendar file */
+char *calendarHome = ".calendar"; /* HOME */
+char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
+
+struct fixs neaster, npaskha;
+
+struct iovec header[] = {
+ {"From: ", 6},
+ {NULL, 0},
+ {" (Reminder Service)\nTo: ", 24},
+ {NULL, 0},
+ {"\nSubject: ", 10},
+ {NULL, 0},
+ {"'s Calendar\nPrecedence: bulk\n\n", 30},
+};
+
+
+void
+cal()
+{
+ register int printing;
+ register char *p;
+ FILE *fp;
+ int ch, l;
+ int month;
+ int day;
+ int var;
+ char buf[2048 + 1];
+
+ if ((fp = opencal()) == NULL)
+ return;
+ for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
+ if ((p = strchr(buf, '\n')) != NULL)
+ *p = '\0';
+ else
+ while ((ch = getchar()) != '\n' && ch != EOF);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (buf[0] == '\0')
+ continue;
+ if (strncmp(buf, "LANG=", 5) == 0) {
+ (void) setlocale(LC_ALL, buf + 5);
+ setnnames();
+ continue;
+ }
+ if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
+ if (neaster.name != NULL)
+ free(neaster.name);
+ if ((neaster.name = strdup(buf + 7)) == NULL)
+ errx(1, "cannot allocate memory");
+ neaster.len = strlen(buf + 7);
+ continue;
+ }
+ if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
+ if (npaskha.name != NULL)
+ free(npaskha.name);
+ if ((npaskha.name = strdup(buf + 7)) == NULL)
+ errx(1, "cannot allocate memory");
+ npaskha.len = strlen(buf + 7);
+ continue;
+ }
+ if (buf[0] != '\t') {
+ printing = isnow(buf, &month, &day, &var) ? 1 : 0;
+ if ((p = strchr(buf, '\t')) == NULL)
+ continue;
+ if (p > buf && p[-1] == '*')
+ var = 1;
+ if (printing) {
+ struct tm tm;
+ char dbuf[30];
+
+ tm.tm_sec = 0; /* unused */
+ tm.tm_min = 0; /* unused */
+ tm.tm_hour = 0; /* unused */
+ tm.tm_wday = 0; /* unused */
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_year = tp->tm_year; /* unused */
+ (void)strftime(dbuf, sizeof(dbuf), "%c", &tm);
+ dbuf[10] = '\0';
+ (void)fprintf(fp, "%s%c%s\n",
+ dbuf + 4/* skip weekdays */,
+ var ? '*' : ' ', p);
+ }
+ }
+ else if (printing)
+ fprintf(fp, "%s\n", buf);
+ }
+ closecal(fp);
+}
+
+int
+getfield(p, endp, flags)
+ char *p, **endp;
+ int *flags;
+{
+ int val, var;
+ char *start, savech;
+
+ for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) && *p != '*'; ++p);
+ if (*p == '*') { /* `*' is current month */
+ *flags |= F_ISMONTH;
+ *endp = p+1;
+ return (tp->tm_mon + 1);
+ }
+ if (isdigit((unsigned char)*p)) {
+ val = strtol(p, &p, 10); /* if 0, it's failure */
+ for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) && *p != '*'; ++p);
+ *endp = p;
+ return (val);
+ }
+ for (start = p; isalpha((unsigned char)*++p););
+
+ /* Sunday-1 */
+ if (*p == '+' || *p == '-')
+ for(; isdigit((unsigned char)*++p););
+
+ savech = *p;
+ *p = '\0';
+
+ /* Month */
+ if ((val = getmonth(start)) != 0)
+ *flags |= F_ISMONTH;
+
+ /* Day */
+ else if ((val = getday(start)) != 0) {
+ *flags |= F_ISDAY;
+
+ /* variable weekday */
+ if ((var = getdayvar(start)) != 0) {
+ if (var <=5 && var >= -4)
+ val += var * 10;
+#ifdef DEBUG
+ printf("var: %d\n", var);
+#endif
+ }
+ }
+
+ /* Easter */
+ else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
+ *flags |= F_EASTER;
+
+ /* Paskha */
+ else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0)
+ *flags |= F_EASTER;
+
+ /* undefined rest */
+ else {
+ *p = savech;
+ return (0);
+ }
+ for (*p = savech; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) && *p != '*'; ++p);
+ *endp = p;
+ return (val);
+}
+
+char path[MAXPATHLEN + 1];
+
+FILE *
+opencal()
+{
+ uid_t uid;
+ int fd, pdes[2];
+ struct stat sbuf;
+
+ /* open up calendar file as stdin */
+ if (!freopen(calendarFile, "r", stdin)) {
+ if (doall) {
+ if (chdir(calendarHome) != 0)
+ return (NULL);
+ if (stat(calendarNoMail, &sbuf) == 0)
+ return (NULL);
+ if (!freopen(calendarFile, "r", stdin))
+ return (NULL);
+ } else {
+ chdir(getenv("HOME"));
+ if (!(chdir(calendarHome) == 0 &&
+ freopen(calendarFile, "r", stdin)))
+ errx(1, "no calendar file: ``%s'' or ``~/%s/%s\n", calendarFile, calendarHome, calendarFile);
+ }
+ }
+ if (pipe(pdes) < 0)
+ return (NULL);
+ switch (vfork()) {
+ case -1: /* error */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ return (NULL);
+ case 0:
+ /* child -- stdin already setup, set stdout to pipe input */
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)dup2(pdes[1], STDOUT_FILENO);
+ (void)close(pdes[1]);
+ }
+ (void)close(pdes[0]);
+ uid = geteuid();
+ if (setuid(getuid()) < 0) {
+ warnx("first setuid failed");
+ _exit(1);
+ };
+ if (setgid(getegid()) < 0) {
+ warnx("setgid failed");
+ _exit(1);
+ }
+ if (setuid(uid) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ }
+ execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
+ warn(_PATH_CPP);
+ _exit(1);
+ }
+ /* parent -- set stdin to pipe output */
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+
+ /* not reading all calendar files, just set output to stdout */
+ if (!doall)
+ return (stdout);
+
+ /* set output to a temporary file, so if no output don't send mail */
+ (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(path)) < 0)
+ return (NULL);
+ return (fdopen(fd, "w+"));
+}
+
+void
+closecal(fp)
+ FILE *fp;
+{
+ uid_t uid;
+ struct stat sbuf;
+ int nread, pdes[2], status;
+ char buf[1024];
+
+ if (!doall)
+ return;
+
+ (void)rewind(fp);
+ if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
+ goto done;
+ if (pipe(pdes) < 0)
+ goto done;
+ switch (vfork()) {
+ case -1: /* error */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ goto done;
+ case 0:
+ /* child -- set stdin to pipe output */
+ if (pdes[0] != STDIN_FILENO) {
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ }
+ (void)close(pdes[1]);
+ uid = geteuid();
+ if (setuid(getuid()) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ };
+ if (setgid(getegid()) < 0) {
+ warnx("setgid failed");
+ _exit(1);
+ }
+ if (setuid(uid) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ }
+ execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
+ "\"Reminder Service\"", NULL);
+ warn(_PATH_SENDMAIL);
+ _exit(1);
+ }
+ /* parent -- write to pipe input */
+ (void)close(pdes[0]);
+
+ header[1].iov_base = header[3].iov_base = pw->pw_name;
+ header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
+ writev(pdes[1], header, 7);
+ while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
+ (void)write(pdes[1], buf, nread);
+ (void)close(pdes[1]);
+done: (void)fclose(fp);
+ (void)unlink(path);
+ while (wait(&status) >= 0);
+}
diff --git a/usr.bin/calendar/ostern.c b/usr.bin/calendar/ostern.c
new file mode 100644
index 0000000..2527eb0
--- /dev/null
+++ b/usr.bin/calendar/ostern.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "calendar.h"
+
+/* return year day for Easter */
+
+int easter (year)
+ int year; /* 0 ... abcd, NOT since 1900 */
+{
+
+ int e_a, e_b, e_c, e_d, e_e,e_f, e_g, e_h, e_i, e_k,
+ e_l, e_m, e_n, e_p, e_q;
+
+ /* silly, but it works */
+ e_a = year % 19;
+ e_b = year / 100;
+ e_c = year % 100;
+
+ e_d = e_b / 4;
+ e_e = e_b % 4;
+ e_f = (e_b + 8) / 25;
+ e_g = (e_b + 1 - e_f) / 3;
+ e_h = ((19 * e_a) + 15 + e_b - (e_d + e_g)) % 30;
+ e_i = e_c / 4;
+ e_k = e_c % 4;
+ e_l = (32 + 2 * e_e + 2 * e_i - (e_h + e_k)) % 7;
+ e_m = (e_a + 11 * e_h + 22 * e_l) / 451;
+ e_n = (e_h + e_l + 114 - (7 * e_m)) / 31;
+ e_p = (e_h + e_l + 114 - (7 * e_m)) % 31;
+ e_p = e_p + 1;
+
+ e_q = 31 + 28;
+
+ if (e_k == 0 && e_c != 0)
+ e_q += 1;
+
+ if (e_n == 4)
+ e_q += 31;
+
+ e_q += e_p;
+
+#if DEBUG
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", e_a , e_b , e_c , e_d , e_e , e_f , e_g , e_h , e_i , e_k , e_l , e_m , e_n , e_p , e_q);
+#endif
+
+ return (e_q);
+}
+
+/* return year day for Easter or easter depending days
+ * Match: Easter([+-][0-9]+)?
+ * e.g: Easter-2 is Good Friday (2 days before Easter)
+ */
+
+int
+geteaster(s, year)
+ char *s;
+ int year;
+{
+ register int offset = 0;
+ extern struct fixs neaster;
+
+#define EASTER "easter"
+#define EASTERNAMELEN (sizeof(EASTER) - 1)
+
+ if (strncasecmp(s, EASTER, EASTERNAMELEN) == 0)
+ s += EASTERNAMELEN;
+ else if ( neaster.name != NULL
+ && strncasecmp(s, neaster.name, neaster.len) == 0
+ )
+ s += neaster.len;
+ else
+ return(0);
+
+#if DEBUG
+ printf("%s %d %d\n", s, year, EASTERNAMELEN);
+#endif
+
+ /* Easter+1 or Easter-2
+ * ^ ^ */
+
+ switch(*s) {
+
+ case '-':
+ case '+':
+ offset = atoi(s);
+ break;
+
+ default:
+ offset = 0;
+ }
+
+ return (easter(year) + offset);
+}
diff --git a/usr.bin/calendar/paskha.c b/usr.bin/calendar/paskha.c
new file mode 100644
index 0000000..47f686f
--- /dev/null
+++ b/usr.bin/calendar/paskha.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "calendar.h"
+
+#define PASKHA "paskha"
+#define PASKHALEN (sizeof(PASKHA) - 1)
+
+/* return year day for Orthodox Easter using Gauss formula */
+/* (old style result) */
+
+static int
+paskha (R)
+int R; /*year*/
+{
+ int a, b, c, d, e;
+ static int x = 15;
+ static int y = 6;
+ extern int *cumdays;
+
+ a = R % 19;
+ b = R % 4;
+ c = R % 7;
+ d = (19*a + x) % 30;
+ e = (2*b + 4*c + 6*d + y) % 7;
+ return (((cumdays[3] + 1) + 22) + (d + e));
+}
+
+/* return year day for Orthodox Easter depending days */
+
+int
+getpaskha(s, year)
+ char *s;
+ int year;
+{
+ int offset;
+ extern struct fixs npaskha;
+
+ if (strncasecmp(s, PASKHA, PASKHALEN) == 0)
+ s += PASKHALEN;
+ else if ( npaskha.name != NULL
+ && strncasecmp(s, npaskha.name, npaskha.len) == 0
+ )
+ s += npaskha.len;
+ else
+ return 0;
+
+
+ /* Paskha+1 or Paskha-2
+ * ^ ^ */
+
+ switch(*s) {
+
+ case '-':
+ case '+':
+ offset = atoi(s);
+ break;
+
+ default:
+ offset = 0;
+ break;
+ }
+
+ return (paskha(year) + offset + 13/* new style */);
+}
diff --git a/usr.bin/calendar/pathnames.h b/usr.bin/calendar/pathnames.h
index 8a0838c..481989c 100644
--- a/usr.bin/calendar/pathnames.h
+++ b/usr.bin/calendar/pathnames.h
@@ -36,5 +36,6 @@
#include <paths.h>
#define _PATH_CPP "/usr/bin/cpp"
+
/* XXX -- fix when cpp parses arguments rationally */
#define _PATH_INCLUDE "-I/usr/share/calendar"
diff --git a/usr.bin/cap_mkdb/cap_mkdb.1 b/usr.bin/cap_mkdb/cap_mkdb.1
index b2a3900..c7e5dec 100644
--- a/usr.bin/cap_mkdb/cap_mkdb.1
+++ b/usr.bin/cap_mkdb/cap_mkdb.1
@@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)cap_mkdb.1 8.1 (Berkeley) 6/6/93
+.\" $Id: cap_mkdb.1,v 1.4 1997/02/22 19:54:19 peter Exp $
.\"
-.Dd "June 6, 1993"
+.Dd June 6, 1993
.Dt CAP_MKDB 1
.Os
.Sh NAME
@@ -63,7 +64,7 @@ than they can the original text file(s).
The ``tc'' capabilities of the records are expanded before the
record is stored into the database.
.Pp
-The options as as follows:
+The options as follows:
.Bl -tag -width XXXXXX -indent
.It Fl f Ar outfile
Specify a different database basename.
@@ -83,7 +84,7 @@ that couldn't be expanded.
.Pp
The second type is a key which consists of one of the names from the
first capability of the record with a data field consisting a special
-byte followed by the the first capability of the record.
+byte followed by the first capability of the record.
The special byte is a 2.
.Pp
In normal operation names are looked up in the database, resulting
diff --git a/usr.bin/cap_mkdb/cap_mkdb.c b/usr.bin/cap_mkdb/cap_mkdb.c
index e3c3ce5..75ba9b7 100644
--- a/usr.bin/cap_mkdb/cap_mkdb.c
+++ b/usr.bin/cap_mkdb/cap_mkdb.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)cap_mkdb.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
@@ -62,15 +62,6 @@ DB *capdbp;
int verbose;
char *capdb, *capname, buf[8 * 1024];
-HASHINFO openinfo = {
- 4096, /* bsize */
- 16, /* ffactor */
- 256, /* nelem */
- 2048 * 1024, /* cachesize */
- NULL, /* hash() */
- 0 /* lorder */
-};
-
/*
* Mkcapdb creates a capability hash database for quick retrieval of capability
* records. The database contains 2 types of entries: records and references
@@ -86,7 +77,7 @@ main(argc, argv)
int c;
capname = NULL;
- while ((c = getopt(argc, argv, "f:v")) != EOF) {
+ while ((c = getopt(argc, argv, "f:v")) != -1) {
switch(c) {
case 'f':
capname = optarg;
@@ -112,8 +103,8 @@ main(argc, argv)
(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
if ((capname = strdup(buf)) == NULL)
err(1, "");
- if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
- DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
+ if ((capdbp = dbopen(capname,
+ O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL)
err(1, "%s", buf);
if (atexit(dounlink))
diff --git a/usr.bin/chat/Example b/usr.bin/chat/Example
new file mode 100644
index 0000000..8b7d0d1
--- /dev/null
+++ b/usr.bin/chat/Example
@@ -0,0 +1,5 @@
+#
+
+../pppd/pppd -d connect 'chat "" ATDT5551212 CONNECT "" ogin: ppp' netmask 255.255.255.0 /dev/cuaa0 38400
+
+../pppd/pppd connect 'chat "" AATDT5551212 CONNECT "" ogin: ppp' netmask 255.255.255.0 /dev/cuaa0 38400
diff --git a/usr.bin/chat/Makefile b/usr.bin/chat/Makefile
new file mode 100644
index 0000000..0dd5055
--- /dev/null
+++ b/usr.bin/chat/Makefile
@@ -0,0 +1,8 @@
+# $Id$
+
+PROG= chat
+SRCS= chat.c
+MAN8= chat.8
+BINDIR?= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/chat/README b/usr.bin/chat/README
new file mode 100644
index 0000000..73d28af
--- /dev/null
+++ b/usr.bin/chat/README
@@ -0,0 +1,169 @@
+I run PPP between crappie.morningstar.com (137.175.6.3, my home
+machine) and remora.morningstar.com (137.175.2.7, my workstation at
+the office). This document describes how I use it. The installation
+of PPP itself is covered in the PPP distribution.
+
+I put a line like this in remora's /etc/passwd:
+
+ Pkarl:2y4613BDaQD3x:51:10:Karl's PPP login:/tmp:/usr/local/etc/pppstart
+
+I created a login shell script on remora called
+/usr/local/etc/pppstart:
+
+ #!/bin/sh
+ /usr/bin/mesg n
+ stty -tostop
+ exec /usr/local/etc/ppp 137.175.2.7:
+
+I use the ppp-on command to bring up a connection, and ppp-off to shut
+it down. These shell scripts, plus the unlock and fix-cua scripts and
+the source to the chat program are included. You will need to heavily
+modify these to suit your own situation, including Internet addresses,
+machine names, telephone numbers, modem dialing commands, baud rates,
+login names and passwords. Make the "ppp..." command in the ppp-on
+script look something like this:
+
+ ppp 137.175.6.3: /dev/cua &
+
+The "137.175.6.3:" is of the format "local-addr:remote-addr" with the
+remote address null (it will be negotiated by PPP). Look at the login
+shell script above; it can be common to all dial-in PPP users on your
+machine because it only specifies the address of the remora
+(receiving) end of the link.
+
+If you use the enclosed chat and unlock programs, be sure they are
+suid uucp, and fix-cua should be suid root. The ppp-on script should
+be chmod 700, owner yourself, to keep the password (semi-) secure.
+
+I use the following eeprom settings and /dev and /etc/ttytab entries
+in order to support dial-in and dial-out on a single phone line:
+
+ crappie 12% eeprom | grep ttya
+ ttya-mode=19200,8,1,n,h
+ ttya-rts-dtr-off=false
+ ttya-ignore-cd=false
+ crappie 13% ls -lg /dev/cua /dev/ttya
+ crw-rw-rw- 1 root staff 12, 128 Nov 20 09:14 /dev/cua
+ crw--w--w- 1 root wheel 12, 0 Nov 20 08:25 /dev/ttya
+ crappie 14% grep ttya /etc/ttytab
+ ttya "/usr/etc/getty std.19200" unknown on
+ crappie 15%
+
+On SunOS 4.1 and later, make sure that the /etc/ttytab line for ttya
+doesn't say "local":
+
+ ttya "/usr/etc/getty std.38400" unknown on
+
+Make sure your modem passes data transparently; watch out especially
+for ^S, ^Q, ^P (UUCP spoofing) and parity problems. I have a Telebit
+Trailblazer+ attached to /dev/ttya with the following register
+settings:
+
+ aaatz
+ OK
+ aat&n
+ E1 F1 M1 Q6 P V1 X0 Version BA4.00
+ S00=001 S01=000 S02=043 S03=013 S04=010 S05=008 S06=002 S07=060 S08=002 S09=006
+ S10=007 S11=070 S12=050
+ S45=000 S47=004 S48=000 S49=000
+ S50=000 S51=005 S52=002 S53=003 S54=001 S55=000 S56=017 S57=019 S58=002 S59=000
+ S60=000 S61=000 S62=003 S63=001 S64=000 S65=000 S66=001 S67=000 S68=255
+ S90=000 S91=000 S92=001 S95=000
+ S100=000 S101=000 S102=000 S104=000
+ S110=001 S111=030 S112=001
+ S121=000
+ N0:
+ N1:
+ N2:
+ N3:
+ N4:
+ N5:
+ N6:
+ N7:
+ N8:
+ N9:
+ OK
+
+And, the following entry is in /etc/gettytab:
+
+ #
+ # 19200/2400 dialin for Telebit Trailblazer+ modem
+ #
+ T|T19200:dial-19200:\
+ :nx=T2400:sp#19200:
+ T2400|dial-2400:\
+ :nx=T19200:sp#2400:
+
+My chat script dialing command looks like "ATs50=255s111=0DT4515678"
+instead of just "ATDT4515678" in order to force a PEP mode connection
+and to disable the UUCP spoofing (otherwise, the modem swallows or
+delays ^P characters).
+
+I run /usr/etc/in.routed on crappie (the calling end) and have this in
+my /etc/gateways file:
+
+ net 0.0.0.0 gateway remora metric 1 passive
+ host crappie gateway crappie metric 0 passive
+
+Routed is started in /etc/rc.local. This way, I don't have to
+manually add or delete routes when links come up. I ifconfig the ppp0
+interface on crappie at boot time like this (in /etc/rc.local with the
+other ifconfig's):
+
+ ifconfig ppp0 crappie remora netmask 0xffffff00 down
+
+I put "init ppp_attach" in my /sys/sun4c/conf/CRAPPIE file so that the
+above ifconfig down will work:
+
+ pseudo-device ppp1 init ppp_attach # Point-to-Point Protocol, 1 line
+
+Routed now keeps my routes sane at the crappie.MorningStar.Com end.
+
+My ethernet (le0) and PPP (ppp0) interfaces are configured with the
+same address and netmask. IP is smart enough to figure out (via the
+routes in /etc/gateways) that everything useful needs to go out ppp0.
+Also, the remora end of my PPP link is configured the same way -- the
+ppp0 interface there is configured with the same address and netmask
+as remora's le0 ethernet. This means that separate interface names
+like "remora-ppp" are not needed; point-to-point links (whether PPP,
+Xerox Synchronous Point-to-Point Protocol, SLIP, IGP or whatever) have
+(apparently) been used this (seemingly bizarre) way for some time.
+This works because when IP looks at a POINTOPOINT link it ignores the
+local address (unlike an ethernet interface) and only looks at the
+remote address.
+
+Here's what netstat shows for me:
+
+ crappie 109% netstat -r
+ Routing tables
+ Destination Gateway Flags Refcnt Use Interface
+ localhost localhost UH 0 0 lo0
+ crappie crappie UH 1 11339 le0
+ default remora UG 0 1266 ppp0
+ mstar-net-ppp-remora crappie U 0 0 le0
+ crappie 110% netstat -rn
+ Routing tables
+ Destination Gateway Flags Refcnt Use Interface
+ 127.0.0.1 127.0.0.1 UH 0 0 lo0
+ 137.175.6.3 137.175.6.3 UH 1 11339 le0
+ default 137.175.2.7 UG 0 1266 ppp0
+ 137.175.6.0 137.175.6.3 U 0 0 le0
+ crappie 111%
+
+The default route to remora is a result of the first line in the
+/etc/gateways file ("default" can't be used there; you have to say
+"0.0.0.0").
+
+On the network at work, I add a static route in our gateway machine's
+/etc/rc.local file:
+
+ /usr/etc/route add net 137.175.6 remora 1
+
+All the other machines in the office have default routes pointing at
+the gateway machine, and all PPP-connected external machines are on the
+137.175.6 subnet.
+
+Send me mail or post to the newsgroup comp.protocols.ppp if you have
+any questions.
+
+Karl Fox <karl@MorningStar.Com>
diff --git a/usr.bin/chat/chat.8 b/usr.bin/chat/chat.8
new file mode 100644
index 0000000..48ed7c8
--- /dev/null
+++ b/usr.bin/chat/chat.8
@@ -0,0 +1,315 @@
+.\" -*- nroff -*-
+.\" manual page [] for chat 1.8
+.\" $Id$
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH CHAT 8 "5 May 1995" "Chat Version 1.9"
+.SH NAME
+chat \- Automated conversational script with a modem
+.SH SYNOPSIS
+.B chat
+[
+.I options
+]
+.I script
+.SH DESCRIPTION
+.LP
+The \fIchat\fR program defines a conversational exchange between the
+computer and the modem. Its primary purpose is to establish the
+connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and
+the remote's \fIpppd\fR process.
+.SH OPTIONS
+.TP
+.B -f \fI<chat file>
+Read the chat script from the chat \fIfile\fR. The use of this option
+is mutually exclusive with the chat script parameters. The user must
+have read access to the file. Multiple lines are permitted in the
+file. Space or horizontal tab characters should be used to separate
+the strings.
+.TP
+.B -t \fI<timeout>
+Set the timeout for the expected string to be received. If the string
+is not received within the time limit then the reply string is not
+sent. An alternate reply may be sent or the script will fail if there
+is no alternate reply string. A failed script will cause the
+\fIchat\fR program to terminate with a non-zero error code.
+.TP
+.B -r \fI<report file>
+Set the file for output of the report strings. If you use the keyword
+\fIREPORT\fR, the resulting strings are written to this file. If this
+option is not used and you still use \fIREPORT\fR keywords, the
+\fIstderr\fR file is used for the report strings.
+.TP
+.B -v
+Request that the \fIchat\fR script be executed in a verbose mode. The
+\fIchat\fR program will then log all text received from the modem and
+the output strings which it sends to
+.IR syslogd (8).
+Logging is
+done to the \fIlocal2\fR facility at level \fIinfo\fR for verbose tracing
+and level \fIerr\fR for some errors.
+.TP
+.B script
+If the script is not specified in a file with the \fI-f\fR option then
+the script is included as parameters to the \fIchat\fR program.
+.SH CHAT SCRIPT
+.LP
+The \fIchat\fR script defines the communications.
+.LP
+A script consists of one or more "expect-send" pairs of strings,
+separated by spaces, with an optional "subexpect-subsend" string pair,
+separated by a dash as in the following example:
+.IP
+ogin:-BREAK-ogin: ppp ssword: hello2u2
+.LP
+This line indicates that the \fIchat\fR program should expect the string
+"ogin:". If it fails to receive a login prompt within the time interval
+allotted, it is to send a break sequence to the remote and then expect the
+string "ogin:". If the first "ogin:" is received then the break sequence is
+not generated.
+.LP
+Once it received the login prompt the \fIchat\fR program will send the
+string ppp and then expect the prompt "ssword:". When it receives the
+prompt for the password, it will send the password hello2u2.
+.LP
+A carriage return is normally sent following the reply string. It is not
+expected in the "expect" string unless it is specifically requested by using
+the \\r character sequence.
+.LP
+The expect sequence should contain only what is needed to identify the
+string. Since it is normally stored on a disk file, it should not contain
+variable information. It is generally not acceptable to look for time
+strings, network identification strings, or other variable pieces of data as
+an expect string.
+.LP
+To help correct for characters which may be corrupted during the initial
+sequence, look for the string "ogin:" rather than "login:". It is possible
+that the leading "l" character may be received in error and you may never
+find the string even though it was sent by the system. For this reason,
+scripts look for "ogin:" rather than "login:" and "ssword:" rather than
+"password:".
+.LP
+A very simple script might look like this:
+.IP
+ogin: ppp ssword: hello2u2
+.LP
+In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2.
+.LP
+In actual practice, simple scripts are rare. At the vary least, you
+should include sub-expect sequences should the original string not be
+received. For example, consider the following script:
+.IP
+ogin:--ogin: ppp ssword: hello2u2
+.LP
+This would be a better script than the simple one used earlier. This would look
+for the same login: prompt, however, if one was not received, a single
+return sequence is sent and then it will look for login: again. Should line
+noise obscure the first login prompt then sending the empty line will
+usually generate a login prompt again.
+.SH ABORT STRINGS
+Many modems will report the status of the call as a string. These
+strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It
+is often desirable to terminate the script should the modem fail to
+connect to the remote. The difficulty is that a script would not know
+exactly which modem string it may receive. On one attempt, it may
+receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR.
+.LP
+These "abort" strings may be specified in the script using the \fIABORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT
+.LP
+This sequence will expect nothing; and then send the string ATZ. The
+expected response to this is the string \fIOK\fR. When it receives \fIOK\fR,
+the string ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the
+script is executed. However, should the modem find a busy telephone, it will
+send the string \fIBUSY\fR. This will cause the string to match the abort
+character sequence. The script will then fail because it found a match to
+the abort string. If it received the string \fINO CARRIER\fR, it will abort
+for the same reason. Either string may be received. Either string will
+terminate the \fIchat\fR script.
+
+.SH REPORT STRINGS
+A \fBreport\fR string is similar to the ABORT string. The difference
+is that the strings, and all characters to the next control character
+such as a carriage return, are written to the report file.
+.LP
+The report strings may be used to isolate the transmission rate of the
+modem's connect string and return the value to the chat user. The
+analysis of the report string logic occurs in conjunction with the
+other string processing such as looking for the expect string. The use
+of the same string for a report and abort sequence is probably not
+very useful, however, it is possible.
+.LP
+The report strings to no change the completion code of the program.
+.LP
+These "report" strings may be specified in the script using the \fIREPORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account
+.LP
+This sequence will expect nothing; and then send the string
+ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder
+of the script is executed. In addition the program will write to the
+expect-file the string "CONNECT" plus any characters which follow it
+such as the connection rate.
+.SH TIMEOUT
+The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR
+parameter.
+.LP
+To change the timeout value for the next expect string, the following
+example may be used:
+.IP
+ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assword: hello2u2
+.LP
+This will change the timeout to 10 seconds when it expects the login:
+prompt. The timeout is then changed to 5 seconds when it looks for the
+password prompt.
+.LP
+The timeout, once changed, remains in effect until it is changed again.
+.SH SENDING EOT
+The special reply string of \fIEOT\fR indicates that the chat program
+should send an EOT character to the remote. This is normally the
+End-of-file character sequence. A return character is not sent
+following the EOT.
+.PR
+The EOT sequence may be embedded into the send string using the
+sequence \fI^D\fR.
+.SH GENERATING BREAK
+The special reply string of \fIBREAK\fR will cause a break condition
+to be sent. The break is a special signal on the transmitter. The
+normal processing on the receiver is to change the transmission rate.
+It may be used to cycle through the available transmission rates on
+the remote until you are able to receive a valid login prompt.
+.PR
+The break sequence may be embedded into the send string using the
+\fI\\K\fR sequence.
+.SH ESCAPE SEQUENCES
+The expect and reply strings may contain escape sequences. All of the
+sequences are legal in the reply string. Many are legal in the expect.
+Those which are not valid in the expect sequence are so indicated.
+.TP
+.B ''
+Expects or sends a null string. If you send a null string then it will still
+send the return character. This sequence may either be a pair of apostrophe
+or quote characters.
+.TP
+.B \\\\b
+represents a backspace character.
+.TP
+.B \\\\c
+Suppresses the newline at the end of the reply string. This is the only
+method to send a string without a trailing return character. It must
+be at the end of the send string. For example,
+the sequence hello\\c will simply send the characters h, e, l, l, o.
+.I (not valid in expect.)
+.TP
+.B \\\\d
+Delay for one second. The program uses sleep(1) which will delay to a
+maximum of one second.
+.I (not valid in expect.)
+.TP
+.B \\\\K
+Insert a BREAK
+.I (not valid in expect.)
+.TP
+.B \\\\n
+Send a newline or linefeed character.
+.TP
+.B \\\\N
+Send a null character. The same sequence may be represented by \\0.
+.I (not valid in expect.)
+.TP
+.B \\\\p
+Pause for a fraction of a second. The delay is 1/10th of a second.
+.I (not valid in expect.)
+.TP
+.B \\\\q
+Suppress writing the string to
+.IR syslogd (8).
+The string ?????? is
+written to the log in its place.
+.I (not valid in expect.)
+.TP
+.B \\\\r
+Send or expect a carriage return.
+.TP
+.B \\\\s
+Represents a space character in the string. This may be used when it
+is not desirable to quote the strings which contains spaces. The
+sequence 'HI TIM' and HI\\sTIM are the same.
+.TP
+.B \\\\t
+Send or expect a tab character.
+.TP
+.B \\\\\\\\
+Send or expect a backslash character.
+.TP
+.B \\\\ddd
+Collapse the octal digits (ddd) into a single ASCII character and send that
+character.
+.I (some characters are not valid in expect.)
+.TP
+.B \^^C
+Substitute the sequence with the control character represented by C.
+For example, the character DC1 (17) is shown as \^^Q.
+.I (some characters are not valid in expect.)
+.SH TERMINATION CODES
+The \fIchat\fR program will terminate with the following completion
+codes.
+.TP
+.B 0
+The normal termination of the program. This indicates that the script
+was executed without error to the normal conclusion.
+.TP
+.B 1
+One or more of the parameters are invalid or an expect string was too
+large for the internal buffers. This indicates that the program as not
+properly executed.
+.TP
+.B 2
+An error occurred during the execution of the program. This may be due
+to a read or write operation failing for some reason or chat receiving
+a signal such as SIGINT.
+.TP
+.B 3
+A timeout event occurred when there was an \fIexpect\fR string without
+having a "-subsend" string. This may mean that you did not program the
+script correctly for the condition or that some unexpected event has
+occurred and the expected string could not be found.
+.TP
+.B 4
+The first string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 5
+The second string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 6
+The third string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 7
+The fourth string marked as an \fIABORT\fR condition occurred.
+.TP
+.B ...
+The other termination codes are also strings marked as an \fIABORT\fR
+condition.
+.LP
+Using the termination code, it is possible to determine which event
+terminated the script. It is possible to decide if the string "BUSY"
+was received from the modem as opposed to "NO DIAL TONE". While the
+first event may be retried, the second will probably have little
+chance of succeeding during a retry.
+.SH SEE ALSO
+Additional information about \fIchat\fR scripts may be found with UUCP
+documentation. The \fIchat\fR script was taken from the ideas proposed
+by the scripts used by the \fIuucico\fR program.
+.LP
+uucico(1), uucp(1)
+.SH COPYRIGHT
+The \fIchat\fR program is in public domain. This is not the GNU public
+license. If it breaks then you get to keep both pieces.
diff --git a/usr.bin/chat/chat.c b/usr.bin/chat/chat.c
new file mode 100644
index 0000000..9f70bc6
--- /dev/null
+++ b/usr.bin/chat/chat.c
@@ -0,0 +1,1348 @@
+/*
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * Standard termination codes:
+ * 0 - successful completion of the script
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condtion.
+ * 3 - timeout waiting for a simple string.
+ * 4 - the first string declared as "ABORT"
+ * 5 - the second string declared as "ABORT"
+ * 6 - ... and so on for successive ABORT strings.
+ *
+ * This software is in the public domain.
+ *
+ * Please send all bug reports, requests for information, etc. to:
+ *
+ * Al Longyear (longyear@netcom.com)
+ * (I was the last person to change this code.)
+ *
+ * Added -r "report file" switch & REPORT keyword.
+ * Robert Geer <bgeer@xmission.com>
+ *
+ * The original author is:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ */
+
+static char rcsid[] = "$Id: chat.c,v 1.7 1997/04/02 09:55:26 jmg Exp $";
+
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#ifndef TERMIO
+#undef TERMIOS
+#define TERMIOS
+#endif
+
+#ifdef TERMIO
+#include <termio.h>
+#endif
+#ifdef TERMIOS
+#include <termios.h>
+#endif
+
+#define STR_LEN 1024
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+#ifdef __STDC__
+#undef __P
+#define __P(x) x
+#else
+#define __P(x) ()
+#define const
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+/*************** Micro getopt() *********************************************/
+#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
+ (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
+ &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
+#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
+ (_O=4,(char*)0):(char*)0)
+#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
+#define ARG(c,v) (c?(--c,*v++):(char*)0)
+
+static int _O = 0; /* Internal state */
+/*************** Micro getopt() *********************************************/
+
+#define MAX_ABORTS 50
+#define MAX_REPORTS 50
+#define DEFAULT_CHAT_TIMEOUT 45
+
+int verbose = 0;
+int quiet = 0;
+int report = 0;
+int exit_code = 0;
+FILE* report_fp = (FILE *) 0;
+char *report_file = (char *) 0;
+char *chat_file = (char *) 0;
+int timeout = DEFAULT_CHAT_TIMEOUT;
+
+int have_tty_parameters = 0;
+
+#ifdef TERMIO
+#define term_parms struct termio
+#define get_term_param(param) ioctl(0, TCGETA, param)
+#define set_term_param(param) ioctl(0, TCSETA, param)
+struct termio saved_tty_parameters;
+#endif
+
+#ifdef TERMIOS
+#define term_parms struct termios
+#define get_term_param(param) tcgetattr(0, param)
+#define set_term_param(param) tcsetattr(0, TCSANOW, param)
+struct termios saved_tty_parameters;
+#endif
+
+char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
+ fail_buffer[50];
+int n_aborts = 0, abort_next = 0, timeout_next = 0;
+
+char *report_string[MAX_REPORTS] ;
+char report_buffer[50] ;
+int n_reports = 0, report_next = 0, report_gathering = 0 ;
+
+void *dup_mem __P((void *b, size_t c));
+void *copy_of __P((char *s));
+static void usage __P((void));
+void logf __P((const char *str));
+void logflush __P((void));
+void fatal __P((const char *msg));
+void sysfatal __P((const char *msg));
+SIGTYPE sigalrm __P((int signo));
+SIGTYPE sigint __P((int signo));
+SIGTYPE sigterm __P((int signo));
+SIGTYPE sighup __P((int signo));
+void unalarm __P((void));
+void init __P((void));
+void set_tty_parameters __P((void));
+void break_sequence __P((void));
+void terminate __P((int status));
+void do_file __P((char *chat_file));
+int get_string __P((register char *string));
+int put_string __P((register char *s));
+int write_char __P((int c));
+int put_char __P((int c));
+int get_char __P((void));
+void chat_send __P((register char *s));
+char *character __P((int c));
+void chat_expect __P((register char *s));
+char *clean __P((register char *s, int sending));
+void break_sequence __P((void));
+void terminate __P((int status));
+void die __P((void));
+
+void *dup_mem(b, c)
+void *b;
+size_t c;
+ {
+ void *ans = malloc (c);
+ if (!ans)
+ {
+ fatal ("memory error!\n");
+ }
+ memcpy (ans, b, c);
+ return ans;
+ }
+
+void *copy_of (s)
+char *s;
+ {
+ return dup_mem (s, strlen (s) + 1);
+ }
+
+/*
+ * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \
+ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
+ *
+ * Perform a UUCP-dialer-like chat script on stdin and stdout.
+ */
+int
+main(argc, argv)
+int argc;
+char **argv;
+ {
+ int option;
+ char *arg;
+
+ tzset();
+
+ while (option = OPTION(argc, argv))
+ {
+ switch (option)
+ {
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'f':
+ if (arg = OPTARG(argc, argv))
+ {
+ chat_file = copy_of(arg);
+ }
+ else
+ {
+ usage();
+ }
+ break;
+
+ case 't':
+ if (arg = OPTARG(argc, argv))
+ {
+ timeout = atoi(arg);
+ }
+ else
+ {
+ usage();
+ }
+ break;
+
+ case 'r':
+ arg = OPTARG (argc, argv);
+ if (arg)
+ {
+ if (report_fp != NULL)
+ {
+ fclose (report_fp);
+ }
+ report_file = copy_of (arg);
+ report_fp = fopen (report_file, "a");
+ if (report_fp != NULL)
+ {
+ if (verbose)
+ {
+ fprintf (report_fp, "Opening \"%s\"...\n",
+ report_file);
+ }
+ report = 1;
+ }
+ }
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+/*
+ * Default the report file to the stderr location
+ */
+ if (report_fp == NULL)
+ {
+ report_fp = stderr;
+ }
+
+#ifdef ultrix
+ openlog("chat", LOG_PID);
+#else
+ openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
+
+ if (verbose)
+ {
+ setlogmask(LOG_UPTO(LOG_INFO));
+ }
+ else
+ {
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ }
+#endif
+
+ init();
+
+ if (chat_file != NULL)
+ {
+ arg = ARG(argc, argv);
+ if (arg != NULL)
+ {
+ usage();
+ }
+ else
+ {
+ do_file (chat_file);
+ }
+ }
+ else
+ {
+ while (arg = ARG(argc, argv))
+ {
+ chat_expect(arg);
+
+ if (arg = ARG(argc, argv))
+ {
+ chat_send(arg);
+ }
+ }
+ }
+
+ terminate(0);
+ }
+
+/*
+ * Process a chat script when read from a file.
+ */
+
+void do_file (chat_file)
+char *chat_file;
+ {
+ int linect, len, sendflg;
+ char *sp, *arg, quote;
+ char buf [STR_LEN];
+ FILE *cfp;
+
+ cfp = fopen (chat_file, "r");
+ if (cfp == NULL)
+ {
+ syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
+ terminate (1);
+ }
+
+ linect = 0;
+ sendflg = 0;
+
+ while (fgets(buf, STR_LEN, cfp) != NULL)
+ {
+ sp = strchr (buf, '\n');
+ if (sp)
+ {
+ *sp = '\0';
+ }
+
+ linect++;
+ sp = buf;
+ while (*sp != '\0')
+ {
+ if (*sp == ' ' || *sp == '\t')
+ {
+ ++sp;
+ continue;
+ }
+
+ if (*sp == '"' || *sp == '\'')
+ {
+ quote = *sp++;
+ arg = sp;
+ while (*sp != quote)
+ {
+ if (*sp == '\0')
+ {
+ syslog (LOG_ERR, "unterminated quote (line %d)",
+ linect);
+ terminate (1);
+ }
+
+ if (*sp++ == '\\')
+ {
+ if (*sp != '\0')
+ {
+ ++sp;
+ }
+ }
+ }
+ }
+ else
+ {
+ arg = sp;
+ while (*sp != '\0' && *sp != ' ' && *sp != '\t')
+ {
+ ++sp;
+ }
+ }
+
+ if (*sp != '\0')
+ {
+ *sp++ = '\0';
+ }
+
+ if (sendflg)
+ {
+ chat_send (arg);
+ }
+ else
+ {
+ chat_expect (arg);
+ }
+ sendflg = !sendflg;
+ }
+ }
+ fclose (cfp);
+ }
+
+/*
+ * We got an error parsing the command line.
+ */
+static void
+usage()
+ {
+ fprintf(stderr, "%s %s\n",
+ "usage: chat [-v] [-t timeout] [-r report-file]",
+ "{-f chat-file | chat-script}");
+ exit(1);
+ }
+
+char line[256];
+char *p;
+
+void logf (str)
+const char *str;
+ {
+ p = line + strlen(line);
+ strcat (p, str);
+
+ if (str[strlen(str)-1] == '\n')
+ {
+ syslog (LOG_INFO, "%s", line);
+ line[0] = 0;
+ }
+ }
+
+void logflush()
+ {
+ if (line[0] != 0)
+ {
+ syslog(LOG_INFO, "%s", line);
+ line[0] = 0;
+ }
+ }
+
+/*
+ * Terminate with an error.
+ */
+void die()
+ {
+ terminate(1);
+ }
+
+/*
+ * Print an error message and terminate.
+ */
+
+void fatal (msg)
+const char *msg;
+ {
+ syslog(LOG_ERR, "%s", msg);
+ terminate(2);
+ }
+
+/*
+ * Print an error message along with the system error message and
+ * terminate.
+ */
+
+void sysfatal (msg)
+const char *msg;
+ {
+ syslog(LOG_ERR, "%s: %m", msg);
+ terminate(2);
+ }
+
+int alarmed = 0;
+
+SIGTYPE sigalrm(signo)
+int signo;
+ {
+ int flags;
+
+ alarm(1);
+ alarmed = 1; /* Reset alarm to avoid race window */
+ signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
+
+ logflush();
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ if (verbose)
+ {
+ syslog(LOG_INFO, "alarm");
+ }
+ }
+
+void unalarm()
+ {
+ int flags;
+
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+ }
+
+SIGTYPE sigint(signo)
+int signo;
+ {
+ fatal("SIGINT");
+ }
+
+SIGTYPE sigterm(signo)
+int signo;
+ {
+ fatal("SIGTERM");
+ }
+
+SIGTYPE sighup(signo)
+int signo;
+ {
+ fatal("SIGHUP");
+ }
+
+void init()
+ {
+ signal(SIGINT, sigint);
+ signal(SIGTERM, sigterm);
+ signal(SIGHUP, sighup);
+
+ set_tty_parameters();
+ signal(SIGALRM, sigalrm);
+ alarm(0);
+ alarmed = 0;
+ }
+
+void set_tty_parameters()
+ {
+#if defined(get_term_param)
+ term_parms t;
+
+ if (get_term_param (&t) < 0)
+ {
+ have_tty_parameters = 0;
+ return;
+ }
+
+ saved_tty_parameters = t;
+ have_tty_parameters = 1;
+
+ t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
+ t.c_oflag = 0;
+ t.c_lflag = 0;
+ t.c_cc[VERASE] =
+ t.c_cc[VKILL] = 0;
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+
+ if (set_term_param (&t) < 0)
+ {
+ sysfatal("Can't set terminal parameters");
+ }
+#endif
+ }
+
+void break_sequence()
+ {
+#ifdef TERMIOS
+ tcsendbreak (0, 0);
+#endif
+ }
+
+void terminate(status)
+int status;
+ {
+ if (report_file != (char *) 0 && report_fp != (FILE *) NULL)
+ {
+ if (verbose)
+ {
+ fprintf (report_fp, "Closing \"%s\".\n", report_file);
+ }
+ fclose (report_fp);
+ report_fp = (FILE*) NULL;
+ }
+
+#if defined(get_term_param)
+ if (have_tty_parameters)
+ {
+ if (set_term_param (&saved_tty_parameters) < 0)
+ {
+ syslog(LOG_ERR, "Can't restore terminal parameters: %m");
+ exit(1);
+ }
+ }
+#endif
+
+ exit(status);
+ }
+
+/*
+ * 'Clean up' this string.
+ */
+char *clean(s, sending)
+register char *s;
+int sending;
+ {
+ char temp[STR_LEN], cur_chr;
+ register char *s1;
+ int add_return = sending;
+#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
+
+ s1 = temp;
+ while (*s)
+ {
+ cur_chr = *s++;
+ if (cur_chr == '^')
+ {
+ cur_chr = *s++;
+ if (cur_chr == '\0')
+ {
+ *s1++ = '^';
+ break;
+ }
+ cur_chr &= 0x1F;
+ if (cur_chr != 0)
+ {
+ *s1++ = cur_chr;
+ }
+ continue;
+ }
+
+ if (cur_chr != '\\')
+ {
+ *s1++ = cur_chr;
+ continue;
+ }
+
+ cur_chr = *s++;
+ if (cur_chr == '\0')
+ {
+ if (sending)
+ {
+ *s1++ = '\\';
+ *s1++ = '\\';
+ }
+ break;
+ }
+
+ switch (cur_chr)
+ {
+ case 'b':
+ *s1++ = '\b';
+ break;
+
+ case 'c':
+ if (sending && *s == '\0')
+ {
+ add_return = 0;
+ }
+ else
+ {
+ *s1++ = cur_chr;
+ }
+ break;
+
+ case '\\':
+ case 'K':
+ case 'p':
+ case 'd':
+ if (sending)
+ {
+ *s1++ = '\\';
+ }
+
+ *s1++ = cur_chr;
+ break;
+
+ case 'q':
+ quiet = ! quiet;
+ break;
+
+ case 'r':
+ *s1++ = '\r';
+ break;
+
+ case 'n':
+ *s1++ = '\n';
+ break;
+
+ case 's':
+ *s1++ = ' ';
+ break;
+
+ case 't':
+ *s1++ = '\t';
+ break;
+
+ case 'N':
+ if (sending)
+ {
+ *s1++ = '\\';
+ *s1++ = '\0';
+ }
+ else
+ {
+ *s1++ = 'N';
+ }
+ break;
+
+ default:
+ if (isoctal (cur_chr))
+ {
+ cur_chr &= 0x07;
+ if (isoctal (*s))
+ {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ if (isoctal (*s))
+ {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ }
+ }
+
+ if (cur_chr != 0 || sending)
+ {
+ if (sending && (cur_chr == '\\' || cur_chr == 0))
+ {
+ *s1++ = '\\';
+ }
+ *s1++ = cur_chr;
+ }
+ break;
+ }
+
+ if (sending)
+ {
+ *s1++ = '\\';
+ }
+ *s1++ = cur_chr;
+ break;
+ }
+ }
+
+ if (add_return)
+ {
+ *s1++ = '\r';
+ }
+
+ *s1++ = '\0'; /* guarantee closure */
+ *s1++ = '\0'; /* terminate the string */
+ return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+ }
+
+/*
+ * Process the expect string
+ */
+void chat_expect(s)
+register char *s;
+ {
+ if (strcmp(s, "ABORT") == 0)
+ {
+ ++abort_next;
+ return;
+ }
+
+ if (strcmp(s, "REPORT") == 0)
+ {
+ ++report_next;
+ return;
+ }
+
+ if (strcmp(s, "TIMEOUT") == 0)
+ {
+ ++timeout_next;
+ return;
+ }
+
+ while (*s)
+ {
+ register char *hyphen;
+
+ for (hyphen = s; *hyphen; ++hyphen)
+ {
+ if (*hyphen == '-')
+ {
+ if (hyphen == s || hyphen[-1] != '\\')
+ {
+ break;
+ }
+ }
+ }
+
+ if (*hyphen == '-')
+ {
+ *hyphen = '\0';
+
+ if (get_string(s))
+ {
+ return;
+ }
+ else
+ {
+ s = hyphen + 1;
+
+ for (hyphen = s; *hyphen; ++hyphen)
+ {
+ if (*hyphen == '-')
+ {
+ if (hyphen == s || hyphen[-1] != '\\')
+ {
+ break;
+ }
+ }
+ }
+
+ if (*hyphen == '-')
+ {
+ *hyphen = '\0';
+
+ chat_send(s);
+ s = hyphen + 1;
+ }
+ else
+ {
+ chat_send(s);
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (get_string(s))
+ {
+ return;
+ }
+ else
+ {
+ if (fail_reason)
+ {
+ syslog(LOG_INFO, "Failed (%s)", fail_reason);
+ }
+ else
+ {
+ syslog(LOG_INFO, "Failed");
+ }
+
+ terminate(exit_code);
+ }
+ }
+ }
+ }
+
+char *character(c)
+int c;
+ {
+ static char string[10];
+ char *meta;
+
+ meta = (c & 0x80) ? "M-" : "";
+ c &= 0x7F;
+
+ if (c < 32)
+ {
+ sprintf(string, "%s^%c", meta, (int)c + '@');
+ }
+ else
+ {
+ if (c == 127)
+ {
+ sprintf(string, "%s^?", meta);
+ }
+ else
+ {
+ sprintf(string, "%s%c", meta, c);
+ }
+ }
+
+ return (string);
+ }
+
+/*
+ * process the reply string
+ */
+void chat_send (s)
+register char *s;
+ {
+ if (abort_next)
+ {
+ char *s1;
+
+ abort_next = 0;
+
+ if (n_aborts >= MAX_ABORTS)
+ {
+ fatal("Too many ABORT strings");
+ }
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
+ {
+ syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
+ die();
+ }
+
+ abort_string[n_aborts++] = s1;
+
+ if (verbose)
+ {
+ logf("abort on (");
+
+ for (s1 = s; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+
+ logf(")\n");
+ }
+ return;
+ }
+
+ if (report_next)
+ {
+ char *s1;
+
+ report_next = 0;
+ if (n_reports >= MAX_REPORTS)
+ {
+ fatal("Too many REPORT strings");
+ }
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ {
+ syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s);
+ die();
+ }
+
+ report_string[n_reports++] = s1;
+
+ if (verbose)
+ {
+ logf("report (");
+ s1 = s;
+ while (*s1)
+ {
+ logf(character(*s1));
+ ++s1;
+ }
+ logf(")\n");
+ }
+ return;
+ }
+
+ if (timeout_next)
+ {
+ timeout_next = 0;
+ timeout = atoi(s);
+
+ if (timeout <= 0)
+ {
+ timeout = DEFAULT_CHAT_TIMEOUT;
+ }
+
+ if (verbose)
+ {
+ syslog(LOG_INFO, "timeout set to %d seconds", timeout);
+ }
+ return;
+ }
+
+ if (strcmp(s, "EOT") == 0)
+ {
+ s = "^D\\c";
+ }
+ else
+ {
+ if (strcmp(s, "BREAK") == 0)
+ {
+ s = "\\K\\c";
+ }
+ }
+
+ if (!put_string(s))
+ {
+ syslog(LOG_INFO, "Failed");
+ terminate(1);
+ }
+ }
+
+int get_char()
+ {
+ int status;
+ char c;
+
+ status = read(0, &c, 1);
+
+ switch (status)
+ {
+ case 1:
+ return ((int)c & 0x7F);
+
+ default:
+ syslog(LOG_WARNING, "warning: read() on stdin returned %d",
+ status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ return (-1);
+ }
+ }
+
+int put_char(c)
+int c;
+ {
+ int status;
+ char ch = c;
+
+ usleep(10000); /* inter-character typing delay (?) */
+
+ status = write(1, &ch, 1);
+
+ switch (status)
+ {
+ case 1:
+ return (0);
+
+ default:
+ syslog(LOG_WARNING, "warning: write() on stdout returned %d",
+ status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ return (-1);
+ }
+ }
+
+int write_char (c)
+int c;
+ {
+ if (alarmed || put_char(c) < 0)
+ {
+ extern int errno;
+
+ alarm(0);
+ alarmed = 0;
+
+ if (verbose)
+ {
+ if (errno == EINTR || errno == EWOULDBLOCK)
+ {
+ syslog(LOG_INFO, " -- write timed out");
+ }
+ else
+ {
+ syslog(LOG_INFO, " -- write failed: %m");
+ }
+ }
+ return (0);
+ }
+ return (1);
+ }
+
+int put_string (s)
+register char *s;
+ {
+ s = clean(s, 1);
+
+ if (verbose)
+ {
+ logf("send (");
+
+ if (quiet)
+ {
+ logf("??????");
+ }
+ else
+ {
+ register char *s1 = s;
+
+ for (s1 = s; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+ }
+
+ logf(")\n");
+ }
+
+ alarm(timeout); alarmed = 0;
+
+ while (*s)
+ {
+ register char c = *s++;
+
+ if (c != '\\')
+ {
+ if (!write_char (c))
+ {
+ return 0;
+ }
+ continue;
+ }
+
+ c = *s++;
+ switch (c)
+ {
+ case 'd':
+ sleep(1);
+ break;
+
+ case 'K':
+ break_sequence();
+ break;
+
+ case 'p':
+ usleep(10000); /* 1/100th of a second (arg is microseconds) */
+ break;
+
+ default:
+ if (!write_char (c))
+ return 0;
+ break;
+ }
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+ }
+
+/*
+ * 'Wait for' this string to appear on this file descriptor.
+ */
+int get_string(string)
+register char *string;
+ {
+ char temp[STR_LEN];
+ int c, printed = 0, len, minlen;
+ register char *s = temp, *end = s + STR_LEN;
+
+ fail_reason = (char *)0;
+ string = clean(string, 0);
+ len = strlen(string);
+ minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
+
+ if (verbose)
+ {
+ register char *s1;
+
+ logf("expect (");
+
+ for (s1 = string; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+
+ logf(")\n");
+ }
+
+ if (len > STR_LEN)
+ {
+ syslog(LOG_INFO, "expect string is too long");
+ exit_code = 1;
+ return 0;
+ }
+
+ if (len == 0)
+ {
+ if (verbose)
+ {
+ syslog(LOG_INFO, "got it");
+ }
+
+ return (1);
+ }
+
+ alarm(timeout);
+ alarmed = 0;
+
+ while ( ! alarmed && (c = get_char()) >= 0)
+ {
+ int n, abort_len, report_len;
+
+ if (verbose)
+ {
+ if (c == '\n')
+ {
+ logf("\n");
+ }
+ else
+ {
+ logf(character(c));
+ }
+ }
+
+ *s++ = c;
+
+ if (s - temp >= len &&
+ c == string[len - 1] &&
+ strncmp(s - len, string, len) == 0)
+ {
+ if (verbose)
+ {
+ logf(" -- got it\n");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+ }
+
+ for (n = 0; n < n_aborts; ++n)
+ {
+ if (s - temp >= (abort_len = strlen(abort_string[n])) &&
+ strncmp(s - abort_len, abort_string[n], abort_len) == 0)
+ {
+ if (verbose)
+ {
+ logf(" -- failed\n");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ exit_code = n + 4;
+ strcpy(fail_reason = fail_buffer, abort_string[n]);
+ return (0);
+ }
+ }
+
+ if (!report_gathering)
+ {
+ for (n = 0; n < n_reports; ++n)
+ {
+ if ((report_string[n] != (char*) NULL) &&
+ s - temp >= (report_len = strlen(report_string[n])) &&
+ strncmp(s - report_len, report_string[n], report_len) == 0)
+ {
+ time_t time_now = time ((time_t*) NULL);
+ struct tm* tm_now = localtime (&time_now);
+
+ strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
+ strcat (report_buffer, report_string[n]);
+
+ report_string[n] = (char *) NULL;
+ report_gathering = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!iscntrl (c))
+ {
+ int rep_len = strlen (report_buffer);
+ report_buffer[rep_len] = c;
+ report_buffer[rep_len + 1] = '\0';
+ }
+ else
+ {
+ report_gathering = 0;
+ fprintf (report_fp, "chat: %s\n", report_buffer);
+ }
+ }
+
+ if (s >= end)
+ {
+ strncpy (temp, s - minlen, minlen);
+ s = temp + minlen;
+ }
+
+ if (alarmed && verbose)
+ {
+ syslog(LOG_WARNING, "warning: alarm synchronization problem");
+ }
+ }
+
+ alarm(0);
+
+ if (verbose && printed)
+ {
+ if (alarmed)
+ {
+ logf(" -- read timed out\n");
+ }
+ else
+ {
+ logflush();
+ syslog(LOG_INFO, " -- read failed: %m");
+ }
+ }
+
+ exit_code = 3;
+ alarmed = 0;
+ return (0);
+ }
+
+#ifdef NO_USLEEP
+#include <sys/types.h>
+#include <sys/time.h>
+
+/*
+ usleep -- support routine for 4.2BSD system call emulations
+ last edit: 29-Oct-1984 D A Gwyn
+ */
+
+extern int select();
+
+int
+usleep( usec ) /* returns 0 if ok, else -1 */
+ long usec; /* delay in microseconds */
+{
+ static struct /* `timeval' */
+ {
+ long tv_sec; /* seconds */
+ long tv_usec; /* microsecs */
+ } delay; /* _select() timeout */
+
+ delay.tv_sec = usec / 1000000L;
+ delay.tv_usec = usec % 1000000L;
+
+ return select( 0, (long *)0, (long *)0, (long *)0, &delay );
+}
+#endif
diff --git a/usr.bin/chat/connect-ppp b/usr.bin/chat/connect-ppp
new file mode 100755
index 0000000..d37067d
--- /dev/null
+++ b/usr.bin/chat/connect-ppp
@@ -0,0 +1,129 @@
+#!/bin/sh
+#
+# USAGE: connect-ppp <host>
+#
+# Set up a PPP link to host.
+#
+# This script locks the tty so that faxd and uucp will not
+# interfere. If you are running with faxd as you "getty" then
+# faxd will remove the lock once it notices that pppd is gone.
+# This is the reason for pppd running in with the -detach flag,
+# and you probably would run this script in the background.
+#
+# I had to create the nodropdtr option to pppd in order to be
+# able to do what the script is doing here. Pathces has been
+# sent to the respective people, but I don't know if they like
+# them :-).
+#
+# Look for comments with <LOCAL> in the string. They identify
+# things that you want to set for your system
+
+#<LOCAL> define whatever your config file is.
+CON_DB=/etc/ppp-connections
+
+#<LOCAL> define whatever your device is.
+DEVICE=cuaa0
+
+#<LOCAL> define whatever your device speed is.
+DEVICESPEED=57600
+
+#<LOCAL> define whatever your lock directory is.
+LOCKDIR=/var/spool/lock
+LOCKFILE=$LOCKDIR/LCK..$DEVICE
+
+#<LOCAL> define whatever debug level you want.
+DEBUG="-d -d -d -d"
+
+# Check that we got a name to connect to. This need not be an actuall hostname
+# just the name you specified in the config file.
+if [ $# -ne 1 ] ; then
+ echo "Usage: $0 <host> &"
+ exit 1
+fi
+
+# Get the configuration that is in effect for <name>
+LINE=`grep "^$1" $CON_DB`
+if [ -z "$LINE" ] ; then
+ echo "Unknow host $1"
+ exit 1
+fi
+
+# parse the CON_DB. The format is:
+#
+# <hostname>:<phone number>:<user id>:<password>:<local ip address>:\
+# <remove_ip_address><netmask>:<pppd options>
+#
+# The last three are optional. But I would recomend specifying a netmask also
+# when you specify a ip address.
+
+IP_ADDR=""
+IFS=':'
+set $LINE
+IFS=' '
+HOST=$1
+PHONE=$2
+USER=$3
+PASSWORD=$4
+OUR_IP_ADDR=$5
+THEIR_IP_ADDR=$6
+NETMASK=$7
+shift 7
+OPTIONS=$*
+
+if [ -f $LOCKFILE ] ; then
+ echo "PPP device is locked"
+ exit 1
+else
+
+ # Lock the device
+ # faxd and UUCP wants 10 character lock id.
+ echo "$$" | awk '{printf("%10s",$0)}' > $LOCKFILE
+fi
+
+
+
+
+#Do we know our local ip address? If so pppd needs a : at the end of it.
+if [ ! -z "$OUR_IP_ADDR" ] ; then
+ IP_ADDR=${OUR_IP_ADDR}:${THEIR_IP_ADDR}
+fi
+
+#Did we specify a netmask? If so convert to pppd format.
+if [ ! -z "$NETMASK" ] ; then
+ NETMASK="netmask ${NETMASK}"
+fi
+
+# Do the actual work in a subshell so that we can turn off tostop and set
+# the tty speed before chat dials. The second reason for doing in like
+# is that if you aren't running BIDIR, and you are running faxd, clocal
+# doesn't get turned on from pppd so chat will never work if you exec
+# it from within pppd. I found that I needed to run uucp with the
+# HAVE_CLOCAL_BUG flag set to 1 in order to get it to work in conjunction
+# with faxd. Anyway, this setup seem to work.
+(
+
+ stty $DEVICESPEED -tostop hupcl 2> /dev/null
+
+ # <LOCAL> Modify the Modem initialization strings to be whatever works for you
+ if chat -v ABORT "NO CARRIER" ABORT BUSY "" ATZ0E1 OK ATS50=255DT$PHONE \
+ CONNECT "" ogin: $USER ssword: \\q$PASSWORD
+ then
+ # We got connected.
+ /usr/libexec/pppd $DEBUG $OPTIONS -detach modem defaultroute \
+ crtscts $NETMASK $DEVICE $DEVICESPEED $IP_ADDR
+
+ else
+ echo "PPP call failed" 1>&2
+ exit 1
+ fi
+) < /dev/$DEVICE > /dev/$DEVICE
+# Get the return code from the subshell.
+RC=$?
+
+# Clear the lock. Slight window here where someone could detect that
+# pppd is no longer running, remove its lock file and create its own.
+# How to fix??
+rm -f $LOCKFILE
+
+#Pass on the exit code.
+exit $RC
diff --git a/usr.bin/chat/ppp-off b/usr.bin/chat/ppp-off
new file mode 100755
index 0000000..22b46f8
--- /dev/null
+++ b/usr.bin/chat/ppp-off
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+kill -INT `ps -ax | egrep " ppp " | egrep -v "egrep" | sed 's/^\([ 0-9]*\) .*/\1'/`
+
+exit 0
diff --git a/usr.bin/chat/ppp-on b/usr.bin/chat/ppp-on
new file mode 100755
index 0000000..d150cfb
--- /dev/null
+++ b/usr.bin/chat/ppp-on
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+#
+# ppp-on
+#
+# Set up a PPP link
+#
+
+LOCKDIR=/var/spool/lock
+DEVICE=cuaa0
+
+PHONE=4511234
+USER=Pkarl
+PASSWORD=password
+OUR_IP_ADDR=137.175.6.3
+
+if [ -f $LOCKDIR/LCK..$DEVICE ]
+then
+ echo "PPP device is locked"
+ exit 1
+fi
+
+(
+ stty 19200 -tostop
+
+ if chat -l LCK..$DEVICE ABORT "NO CARRIER" ABORT BUSY "" ATZ OK ATs50=255s111=0DT$PHONE CONNECT "" ogin: $USER ssword: \\q$PASSWORD
+ then
+ ppp mru 1500 $OUR_IP_ADDR: /dev/$DEVICE &
+ sleep 10
+ exit 0
+ else
+ echo "PPP call failed" 1>&2
+ exit 1
+ fi
+) < /dev/$DEVICE > /dev/$DEVICE
diff --git a/usr.bin/chat/unlock b/usr.bin/chat/unlock
new file mode 100755
index 0000000..978bc6e
--- /dev/null
+++ b/usr.bin/chat/unlock
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+LOCKDIR=/var/spool/lock
+
+case "$1" in
+ "") echo "Usage: unlock lockfile"; exit 1 ;;
+ .*) echo "Usage: unlock lockfile"; exit 1 ;;
+esac
+
+if [ -f $LOCKDIR/$1 ]
+then
+ if [ `wc -c < $LOCKDIR/$1` -eq 4 ]
+ then
+ rm -f $LOCKDIR/$1
+ exit 0
+ else
+ echo "Usage: unlock lockfile"
+ exit 1
+ fi
+else
+ echo "lockfile" $LOCKDIR/$1 "does not exist"
+ exit 1
+fi
diff --git a/usr.bin/checknr/checknr.1 b/usr.bin/checknr/checknr.1
index 1a49c5f..5cdcc9c 100644
--- a/usr.bin/checknr/checknr.1
+++ b/usr.bin/checknr/checknr.1
@@ -137,9 +137,9 @@ macro packages.
.Sh SEE ALSO
.Xr nroff 1 ,
.Xr troff 1 ,
-.Xr checkeq 1 ,
-.Xr ms 7 ,
-.Xr me 7
+.Xr me 7 ,
+.Xr ms 7
+.\" .Xr checkeq 1 ,
.Sh DIAGNOSTICS
.Bd -ragged -compact
Complaints about unmatched delimiters.
diff --git a/usr.bin/checknr/checknr.c b/usr.bin/checknr/checknr.c
index 774d3b0..f8531cc 100644
--- a/usr.bin/checknr/checknr.c
+++ b/usr.bin/checknr/checknr.c
@@ -49,12 +49,27 @@ static char sccsid[] = "@(#)checknr.c 8.1 (Berkeley) 6/6/93";
* structured typesetting.
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#define MAXSTK 100 /* Stack size */
#define MAXBR 100 /* Max number of bracket pairs known */
#define MAXCMDS 500 /* Max number of commands known */
+void addcmd __P((char *));
+void addmac __P((char *));
+int binsrch __P((char *));
+void checkknown __P((char *));
+void chkcmd __P((char *, char *));
+void complain __P((int));
+int eq __P((char *, char *));
+void nomatch __P((char *));
+void pe __P((int));
+void process __P((FILE *));
+void prop __P((int));
+static void usage __P((void));
+
/*
* The stack on which we remember what we've seen so far.
*/
@@ -75,53 +90,53 @@ struct brstr {
} br[MAXBR] = {
/* A few bare bones troff commands */
#define SZ 0
- "sz", "sz", /* also \s */
+ {"sz", "sz"}, /* also \s */
#define FT 1
- "ft", "ft", /* also \f */
+ {"ft", "ft"}, /* also \f */
/* the -mm package */
- "AL", "LE",
- "AS", "AE",
- "BL", "LE",
- "BS", "BE",
- "DF", "DE",
- "DL", "LE",
- "DS", "DE",
- "FS", "FE",
- "ML", "LE",
- "NS", "NE",
- "RL", "LE",
- "VL", "LE",
+ {"AL", "LE"},
+ {"AS", "AE"},
+ {"BL", "LE"},
+ {"BS", "BE"},
+ {"DF", "DE"},
+ {"DL", "LE"},
+ {"DS", "DE"},
+ {"FS", "FE"},
+ {"ML", "LE"},
+ {"NS", "NE"},
+ {"RL", "LE"},
+ {"VL", "LE"},
/* the -ms package */
- "AB", "AE",
- "BD", "DE",
- "CD", "DE",
- "DS", "DE",
- "FS", "FE",
- "ID", "DE",
- "KF", "KE",
- "KS", "KE",
- "LD", "DE",
- "LG", "NL",
- "QS", "QE",
- "RS", "RE",
- "SM", "NL",
- "XA", "XE",
- "XS", "XE",
+ {"AB", "AE"},
+ {"BD", "DE"},
+ {"CD", "DE"},
+ {"DS", "DE"},
+ {"FS", "FE"},
+ {"ID", "DE"},
+ {"KF", "KE"},
+ {"KS", "KE"},
+ {"LD", "DE"},
+ {"LG", "NL"},
+ {"QS", "QE"},
+ {"RS", "RE"},
+ {"SM", "NL"},
+ {"XA", "XE"},
+ {"XS", "XE"},
/* The -me package */
- "(b", ")b",
- "(c", ")c",
- "(d", ")d",
- "(f", ")f",
- "(l", ")l",
- "(q", ")q",
- "(x", ")x",
- "(z", ")z",
+ {"(b", ")b"},
+ {"(c", ")c"},
+ {"(d", ")d"},
+ {"(f", ")f"},
+ {"(l", ")l"},
+ {"(q", ")q"},
+ {"(x", ")x"},
+ {"(z", ")z"},
/* Things needed by preprocessors */
- "EQ", "EN",
- "TS", "TE",
+ {"EQ", "EN"},
+ {"TS", "TE"},
/* Refer */
- "[", "]",
- 0, 0
+ {"[", "]"},
+ {0, 0}
};
/*
@@ -171,8 +186,7 @@ int sflag; /* -s: ignore \s */
int ncmds; /* size of knowncmds */
int slot; /* slot in knowncmds found by binsrch */
-char *malloc();
-
+int
main(argc, argv)
int argc;
char **argv;
@@ -216,6 +230,7 @@ char **argv;
if (cp[2] && cp[2] != '.')
usage();
strncpy(b1, cp, 2);
+ b1[2] = '\0';
addmac(b1);
}
break;
@@ -253,12 +268,15 @@ char **argv;
exit(0);
}
+static void
usage()
{
- printf("Usage: checknr -s -f -a.xx.yy.xx.yy... -c.xx.xx.xx...\n");
+ fprintf(stderr,
+ "usage: checknr [-a.xx.yy.xx.yy...] [-c.xx.xx.xx...] [-s] [-f] file\n");
exit(1);
}
+void
process(f)
FILE *f;
{
@@ -355,7 +373,9 @@ FILE *f;
}
}
+void
complain(i)
+int i;
{
pe(stk[i].lno);
printf("Unmatched ");
@@ -363,7 +383,9 @@ complain(i)
printf("\n");
}
+void
prop(i)
+int i;
{
if (stk[i].pl == 0)
printf(".%s", br[stk[i].opno].opbr);
@@ -380,11 +402,12 @@ prop(i)
}
}
+void
chkcmd(line, mac)
char *line;
char *mac;
{
- register int i, n;
+ register int i;
/*
* Check to see if it matches top of stack.
@@ -417,6 +440,7 @@ char *mac;
}
}
+void
nomatch(mac)
char *mac;
{
@@ -462,6 +486,7 @@ char *mac;
}
/* eq: are two strings equal? */
+int
eq(s1, s2)
char *s1, *s2;
{
@@ -469,6 +494,7 @@ char *s1, *s2;
}
/* print the first part of an error message, given the line number */
+void
pe(lineno)
int lineno;
{
@@ -477,6 +503,7 @@ int lineno;
printf("%d: ", lineno);
}
+void
checkknown(mac)
char *mac;
{
@@ -495,6 +522,7 @@ char *mac;
/*
* We have a .de xx line in "line". Add xx to the list of known commands.
*/
+void
addcmd(line)
char *line;
{
@@ -526,6 +554,7 @@ char *line;
* me someday?) Anyway, I claim that .de is fairly rare in user
* nroff programs, and the register loop below is pretty fast.
*/
+void
addmac(mac)
char *mac;
{
@@ -558,6 +587,7 @@ printf("after: %s %s %s %s %s, %d cmds\n", knowncmds[slot-2], knowncmds[slot-1],
* Do a binary search in knowncmds for mac.
* If found, return the index. If not, return -1.
*/
+int
binsrch(mac)
char *mac;
{
diff --git a/usr.bin/chflags/Makefile b/usr.bin/chflags/Makefile
index a432e5f..d269255 100644
--- a/usr.bin/chflags/Makefile
+++ b/usr.bin/chflags/Makefile
@@ -1,5 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
+NOSHARED?=yes
+
PROG= chflags
SRCS= chflags.c stat_flags.c
.PATH: ${.CURDIR}/../../bin/ls
diff --git a/usr.bin/chflags/chflags.1 b/usr.bin/chflags/chflags.1
index 8b07e9a..99424f8 100644
--- a/usr.bin/chflags/chflags.1
+++ b/usr.bin/chflags/chflags.1
@@ -32,9 +32,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)chflags.1 8.4 (Berkeley) 5/2/95
+.\" @(#)chflags.1 8.2 (Berkeley) 3/31/94
+.\" $Id$
.\"
-.Dd May 2, 1995
+.Dd March 31, 1994
.Dt CHFLAGS 1
.Os
.Sh NAME
@@ -79,13 +80,17 @@ in the files instead of just the files themselves.
Flags are a comma separated list of keywords.
The following keywords are currently defined:
.Bd -literal -offset indent compact
-.\"arch nothing yet.
-opaque set the opaque flag (owner or super-user only)
-nodump set the nodump flag (owner or super-user only)
+arch set the archived flag (super-user only)
+dump set the dump flag
sappnd set the system append-only flag (super-user only)
schg set the system immutable flag (super-user only)
+sunlnk set the system undeletable flag (super-user only)
uappnd set the user append-only flag (owner or super-user only)
uchg set the user immutable flag (owner or super-user only)
+uunlnk set the user undeletable flag (owner or super-user only)
+archived, sappend, schange, simmutable, uappend, uchange, uimmutable,
+sunlink, uunlink
+ aliases for the above
.Ed
.Pp
Putting the letters
@@ -93,7 +98,7 @@ Putting the letters
before an option causes the flag to be turned off.
For example:
.Bd -literal -offset indent compact
-nouchg the immutable bit should be cleared
+nodump the file should never be dumped
.Ed
.Pp
Symbolic links do not have flags, so unless the
@@ -114,11 +119,19 @@ option is specified.
In addition, these options override each other and the
command's actions are determined by the last one specified.
.Pp
+You can use "ls -lo" to see the flags of existing files.
+.Pp
The
.Nm chflags
utility exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
+.Xr ls 1 ,
.Xr chflags 2 ,
.Xr stat 2 ,
.Xr fts 3 ,
.Xr symlink 7
+.Sh HISTORY
+The
+.Nm chflags
+command first appeared in
+.Bx 4.4 .
diff --git a/usr.bin/chflags/chflags.c b/usr.bin/chflags/chflags.c
index 8abeee1..f33f46e 100644
--- a/usr.bin/chflags/chflags.c
+++ b/usr.bin/chflags/chflags.c
@@ -68,7 +68,7 @@ main(argc, argv)
char *flags, *ep;
Hflag = Lflag = Pflag = Rflag = 0;
- while ((ch = getopt(argc, argv, "HLPR")) != EOF)
+ while ((ch = getopt(argc, argv, "HLPR")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@@ -125,7 +125,7 @@ main(argc, argv)
}
if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
- err(1, NULL);
+ err(1, NULL);
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
switch (p->fts_info) {
diff --git a/usr.bin/chkey/Makefile b/usr.bin/chkey/Makefile
new file mode 100644
index 0000000..6cc1d1c
--- /dev/null
+++ b/usr.bin/chkey/Makefile
@@ -0,0 +1,14 @@
+# $Id$
+
+PROG= chkey
+SRCS= chkey.c update.c generic.c
+
+.PATH: ${.CURDIR}/../newkey
+
+MAN1= chkey.1
+
+CFLAGS+= -DYP
+
+LDADD+= -lrpcsvc -lmp -lgmp
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/chkey/chkey.1 b/usr.bin/chkey/chkey.1
new file mode 100644
index 0000000..7db240d
--- /dev/null
+++ b/usr.bin/chkey/chkey.1
@@ -0,0 +1,21 @@
+.\" @(#)chkey.1 1.5 91/03/11 TIRPC 1.0;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\"
+.TH CHKEY 1 "5 July 1989"
+.SH NAME
+chkey \- change your encryption key
+.SH SYNOPSIS
+.B chkey
+.SH DESCRIPTION
+.LP
+.B chkey
+prompts the user for their login password,
+and uses it to encrypt a new encryption key
+for the user to be stored in the
+.BR publickey (5)
+database.
+.SH "SEE ALSO"
+.BR keylogin (1),
+.BR publickey (5),
+.BR keyserv (8C),
+.BR newkey (8).
diff --git a/usr.bin/chkey/chkey.c b/usr.bin/chkey/chkey.c
new file mode 100644
index 0000000..b769054
--- /dev/null
+++ b/usr.bin/chkey/chkey.c
@@ -0,0 +1,288 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#ifndef lint
+static char sccsid[] = "@(#)chkey.c 1.7 91/03/11 Copyr 1986 Sun Micro";
+#endif
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Command to change one's public key in the public key database
+ */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#else
+#define YPOP_STORE 4
+#endif
+#include <pwd.h>
+#include <string.h>
+#include <sys/fcntl.h>
+
+extern char *getpass();
+#define index strchr
+extern char *crypt();
+#ifdef YPPASSWD
+struct passwd *ypgetpwuid();
+#endif
+
+#ifdef YP
+static char *domain;
+static char PKMAP[] = "publickey.byname";
+#else
+static char PKFILE[] = "/etc/publickey";
+#endif /* YP */
+static char ROOTKEY[] = "/etc/.rootkey";
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char name[MAXNETNAMELEN+1];
+ char public[HEXKEYBYTES + 1];
+ char secret[HEXKEYBYTES + 1];
+ char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
+ char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
+ int status;
+ char *pass;
+ struct passwd *pw;
+ uid_t uid;
+ int force = 0;
+ char *self;
+#ifdef YP
+ char *master;
+#endif
+
+ self = argv[0];
+ for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
+ if (argv[0][2] != 0) {
+ usage(self);
+ }
+ switch (argv[0][1]) {
+ case 'f':
+ force = 1;
+ break;
+ default:
+ usage(self);
+ }
+ }
+ if (argc != 0) {
+ usage(self);
+ }
+
+#ifdef YP
+ (void)yp_get_default_domain(&domain);
+ if (yp_master(domain, PKMAP, &master) != 0) {
+ (void)fprintf(stderr,
+ "can't find master of publickey database\n");
+ exit(1);
+ }
+#endif
+ uid = getuid() /*geteuid()*/;
+ if (uid == 0) {
+ if (host2netname(name, NULL, NULL) == 0) {
+ (void)fprintf(stderr,
+ "chkey: cannot convert hostname to netname\n");
+ exit(1);
+ }
+ } else {
+ if (user2netname(name, uid, NULL) == 0) {
+ (void)fprintf(stderr,
+ "chkey: cannot convert username to netname\n");
+ exit(1);
+ }
+ }
+ (void)printf("Generating new key for %s.\n", name);
+
+ if (!force) {
+ if (uid != 0) {
+#ifdef YPPASSWD
+ pw = ypgetpwuid(uid);
+#else
+ pw = getpwuid(uid);
+#endif
+ if (pw == NULL) {
+#ifdef YPPASSWD
+ (void)fprintf(stderr,
+ "No NIS password entry found: can't change key.\n");
+#else
+ (void)fprintf(stderr,
+ "No password entry found: can't change key.\n");
+#endif
+ exit(1);
+ }
+ } else {
+ pw = getpwuid(0);
+ if (pw == NULL) {
+ (void)fprintf(stderr,
+ "No password entry found: can't change key.\n");
+ exit(1);
+ }
+ }
+ }
+ pass = getpass("Password:");
+#ifdef YPPASSWD
+ if (!force) {
+ if (strcmp(crypt(pass, pw->pw_passwd), pw->pw_passwd) != 0) {
+ (void)fprintf(stderr, "Invalid password.\n");
+ exit(1);
+ }
+ }
+#else
+ force = 1; /* Make this mandatory */
+#endif
+ genkeys(public, secret, pass);
+
+ memcpy(crypt1, secret, HEXKEYBYTES);
+ memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
+ crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
+ xencrypt(crypt1, pass);
+
+ if (force) {
+ memcpy(crypt2, crypt1, HEXKEYBYTES + KEYCHECKSUMSIZE + 1);
+ xdecrypt(crypt2, getpass("Retype password:"));
+ if (memcmp(crypt2, crypt2 + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0 ||
+ memcmp(crypt2, secret, HEXKEYBYTES) != 0) {
+ (void)fprintf(stderr, "Password incorrect.\n");
+ exit(1);
+ }
+ }
+
+#ifdef YP
+ (void)printf("Sending key change request to %s...\n", master);
+#endif
+ status = setpublicmap(name, public, crypt1);
+ if (status != 0) {
+#ifdef YP
+ (void)fprintf(stderr,
+ "%s: unable to update NIS database (%u): %s\n",
+ self, status, yperr_string(status));
+#else
+ (void)fprintf(stderr,
+ "%s: unable to update publickey database\n", self);
+#endif
+ exit(1);
+ }
+
+ if (uid == 0) {
+ /*
+ * Root users store their key in /etc/$ROOTKEY so
+ * that they can auto reboot without having to be
+ * around to type a password. Storing this in a file
+ * is rather dubious: it should really be in the EEPROM
+ * so it does not go over the net.
+ */
+ int fd;
+
+ fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0);
+ if (fd < 0) {
+ perror(ROOTKEY);
+ } else {
+ char newline = '\n';
+
+ if (write(fd, secret, strlen(secret)) < 0 ||
+ write(fd, &newline, sizeof(newline)) < 0) {
+ (void)fprintf(stderr, "%s: ", ROOTKEY);
+ perror("write");
+ }
+ }
+ }
+
+ if (key_setsecret(secret) < 0) {
+ (void)printf("Unable to login with new secret key.\n");
+ exit(1);
+ }
+ (void)printf("Done.\n");
+ exit(0);
+ /* NOTREACHED */
+}
+
+usage(name)
+ char *name;
+{
+ (void)fprintf(stderr, "usage: %s [-f]\n", name);
+ exit(1);
+ /* NOTREACHED */
+}
+
+
+/*
+ * Set the entry in the public key file
+ */
+setpublicmap(name, public, secret)
+ char *name;
+ char *public;
+ char *secret;
+{
+ char pkent[1024];
+
+ (void)sprintf(pkent,"%s:%s", public, secret);
+#ifdef YP
+ return (yp_update(domain, PKMAP, YPOP_STORE,
+ name, strlen(name), pkent, strlen(pkent)));
+#else
+ return (localupdate(name, PKFILE, YPOP_STORE,
+ strlen(name), name, strlen(pkent), pkent));
+#endif
+}
+
+#ifdef YPPASSWD
+struct passwd *
+ypgetpwuid(uid)
+ uid_t uid;
+{
+ char uidstr[10];
+ char *val;
+ int vallen;
+ static struct passwd pw;
+ char *p;
+
+ (void)sprintf(uidstr, "%d", uid);
+ if (yp_match(domain, "passwd.byuid", uidstr, strlen(uidstr),
+ &val, &vallen) != 0) {
+ return (NULL);
+ }
+ p = index(val, ':');
+ if (p == NULL) {
+ return (NULL);
+ }
+ pw.pw_passwd = p + 1;
+ p = index(pw.pw_passwd, ':');
+ if (p == NULL) {
+ return (NULL);
+ }
+ *p = 0;
+ return (&pw);
+}
+#endif /* YPPASSWD */
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index b68ad10..cef2d57 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/chpass/Makefile
@@ -4,12 +4,60 @@ PROG= chpass
SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c table.c util.c
BINOWN= root
BINMODE=4555
-.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw
+.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw \
+ ${.CURDIR}/../../libexec/ypxfr \
+ ${.CURDIR}/../../usr.sbin/rpc.yppasswdd
CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw
-LINKS= ${BINDIR}/chpass ${BINDIR}/chfn ${BINDIR}/chpass ${BINDIR}/chsh
+LINKS= ${BINDIR}/chpass ${BINDIR}/chfn
+LINKS+= ${BINDIR}/chpass ${BINDIR}/chsh
+LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchpass
+LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchfn
+LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchsh
MLINKS= chpass.1 chfn.1 chpass.1 chsh.1
+COPTS+= -DYP -I. -I${.CURDIR}/../../libexec/ypxfr \
+ -I${.CURDIR}/../../usr.sbin/rpc.yppasswdd -Dyp_error=warnx
+
+#Some people need this, uncomment to activate
+#COPTS+= -DRESTRICT_FULLNAME_CHANGE
+
+SRCS+= yppasswd_private_xdr.c yppasswd_comm.c yp_clnt.c \
+ yppasswd_clnt.c pw_yp.c ypxfr_misc.c
+CLEANFILES= yp_clnt.c yp.h yppasswd_clnt.c yppasswd.h \
+ yppasswd_private_xdr.c yppasswd_private.h
+
+DPADD= ${LIBRPCSVC} ${LIBCRYPT}
+LDADD+= -lrpcsvc -lcrypt
+
+RPCGEN= rpcgen -C
+RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCSRC_PW= ${DESTDIR}/usr/include/rpcsvc/yppasswd.x
+RPCSRC_PRIV= ${.CURDIR}/../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC} yp.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
+
+yppasswd.h: ${RPCSRC_PW}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_clnt.c: ${RPCSRC_PW} yppasswd.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_xdr.c: ${RPCSRC_PRIV} yppasswd_private.h
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
+
+beforeinstall:
+.for i in chpass chfn chsh ypchpass ypchfn ypchsh
+ [ ! -e ${DESTDIR}${BINDIR}/$i ] || \
+ chflags noschg ${DESTDIR}${BINDIR}/$i
+.endfor
afterinstall:
- chflags schg /usr/bin/chpass
+ chflags schg ${DESTDIR}${BINDIR}/chpass
.include <bsd.prog.mk>
diff --git a/usr.bin/chpass/chpass.1 b/usr.bin/chpass/chpass.1
index 1a40905..e9059a6 100644
--- a/usr.bin/chpass/chpass.1
+++ b/usr.bin/chpass/chpass.1
@@ -30,20 +30,24 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)chpass.1 8.2 (Berkeley) 12/30/93
+.\" $Id$
.\"
.Dd December 30, 1993
.Dt CHPASS 1
.Os
.Sh NAME
-.Nm chpass
+.Nm chpass, chfn, chsh, ypchpass, ypchfn, ypchsh
.Nd add or change user database information
.Sh SYNOPSIS
-chpass
+.Nm chpass
.Op Fl a Ar list
+.Op Fl p Ar encpass
.Op Fl s Ar newshell
.Op user
.Sh DESCRIPTION
-.Nm Chpass
+The
+.Nm chpass
+program
allows editing of the user database information associated
with
.Ar user
@@ -53,7 +57,7 @@ The information is formatted and supplied to an editor for changes.
Only the information that the user is allowed to change is displayed.
.Pp
The options are as follows:
-.Bl -tag -width Ds
+.Bl -tag -width flag
.It Fl a
The super-user is allowed to directly supply a user database
entry, in the format specified by
@@ -61,6 +65,11 @@ entry, in the format specified by
as an argument.
This argument must be a colon (``:'') separated list of all the
user database fields, although they may be empty.
+.It Fl p
+The super-user is allowed to directly supply an encrypted password field,
+in the format used by
+.Xr crypt 3 ,
+as an argument.
.It Fl s
The
.Fl s
@@ -197,6 +206,178 @@ When the editor terminates, the information is re-read and used to
update the user database itself.
Only the user, or the super-user, may edit the information associated
with the user.
+.Sh NIS INTERACTION
+.Nm Chpass
+can also be used in conjunction with NIS, however some restrictions
+apply.
+Currently,
+.Nm chpass
+can only make changes to the NIS passwd maps through
+.Xr rpc.yppasswdd 8 ,
+which normally only permits changes to a user's password, shell and GECOS
+fields. Except when invoked by the super-user on the NIS master server,
+.Nm chpass
+(and, similarly,
+.Xr passwd 1 )
+can not use the
+.Xr rpc.yppasswdd 8
+server to change other user information or
+add new records to the NIS passwd maps.
+Furthermore,
+.Xr rpc.yppasswdd 8
+requires password authentication before it will make any
+changes. The only user allowed to submit changes without supplying
+a password is the super-user on the NIS master server; all other users,
+including those with root privileges on NIS clients (and NIS slave
+servers) must enter a password.
+(The super-user on the NIS master is allowed to bypass these restrictions
+largely for convenience: a user with root access
+to the NIS master server already has the privileges required to make
+updates to the NIS maps, but editing the map source files by hand can
+be cumbersome.
+.Pp
+Note: these exceptions only apply when the NIS master server is a
+FreeBSD system.)
+.Pp
+Consequently, except where noted, the following restrictions apply when
+.Nm chpass
+is used with NIS:
+.Bl -enum -offset indent
+.It
+.Pa Only the shell and GECOS information may be changed.
+All other
+fields are restricted, even when
+.Nm chpass
+is invoked by the super-user.
+While support for
+changing other fields could be added, this would lead to
+compatibility problems with other NIS-capable systems.
+Even though the super-user may supply data for other fields
+while editing an entry, the extra information (other than the
+password -- see below) will be silently discarded.
+.Pp
+Exception: the super-user on the NIS master server is permitted to
+change any field.
+.Pp
+.It
+.Pa Password authentication is required.
+.Nm Chpass
+will prompt for the user's NIS password before effecting
+any changes. If the password is invalid, all changes will be
+discarded.
+.Pp
+Exception: the super-user on the NIS master server is allowed to
+submit changes without supplying a password. (The super-user may
+choose to turn off this feature using the
+.Fl o
+flag, described below.)
+.It
+.Pa Adding new records to the local
+.Pa password database is discouraged.
+.Nm Chpass
+will allow the administrator to add new records to the
+local password database while NIS is enabled, but this can lead to
+some confusion since the new records are appended to the end of
+the master password file, usually after the special NIS '+' entries.
+The administrator should use
+.Xr vipw 8
+to modify the local password
+file when NIS is running.
+.Pp
+The super-user on the NIS master server is permitted to add new records
+to the NIS password maps, provided the
+.Xr rpc.yppasswdd 8
+server has been started with the
+.Fl a
+flag to permitted additions (it refuses them by default).
+.Nm Chpass
+tries to update the local password database by default; to update the
+NIS maps instead, invoke chpass with the
+.Fl y
+flag.
+.It
+.Pa Password changes are not permitted.
+Users should use
+.Xr passwd 1
+or
+.Xr yppasswd 1
+to change their NIS passwords. The super-user is allowed to specify
+a new password (even though the ``Password:'' field does not show
+up in the editor template, the super-user may add it back by hand),
+but even the super-user must supply the user's original password
+otherwise
+.Xr rpc.yppasswdd 8
+will refuse to update the NIS maps.
+.Pp
+Exception: the super-user on the NIS master server is permitted to
+change a user's NIS password with
+.Nm chpass .
+.El
+.Pp
+There are also a few extra option flags that are available when
+.Nm chpass
+is compiled with NIS support:
+.Bl -tag -width flag
+.It Fl l
+The
+.Fl l
+flag forces
+.Nm chpass
+to modify the local copy of a user's password
+information in the even that a user exists in both
+the local and NIS databases.
+.It Fl y
+This flag has the opposite effect of
+.Fl l .
+This flag is largely redundant since
+.Nm chpass
+operates on NIS entries by default if NIS is enabled.
+.It Fl d Ar domain
+Specify a particular NIS domain.
+.Nm Chpass
+uses the system domain name by default, as set by the
+.Xr domainname 1
+command. The
+.Fl d
+option can be used to override a default, or to specify a domain
+when the system domain name is not set.
+.It Fl h Ar host
+Specify the name or address of an NIS server to query. Normally,
+.Nm chpass
+will communicate with the NIS master host specified in the
+.Pa master.passwd
+or
+.Pa passwd
+maps. On hosts that have not been configured as NIS clients, there is
+no way for the program to determine this information unless the user
+provides the hostname of a server. Note that the specified hostname need
+not be that of the NIS master server; the name of any server, master or
+slave, in a given NIS domain will do.
+.Pp
+When using the
+.Fl d
+option, the hostname defaults to ``localhost.'' The
+.Fl h
+option can be used in conjunction with the
+.Fl d
+option, in which case the user-specified hostname will override
+the default.
+.Pp
+.It Fl o
+Force the use of RPC-based updates when communicating with
+.Xr rpc.yppasswdd 8
+(``old-mode'').
+When invoked by the super-user on the NIS master server,
+.Nm chpass
+allows unrestricted changes to the NIS passwd maps using dedicated,
+non-RPC-based mechanism (in this case, a UNIX domain socket). The
+.Fl o
+flag can be used to force
+.Nm chpass
+to use the standard update mechanism instead. This option is provided
+mainly for testing purposes.
+.El
+.Pp
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/master.passwd
@@ -209,8 +390,8 @@ Temporary copy of the password file
The list of approved shells
.El
.Sh SEE ALSO
-.Xr login 1 ,
.Xr finger 1 ,
+.Xr login 1 ,
.Xr passwd 1 ,
.Xr getusershell 3 ,
.Xr passwd 5 ,
@@ -222,6 +403,16 @@ and
.%A Ken Thompson
.%T "UNIX Password security"
.Re
+.Sh NOTES
+The
+.Xr chfn 1 ,
+.Xr chsh 1 ,
+.Xr ypchpass 1 ,
+.Xr ypchfn 1
+and
+.Xr ypchsh 1
+commands are really only links to
+.Nm chpass .
.Sh BUGS
User information should (and eventually will) be stored elsewhere.
.Sh HISTORY
diff --git a/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c
index 0852c53..982548f 100644
--- a/usr.bin/chpass/chpass.c
+++ b/usr.bin/chpass/chpass.c
@@ -38,7 +38,9 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
+static char sccsid[] = "From: @(#)chpass.c 8.4 (Berkeley) 4/2/94";
+static char rcsid[] =
+ "$Id: chpass.c,v 1.13 1997/02/22 19:54:25 peter Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -60,11 +62,15 @@ static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
#include <pw_scan.h>
#include <pw_util.h>
#include "pw_copy.h"
+#ifdef YP
+#include <rpcsvc/yp.h>
+int yp_errno = YP_TRUE;
+#include "pw_yp.h"
+#endif
#include "chpass.h"
#include "pathnames.h"
-char *progname = "chpass";
char *tempname;
uid_t uid;
@@ -76,13 +82,22 @@ main(argc, argv)
int argc;
char **argv;
{
- enum { NEWSH, LOADENTRY, EDITENTRY } op;
+ enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
struct passwd *pw, lpw;
+ char *username = NULL;
int ch, pfd, tfd;
char *arg;
+#ifdef YP
+ int force_local = 0;
+ int force_yp = 0;
+#endif
op = EDITENTRY;
- while ((ch = getopt(argc, argv, "a:s:")) != EOF)
+#ifdef YP
+ while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
+#endif
switch(ch) {
case 'a':
op = LOADENTRY;
@@ -92,6 +107,50 @@ main(argc, argv)
op = NEWSH;
arg = optarg;
break;
+ case 'p':
+ op = NEWPW;
+ arg = optarg;
+ break;
+ case 'e':
+ op = NEWEXP;
+ arg = optarg;
+ break;
+#ifdef YP
+ case 'h':
+#ifdef PARANOID
+ if (getuid()) {
+ warnx("Only the superuser can use the -h flag");
+ } else {
+#endif
+ yp_server = optarg;
+#ifdef PARANOID
+ }
+#endif
+ break;
+ case 'd':
+#ifdef PARANOID
+ if (getuid()) {
+ warnx("Only the superuser can use the -d flag");
+ } else {
+#endif
+ yp_domain = optarg;
+ if (yp_server == NULL)
+ yp_server = "localhost";
+#ifdef PARANOID
+ }
+#endif
+ break;
+ case 'l':
+ _use_yp = 0;
+ force_local = 1;
+ break;
+ case 'y':
+ _use_yp = force_yp = 1;
+ break;
+ case 'o':
+ force_old++;
+ break;
+#endif
case '?':
default:
usage();
@@ -101,8 +160,17 @@ main(argc, argv)
uid = getuid();
- if (op == EDITENTRY || op == NEWSH)
+ if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP)
switch(argc) {
+#ifdef YP
+ case 0:
+ GETPWUID(uid)
+ get_yp_master(1); /* XXX just to set the suser flag */
+ break;
+ case 1:
+ GETPWNAM(*argv)
+ get_yp_master(1); /* XXX just to set the suser flag */
+#else
case 0:
if (!(pw = getpwuid(uid)))
errx(1, "unknown user: uid %u", uid);
@@ -110,13 +178,13 @@ main(argc, argv)
case 1:
if (!(pw = getpwnam(*argv)))
errx(1, "unknown user: %s", *argv);
+#endif
if (uid && uid != pw->pw_uid)
baduser();
break;
default:
usage();
}
-
if (op == NEWSH) {
/* protect p_shell -- it thinks NULL is /bin/sh */
if (!arg[0])
@@ -125,6 +193,13 @@ main(argc, argv)
pw_error((char *)NULL, 0, 1);
}
+ if (op == NEWEXP) {
+ if (uid) /* only root can change expire */
+ baduser();
+ if (p_expire(arg, pw, (ENTRY *)NULL))
+ pw_error((char *)NULL, 0, 1);
+ }
+
if (op == LOADENTRY) {
if (uid)
baduser();
@@ -132,6 +207,17 @@ main(argc, argv)
if (!pw_scan(arg, pw))
exit(1);
}
+ username = pw->pw_name;
+
+ if (op == NEWPW) {
+ if (uid)
+ baduser();
+
+ if(strchr(arg, ':')) {
+ errx(1, "invalid format for password");
+ }
+ pw->pw_passwd = arg;
+ }
/*
* The temporary file/file descriptor usage is a little tricky here.
@@ -168,18 +254,26 @@ main(argc, argv)
(void)unlink(tempname);
tfd = pw_tmp();
}
-
+
+#ifdef YP
+ if (_use_yp) {
+ yp_submit(pw);
+ (void)unlink(tempname);
+ } else {
+#endif /* YP */
pw_copy(pfd, tfd, pw);
- if (!pw_mkdb())
+ if (!pw_mkdb(username))
pw_error((char *)NULL, 0, 1);
+#ifdef YP
+ }
+#endif /* YP */
exit(0);
}
void
baduser()
{
-
errx(1, "%s", strerror(EACCES));
}
@@ -187,6 +281,11 @@ void
usage()
{
- (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n");
+ (void)fprintf(stderr,
+#ifdef YP
+ "usage: chpass [-l] [-y] [-d domain [-h host]] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
+#else
+ "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
+#endif
exit(1);
}
diff --git a/usr.bin/chpass/edit.c b/usr.bin/chpass/edit.c
index 34bd35b..ad99822 100644
--- a/usr.bin/chpass/edit.c
+++ b/usr.bin/chpass/edit.c
@@ -29,6 +29,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
@@ -52,6 +54,9 @@ static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94";
#include <pw_util.h>
#include "chpass.h"
+#ifdef YP
+#include "pw_yp.h"
+#endif /* YP */
extern char *tempname;
@@ -94,8 +99,13 @@ display(fd, pw)
pw_error(tempname, 1, 1);
(void)fprintf(fp,
+#ifdef YP
+ "#Changing %s information for %s.\n", _use_yp ? "NIS" : "user database", pw->pw_name);
+ if (!uid && (!_use_yp || suser_override)) {
+#else
"#Changing user database information for %s.\n", pw->pw_name);
if (!uid) {
+#endif /* YP */
(void)fprintf(fp, "Login: %s\n", pw->pw_name);
(void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
(void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid);
@@ -110,24 +120,48 @@ display(fd, pw)
*pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
}
/* Only admin can change "restricted" shells. */
+#ifdef 0
else if (ok_shell(pw->pw_shell))
/*
* Make shell a restricted field. Ugly with a
* necklace, but there's not much else to do.
*/
+#else
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) || !uid)
+ /*
+ * If change not restrict (table.c) and standard shell
+ * OR if root, then allow editing of shell.
+ */
+#endif
(void)fprintf(fp, "Shell: %s\n",
*pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
else
- list[E_SHELL].restricted = 1;
+ list[E_SHELL].restricted = 1;
bp = pw->pw_gecos;
+
p = strsep(&bp, ",");
- (void)fprintf(fp, "Full Name: %s\n", p ? p : "");
- p = strsep(&bp, ",");
- (void)fprintf(fp, "Location: %s\n", p ? p : "");
- p = strsep(&bp, ",");
- (void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
- p = strsep(&bp, ",");
- (void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
+ if (p)
+ list[E_NAME].save = strdup(p);
+ if (!list[E_NAME].restricted || !uid)
+ (void)fprintf(fp, "Full Name: %s\n", p ? p : "");
+
+ p = strsep(&bp, ",");
+ if (p)
+ list[E_LOCATE].save = strdup(p);
+ if (!list[E_LOCATE].restricted || !uid)
+ (void)fprintf(fp, "Location: %s\n", p ? p : "");
+
+ p = strsep(&bp, ",");
+ if (p)
+ list[E_BPHONE].save = strdup(p);
+ if (!list[E_BPHONE].restricted || !uid)
+ (void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
+
+ p = strsep(&bp, ",");
+ if (p)
+ list[E_HPHONE].save = strdup(p);
+ if (!list[E_HPHONE].restricted || !uid)
+ (void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
(void)fchown(fd, getuid(), getgid());
(void)fclose(fp);
@@ -141,8 +175,8 @@ verify(pw)
char *p;
struct stat sb;
FILE *fp;
- int len;
- char buf[LINE_MAX];
+ int len, line;
+ static char buf[LINE_MAX];
if (!(fp = fopen(tempname, "r")))
pw_error(tempname, 1, 1);
@@ -152,17 +186,19 @@ verify(pw)
warnx("corrupted temporary file");
goto bad;
}
+ line = 0;
while (fgets(buf, sizeof(buf), fp)) {
+ line++;
if (!buf[0] || buf[0] == '#')
continue;
if (!(p = strchr(buf, '\n'))) {
- warnx("line too long");
+ warnx("line %d too long", line);
goto bad;
}
*p = '\0';
for (ep = list;; ++ep) {
if (!ep->prompt) {
- warnx("unrecognized field");
+ warnx("unrecognized field on line %d", line);
goto bad;
}
if (!strncasecmp(buf, ep->prompt, ep->len)) {
@@ -173,7 +209,7 @@ verify(pw)
goto bad;
}
if (!(p = strchr(buf, ':'))) {
- warnx("line corrupted");
+ warnx("line %d corrupted", line);
goto bad;
}
while (isspace(*++p));
@@ -201,13 +237,18 @@ bad: (void)fclose(fp);
(void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save,
list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save);
+ while ((len = strlen(pw->pw_gecos)) && pw->pw_gecos[len - 1] == ',')
+ pw->pw_gecos[len - 1] = '\0';
+
if (snprintf(buf, sizeof(buf),
"%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir,
pw->pw_shell) >= sizeof(buf)) {
warnx("entries too long");
+ free(p);
return (0);
}
+ free(p);
return (pw_scan(buf, pw));
}
diff --git a/usr.bin/chpass/field.c b/usr.bin/chpass/field.c
index 898ba4d..73fa479 100644
--- a/usr.bin/chpass/field.c
+++ b/usr.bin/chpass/field.c
@@ -36,6 +36,7 @@ static char sccsid[] = "@(#)field.c 8.4 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/param.h>
+#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
@@ -92,7 +93,7 @@ p_passwd(p, pw, ep)
warnx("can't save password entry");
return (1);
}
-
+
return (0);
}
@@ -170,7 +171,7 @@ p_class(p, pw, ep)
warnx("can't save entry");
return (1);
}
-
+
return (0);
}
@@ -242,6 +243,7 @@ p_shell(p, pw, ep)
ENTRY *ep;
{
char *t, *ok_shell();
+ struct stat sbuf;
if (!*p) {
pw->pw_shell = _PATH_BSHELL;
@@ -264,5 +266,22 @@ p_shell(p, pw, ep)
warnx("can't save entry");
return (1);
}
+ if (stat(pw->pw_shell, &sbuf) < 0) {
+ if (errno == ENOENT)
+ warnx("WARNING: shell '%s' does not exist",
+ pw->pw_shell);
+ else
+ warn("WARNING: can't stat shell '%s'", pw->pw_shell);
+ return (0);
+ }
+ if (!S_ISREG(sbuf.st_mode)) {
+ warnx("WARNING: shell '%s' is not a regular file",
+ pw->pw_shell);
+ return (0);
+ }
+ if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
+ warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
+ return (0);
+ }
return (0);
}
diff --git a/usr.bin/chpass/pw_copy.c b/usr.bin/chpass/pw_copy.c
index 3db04ed..fa77f05 100644
--- a/usr.bin/chpass/pw_copy.c
+++ b/usr.bin/chpass/pw_copy.c
@@ -58,6 +58,15 @@ pw_copy(ffd, tfd, pw)
FILE *from, *to;
int done;
char *p, buf[8192];
+ char uidstr[20];
+ char gidstr[20];
+ char chgstr[20];
+ char expstr[20];
+
+ snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid);
+ snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid);
+ snprintf(chgstr, sizeof(chgstr), "%ld", pw->pw_change);
+ snprintf(expstr, sizeof(expstr), "%ld", pw->pw_expire);
if (!(from = fdopen(ffd, "r")))
pw_error(_PATH_MASTERPASSWD, 1, 1);
@@ -87,19 +96,35 @@ pw_copy(ffd, tfd, pw)
goto err;
continue;
}
- (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
- pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
- pw->pw_dir, pw->pw_shell);
+ (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd,
+ pw->pw_fields & _PWF_UID ? uidstr : "",
+ pw->pw_fields & _PWF_GID ? gidstr : "",
+ pw->pw_class,
+ pw->pw_fields & _PWF_CHANGE ? chgstr : "",
+ pw->pw_fields & _PWF_EXPIRE ? expstr : "",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell);
done = 1;
if (ferror(to))
goto err;
}
if (!done)
- (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
- pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
- pw->pw_dir, pw->pw_shell);
+#ifdef YP
+ /* Ultra paranoid: shouldn't happen. */
+ if (getuid()) {
+ warnx("%s: not found in %s -- permission denied",
+ pw->pw_name, _PATH_MASTERPASSWD);
+ pw_error(NULL, 0, 1);
+ } else
+#endif /* YP */
+ (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd,
+ pw->pw_fields & _PWF_UID ? uidstr : "",
+ pw->pw_fields & _PWF_GID ? gidstr : "",
+ pw->pw_class,
+ pw->pw_fields & _PWF_CHANGE ? chgstr : "",
+ pw->pw_fields & _PWF_EXPIRE ? expstr : "",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell);
if (ferror(to))
err: pw_error(NULL, 1, 1);
diff --git a/usr.bin/chpass/pw_yp.c b/usr.bin/chpass/pw_yp.c
new file mode 100644
index 0000000..0080e85
--- /dev/null
+++ b/usr.bin/chpass/pw_yp.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NIS interface routines for chpass
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ *
+ * $Id: pw_yp.c,v 1.9 1997/02/22 19:54:26 peter Exp $
+ */
+
+#ifdef YP
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+#include <db.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <limits.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <pw_util.h>
+#include "pw_yp.h"
+#include "ypxfr_extern.h"
+#include "yppasswd_comm.h"
+#include "yppasswd_private.h"
+
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+static HASHINFO openinfo = {
+ 4096, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash */
+ 0, /* lorder */
+};
+
+int force_old = 0;
+int _use_yp = 0;
+int suser_override = 0;
+int yp_in_pw_file = 0;
+char *yp_domain = NULL;
+char *yp_server = NULL;
+
+extern char *tempname;
+
+/* Save the local and NIS password information */
+struct passwd local_password;
+struct passwd yp_password;
+
+void copy_yp_pass(p, x, m)
+char *p;
+int x, m;
+{
+ register char *t, *s = p;
+ static char *buf;
+
+ yp_password.pw_fields = 0;
+
+ buf = (char *)realloc(buf, m + 10);
+ bzero(buf, m + 10);
+
+ /* Turn all colons into NULLs */
+ while (strchr(s, ':')) {
+ s = (strchr(s, ':') + 1);
+ *(s - 1)= '\0';
+ }
+
+ t = buf;
+#define EXPAND(e) e = t; while ((*t++ = *p++));
+ EXPAND(yp_password.pw_name);
+ yp_password.pw_fields |= _PWF_NAME;
+ EXPAND(yp_password.pw_passwd);
+ yp_password.pw_fields |= _PWF_PASSWD;
+ yp_password.pw_uid = atoi(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_UID;
+ yp_password.pw_gid = atoi(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_GID;
+ if (x) {
+ EXPAND(yp_password.pw_class);
+ yp_password.pw_fields |= _PWF_CLASS;
+ yp_password.pw_change = atol(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_CHANGE;
+ yp_password.pw_expire = atol(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_EXPIRE;
+ }
+ EXPAND(yp_password.pw_gecos);
+ yp_password.pw_fields |= _PWF_GECOS;
+ EXPAND(yp_password.pw_dir);
+ yp_password.pw_fields |= _PWF_DIR;
+ EXPAND(yp_password.pw_shell);
+ yp_password.pw_fields |= _PWF_SHELL;
+
+ return;
+}
+
+void copy_local_pass(p,m)
+char *p;
+int m;
+{
+ register char *t;
+ static char *buf;
+
+ buf = (char *)realloc(buf, m + 10);
+ bzero(buf, m + 10);
+
+ t = buf;
+ EXPAND(local_password.pw_name);
+ EXPAND(local_password.pw_passwd);
+ bcopy(p, (char *)&local_password.pw_uid, sizeof(int));
+ p += sizeof(int);
+ bcopy(p, (char *)&local_password.pw_gid, sizeof(int));
+ p += sizeof(int);
+ bcopy(p, (char *)&local_password.pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ EXPAND(local_password.pw_class);
+ EXPAND(local_password.pw_gecos);
+ EXPAND(local_password.pw_dir);
+ EXPAND(local_password.pw_shell);
+ bcopy(p, (char *)&local_password.pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ bcopy(p, (char *)&local_password.pw_fields, sizeof local_password.pw_fields);
+ p += sizeof local_password.pw_fields;
+
+ return;
+}
+
+/*
+ * It is not mandatory that an NIS master server also be a client.
+ * However, if the NIS master is not configured as a client, then the
+ * domain name will not be set and ypbind will not be running, so we
+ * will be unable to use the ypclnt routines inside libc. We therefore
+ * need our own magic version of yp_match() which we can use in any
+ * environment.
+ */
+static int my_yp_match(server, domain, map, key, keylen, result, resultlen)
+ char *server;
+ char *domain;
+ char *map;
+ char *key;
+ unsigned long keylen;
+ char **result;
+ unsigned long *resultlen;
+{
+ ypreq_key ypkey;
+ ypresp_val *ypval;
+ CLIENT *clnt;
+ static char buf[YPMAXRECORD + 2];
+
+ bzero((char *)buf, sizeof(buf));
+
+ if ((clnt = clnt_create(server, YPPROG,YPVERS,"udp")) == NULL) {
+ warnx("failed to create UDP handle: %s",
+ clnt_spcreateerror(server));
+ pw_error(tempname, 0, 1);
+ }
+
+ ypkey.domain = domain;
+ ypkey.map = map;
+ ypkey.key.keydat_len = keylen;
+ ypkey.key.keydat_val = key;
+
+ if ((ypval = ypproc_match_2(&ypkey, clnt)) == NULL) {
+ clnt_destroy(clnt);
+ warnx("%s",clnt_sperror(clnt,"YPPROC_MATCH failed"));
+ pw_error(tempname, 0, 1);
+ }
+
+ clnt_destroy(clnt);
+
+ if (ypval->stat != YP_TRUE) {
+ int stat = ypval->stat;
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+ if (stat == YP_NOMAP && strstr(map, "master.passwd"))
+ return(1);
+ if (stat == YP_NOKEY)
+ return(1);
+ warnx("ypmatch failed: %s", yperr_string(ypprot_err(stat)));
+ pw_error(tempname, 0, 1);
+ }
+
+
+ strncpy((char *)&buf, ypval->val.valdat_val, ypval->val.valdat_len);
+
+ *result = (char *)&buf;
+ *resultlen = ypval->val.valdat_len;
+
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+
+ return(0);
+}
+
+/*
+ * Check if the user we're working with is local or in NIS.
+ */
+int use_yp (user, uid, which)
+ char *user;
+ uid_t uid;
+ int which; /* 0 = use username, 1 = use uid */
+{
+ int user_local = 0, user_yp = 0, user_exists = 0;
+ DB *dbp;
+ DBT key,data;
+ char bf[UT_NAMESIZE + 2];
+ char *result;
+ char *server;
+ int resultlen;
+ char ubuf[UT_NAMESIZE + 2];
+
+ if (which) {
+ snprintf(ubuf, sizeof(ubuf), "%lu", uid);
+ user = (char *)&ubuf;
+ }
+
+ /* Grope around for the user in the usual way */
+ if (which) {
+ if (getpwuid(uid) != NULL)
+ user_exists = 1;
+ } else {
+ if (getpwnam(user) != NULL)
+ user_exists = 1;
+ }
+
+ /* Now grope directly through the user database */
+ if ((dbp = dbopen(_PATH_SMP_DB, O_RDONLY, PERM_SECURE,
+ DB_HASH, &openinfo)) == NULL) {
+ warn("error opening database: %s.", _PATH_MP_DB);
+ pw_error(tempname, 0, 1);
+ }
+
+ /* Is NIS turned on */
+ bf[0] = _PW_KEYYPENABLED;
+ key.data = (u_char *)bf;
+ key.size = 1;
+ yp_in_pw_file = !(dbp->get)(dbp,&key,&data,0);
+ if (_yp_check(NULL) || (yp_domain && yp_server)) {
+ server = get_yp_master(0);
+
+ /* Is the user in the NIS passwd map */
+ if (!my_yp_match(server, yp_domain, which ? "passwd.byuid" :
+ "passwd.byname", user, strlen(user),
+ &result, &resultlen)) {
+ user_yp = user_exists = 1;
+ *(char *)(result + resultlen) = '\0';
+ copy_yp_pass(result, 0, resultlen);
+ }
+ /* Is the user in the NIS master.passwd map */
+ if (user_yp && !my_yp_match(server, yp_domain, which ?
+ "master.passwd.byuid" : "master.passwd.byname",
+ user, strlen(user),
+ &result, &resultlen)) {
+ *(char *)(result + resultlen) = '\0';
+ copy_yp_pass(result, 1, resultlen);
+ }
+ }
+
+ /* Is the user in the local password database */
+
+ bf[0] = which ? _PW_KEYBYUID : _PW_KEYBYNAME;
+ if (which)
+ bcopy((char *)&uid, bf + 1, sizeof(uid));
+ else
+ bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE));
+ key.data = (u_char *)bf;
+ key.size = which ? sizeof(uid) + 1 : strlen(user) + 1;
+ if (!(dbp->get)(dbp,&key,&data,0)) {
+ user_local = 1;
+ copy_local_pass(data.data, data.size);
+ }
+
+ (dbp->close)(dbp);
+
+ if (user_local && user_yp && user_exists)
+ return(USER_YP_AND_LOCAL);
+ else if (!user_local && user_yp && user_exists)
+ return(USER_YP_ONLY);
+ else if (user_local && !user_yp && user_exists)
+ return(USER_LOCAL_ONLY);
+ else if (!user_exists)
+ return(USER_UNKNOWN);
+
+ return(-1);
+}
+
+/*
+ * Find the name of the NIS master server for this domain
+ * and make sure it's running yppasswdd.
+ */
+char *get_yp_master(getserver)
+ int getserver;
+{
+ char *mastername;
+ int rval, localport;
+ struct stat st;
+
+ /*
+ * Sometimes we are called just to probe for rpc.yppasswdd and
+ * set the suser_override flag. Just return NULL and leave
+ * suser_override at 0 if _use_yp doesn't indicate that NIS is
+ * in use and we weren't called from use_yp() itself.
+ * Without this check, we might try probing and fail with an NIS
+ * error in non-NIS environments.
+ */
+ if ((_use_yp == USER_UNKNOWN || _use_yp == USER_LOCAL_ONLY) &&
+ getserver)
+ return(NULL);
+
+ /* Get default NIS domain. */
+
+ if (yp_domain == NULL && (rval = yp_get_default_domain(&yp_domain))) {
+ warnx("can't get local NIS domain name: %s",yperr_string(rval));
+ pw_error(tempname, 0, 1);
+ }
+
+ /* Get master server of passwd map. */
+
+ if ((mastername = ypxfr_get_master(yp_domain, "passwd.byname",
+ yp_server, yp_server ? 0 : 1)) == NULL) {
+ warnx("can't get name of master NIS server");
+ pw_error(tempname, 0, 1);
+ }
+
+ if (!getserver)
+ return(mastername);
+
+ /* Check if yppasswdd is out there. */
+
+ if ((rval = getrpcport(mastername, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP)) == 0) {
+ warnx("rpc.yppasswdd is not running on the NIS master server");
+ pw_error(tempname, 0, 1);
+ }
+
+ /*
+ * Make sure it's on a reserved port.
+ * XXX Might break with yppasswdd servers running on Solaris 2.x.
+ */
+
+ if (rval >= IPPORT_RESERVED) {
+ warnx("rpc.yppasswdd server not running on reserved port");
+ pw_error(tempname, 0, 1);
+ }
+
+ /* See if _we_ are the master server. */
+ if (!force_old && !getuid() && (localport = getrpcport("localhost",
+ YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP)) != 0) {
+ if (localport == rval && stat(sockname, &st) != -1) {
+ suser_override = 1;
+ mastername = "localhost";
+ }
+ }
+
+ /* Everything checks out: return the name of the server. */
+
+ return (mastername);
+}
+
+/*
+ * Ask the user for his NIS password and submit the new information
+ * to yppasswdd. Note that rpc.yppasswdd requires password authentication
+ * and only allows changes to existing records rather than the addition
+ * of new records. (To do actual updates we would need something like
+ * secure RPC and ypupdated, which FreeBSD doesn't have yet.) The FreeBSD
+ * rpc.yppasswdd has some special hooks to allow the superuser update
+ * information without specifying a password, however this only works
+ * for the superuser on the NIS master server.
+ */
+void yp_submit(pw)
+ struct passwd *pw;
+{
+ struct yppasswd yppasswd;
+ struct master_yppasswd master_yppasswd;
+ CLIENT *clnt;
+ char *master, *password;
+ int *status = NULL;
+ struct rpc_err err;
+
+ _use_yp = 1;
+
+ /* Get NIS master server name */
+
+ master = get_yp_master(1);
+
+ /* Populate the yppasswd structure that gets handed to yppasswdd. */
+
+ if (suser_override) {
+ master_yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ master_yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ master_yppasswd.newpw.pw_uid = pw->pw_uid;
+ master_yppasswd.newpw.pw_gid = pw->pw_gid;
+ master_yppasswd.newpw.pw_expire = pw->pw_expire;
+ master_yppasswd.newpw.pw_change = pw->pw_change;
+ master_yppasswd.newpw.pw_fields = pw->pw_fields;
+ master_yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ master_yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ master_yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ master_yppasswd.newpw.pw_class = pw->pw_class != NULL ?
+ strdup(pw->pw_class) : "";
+ master_yppasswd.oldpass = ""; /* not really needed */
+ master_yppasswd.domain = yp_domain;
+ } else {
+ yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ yppasswd.newpw.pw_uid = pw->pw_uid;
+ yppasswd.newpw.pw_gid = pw->pw_gid;
+ yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ yppasswd.oldpass = "";
+ }
+
+ /* Get the user's password for authentication purposes. */
+
+ printf ("Changing NIS information for %s on %s\n",
+ pw->pw_name, master);
+
+ if (pw->pw_passwd[0] && !suser_override) {
+ password = getpass("Please enter password: ");
+ if (strncmp(crypt(password,pw->pw_passwd),
+ pw->pw_passwd,strlen(pw->pw_passwd))) {
+ warnx("Password incorrect.");
+ pw_error(tempname, 0, 1);
+ }
+ yppasswd.oldpass = password; /* XXX */
+ }
+
+ if (suser_override) {
+ /* Talk to server via AF_UNIX socket. */
+ if (senddat(&master_yppasswd)) {
+ warnx("failed to contact local rpc.yppasswdd");
+ pw_error(tempname, 0, 1);
+ }
+ /* Get return code. */
+ status = getresp();
+ } else {
+ /* Create a handle to yppasswdd. */
+
+ if ((clnt = clnt_create(master, YPPASSWDPROG,
+ YPPASSWDVERS, "udp")) == NULL) {
+ warnx("failed to contact rpc.yppasswdd: %s",
+ master, clnt_spcreateerror(master));
+ pw_error(tempname, 0, 1);
+ }
+
+ clnt->cl_auth = authunix_create_default();
+
+ status = yppasswdproc_update_1(&yppasswd, clnt);
+
+ clnt_geterr(clnt, &err);
+
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ /* Call failed: signal the error. */
+
+ if ((!suser_override && err.re_status) != RPC_SUCCESS || status == NULL || *status) {
+ warnx("NIS update failed: %s", (err.re_status != RPC_SUCCESS &&
+ !suser_override) ? clnt_sperrno(err.re_status) :
+ "rpc.yppasswdd returned error status");
+ pw_error(NULL, 0, 1);
+ }
+
+ /* Success. */
+
+ if (suser_override)
+ warnx("NIS information changed on host %s, domain %s",
+ master, yp_domain);
+ else
+ warnx("NIS information changed on host %s", master);
+
+ return;
+}
+#endif /* YP */
diff --git a/usr.bin/chpass/pw_yp.h b/usr.bin/chpass/pw_yp.h
new file mode 100644
index 0000000..0a1e1c0
--- /dev/null
+++ b/usr.bin/chpass/pw_yp.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NIS interface routines for chpass
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ *
+ * $Id$
+ */
+
+#ifdef YP
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+/* Four possible return codes from use_yp() */
+#define USER_UNKNOWN 0
+#define USER_YP_ONLY 1
+#define USER_LOCAL_ONLY 2
+#define USER_YP_AND_LOCAL 3
+
+extern int force_old;
+extern int _use_yp;
+extern int suser_override;
+extern struct passwd local_password;
+extern struct passwd yp_password;
+extern void copy_yp_pass __P(( char *, int, int ));
+extern char *yp_domain;
+extern char *yp_server;
+extern void yp_submit __P(( struct passwd * ));
+extern int use_yp __P(( char * , uid_t , int ));
+extern char *get_yp_master __P(( int ));
+extern int yp_in_pw_file;
+
+/*
+ * Yucky.
+ */
+#define GETPWUID(X) \
+ _use_yp = use_yp(NULL, X, 1); \
+ \
+ if (_use_yp == USER_UNKNOWN) { \
+ errx(1, "unknown user: uid %u", X); \
+ } \
+ \
+ if (_use_yp == USER_YP_ONLY) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else \
+ errx(1, "unknown local user: uid %u", X); \
+ } else if (_use_yp == USER_LOCAL_ONLY) { \
+ if (!force_yp) { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } else \
+ errx(1, "unknown NIS user: uid %u", X); \
+ } else if (_use_yp == USER_YP_AND_LOCAL) { \
+ if (!force_local && (force_yp || yp_in_pw_file)) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } \
+ }
+
+#define GETPWNAM(X) \
+ _use_yp = use_yp(X, 0, 0); \
+ \
+ if (_use_yp == USER_UNKNOWN) { \
+ errx(1, "unknown user: %s", X); \
+ } \
+ \
+ if (_use_yp == USER_YP_ONLY) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else \
+ errx(1, "unknown local user: %s.", X); \
+ } else if (_use_yp == USER_LOCAL_ONLY) { \
+ if (!force_yp) { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } else \
+ errx(1, "unknown NIS user: %s.", X); \
+ } else if (_use_yp == USER_YP_AND_LOCAL) { \
+ if (!force_local && (force_yp || yp_in_pw_file)) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } \
+ }
+
+#endif /* YP */
diff --git a/usr.bin/chpass/table.c b/usr.bin/chpass/table.c
index 46a12d1..3363e1d 100644
--- a/usr.bin/chpass/table.c
+++ b/usr.bin/chpass/table.c
@@ -50,7 +50,11 @@ ENTRY list[] = {
{ "class", p_class, 1, 5, e1, },
{ "change", p_change, 1, 6, NULL, },
{ "expire", p_expire, 1, 6, NULL, },
+#ifdef RESTRICT_FULLNAME_CHANGE /* do not allow fullname changes */
+ { "full name", p_gecos, 1, 9, e2, },
+#else
{ "full name", p_gecos, 0, 9, e2, },
+#endif
{ "office phone", p_gecos, 0, 12, e2, },
{ "home phone", p_gecos, 0, 10, e2, },
{ "location", p_gecos, 0, 8, e2, },
diff --git a/usr.bin/chpass/util.c b/usr.bin/chpass/util.c
index ec4cc1f..605a484 100644
--- a/usr.bin/chpass/util.c
+++ b/usr.bin/chpass/util.c
@@ -43,14 +43,11 @@ static char sccsid[] = "@(#)util.c 8.4 (Berkeley) 4/2/94";
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
#include "chpass.h"
#include "pathnames.h"
-static int dmsize[] =
- { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static char *months[] =
{ "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November",
@@ -66,12 +63,12 @@ ttoa(tval)
if (tval) {
tp = localtime(&tval);
(void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon],
- tp->tm_mday, tp->tm_year + TM_YEAR_BASE);
+ tp->tm_mday, tp->tm_year + 1900);
}
else
*tbuf = '\0';
return (tbuf);
-}
+}
int
atot(p, store)
@@ -94,12 +91,16 @@ atot(p, store)
}
if (!(t = strtok(p, " \t")))
goto bad;
- for (mp = months;; ++mp) {
- if (!*mp)
- goto bad;
- if (!strncasecmp(*mp, t, 3)) {
- month = mp - months + 1;
- break;
+ if (isdigit(*t)) {
+ month = atoi(t);
+ } else {
+ for (mp = months;; ++mp) {
+ if (!*mp)
+ goto bad;
+ if (!strncasecmp(*mp, t, 3)) {
+ month = mp - months + 1;
+ break;
+ }
}
}
if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
@@ -111,18 +112,18 @@ atot(p, store)
if (day < 1 || day > 31 || month < 1 || month > 12 || !year)
goto bad;
if (year < 100)
- year += TM_YEAR_BASE;
- if (year <= EPOCH_YEAR)
+ year += 1900;
+ if (year <= 1970)
bad: return (1);
- tval = isleap(year) && month > 2;
- for (--year; year >= EPOCH_YEAR; --year)
- tval += isleap(year) ?
- DAYSPERLYEAR : DAYSPERNYEAR;
- while (--month)
- tval += dmsize[month];
- tval += day;
- tval = tval * HOURSPERDAY * MINSPERHOUR * SECSPERMIN;
- tval -= lt->tm_gmtoff;
+ lt->tm_year = year - 1900;
+ lt->tm_mon = month - 1;
+ lt->tm_mday = day;
+ lt->tm_hour = 0;
+ lt->tm_min = 0;
+ lt->tm_sec = 0;
+ lt->tm_isdst = -1;
+ if ((tval = mktime(lt)) < 0)
+ return (1);
*store = tval;
return (0);
}
diff --git a/usr.bin/cksum/cksum.1 b/usr.bin/cksum/cksum.1
index f5f292b..c94fceb 100644
--- a/usr.bin/cksum/cksum.1
+++ b/usr.bin/cksum/cksum.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)cksum.1 8.2 (Berkeley) 4/28/95
+.\" $Id: cksum.1,v 1.4 1997/06/25 07:02:00 charnier Exp $
.\"
.Dd April 28, 1995
.Dt CKSUM 1
@@ -42,7 +43,7 @@
.Nd display file checksums and block counts
.Sh SYNOPSIS
.Nm cksum
-.Op Fl o Op \&1 \&| \&2
+.Op Fl o Ar \&1 No \&| Ar \&2
.Op Ar file ...
.Nm sum
.Op Ar file ...
@@ -155,6 +156,8 @@ and
.Nm sum
utilities exit 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
+.Xr md5 1
+.Rs
The default calculation is identical to that given in pseudo-code
in the following
.Tn ACM
@@ -168,9 +171,10 @@ article.
.Sh STANDARDS
The
.Nm cksum
-utility is expected to be POSIX 1003.2 compatible.
+utility is expected to conform to
+.St -p1003.2-92 .
.Sh HISTORY
The
.Nm cksum
-utility appears in
+utility appeared in
.Bx 4.4 .
diff --git a/usr.bin/cksum/cksum.c b/usr.bin/cksum/cksum.c
index 9b8e81a..1917558 100644
--- a/usr.bin/cksum/cksum.c
+++ b/usr.bin/cksum/cksum.c
@@ -35,13 +35,17 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
+#if 0
static char sccsid[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <sys/cdefs.h>
@@ -57,7 +61,7 @@ static char sccsid[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95";
#include "extern.h"
-void usage __P((void));
+static void usage __P((void));
int
main(argc, argv)
@@ -74,12 +78,12 @@ main(argc, argv)
p = argv[0];
else
++p;
- if (*p == 'c') {
- cfncn = crc;
- pfncn = pcrc;
- } else {
+ if (!strcmp(p, "sum")) {
cfncn = csum1;
pfncn = psum1;
+ } else {
+ cfncn = crc;
+ pfncn = pcrc;
}
while ((ch = getopt(argc, argv, "o:")) != -1)
@@ -125,9 +129,10 @@ main(argc, argv)
exit(rval);
}
-void
+static void
usage()
{
(void)fprintf(stderr, "usage: cksum [-o 1 | 2] [file ...]\n");
+ (void)fprintf(stderr, " sum [file ...]\n");
exit(1);
}
diff --git a/usr.bin/cmp/cmp.1 b/usr.bin/cmp/cmp.1
index 9db561a..637b1ce 100644
--- a/usr.bin/cmp/cmp.1
+++ b/usr.bin/cmp/cmp.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)cmp.1 8.1 (Berkeley) 6/6/93
+.\" $Id: cmp.1,v 1.4 1997/02/22 19:54:29 peter Exp $
.\"
.Dd June 6, 1993
.Dt CMP 1
@@ -46,10 +47,12 @@
.Ar file1 file2
.Op Ar skip1 Op Ar skip2
.Sh DESCRIPTION
-The cmp utility compares two files of any type and writes the results
+The
+.Nm cmp
+utility compares two files of any type and writes the results
to the standard output.
By default,
-.Nm
+.Nm cmp
is silent if the files are the same; if they differ, the byte
and line number at which the first difference occurred is reported.
.Pp
@@ -105,3 +108,8 @@ The
utility is expected to be
.St -p1003.2
compatible.
+.Sh HISTORY
+A
+.Nm cmp
+command appeared in
+.At v1 .
diff --git a/usr.bin/cmp/cmp.c b/usr.bin/cmp/cmp.c
index dc6c64e..6755ff6 100644
--- a/usr.bin/cmp/cmp.c
+++ b/usr.bin/cmp/cmp.c
@@ -67,7 +67,7 @@ main(argc, argv)
int ch, fd1, fd2, special;
char *file1, *file2;
- while ((ch = getopt(argc, argv, "-ls")) != EOF)
+ while ((ch = getopt(argc, argv, "-ls")) != -1)
switch (ch) {
case 'l': /* print all differences */
lflag = 1;
@@ -99,8 +99,12 @@ endargs:
fd1 = 0;
file1 = "stdin";
}
- else if ((fd1 = open(file1, O_RDONLY, 0)) < 0)
- err(ERR_EXIT, "%s", file1);
+ else if ((fd1 = open(file1, O_RDONLY, 0)) < 0) {
+ if (!sflag)
+ err(ERR_EXIT, "%s", file1);
+ else
+ exit(1);
+ }
if (strcmp(file2 = argv[1], "-") == 0) {
if (special)
errx(ERR_EXIT,
@@ -109,20 +113,32 @@ endargs:
fd2 = 0;
file2 = "stdin";
}
- else if ((fd2 = open(file2, O_RDONLY, 0)) < 0)
- err(ERR_EXIT, "%s", file2);
+ else if ((fd2 = open(file2, O_RDONLY, 0)) < 0) {
+ if (!sflag)
+ err(ERR_EXIT, "%s", file2);
+ else
+ exit(1);
+ }
skip1 = argc > 2 ? strtol(argv[2], NULL, 10) : 0;
skip2 = argc == 4 ? strtol(argv[3], NULL, 10) : 0;
if (!special) {
- if (fstat(fd1, &sb1))
- err(ERR_EXIT, "%s", file1);
+ if (fstat(fd1, &sb1)) {
+ if (!sflag)
+ err(ERR_EXIT, "%s", file1);
+ else
+ exit(1);
+ }
if (!S_ISREG(sb1.st_mode))
special = 1;
else {
- if (fstat(fd2, &sb2))
- err(ERR_EXIT, "%s", file2);
+ if (fstat(fd2, &sb2)) {
+ if (!sflag)
+ err(ERR_EXIT, "%s", file2);
+ else
+ exit(1);
+ }
if (!S_ISREG(sb2.st_mode))
special = 1;
}
@@ -141,6 +157,6 @@ usage()
{
(void)fprintf(stderr,
- "usage: cmp [-l | s] file1 file2 [skip1 [skip2]]\n");
+ "usage: cmp [-l | -s] file1 file2 [skip1 [skip2]]\n");
exit(ERR_EXIT);
}
diff --git a/usr.bin/cmp/regular.c b/usr.bin/cmp/regular.c
index 35f62d1..f540ab4 100644
--- a/usr.bin/cmp/regular.c
+++ b/usr.bin/cmp/regular.c
@@ -44,9 +44,12 @@ static char sccsid[] = "@(#)regular.c 8.3 (Berkeley) 4/2/94";
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "extern.h"
+#define ROUNDPAGE(i) ((i) & ~pagemask)
+
void
c_regular(fd1, file1, skip1, len1, fd2, file2, skip2, len2)
int fd1, fd2;
@@ -56,6 +59,7 @@ c_regular(fd1, file1, skip1, len1, fd2, file2, skip2, len2)
u_char ch, *p1, *p2;
off_t byte, length, line;
int dfound;
+ off_t pagemask, off1, off2;
if (sflag && len1 != len2)
exit(1);
@@ -67,18 +71,27 @@ c_regular(fd1, file1, skip1, len1, fd2, file2, skip2, len2)
eofmsg(file2);
len2 -= skip2;
+ pagemask = (off_t)getpagesize() - 1;
+ off1 = ROUNDPAGE(skip1);
+ off2 = ROUNDPAGE(skip2);
+
length = MIN(len1, len2);
if (length > SIZE_T_MAX)
return (c_special(fd1, file1, skip1, fd2, file2, skip2));
if ((p1 = (u_char *)mmap(NULL,
- (size_t)length, PROT_READ, 0, fd1, skip1)) == (u_char *)-1)
+ (size_t)length, PROT_READ, MAP_SHARED, fd1, off1)) == (u_char *)MAP_FAILED)
err(ERR_EXIT, "%s", file1);
+
+ madvise(p1, length, MADV_SEQUENTIAL);
if ((p2 = (u_char *)mmap(NULL,
- (size_t)length, PROT_READ, 0, fd2, skip2)) == (u_char *)-1)
+ (size_t)length, PROT_READ, MAP_SHARED, fd2, off2)) == (u_char *)MAP_FAILED)
err(ERR_EXIT, "%s", file2);
+ madvise(p2, length, MADV_SEQUENTIAL);
dfound = 0;
+ p1 += skip1 - off1;
+ p2 += skip2 - off2;
for (byte = line = 1; length--; ++p1, ++p2, ++byte) {
if ((ch = *p1) != *p2)
if (lflag) {
diff --git a/usr.bin/cmp/special.c b/usr.bin/cmp/special.c
index 0dcd0c5..0a15fa1 100644
--- a/usr.bin/cmp/special.c
+++ b/usr.bin/cmp/special.c
@@ -60,6 +60,7 @@ c_special(fd1, file1, skip1, fd2, file2, skip2)
if ((fp2 = fdopen(fd2, "r")) == NULL)
err(ERR_EXIT, "%s", file2);
+ dfound = 0;
while (skip1--)
if (getc(fp1) == EOF)
goto eof;
@@ -67,7 +68,6 @@ c_special(fd1, file1, skip1, fd2, file2, skip2)
if (getc(fp2) == EOF)
goto eof;
- dfound = 0;
for (byte = line = 1;; ++byte) {
ch1 = getc(fp1);
ch2 = getc(fp2);
diff --git a/usr.bin/col/col.1 b/usr.bin/col/col.1
index 2a55ef2..99ecda5 100644
--- a/usr.bin/col/col.1
+++ b/usr.bin/col/col.1
@@ -123,4 +123,5 @@ will display a warning message.
A
.Nm col
command
-appeared in Version 6 AT&T UNIX.
+appeared in
+.At v6 .
diff --git a/usr.bin/col/col.c b/usr.bin/col/col.c
index 8458281..88d024e 100644
--- a/usr.bin/col/col.c
+++ b/usr.bin/col/col.c
@@ -50,6 +50,7 @@ static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <locale.h>
#define BS '\b' /* backspace */
#define TAB '\t' /* tab */
@@ -107,8 +108,10 @@ int nblank_lines; /* # blanks after last flushed line */
int no_backspaces; /* if not to output any backspaces */
#define PUTC(ch) \
- if (putchar(ch) == EOF) \
- wrerr();
+ do { \
+ if (putchar(ch) == EOF) \
+ wrerr(); \
+ } while (0)
int
main(argc, argv)
@@ -127,9 +130,11 @@ main(argc, argv)
int nflushd_lines; /* number of lines that were flushed */
int adjust, opt, warned;
+ (void) setlocale(LC_CTYPE, "");
+
max_bufd_lines = 128;
compress_spaces = 1; /* compress spaces into tabs */
- while ((opt = getopt(argc, argv, "bfhl:x")) != EOF)
+ while ((opt = getopt(argc, argv, "bfhl:x")) != -1)
switch (opt) {
case 'b': /* do not output backspaces */
no_backspaces = 1;
@@ -436,12 +441,20 @@ flush_line(l)
int nspace = this_col - last_col;
if (compress_spaces && nspace > 1) {
- int ntabs;
-
- ntabs = this_col / 8 - last_col / 8;
- nspace -= ntabs * 8;
- while (--ntabs >= 0)
- PUTC('\t');
+ while (1) {
+ int tab_col, tab_size;;
+
+ tab_col = (last_col + 8) & ~7;
+ if (tab_col > this_col)
+ break;
+ tab_size = tab_col - last_col;
+ if (tab_size == 1)
+ PUTC(' ');
+ else
+ PUTC('\t');
+ nspace -= tab_size;
+ last_col = tab_col;
+ }
}
while (--nspace >= 0)
PUTC(' ');
diff --git a/usr.bin/colcrt/colcrt.1 b/usr.bin/colcrt/colcrt.1
index a9447af..8c4a88a 100644
--- a/usr.bin/colcrt/colcrt.1
+++ b/usr.bin/colcrt/colcrt.1
@@ -76,10 +76,10 @@ would be
tbl exum2.n \&| nroff \-ms \&| colcrt \- \&| more
.Ed
.Sh SEE ALSO
-.Xr nroff 1 ,
-.Xr troff 1 ,
.Xr col 1 ,
.Xr more 1 ,
+.Xr nroff 1 ,
+.Xr troff 1 ,
.Xr ul 1
.Sh BUGS
Should fold underlines onto blanks even with the
diff --git a/usr.bin/colcrt/colcrt.c b/usr.bin/colcrt/colcrt.c
index 9e6136b..f3661a8 100644
--- a/usr.bin/colcrt/colcrt.c
+++ b/usr.bin/colcrt/colcrt.c
@@ -64,9 +64,11 @@ int outcol;
char suppresul;
char printall;
-char *progname;
FILE *f;
+static void usage __P((void));
+
+int
main(argc, argv)
int argc;
char *argv[];
@@ -75,7 +77,7 @@ main(argc, argv)
register char *cp, *dp;
argc--;
- progname = *argv++;
+ argv++;
while (argc > 0 && argv[0][0] == '-') {
switch (argv[0][1]) {
case 0:
@@ -85,9 +87,7 @@ main(argc, argv)
printall = 1;
break;
default:
- printf("usage: %s [ - ] [ -2 ] [ file ... ]\n", progname);
- fflush(stdout);
- exit(1);
+ usage();
}
argc--;
argv++;
@@ -97,8 +97,7 @@ main(argc, argv)
close(0);
if (!(f = fopen(argv[0], "r"))) {
fflush(stdout);
- perror(argv[0]);
- exit (1);
+ err(1, argv[0]);
}
argc--;
argv++;
@@ -180,6 +179,13 @@ main(argc, argv)
exit(0);
}
+static void
+usage()
+{
+ fprintf(stderr, "usage: colcrt [ - ] [ -2 ] [ file ... ]\n");
+ exit(1);
+}
+
plus(c, d)
char c, d;
{
diff --git a/usr.bin/colldef/Makefile b/usr.bin/colldef/Makefile
new file mode 100644
index 0000000..295fe3f
--- /dev/null
+++ b/usr.bin/colldef/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+
+PROG = colldef
+LFLAGS = -8 -i
+YFLAGS = -d
+CFLAGS += -I. -I${.CURDIR}/../../lib/libc/locale -DCOLLATE_DEBUG
+SRCS = parse.c scan.c
+LDADD = -ll
+DPADD = ${LIBL}
+CLEANFILES += lex.yy.c parse.c scan.c y.tab.[ch]
+SUBDIR = data
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/colldef/colldef.1 b/usr.bin/colldef/colldef.1
new file mode 100644
index 0000000..b668d1a
--- /dev/null
+++ b/usr.bin/colldef/colldef.1
@@ -0,0 +1,252 @@
+.\" Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+.\" at Electronni Visti IA, Kiev, Ukraine.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd January, 27 1995
+.Dt COLLDEF 1
+.Os
+.Sh NAME
+.Nm colldef
+.Nd convert collation sequence source definition
+.Sh SYNOPSIS
+.Nm colldef
+.Op Fl I Ar map_dir
+.Op Fl o Ar out_file
+.Op Ar filename
+.Sh DESCRIPTION
+.Nm Colldef
+converts a collation sequence source definition
+into a format usable by the
+.Fn strxfrm
+and
+.Fn strcoll
+functions. It is used to define the many ways in which
+strings can be ordered and collated.
+.Fn strxfrm
+transforms
+its first argument and places the result in its second
+argument. The transformed string is such that it can be
+correctly ordered with other transformed strings by using
+.Fn strcmp ,
+.Fn strncmp ,
+or
+.Fn memcmp .
+.Fn strcoll
+transforms its arguments and does a
+comparison.
+.Pp
+.Nm Colldef
+reads the collation sequence source definition
+from the standard input and stores the converted definition in filename.
+The output file produced contains the
+database with collating sequence information in a form
+usable by system commands and routines.
+.Pp
+Options list:
+.Bl -tag -width 4n
+.It Cm Fl I Ar map_dir
+This option set directory name where
+.Ar charmap
+files can be found, current directory by default.
+.It Cm Fl o Ar out_file
+This option set output file name,
+.Ar LC_COLLATE
+by default.
+.El
+.Pp
+The collation sequence definition specifies a set of collating elements and
+the rules defining how strings containing these should be ordered.
+This is most useful for different language definitions.
+.Pp
+The specification file can consist of three statements:
+.Ar charmap ,
+.Ar substitute
+and
+.Ar order .
+.Pp
+Of these, only the
+.Ar order
+statement is required. When
+.Ar charmap
+or
+.Ar substitute
+is
+supplied, these statements must be ordered as above. Any
+statements after the order statement are ignored.
+.Pp
+Lines in the specification file beginning with a
+.Ar #
+are
+treated as comments and are ignored. Blank lines are also
+ignored.
+.Pp
+.Ar charmap charmapfile
+.Pp
+.Ar charmap
+defines where a mapping of the character
+and collating element symbols to the actual
+character encoding can be found.
+.Pp
+The format of
+.Ar charmapfile
+is shown below. Symbol
+names are separated from their values by TAB or
+SPACE characters. symbol-value can be specified in
+a hexadecimal (\ex\fI??\fR) or octal (\e\fI???\fR)
+representation, and can be only one character in length.
+.Pp
+.Ar symbol-name1 symbol-value1
+.br
+.Ar symbol-name2 symbol-value2
+.br
+.Ar ...
+.Pp
+Symbol names cannot be specified in
+.Ar substitute
+fields.
+.Pp
+The
+.Ar charmap
+statement is optional.
+.Pp
+.Ar substitute
+"\fIchar\fR"
+.Ar with
+"\fIrepl\fR"
+.Pp
+The
+.Ar substitute
+statement substitutes the character
+.Ar char
+with the string
+.Ar repl .
+.Pp
+The
+.Ar substitute
+statement is optional.
+.Pp
+.Ar order order_list
+.Pp
+.Ar order_list
+is a list of symbols, separated by semi colons, that defines the
+collating sequence. The
+special symbol
+.Ar ...
+specifies, in a short-hand
+form, symbols that are sequential in machine code
+order.
+.Pp
+An order list element
+can be represented in any one of the following
+ways:
+.Bl -bullet
+.It
+The symbol itself (for example,
+.Ar a
+for the lower-case letter
+.Ar a )
+.It
+The symbol chain (for example,
+.Ar abc )
+.It
+In octal representation (for example,
+.Ar \e141
+for the letter
+.Ar a )
+.It
+In hexadecimal representation (for example,
+.Ar \ex61
+for the letter
+.Ar a )
+.It
+The symbol name as defined in the
+.Ar charmap
+file (for example,
+.Ar <abc>
+for
+.Ar abc \e023
+record in
+.Ar charmapfile ) .
+If character map name have
+.Ar >
+character, it must be escaped as
+.Ar /> ,
+single
+.Ar /
+must be escaped as
+.Ar // .
+.It
+Symbols
+.Ar \ea ,
+.Ar \eb ,
+.Ar \ef ,
+.Ar \en ,
+.Ar \er ,
+.Ar \ev
+are permitted in its usual C-language meaning
+.It
+The symbol range (for example,
+.Ar a;...;z )
+.It
+Comma-separated symbols, ranges and chains enclosed in parenthesis (for example
+.Ar \&(
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&) )
+are assigned the
+same primary ordering but different secondary
+ordering.
+.It
+Comma-separated symbols, ranges and chains enclosed in curly brackets (for example
+.Ar \&{
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&} )
+are assigned the same primary ordering only.
+.El
+.Pp
+The backslash character
+.Ar \e
+is used for continuation. In this case, no characters are permitted
+after the backslash character.
+.Sh EXIT STATUS
+.Nm Colldef
+exits with the following values:
+.Ar 0
+No errors were found and the output was successfully created.
+.Ar !=0
+Errors were found.
+.Sh FILES
+.Ar /usr/share/locale/<language>/LC_COLLATE
+standard shared location for collation orders
+under the locale locale
+.Sh SEE ALSO
+.Xr mklocale 1 ,
+.Xr setlocale 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3
diff --git a/usr.bin/colldef/data/Makefile b/usr.bin/colldef/data/Makefile
new file mode 100644
index 0000000..e4b6042
--- /dev/null
+++ b/usr.bin/colldef/data/Makefile
@@ -0,0 +1,72 @@
+# $Id: Makefile,v 1.8 1997/03/01 00:28:05 wosch Exp $
+
+NOMAN=YES
+CLEANFILES+= ${LOCALES:S/$/.out/g}
+
+LOCALES= de_DE.ISO_8859-1 \
+ es_ES.ISO_8859-1 \
+ is_IS.ISO_8859-1 \
+ lt_LN.ASCII \
+ lt_LN.ISO_8859-1 \
+ lt_LN.ISO_8859-2 \
+ ru_SU.CP866 \
+ ru_SU.KOI8-R
+
+LOCALEDIR= ${DESTDIR}/usr/share/locale
+
+.if exists(${.OBJDIR}/../colldef)
+COLLDEF=${.OBJDIR}/../colldef
+.else
+COLLDEF=${.CURDIR}/../colldef
+.endif
+
+ASCIILINKS = \
+ ko_KR.EUC ja_JP.EUC
+
+LATIN1LINKS = \
+ da_DK en_AU en_CA en_GB en_US fi_FI \
+ fr_BE fr_CA fr_CH fr_FR it_CH it_IT nl_BE nl_NL no_NO \
+ pt_PT sv_SE
+
+LATIN2LINKS = hr_HR
+
+DELINKS = de_AT de_CH
+
+.SUFFIXES: .src .out
+
+.src.out:
+ ${COLLDEF} -I ${.CURDIR} -o ${.TARGET} ${.IMPSRC}
+
+all: ${LOCALES:S/$/.out/g}
+
+ru_SU.KOI8-R.out: map.KOI8-R
+ru_SU.CP866.out: map.CP866
+lt_LN.ISO_8859-1.out: map.ISO_8859-1
+lt_LN.ISO_8859-2.out: map.ISO_8859-2
+es_ES.ISO_8859-1.out: map.ISO_8859-1
+de_DE.ISO_8859-1.out: map.ISO_8859-1
+
+afterinstall:
+.for locale in ${LOCALES}
+ ${INSTALL} -c -m 644 -o ${BINOWN} -g ${BINGRP} \
+ ${locale}.out ${LOCALEDIR}/${locale}/LC_COLLATE
+.endfor
+.for link in ${ASCIILINKS}
+ ln -fs ../lt_LN.ASCII/LC_COLLATE \
+ ${LOCALEDIR}/${link}/LC_COLLATE
+.endfor
+.for link in ${LATIN1LINKS}
+ ln -fs ../lt_LN.ISO_8859-1/LC_COLLATE \
+ ${LOCALEDIR}/${link}.ISO_8859-1/LC_COLLATE
+.endfor
+.for link in ${LATIN2LINKS}
+ ln -fs ../lt_LN.ISO_8859-2/LC_COLLATE \
+ ${LOCALEDIR}/${link}.ISO_8859-2/LC_COLLATE
+.endfor
+.for link in ${DELINKS}
+ ln -fs ../de_DE.ISO_8859-1/LC_COLLATE \
+ ${LOCALEDIR}/${link}.ISO_8859-1/LC_COLLATE
+.endfor
+
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/colldef/data/de_DE.ISO_8859-1.src b/usr.bin/colldef/data/de_DE.ISO_8859-1.src
new file mode 100644
index 0000000..c7afa46
--- /dev/null
+++ b/usr.bin/colldef/data/de_DE.ISO_8859-1.src
@@ -0,0 +1,38 @@
+# German/ISO 8859-1 (backward compatible with ASCII)
+#
+# $Id: de_DE.ISO_8859-1.src,v 1.3 1997/02/22 19:54:34 peter Exp $
+#
+charmap map.ISO_8859-1
+order \
+# controls
+ <NU>;...;<US>;<PA>;...;<AC>;\
+#
+ <NS>;<SP>;!;<!I>;\";<<<>;</>/>>;<Nb>;\
+ <Cu>;<Ct>;<DO>;<Pd>;<Ye>;\
+ %;&;<',>;';\(;\);*;+;<+->;<-:>;<*X>;\,;<-->;-;.;/;\
+# digits
+ (0,<14>,<12>,<34>);(1,<1S>);(2,<2S>);(3,<3S>);4;...;9;\
+#
+ :;\;;\<;=;>;?;<?I>;<SE>;<PI>;<Co>;<Rg>;<At>;\
+# capital
+ (A,<A'>,<A!>,<A/>>,<AA>,<A:>,<A?>,<AE>);\
+ B;(C,<C,>);D;(E,<E'>,<E!>,<E/>>,<E:>);\
+ F;G;H;(I,<I'>,<I!>,<I/>>,<I:>);\
+ J;...;M;(N,<N?>);(O,<O'>,<O!>,<O/>>,<O:>,<O?>,<O//>);\
+ P;...;T;(U,<U'>,<U!>,<U/>>,<U:>);\
+ V;W;X;(Y,<Y'>);Z;\
+ <D->;<TH>;\
+#
+ [;\\;];^;<':>;_;<'m>;<''>;`;\
+# small
+ (a,<a'>,<a!>,<a/>>,<aa>,<a:>,<a?>,<ae>);\
+ b;(c,<c,>);d;(e,<e'>,<e!>,<e/>>,<e:>);\
+ f;g;h;(i,<i'>,<i!>,<i/>>,<i:>);\
+ j;...;m;(n,<n?>);(o,<o'>,<o!>,<o/>>,<o:>,<o?>,<o//>);\
+ p;...;r;s;(<ss>,ss);t;(u,<u'>,<u!>,<u/>>,<u:>);\
+ v;w;x;(y,<y'>,<y:>);z;\
+ <d->;<th>;\
+#
+ \{;<NO>;|;<BB>;\};~;<.M>;<DG>;<My>;<DT>;\
+# remains
+ <-a>;<-o>
diff --git a/usr.bin/colldef/data/es_ES.ISO_8859-1.src b/usr.bin/colldef/data/es_ES.ISO_8859-1.src
new file mode 100644
index 0000000..e088e21
--- /dev/null
+++ b/usr.bin/colldef/data/es_ES.ISO_8859-1.src
@@ -0,0 +1,38 @@
+# Espan~ol (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.ISO_8859-1
+order \
+# controls
+ <NU>;...;<US>;<PA>;...;<AC>;\
+#
+ <NS>;<SP>;!;<!I>;\";<<<>;</>/>>;<Nb>;\
+ <Cu>;<Ct>;<DO>;<Pd>;<Ye>;\
+ %;&;<',>;';\(;\);*;+;<+->;<-:>;<*X>;\,;<-->;-;.;/;\
+# digits
+ (0,<14>,<12>,<34>);(1,<1S>);(2,<2S>);(3,<3S>);4;...;9;\
+#
+ :;\;;\<;=;>;?;<?I>;<SE>;<PI>;<Co>;<Rg>;<At>;\
+# capital
+ (A,<A'>,<A!>,<A/>>,<AA>,<A:>,<A?>,<AE>);\
+ B;(C,<C,>);{CH,Ch};D;(E,<E'>,<E!>,<E/>>,<E:>);\
+ F;G;H;(I,<I'>,<I!>,<I/>>,<I:>);\
+ J;...;K;L;{LL,Ll};M;(N,<N?>);(O,<O'>,<O!>,<O/>>,<O:>,<O?>,<O//>);\
+ P;Q;R;{RR,Rr};S;T;(U,<U'>,<U!>,<U/>>,<U:>);\
+ V;W;X;(Y,<Y'>);Z;\
+ <D->;<TH>;\
+#
+ [;\\;];^;<':>;_;<'m>;<''>;`;\
+# small
+ (a,<a'>,<a!>,<a/>>,<aa>,<a:>,<a?>,<ae>);\
+ b;(c,<c,>);ch;d;(e,<e'>,<e!>,<e/>>,<e:>);\
+ f;g;h;(i,<i'>,<i!>,<i/>>,<i:>);\
+ j;...;k;l;ll;m;(n,<n?>);(o,<o'>,<o!>,<o/>>,<o:>,<o?>,<o//>);\
+ p;q;r;rr;s;t;(u,<u'>,<u!>,<u/>>,<u:>);\
+ v;w;x;(y,<y'>,<y:>);z;\
+ <d->;<th>;<ss>;\
+#
+ \{;<NO>;|;<BB>;\};~;<.M>;<DG>;<My>;<DT>;\
+# remains
+ <-a>;<-o>
diff --git a/usr.bin/colldef/data/is_IS.ISO_8859-1.src b/usr.bin/colldef/data/is_IS.ISO_8859-1.src
new file mode 100644
index 0000000..288459c
--- /dev/null
+++ b/usr.bin/colldef/data/is_IS.ISO_8859-1.src
@@ -0,0 +1,38 @@
+# icelandic (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.ISO_8859-1
+order \
+# controls
+ <NU>;...;<US>;<PA>;...;<AC>;\
+#
+ <NS>;<SP>;!;<!I>;\";<<<>;</>/>>;<Nb>;\
+ <Cu>;<Ct>;<DO>;<Pd>;<Ye>;\
+ %;&;<',>;';\(;\);*;+;<+->;<-:>;<*X>;\,;<-->;-;.;/;\
+# digits
+ (0,<14>,<12>,<34>);(1,<1S>);(2,<2S>);(3,<3S>);4;...;9;\
+#
+ :;\;;\<;=;>;?;<?I>;<SE>;<PI>;<Co>;<Rg>;<At>;\
+# capital
+ (A,<A'>,<A!>,<A/>>,<AA>,<A:>,<A?>);\
+ B;(C,<C,>);(D,<D->);(E,<E'>,<E!>,<E/>>,<E:>);\
+ F;G;H;(I,<I'>,<I!>,<I/>>,<I:>);\
+ J;...;M;(N,<N?>);(O,<O'>,<O!>,<O/>>,<O?>,<O//>);\
+ P;...;T;(U,<U'>,<U!>,<U/>>,<U:>);\
+ V;W;X;(Y,<Y'>);Z;\
+ <TH>;<AE>;<O:>;\
+#
+ [;\\;];^;<':>;_;<'m>;<''>;`;\
+# small
+ (a,<a'>,<a!>,<a/>>,<aa>,<a:>,<a?>);\
+ b;(c,<c,>);(d,<d->);(e,<e'>,<e!>,<e/>>,<e:>);\
+ f;g;h;(i,<i'>,<i!>,<i/>>,<i:>);\
+ j;...;m;(n,<n?>);(o,<o'>,<o!>,<o/>>,<o?>,<o//>);\
+ p;...;t;(u,<u'>,<u!>,<u/>>,<u:>);\
+ v;w;x;(y,<y'>,<y:>);z;\
+ <th>;<ae>;<o:>;<ss>;\
+#
+ \{;<NO>;|;<BB>;\};~;<.M>;<DG>;<My>;<DT>;\
+# remains
+ <-a>;<-o>
diff --git a/usr.bin/colldef/data/lt_LN.ASCII.src b/usr.bin/colldef/data/lt_LN.ASCII.src
new file mode 100644
index 0000000..525ebb9
--- /dev/null
+++ b/usr.bin/colldef/data/lt_LN.ASCII.src
@@ -0,0 +1,6 @@
+# ASCII
+#
+# $Id: lt_LN.ISO_8859-1.src,v 1.8 1997/02/22 19:54:39 peter Exp $
+#
+order \
+ \x00;...;\xff
diff --git a/usr.bin/colldef/data/lt_LN.ISO_8859-1.src b/usr.bin/colldef/data/lt_LN.ISO_8859-1.src
new file mode 100644
index 0000000..93a2da0
--- /dev/null
+++ b/usr.bin/colldef/data/lt_LN.ISO_8859-1.src
@@ -0,0 +1,38 @@
+# latin1 (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.ISO_8859-1
+order \
+# controls
+ <NU>;...;<US>;<PA>;...;<AC>;\
+#
+ <NS>;<SP>;!;<!I>;\";<<<>;</>/>>;<Nb>;\
+ <Cu>;<Ct>;<DO>;<Pd>;<Ye>;\
+ %;&;<',>;';\(;\);*;+;<+->;<-:>;<*X>;\,;<-->;-;.;/;\
+# digits
+ (0,<14>,<12>,<34>);(1,<1S>);(2,<2S>);(3,<3S>);4;...;9;\
+#
+ :;\;;\<;=;>;?;<?I>;<SE>;<PI>;<Co>;<Rg>;<At>;\
+# capital
+ (A,<A'>,<A!>,<A/>>,<AA>,<A:>,<A?>,<AE>);\
+ B;(C,<C,>);D;(E,<E'>,<E!>,<E/>>,<E:>);\
+ F;G;H;(I,<I'>,<I!>,<I/>>,<I:>);\
+ J;...;M;(N,<N?>);(O,<O'>,<O!>,<O/>>,<O:>,<O?>,<O//>);\
+ P;...;T;(U,<U'>,<U!>,<U/>>,<U:>);\
+ V;W;X;(Y,<Y'>);Z;\
+ <D->;<TH>;\
+#
+ [;\\;];^;<':>;_;<'m>;<''>;`;\
+# small
+ (a,<a'>,<a!>,<a/>>,<aa>,<a:>,<a?>,<ae>);\
+ b;(c,<c,>);d;(e,<e'>,<e!>,<e/>>,<e:>);\
+ f;g;h;(i,<i'>,<i!>,<i/>>,<i:>);\
+ j;...;m;(n,<n?>);(o,<o'>,<o!>,<o/>>,<o:>,<o?>,<o//>);\
+ p;...;t;(u,<u'>,<u!>,<u/>>,<u:>);\
+ v;w;x;(y,<y'>,<y:>);z;\
+ <d->;<th>;<ss>;\
+#
+ \{;<NO>;|;<BB>;\};~;<.M>;<DG>;<My>;<DT>;\
+# remains
+ <-a>;<-o>
diff --git a/usr.bin/colldef/data/lt_LN.ISO_8859-2.src b/usr.bin/colldef/data/lt_LN.ISO_8859-2.src
new file mode 100644
index 0000000..772fe32
--- /dev/null
+++ b/usr.bin/colldef/data/lt_LN.ISO_8859-2.src
@@ -0,0 +1,36 @@
+# latin2 (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.ISO_8859-2
+order \
+# controls
+ <NU>;...;<US>;<PA>;...;<AC>;\
+#
+ <NS>;<SP>;!;\";<Nb>;\
+ <Cu>;<DO>;\
+ %;&;<',>;<';>;';\(;\);*;+;<-:>;<*X>;\,;<-->;-;.;<'.>;/;\
+# digits
+ 0;...;9;\
+#
+ :;\;;\<;=;>;?;<SE>;<At>;\
+# capital
+ (A,<A'>,<A/>>,<A:>,<A;>,<A(>);\
+ B;(C,<C,>,<C'>,<C<>);(D,<D<>,<D//>);(E,<E'>,<E:>,<E;>,<E<>);\
+ F;G;H;(I,<I'>,<I/>>);\
+ J;K;(L,<L//>,<L<>,<L'>);M;(N,<N'>,<N<>);(O,<O'>,<O/>>,<O:>,<O">);\
+ P;Q;(R,<R'>,<R<>);(S,<S'>,<S<>,<S,>);(T,<T<>,<T,>);\
+ (U,<U'>,<U:>,<U0>,<U">);\
+ V;W;X;(Y,<Y'>);(Z,<Z'>,<Z<>,<Z.>);\
+#
+ [;\\;];^;<':>;<'">;<'<>;<'(>;_;<''>;`;\
+# small
+ (a,<a'>,<a/>>,<a:>,<a;>,<a(>);\
+ b;(c,<c,>,<c'>,<c<>);(d,<d<>,<d//>);(e,<e'>,<e:>,<e;>,<e<>);\
+ f;g;h;(i,<i'>,<i/>>);\
+ j;k;(l,<l//>,<l<>,<l'>);m;(n,<n'>,<n<>);(o,<o'>,<o/>>,<o:>,<o">);\
+ p;q;(r,<r'>,<r<>);(s,<s'>,<s<>,<s,>,<ss>);(t,<t<>,<t,>);\
+ (u,<u'>,<u:>,<u0>,<u">);\
+ v;w;x;(y,<y'>);(z,<z'>,<z<>,<z.>);\
+#
+ \{;|;\};~;<DG>;<DT>
diff --git a/usr.bin/colldef/data/map.CP866 b/usr.bin/colldef/data/map.CP866
new file mode 100644
index 0000000..0311771
--- /dev/null
+++ b/usr.bin/colldef/data/map.CP866
@@ -0,0 +1,174 @@
+NU \x00
+SH \x01
+SX \x02
+EX \x03
+ET \x04
+EQ \x05
+AK \x06
+BL \x07
+BS \x08
+HT \x09
+LF \x0a
+VT \x0b
+FF \x0c
+CR \x0d
+SO \x0e
+SI \x0f
+DL \x10
+D1 \x11
+D2 \x12
+D3 \x13
+D4 \x14
+NK \x15
+SY \x16
+EB \x17
+CN \x18
+EM \x19
+SB \x1a
+EC \x1b
+FS \x1c
+GS \x1d
+RS \x1e
+US \x1f
+SP \x20
+Nb \x23
+DO \x24
+At \x40
+<( \x5b
+// \x5c
+)> \x5d
+'> \x5e
+'! \x60
+(! \x7b
+!! \x7c
+!) \x7d
+'? \x7e
+DT \x7f
+hh \xc4
+vv \xb3
+dr \xda
+dl \xbf
+ur \xc0
+ul \xd9
+vr \xc3
+vl \xb4
+dh \xc2
+uh \xc1
+vh \xc5
+TB \xdf
+LB \xdc
+FB \xdb
+lB \xdd
+RB \xde
+.S \xb0
+:S \xb1
+?S \xb2
+Iu \xf4
+fS \xfe
+sb \xf9
+RT \xfb
+?2 \xf7
+=< \xf3
+>= \xf2
+NS \xff
+Il \xf5
+DG \xf8
+2S \xfd
+.M \xfa
+-: \xf6
+HH \xcd
+VV \xba
+dR \xd5
+io \xf1
+Dr \xd6
+DR \xc9
+dL \xb8
+Dl \xb7
+LD \xbb
+uR \xd4
+Ur \xd3
+UR \xc8
+uL \xbe
+Ul \xbd
+UL \xbc
+vR \xc6
+Vr \xc7
+VR \xcc
+vL \xb5
+IO \xf0
+Vl \xb6
+VL \xb9
+dH \xd1
+Dh \xd2
+DH \xcb
+uH \xcf
+Uh \xd0
+UH \xca
+vH \xd8
+Vh \xd7
+VH \xce
+Co \xfc
+ju \xee
+a= \xa0
+b= \xa1
+c= \xe6
+d= \xa4
+e= \xa5
+f= \xe4
+g= \xa3
+h= \xe5
+i= \xa8
+j= \xa9
+k= \xaa
+l= \xab
+m= \xac
+n= \xad
+o= \xae
+p= \xaf
+ja \xef
+r= \xe0
+s= \xe1
+t= \xe2
+u= \xe3
+z% \xa6
+v= \xa2
+%' \xec
+y= \xeb
+z= \xa7
+s% \xe8
+je \xed
+sc \xe9
+c% \xe7
+=' \xea
+JU \x9e
+A= \x80
+B= \x81
+C= \x96
+D= \x84
+E= \x85
+F= \x94
+G= \x83
+H= \x95
+I= \x88
+J= \x89
+K= \x8a
+L= \x8b
+M= \x8c
+N= \x8d
+O= \x8e
+P= \x8f
+JA \x9f
+R= \x90
+S= \x91
+T= \x92
+U= \x93
+Z% \x86
+V= \x82
+%" \x9c
+Y= \x9b
+Z= \x87
+S% \x98
+JE \x9d
+Sc \x99
+C% \x97
+=" \x9a
diff --git a/usr.bin/colldef/data/map.ISO_8859-1 b/usr.bin/colldef/data/map.ISO_8859-1
new file mode 100644
index 0000000..ee5a557
--- /dev/null
+++ b/usr.bin/colldef/data/map.ISO_8859-1
@@ -0,0 +1,174 @@
+NU \x00
+SH \x01
+SX \x02
+EX \x03
+ET \x04
+EQ \x05
+AK \x06
+BL \x07
+BS \x08
+HT \x09
+LF \x0a
+VT \x0b
+FF \x0c
+CR \x0d
+SO \x0e
+SI \x0f
+DL \x10
+D1 \x11
+D2 \x12
+D3 \x13
+D4 \x14
+NK \x15
+SY \x16
+EB \x17
+CN \x18
+EM \x19
+SB \x1a
+EC \x1b
+FS \x1c
+GS \x1d
+RS \x1e
+US \x1f
+SP \x20
+Nb \x23
+DO \x24
+At \x40
+<( \x5b
+// \x5c
+)> \x5d
+'> \x5e
+'! \x60
+(! \x7b
+!! \x7c
+!) \x7d
+'? \x7e
+DT \x7f
+PA \x80
+HO \x81
+BH \x82
+NH \x83
+IN \x84
+NL \x85
+SA \x86
+ES \x87
+HS \x88
+HJ \x89
+VS \x8a
+PD \x8b
+PU \x8c
+RI \x8d
+S2 \x8e
+S3 \x8f
+DC \x90
+P1 \x91
+P2 \x92
+TS \x93
+CC \x94
+MW \x95
+SG \x96
+EG \x97
+SS \x98
+GC \x99
+SC \x9a
+CI \x9b
+ST \x9c
+OC \x9d
+PM \x9e
+AC \x9f
+NS \xa0
+!I \xa1
+Ct \xa2
+Pd \xa3
+Cu \xa4
+Ye \xa5
+BB \xa6
+SE \xa7
+': \xa8
+Co \xa9
+-a \xaa
+<< \xab
+NO \xac
+-- \xad
+Rg \xae
+'m \xaf
+DG \xb0
++- \xb1
+2S \xb2
+3S \xb3
+'' \xb4
+My \xb5
+PI \xb6
+.M \xb7
+', \xb8
+1S \xb9
+-o \xba
+>> \xbb
+14 \xbc
+12 \xbd
+34 \xbe
+?I \xbf
+A! \xc0
+A' \xc1
+A> \xc2
+A? \xc3
+A: \xc4
+AA \xc5
+AE \xc6
+C, \xc7
+E! \xc8
+E' \xc9
+E> \xca
+E: \xcb
+I! \xcc
+I' \xcd
+I> \xce
+I: \xcf
+D- \xd0
+N? \xd1
+O! \xd2
+O' \xd3
+O> \xd4
+O? \xd5
+O: \xd6
+*X \xd7
+O/ \xd8
+U! \xd9
+U' \xda
+U> \xdb
+U: \xdc
+Y' \xdd
+TH \xde
+ss \xdf
+a! \xe0
+a' \xe1
+a> \xe2
+a? \xe3
+a: \xe4
+aa \xe5
+ae \xe6
+c, \xe7
+e! \xe8
+e' \xe9
+e> \xea
+e: \xeb
+i! \xec
+i' \xed
+i> \xee
+i: \xef
+d- \xf0
+n? \xf1
+o! \xf2
+o' \xf3
+o> \xf4
+o? \xf5
+o: \xf6
+-: \xf7
+o/ \xf8
+u! \xf9
+u' \xfa
+u> \xfb
+u: \xfc
+y' \xfd
+th \xfe
+y: \xff
diff --git a/usr.bin/colldef/data/map.ISO_8859-2 b/usr.bin/colldef/data/map.ISO_8859-2
new file mode 100644
index 0000000..75f2013
--- /dev/null
+++ b/usr.bin/colldef/data/map.ISO_8859-2
@@ -0,0 +1,174 @@
+NU \x00
+SH \x01
+SX \x02
+EX \x03
+ET \x04
+EQ \x05
+AK \x06
+BL \x07
+BS \x08
+HT \x09
+LF \x0a
+VT \x0b
+FF \x0c
+CR \x0d
+SO \x0e
+SI \x0f
+DL \x10
+D1 \x11
+D2 \x12
+D3 \x13
+D4 \x14
+NK \x15
+SY \x16
+EB \x17
+CN \x18
+EM \x19
+SB \x1a
+EC \x1b
+FS \x1c
+GS \x1d
+RS \x1e
+US \x1f
+SP \x20
+Nb \x23
+DO \x24
+At \x40
+<( \x5b
+// \x5c
+)> \x5d
+'> \x5e
+'! \x60
+(! \x7b
+!! \x7c
+!) \x7d
+'? \x7e
+DT \x7f
+PA \x80
+HO \x81
+BH \x82
+NH \x83
+IN \x84
+NL \x85
+SA \x86
+ES \x87
+HS \x88
+HJ \x89
+VS \x8a
+PD \x8b
+PU \x8c
+RI \x8d
+S2 \x8e
+S3 \x8f
+DC \x90
+P1 \x91
+P2 \x92
+TS \x93
+CC \x94
+MW \x95
+SG \x96
+EG \x97
+SS \x98
+GC \x99
+SC \x9a
+CI \x9b
+ST \x9c
+OC \x9d
+PM \x9e
+AC \x9f
+NS \xa0
+A; \xa1
+'( \xa2
+L/ \xa3
+Cu \xa4
+L< \xa5
+S' \xa6
+SE \xa7
+': \xa8
+S< \xa9
+S, \xaa
+T< \xab
+Z' \xac
+-- \xad
+Z< \xae
+Z. \xaf
+DG \xb0
+a; \xb1
+'; \xb2
+l/ \xb3
+'' \xb4
+l< \xb5
+s' \xb6
+'< \xb7
+', \xb8
+s< \xb9
+s, \xba
+t< \xbb
+z' \xbc
+'" \xbd
+z< \xbe
+z. \xbf
+R' \xc0
+A' \xc1
+A> \xc2
+A( \xc3
+A: \xc4
+L' \xc5
+C' \xc6
+C, \xc7
+C< \xc8
+E' \xc9
+E; \xca
+E: \xcb
+E< \xcc
+I' \xcd
+I> \xce
+D< \xcf
+D/ \xd0
+N' \xd1
+N< \xd2
+O' \xd3
+O> \xd4
+O" \xd5
+O: \xd6
+*X \xd7
+R< \xd8
+U0 \xd9
+U' \xda
+U" \xdb
+U: \xdc
+Y' \xdd
+T, \xde
+ss \xdf
+r' \xe0
+a' \xe1
+a> \xe2
+a( \xe3
+a: \xe4
+l' \xe5
+c' \xe6
+c, \xe7
+c< \xe8
+e' \xe9
+e; \xea
+e: \xeb
+e< \xec
+i' \xed
+i> \xee
+d< \xef
+d/ \xf0
+n' \xf1
+n< \xf2
+o' \xf3
+o> \xf4
+o" \xf5
+o: \xf6
+-: \xf7
+r< \xf8
+u0 \xf9
+u' \xfa
+u" \xfb
+u: \xfc
+y' \xfd
+t, \xfe
+'. \xff
diff --git a/usr.bin/colldef/data/map.KOI8-R b/usr.bin/colldef/data/map.KOI8-R
new file mode 100644
index 0000000..180568f
--- /dev/null
+++ b/usr.bin/colldef/data/map.KOI8-R
@@ -0,0 +1,174 @@
+NU \x00
+SH \x01
+SX \x02
+EX \x03
+ET \x04
+EQ \x05
+AK \x06
+BL \x07
+BS \x08
+HT \x09
+LF \x0a
+VT \x0b
+FF \x0c
+CR \x0d
+SO \x0e
+SI \x0f
+DL \x10
+D1 \x11
+D2 \x12
+D3 \x13
+D4 \x14
+NK \x15
+SY \x16
+EB \x17
+CN \x18
+EM \x19
+SB \x1a
+EC \x1b
+FS \x1c
+GS \x1d
+RS \x1e
+US \x1f
+SP \x20
+Nb \x23
+DO \x24
+At \x40
+<( \x5b
+// \x5c
+)> \x5d
+'> \x5e
+'! \x60
+(! \x7b
+!! \x7c
+!) \x7d
+'? \x7e
+DT \x7f
+hh \x80
+vv \x81
+dr \x82
+dl \x83
+ur \x84
+ul \x85
+vr \x86
+vl \x87
+dh \x88
+uh \x89
+vh \x8a
+TB \x8b
+LB \x8c
+FB \x8d
+lB \x8e
+RB \x8f
+.S \x90
+:S \x91
+?S \x92
+Iu \x93
+fS \x94
+sb \x95
+RT \x96
+?2 \x97
+=< \x98
+>= \x99
+NS \x9a
+Il \x9b
+DG \x9c
+2S \x9d
+.M \x9e
+-: \x9f
+HH \xa0
+VV \xa1
+dR \xa2
+io \xa3
+Dr \xa4
+DR \xa5
+dL \xa6
+Dl \xa7
+LD \xa8
+uR \xa9
+Ur \xaa
+UR \xab
+uL \xac
+Ul \xad
+UL \xae
+vR \xaf
+Vr \xb0
+VR \xb1
+vL \xb2
+IO \xb3
+Vl \xb4
+VL \xb5
+dH \xb6
+Dh \xb7
+DH \xb8
+uH \xb9
+Uh \xba
+UH \xbb
+vH \xbc
+Vh \xbd
+VH \xbe
+Co \xbf
+ju \xc0
+a= \xc1
+b= \xc2
+c= \xc3
+d= \xc4
+e= \xc5
+f= \xc6
+g= \xc7
+h= \xc8
+i= \xc9
+j= \xca
+k= \xcb
+l= \xcc
+m= \xcd
+n= \xce
+o= \xcf
+p= \xd0
+ja \xd1
+r= \xd2
+s= \xd3
+t= \xd4
+u= \xd5
+z% \xd6
+v= \xd7
+%' \xd8
+y= \xd9
+z= \xda
+s% \xdb
+je \xdc
+sc \xdd
+c% \xde
+=' \xdf
+JU \xe0
+A= \xe1
+B= \xe2
+C= \xe3
+D= \xe4
+E= \xe5
+F= \xe6
+G= \xe7
+H= \xe8
+I= \xe9
+J= \xea
+K= \xeb
+L= \xec
+M= \xed
+N= \xee
+O= \xef
+P= \xf0
+JA \xf1
+R= \xf2
+S= \xf3
+T= \xf4
+U= \xf5
+Z% \xf6
+V= \xf7
+%" \xf8
+Y= \xf9
+Z= \xfa
+S% \xfb
+JE \xfc
+Sc \xfd
+C% \xfe
+=" \xff
diff --git a/usr.bin/colldef/data/ru_SU.CP866.src b/usr.bin/colldef/data/ru_SU.CP866.src
new file mode 100644
index 0000000..88ca377
--- /dev/null
+++ b/usr.bin/colldef/data/ru_SU.CP866.src
@@ -0,0 +1,39 @@
+# CP866 (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.CP866
+order \
+# controls
+ <NU>;...;<US>;\
+#
+ <NS>;<SP>;!;\";<Nb>;<DO>;\
+ %;&;';\(;\);*;+;<-:>;\,;-;.;/;\
+# digits
+ 0;1;(2,<2S>);3;...;9;\
+#
+ :;\;;\<;<=<>;=;</>=>;>;?;<Co>;<At>;\
+# capital
+ A;...;Z;\
+ <A=>;<B=>;<V=>;<G=>;<D=>;<E=>;<IO>;<Z%>;<Z=>;\
+ <I=>;<J=>;<K=>;<L=>;<M=>;<N=>;<O=>;<P=>;<R=>;\
+ <S=>;<T=>;<U=>;<F=>;<H=>;<C=>;<C%>;<S%>;<Sc>;\
+ <=">;<Y=>;<%">;<JE>;<JU>;<JA>;\
+#
+ [;\\;];^;_;`;\
+# small
+ a;...;z;\
+ <a=>;<b=>;<v=>;<g=>;<d=>;<e=>;<io>;<z%>;<z=>;\
+ <i=>;<j=>;<k=>;<l=>;<m=>;<n=>;<o=>;<p=>;<r=>;\
+ <s=>;<t=>;<u=>;<f=>;<h=>;<c=>;<c%>;<s%>;<sc>;\
+ <='>;<y=>;<%'>;<je>;<ju>;<ja>;\
+#
+ \{;|;\};~;<.M>;<DG>;<DT>;\
+#
+ <sb>;<RT>;<?2>;<Iu>;<Il>;\
+ <hh>;<HH>;<vv>;<VV>;<dr>;<dR>;<Dr>;<DR>;\
+ <dl>;<dL>;<Dl>;<LD>;<ur>;<uR>;<Ur>;<UR>;\
+ <ul>;<uL>;<Ul>;<UL>;<vr>;<vR>;<Vr>;<VR>;\
+ <vl>;<vL>;<Vl>;<VL>;<dh>;<dH>;<Dh>;<DH>;\
+ <uh>;<uH>;<Uh>;<UH>;<vh>;<vH>;<Vh>;<VH>;\
+ <TB>;<LB>;<FB>;<lB>;<RB>;<.S>;<:S>;<?S>;<fS>
diff --git a/usr.bin/colldef/data/ru_SU.KOI8-R.src b/usr.bin/colldef/data/ru_SU.KOI8-R.src
new file mode 100644
index 0000000..f6b0a18
--- /dev/null
+++ b/usr.bin/colldef/data/ru_SU.KOI8-R.src
@@ -0,0 +1,39 @@
+# koi8-r (backward compatible with ASCII)
+#
+# $Id$
+#
+charmap map.KOI8-R
+order \
+# controls
+ <NU>;...;<US>;\
+#
+ <NS>;<SP>;!;\";<Nb>;<DO>;\
+ %;&;';\(;\);*;+;<-:>;\,;-;.;/;\
+# digits
+ 0;1;(2,<2S>);3;...;9;\
+#
+ :;\;;\<;<=<>;=;</>=>;>;?;<Co>;<At>;\
+# capital
+ A;...;Z;\
+ <A=>;<B=>;<V=>;<G=>;<D=>;<E=>;<IO>;<Z%>;<Z=>;\
+ <I=>;<J=>;<K=>;<L=>;<M=>;<N=>;<O=>;<P=>;<R=>;\
+ <S=>;<T=>;<U=>;<F=>;<H=>;<C=>;<C%>;<S%>;<Sc>;\
+ <=">;<Y=>;<%">;<JE>;<JU>;<JA>;\
+#
+ [;\\;];^;_;`;\
+# small
+ a;...;z;\
+ <a=>;<b=>;<v=>;<g=>;<d=>;<e=>;<io>;<z%>;<z=>;\
+ <i=>;<j=>;<k=>;<l=>;<m=>;<n=>;<o=>;<p=>;<r=>;\
+ <s=>;<t=>;<u=>;<f=>;<h=>;<c=>;<c%>;<s%>;<sc>;\
+ <='>;<y=>;<%'>;<je>;<ju>;<ja>;\
+#
+ \{;|;\};~;<.M>;<DG>;<DT>;\
+#
+ <sb>;<RT>;<?2>;<Iu>;<Il>;\
+ <hh>;<HH>;<vv>;<VV>;<dr>;<dR>;<Dr>;<DR>;\
+ <dl>;<dL>;<Dl>;<LD>;<ur>;<uR>;<Ur>;<UR>;\
+ <ul>;<uL>;<Ul>;<UL>;<vr>;<vR>;<Vr>;<VR>;\
+ <vl>;<vL>;<Vl>;<VL>;<dh>;<dH>;<Dh>;<DH>;\
+ <uh>;<uH>;<Uh>;<UH>;<vh>;<vH>;<Vh>;<VH>;\
+ <TB>;<LB>;<FB>;<lB>;<RB>;<.S>;<:S>;<?S>;<fS>
diff --git a/usr.bin/colldef/en_DK.example b/usr.bin/colldef/en_DK.example
new file mode 100644
index 0000000..c6777d2
--- /dev/null
+++ b/usr.bin/colldef/en_DK.example
@@ -0,0 +1,3073 @@
+escape_char /
+comment_char %
+
+% English language locale for Denmark
+%
+% Written according to POSIX.2
+% ISO/IEC 9945-2:1993 specifications
+%
+% Source: Danish Standards Association
+% Address: Baunegaardsvej 73,
+% DK-2900 Hellerup, Danmark
+% Contact: Keld Simonsen
+% Email: Keld.Simonsen@dkuug.dk
+% Tel: +45 - 39770101
+% Fax: +45 - 39770202
+% Language: en
+% Territory: DK
+% Revision: 3.3
+% Date: 1994-03-22
+% Application: general
+% Users: general
+% Repertoiremap: mnemonic.ds
+% Charset: ISO_8859-1:1987
+% Distribution and use is free, also for
+% commercial purposes.
+
+LC_COLLATE
+
+% Base collation scheme: 1994-03-22
+
+% Ordering algorithm:
+% 1. Spaces and hyphen (but not soft
+% hyphen) before punctuation
+% characters, punctuation characters
+% before numbers,
+% numbers before letters.
+% 2. Letters with diacritical marks are
+% members of equivalence classes
+% 3. A distinction is made with regards
+% to case as noted below.
+% 4. Special characters are ignored
+% when comparing letters, but then
+% they are considered
+% 5. The alphabets are sorted in order
+% of first appearance in ISO 10646:
+% Latin, Greek, Cyrillic, etc.
+%
+% According to Greek specifications,
+% the steps 2. and 3. above are reversed
+% for the Greek script
+
+% collating symbols
+
+% The collating symbol naming is
+% mostly taken from ISO 10646-1,
+% for example the case and accent
+% names are from this standard.
+
+collating-symbol <CAPITAL>
+collating-symbol <CAPITAL-SMALL>
+collating-symbol <SMALL-CAPITAL>
+collating-symbol <SMALL>
+
+% <CAPITAL-SMALL> and <SMALL-CAPITAL>
+% are for cases like Danish <A><a>
+% and Spanish <C><h> being treated
+% as one letter.
+
+% The <a8> ...... <z8> collating
+% symbols have defined weights as
+% the last character in a group of
+% Latin letters. They are used
+% to specify deltas by locales using
+% a locale as the default ordering
+% and by "replace-after" statements
+% specifying the changed placement
+% in an ordering of a character.
+
+collating-symbol <a8>
+collating-symbol <b8>
+collating-symbol <c8>
+collating-symbol <d8>
+collating-symbol <e8>
+collating-symbol <f8>
+collating-symbol <g8>
+collating-symbol <h8>
+collating-symbol <i8>
+collating-symbol <j8>
+collating-symbol <k8>
+collating-symbol <l8>
+collating-symbol <m8>
+collating-symbol <n8>
+collating-symbol <o8>
+collating-symbol <p8>
+collating-symbol <q8>
+collating-symbol <r8>
+collating-symbol <s8>
+collating-symbol <t8>
+collating-symbol <u8>
+collating-symbol <v8>
+collating-symbol <w8>
+collating-symbol <x8>
+collating-symbol <y8>
+collating-symbol <z8>
+
+collating-symbol <NONE>
+collating-symbol <ACUTE>
+collating-symbol <ACUTE+DOT>
+collating-symbol <GRAVE>
+collating-symbol <DOUBLE-GRAVE>
+collating-symbol <BREVE>
+collating-symbol <BREVE+ACUTE>
+collating-symbol <BREVE+GRAVE>
+collating-symbol <BREVE+MACRON>
+collating-symbol <BREVE+HOOK>
+collating-symbol <BREVE+TILDE>
+collating-symbol <BREVE+DOT-BELOW>
+collating-symbol <BREVE-BELOW>
+collating-symbol <INVERTED-BREVE>
+collating-symbol <CIRCUMFLEX>
+collating-symbol <CIRCUMFLEX+ACUTE>
+collating-symbol <CIRCUMFLEX+GRAVE>
+collating-symbol <CIRCUMFLEX+HOOK>
+collating-symbol <CIRCUMFLEX+TILDE>
+collating-symbol <CIRCUMFLEX+DOT-BELOW>
+collating-symbol <CARON>
+collating-symbol <CARON+DIAERESIS>
+collating-symbol <CARON+DOT>
+collating-symbol <RING>
+collating-symbol <RING+ACUTE>
+collating-symbol <RING-BELOW>
+collating-symbol <DIAERESIS>
+collating-symbol <DIAERESIS+MACRON>
+collating-symbol <DIAERESIS+ACUTE>
+collating-symbol <DIAERESIS+GRAVE>
+collating-symbol <DIAERESIS+CARON>
+collating-symbol <DOUBLE-ACUTE>
+collating-symbol <HOOK>
+collating-symbol <TILDE>
+collating-symbol <TILDE+ACUTE>
+collating-symbol <TILDE+DIAERESIS>
+collating-symbol <TILDE-BELOW>
+collating-symbol <DOT>
+collating-symbol <DOT-BELOW>
+collating-symbol <DOT+DOT-BELOW>
+collating-symbol <STROKE>
+collating-symbol <STROKE+ACUTE>
+collating-symbol <CEDILLA>
+collating-symbol <CEDILLA+ACUTE>
+collating-symbol <CEDILLA+GRAVE>
+collating-symbol <CEDILLA+BREVE>
+collating-symbol <OGONEK>
+collating-symbol <OGONEK+MACRON>
+collating-symbol <MACRON>
+collating-symbol <MACRON+ACUTE>
+collating-symbol <MACRON+GRAVE>
+collating-symbol <MACRON+DIAERESIS>
+collating-symbol <MACRON+DIAERESIS-BELOW>
+collating-symbol <MACRON+DOT>
+collating-symbol <MACRON+DOT-BELOW>
+collating-symbol <MACRON+CIRCUMFLEX>
+collating-symbol <LINE-BELOW>
+collating-symbol <HORN>
+collating-symbol <HORN+ACUTE>
+collating-symbol <HORN+GRAVE>
+collating-symbol <HORN+HOOK>
+collating-symbol <HORN+TILDE>
+collating-symbol <HORN+DOT-BELOW>
+collating-symbol <PRECEDED-BY-APOSTROPHE>
+collating-symbol <GREEK>
+collating-symbol <TONOS>
+collating-symbol <DIALYTICA>
+collating-symbol <DIALYTICA+TONOS>
+collating-symbol <CYRILLIC>
+collating-symbol <HIRAGANA>
+collating-symbol <KATAKANA>
+collating-symbol <SPECIAL>
+
+% letter;accent;case;specials
+
+order_start forward;backward/
+ ;forward;position
+
+% <CAPITAL> or <SMALL> letters first:
+
+<CAPITAL>
+<CAPITAL-SMALL>
+<SMALL-CAPITAL>
+<SMALL>
+
+% Accents:
+
+<NONE>
+<ACUTE>
+<ACUTE+DOT>
+<GRAVE>
+<DOUBLE-GRAVE>
+<BREVE>
+<BREVE+ACUTE>
+<BREVE+GRAVE>
+<BREVE+MACRON>
+<BREVE+HOOK>
+<BREVE+TILDE>
+<BREVE+DOT-BELOW>
+<BREVE-BELOW>
+<INVERTED-BREVE>
+<CIRCUMFLEX>
+<CIRCUMFLEX+ACUTE>
+<CIRCUMFLEX+GRAVE>
+<CIRCUMFLEX+HOOK>
+<CIRCUMFLEX+TILDE>
+<CIRCUMFLEX+DOT-BELOW>
+<CARON>
+<CARON+DIAERESIS>
+<CARON+DOT>
+<RING>
+<RING+ACUTE>
+<RING-BELOW>
+<DIAERESIS>
+<DIAERESIS+MACRON>
+<DIAERESIS+ACUTE>
+<DIAERESIS+GRAVE>
+<DIAERESIS+CARON>
+<DOUBLE-ACUTE>
+<HOOK>
+<TILDE>
+<TILDE+ACUTE>
+<TILDE+DIAERESIS>
+<TILDE-BELOW>
+<DOT>
+<DOT-BELOW>
+<DOT+DOT-BELOW>
+<STROKE>
+<STROKE+ACUTE>
+<CEDILLA>
+<CEDILLA+ACUTE>
+<CEDILLA+GRAVE>
+<CEDILLA+BREVE>
+<OGONEK>
+<OGONEK+MACRON>
+<MACRON>
+<MACRON+ACUTE>
+<MACRON+GRAVE>
+<MACRON+DIAERESIS>
+<MACRON+DIAERESIS-BELOW>
+<MACRON+DOT>
+<MACRON+DOT-BELOW>
+<MACRON+CIRCUMFLEX>
+<LINE-BELOW>
+<HORN>
+<HORN+ACUTE>
+<HORN+GRAVE>
+<HORN+HOOK>
+<HORN+TILDE>
+<HORN+DOT-BELOW>
+<PRECEDED-BY-APOSTROPHE>
+<GREEK>
+<TONOS>
+<DIALYTICA>
+<DIALYTICA+TONOS>
+<CYRILLIC>
+<HIRAGANA>
+<KATAKANA>
+<SPECIAL>
+
+<NS> <NS>;<NS>;<NS>;IGNORE
+<SP> IGNORE;IGNORE;IGNORE;<SP>
+<HT> IGNORE;IGNORE;IGNORE;<HT>
+<VT> IGNORE;IGNORE;IGNORE;<VT>
+<CR> IGNORE;IGNORE;IGNORE;<CR>
+<LF> IGNORE;IGNORE;IGNORE;<LF>
+<FF> IGNORE;IGNORE;IGNORE;<FF>
+<_> IGNORE;IGNORE;IGNORE;<_>
+<'m> IGNORE;IGNORE;IGNORE;<'m>
+<--> IGNORE;IGNORE;IGNORE;<-->
+<-> IGNORE;IGNORE;IGNORE;<->
+<,> IGNORE;IGNORE;IGNORE;<,>
+<;> IGNORE;IGNORE;IGNORE;<;>
+<:> IGNORE;IGNORE;IGNORE;<:>
+<!> IGNORE;IGNORE;IGNORE;<!>
+<!I> IGNORE;IGNORE;IGNORE;<!I>
+<?> IGNORE;IGNORE;IGNORE;<?>
+<?I> IGNORE;IGNORE;IGNORE;<?I>
+<//> IGNORE;IGNORE;IGNORE;<//>
+<.> IGNORE;IGNORE;IGNORE;<.>
+<''> IGNORE;IGNORE;IGNORE;<''>
+<'!> IGNORE;IGNORE;IGNORE;<'!>
+<'/>> IGNORE;IGNORE;IGNORE;<'/>>
+<':> IGNORE;IGNORE;IGNORE;<':>
+<'?> IGNORE;IGNORE;IGNORE;<'?>
+<.M> IGNORE;IGNORE;IGNORE;<.M>
+<',> IGNORE;IGNORE;IGNORE;<',>
+<'> IGNORE;IGNORE;IGNORE;<'>
+<'6> IGNORE;IGNORE;IGNORE;<'6>
+<'9> IGNORE;IGNORE;IGNORE;<'9>
+<"> IGNORE;IGNORE;IGNORE;<">
+<"6> IGNORE;IGNORE;IGNORE;<"6>
+<"9> IGNORE;IGNORE;IGNORE;<"9>
+<<<> IGNORE;IGNORE;IGNORE;<<<>
+</>/>> IGNORE;IGNORE;IGNORE;</>/>>
+<(> IGNORE;IGNORE;IGNORE;<(>
+<(S> IGNORE;IGNORE;IGNORE;<(S>
+<)> IGNORE;IGNORE;IGNORE;<)>
+<)S> IGNORE;IGNORE;IGNORE;<)S>
+<<(> IGNORE;IGNORE;IGNORE;<<(>
+<)/>> IGNORE;IGNORE;IGNORE;<)/>>
+<(!> IGNORE;IGNORE;IGNORE;<(!>
+<!)> IGNORE;IGNORE;IGNORE;<!)>
+<SE> IGNORE;IGNORE;IGNORE;<SE>
+<PI> IGNORE;IGNORE;IGNORE;<PI>
+<Co> IGNORE;IGNORE;IGNORE;<Co>
+<Rg> IGNORE;IGNORE;IGNORE;<Rg>
+<At> IGNORE;IGNORE;IGNORE;<At>
+<Cu> IGNORE;IGNORE;IGNORE;<Cu>
+<Ct> IGNORE;IGNORE;IGNORE;<Ct>
+<DO> IGNORE;IGNORE;IGNORE;<DO>
+<Pd> IGNORE;IGNORE;IGNORE;<Pd>
+<Ye> IGNORE;IGNORE;IGNORE;<Ye>
+<*> IGNORE;IGNORE;IGNORE;<*>
+<////> IGNORE;IGNORE;IGNORE;<////>
+<&> IGNORE;IGNORE;IGNORE;<&>
+<Nb> IGNORE;IGNORE;IGNORE;<Nb>
+<%> IGNORE;IGNORE;IGNORE;<%>
+<-S> IGNORE;IGNORE;IGNORE;<-S>
+<+> IGNORE;IGNORE;IGNORE;<+>
+<+S> IGNORE;IGNORE;IGNORE;<+S>
+<+-> IGNORE;IGNORE;IGNORE;<+->
+<-:> IGNORE;IGNORE;IGNORE;<-:>
+<*X> IGNORE;IGNORE;IGNORE;<*X>
+<!=> IGNORE;IGNORE;IGNORE;<!=>
+<<> IGNORE;IGNORE;IGNORE;<<>
+<=<> IGNORE;IGNORE;IGNORE;<=<>
+<=> IGNORE;IGNORE;IGNORE;<=>
+</>=> IGNORE;IGNORE;IGNORE;</>=>
+</>> IGNORE;IGNORE;IGNORE;</>>
+<NO> IGNORE;IGNORE;IGNORE;<NO>
+<!!> IGNORE;IGNORE;IGNORE;<!!>
+<BB> IGNORE;IGNORE;IGNORE;<BB>
+<DG> IGNORE;IGNORE;IGNORE;<DG>
+<My> IGNORE;IGNORE;IGNORE;<My>
+<'<> IGNORE;IGNORE;IGNORE;<'<>
+<'(> IGNORE;IGNORE;IGNORE;<'(>
+<'.> IGNORE;IGNORE;IGNORE;<'.>
+<'0> IGNORE;IGNORE;IGNORE;<'0>
+<';> IGNORE;IGNORE;IGNORE;<';>
+<1?> IGNORE;IGNORE;IGNORE;<1?>
+<'"> IGNORE;IGNORE;IGNORE;<'">
+<'G> IGNORE;IGNORE;IGNORE;<'G>
+<,G> IGNORE;IGNORE;IGNORE;<,G>
+<j3> IGNORE;IGNORE;IGNORE;<j3>
+<?%> IGNORE;IGNORE;IGNORE;<?%>
+<'*> IGNORE;IGNORE;IGNORE;<'*>
+<'%> IGNORE;IGNORE;IGNORE;<'%>
+<.*> IGNORE;IGNORE;IGNORE;<.*>
+<b3> IGNORE;IGNORE;IGNORE;<b3>
+<,,> IGNORE;IGNORE;IGNORE;<,,>
+<?*> IGNORE;IGNORE;IGNORE;<?*>
+<?:> IGNORE;IGNORE;IGNORE;<?:>
+<,!> IGNORE;IGNORE;IGNORE;<,!>
+<,'> IGNORE;IGNORE;IGNORE;<,'>
+<?,> IGNORE;IGNORE;IGNORE;<?,>
+<;!> IGNORE;IGNORE;IGNORE;<;!>
+<;'> IGNORE;IGNORE;IGNORE;<;'>
+<?;> IGNORE;IGNORE;IGNORE;<?;>
+<!:> IGNORE;IGNORE;IGNORE;<!:>
+<!*> IGNORE;IGNORE;IGNORE;<!*>
+<;;> IGNORE;IGNORE;IGNORE;<;;>
+<1N> IGNORE;IGNORE;IGNORE;<1N>
+<1M> IGNORE;IGNORE;IGNORE;<1M>
+<3M> IGNORE;IGNORE;IGNORE;<3M>
+<4M> IGNORE;IGNORE;IGNORE;<4M>
+<6M> IGNORE;IGNORE;IGNORE;<6M>
+<LR> IGNORE;IGNORE;IGNORE;<LR>
+<RL> IGNORE;IGNORE;IGNORE;<RL>
+<1T> IGNORE;IGNORE;IGNORE;<1T>
+<1H> IGNORE;IGNORE;IGNORE;<1H>
+<-1> IGNORE;IGNORE;IGNORE;<-1>
+<-N> IGNORE;IGNORE;IGNORE;<-N>
+<-M> IGNORE;IGNORE;IGNORE;<-M>
+<-3> IGNORE;IGNORE;IGNORE;<-3>
+<!2> IGNORE;IGNORE;IGNORE;<!2>
+<=2> IGNORE;IGNORE;IGNORE;<=2>
+<.9> IGNORE;IGNORE;IGNORE;<.9>
+<9'> IGNORE;IGNORE;IGNORE;<9'>
+<:9> IGNORE;IGNORE;IGNORE;<:9>
+<9"> IGNORE;IGNORE;IGNORE;<9">
+<//-> IGNORE;IGNORE;IGNORE;<//->
+<//=> IGNORE;IGNORE;IGNORE;<//=>
+<Sb> IGNORE;IGNORE;IGNORE;<Sb>
+<..> IGNORE;IGNORE;IGNORE;<..>
+<.3> IGNORE;IGNORE;IGNORE;<.3>
+<%0> IGNORE;IGNORE;IGNORE;<%0>
+<1'> IGNORE;IGNORE;IGNORE;<1'>
+<2'> IGNORE;IGNORE;IGNORE;<2'>
+<3'> IGNORE;IGNORE;IGNORE;<3'>
+<1"> IGNORE;IGNORE;IGNORE;<1">
+<2"> IGNORE;IGNORE;IGNORE;<2">
+<3"> IGNORE;IGNORE;IGNORE;<3">
+<Ca> IGNORE;IGNORE;IGNORE;<Ca>
+<<1> IGNORE;IGNORE;IGNORE;<<1>
+</>1> IGNORE;IGNORE;IGNORE;</>1>
+<:X> IGNORE;IGNORE;IGNORE;<:X>
+<!*2> IGNORE;IGNORE;IGNORE;<!*2>
+<'-> IGNORE;IGNORE;IGNORE;<'->
+<=S> IGNORE;IGNORE;IGNORE;<=S>
+<0s> IGNORE;IGNORE;IGNORE;<0s>
+<1s> IGNORE;IGNORE;IGNORE;<1s>
+<2s> IGNORE;IGNORE;IGNORE;<2s>
+<3s> IGNORE;IGNORE;IGNORE;<3s>
+<4s> IGNORE;IGNORE;IGNORE;<4s>
+<5s> IGNORE;IGNORE;IGNORE;<5s>
+<6s> IGNORE;IGNORE;IGNORE;<6s>
+<7s> IGNORE;IGNORE;IGNORE;<7s>
+<8s> IGNORE;IGNORE;IGNORE;<8s>
+<9s> IGNORE;IGNORE;IGNORE;<9s>
+<+s> IGNORE;IGNORE;IGNORE;<+s>
+<-s> IGNORE;IGNORE;IGNORE;<-s>
+<=s> IGNORE;IGNORE;IGNORE;<=s>
+<(s> IGNORE;IGNORE;IGNORE;<(s>
+<)s> IGNORE;IGNORE;IGNORE;<)s>
+<Ff> IGNORE;IGNORE;IGNORE;<Ff>
+<Li> IGNORE;IGNORE;IGNORE;<Li>
+<Pt> IGNORE;IGNORE;IGNORE;<Pt>
+<W=> IGNORE;IGNORE;IGNORE;<W=>
+<oC> IGNORE;IGNORE;IGNORE;<oC>
+<co> IGNORE;IGNORE;IGNORE;<co>
+<oF> IGNORE;IGNORE;IGNORE;<oF>
+<N0> IGNORE;IGNORE;IGNORE;<N0>
+<PO> IGNORE;IGNORE;IGNORE;<PO>
+<Rx> IGNORE;IGNORE;IGNORE;<Rx>
+<SM> IGNORE;IGNORE;IGNORE;<SM>
+<TM> IGNORE;IGNORE;IGNORE;<TM>
+<Om> IGNORE;IGNORE;IGNORE;<Om>
+<AO> IGNORE;IGNORE;IGNORE;<AO>
+<13> IGNORE;IGNORE;IGNORE;<13>
+<23> IGNORE;IGNORE;IGNORE;<23>
+<15> IGNORE;IGNORE;IGNORE;<15>
+<25> IGNORE;IGNORE;IGNORE;<25>
+<35> IGNORE;IGNORE;IGNORE;<35>
+<45> IGNORE;IGNORE;IGNORE;<45>
+<16> IGNORE;IGNORE;IGNORE;<16>
+<56> IGNORE;IGNORE;IGNORE;<56>
+<1R> IGNORE;IGNORE;IGNORE;<1R>
+<2R> IGNORE;IGNORE;IGNORE;<2R>
+<3R> IGNORE;IGNORE;IGNORE;<3R>
+<4R> IGNORE;IGNORE;IGNORE;<4R>
+<5R> IGNORE;IGNORE;IGNORE;<5R>
+<6R> IGNORE;IGNORE;IGNORE;<6R>
+<7R> IGNORE;IGNORE;IGNORE;<7R>
+<8R> IGNORE;IGNORE;IGNORE;<8R>
+<9R> IGNORE;IGNORE;IGNORE;<9R>
+<aR> IGNORE;IGNORE;IGNORE;<aR>
+<bR> IGNORE;IGNORE;IGNORE;<bR>
+<cR> IGNORE;IGNORE;IGNORE;<cR>
+<50R> IGNORE;IGNORE;IGNORE;<50R>
+<100R> IGNORE;IGNORE;IGNORE;<100R>
+<500R> IGNORE;IGNORE;IGNORE;<500R>
+<1000R> IGNORE;IGNORE;IGNORE;<1000R>
+<1r> IGNORE;IGNORE;IGNORE;<1r>
+<2r> IGNORE;IGNORE;IGNORE;<2r>
+<3r> IGNORE;IGNORE;IGNORE;<3r>
+<4r> IGNORE;IGNORE;IGNORE;<4r>
+<5r> IGNORE;IGNORE;IGNORE;<5r>
+<6r> IGNORE;IGNORE;IGNORE;<6r>
+<7r> IGNORE;IGNORE;IGNORE;<7r>
+<8r> IGNORE;IGNORE;IGNORE;<8r>
+<9r> IGNORE;IGNORE;IGNORE;<9r>
+<ar> IGNORE;IGNORE;IGNORE;<ar>
+<br> IGNORE;IGNORE;IGNORE;<br>
+<cr> IGNORE;IGNORE;IGNORE;<cr>
+<50r> IGNORE;IGNORE;IGNORE;<50r>
+<100r> IGNORE;IGNORE;IGNORE;<100r>
+<500r> IGNORE;IGNORE;IGNORE;<500r>
+<1000r> IGNORE;IGNORE;IGNORE;<1000r>
+<1000RCD> IGNORE;IGNORE;IGNORE;<1000RCD>
+<5000R> IGNORE;IGNORE;IGNORE;<5000R>
+<10000R> IGNORE;IGNORE;IGNORE;<10000R>
+<-!> IGNORE;IGNORE;IGNORE;<-!>
+<-v> IGNORE;IGNORE;IGNORE;<-v>
+<</>> IGNORE;IGNORE;IGNORE;<</>>
+<UD> IGNORE;IGNORE;IGNORE;<UD>
+<<!!> IGNORE;IGNORE;IGNORE;<<!!>
+</////>> IGNORE;IGNORE;IGNORE;</////>>
+<!!/>> IGNORE;IGNORE;IGNORE;<!!/>>
+<<////> IGNORE;IGNORE;IGNORE;<<////>
+<UD-> IGNORE;IGNORE;IGNORE;<UD->
+</>V> IGNORE;IGNORE;IGNORE;</>V>
+<<=> IGNORE;IGNORE;IGNORE;<<=>
+<=/>> IGNORE;IGNORE;IGNORE;<=/>>
+<==> IGNORE;IGNORE;IGNORE;<==>
+<FA> IGNORE;IGNORE;IGNORE;<FA>
+<dP> IGNORE;IGNORE;IGNORE;<dP>
+<TE> IGNORE;IGNORE;IGNORE;<TE>
+<//0> IGNORE;IGNORE;IGNORE;<//0>
+<DE> IGNORE;IGNORE;IGNORE;<DE>
+<NB> IGNORE;IGNORE;IGNORE;<NB>
+<(-> IGNORE;IGNORE;IGNORE;<(->
+<-)> IGNORE;IGNORE;IGNORE;<-)>
+<*P> IGNORE;IGNORE;IGNORE;<*P>
+<+Z> IGNORE;IGNORE;IGNORE;<+Z>
+<-2> IGNORE;IGNORE;IGNORE;<-2>
+<-+> IGNORE;IGNORE;IGNORE;<-+>
+<.+> IGNORE;IGNORE;IGNORE;<.+>
+<//f> IGNORE;IGNORE;IGNORE;<//f>
+<*-> IGNORE;IGNORE;IGNORE;<*->
+<Ob> IGNORE;IGNORE;IGNORE;<Ob>
+<sb> IGNORE;IGNORE;IGNORE;<sb>
+<RT> IGNORE;IGNORE;IGNORE;<RT>
+<0(> IGNORE;IGNORE;IGNORE;<0(>
+<00> IGNORE;IGNORE;IGNORE;<00>
+<-L> IGNORE;IGNORE;IGNORE;<-L>
+<-V> IGNORE;IGNORE;IGNORE;<-V>
+<PP> IGNORE;IGNORE;IGNORE;<PP>
+<AN> IGNORE;IGNORE;IGNORE;<AN>
+<OR> IGNORE;IGNORE;IGNORE;<OR>
+<(U> IGNORE;IGNORE;IGNORE;<(U>
+<)U> IGNORE;IGNORE;IGNORE;<)U>
+<In> IGNORE;IGNORE;IGNORE;<In>
+<DI> IGNORE;IGNORE;IGNORE;<DI>
+<Io> IGNORE;IGNORE;IGNORE;<Io>
+<.:> IGNORE;IGNORE;IGNORE;<.:>
+<:.> IGNORE;IGNORE;IGNORE;<:.>
+<:R> IGNORE;IGNORE;IGNORE;<:R>
+<::> IGNORE;IGNORE;IGNORE;<::>
+<?1> IGNORE;IGNORE;IGNORE;<?1>
+<CG> IGNORE;IGNORE;IGNORE;<CG>
+<?-> IGNORE;IGNORE;IGNORE;<?->
+<?=> IGNORE;IGNORE;IGNORE;<?=>
+<?2> IGNORE;IGNORE;IGNORE;<?2>
+<=?> IGNORE;IGNORE;IGNORE;<=?>
+<HI> IGNORE;IGNORE;IGNORE;<HI>
+<=3> IGNORE;IGNORE;IGNORE;<=3>
+<<*> IGNORE;IGNORE;IGNORE;<<*>
+<*/>> IGNORE;IGNORE;IGNORE;<*/>>
+<!<> IGNORE;IGNORE;IGNORE;<!<>
+<!/>> IGNORE;IGNORE;IGNORE;<!/>>
+<(C> IGNORE;IGNORE;IGNORE;<(C>
+<)C> IGNORE;IGNORE;IGNORE;<)C>
+<(_> IGNORE;IGNORE;IGNORE;<(_>
+<)_> IGNORE;IGNORE;IGNORE;<)_>
+<0.> IGNORE;IGNORE;IGNORE;<0.>
+<02> IGNORE;IGNORE;IGNORE;<02>
+<-T> IGNORE;IGNORE;IGNORE;<-T>
+<.P> IGNORE;IGNORE;IGNORE;<.P>
+<:3> IGNORE;IGNORE;IGNORE;<:3>
+<Eh> IGNORE;IGNORE;IGNORE;<Eh>
+<<7> IGNORE;IGNORE;IGNORE;<<7>
+</>7> IGNORE;IGNORE;IGNORE;</>7>
+<7<> IGNORE;IGNORE;IGNORE;<7<>
+<7/>> IGNORE;IGNORE;IGNORE;<7/>>
+<NI> IGNORE;IGNORE;IGNORE;<NI>
+<(A> IGNORE;IGNORE;IGNORE;<(A>
+<TR> IGNORE;IGNORE;IGNORE;<TR>
+<Iu> IGNORE;IGNORE;IGNORE;<Iu>
+<Il> IGNORE;IGNORE;IGNORE;<Il>
+<Vs> IGNORE;IGNORE;IGNORE;<Vs>
+<1h> IGNORE;IGNORE;IGNORE;<1h>
+<3h> IGNORE;IGNORE;IGNORE;<3h>
+<2h> IGNORE;IGNORE;IGNORE;<2h>
+<4h> IGNORE;IGNORE;IGNORE;<4h>
+<1j> IGNORE;IGNORE;IGNORE;<1j>
+<2j> IGNORE;IGNORE;IGNORE;<2j>
+<3j> IGNORE;IGNORE;IGNORE;<3j>
+<4j> IGNORE;IGNORE;IGNORE;<4j>
+<1-o> IGNORE;IGNORE;IGNORE;<1-o>
+<2-o> IGNORE;IGNORE;IGNORE;<2-o>
+<3-o> IGNORE;IGNORE;IGNORE;<3-o>
+<4-o> IGNORE;IGNORE;IGNORE;<4-o>
+<5-o> IGNORE;IGNORE;IGNORE;<5-o>
+<6-o> IGNORE;IGNORE;IGNORE;<6-o>
+<7-o> IGNORE;IGNORE;IGNORE;<7-o>
+<8-o> IGNORE;IGNORE;IGNORE;<8-o>
+<9-o> IGNORE;IGNORE;IGNORE;<9-o>
+<10-o> IGNORE;IGNORE;IGNORE;<10-o>
+<11-o> IGNORE;IGNORE;IGNORE;<11-o>
+<12-o> IGNORE;IGNORE;IGNORE;<12-o>
+<13-o> IGNORE;IGNORE;IGNORE;<13-o>
+<14-o> IGNORE;IGNORE;IGNORE;<14-o>
+<15-o> IGNORE;IGNORE;IGNORE;<15-o>
+<16-o> IGNORE;IGNORE;IGNORE;<16-o>
+<17-o> IGNORE;IGNORE;IGNORE;<17-o>
+<18-o> IGNORE;IGNORE;IGNORE;<18-o>
+<19-o> IGNORE;IGNORE;IGNORE;<19-o>
+<20-o> IGNORE;IGNORE;IGNORE;<20-o>
+<(1)> IGNORE;IGNORE;IGNORE;<(1)>
+<(2)> IGNORE;IGNORE;IGNORE;<(2)>
+<(3)> IGNORE;IGNORE;IGNORE;<(3)>
+<(4)> IGNORE;IGNORE;IGNORE;<(4)>
+<(5)> IGNORE;IGNORE;IGNORE;<(5)>
+<(6)> IGNORE;IGNORE;IGNORE;<(6)>
+<(7)> IGNORE;IGNORE;IGNORE;<(7)>
+<(8)> IGNORE;IGNORE;IGNORE;<(8)>
+<(9)> IGNORE;IGNORE;IGNORE;<(9)>
+<(10)> IGNORE;IGNORE;IGNORE;<(10)>
+<(11)> IGNORE;IGNORE;IGNORE;<(11)>
+<(12)> IGNORE;IGNORE;IGNORE;<(12)>
+<(13)> IGNORE;IGNORE;IGNORE;<(13)>
+<(14)> IGNORE;IGNORE;IGNORE;<(14)>
+<(15)> IGNORE;IGNORE;IGNORE;<(15)>
+<(16)> IGNORE;IGNORE;IGNORE;<(16)>
+<(17)> IGNORE;IGNORE;IGNORE;<(17)>
+<(18)> IGNORE;IGNORE;IGNORE;<(18)>
+<(19)> IGNORE;IGNORE;IGNORE;<(19)>
+<(20)> IGNORE;IGNORE;IGNORE;<(20)>
+<1.> IGNORE;IGNORE;IGNORE;<1.>
+<2.> IGNORE;IGNORE;IGNORE;<2.>
+<3.> IGNORE;IGNORE;IGNORE;<3.>
+<4.> IGNORE;IGNORE;IGNORE;<4.>
+<5.> IGNORE;IGNORE;IGNORE;<5.>
+<6.> IGNORE;IGNORE;IGNORE;<6.>
+<7.> IGNORE;IGNORE;IGNORE;<7.>
+<8.> IGNORE;IGNORE;IGNORE;<8.>
+<9.> IGNORE;IGNORE;IGNORE;<9.>
+<10.> IGNORE;IGNORE;IGNORE;<10.>
+<11.> IGNORE;IGNORE;IGNORE;<11.>
+<12.> IGNORE;IGNORE;IGNORE;<12.>
+<13.> IGNORE;IGNORE;IGNORE;<13.>
+<14.> IGNORE;IGNORE;IGNORE;<14.>
+<15.> IGNORE;IGNORE;IGNORE;<15.>
+<16.> IGNORE;IGNORE;IGNORE;<16.>
+<17.> IGNORE;IGNORE;IGNORE;<17.>
+<18.> IGNORE;IGNORE;IGNORE;<18.>
+<19.> IGNORE;IGNORE;IGNORE;<19.>
+<20.> IGNORE;IGNORE;IGNORE;<20.>
+<0-o> IGNORE;IGNORE;IGNORE;<0-o>
+<hh> IGNORE;IGNORE;IGNORE;<hh>
+<HH> IGNORE;IGNORE;IGNORE;<HH>
+<vv> IGNORE;IGNORE;IGNORE;<vv>
+<VV> IGNORE;IGNORE;IGNORE;<VV>
+<3-> IGNORE;IGNORE;IGNORE;<3->
+<3_> IGNORE;IGNORE;IGNORE;<3_>
+<3!> IGNORE;IGNORE;IGNORE;<3!>
+<3//> IGNORE;IGNORE;IGNORE;<3//>
+<4-> IGNORE;IGNORE;IGNORE;<4->
+<4_> IGNORE;IGNORE;IGNORE;<4_>
+<4!> IGNORE;IGNORE;IGNORE;<4!>
+<4//> IGNORE;IGNORE;IGNORE;<4//>
+<dr> IGNORE;IGNORE;IGNORE;<dr>
+<dR> IGNORE;IGNORE;IGNORE;<dR>
+<Dr> IGNORE;IGNORE;IGNORE;<Dr>
+<DR> IGNORE;IGNORE;IGNORE;<DR>
+<dl> IGNORE;IGNORE;IGNORE;<dl>
+<dL> IGNORE;IGNORE;IGNORE;<dL>
+<Dl> IGNORE;IGNORE;IGNORE;<Dl>
+<LD> IGNORE;IGNORE;IGNORE;<LD>
+<ur> IGNORE;IGNORE;IGNORE;<ur>
+<uR> IGNORE;IGNORE;IGNORE;<uR>
+<Ur> IGNORE;IGNORE;IGNORE;<Ur>
+<UR> IGNORE;IGNORE;IGNORE;<UR>
+<ul> IGNORE;IGNORE;IGNORE;<ul>
+<uL> IGNORE;IGNORE;IGNORE;<uL>
+<Ul> IGNORE;IGNORE;IGNORE;<Ul>
+<UL> IGNORE;IGNORE;IGNORE;<UL>
+<vr> IGNORE;IGNORE;IGNORE;<vr>
+<vR> IGNORE;IGNORE;IGNORE;<vR>
+<Udr> IGNORE;IGNORE;IGNORE;<Udr>
+<uDr> IGNORE;IGNORE;IGNORE;<uDr>
+<Vr> IGNORE;IGNORE;IGNORE;<Vr>
+<UdR> IGNORE;IGNORE;IGNORE;<UdR>
+<uDR> IGNORE;IGNORE;IGNORE;<uDR>
+<VR> IGNORE;IGNORE;IGNORE;<VR>
+<vl> IGNORE;IGNORE;IGNORE;<vl>
+<vL> IGNORE;IGNORE;IGNORE;<vL>
+<Udl> IGNORE;IGNORE;IGNORE;<Udl>
+<uDl> IGNORE;IGNORE;IGNORE;<uDl>
+<Vl> IGNORE;IGNORE;IGNORE;<Vl>
+<UdL> IGNORE;IGNORE;IGNORE;<UdL>
+<uDL> IGNORE;IGNORE;IGNORE;<uDL>
+<VL> IGNORE;IGNORE;IGNORE;<VL>
+<dh> IGNORE;IGNORE;IGNORE;<dh>
+<dLr> IGNORE;IGNORE;IGNORE;<dLr>
+<dlR> IGNORE;IGNORE;IGNORE;<dlR>
+<dH> IGNORE;IGNORE;IGNORE;<dH>
+<Dh> IGNORE;IGNORE;IGNORE;<Dh>
+<DLr> IGNORE;IGNORE;IGNORE;<DLr>
+<DlR> IGNORE;IGNORE;IGNORE;<DlR>
+<DH> IGNORE;IGNORE;IGNORE;<DH>
+<uh> IGNORE;IGNORE;IGNORE;<uh>
+<uLr> IGNORE;IGNORE;IGNORE;<uLr>
+<ulR> IGNORE;IGNORE;IGNORE;<ulR>
+<uH> IGNORE;IGNORE;IGNORE;<uH>
+<Uh> IGNORE;IGNORE;IGNORE;<Uh>
+<ULr> IGNORE;IGNORE;IGNORE;<ULr>
+<UlR> IGNORE;IGNORE;IGNORE;<UlR>
+<UH> IGNORE;IGNORE;IGNORE;<UH>
+<vh> IGNORE;IGNORE;IGNORE;<vh>
+<vLr> IGNORE;IGNORE;IGNORE;<vLr>
+<vlR> IGNORE;IGNORE;IGNORE;<vlR>
+<vH> IGNORE;IGNORE;IGNORE;<vH>
+<Udh> IGNORE;IGNORE;IGNORE;<Udh>
+<uDh> IGNORE;IGNORE;IGNORE;<uDh>
+<Vh> IGNORE;IGNORE;IGNORE;<Vh>
+<UdLr> IGNORE;IGNORE;IGNORE;<UdLr>
+<UdlR> IGNORE;IGNORE;IGNORE;<UdlR>
+<uDLr> IGNORE;IGNORE;IGNORE;<uDLr>
+<uDlR> IGNORE;IGNORE;IGNORE;<uDlR>
+<UdH> IGNORE;IGNORE;IGNORE;<UdH>
+<uDH> IGNORE;IGNORE;IGNORE;<uDH>
+<VLr> IGNORE;IGNORE;IGNORE;<VLr>
+<VlR> IGNORE;IGNORE;IGNORE;<VlR>
+<VH> IGNORE;IGNORE;IGNORE;<VH>
+<FD> IGNORE;IGNORE;IGNORE;<FD>
+<BD> IGNORE;IGNORE;IGNORE;<BD>
+<TB> IGNORE;IGNORE;IGNORE;<TB>
+<LB> IGNORE;IGNORE;IGNORE;<LB>
+<FB> IGNORE;IGNORE;IGNORE;<FB>
+<lB> IGNORE;IGNORE;IGNORE;<lB>
+<RB> IGNORE;IGNORE;IGNORE;<RB>
+<.S> IGNORE;IGNORE;IGNORE;<.S>
+<:S> IGNORE;IGNORE;IGNORE;<:S>
+<?S> IGNORE;IGNORE;IGNORE;<?S>
+<fS> IGNORE;IGNORE;IGNORE;<fS>
+<OS> IGNORE;IGNORE;IGNORE;<OS>
+<RO> IGNORE;IGNORE;IGNORE;<RO>
+<Rr> IGNORE;IGNORE;IGNORE;<Rr>
+<RF> IGNORE;IGNORE;IGNORE;<RF>
+<RY> IGNORE;IGNORE;IGNORE;<RY>
+<RH> IGNORE;IGNORE;IGNORE;<RH>
+<RZ> IGNORE;IGNORE;IGNORE;<RZ>
+<RK> IGNORE;IGNORE;IGNORE;<RK>
+<RX> IGNORE;IGNORE;IGNORE;<RX>
+<sB> IGNORE;IGNORE;IGNORE;<sB>
+<SR> IGNORE;IGNORE;IGNORE;<SR>
+<Or> IGNORE;IGNORE;IGNORE;<Or>
+<UT> IGNORE;IGNORE;IGNORE;<UT>
+<uT> IGNORE;IGNORE;IGNORE;<uT>
+<Tr> IGNORE;IGNORE;IGNORE;<Tr>
+<PR> IGNORE;IGNORE;IGNORE;<PR>
+<Dt> IGNORE;IGNORE;IGNORE;<Dt>
+<dT> IGNORE;IGNORE;IGNORE;<dT>
+<Tl> IGNORE;IGNORE;IGNORE;<Tl>
+<PL> IGNORE;IGNORE;IGNORE;<PL>
+<Db> IGNORE;IGNORE;IGNORE;<Db>
+<Dw> IGNORE;IGNORE;IGNORE;<Dw>
+<LZ> IGNORE;IGNORE;IGNORE;<LZ>
+<0m> IGNORE;IGNORE;IGNORE;<0m>
+<0o> IGNORE;IGNORE;IGNORE;<0o>
+<0M> IGNORE;IGNORE;IGNORE;<0M>
+<0L> IGNORE;IGNORE;IGNORE;<0L>
+<0R> IGNORE;IGNORE;IGNORE;<0R>
+<Sn> IGNORE;IGNORE;IGNORE;<Sn>
+<Ic> IGNORE;IGNORE;IGNORE;<Ic>
+<Fd> IGNORE;IGNORE;IGNORE;<Fd>
+<Bd> IGNORE;IGNORE;IGNORE;<Bd>
+<Ci> IGNORE;IGNORE;IGNORE;<Ci>
+<*2> IGNORE;IGNORE;IGNORE;<*2>
+<*1> IGNORE;IGNORE;IGNORE;<*1>
+<TEL> IGNORE;IGNORE;IGNORE;<TEL>
+<tel> IGNORE;IGNORE;IGNORE;<tel>
+<<H> IGNORE;IGNORE;IGNORE;<<H>
+</>H> IGNORE;IGNORE;IGNORE;</>H>
+<0u> IGNORE;IGNORE;IGNORE;<0u>
+<0U> IGNORE;IGNORE;IGNORE;<0U>
+<SU> IGNORE;IGNORE;IGNORE;<SU>
+<Fm> IGNORE;IGNORE;IGNORE;<Fm>
+<Ml> IGNORE;IGNORE;IGNORE;<Ml>
+<cS> IGNORE;IGNORE;IGNORE;<cS>
+<cH> IGNORE;IGNORE;IGNORE;<cH>
+<cD> IGNORE;IGNORE;IGNORE;<cD>
+<cC> IGNORE;IGNORE;IGNORE;<cC>
+<cS-> IGNORE;IGNORE;IGNORE;<cS->
+<cH-> IGNORE;IGNORE;IGNORE;<cH->
+<cD-> IGNORE;IGNORE;IGNORE;<cD->
+<cC-> IGNORE;IGNORE;IGNORE;<cC->
+<Md> IGNORE;IGNORE;IGNORE;<Md>
+<M8> IGNORE;IGNORE;IGNORE;<M8>
+<M2> IGNORE;IGNORE;IGNORE;<M2>
+<M16> IGNORE;IGNORE;IGNORE;<M16>
+<Mb> IGNORE;IGNORE;IGNORE;<Mb>
+<Mx> IGNORE;IGNORE;IGNORE;<Mx>
+<MX> IGNORE;IGNORE;IGNORE;<MX>
+<OK> IGNORE;IGNORE;IGNORE;<OK>
+<XX> IGNORE;IGNORE;IGNORE;<XX>
+<-X> IGNORE;IGNORE;IGNORE;<-X>
+<IS> IGNORE;IGNORE;IGNORE;<IS>
+<,_> IGNORE;IGNORE;IGNORE;<,_>
+<._> IGNORE;IGNORE;IGNORE;<._>
+<+"> IGNORE;IGNORE;IGNORE;<+">
+<JIS> IGNORE;IGNORE;IGNORE;<JIS>
+<*_> IGNORE;IGNORE;IGNORE;<*_>
+<;_> IGNORE;IGNORE;IGNORE;<;_>
+<0_> IGNORE;IGNORE;IGNORE;<0_>
+<<+> IGNORE;IGNORE;IGNORE;<<+>
+</>+> IGNORE;IGNORE;IGNORE;</>+>
+<<'> IGNORE;IGNORE;IGNORE;<<'>
+</>'> IGNORE;IGNORE;IGNORE;</>'>
+<<"> IGNORE;IGNORE;IGNORE;<<">
+</>"> IGNORE;IGNORE;IGNORE;</>">
+<("> IGNORE;IGNORE;IGNORE;<(">
+<)"> IGNORE;IGNORE;IGNORE;<)">
+<=T> IGNORE;IGNORE;IGNORE;<=T>
+<=_> IGNORE;IGNORE;IGNORE;<=_>
+<('> IGNORE;IGNORE;IGNORE;<('>
+<)'> IGNORE;IGNORE;IGNORE;<)'>
+<(I> IGNORE;IGNORE;IGNORE;<(I>
+<)I> IGNORE;IGNORE;IGNORE;<)I>
+<-?> IGNORE;IGNORE;IGNORE;<-?>
+<=T:)> IGNORE;IGNORE;IGNORE;<=T:)>
+<"5> IGNORE;IGNORE;IGNORE;<"5>
+<05> IGNORE;IGNORE;IGNORE;<05>
+<*5> IGNORE;IGNORE;IGNORE;<*5>
+<+5> IGNORE;IGNORE;IGNORE;<+5>
+<.6> IGNORE;IGNORE;IGNORE;<.6>
+<-6> IGNORE;IGNORE;IGNORE;<-6>
+<*6> IGNORE;IGNORE;IGNORE;<*6>
+<+6> IGNORE;IGNORE;IGNORE;<+6>
+<(JU)> IGNORE;IGNORE;IGNORE;<(JU)>
+<1c> IGNORE;IGNORE;IGNORE;<1c>
+<2c> IGNORE;IGNORE;IGNORE;<2c>
+<3c> IGNORE;IGNORE;IGNORE;<3c>
+<4c> IGNORE;IGNORE;IGNORE;<4c>
+<5c> IGNORE;IGNORE;IGNORE;<5c>
+<6c> IGNORE;IGNORE;IGNORE;<6c>
+<7c> IGNORE;IGNORE;IGNORE;<7c>
+<8c> IGNORE;IGNORE;IGNORE;<8c>
+<9c> IGNORE;IGNORE;IGNORE;<9c>
+<10c> IGNORE;IGNORE;IGNORE;<10c>
+<KSC> IGNORE;IGNORE;IGNORE;<KSC>
+<am> IGNORE;IGNORE;IGNORE;<am>
+<pm> IGNORE;IGNORE;IGNORE;<pm>
+<NU> IGNORE;IGNORE;IGNORE;<NU>
+<SH> IGNORE;IGNORE;IGNORE;<SH>
+<SX> IGNORE;IGNORE;IGNORE;<SX>
+<EX> IGNORE;IGNORE;IGNORE;<EX>
+<ET> IGNORE;IGNORE;IGNORE;<ET>
+<EQ> IGNORE;IGNORE;IGNORE;<EQ>
+<AK> IGNORE;IGNORE;IGNORE;<AK>
+<BL> IGNORE;IGNORE;IGNORE;<BL>
+<BS> IGNORE;IGNORE;IGNORE;<BS>
+<SO> IGNORE;IGNORE;IGNORE;<SO>
+<SI> IGNORE;IGNORE;IGNORE;<SI>
+<DL> IGNORE;IGNORE;IGNORE;<DL>
+<D1> IGNORE;IGNORE;IGNORE;<D1>
+<D2> IGNORE;IGNORE;IGNORE;<D2>
+<D3> IGNORE;IGNORE;IGNORE;<D3>
+<D4> IGNORE;IGNORE;IGNORE;<D4>
+<NK> IGNORE;IGNORE;IGNORE;<NK>
+<SY> IGNORE;IGNORE;IGNORE;<SY>
+<EB> IGNORE;IGNORE;IGNORE;<EB>
+<CN> IGNORE;IGNORE;IGNORE;<CN>
+<EM> IGNORE;IGNORE;IGNORE;<EM>
+<SB> IGNORE;IGNORE;IGNORE;<SB>
+<EC> IGNORE;IGNORE;IGNORE;<EC>
+<FS> IGNORE;IGNORE;IGNORE;<FS>
+<GS> IGNORE;IGNORE;IGNORE;<GS>
+<RS> IGNORE;IGNORE;IGNORE;<RS>
+<US> IGNORE;IGNORE;IGNORE;<US>
+<DT> IGNORE;IGNORE;IGNORE;<DT>
+<PA> IGNORE;IGNORE;IGNORE;<PA>
+<HO> IGNORE;IGNORE;IGNORE;<HO>
+<BH> IGNORE;IGNORE;IGNORE;<BH>
+<NH> IGNORE;IGNORE;IGNORE;<NH>
+<IN> IGNORE;IGNORE;IGNORE;<IN>
+<NL> IGNORE;IGNORE;IGNORE;<NL>
+<SA> IGNORE;IGNORE;IGNORE;<SA>
+<ES> IGNORE;IGNORE;IGNORE;<ES>
+<HS> IGNORE;IGNORE;IGNORE;<HS>
+<HJ> IGNORE;IGNORE;IGNORE;<HJ>
+<VS> IGNORE;IGNORE;IGNORE;<VS>
+<PD> IGNORE;IGNORE;IGNORE;<PD>
+<PU> IGNORE;IGNORE;IGNORE;<PU>
+<RI> IGNORE;IGNORE;IGNORE;<RI>
+<S2> IGNORE;IGNORE;IGNORE;<S2>
+<S3> IGNORE;IGNORE;IGNORE;<S3>
+<DC> IGNORE;IGNORE;IGNORE;<DC>
+<P1> IGNORE;IGNORE;IGNORE;<P1>
+<P2> IGNORE;IGNORE;IGNORE;<P2>
+<TS> IGNORE;IGNORE;IGNORE;<TS>
+<CC> IGNORE;IGNORE;IGNORE;<CC>
+<MW> IGNORE;IGNORE;IGNORE;<MW>
+<SG> IGNORE;IGNORE;IGNORE;<SG>
+<EG> IGNORE;IGNORE;IGNORE;<EG>
+<SS> IGNORE;IGNORE;IGNORE;<SS>
+<GC> IGNORE;IGNORE;IGNORE;<GC>
+<SC> IGNORE;IGNORE;IGNORE;<SC>
+<CI> IGNORE;IGNORE;IGNORE;<CI>
+<ST> IGNORE;IGNORE;IGNORE;<ST>
+<OC> IGNORE;IGNORE;IGNORE;<OC>
+<PM> IGNORE;IGNORE;IGNORE;<PM>
+<AC> IGNORE;IGNORE;IGNORE;<AC>
+<"3> IGNORE;IGNORE;IGNORE;<"3>
+<"1> IGNORE;IGNORE;IGNORE;<"1>
+<"!> IGNORE;IGNORE;IGNORE;<"!>
+<"'> IGNORE;IGNORE;IGNORE;<"'>
+<"/>> IGNORE;IGNORE;IGNORE;<"/>>
+<"?> IGNORE;IGNORE;IGNORE;<"?>
+<"-> IGNORE;IGNORE;IGNORE;<"->
+<"(> IGNORE;IGNORE;IGNORE;<"(>
+<".> IGNORE;IGNORE;IGNORE;<".>
+<":> IGNORE;IGNORE;IGNORE;<":>
+<"0> IGNORE;IGNORE;IGNORE;<"0>
+<",> IGNORE;IGNORE;IGNORE;<",>
+<"_> IGNORE;IGNORE;IGNORE;<"_>
+<""> IGNORE;IGNORE;IGNORE;<"">
+<";> IGNORE;IGNORE;IGNORE;<";>
+<"<> IGNORE;IGNORE;IGNORE;<"<>
+<"=> IGNORE;IGNORE;IGNORE;<"=>
+<"//> IGNORE;IGNORE;IGNORE;<"//>
+<"p> IGNORE;IGNORE;IGNORE;<"p>
+<"d> IGNORE;IGNORE;IGNORE;<"d>
+<"i> IGNORE;IGNORE;IGNORE;<"i>
+<+_> IGNORE;IGNORE;IGNORE;<+_>
+<Tel> IGNORE;IGNORE;IGNORE;<Tel>
+<UA> IGNORE;IGNORE;IGNORE;<UA>
+<UB> IGNORE;IGNORE;IGNORE;<UB>
+UNDEFINED IGNORE;IGNORE;IGNORE
+
+<0> <0>;<0>;IGNORE;IGNORE
+<0S> <0>;<0S>;IGNORE;IGNORE
+<18> <0>;<18>;IGNORE;IGNORE
+<14> <0>;<14>;IGNORE;IGNORE
+<38> <0>;<38>;IGNORE;IGNORE
+<12> <0>;<12>;IGNORE;IGNORE
+<58> <0>;<58>;IGNORE;IGNORE
+<34> <0>;<34>;IGNORE;IGNORE
+<78> <0>;<78>;IGNORE;IGNORE
+<1> <1>;<1>;IGNORE;IGNORE
+<2> <2>;<2>;IGNORE;IGNORE
+<3> <3>;<3>;IGNORE;IGNORE
+<4> <4>;<4>;IGNORE;IGNORE
+<5> <5>;<5>;IGNORE;IGNORE
+<6> <6>;<6>;IGNORE;IGNORE
+<7> <7>;<7>;IGNORE;IGNORE
+<8> <8>;<8>;IGNORE;IGNORE
+<9> <9>;<9>;IGNORE;IGNORE
+<1S> <1>;<1S>;IGNORE;IGNORE
+<2S> <2>;<2S>;IGNORE;IGNORE
+<3S> <3>;<3S>;IGNORE;IGNORE
+<4S> <4>;<4S>;IGNORE;IGNORE
+<5S> <5>;<5S>;IGNORE;IGNORE
+<6S> <6>;<6S>;IGNORE;IGNORE
+<7S> <7>;<7S>;IGNORE;IGNORE
+<8S> <8>;<8S>;IGNORE;IGNORE
+<9S> <9>;<9S>;IGNORE;IGNORE
+<A> <A>;<NONE>;<CAPITAL>;IGNORE
+<a> <A>;<NONE>;<SMALL>;IGNORE
+<-a> <A>;<NONE>;<-a>;IGNORE
+<A'> <A>;<ACUTE>;<CAPITAL>;IGNORE
+<a'> <A>;<ACUTE>;<SMALL>;IGNORE
+<A!> <A>;<GRAVE>;<CAPITAL>;IGNORE
+<a!> <A>;<GRAVE>;<SMALL>;IGNORE
+<A!!> <A>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<a!!> <A>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<A(> <A>;<BREVE>;<CAPITAL>;IGNORE
+<a(> <A>;<BREVE>;<SMALL>;IGNORE
+<A('> <A>;<BREVE+ACUTE>;<CAPITAL>;IGNORE
+<a('> <A>;<BREVE+ACUTE>;<SMALL>;IGNORE
+<A(!> <A>;<BREVE+GRAVE>;<CAPITAL>;IGNORE
+<a(!> <A>;<BREVE+GRAVE>;<SMALL>;IGNORE
+<A(2> <A>;<BREVE+HOOK>;<CAPITAL>;IGNORE
+<a(2> <A>;<BREVE+HOOK>;<SMALL>;IGNORE
+<A(?> <A>;<BREVE+TILDE>;<CAPITAL>;IGNORE
+<a(?> <A>;<BREVE+TILDE>;<SMALL>;IGNORE
+<A(-.> <A>;<BREVE+DOT-BELOW>;<CAPITAL>;IGNORE
+<a(-.> <A>;<BREVE+DOT-BELOW>;<SMALL>;IGNORE
+<A)> <A>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<a)> <A>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<A/>> <A>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<a/>> <A>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<A/>'> <A>;<CIRCUMFLEX+ACUTE>;<CAPITAL>;IGNORE
+<a/>'> <A>;<CIRCUMFLEX+ACUTE>;<SMALL>;IGNORE
+<A/>!> <A>;<CIRCUMFLEX+GRAVE>;<CAPITAL>;IGNORE
+<a/>!> <A>;<CIRCUMFLEX+GRAVE>;<SMALL>;IGNORE
+<A/>2> <A>;<CIRCUMFLEX+HOOK>;<CAPITAL>;IGNORE
+<a/>2> <A>;<CIRCUMFLEX+HOOK>;<SMALL>;IGNORE
+<A/>?> <A>;<CIRCUMFLEX+TILDE>;<CAPITAL>;IGNORE
+<a/>?> <A>;<CIRCUMFLEX+TILDE>;<SMALL>;IGNORE
+<A/>-.> <A>;<CIRCUMFLEX+DOT-BELOW>;<CAPITAL>;IGNORE
+<a/>-.> <A>;<CIRCUMFLEX+DOT-BELOW>;<SMALL>;IGNORE
+<A<> <A>;<CARON>;<CAPITAL>;IGNORE
+<a<> <A>;<CARON>;<SMALL>;IGNORE
+<AA> <A>;<RING>;<CAPITAL>;IGNORE
+<aa> <A>;<RING>;<SMALL>;IGNORE
+<AA'> <A>;<RING+ACUTE>;<CAPITAL>;IGNORE
+<aa'> <A>;<RING+ACUTE>;<SMALL>;IGNORE
+<A-0> <A>;<RING-BELOW>;<CAPITAL>;IGNORE
+<a-0> <A>;<RING-BELOW>;<SMALL>;IGNORE
+<A:> <A>;<DIAERESIS>;<CAPITAL>;IGNORE
+<a:> <A>;<DIAERESIS>;<SMALL>;IGNORE
+<A1> <A>;<DIAERESIS+MACRON>;<CAPITAL>;IGNORE
+<a1> <A>;<DIAERESIS+MACRON>;<SMALL>;IGNORE
+<A2> <A>;<HOOK>;<CAPITAL>;IGNORE
+<a2> <A>;<HOOK>;<SMALL>;IGNORE
+<A?> <A>;<TILDE>;<CAPITAL>;IGNORE
+<a?> <A>;<TILDE>;<SMALL>;IGNORE
+<A-.> <A>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<a-.> <A>;<DOT-BELOW>;<SMALL>;IGNORE
+<A;> <A>;<OGONEK>;<CAPITAL>;IGNORE
+<a;> <A>;<OGONEK>;<SMALL>;IGNORE
+<A-> <A>;<MACRON>;<CAPITAL>;IGNORE
+<a-> <A>;<MACRON>;<SMALL>;IGNORE
+<A7> <A>;<MACRON+DOT>;<CAPITAL>;IGNORE
+<a7> <A>;<MACRON+DOT>;<SMALL>;IGNORE
+<a8>
+<AE> "<A><E>";"<AE><AE>";"<CAPITAL><CAPITAL>";IGNORE
+<ae> "<A><E>";"<AE><AE>";"<SMALL><SMALL>";IGNORE
+<AE'> "<A><E>";"<AE'><AE'>";"<CAPITAL><CAPITAL>";IGNORE
+<ae'> "<A><E>";"<AE'><AE'>";"<SMALL><SMALL>";IGNORE
+<A3> "<A><E>";"<A3><A3>";"<CAPITAL><CAPITAL>";IGNORE
+<a3> "<A><E>";"<A3><A3>";"<SMALL><SMALL>";IGNORE
+<B> <B>;<NONE>;<CAPITAL>;IGNORE
+<b> <B>;<NONE>;<SMALL>;IGNORE
+<B.> <B>;<DOT>;<CAPITAL>;IGNORE
+<b.> <B>;<DOT>;<SMALL>;IGNORE
+<B-.> <B>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<b-.> <B>;<DOT-BELOW>;<SMALL>;IGNORE
+<B_> <B>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<b_> <B>;<LINE-BELOW>;<SMALL>;IGNORE
+<b8>
+<C> <C>;<NONE>;<CAPITAL>;IGNORE
+<c> <C>;<NONE>;<SMALL>;IGNORE
+<C'> <C>;<ACUTE>;<CAPITAL>;IGNORE
+<c'> <C>;<ACUTE>;<SMALL>;IGNORE
+<C/>> <C>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<c/>> <C>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<C<> <C>;<CARON>;<CAPITAL>;IGNORE
+<c<> <C>;<CARON>;<SMALL>;IGNORE
+<C2> <C>;<HOOK>;<CAPITAL>;IGNORE
+<c2> <C>;<HOOK>;<SMALL>;IGNORE
+<C.> <C>;<DOT>;<CAPITAL>;IGNORE
+<c.> <C>;<DOT>;<SMALL>;IGNORE
+<C,> <C>;<CEDILLA>;<CAPITAL>;IGNORE
+<c,> <C>;<CEDILLA>;<SMALL>;IGNORE
+<C,'> <C>;<CEDILLA+ACUTE>;<CAPITAL>;IGNORE
+<c,'> <C>;<CEDILLA+ACUTE>;<SMALL>;IGNORE
+<c8>
+<D> <D>;<NONE>;<CAPITAL>;IGNORE
+<d> <D>;<NONE>;<SMALL>;IGNORE
+<D<> <D>;<CARON>;<CAPITAL>;IGNORE
+<d<> <D>;<CARON>;<SMALL>;IGNORE
+<D.> <D>;<DOT>;<CAPITAL>;IGNORE
+<d.> <D>;<DOT>;<SMALL>;IGNORE
+<D-.> <D>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<d-.> <D>;<DOT-BELOW>;<SMALL>;IGNORE
+<D//> <D>;<STROKE>;<CAPITAL>;IGNORE
+<d//> <D>;<STROKE>;<SMALL>;IGNORE
+<D,> <D>;<CEDILLA>;<CAPITAL>;IGNORE
+<d,> <D>;<CEDILLA>;<SMALL>;IGNORE
+<D-/>> <D>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<d-/>> <D>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<D_> <D>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<d_> <D>;<LINE-BELOW>;<SMALL>;IGNORE
+<d8>
+<E> <E>;<NONE>;<CAPITAL>;IGNORE
+<e> <E>;<NONE>;<SMALL>;IGNORE
+<E'> <E>;<ACUTE>;<CAPITAL>;IGNORE
+<e'> <E>;<ACUTE>;<SMALL>;IGNORE
+<E!> <E>;<GRAVE>;<CAPITAL>;IGNORE
+<e!> <E>;<GRAVE>;<SMALL>;IGNORE
+<E!!> <E>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<e!!> <E>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<E(> <E>;<BREVE>;<CAPITAL>;IGNORE
+<e(> <E>;<BREVE>;<SMALL>;IGNORE
+<E)> <E>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<e)> <E>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<E/>> <E>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<e/>> <E>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<E/>'> <E>;<CIRCUMFLEX+ACUTE>;<CAPITAL>;IGNORE
+<e/>'> <E>;<CIRCUMFLEX+ACUTE>;<SMALL>;IGNORE
+<E/>!> <E>;<CIRCUMFLEX+GRAVE>;<CAPITAL>;IGNORE
+<e/>!> <E>;<CIRCUMFLEX+GRAVE>;<SMALL>;IGNORE
+<E/>2> <E>;<CIRCUMFLEX+HOOK>;<CAPITAL>;IGNORE
+<e/>2> <E>;<CIRCUMFLEX+HOOK>;<SMALL>;IGNORE
+<E/>?> <E>;<CIRCUMFLEX+TILDE>;<CAPITAL>;IGNORE
+<e/>?> <E>;<CIRCUMFLEX+TILDE>;<SMALL>;IGNORE
+<E/>-.> <E>;<CIRCUMFLEX+DOT-BELOW>;<CAPITAL>;IGNORE
+<e/>-.> <E>;<CIRCUMFLEX+DOT-BELOW>;<SMALL>;IGNORE
+<E<> <E>;<CARON>;<CAPITAL>;IGNORE
+<e<> <E>;<CARON>;<SMALL>;IGNORE
+<E:> <E>;<DIAERESIS>;<CAPITAL>;IGNORE
+<e:> <E>;<DIAERESIS>;<SMALL>;IGNORE
+<E2> <E>;<HOOK>;<CAPITAL>;IGNORE
+<e2> <E>;<HOOK>;<SMALL>;IGNORE
+<E?> <E>;<TILDE>;<CAPITAL>;IGNORE
+<e?> <E>;<TILDE>;<SMALL>;IGNORE
+<E-?> <E>;<TILDE-BELOW>;<CAPITAL>;IGNORE
+<e-?> <E>;<TILDE-BELOW>;<SMALL>;IGNORE
+<E.> <E>;<DOT>;<CAPITAL>;IGNORE
+<e.> <E>;<DOT>;<SMALL>;IGNORE
+<E-.> <E>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<e-.> <E>;<DOT-BELOW>;<SMALL>;IGNORE
+<E,(> <E>;<CEDILLA+BREVE>;<CAPITAL>;IGNORE
+<e,(> <E>;<CEDILLA+BREVE>;<SMALL>;IGNORE
+<E;> <E>;<OGONEK>;<CAPITAL>;IGNORE
+<e;> <E>;<OGONEK>;<SMALL>;IGNORE
+<E-> <E>;<MACRON>;<CAPITAL>;IGNORE
+<e-> <E>;<MACRON>;<SMALL>;IGNORE
+<E-'> <E>;<MACRON+ACUTE>;<CAPITAL>;IGNORE
+<e-'> <E>;<MACRON+ACUTE>;<SMALL>;IGNORE
+<E-!> <E>;<MACRON+GRAVE>;<CAPITAL>;IGNORE
+<e-!> <E>;<MACRON+GRAVE>;<SMALL>;IGNORE
+<E-/>> <E>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<e-/>> <E>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<e8>
+<F> <F>;<NONE>;<CAPITAL>;IGNORE
+<f> <F>;<NONE>;<SMALL>;IGNORE
+<F2> <F>;<HOOK>;<CAPITAL>;IGNORE
+<f2> <F>;<HOOK>;<SMALL>;IGNORE
+<F.> <F>;<DOT>;<CAPITAL>;IGNORE
+<f.> <F>;<DOT>;<SMALL>;IGNORE
+<f8>
+<ff> "<F><F>";"<NONE><NONE>";"<ff><ff>";IGNORE
+<fi> "<F><I>";"<NONE><NONE>";"<fi><fi>";IGNORE
+<fl> "<F><L>";"<NONE><NONE>";"<fl><fl>";IGNORE
+<ffi> "<F><F><I>";"<NONE><NONE><NONE>";"<ffi><ffi><ffi>";IGNORE
+<ffl> "<F><F><L>";"<NONE><NONE><NONE>";"<ffl><ffl><ffl>";IGNORE
+<ft> "<F><T>";"<NONE><NONE>";"<ft><ft>";IGNORE
+<G> <G>;<NONE>;<CAPITAL>;IGNORE
+<g> <G>;<NONE>;<SMALL>;IGNORE
+<G'> <G>;<ACUTE>;<CAPITAL>;IGNORE
+<g'> <G>;<ACUTE>;<SMALL>;IGNORE
+<G(> <G>;<BREVE>;<CAPITAL>;IGNORE
+<g(> <G>;<BREVE>;<SMALL>;IGNORE
+<G/>> <G>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<g/>> <G>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<G<> <G>;<CARON>;<CAPITAL>;IGNORE
+<g<> <G>;<CARON>;<SMALL>;IGNORE
+<G.> <G>;<DOT>;<CAPITAL>;IGNORE
+<g.> <G>;<DOT>;<SMALL>;IGNORE
+<G//> <G>;<STROKE>;<CAPITAL>;IGNORE
+<g//> <G>;<STROKE>;<SMALL>;IGNORE
+<G,> <G>;<CEDILLA>;<CAPITAL>;IGNORE
+<g,> <G>;<CEDILLA>;<SMALL>;IGNORE
+<G-> <G>;<MACRON>;<CAPITAL>;IGNORE
+<g-> <G>;<MACRON>;<SMALL>;IGNORE
+<g8>
+<H> <H>;<NONE>;<CAPITAL>;IGNORE
+<h> <H>;<NONE>;<SMALL>;IGNORE
+<H-(> <H>;<BREVE-BELOW>;<CAPITAL>;IGNORE
+<h-(> <H>;<BREVE-BELOW>;<SMALL>;IGNORE
+<H/>> <H>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<h/>> <H>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<H:> <H>;<DIAERESIS>;<CAPITAL>;IGNORE
+<h:> <H>;<DIAERESIS>;<SMALL>;IGNORE
+<H.> <H>;<DOT>;<CAPITAL>;IGNORE
+<h.> <H>;<DOT>;<SMALL>;IGNORE
+<H-.> <H>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<h-.> <H>;<DOT-BELOW>;<SMALL>;IGNORE
+<H//> <H>;<STROKE>;<CAPITAL>;IGNORE
+<h//> <H>;<STROKE>;<SMALL>;IGNORE
+<H,> <H>;<CEDILLA>;<CAPITAL>;IGNORE
+<h,> <H>;<CEDILLA>;<SMALL>;IGNORE
+<h8>
+<I> <I>;<NONE>;<CAPITAL>;IGNORE
+<i> <I>;<NONE>;<SMALL>;IGNORE
+<I'> <I>;<ACUTE>;<CAPITAL>;IGNORE
+<i'> <I>;<ACUTE>;<SMALL>;IGNORE
+<I!> <I>;<GRAVE>;<CAPITAL>;IGNORE
+<i!> <I>;<GRAVE>;<SMALL>;IGNORE
+<I!!> <I>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<i!!> <I>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<I(> <I>;<BREVE>;<CAPITAL>;IGNORE
+<i(> <I>;<BREVE>;<SMALL>;IGNORE
+<I)> <I>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<i)> <I>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<I/>> <I>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<i/>> <I>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<I<> <I>;<CARON>;<CAPITAL>;IGNORE
+<i<> <I>;<CARON>;<SMALL>;IGNORE
+<I:> <I>;<DIAERESIS>;<CAPITAL>;IGNORE
+<i:> <I>;<DIAERESIS>;<SMALL>;IGNORE
+<I:'> <I>;<DIAERESIS+ACUTE>;<CAPITAL>;IGNORE
+<i:'> <I>;<DIAERESIS+ACUTE>;<SMALL>;IGNORE
+<I2> <I>;<HOOK>;<CAPITAL>;IGNORE
+<i2> <I>;<HOOK>;<SMALL>;IGNORE
+<I?> <I>;<TILDE>;<CAPITAL>;IGNORE
+<i?> <I>;<TILDE>;<SMALL>;IGNORE
+<I-?> <I>;<TILDE-BELOW>;<CAPITAL>;IGNORE
+<i-?> <I>;<TILDE-BELOW>;<SMALL>;IGNORE
+<I.> <I>;<DOT>;<CAPITAL>;IGNORE
+<i.> <I>;<DOT>;<SMALL>;IGNORE
+<I-.> <I>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<i-.> <I>;<DOT-BELOW>;<SMALL>;IGNORE
+<I;> <I>;<OGONEK>;<CAPITAL>;IGNORE
+<i;> <I>;<OGONEK>;<SMALL>;IGNORE
+<I-> <I>;<MACRON>;<CAPITAL>;IGNORE
+<i-> <I>;<MACRON>;<SMALL>;IGNORE
+<i8>
+<IJ> "<I><J>";"<IJ><IJ>";"<CAPITAL><CAPITAL>";IGNORE
+<ij> "<I><J>";"<IJ><IJ>";"<SMALL><SMALL>";IGNORE
+<J> <J>;<NONE>;<CAPITAL>;IGNORE
+<j> <J>;<NONE>;<SMALL>;IGNORE
+<J/>> <J>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<j/>> <J>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<j8>
+<K> <K>;<NONE>;<CAPITAL>;IGNORE
+<k> <K>;<NONE>;<SMALL>;IGNORE
+<K'> <K>;<ACUTE>;<CAPITAL>;IGNORE
+<k'> <K>;<ACUTE>;<SMALL>;IGNORE
+<K<> <K>;<CARON>;<CAPITAL>;IGNORE
+<k<> <K>;<CARON>;<SMALL>;IGNORE
+<K2> <K>;<HOOK>;<CAPITAL>;IGNORE
+<k2> <K>;<HOOK>;<SMALL>;IGNORE
+<K-.> <K>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<k-.> <K>;<DOT-BELOW>;<SMALL>;IGNORE
+<K,> <K>;<CEDILLA>;<CAPITAL>;IGNORE
+<k,> <K>;<CEDILLA>;<SMALL>;IGNORE
+<K_> <K>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<k_> <K>;<LINE-BELOW>;<SMALL>;IGNORE
+<k8>
+<kk> <K>;<kk>;<SMALL>;IGNORE
+<L> <L>;<NONE>;<CAPITAL>;IGNORE
+<l> <L>;<NONE>;<SMALL>;IGNORE
+<L'> <L>;<ACUTE>;<CAPITAL>;IGNORE
+<l'> <L>;<ACUTE>;<SMALL>;IGNORE
+<L<> <L>;<CARON>;<CAPITAL>;IGNORE
+<l<> <L>;<CARON>;<SMALL>;IGNORE
+<L.> <L>;<DOT>;<CAPITAL>;IGNORE
+<l.> <L>;<DOT>;<SMALL>;IGNORE
+<L-.> <L>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<l-.> <L>;<DOT-BELOW>;<SMALL>;IGNORE
+<L//> <L>;<STROKE>;<CAPITAL>;IGNORE
+<l//> <L>;<STROKE>;<SMALL>;IGNORE
+<L,> <L>;<CEDILLA>;<CAPITAL>;IGNORE
+<l,> <L>;<CEDILLA>;<SMALL>;IGNORE
+<L--.> <L>;<MACRON+DOT-BELOW>;<CAPITAL>;IGNORE
+<l--.> <L>;<MACRON+DOT-BELOW>;<SMALL>;IGNORE
+<L-/>> <L>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<l-/>> <L>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<L_> <L>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<l_> <L>;<LINE-BELOW>;<SMALL>;IGNORE
+<l8>
+<M> <M>;<NONE>;<CAPITAL>;IGNORE
+<m> <M>;<NONE>;<SMALL>;IGNORE
+<M'> <M>;<ACUTE>;<CAPITAL>;IGNORE
+<m'> <M>;<ACUTE>;<SMALL>;IGNORE
+<M.> <M>;<DOT>;<CAPITAL>;IGNORE
+<m.> <M>;<DOT>;<SMALL>;IGNORE
+<M-.> <M>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<m-.> <M>;<DOT-BELOW>;<SMALL>;IGNORE
+<m8>
+<N> <N>;<NONE>;<CAPITAL>;IGNORE
+<n> <N>;<NONE>;<SMALL>;IGNORE
+<N'> <N>;<ACUTE>;<CAPITAL>;IGNORE
+<n'> <N>;<ACUTE>;<SMALL>;IGNORE
+<N<> <N>;<CARON>;<CAPITAL>;IGNORE
+<n<> <N>;<CARON>;<SMALL>;IGNORE
+<N?> <N>;<TILDE>;<CAPITAL>;IGNORE
+<n?> <N>;<TILDE>;<SMALL>;IGNORE
+<N.> <N>;<DOT>;<CAPITAL>;IGNORE
+<n.> <N>;<DOT>;<SMALL>;IGNORE
+<N-.> <N>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<n-.> <N>;<DOT-BELOW>;<SMALL>;IGNORE
+<N,> <N>;<CEDILLA>;<CAPITAL>;IGNORE
+<n,> <N>;<CEDILLA>;<SMALL>;IGNORE
+<N-/>> <N>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<n-/>> <N>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<N_> <N>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<n_> <N>;<LINE-BELOW>;<SMALL>;IGNORE
+<'n> <N>;<PRECEDED-BY-APOSTROPHE>;<SMALL>;IGNORE
+<n8>
+<NG> "<N><G>";"<NG><NG>";"<CAPITAL><CAPITAL>";IGNORE
+<ng> "<N><G>";"<NG><NG>";"<SMALL><SMALL>";IGNORE
+<O> <O>;<NONE>;<CAPITAL>;IGNORE
+<o> <O>;<NONE>;<SMALL>;IGNORE
+<-o> <O>;<NONE>;<-o>;IGNORE
+<O'> <O>;<ACUTE>;<CAPITAL>;IGNORE
+<o'> <O>;<ACUTE>;<SMALL>;IGNORE
+<O!> <O>;<GRAVE>;<CAPITAL>;IGNORE
+<o!> <O>;<GRAVE>;<SMALL>;IGNORE
+<O!!> <O>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<o!!> <O>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<O(> <O>;<BREVE>;<CAPITAL>;IGNORE
+<o(> <O>;<BREVE>;<SMALL>;IGNORE
+<O)> <O>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<o)> <O>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<O/>> <O>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<o/>> <O>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<O/>'> <O>;<CIRCUMFLEX+ACUTE>;<CAPITAL>;IGNORE
+<o/>'> <O>;<CIRCUMFLEX+ACUTE>;<SMALL>;IGNORE
+<O/>!> <O>;<CIRCUMFLEX+GRAVE>;<CAPITAL>;IGNORE
+<o/>!> <O>;<CIRCUMFLEX+GRAVE>;<SMALL>;IGNORE
+<O/>2> <O>;<CIRCUMFLEX+HOOK>;<CAPITAL>;IGNORE
+<o/>2> <O>;<CIRCUMFLEX+HOOK>;<SMALL>;IGNORE
+<O/>?> <O>;<CIRCUMFLEX+TILDE>;<CAPITAL>;IGNORE
+<o/>?> <O>;<CIRCUMFLEX+TILDE>;<SMALL>;IGNORE
+<O/>-.> <O>;<CIRCUMFLEX+DOT-BELOW>;<CAPITAL>;IGNORE
+<o/>-.> <O>;<CIRCUMFLEX+DOT-BELOW>;<SMALL>;IGNORE
+<O<> <O>;<CARON>;<CAPITAL>;IGNORE
+<o<> <O>;<CARON>;<SMALL>;IGNORE
+<O:> <O>;<DIAERESIS>;<CAPITAL>;IGNORE
+<o:> <O>;<DIAERESIS>;<SMALL>;IGNORE
+<O"> <O>;<DOUBLE-ACUTE>;<CAPITAL>;IGNORE
+<o"> <O>;<DOUBLE-ACUTE>;<SMALL>;IGNORE
+<O2> <O>;<HOOK>;<CAPITAL>;IGNORE
+<o2> <O>;<HOOK>;<SMALL>;IGNORE
+<O?> <O>;<TILDE>;<CAPITAL>;IGNORE
+<o?> <O>;<TILDE>;<SMALL>;IGNORE
+<O?'> <O>;<TILDE+ACUTE>;<CAPITAL>;IGNORE
+<o?'> <O>;<TILDE+ACUTE>;<SMALL>;IGNORE
+<O?:> <O>;<TILDE+DIAERESIS>;<CAPITAL>;IGNORE
+<o?:> <O>;<TILDE+DIAERESIS>;<SMALL>;IGNORE
+<O-.> <O>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<o-.> <O>;<DOT-BELOW>;<SMALL>;IGNORE
+<O//> <O>;<STROKE>;<CAPITAL>;IGNORE
+<o//> <O>;<STROKE>;<SMALL>;IGNORE
+<O//'> <O>;<STROKE+ACUTE>;<CAPITAL>;IGNORE
+<o//'> <O>;<STROKE+ACUTE>;<SMALL>;IGNORE
+<O;> <O>;<OGONEK>;<CAPITAL>;IGNORE
+<o;> <O>;<OGONEK>;<SMALL>;IGNORE
+<O1> <O>;<OGONEK+MACRON>;<CAPITAL>;IGNORE
+<o1> <O>;<OGONEK+MACRON>;<SMALL>;IGNORE
+<O-> <O>;<MACRON>;<CAPITAL>;IGNORE
+<o-> <O>;<MACRON>;<SMALL>;IGNORE
+<O-'> <O>;<MACRON+ACUTE>;<CAPITAL>;IGNORE
+<o-'> <O>;<MACRON+ACUTE>;<SMALL>;IGNORE
+<O-!> <O>;<MACRON+GRAVE>;<CAPITAL>;IGNORE
+<o-!> <O>;<MACRON+GRAVE>;<SMALL>;IGNORE
+<O9> <O>;<HORN>;<CAPITAL>;IGNORE
+<o9> <O>;<HORN>;<SMALL>;IGNORE
+<O9'> <O>;<HORN+ACUTE>;<CAPITAL>;IGNORE
+<o9'> <O>;<HORN+ACUTE>;<SMALL>;IGNORE
+<O9!> <O>;<HORN+GRAVE>;<CAPITAL>;IGNORE
+<o9!> <O>;<HORN+GRAVE>;<SMALL>;IGNORE
+<O92> <O>;<HORN+HOOK>;<CAPITAL>;IGNORE
+<o92> <O>;<HORN+HOOK>;<SMALL>;IGNORE
+<O9?> <O>;<HORN+TILDE>;<CAPITAL>;IGNORE
+<o9?> <O>;<HORN+TILDE>;<SMALL>;IGNORE
+<O9-.> <O>;<HORN+DOT-BELOW>;<CAPITAL>;IGNORE
+<o9-.> <O>;<HORN+DOT-BELOW>;<SMALL>;IGNORE
+<o8>
+<OE> "<O><E>";"<OE><OE>";"<CAPITAL><CAPITAL>";IGNORE
+<oe> "<O><E>";"<OE><OE>";"<SMALL><SMALL>";IGNORE
+<P> <P>;<NONE>;<CAPITAL>;IGNORE
+<p> <P>;<NONE>;<SMALL>;IGNORE
+<P'> <P>;<ACUTE>;<CAPITAL>;IGNORE
+<p'> <P>;<ACUTE>;<SMALL>;IGNORE
+<P.> <P>;<DOT>;<CAPITAL>;IGNORE
+<p.> <P>;<DOT>;<SMALL>;IGNORE
+<p8>
+<Q> <Q>;<NONE>;<CAPITAL>;IGNORE
+<q> <Q>;<NONE>;<SMALL>;IGNORE
+<q8>
+<R> <R>;<NONE>;<CAPITAL>;IGNORE
+<r> <R>;<NONE>;<SMALL>;IGNORE
+<R'> <R>;<ACUTE>;<CAPITAL>;IGNORE
+<r'> <R>;<ACUTE>;<SMALL>;IGNORE
+<R!!> <R>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<r!!> <R>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<R)> <R>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<r)> <R>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<R<> <R>;<CARON>;<CAPITAL>;IGNORE
+<r<> <R>;<CARON>;<SMALL>;IGNORE
+<R.> <R>;<DOT>;<CAPITAL>;IGNORE
+<r.> <R>;<DOT>;<SMALL>;IGNORE
+<R-.> <R>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<r-.> <R>;<DOT-BELOW>;<SMALL>;IGNORE
+<R,> <R>;<CEDILLA>;<CAPITAL>;IGNORE
+<r,> <R>;<CEDILLA>;<SMALL>;IGNORE
+<R--.> <R>;<MACRON+DOT-BELOW>;<CAPITAL>;IGNORE
+<r--.> <R>;<MACRON+DOT-BELOW>;<SMALL>;IGNORE
+<R_> <R>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<r_> <R>;<LINE-BELOW>;<SMALL>;IGNORE
+<r8>
+<S> <S>;<NONE>;<CAPITAL>;IGNORE
+<s> <S>;<NONE>;<SMALL>;IGNORE
+<st> "<S><T>";"<NONE><NONE>";"<st><st>";IGNORE
+<S'> <S>;<ACUTE>;<CAPITAL>;IGNORE
+<s'> <S>;<ACUTE>;<SMALL>;IGNORE
+<S'.> <S>;<ACUTE+DOT>;<CAPITAL>;IGNORE
+<s'.> <S>;<ACUTE+DOT>;<SMALL>;IGNORE
+<S/>> <S>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<s/>> <S>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<S<> <S>;<CARON>;<CAPITAL>;IGNORE
+<s<> <S>;<CARON>;<SMALL>;IGNORE
+<S<.> <S>;<CARON+DOT>;<CAPITAL>;IGNORE
+<s<.> <S>;<CARON+DOT>;<SMALL>;IGNORE
+<S.> <S>;<DOT>;<CAPITAL>;IGNORE
+<s.> <S>;<DOT>;<SMALL>;IGNORE
+<S-.> <S>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<s-.> <S>;<DOT-BELOW>;<SMALL>;IGNORE
+<S.-.> <S>;<DOT+DOT-BELOW>;<CAPITAL>;IGNORE
+<s.-.> <S>;<DOT+DOT-BELOW>;<SMALL>;IGNORE
+<S,> <S>;<CEDILLA>;<CAPITAL>;IGNORE
+<s,> <S>;<CEDILLA>;<SMALL>;IGNORE
+<s8>
+<s1> <S>;<s1>;<SMALL>;IGNORE
+<ss> "<S><S>";"<NONE><NONE>";"<SMALL><ss>";IGNORE
+<T> <T>;<NONE>;<CAPITAL>;IGNORE
+<t> <T>;<NONE>;<SMALL>;IGNORE
+<T<> <T>;<CARON>;<CAPITAL>;IGNORE
+<t<> <T>;<CARON>;<SMALL>;IGNORE
+<T.> <T>;<DOT>;<CAPITAL>;IGNORE
+<t.> <T>;<DOT>;<SMALL>;IGNORE
+<T-.> <T>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<t-.> <T>;<DOT-BELOW>;<SMALL>;IGNORE
+<T//> <T>;<STROKE>;<CAPITAL>;IGNORE
+<t//> <T>;<STROKE>;<SMALL>;IGNORE
+<T,> <T>;<CEDILLA>;<CAPITAL>;IGNORE
+<t,> <T>;<CEDILLA>;<SMALL>;IGNORE
+<T-/>> <T>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<t-/>> <T>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<T_> <T>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<t_> <T>;<LINE-BELOW>;<SMALL>;IGNORE
+<t8>
+<TH> "<T><H>";"<TH><TH>";"<CAPITAL><CAPITAL>";IGNORE
+<th> "<T><H>";"<TH><TH>";"<SMALL><SMALL>";IGNORE
+<U> <U>;<NONE>;<CAPITAL>;IGNORE
+<u> <U>;<NONE>;<SMALL>;IGNORE
+<U'> <U>;<ACUTE>;<CAPITAL>;IGNORE
+<u'> <U>;<ACUTE>;<SMALL>;IGNORE
+<U!> <U>;<GRAVE>;<CAPITAL>;IGNORE
+<u!> <U>;<GRAVE>;<SMALL>;IGNORE
+<U!!> <U>;<DOUBLE-GRAVE>;<CAPITAL>;IGNORE
+<u!!> <U>;<DOUBLE-GRAVE>;<SMALL>;IGNORE
+<U(> <U>;<BREVE>;<CAPITAL>;IGNORE
+<u(> <U>;<BREVE>;<SMALL>;IGNORE
+<U)> <U>;<INVERTED-BREVE>;<CAPITAL>;IGNORE
+<u)> <U>;<INVERTED-BREVE>;<SMALL>;IGNORE
+<U/>> <U>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<u/>> <U>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<U<> <U>;<CARON>;<CAPITAL>;IGNORE
+<u<> <U>;<CARON>;<SMALL>;IGNORE
+<U0> <U>;<RING>;<CAPITAL>;IGNORE
+<u0> <U>;<RING>;<SMALL>;IGNORE
+<U:> <U>;<DIAERESIS>;<CAPITAL>;IGNORE
+<u:> <U>;<DIAERESIS>;<SMALL>;IGNORE
+<U:-> <U>;<DIAERESIS+MACRON>;<CAPITAL>;IGNORE
+<u:-> <U>;<DIAERESIS+MACRON>;<SMALL>;IGNORE
+<U:'> <U>;<DIAERESIS+ACUTE>;<CAPITAL>;IGNORE
+<u:'> <U>;<DIAERESIS+ACUTE>;<SMALL>;IGNORE
+<U:!> <U>;<DIAERESIS+GRAVE>;<CAPITAL>;IGNORE
+<u:!> <U>;<DIAERESIS+GRAVE>;<SMALL>;IGNORE
+<U:<> <U>;<DIAERESIS+CARON>;<CAPITAL>;IGNORE
+<u:<> <U>;<DIAERESIS+CARON>;<SMALL>;IGNORE
+<U"> <U>;<DOUBLE-ACUTE>;<CAPITAL>;IGNORE
+<u"> <U>;<DOUBLE-ACUTE>;<SMALL>;IGNORE
+<U2> <U>;<HOOK>;<CAPITAL>;IGNORE
+<u2> <U>;<HOOK>;<SMALL>;IGNORE
+<U?> <U>;<TILDE>;<CAPITAL>;IGNORE
+<u?> <U>;<TILDE>;<SMALL>;IGNORE
+<U?'> <U>;<TILDE+ACUTE>;<CAPITAL>;IGNORE
+<u?'> <U>;<TILDE+ACUTE>;<SMALL>;IGNORE
+<U-?> <U>;<TILDE-BELOW>;<CAPITAL>;IGNORE
+<u-?> <U>;<TILDE-BELOW>;<SMALL>;IGNORE
+<U-.> <U>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<u-.> <U>;<DOT-BELOW>;<SMALL>;IGNORE
+<U;> <U>;<OGONEK>;<CAPITAL>;IGNORE
+<u;> <U>;<OGONEK>;<SMALL>;IGNORE
+<U-> <U>;<MACRON>;<CAPITAL>;IGNORE
+<u-> <U>;<MACRON>;<SMALL>;IGNORE
+<U-:> <U>;<MACRON+DIAERESIS>;<CAPITAL>;IGNORE
+<u-:> <U>;<MACRON+DIAERESIS>;<SMALL>;IGNORE
+<U--:> <U>;<MACRON+DIAERESIS-BELOW>;<CAPITAL>;IGNORE
+<u--:> <U>;<MACRON+DIAERESIS-BELOW>;<SMALL>;IGNORE
+<U-/>> <U>;<MACRON+CIRCUMFLEX>;<CAPITAL>;IGNORE
+<u-/>> <U>;<MACRON+CIRCUMFLEX>;<SMALL>;IGNORE
+<U9> <U>;<HORN>;<CAPITAL>;IGNORE
+<u9> <U>;<HORN>;<SMALL>;IGNORE
+<U9'> <U>;<HORN+ACUTE>;<CAPITAL>;IGNORE
+<u9'> <U>;<HORN+ACUTE>;<SMALL>;IGNORE
+<U9!> <U>;<HORN+GRAVE>;<CAPITAL>;IGNORE
+<u9!> <U>;<HORN+GRAVE>;<SMALL>;IGNORE
+<U92> <U>;<HORN+HOOK>;<CAPITAL>;IGNORE
+<u92> <U>;<HORN+HOOK>;<SMALL>;IGNORE
+<U9?> <U>;<HORN+TILDE>;<CAPITAL>;IGNORE
+<u9?> <U>;<HORN+TILDE>;<SMALL>;IGNORE
+<U9-.> <U>;<HORN+DOT-BELOW>;<CAPITAL>;IGNORE
+<u9-.> <U>;<HORN+DOT-BELOW>;<SMALL>;IGNORE
+<u8>
+<V> <V>;<NONE>;<CAPITAL>;IGNORE
+<v> <V>;<NONE>;<SMALL>;IGNORE
+<V?> <V>;<TILDE>;<CAPITAL>;IGNORE
+<v?> <V>;<TILDE>;<SMALL>;IGNORE
+<V-.> <V>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<v-.> <V>;<DOT-BELOW>;<SMALL>;IGNORE
+<v8>
+<W> <W>;<NONE>;<CAPITAL>;IGNORE
+<w> <W>;<NONE>;<SMALL>;IGNORE
+<W'> <W>;<ACUTE>;<CAPITAL>;IGNORE
+<w'> <W>;<ACUTE>;<SMALL>;IGNORE
+<W!> <W>;<GRAVE>;<CAPITAL>;IGNORE
+<w!> <W>;<GRAVE>;<SMALL>;IGNORE
+<W/>> <W>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<w/>> <W>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<W:> <W>;<DIAERESIS>;<CAPITAL>;IGNORE
+<w:> <W>;<DIAERESIS>;<SMALL>;IGNORE
+<W.> <W>;<DOT>;<CAPITAL>;IGNORE
+<w.> <W>;<DOT>;<SMALL>;IGNORE
+<W-.> <W>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<w-.> <W>;<DOT-BELOW>;<SMALL>;IGNORE
+<w8>
+<X> <X>;<NONE>;<CAPITAL>;IGNORE
+<x> <X>;<NONE>;<SMALL>;IGNORE
+<X:> <X>;<DIAERESIS>;<CAPITAL>;IGNORE
+<x:> <X>;<DIAERESIS>;<SMALL>;IGNORE
+<X.> <X>;<DOT>;<CAPITAL>;IGNORE
+<x.> <X>;<DOT>;<SMALL>;IGNORE
+<x8>
+<Y> <Y>;<NONE>;<CAPITAL>;IGNORE
+<y> <Y>;<NONE>;<SMALL>;IGNORE
+<Y'> <Y>;<ACUTE>;<CAPITAL>;IGNORE
+<y'> <Y>;<ACUTE>;<SMALL>;IGNORE
+<Y!> <Y>;<GRAVE>;<CAPITAL>;IGNORE
+<y!> <Y>;<GRAVE>;<SMALL>;IGNORE
+<Y/>> <Y>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<y/>> <Y>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<Y:> <Y>;<DIAERESIS>;<CAPITAL>;IGNORE
+<y:> <Y>;<DIAERESIS>;<SMALL>;IGNORE
+<Y2> <Y>;<HOOK>;<CAPITAL>;IGNORE
+<y2> <Y>;<HOOK>;<SMALL>;IGNORE
+<Y?> <Y>;<TILDE>;<CAPITAL>;IGNORE
+<y?> <Y>;<TILDE>;<SMALL>;IGNORE
+<Y.> <Y>;<DOT>;<CAPITAL>;IGNORE
+<y.> <Y>;<DOT>;<SMALL>;IGNORE
+<Y-.> <Y>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<y-.> <Y>;<DOT-BELOW>;<SMALL>;IGNORE
+<y8>
+<Z> <Z>;<NONE>;<CAPITAL>;IGNORE
+<z> <Z>;<NONE>;<SMALL>;IGNORE
+<Z'> <Z>;<ACUTE>;<CAPITAL>;IGNORE
+<z'> <Z>;<ACUTE>;<SMALL>;IGNORE
+<Z/>> <Z>;<CIRCUMFLEX>;<CAPITAL>;IGNORE
+<z/>> <Z>;<CIRCUMFLEX>;<SMALL>;IGNORE
+<Z<> <Z>;<CARON>;<CAPITAL>;IGNORE
+<z<> <Z>;<CARON>;<SMALL>;IGNORE
+<Z.> <Z>;<DOT>;<CAPITAL>;IGNORE
+<z.> <Z>;<DOT>;<SMALL>;IGNORE
+<Z-.> <Z>;<DOT-BELOW>;<CAPITAL>;IGNORE
+<z-.> <Z>;<DOT-BELOW>;<SMALL>;IGNORE
+<Z//> <Z>;<STROKE>;<CAPITAL>;IGNORE
+<z//> <Z>;<STROKE>;<SMALL>;IGNORE
+<Z_> <Z>;<LINE-BELOW>;<CAPITAL>;IGNORE
+<z_> <Z>;<LINE-BELOW>;<SMALL>;IGNORE
+<z8>
+<A*> <A*>;<CAPITAL>;<GREEK>;IGNORE
+<A%> <A*>;<CAPITAL>;<TONOS>;IGNORE
+<a*> <A*>;<SMALL>;<GREEK>;IGNORE
+<a%> <A*>;<SMALL>;<TONOS>;IGNORE
+<B*> <B*>;<CAPITAL>;<GREEK>;IGNORE
+<b*> <B*>;<SMALL>;<GREEK>;IGNORE
+<G*> <G*>;<CAPITAL>;<GREEK>;IGNORE
+<g*> <G*>;<SMALL>;<GREEK>;IGNORE
+<D*> <D*>;<CAPITAL>;<GREEK>;IGNORE
+<d*> <D*>;<SMALL>;<GREEK>;IGNORE
+<E*> <E*>;<CAPITAL>;<GREEK>;IGNORE
+<E%> <E*>;<CAPITAL>;<TONOS>;IGNORE
+<e*> <E*>;<SMALL>;<GREEK>;IGNORE
+<e%> <E*>;<SMALL>;<TONOS>;IGNORE
+<Z*> <Z*>;<CAPITAL>;<GREEK>;IGNORE
+<z*> <Z*>;<SMALL>;<GREEK>;IGNORE
+<Y*> <Y*>;<CAPITAL>;<GREEK>;IGNORE
+<Y%> <Y*>;<CAPITAL>;<TONOS>;IGNORE
+<y*> <Y*>;<SMALL>;<GREEK>;IGNORE
+<y%> <Y*>;<SMALL>;<TONOS>;IGNORE
+<H*> <H*>;<CAPITAL>;<GREEK>;IGNORE
+<h*> <H*>;<SMALL>;<GREEK>;IGNORE
+<I*> <I*>;<CAPITAL>;<GREEK>;IGNORE
+<I%> <I*>;<CAPITAL>;<TONOS>;IGNORE
+<J*> <I*>;<CAPITAL>;<DIALYTICA>;IGNORE
+<i*> <I*>;<SMALL>;<GREEK>;IGNORE
+<i%> <I*>;<SMALL>;<TONOS>;IGNORE
+<j*> <I*>;<SMALL>;<DIALYTICA>;IGNORE
+<i3> <I*>;<SMALL>;<DIALYTICA+TONOS>;IGNORE
+<K*> <K*>;<CAPITAL>;<GREEK>;IGNORE
+<k*> <K*>;<SMALL>;<GREEK>;IGNORE
+<L*> <L*>;<CAPITAL>;<GREEK>;IGNORE
+<l*> <L*>;<SMALL>;<GREEK>;IGNORE
+<M*> <M*>;<CAPITAL>;<GREEK>;IGNORE
+<m*> <M*>;<SMALL>;<GREEK>;IGNORE
+<N*> <N*>;<CAPITAL>;<GREEK>;IGNORE
+<n*> <N*>;<SMALL>;<GREEK>;IGNORE
+<C*> <C*>;<CAPITAL>;<GREEK>;IGNORE
+<c*> <C*>;<SMALL>;<GREEK>;IGNORE
+<O*> <O*>;<CAPITAL>;<GREEK>;IGNORE
+<O%> <O*>;<CAPITAL>;<TONOS>;IGNORE
+<o*> <O*>;<SMALL>;<GREEK>;IGNORE
+<o%> <O*>;<SMALL>;<TONOS>;IGNORE
+<P*> <P*>;<CAPITAL>;<GREEK>;IGNORE
+<p*> <P*>;<SMALL>;<GREEK>;IGNORE
+<R*> <R*>;<CAPITAL>;<GREEK>;IGNORE
+<r*> <R*>;<SMALL>;<GREEK>;IGNORE
+<S*> <S*>;<CAPITAL>;<GREEK>;IGNORE
+<s*> <S*>;<SMALL>;<GREEK>;IGNORE
+<*s> <S*>;<SMALL>;<*s>;IGNORE
+<T*> <T*>;<CAPITAL>;<GREEK>;IGNORE
+<t*> <T*>;<SMALL>;<GREEK>;IGNORE
+<U*> <U*>;<CAPITAL>;<GREEK>;IGNORE
+<U%> <U*>;<CAPITAL>;<TONOS>;IGNORE
+<V*> <U*>;<CAPITAL>;<DIALYTICA>;IGNORE
+<u*> <U*>;<SMALL>;<GREEK>;IGNORE
+<u%> <U*>;<SMALL>;<TONOS>;IGNORE
+<v*> <U*>;<SMALL>;<DIALYTICA>;IGNORE
+<u3> <U*>;<SMALL>;<DIALYTICA+TONOS>;IGNORE
+<F*> <F*>;<CAPITAL>;<GREEK>;IGNORE
+<f*> <F*>;<SMALL>;<GREEK>;IGNORE
+<X*> <X*>;<CAPITAL>;<GREEK>;IGNORE
+<x*> <X*>;<SMALL>;<GREEK>;IGNORE
+<Q*> <Q*>;<CAPITAL>;<GREEK>;IGNORE
+<q*> <Q*>;<SMALL>;<GREEK>;IGNORE
+<W*> <W*>;<CAPITAL>;<GREEK>;IGNORE
+<W%> <W*>;<CAPITAL>;<TONOS>;IGNORE
+<w*> <W*>;<SMALL>;<GREEK>;IGNORE
+<w%> <W*>;<SMALL>;<TONOS>;IGNORE
+<A=> <A=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<a=> <A=>;<CYRILLIC>;<SMALL>;IGNORE
+<B=> <B=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<b=> <B=>;<CYRILLIC>;<SMALL>;IGNORE
+<V=> <V=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<v=> <V=>;<CYRILLIC>;<SMALL>;IGNORE
+<G=> <G=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<g=> <G=>;<CYRILLIC>;<SMALL>;IGNORE
+<G%> <G%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<g%> <G%>;<CYRILLIC>;<SMALL>;IGNORE
+<G3> <G3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<g3> <G3>;<CYRILLIC>;<SMALL>;IGNORE
+<D=> <D=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<d=> <D=>;<CYRILLIC>;<SMALL>;IGNORE
+<D%> <D%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<d%> <D%>;<CYRILLIC>;<SMALL>;IGNORE
+<E=> <E=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<e=> <E=>;<CYRILLIC>;<SMALL>;IGNORE
+<IO> <IO>;<CYRILLIC>;<CAPITAL>;IGNORE
+<io> <IO>;<CYRILLIC>;<SMALL>;IGNORE
+<IE> <IE>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ie> <IE>;<CYRILLIC>;<SMALL>;IGNORE
+<Z%> <Z%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<z%> <Z%>;<CYRILLIC>;<SMALL>;IGNORE
+<Z=> <Z=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<z=> <Z=>;<CYRILLIC>;<SMALL>;IGNORE
+<I=> <I=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<i=> <I=>;<CYRILLIC>;<SMALL>;IGNORE
+<II> <II>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ii> <II>;<CYRILLIC>;<SMALL>;IGNORE
+<YI> <YI>;<CYRILLIC>;<CAPITAL>;IGNORE
+<yi> <YI>;<CYRILLIC>;<SMALL>;IGNORE
+<J%> <J%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<j%> <J%>;<CYRILLIC>;<SMALL>;IGNORE
+<J=> <J=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<j=> <J=>;<CYRILLIC>;<SMALL>;IGNORE
+<K=> <K=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<k=> <K=>;<CYRILLIC>;<SMALL>;IGNORE
+<KJ> <KJ>;<CYRILLIC>;<CAPITAL>;IGNORE
+<kj> <KJ>;<CYRILLIC>;<SMALL>;IGNORE
+<L=> <L=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<l=> <L=>;<CYRILLIC>;<SMALL>;IGNORE
+<LJ> <LJ>;<CYRILLIC>;<CAPITAL>;IGNORE
+<lj> <LJ>;<CYRILLIC>;<SMALL>;IGNORE
+<M=> <M=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<m=> <M=>;<CYRILLIC>;<SMALL>;IGNORE
+<N=> <N=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<n=> <N=>;<CYRILLIC>;<SMALL>;IGNORE
+<NJ> <NJ>;<CYRILLIC>;<CAPITAL>;IGNORE
+<nj> <NJ>;<CYRILLIC>;<SMALL>;IGNORE
+<O=> <O=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<o=> <O=>;<CYRILLIC>;<SMALL>;IGNORE
+<P=> <P=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<p=> <P=>;<CYRILLIC>;<SMALL>;IGNORE
+<R=> <R=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<r=> <R=>;<CYRILLIC>;<SMALL>;IGNORE
+<S=> <S=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<s=> <S=>;<CYRILLIC>;<SMALL>;IGNORE
+<T=> <T=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<t=> <T=>;<CYRILLIC>;<SMALL>;IGNORE
+<Ts> <Ts>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ts> <Ts>;<CYRILLIC>;<SMALL>;IGNORE
+<U=> <U=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<u=> <U=>;<CYRILLIC>;<SMALL>;IGNORE
+<V%> <V%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<v%> <V%>;<CYRILLIC>;<SMALL>;IGNORE
+<F=> <F=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<f=> <F=>;<CYRILLIC>;<SMALL>;IGNORE
+<H=> <H=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<h=> <H=>;<CYRILLIC>;<SMALL>;IGNORE
+<C=> <C=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<c=> <C=>;<CYRILLIC>;<SMALL>;IGNORE
+<DS> <DS>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ds> <DS>;<CYRILLIC>;<SMALL>;IGNORE
+<C%> <C%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<c%> <C%>;<CYRILLIC>;<SMALL>;IGNORE
+<DZ> <DZ>;<CYRILLIC>;<CAPITAL>;IGNORE
+<dz> <DZ>;<CYRILLIC>;<SMALL>;IGNORE
+<S%> <S%>;<CYRILLIC>;<CAPITAL>;IGNORE
+<s%> <S%>;<CYRILLIC>;<SMALL>;IGNORE
+<Sc> <Sc>;<CYRILLIC>;<CAPITAL>;IGNORE
+<sc> <Sc>;<CYRILLIC>;<SMALL>;IGNORE
+<='> <='>;<CYRILLIC>;<SMALL>;IGNORE
+<="> <='>;<CYRILLIC>;<CAPITAL>;IGNORE
+<Y=> <Y=>;<CYRILLIC>;<CAPITAL>;IGNORE
+<y=> <Y=>;<CYRILLIC>;<SMALL>;IGNORE
+<%'> <%'>;<CYRILLIC>;<SMALL>;IGNORE
+<%"> <%'>;<CYRILLIC>;<CAPITAL>;IGNORE
+<JE> <JE>;<CYRILLIC>;<CAPITAL>;IGNORE
+<je> <JE>;<CYRILLIC>;<SMALL>;IGNORE
+<JU> <JU>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ju> <JU>;<CYRILLIC>;<SMALL>;IGNORE
+<JA> <JA>;<CYRILLIC>;<CAPITAL>;IGNORE
+<ja> <JA>;<CYRILLIC>;<SMALL>;IGNORE
+<Y3> <Y3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<y3> <Y3>;<CYRILLIC>;<SMALL>;IGNORE
+<O3> <O3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<o3> <O3>;<CYRILLIC>;<SMALL>;IGNORE
+<F3> <F3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<f3> <F3>;<CYRILLIC>;<SMALL>;IGNORE
+<V3> <V3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<v3> <V3>;<CYRILLIC>;<SMALL>;IGNORE
+<C3> <C3>;<CYRILLIC>;<CAPITAL>;IGNORE
+<c3> <C3>;<CYRILLIC>;<SMALL>;IGNORE
+<A+> <A+>;IGNORE;IGNORE;IGNORE
+<B+> <B+>;IGNORE;IGNORE;IGNORE
+<G+> <G+>;IGNORE;IGNORE;IGNORE
+<D+> <D+>;IGNORE;IGNORE;IGNORE
+<H+> <H+>;IGNORE;IGNORE;IGNORE
+<W+> <W+>;IGNORE;IGNORE;IGNORE
+<Z+> <Z+>;IGNORE;IGNORE;IGNORE
+<X+> <X+>;IGNORE;IGNORE;IGNORE
+<Tj> <Tj>;IGNORE;IGNORE;IGNORE
+<J+> <J+>;IGNORE;IGNORE;IGNORE
+<K%> <K%>;IGNORE;IGNORE;IGNORE
+<K+> <K+>;IGNORE;IGNORE;IGNORE
+<L+> <L+>;IGNORE;IGNORE;IGNORE
+<M%> <M%>;IGNORE;IGNORE;IGNORE
+<M+> <M+>;IGNORE;IGNORE;IGNORE
+<N%> <N%>;IGNORE;IGNORE;IGNORE
+<N+> <N+>;IGNORE;IGNORE;IGNORE
+<S+> <S+>;IGNORE;IGNORE;IGNORE
+<E+> <E+>;IGNORE;IGNORE;IGNORE
+<P%> <P%>;IGNORE;IGNORE;IGNORE
+<P+> <P+>;IGNORE;IGNORE;IGNORE
+<Zj> <Zj>;IGNORE;IGNORE;IGNORE
+<ZJ> <ZJ>;IGNORE;IGNORE;IGNORE
+<Q+> <Q+>;IGNORE;IGNORE;IGNORE
+<R+> <R+>;IGNORE;IGNORE;IGNORE
+<Sh> <Sh>;IGNORE;IGNORE;IGNORE
+<T+> <T+>;IGNORE;IGNORE;IGNORE
+
+% Arabic collating
+
+<,+> IGNORE;IGNORE;IGNORE;<,+>
+<;+> IGNORE;IGNORE;IGNORE;<;+>
+<?+> IGNORE;IGNORE;IGNORE;<?+>
+<++> IGNORE;IGNORE;IGNORE;<++>
+
+<H'> <H'>;<H'>;IGNORE;IGNORE
+<aM> <aM>;<aM>;IGNORE;IGNORE
+<aM.> <aM>;<aM.>;IGNORE;IGNORE
+<aH> <H'>;<aH>;IGNORE;IGNORE
+<aH.> <H'>;<aH.>;IGNORE;IGNORE
+<wH> <H'>;<wH>;IGNORE;IGNORE
+<ah> <H'>;<ah>;IGNORE;IGNORE
+<ah.> <H'>;<ah.>;IGNORE;IGNORE
+<yH> <H'>;<yH>;IGNORE;IGNORE
+<aS> <aS>;<aS>;IGNORE;IGNORE
+<a+> <a+>;<a+>;IGNORE;IGNORE
+<a+-> <a+>;<a+->;IGNORE;IGNORE
+<a+.> <a+>;<a+.>;IGNORE;IGNORE
+<a+:> <a+>;<a+:>;IGNORE;IGNORE
+<b+> <b+>;<b+>;IGNORE;IGNORE
+<b+-> <b+>;<b+->;IGNORE;IGNORE
+<b+.> <b+>;<b+.>;IGNORE;IGNORE
+<b+,> <b+>;<b+,>;IGNORE;IGNORE
+<b+;> <b+>;<b+;>;IGNORE;IGNORE
+<p+> <p+>;<p+>;IGNORE;IGNORE
+<v+> <v+>;<v+>;IGNORE;IGNORE
+<tm> <tm>;<tm>;IGNORE;IGNORE
+<tm-> <tm>;<tm->;IGNORE;IGNORE
+<tm.> <tm>;<tm.>;IGNORE;IGNORE
+<t+> <tm>;<t+>;IGNORE;IGNORE
+<t+-> <tm>;<t+->;IGNORE;IGNORE
+<t+.> <tm>;<t+.>;IGNORE;IGNORE
+<t+,> <tm>;<t+,>;IGNORE;IGNORE
+<t+;> <tm>;<t+;>;IGNORE;IGNORE
+<tk> <tk>;<tk>;IGNORE;IGNORE
+<tk-> <tk>;<tk->;IGNORE;IGNORE
+<tk.> <tk>;<tk.>;IGNORE;IGNORE
+<tk,> <tk>;<tk,>;IGNORE;IGNORE
+<tk;> <tk>;<tk;>;IGNORE;IGNORE
+<g+> <g+>;<g+>;IGNORE;IGNORE
+<g+-> <g+>;<g+->;IGNORE;IGNORE
+<g+.> <g+>;<g+.>;IGNORE;IGNORE
+<g+,> <g+>;<g+,>;IGNORE;IGNORE
+<g+;> <g+>;<g+;>;IGNORE;IGNORE
+<hk> <hk>;<hk>;IGNORE;IGNORE
+<hk-> <hk>;<hk->;IGNORE;IGNORE
+<hk.> <hk>;<hk.>;IGNORE;IGNORE
+<hk,> <hk>;<hk,>;IGNORE;IGNORE
+<hk;> <hk>;<hk;>;IGNORE;IGNORE
+<x+> <x+>;<x+>;IGNORE;IGNORE
+<x+-> <x+>;<x+->;IGNORE;IGNORE
+<x+.> <x+>;<x+.>;IGNORE;IGNORE
+<x+,> <x+>;<x+,>;IGNORE;IGNORE
+<x+;> <x+>;<x+;>;IGNORE;IGNORE
+<d+> <d+>;<d+>;IGNORE;IGNORE
+<d+-> <d+>;<d+->;IGNORE;IGNORE
+<d+.> <d+>;<d+.>;IGNORE;IGNORE
+<dk> <dk>;<dk>;IGNORE;IGNORE
+<dk-> <dk>;<dk->;IGNORE;IGNORE
+<dk.> <dk>;<dk.>;IGNORE;IGNORE
+<r+> <r+>;<r+>;IGNORE;IGNORE
+<r+-> <r+>;<r+->;IGNORE;IGNORE
+<r+.> <r+>;<r+.>;IGNORE;IGNORE
+<z+> <z+>;<z+>;IGNORE;IGNORE
+<z+-> <z+>;<z+->;IGNORE;IGNORE
+<z+.> <z+>;<z+.>;IGNORE;IGNORE
+<s+> <s+>;<s+>;IGNORE;IGNORE
+<s+-> <s+>;<s+->;IGNORE;IGNORE
+<s+.> <s+>;<s+.>;IGNORE;IGNORE
+<s+,> <s+>;<s+,>;IGNORE;IGNORE
+<s+;> <s+>;<s+;>;IGNORE;IGNORE
+<sn> <sn>;<sn>;IGNORE;IGNORE
+<sn-> <sn>;<sn->;IGNORE;IGNORE
+<sn.> <sn>;<sn.>;IGNORE;IGNORE
+<sn,> <sn>;<sn,>;IGNORE;IGNORE
+<sn;> <sn>;<sn;>;IGNORE;IGNORE
+<c+> <c+>;<c+>;IGNORE;IGNORE
+<c+-> <c+>;<c+->;IGNORE;IGNORE
+<c+.> <c+>;<c+.>;IGNORE;IGNORE
+<c+,> <c+>;<c+,>;IGNORE;IGNORE
+<c+;> <c+>;<c+;>;IGNORE;IGNORE
+<dd> <dd>;<dd>;IGNORE;IGNORE
+<dd-> <dd>;<dd->;IGNORE;IGNORE
+<dd.> <dd>;<dd.>;IGNORE;IGNORE
+<dd,> <dd>;<dd,>;IGNORE;IGNORE
+<dd;> <dd>;<dd;>;IGNORE;IGNORE
+<tj> <tj>;<tj>;IGNORE;IGNORE
+<tj-> <tj>;<tj->;IGNORE;IGNORE
+<tj.> <tj>;<tj.>;IGNORE;IGNORE
+<tj,> <tj>;<tj,>;IGNORE;IGNORE
+<tj;> <tj>;<tj;>;IGNORE;IGNORE
+<zH> <zH>;<zH>;IGNORE;IGNORE
+<zH-> <zH>;<zH->;IGNORE;IGNORE
+<zH.> <zH>;<zH.>;IGNORE;IGNORE
+<zH,> <zH>;<zH,>;IGNORE;IGNORE
+<zH;> <zH>;<zH;>;IGNORE;IGNORE
+<e+> <e+>;<e+>;IGNORE;IGNORE
+<e+-> <e+>;<e+->;IGNORE;IGNORE
+<e+.> <e+>;<e+.>;IGNORE;IGNORE
+<e+,> <e+>;<e+,>;IGNORE;IGNORE
+<e+;> <e+>;<e+;>;IGNORE;IGNORE
+<i+> <i+>;<i+>;IGNORE;IGNORE
+<i+-> <i+>;<i+->;IGNORE;IGNORE
+<i+.> <i+>;<i+.>;IGNORE;IGNORE
+<i+,> <i+>;<i+,>;IGNORE;IGNORE
+<i+;> <i+>;<i+;>;IGNORE;IGNORE
+<f+> <f+>;<f+>;IGNORE;IGNORE
+<f+-> <f+>;<f+->;IGNORE;IGNORE
+<f+.> <f+>;<f+.>;IGNORE;IGNORE
+<f+,> <f+>;<f+,>;IGNORE;IGNORE
+<f+;> <f+>;<f+;>;IGNORE;IGNORE
+<q+> <q+>;<q+>;IGNORE;IGNORE
+<q+-> <q+>;<q+->;IGNORE;IGNORE
+<q+.> <q+>;<q+.>;IGNORE;IGNORE
+<q+,> <q+>;<q+,>;IGNORE;IGNORE
+<q+;> <q+>;<q+;>;IGNORE;IGNORE
+<k+> <k+>;<k+>;IGNORE;IGNORE
+<k+-> <k+>;<k+->;IGNORE;IGNORE
+<k+.> <k+>;<k+.>;IGNORE;IGNORE
+<k+,> <k+>;<k+,>;IGNORE;IGNORE
+<k+;> <k+>;<k+;>;IGNORE;IGNORE
+<l+> <l+>;<l+>;IGNORE;IGNORE
+<l+-> <l+>;<l+->;IGNORE;IGNORE
+<l+.> <l+>;<l+.>;IGNORE;IGNORE
+<l+,> <l+>;<l+,>;IGNORE;IGNORE
+<l+;> <l+>;<l+;>;IGNORE;IGNORE
+<m+> <m+>;<m+>;IGNORE;IGNORE
+<m+-> <m+>;<m+->;IGNORE;IGNORE
+<m+.> <m+>;<m+.>;IGNORE;IGNORE
+<m+,> <m+>;<m+,>;IGNORE;IGNORE
+<m+;> <m+>;<m+;>;IGNORE;IGNORE
+<n+> <n+>;<n+>;IGNORE;IGNORE
+<n+-> <n+>;<n+->;IGNORE;IGNORE
+<n+.> <n+>;<n+.>;IGNORE;IGNORE
+<n+,> <n+>;<n+,>;IGNORE;IGNORE
+<n+;> <n+>;<n+;>;IGNORE;IGNORE
+<h+> <h+>;<h+>;IGNORE;IGNORE
+<h+-> <h+>;<h+->;IGNORE;IGNORE
+<h+.> <h+>;<h+.>;IGNORE;IGNORE
+<h+,> <h+>;<h+,>;IGNORE;IGNORE
+<h+;> <h+>;<h+;>;IGNORE;IGNORE
+<w+> <w+>;<w+>;IGNORE;IGNORE
+<w+-> <w+>;<w+->;IGNORE;IGNORE
+<w+.> <w+>;<w+.>;IGNORE;IGNORE
+<j+> <j+>;<j+>;IGNORE;IGNORE
+<j+-> <j+>;<j+->;IGNORE;IGNORE
+<j+.> <j+>;<j+.>;IGNORE;IGNORE
+<y+> <y+>;<y+>;IGNORE;IGNORE
+<y+-> <y+>;<y+->;IGNORE;IGNORE
+<y+.> <y+>;<y+.>;IGNORE;IGNORE
+<y+,> <y+>;<y+,>;IGNORE;IGNORE
+<y+;> <y+>;<y+;>;IGNORE;IGNORE
+
+<:+> IGNORE;IGNORE;<:+>;IGNORE
+<"+> IGNORE;IGNORE;<"+>;IGNORE
+<=+> IGNORE;IGNORE;<=+>;IGNORE
+<//+> IGNORE;IGNORE;<//+>;IGNORE
+<'+> IGNORE;IGNORE;<'+>;IGNORE
+<1+> IGNORE;IGNORE;<1+>;IGNORE
+<3+> IGNORE;IGNORE;<3+>;IGNORE
+<3+;> IGNORE;IGNORE;<3+;>;IGNORE
+<0+> IGNORE;IGNORE;<0+>;IGNORE
+
+<0a> <0>;<0a>;IGNORE;IGNORE
+<1a> <1>;<1a>;IGNORE;IGNORE
+<2a> <2>;<2a>;IGNORE;IGNORE
+<3a> <3>;<3a>;IGNORE;IGNORE
+<4a> <4>;<4a>;IGNORE;IGNORE
+<5a> <5>;<5a>;IGNORE;IGNORE
+<6a> <6>;<6a>;IGNORE;IGNORE
+<7a> <7>;<7a>;IGNORE;IGNORE
+<8a> <8>;<8a>;IGNORE;IGNORE
+<9a> <9>;<9a>;IGNORE;IGNORE
+
+<lM-> <l+><aM>;<l+><aM>;<lM-><lM->;IGNORE
+<lM.> <l+><aM>;<l+><aM.>;<lM.><lM.>;IGNORE
+<lH-> <l+><aH>;<l+><aH>;<lH-><lH->;IGNORE
+<lH.> <l+><aH>;<l+><aH.>;<lH.><lH.>;IGNORE
+<lh-> <l+><ah>;<l+><ah>;<lh-><lh->;IGNORE
+<lh.> <l+><ah>;<l+><ah.>;<lh.><lh.>;IGNORE
+<la-> <l+><a+>;<l+><a+->;<la-><la->;IGNORE
+<la.> <l+><a+>;<l+><a+.>;<la.><la.>;IGNORE
+
+% katakana/hiragana sorting
+% base is katakana, as this is present in most charsets
+% normal before voiced before semi-voiced
+% small vocals before normal vocals
+% katakana before hiragana
+
+<a6> <a6>;<a6>;IGNORE;IGNORE
+<A5> <a6>;<A5>;IGNORE;IGNORE
+<A6> <a6>;<A6>;IGNORE;IGNORE
+<a5> <a6>;<a5>;IGNORE;IGNORE
+<i6> <i6>;<i6>;IGNORE;IGNORE
+<I5> <i6>;<I5>;IGNORE;IGNORE
+<I6> <i6>;<I6>;IGNORE;IGNORE
+<i5> <i6>;<i5>;IGNORE;IGNORE
+<u6> <u6>;<u6>;IGNORE;IGNORE
+<U5> <u6>;<U5>;IGNORE;IGNORE
+<U6> <u6>;<U6>;IGNORE;IGNORE
+<u5> <u6>;<u5>;IGNORE;IGNORE
+<Vu> <u6>;<Vu>;IGNORE;IGNORE
+<e6> <e6>;<e6>;IGNORE;IGNORE
+<E5> <e6>;<E5>;IGNORE;IGNORE
+<E6> <e6>;<E6>;IGNORE;IGNORE
+<e5> <e6>;<e5>;IGNORE;IGNORE
+<o6> <o6>;<o6>;IGNORE;IGNORE
+<O5> <o6>;<O5>;IGNORE;IGNORE
+<O6> <o6>;<O6>;IGNORE;IGNORE
+<o5> <o6>;<o5>;IGNORE;IGNORE
+<KA> <KA>;<KA>;IGNORE;IGNORE
+<Ka> <KA>;<Ka>;IGNORE;IGNORE
+<ka> <KA>;<ka>;IGNORE;IGNORE
+<Ga> <KA>;<Ga>;IGNORE;IGNORE
+<ga> <KA>;<ga>;IGNORE;IGNORE
+<Ki> <Ki>;<Ki>;IGNORE;IGNORE
+<ki> <Ki>;<ki>;IGNORE;IGNORE
+<Gi> <Ki>;<Gi>;IGNORE;IGNORE
+<gi> <Ki>;<gi>;IGNORE;IGNORE
+<Ku> <Ku>;<Ku>;IGNORE;IGNORE
+<ku> <Ku>;<ku>;IGNORE;IGNORE
+<Gu> <Ku>;<Gu>;IGNORE;IGNORE
+<gu> <Ku>;<gu>;IGNORE;IGNORE
+<KE> <KE>;<KE>;IGNORE;IGNORE
+<Ke> <KE>;<Ke>;IGNORE;IGNORE
+<ke> <KE>;<ke>;IGNORE;IGNORE
+<Ge> <KE>;<Ge>;IGNORE;IGNORE
+<ge> <KE>;<ge>;IGNORE;IGNORE
+<Ko> <Ko>;<Ko>;IGNORE;IGNORE
+<ko> <Ko>;<ko>;IGNORE;IGNORE
+<Go> <Ko>;<Go>;IGNORE;IGNORE
+<go> <Ko>;<go>;IGNORE;IGNORE
+<Sa> <Sa>;<Sa>;IGNORE;IGNORE
+<sa> <Sa>;<sa>;IGNORE;IGNORE
+<Za> <Sa>;<Za>;IGNORE;IGNORE
+<za> <Sa>;<za>;IGNORE;IGNORE
+<Si> <Si>;<Si>;IGNORE;IGNORE
+<si> <Si>;<si>;IGNORE;IGNORE
+<Zi> <Si>;<Zi>;IGNORE;IGNORE
+<zi> <Si>;<zi>;IGNORE;IGNORE
+<Su> <Su>;<Su>;IGNORE;IGNORE
+<su> <Su>;<su>;IGNORE;IGNORE
+<Zu> <Su>;<Zu>;IGNORE;IGNORE
+<zu> <Su>;<zu>;IGNORE;IGNORE
+<Se> <Se>;<Se>;IGNORE;IGNORE
+<se> <Se>;<se>;IGNORE;IGNORE
+<Ze> <Se>;<Ze>;IGNORE;IGNORE
+<ze> <Se>;<ze>;IGNORE;IGNORE
+<So> <So>;<So>;IGNORE;IGNORE
+<so> <So>;<so>;IGNORE;IGNORE
+<Zo> <So>;<Zo>;IGNORE;IGNORE
+<zo> <So>;<zo>;IGNORE;IGNORE
+<Ta> <Ta>;<Ta>;IGNORE;IGNORE
+<ta> <Ta>;<ta>;IGNORE;IGNORE
+<Da> <Ta>;<Da>;IGNORE;IGNORE
+<da> <Ta>;<da>;IGNORE;IGNORE
+<Ti> <Ti>;<Ti>;IGNORE;IGNORE
+<ti> <Ti>;<ti>;IGNORE;IGNORE
+<Di> <Ti>;<Di>;IGNORE;IGNORE
+<di> <Ti>;<di>;IGNORE;IGNORE
+<TU> <TU>;<TU>;IGNORE;IGNORE
+<tU> <TU>;<tU>;IGNORE;IGNORE
+<Tu> <TU>;<Tu>;IGNORE;IGNORE
+<tu> <TU>;<tu>;IGNORE;IGNORE
+<Du> <TU>;<Du>;IGNORE;IGNORE
+<du> <TU>;<du>;IGNORE;IGNORE
+<Te> <Te>;<Te>;IGNORE;IGNORE
+<te> <Te>;<te>;IGNORE;IGNORE
+<De> <Te>;<De>;IGNORE;IGNORE
+<de> <Te>;<de>;IGNORE;IGNORE
+<To> <To>;<To>;IGNORE;IGNORE
+<to> <To>;<to>;IGNORE;IGNORE
+<Do> <To>;<Do>;IGNORE;IGNORE
+<do> <To>;<do>;IGNORE;IGNORE
+<Na> <Na>;<Na>;IGNORE;IGNORE
+<na> <Na>;<na>;IGNORE;IGNORE
+<Ni> <Ni>;<Ni>;IGNORE;IGNORE
+<ni> <Ni>;<ni>;IGNORE;IGNORE
+<Nu> <Nu>;<Nu>;IGNORE;IGNORE
+<nu> <Nu>;<nu>;IGNORE;IGNORE
+<Ne> <Ne>;<Ne>;IGNORE;IGNORE
+<ne> <Ne>;<ne>;IGNORE;IGNORE
+<No> <No>;<No>;IGNORE;IGNORE
+<no> <No>;<no>;IGNORE;IGNORE
+<Ha> <Ha>;<Ha>;IGNORE;IGNORE
+<ha> <Ha>;<ha>;IGNORE;IGNORE
+<Ba> <Ha>;<Ba>;IGNORE;IGNORE
+<ba> <Ha>;<ba>;IGNORE;IGNORE
+<Pa> <Ha>;<Pa>;IGNORE;IGNORE
+<pa> <Ha>;<pa>;IGNORE;IGNORE
+<Hi> <Hi>;<Hi>;IGNORE;IGNORE
+<hi> <Hi>;<hi>;IGNORE;IGNORE
+<Bi> <Hi>;<Bi>;IGNORE;IGNORE
+<bi> <Hi>;<bi>;IGNORE;IGNORE
+<Pi> <Hi>;<Pi>;IGNORE;IGNORE
+<pi> <Hi>;<pi>;IGNORE;IGNORE
+<Hu> <Hu>;<Hu>;IGNORE;IGNORE
+<hu> <Hu>;<hu>;IGNORE;IGNORE
+<Bu> <Hu>;<Bu>;IGNORE;IGNORE
+<bu> <Hu>;<bu>;IGNORE;IGNORE
+<Pu> <Hu>;<Pu>;IGNORE;IGNORE
+<pu> <Hu>;<pu>;IGNORE;IGNORE
+<He> <He>;<He>;IGNORE;IGNORE
+<he> <He>;<he>;IGNORE;IGNORE
+<Be> <He>;<Be>;IGNORE;IGNORE
+<be> <He>;<be>;IGNORE;IGNORE
+<Pe> <He>;<Pe>;IGNORE;IGNORE
+<pe> <He>;<pe>;IGNORE;IGNORE
+<Ho> <Ho>;<Ho>;IGNORE;IGNORE
+<ho> <Ho>;<ho>;IGNORE;IGNORE
+<Bo> <Ho>;<Bo>;IGNORE;IGNORE
+<bo> <Ho>;<bo>;IGNORE;IGNORE
+<Po> <Ho>;<Po>;IGNORE;IGNORE
+<po> <Ho>;<po>;IGNORE;IGNORE
+<Ma> <Ma>;<Ma>;IGNORE;IGNORE
+<ma> <Ma>;<ma>;IGNORE;IGNORE
+<Mi> <Mi>;<Mi>;IGNORE;IGNORE
+<mi> <Mi>;<mi>;IGNORE;IGNORE
+<Mu> <Mu>;<Mu>;IGNORE;IGNORE
+<mu> <Mu>;<mu>;IGNORE;IGNORE
+<Me> <Me>;<Me>;IGNORE;IGNORE
+<me> <Me>;<me>;IGNORE;IGNORE
+<Mo> <Mo>;<Mo>;IGNORE;IGNORE
+<mo> <Mo>;<mo>;IGNORE;IGNORE
+<YA> <YA>;<YA>;IGNORE;IGNORE
+<yA> <YA>;<yA>;IGNORE;IGNORE
+<Ya> <YA>;<Ya>;IGNORE;IGNORE
+<ya> <YA>;<ya>;IGNORE;IGNORE
+<YU> <YU>;<YU>;IGNORE;IGNORE
+<yU> <YU>;<yU>;IGNORE;IGNORE
+<Yu> <YU>;<Yu>;IGNORE;IGNORE
+<yu> <YU>;<yu>;IGNORE;IGNORE
+<YO> <YO>;<YO>;IGNORE;IGNORE
+<yO> <YO>;<yO>;IGNORE;IGNORE
+<Yo> <YO>;<Yo>;IGNORE;IGNORE
+<yo> <YO>;<yo>;IGNORE;IGNORE
+<Ra> <Ra>;<Ra>;IGNORE;IGNORE
+<ra> <Ra>;<ra>;IGNORE;IGNORE
+<Ri> <Ri>;<Ri>;IGNORE;IGNORE
+<ri> <Ri>;<ri>;IGNORE;IGNORE
+<Ru> <Ru>;<Ru>;IGNORE;IGNORE
+<ru> <Ru>;<ru>;IGNORE;IGNORE
+<Re> <Re>;<Re>;IGNORE;IGNORE
+<re> <Re>;<re>;IGNORE;IGNORE
+<Ro> <Ro>;<Ro>;IGNORE;IGNORE
+<ro> <Ro>;<ro>;IGNORE;IGNORE
+<WA> <WA>;<WA>;IGNORE;IGNORE
+<wA> <WA>;<wA>;IGNORE;IGNORE
+<Wa> <WA>;<Wa>;IGNORE;IGNORE
+<wa> <WA>;<wa>;IGNORE;IGNORE
+<Wi> <Wi>;<Wi>;IGNORE;IGNORE
+<wi> <Wi>;<wi>;IGNORE;IGNORE
+<We> <We>;<We>;IGNORE;IGNORE
+<we> <We>;<we>;IGNORE;IGNORE
+<Wo> <Wo>;<Wo>;IGNORE;IGNORE
+<wo> <Wo>;<wo>;IGNORE;IGNORE
+<N6> <N6>;<N6>;IGNORE;IGNORE
+<n5> <N6>;<n5>;IGNORE;IGNORE
+
+order_end
+
+END LC_COLLATE
+
+LC_CTYPE
+
+digit <0>;<1>;<2>;<3>;<4>;/
+ <5>;<6>;<7>;<8>;<9>
+
+xdigit <0>;<1>;<2>;<3>;<4>;/
+ <5>;<6>;<7>;<8>;<9>;/
+ <A>;<B>;<C>;<D>;<E>;<F>;/
+ <a>;<b>;<c>;<d>;<e>;<f>
+
+blank <SP>;<HT>;<NS>
+
+space <SP>;<LF>;<VT>;<FF>;/
+ <CR>;<HT>;<NS>
+
+upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;/
+ <H>;<I>;<J>;<K>;<L>;<M>;<N>;/
+ <O>;<P>;<Q>;<R>;<S>;<T>;<U>;/
+ <V>;<W>;<X>;<Y>;<Z>;<A!>;<A'>;/
+ <A/>>;<A?>;<A:>;<AA>;<AE>;<C,>;/
+ <E!>;<E'>;<E/>>;<E:>;<I!>;<I'>;/
+ <I/>>;<I:>;<D->;<N?>;<O!>;<O'>;/
+ <O/>>;<O?>;<O:>;<O//>;<U!>;/
+ <U'>;<U/>>;<U:>;<Y'>;<TH>;<A->;/
+ <A(>;<A;>;<C'>;<C/>>;<C.>;<C<>;/
+ <D<>;<D//>;<E->;<E(>;<E.>;<E;>;/
+ <E<>;<G/>>;<G(>;<G.>;<G,>;/
+ <H/>>;<H//>;<I?>;<I->;<I(>;/
+ <I;>;<I.>;<IJ>;<J/>>;<K,>;<L'>;/
+ <L,>;<L<>;<L.>;<L//>;<N'>;<N,>;/
+ <N<>;<NG>;<O->;<O(>;<O">;<OE>;/
+ <R'>;<R,>;<R<>;<S'>;<S/>>;<S,>;/
+ <S<>;<T,>;<T<>;<T//>;<U?>;<U->;/
+ <U(>;<U0>;<U">;<U;>;<W/>>;/
+ <Y/>>;<Y:>;<Z'>;<Z.>;<Z<>;<C2>;/
+ <F2>;<K2>;<O9>;<OI>;<U9>;<Z//>;/
+ <ED>;<A<>;<I<>;<O<>;<U<>;<U:->;/
+ <U:'>;<U:<>;<U:!>;<A1>;<A7>;/
+ <A3>;<G//>;<G<>;<K<>;<O;>;<O1>;/
+ <EZ>;<G'>;<AA'>;<AE'>;<O//'>;/
+ <A!!>;<A)>;<E!!>;<E)>;<I!!>;/
+ <I)>;<O!!>;<O)>;<R!!>;<R)>;/
+ <U!!>;<U)>;<A%>;<E%>;<Y%>;<I%>;/
+ <O%>;<U%>;<W%>;<A*>;<B*>;<G*>;/
+ <D*>;<E*>;<Z*>;<Y*>;<H*>;<I*>;/
+ <K*>;<L*>;<M*>;<N*>;<C*>;<O*>;/
+ <P*>;<R*>;<S*>;<T*>;<U*>;<F*>;/
+ <X*>;<Q*>;<W*>;<J*>;<V*>;<IO>;/
+ <D%>;<G%>;<IE>;<DS>;<II>;<YI>;/
+ <J%>;<LJ>;<NJ>;<Ts>;<KJ>;<V%>;/
+ <DZ>;<A=>;<B=>;<V=>;<G=>;<D=>;/
+ <E=>;<Z%>;<Z=>;<I=>;<J=>;<K=>;/
+ <L=>;<M=>;<N=>;<O=>;<P=>;<R=>;/
+ <S=>;<T=>;<U=>;<F=>;<H=>;<C=>;/
+ <C%>;<S%>;<Sc>;<=">;<Y=>;<%">;/
+ <JE>;<JU>;<JA>;<Y3>;<O3>;<F3>;/
+ <V3>;<C3>;<G3>;<A-0>;<B.>;/
+ <B-.>;<B_>;<C,'>;<D.>;<D-.>;/
+ <D_>;<D,>;<D-/>>;<E-!>;<E-'>;/
+ <E-/>>;<E-?>;<E,(>;<F.>;<G->;/
+ <H.>;<H-.>;<H:>;<H,>;<H-(>;/
+ <I-?>;<I:'>;<K'>;<K-.>;<K_>;/
+ <L-.>;<L--.>;<L_>;<L-/>>;<M'>;/
+ <M.>;<M-.>;<N.>;<N-.>;<N_>;/
+ <N-/>>;<O?'>;<O?:>;<O-!>;<O-'>;/
+ <P'>;<P.>;<R.>;<R-.>;<R--.>;/
+ <R_>;<S.>;<S-.>;<S'.>;<S<.>;/
+ <S.-.>;<T.>;<T-.>;<T_>;<T-/>>;/
+ <U--:>;<U-?>;<U-/>>;<U?'>;/
+ <U-:>;<V?>;<V-.>;<W!>;<W'>;/
+ <W:>;<W.>;<W-.>;<X.>;<X:>;<Y.>;/
+ <Z/>>;<Z-.>;<Z_>;<A-.>;<A2>;/
+ <A/>'>;<A/>!>;<A/>2>;<A/>?>;/
+ <A/>-.>;<A('>;<A(!>;<A(2>;/
+ <A(?>;<A(-.>;<E-.>;<E2>;<E?>;/
+ <E/>'>;<E/>!>;<E/>2>;<E/>?>;/
+ <E/>-.>;<I2>;<I-.>;<O-.>;<O2>;/
+ <O/>'>;<O/>!>;<O/>2>;<O/>?>;/
+ <O/>-.>;<O9'>;<O9!>;<O92>;/
+ <O9?>;<O9-.>;<U-.>;<U2>;<U9'>;/
+ <U9!>;<U92>;<U9?>;<U9-.>;<Y!>;/
+ <Y-.>;<Y2>;<Y?>;<A-o>;<B-o>;/
+ <C-o>;<D-o>;<E-o>;<F-o>;<G-o>;/
+ <H-o>;<I-o>;<J-o>;<K-o>;<L-o>;/
+ <M-o>;<N-o>;<O-o>;<P-o>;<Q-o>;/
+ <R-o>;<S-o>;<T-o>;<U-o>;<V-o>;/
+ <W-o>;<X-o>;<Y-o>;<Z-o>
+
+lower <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>;<ss>;<a!>;/
+ <a'>;<a/>>;<a?>;<a:>;<aa>;<ae>;/
+ <c,>;<e!>;<e'>;<e/>>;<e:>;<i!>;/
+ <i'>;<i/>>;<i:>;<d->;<n?>;<o!>;/
+ <o'>;<o/>>;<o?>;<o:>;<o//>;/
+ <u!>;<u'>;<u/>>;<u:>;<y'>;<th>;/
+ <y:>;<a->;<a(>;<a;>;<c'>;<c/>>;/
+ <c.>;<c<>;<d<>;<d//>;<e->;<e(>;/
+ <e.>;<e;>;<e<>;<g/>>;<g(>;<g.>;/
+ <g,>;<h/>>;<h//>;<i?>;<i->;/
+ <i(>;<i;>;<i.>;<ij>;<j/>>;<k,>;/
+ <kk>;<l'>;<l,>;<l<>;<l.>;<l//>;/
+ <n'>;<n,>;<n<>;<'n>;<ng>;<o->;/
+ <o(>;<o">;<oe>;<r'>;<r,>;<r<>;/
+ <s'>;<s/>>;<s,>;<s<>;<t,>;<t<>;/
+ <t//>;<u?>;<u->;<u(>;<u0>;<u">;/
+ <u;>;<w/>>;<y/>>;<z'>;<z.>;/
+ <z<>;<s1>;<c2>;<f2>;<k2>;<o9>;/
+ <oi>;<u9>;<z//>;<a<>;<i<>;<o<>;/
+ <u<>;<u:->;<u:'>;<u:<>;<u:!>;/
+ <a1>;<a7>;<a3>;<g//>;<g<>;<k<>;/
+ <o;>;<o1>;<ez>;<g'>;<aa'>;/
+ <ae'>;<o//'>;<a!!>;<a)>;<e!!>;/
+ <e)>;<i!!>;<i)>;<o!!>;<o)>;/
+ <r!!>;<r)>;<u!!>;<u)>;<ed>;/
+ <i3>;<a%>;<e%>;<y%>;<i%>;<u3>;/
+ <a*>;<b*>;<g*>;<d*>;<e*>;<z*>;/
+ <y*>;<h*>;<i*>;<k*>;<l*>;<m*>;/
+ <n*>;<c*>;<o*>;<p*>;<r*>;<*s>;/
+ <s*>;<t*>;<u*>;<f*>;<x*>;<q*>;/
+ <w*>;<j*>;<v*>;<o%>;<u%>;<w%>;/
+ <a=>;<b=>;<v=>;<g=>;<d=>;<e=>;/
+ <z%>;<z=>;<i=>;<j=>;<k=>;<l=>;/
+ <m=>;<n=>;<o=>;<p=>;<r=>;<s=>;/
+ <t=>;<u=>;<f=>;<h=>;<c=>;<c%>;/
+ <s%>;<sc>;<='>;<y=>;<%'>;<je>;/
+ <ju>;<ja>;<io>;<d%>;<g%>;<ie>;/
+ <ds>;<ii>;<yi>;<j%>;<lj>;<nj>;/
+ <ts>;<kj>;<v%>;<dz>;<y3>;<o3>;/
+ <f3>;<v3>;<c3>;<g3>;<a-0>;<b.>;/
+ <b-.>;<b_>;<c,'>;<d.>;<d-.>;/
+ <d_>;<d,>;<d-/>>;<e-!>;<e-'>;/
+ <e-/>>;<e-?>;<e,(>;<f.>;<g->;/
+ <h.>;<h-.>;<h:>;<h,>;<h-(>;/
+ <i-?>;<i:'>;<k'>;<k-.>;<k_>;/
+ <l-.>;<l--.>;<l_>;<l-/>>;<m'>;/
+ <m.>;<m-.>;<n.>;<n-.>;<n_>;/
+ <n-/>>;<o?'>;<o?:>;<o-!>;<o-'>;/
+ <p'>;<p.>;<r.>;<r-.>;<r--.>;/
+ <r_>;<s.>;<s-.>;<s'.>;<s<.>;/
+ <s.-.>;<t.>;<t-.>;<t_>;<t-/>>;/
+ <u--:>;<u-?>;<u-/>>;<u?'>;/
+ <u-:>;<v?>;<v-.>;<w!>;<w'>;/
+ <w:>;<w.>;<w-.>;<x.>;<x:>;<y.>;/
+ <z/>>;<z-.>;<z_>;<a-.>;<a2>;/
+ <a/>'>;<a/>!>;<a/>2>;<a/>?>;/
+ <a/>-.>;<a('>;<a(!>;<a(2>;/
+ <a(?>;<a(-.>;<e-.>;<e2>;<e?>;/
+ <e/>'>;<e/>!>;<e/>2>;<e/>?>;/
+ <e/>-.>;<i2>;<i-.>;<o-.>;<o2>;/
+ <o/>'>;<o/>!>;<o/>2>;<o/>?>;/
+ <o/>-.>;<o9'>;<o9!>;<o92>;/
+ <o9?>;<o9-.>;<u-.>;<u2>;<u9'>;/
+ <u9!>;<u92>;<u9?>;<u9-.>;<y!>;/
+ <y-.>;<y2>;<y?>;<nS>;<(a)>;/
+ <(b)>;<(c)>;<(d)>;<(e)>;<(f)>;/
+ <(g)>;<(h)>;<(i)>;<(j)>;<(k)>;/
+ <(l)>;<(m)>;<(n)>;<(o)>;<(p)>;/
+ <(q)>;<(r)>;<(s)>;<(t)>;<(u)>;/
+ <(v)>;<(w)>;<(x)>;<(y)>;<(z)>;/
+ <a-o>;<b-o>;<c-o>;<d-o>;<e-o>;/
+ <f-o>;<g-o>;<h-o>;<i-o>;<j-o>;/
+ <k-o>;<l-o>;<m-o>;<n-o>;<o-o>;/
+ <p-o>;<q-o>;<r-o>;<s-o>;<t-o>;/
+ <u-o>;<v-o>;<w-o>;<x-o>;<y-o>;/
+ <z-o>;<ff>;<fi>;<fl>;<ffi>;/
+ <ffl>;<ft>;<st>
+
+alpha <A>;<B>;<C>;<D>;<E>;<F>;<G>;/
+ <H>;<I>;<J>;<K>;<L>;<M>;<N>;/
+ <O>;<P>;<Q>;<R>;<S>;<T>;<U>;/
+ <V>;<W>;<X>;<Y>;<Z>;<a>;<b>;/
+ <c>;<d>;<e>;<f>;<g>;<h>;<i>;/
+ <j>;<k>;<l>;<m>;<n>;<o>;<p>;/
+ <q>;<r>;<s>;<t>;<u>;<v>;<w>;/
+ <x>;<y>;<z>;<-->;<A!>;<A'>;/
+ <A/>>;<A?>;<A:>;<AA>;<AE>;<C,>;/
+ <E!>;<E'>;<E/>>;<E:>;<I!>;<I'>;/
+ <I/>>;<I:>;<D->;<N?>;<O!>;<O'>;/
+ <O/>>;<O?>;<O:>;<O//>;<U!>;/
+ <U'>;<U/>>;<U:>;<Y'>;<TH>;<ss>;/
+ <a!>;<a'>;<a/>>;<a?>;<a:>;<aa>;/
+ <ae>;<c,>;<e!>;<e'>;<e/>>;<e:>;/
+ <i!>;<i'>;<i/>>;<i:>;<d->;<n?>;/
+ <o!>;<o'>;<o/>>;<o?>;<o:>;/
+ <o//>;<u!>;<u'>;<u/>>;<u:>;/
+ <y'>;<th>;<y:>;<A->;<a->;<A(>;/
+ <a(>;<A;>;<a;>;<C'>;<c'>;<C/>>;/
+ <c/>>;<C.>;<c.>;<C<>;<c<>;<D<>;/
+ <d<>;<D//>;<d//>;<E->;<e->;/
+ <E(>;<e(>;<E.>;<e.>;<E;>;<e;>;/
+ <E<>;<e<>;<G/>>;<g/>>;<G(>;/
+ <g(>;<G.>;<g.>;<G,>;<g,>;<H/>>;/
+ <h/>>;<H//>;<h//>;<I?>;<i?>;/
+ <I->;<i->;<I(>;<i(>;<I;>;<i;>;/
+ <I.>;<i.>;<IJ>;<ij>;<J/>>;/
+ <j/>>;<K,>;<k,>;<kk>;<L'>;<l'>;/
+ <L,>;<l,>;<L<>;<l<>;<L.>;<l.>;/
+ <L//>;<l//>;<N'>;<n'>;<N,>;/
+ <n,>;<N<>;<n<>;<'n>;<NG>;<ng>;/
+ <O->;<o->;<O(>;<o(>;<O">;<o">;/
+ <OE>;<oe>;<R'>;<r'>;<R,>;<r,>;/
+ <R<>;<r<>;<S'>;<s'>;<S/>>;/
+ <s/>>;<S,>;<s,>;<S<>;<s<>;<T,>;/
+ <t,>;<T<>;<t<>;<T//>;<t//>;/
+ <U?>;<u?>;<U->;<u->;<U(>;<u(>;/
+ <U0>;<u0>;<U">;<u">;<U;>;<u;>;/
+ <W/>>;<w/>>;<Y/>>;<y/>>;<Y:>;/
+ <Z'>;<z'>;<Z.>;<z.>;<Z<>;<z<>;/
+ <s1>;<C2>;<c2>;<F2>;<f2>;<K2>;/
+ <k2>;<O9>;<o9>;<OI>;<oi>;<yr>;/
+ <U9>;<u9>;<Z//>;<z//>;<ED>;/
+ <A<>;<a<>;<I<>;<i<>;<O<>;<o<>;/
+ <U<>;<u<>;<U:->;<u:->;<U:'>;/
+ <u:'>;<U:<>;<u:<>;<U:!>;<u:!>;/
+ <A1>;<a1>;<A7>;<a7>;<A3>;<a3>;/
+ <G//>;<g//>;<G<>;<g<>;<K<>;/
+ <k<>;<O;>;<o;>;<O1>;<o1>;<EZ>;/
+ <ez>;<G'>;<g'>;<AA'>;<aa'>;/
+ <AE'>;<ae'>;<O//'>;<o//'>;/
+ <A!!>;<a!!>;<A)>;<a)>;<E!!>;/
+ <e!!>;<E)>;<e)>;<I!!>;<i!!>;/
+ <I)>;<i)>;<O!!>;<o!!>;<O)>;/
+ <o)>;<R!!>;<r!!>;<R)>;<r)>;/
+ <U!!>;<u!!>;<U)>;<u)>;<ed>;/
+ <;S>;<1/>>;<1!>;<A%>;<E%>;<Y%>;/
+ <I%>;<O%>;<U%>;<W%>;<i3>;<A*>;/
+ <B*>;<G*>;<D*>;<E*>;<Z*>;<Y*>;/
+ <H*>;<I*>;<K*>;<L*>;<M*>;<N*>;/
+ <C*>;<O*>;<P*>;<R*>;<S*>;<T*>;/
+ <U*>;<F*>;<X*>;<Q*>;<W*>;<J*>;/
+ <V*>;<a%>;<e%>;<y%>;<i%>;<u3>;/
+ <a*>;<b*>;<g*>;<d*>;<e*>;<z*>;/
+ <y*>;<h*>;<i*>;<k*>;<l*>;<m*>;/
+ <n*>;<c*>;<o*>;<p*>;<r*>;<*s>;/
+ <s*>;<t*>;<u*>;<f*>;<x*>;<q*>;/
+ <w*>;<j*>;<v*>;<o%>;<u%>;<w%>;/
+ <IO>;<D%>;<G%>;<IE>;<DS>;<II>;/
+ <YI>;<J%>;<LJ>;<NJ>;<Ts>;<KJ>;/
+ <V%>;<DZ>;<A=>;<B=>;<V=>;<G=>;/
+ <D=>;<E=>;<Z%>;<Z=>;<I=>;<J=>;/
+ <K=>;<L=>;<M=>;<N=>;<O=>;<P=>;/
+ <R=>;<S=>;<T=>;<U=>;<F=>;<H=>;/
+ <C=>;<C%>;<S%>;<Sc>;<=">;<Y=>;/
+ <%">;<JE>;<JU>;<JA>;<a=>;<b=>;/
+ <v=>;<g=>;<d=>;<e=>;<z%>;<z=>;/
+ <i=>;<j=>;<k=>;<l=>;<m=>;<n=>;/
+ <o=>;<p=>;<r=>;<s=>;<t=>;<u=>;/
+ <f=>;<h=>;<c=>;<c%>;<s%>;<sc>;/
+ <='>;<y=>;<%'>;<je>;<ju>;<ja>;/
+ <io>;<d%>;<g%>;<ie>;<ds>;<ii>;/
+ <yi>;<j%>;<lj>;<nj>;<ts>;<kj>;/
+ <v%>;<dz>;<Y3>;<y3>;<O3>;<o3>;/
+ <F3>;<f3>;<V3>;<v3>;<C3>;<c3>;/
+ <G3>;<g3>;<A+>;<B+>;<G+>;<D+>;/
+ <H+>;<W+>;<Z+>;<X+>;<Tj>;<J+>;/
+ <K%>;<K+>;<L+>;<M%>;<M+>;<N%>;/
+ <N+>;<S+>;<E+>;<P%>;<P+>;<Zj>;/
+ <ZJ>;<Q+>;<R+>;<Sh>;<T+>;<H'>;/
+ <aM>;<aH>;<wH>;<ah>;<yH>;<a+>;/
+ <b+>;<tm>;<t+>;<tk>;<g+>;<hk>;/
+ <x+>;<d+>;<dk>;<r+>;<z+>;<s+>;/
+ <sn>;<c+>;<dd>;<tj>;<zH>;<e+>;/
+ <i+>;<f+>;<q+>;<k+>;<l+>;<m+>;/
+ <n+>;<h+>;<w+>;<j+>;<y+>;<aS>;/
+ <p+>;<hH>;<tc>;<zj>;<v+>;<gf>;/
+ <A-0>;<a-0>;<B.>;<b.>;<B-.>;/
+ <b-.>;<B_>;<b_>;<C,'>;<c,'>;/
+ <D.>;<d.>;<D-.>;<d-.>;<D_>;/
+ <d_>;<D,>;<d,>;<D-/>>;<d-/>>;/
+ <E-!>;<e-!>;<E-'>;<e-'>;<E-/>>;/
+ <e-/>>;<E-?>;<e-?>;<E,(>;<e,(>;/
+ <F.>;<f.>;<G->;<g->;<H.>;<h.>;/
+ <H-.>;<h-.>;<H:>;<h:>;<H,>;/
+ <h,>;<H-(>;<h-(>;<I-?>;<i-?>;/
+ <I:'>;<i:'>;<K'>;<k'>;<K-.>;/
+ <k-.>;<K_>;<k_>;<L-.>;<l-.>;/
+ <L--.>;<l--.>;<L_>;<l_>;<L-/>>;/
+ <l-/>>;<M'>;<m'>;<M.>;<m.>;/
+ <M-.>;<m-.>;<N.>;<n.>;<N-.>;/
+ <n-.>;<N_>;<n_>;<N-/>>;<n-/>>;/
+ <O?'>;<o?'>;<O?:>;<o?:>;<O-!>;/
+ <o-!>;<O-'>;<o-'>;<P'>;<p'>;/
+ <P.>;<p.>;<R.>;<r.>;<R-.>;/
+ <r-.>;<R--.>;<r--.>;<R_>;<r_>;/
+ <S.>;<s.>;<S-.>;<s-.>;<S'.>;/
+ <s'.>;<S<.>;<s<.>;<S.-.>;/
+ <s.-.>;<T.>;<t.>;<T-.>;<t-.>;/
+ <T_>;<t_>;<T-/>>;<t-/>>;<U--:>;/
+ <u--:>;<U-?>;<u-?>;<U-/>>;/
+ <u-/>>;<U?'>;<u?'>;<U-:>;<u-:>;/
+ <V?>;<v?>;<V-.>;<v-.>;<W!>;/
+ <w!>;<W'>;<w'>;<W:>;<w:>;<W.>;/
+ <w.>;<W-.>;<w-.>;<X.>;<x.>;/
+ <X:>;<x:>;<Y.>;<y.>;<Z/>>;/
+ <z/>>;<Z-.>;<z-.>;<Z_>;<z_>;/
+ <A-.>;<a-.>;<A2>;<a2>;<A/>'>;/
+ <a/>'>;<A/>!>;<a/>!>;<A/>2>;/
+ <a/>2>;<A/>?>;<a/>?>;<A/>-.>;/
+ <a/>-.>;<A('>;<a('>;<A(!>;/
+ <a(!>;<A(2>;<a(2>;<A(?>;<a(?>;/
+ <A(-.>;<a(-.>;<E-.>;<e-.>;<E2>;/
+ <e2>;<E?>;<e?>;<E/>'>;<e/>'>;/
+ <E/>!>;<e/>!>;<E/>2>;<e/>2>;/
+ <E/>?>;<e/>?>;<E/>-.>;<e/>-.>;/
+ <I2>;<i2>;<I-.>;<i-.>;<O-.>;/
+ <o-.>;<O2>;<o2>;<O/>'>;<o/>'>;/
+ <O/>!>;<o/>!>;<O/>2>;<o/>2>;/
+ <O/>?>;<o/>?>;<O/>-.>;<o/>-.>;/
+ <O9'>;<o9'>;<O9!>;<o9!>;<O92>;/
+ <o92>;<O9?>;<o9?>;<O9-.>;/
+ <o9-.>;<U-.>;<u-.>;<U2>;<u2>;/
+ <U9'>;<u9'>;<U9!>;<u9!>;<U92>;/
+ <u92>;<U9?>;<u9?>;<U9-.>;/
+ <u9-.>;<Y!>;<y!>;<Y-.>;<y-.>;/
+ <Y2>;<y2>;<Y?>;<y?>;<nS>;<(a)>;/
+ <(b)>;<(c)>;<(d)>;<(e)>;<(f)>;/
+ <(g)>;<(h)>;<(i)>;<(j)>;<(k)>;/
+ <(l)>;<(m)>;<(n)>;<(o)>;<(p)>;/
+ <(q)>;<(r)>;<(s)>;<(t)>;<(u)>;/
+ <(v)>;<(w)>;<(x)>;<(y)>;<(z)>;/
+ <A-o>;<B-o>;<C-o>;<D-o>;<E-o>;/
+ <F-o>;<G-o>;<H-o>;<I-o>;<J-o>;/
+ <K-o>;<L-o>;<M-o>;<N-o>;<O-o>;/
+ <P-o>;<Q-o>;<R-o>;<S-o>;<T-o>;/
+ <U-o>;<V-o>;<W-o>;<X-o>;<Y-o>;/
+ <Z-o>;<a-o>;<b-o>;<c-o>;<d-o>;/
+ <e-o>;<f-o>;<g-o>;<h-o>;<i-o>;/
+ <j-o>;<k-o>;<l-o>;<m-o>;<n-o>;/
+ <o-o>;<p-o>;<q-o>;<r-o>;<s-o>;/
+ <t-o>;<u-o>;<v-o>;<w-o>;<x-o>;/
+ <y-o>;<z-o>;<A5>;<a5>;<I5>;/
+ <i5>;<U5>;<u5>;<E5>;<e5>;<O5>;/
+ <o5>;<ka>;<ga>;<ki>;<gi>;<ku>;/
+ <gu>;<ke>;<ge>;<ko>;<go>;<sa>;/
+ <za>;<si>;<zi>;<su>;<zu>;<se>;/
+ <ze>;<so>;<zo>;<ta>;<da>;<ti>;/
+ <di>;<tU>;<tu>;<du>;<te>;<de>;/
+ <to>;<do>;<na>;<ni>;<nu>;<ne>;/
+ <no>;<ha>;<ba>;<pa>;<hi>;<bi>;/
+ <pi>;<hu>;<bu>;<pu>;<he>;<be>;/
+ <pe>;<ho>;<bo>;<po>;<ma>;<mi>;/
+ <mu>;<me>;<mo>;<yA>;<ya>;<yU>;/
+ <yu>;<yO>;<yo>;<ra>;<ri>;<ru>;/
+ <re>;<ro>;<wA>;<wa>;<wi>;<we>;/
+ <wo>;<n5>;<vu>;<a6>;<A6>;<i6>;/
+ <I6>;<u6>;<U6>;<e6>;<E6>;<o6>;/
+ <O6>;<Ka>;<Ga>;<Ki>;<Gi>;<Ku>;/
+ <Gu>;<Ke>;<Ge>;<Ko>;<Go>;<Sa>;/
+ <Za>;<Si>;<Zi>;<Su>;<Zu>;<Se>;/
+ <Ze>;<So>;<Zo>;<Ta>;<Da>;<Ti>;/
+ <Di>;<TU>;<Tu>;<Du>;<Te>;<De>;/
+ <To>;<Do>;<Na>;<Ni>;<Nu>;<Ne>;/
+ <No>;<Ha>;<Ba>;<Pa>;<Hi>;<Bi>;/
+ <Pi>;<Hu>;<Bu>;<Pu>;<He>;<Be>;/
+ <Pe>;<Ho>;<Bo>;<Po>;<Ma>;<Mi>;/
+ <Mu>;<Me>;<Mo>;<YA>;<Ya>;<YU>;/
+ <Yu>;<YO>;<Yo>;<Ra>;<Ri>;<Ru>;/
+ <Re>;<Ro>;<WA>;<Wa>;<Wi>;<We>;/
+ <Wo>;<N6>;<Vu>;<KA>;<KE>;<Va>;/
+ <Vi>;<Ve>;<Vo>;<ff>;<fi>;<fl>;/
+ <ffi>;<ffl>;<ft>;<st>;<aM.>;/
+ <aH.>;<ah.>;<a+->;<a+.>;<b+->;/
+ <b+.>;<b+,>;<b+;>;<tm->;<tm.>;/
+ <t+->;<t+.>;<t+,>;<t+;>;<tk->;/
+ <tk.>;<tk,>;<tk;>;<g+->;<g+.>;/
+ <g+,>;<g+;>;<hk->;<hk.>;<hk,>;/
+ <hk;>;<x+->;<x+.>;<x+,>;<x+;>;/
+ <d+->;<d+.>;<dk->;<dk.>;<r+->;/
+ <r+.>;<z+->;<z+.>;<s+->;<s+.>;/
+ <s+,>;<s+;>;<sn->;<sn.>;<sn,>;/
+ <sn;>;<c+->;<c+.>;<c+,>;<c+;>;/
+ <dd->;<dd.>;<dd,>;<dd;>;<tj->;/
+ <tj.>;<tj,>;<tj;>;<zH->;<zH.>;/
+ <zH,>;<zH;>;<e+->;<e+.>;<e+,>;/
+ <e+;>;<i+->;<i+.>;<i+,>;<i+;>;/
+ <f+->;<f+.>;<f+,>;<f+;>;<q+->;/
+ <q+.>;<q+,>;<q+;>;<k+->;<k+.>;/
+ <k+,>;<k+;>;<l+->;<l+.>;<l+,>;/
+ <l+;>;<m+->;<m+.>;<m+,>;<m+;>;/
+ <n+->;<n+.>;<n+,>;<n+;>;<h+->;/
+ <h+.>;<h+,>;<h+;>;<w+->;<w+.>;/
+ <j+->;<j+.>;<y+->;<y+.>;<y+,>;/
+ <y+;>;<lM->;<lM.>;<lH->;<lH.>;/
+ <lh->;<lh.>;<la->;<la.>;<a+:>
+
+cntrl <NU>;<SH>;<SX>;<EX>;<ET>;<EQ>;/
+ <AK>;<BL>;<BS>;<HT>;<LF>;<VT>;/
+ <FF>;<CR>;<SO>;<SI>;<DL>;<D1>;/
+ <D2>;<D3>;<D4>;<NK>;<SY>;<EB>;/
+ <CN>;<EM>;<SB>;<EC>;<FS>;<GS>;/
+ <RS>;<US>;<DT>;<PA>;<HO>;<BH>;/
+ <NH>;<IN>;<NL>;<SA>;<ES>;<HS>;/
+ <HJ>;<VS>;<PD>;<PU>;<RI>;<S2>;/
+ <S3>;<DC>;<P1>;<P2>;<TS>;<CC>;/
+ <MW>;<SG>;<EG>;<SS>;<GC>;<SC>;/
+ <CI>;<ST>;<OC>;<PM>;<AC>
+
+punct <!>;<">;<Nb>;<DO>;<%>;<&>;<'>;/
+ <(>;<)>;<*>;<+>;<,>;<->;<.>;/
+ <//>;<:>;<;>;<<>;<=>;</>>;<?>;/
+ <At>;<<(>;<////>;<)/>>;<'/>>;/
+ <_>;<'!>;<(!>;<!!>;<!)>;<'?>;/
+ <!I>;<Ct>;<Pd>;<Cu>;<Ye>;<BB>;/
+ <SE>;<':>;<Co>;<-a>;<<<>;<NO>;/
+ <Rg>;<'m>;<DG>;<+->;<2S>;<3S>;/
+ <''>;<My>;<PI>;<.M>;<',>;<1S>;/
+ <-o>;</>/>>;<14>;<12>;<34>;/
+ <?I>;<*X>;<-:>;<'<>;<'(>;<'.>;/
+ <'0>;<';>;<1?>;<'">;<'G>;<,G>;/
+ <j3>;<?%>;<'*>;<'%>;<.*>;<b3>;/
+ <,+>;<;+>;<?+>;<++>;<:+>;<"+>;/
+ <=+>;<//+>;<'+>;<1+>;<3+>;<0+>;/
+ <0a>;<1a>;<2a>;<3a>;<4a>;<5a>;/
+ <6a>;<7a>;<8a>;<9a>;<,,>;<?*>;/
+ <?:>;<,!>;<,'>;<?,>;<;!>;<;'>;/
+ <?;>;<!:>;<!*>;<;;>;<1N>;<1M>;/
+ <3M>;<4M>;<6M>;<LR>;<RL>;<1T>;/
+ <1H>;<-1>;<-N>;<-M>;<-3>;<!2>;/
+ <=2>;<'6>;<'9>;<.9>;<9'>;<"6>;/
+ <"9>;<:9>;<9">;<//->;<//=>;/
+ <Sb>;<..>;<.3>;<%0>;<1'>;<2'>;/
+ <3'>;<1">;<2">;<3">;<Ca>;<<1>;/
+ </>1>;<:X>;<!*2>;<'->;<0S>;/
+ <4S>;<5S>;<6S>;<7S>;<8S>;<9S>;/
+ <+S>;<-S>;<=S>;<(S>;<)S>;<0s>;/
+ <1s>;<2s>;<3s>;<4s>;<5s>;<6s>;/
+ <7s>;<8s>;<9s>;<+s>;<-s>;<=s>;/
+ <(s>;<)s>;<Ff>;<Li>;<Pt>;<W=>;/
+ <oC>;<co>;<oF>;<N0>;<PO>;<Rx>;/
+ <SM>;<TM>;<Om>;<AO>;<13>;<23>;/
+ <15>;<25>;<35>;<45>;<16>;<56>;/
+ <18>;<38>;<58>;<78>;<1R>;<2R>;/
+ <3R>;<4R>;<5R>;<6R>;<7R>;<8R>;/
+ <9R>;<aR>;<bR>;<cR>;<50R>;/
+ <100R>;<500R>;<1000R>;<1r>;/
+ <2r>;<3r>;<4r>;<5r>;<6r>;<7r>;/
+ <8r>;<9r>;<ar>;<br>;<cr>;<50r>;/
+ <100r>;<500r>;<1000r>;/
+ <1000RCD>;<5000R>;<10000R>;/
+ <<->;<-!>;<-/>>;<-v>;<</>>;/
+ <UD>;<<!!>;</////>>;<!!/>>;/
+ <<////>;<UD->;</>V>;<<=>;<=/>>;/
+ <==>;<FA>;<dP>;<TE>;<//0>;<DE>;/
+ <NB>;<(->;<-)>;<*P>;<+Z>;<-2>;/
+ <-+>;<.+>;<//f>;<*->;<Ob>;<sb>;/
+ <RT>;<0(>;<00>;<-L>;<-V>;<PP>;/
+ <AN>;<OR>;<(U>;<)U>;<In>;<DI>;/
+ <Io>;<.:>;<:.>;<:R>;<::>;<?1>;/
+ <CG>;<?->;<?=>;<?2>;<=?>;<HI>;/
+ <!=>;<=3>;<=<>;</>=>;<<*>;/
+ <*/>>;<!<>;<!/>>;<(C>;<)C>;/
+ <(_>;<)_>;<0.>;<02>;<-T>;<.P>;/
+ <:3>;<Eh>;<<7>;</>7>;<7<>;/
+ <7/>>;<NI>;<(A>;<TR>;<Iu>;<Il>;/
+ <<//>;<///>>;<Vs>;<1h>;<3h>;/
+ <2h>;<4h>;<1j>;<2j>;<3j>;<4j>;/
+ <1-o>;<2-o>;<3-o>;<4-o>;<5-o>;/
+ <6-o>;<7-o>;<8-o>;<9-o>;<10-o>;/
+ <11-o>;<12-o>;<13-o>;<14-o>;/
+ <15-o>;<16-o>;<17-o>;<18-o>;/
+ <19-o>;<20-o>;<(1)>;<(2)>;/
+ <(3)>;<(4)>;<(5)>;<(6)>;<(7)>;/
+ <(8)>;<(9)>;<(10)>;<(11)>;/
+ <(12)>;<(13)>;<(14)>;<(15)>;/
+ <(16)>;<(17)>;<(18)>;<(19)>;/
+ <(20)>;<1.>;<2.>;<3.>;<4.>;/
+ <5.>;<6.>;<7.>;<8.>;<9.>;<10.>;/
+ <11.>;<12.>;<13.>;<14.>;<15.>;/
+ <16.>;<17.>;<18.>;<19.>;<20.>;/
+ <0-o>;<hh>;<HH>;<vv>;<VV>;<3->;/
+ <3_>;<3!>;<3//>;<4->;<4_>;<4!>;/
+ <4//>;<dr>;<dR>;<Dr>;<DR>;<dl>;/
+ <dL>;<Dl>;<LD>;<ur>;<uR>;<Ur>;/
+ <UR>;<ul>;<uL>;<Ul>;<UL>;<vr>;/
+ <vR>;<Udr>;<uDr>;<Vr>;<UdR>;/
+ <uDR>;<VR>;<vl>;<vL>;<Udl>;/
+ <uDl>;<Vl>;<UdL>;<uDL>;<VL>;/
+ <dh>;<dLr>;<dlR>;<dH>;<Dh>;/
+ <DLr>;<DlR>;<DH>;<uh>;<uLr>;/
+ <ulR>;<uH>;<Uh>;<ULr>;<UlR>;/
+ <UH>;<vh>;<vLr>;<vlR>;<vH>;/
+ <Udh>;<uDh>;<Vh>;<UdLr>;<UdlR>;/
+ <uDLr>;<uDlR>;<UdH>;<uDH>;/
+ <VLr>;<VlR>;<VH>;<FD>;<BD>;/
+ <TB>;<LB>;<FB>;<lB>;<RB>;<.S>;/
+ <:S>;<?S>;<fS>;<OS>;<RO>;<Rr>;/
+ <RF>;<RY>;<RH>;<RZ>;<RK>;<RX>;/
+ <sB>;<SR>;<Or>;<UT>;<uT>;<Tr>;/
+ <PR>;<Dt>;<dT>;<Tl>;<PL>;<Db>;/
+ <Dw>;<LZ>;<0m>;<0o>;<0M>;<0L>;/
+ <0R>;<Sn>;<Ic>;<Fd>;<Bd>;<Ci>;/
+ <*2>;<*1>;<TEL>;<tel>;<<H>;/
+ </>H>;<0u>;<0U>;<SU>;<Fm>;<Ml>;/
+ <cS>;<cH>;<cD>;<cC>;<cS->;/
+ <cH->;<cD->;<cC->;<Md>;<M8>;/
+ <M2>;<M16>;<Mb>;<Mx>;<MX>;<OK>;/
+ <XX>;<-X>;<IS>;<,_>;<._>;<+">;/
+ <JIS>;<*_>;<;_>;<0_>;<<+>;/
+ </>+>;<<'>;</>'>;<<">;</>">;/
+ <(">;<)">;<=T>;<=_>;<('>;<)'>;/
+ <(I>;<)I>;<-?>;<=T:)>;<"5>;/
+ <05>;<*5>;<+5>;<.6>;<-6>;<*6>;/
+ <+6>;<(JU)>;<1c>;<2c>;<3c>;/
+ <4c>;<5c>;<6c>;<7c>;<8c>;<9c>;/
+ <10c>;<KSC>;<am>;<pm>;<3+;>;/
+ <"3>;<"1>;<"!>;<"'>;<"/>>;<"?>;/
+ <"->;<"(>;<".>;<":>;<"0>;<",>;/
+ <"_>;<"">;<";>;<"<>;<"=>;<"//>;/
+ <"p>;<"d>;<"i>;<+_>;<Tel>;<UA>;/
+ <UB>
+
+tolower (<A>,<a>);(<A!>,<a!>);/
+ (<A!!>,<a!!>);(<A'>,<a'>);/
+ (<A(>,<a(>);(<A(!>,<a(!>);/
+ (<A('>,<a('>);(<A(-.>,<a(-.>);/
+ (<A(2>,<a(2>);(<A(?>,<a(?>);/
+ (<A)>,<a)>);(<A->,<a->);/
+ (<A-.>,<a-.>);(<A-0>,<a-0>);/
+ (<A-o>,<a-o>);(<A1>,<a1>);/
+ (<A2>,<a2>);(<A3>,<a3>);/
+ (<A7>,<a7>);(<A:>,<a:>);/
+ (<A;>,<a;>);(<A<>,<a<>);/
+ (<A/>>,<a/>>);(<A/>!>,<a/>!>);/
+ (<A/>'>,<a/>'>);/
+ (<A/>-.>,<a/>-.>);/
+ (<A/>2>,<a/>2>);/
+ (<A/>?>,<a/>?>);(<A?>,<a?>);/
+ (<AA>,<aa>);(<AA'>,<aa'>);/
+ (<AE>,<ae>);(<AE'>,<ae'>);/
+ (<B>,<b>);(<B-.>,<b-.>);/
+ (<B-o>,<b-o>);(<B.>,<b.>);/
+ (<B_>,<b_>);(<C>,<c>);/
+ (<C'>,<c'>);(<C,>,<c,>);/
+ (<C,'>,<c,'>);(<C-o>,<c-o>);/
+ (<C.>,<c.>);(<C2>,<c2>);/
+ (<C<>,<c<>);(<C/>>,<c/>>);/
+ (<D>,<d>);(<D,>,<d,>);/
+ (<D->,<d->);(<D-.>,<d-.>);/
+ (<D-/>>,<d-/>>);(<D-o>,<d-o>);/
+ (<D.>,<d.>);(<D//>,<d//>);/
+ (<D<>,<d<>);(<D_>,<d_>);/
+ (<E>,<e>);(<E!>,<e!>);/
+ (<E!!>,<e!!>);(<E'>,<e'>);/
+ (<E(>,<e(>);(<E)>,<e)>);/
+ (<E,(>,<e,(>);(<E->,<e->);/
+ (<E-!>,<e-!>);(<E-'>,<e-'>);/
+ (<E-.>,<e-.>);(<E-/>>,<e-/>>);/
+ (<E-?>,<e-?>);(<E-o>,<e-o>);/
+ (<E.>,<e.>);(<E2>,<e2>);/
+ (<E:>,<e:>);(<E;>,<e;>);/
+ (<E<>,<e<>);(<E/>>,<e/>>);/
+ (<E/>!>,<e/>!>);/
+ (<E/>'>,<e/>'>);/
+ (<E/>-.>,<e/>-.>);/
+ (<E/>2>,<e/>2>);/
+ (<E/>?>,<e/>?>);(<E?>,<e?>);/
+ (<ED>,<ed>);(<EZ>,<ez>);/
+ (<F>,<f>);(<F-o>,<f-o>);/
+ (<F.>,<f.>);(<F2>,<f2>);/
+ (<G>,<g>);(<G'>,<g'>);/
+ (<G(>,<g(>);(<G,>,<g,>);/
+ (<G->,<g->);(<G-o>,<g-o>);/
+ (<G.>,<g.>);(<G//>,<g//>);/
+ (<G<>,<g<>);(<G/>>,<g/>>);/
+ (<H>,<h>);(<H,>,<h,>);/
+ (<H-(>,<h-(>);(<H-.>,<h-.>);/
+ (<H-o>,<h-o>);(<H.>,<h.>);/
+ (<H//>,<h//>);(<H:>,<h:>);/
+ (<H/>>,<h/>>);(<I>,<i>);/
+ (<I!>,<i!>);(<I!!>,<i!!>);/
+ (<I'>,<i'>);(<I(>,<i(>);/
+ (<I)>,<i)>);(<I->,<i->);/
+ (<I-.>,<i-.>);(<I-?>,<i-?>);/
+ (<I-o>,<i-o>);(<I.>,<i.>);/
+ (<I2>,<i2>);(<I:>,<i:>);/
+ (<I:'>,<i:'>);(<I;>,<i;>);/
+ (<I<>,<i<>);(<I/>>,<i/>>);/
+ (<I?>,<i?>);(<IJ>,<ij>);/
+ (<J>,<j>);(<J-o>,<j-o>);/
+ (<J/>>,<j/>>);(<K>,<k>);/
+ (<K'>,<k'>);(<K,>,<k,>);/
+ (<K-.>,<k-.>);(<K-o>,<k-o>);/
+ (<K2>,<k2>);(<K<>,<k<>);/
+ (<K_>,<k_>);(<L>,<l>);/
+ (<L'>,<l'>);(<L,>,<l,>);/
+ (<L--.>,<l--.>);(<L-.>,<l-.>);/
+ (<L-/>>,<l-/>>);(<L-o>,<l-o>);/
+ (<L.>,<l.>);(<L//>,<l//>);/
+ (<L<>,<l<>);(<L_>,<l_>);/
+ (<M>,<m>);(<M'>,<m'>);/
+ (<M-.>,<m-.>);(<M-o>,<m-o>);/
+ (<M.>,<m.>);(<N>,<n>);/
+ (<N'>,<n'>);(<N,>,<n,>);/
+ (<N-.>,<n-.>);(<N-/>>,<n-/>>);/
+ (<N-o>,<n-o>);(<N.>,<n.>);/
+ (<N<>,<n<>);(<N?>,<n?>);/
+ (<NG>,<ng>);(<N_>,<n_>);/
+ (<O>,<o>);(<O!>,<o!>);/
+ (<O!!>,<o!!>);(<O">,<o">);/
+ (<O'>,<o'>);(<O(>,<o(>);/
+ (<O)>,<o)>);(<O->,<o->);/
+ (<O-!>,<o-!>);(<O-'>,<o-'>);/
+ (<O-.>,<o-.>);(<O-o>,<o-o>);/
+ (<O//>,<o//>);(<O1>,<o1>);/
+ (<O2>,<o2>);(<O9>,<o9>);/
+ (<O9!>,<o9!>);(<O9'>,<o9'>);/
+ (<O9-.>,<o9-.>);(<O92>,<o92>);/
+ (<O9?>,<o9?>);(<O:>,<o:>);/
+ (<O;>,<o;>);(<O<>,<o<>);/
+ (<O/>>,<o/>>);(<O/>!>,<o/>!>);/
+ (<O/>'>,<o/>'>);/
+ (<O/>-.>,<o/>-.>);/
+ (<O/>2>,<o/>2>);/
+ (<O/>?>,<o/>?>);(<O?>,<o?>);/
+ (<O?'>,<o?'>);(<O?:>,<o?:>);/
+ (<OE>,<oe>);(<OI>,<oi>);/
+ (<P>,<p>);(<P'>,<p'>);/
+ (<P-o>,<p-o>);(<P.>,<p.>);/
+ (<Q>,<q>);(<Q-o>,<q-o>);/
+ (<R>,<r>);(<R!!>,<r!!>);/
+ (<R'>,<r'>);(<R)>,<r)>);/
+ (<R,>,<r,>);(<R--.>,<r--.>);/
+ (<R-.>,<r-.>);(<R-o>,<r-o>);/
+ (<R.>,<r.>);(<R<>,<r<>);/
+ (<R_>,<r_>);(<S>,<s>);/
+ (<S'>,<s'>);(<S'.>,<s'.>);/
+ (<S,>,<s,>);(<S-.>,<s-.>);/
+ (<S-o>,<s-o>);(<S.>,<s.>);/
+ (<S.-.>,<s.-.>);(<S<>,<s<>);/
+ (<S<.>,<s<.>);(<S/>>,<s/>>);/
+ (<T>,<t>);(<T,>,<t,>);/
+ (<T-.>,<t-.>);(<T-/>>,<t-/>>);/
+ (<T-o>,<t-o>);(<T.>,<t.>);/
+ (<T//>,<t//>);(<T<>,<t<>);/
+ (<TH>,<th>);(<T_>,<t_>);/
+ (<U>,<u>);(<U!>,<u!>);/
+ (<U!!>,<u!!>);(<U">,<u">);/
+ (<U'>,<u'>);(<U(>,<u(>);/
+ (<U)>,<u)>);(<U->,<u->);/
+ (<U--:>,<u--:>);(<U-.>,<u-.>);/
+ (<U-:>,<u-:>);(<U-/>>,<u-/>>);/
+ (<U-?>,<u-?>);(<U-o>,<u-o>);/
+ (<U0>,<u0>);(<U2>,<u2>);/
+ (<U9>,<u9>);(<U9!>,<u9!>);/
+ (<U9'>,<u9'>);(<U9-.>,<u9-.>);/
+ (<U92>,<u92>);(<U9?>,<u9?>);/
+ (<U:>,<u:>);(<U:!>,<u:!>);/
+ (<U:'>,<u:'>);(<U:->,<u:->);/
+ (<U:<>,<u:<>);(<U;>,<u;>);/
+ (<U<>,<u<>);(<U/>>,<u/>>);/
+ (<U?>,<u?>);(<U?'>,<u?'>);/
+ (<V>,<v>);(<V-.>,<v-.>);/
+ (<V-o>,<v-o>);(<V?>,<v?>);/
+ (<W>,<w>);(<W!>,<w!>);/
+ (<W'>,<w'>);(<W-.>,<w-.>);/
+ (<W-o>,<w-o>);(<W.>,<w.>);/
+ (<W:>,<w:>);(<W/>>,<w/>>);/
+ (<X>,<x>);(<X-o>,<x-o>);/
+ (<X.>,<x.>);(<X:>,<x:>);/
+ (<Y>,<y>);(<Y!>,<y!>);/
+ (<Y'>,<y'>);(<Y-.>,<y-.>);/
+ (<Y-o>,<y-o>);(<Y.>,<y.>);/
+ (<Y2>,<y2>);(<Y/>>,<y/>>);/
+ (<Y?>,<y?>);(<Z>,<z>);/
+ (<Z'>,<z'>);(<Z-.>,<z-.>);/
+ (<Z-o>,<z-o>);(<Z.>,<z.>);/
+ (<Z//>,<z//>);(<Z<>,<z<>);/
+ (<Z/>>,<z/>>);(<Z_>,<z_>);/
+ (<A%>,<a%>);(<A*>,<a*>);/
+ (<B*>,<b*>);(<C*>,<c*>);/
+ (<D*>,<d*>);(<E%>,<e%>);/
+ (<E*>,<e*>);(<F*>,<f*>);/
+ (<G*>,<g*>);(<H*>,<h*>);/
+ (<I%>,<i%>);(<I*>,<i*>);/
+ (<J*>,<j*>);(<K*>,<k*>);/
+ (<L*>,<l*>);(<M*>,<m*>);/
+ (<N*>,<n*>);(<O%>,<o%>);/
+ (<O*>,<o*>);(<P*>,<p*>);/
+ (<Q*>,<q*>);(<R*>,<r*>);/
+ (<S*>,<s*>);(<T*>,<t*>);/
+ (<U%>,<u%>);(<U*>,<u*>);/
+ (<V*>,<v*>);(<W%>,<w%>);/
+ (<W*>,<w*>);(<X*>,<x*>);/
+ (<Y%>,<y%>);(<Y*>,<y*>);/
+ (<Z*>,<z*>);(<%">,<%'>);/
+ (<=">,<='>);(<A=>,<a=>);/
+ (<B=>,<b=>);(<C%>,<c%>);/
+ (<C3>,<c3>);(<C=>,<c=>);/
+ (<D%>,<d%>);(<D=>,<d=>);/
+ (<DS>,<ds>);(<DZ>,<dz>);/
+ (<E=>,<e=>);(<F3>,<f3>);/
+ (<F=>,<f=>);(<G%>,<g%>);/
+ (<G3>,<g3>);(<G=>,<g=>);/
+ (<H=>,<h=>);(<I=>,<i=>);/
+ (<IE>,<ie>);(<II>,<ii>);/
+ (<IO>,<io>);(<J%>,<j%>);/
+ (<J=>,<j=>);(<JA>,<ja>);/
+ (<JE>,<je>);(<JU>,<ju>);/
+ (<K=>,<k=>);(<KJ>,<kj>);/
+ (<L=>,<l=>);(<LJ>,<lj>);/
+ (<M=>,<m=>);(<N=>,<n=>);/
+ (<NJ>,<nj>);(<O3>,<o3>);/
+ (<O=>,<o=>);(<P=>,<p=>);/
+ (<R=>,<r=>);(<S%>,<s%>);/
+ (<S=>,<s=>);(<Sc>,<sc>);/
+ (<T=>,<t=>);(<Ts>,<ts>);/
+ (<U=>,<u=>);(<V3>,<v3>);/
+ (<V=>,<v=>);(<Y3>,<y3>);/
+ (<Y=>,<y=>);(<YI>,<yi>);/
+ (<Z%>,<z%>);(<Z=>,<z=>)
+
+toupper (<a>,<A>);(<a!>,<A!>);/
+ (<a!!>,<A!!>);(<a'>,<A'>);/
+ (<a(>,<A(>);(<a(!>,<A(!>);/
+ (<a('>,<A('>);(<a(-.>,<A(-.>);/
+ (<a(2>,<A(2>);(<a(?>,<A(?>);/
+ (<a)>,<A)>);(<a->,<A->);/
+ (<a-.>,<A-.>);(<a-0>,<A-0>);/
+ (<a-o>,<A-o>);(<a1>,<A1>);/
+ (<a2>,<A2>);(<a3>,<A3>);/
+ (<a7>,<A7>);(<a:>,<A:>);/
+ (<a;>,<A;>);(<a<>,<A<>);/
+ (<a/>>,<A/>>);(<a/>!>,<A/>!>);/
+ (<a/>'>,<A/>'>);/
+ (<a/>-.>,<A/>-.>);/
+ (<a/>2>,<A/>2>);/
+ (<a/>?>,<A/>?>);(<a?>,<A?>);/
+ (<aa>,<AA>);(<aa'>,<AA'>);/
+ (<ae>,<AE>);(<ae'>,<AE'>);/
+ (<b>,<B>);(<b-.>,<B-.>);/
+ (<b-o>,<B-o>);(<b.>,<B.>);/
+ (<b_>,<B_>);(<c>,<C>);/
+ (<c'>,<C'>);(<c,>,<C,>);/
+ (<c,'>,<C,'>);(<c-o>,<C-o>);/
+ (<c.>,<C.>);(<c2>,<C2>);/
+ (<c<>,<C<>);(<c/>>,<C/>>);/
+ (<d>,<D>);(<d,>,<D,>);/
+ (<d->,<D->);(<d-.>,<D-.>);/
+ (<d-/>>,<D-/>>);(<d-o>,<D-o>);/
+ (<d.>,<D.>);(<d//>,<D//>);/
+ (<d<>,<D<>);(<d_>,<D_>);/
+ (<e>,<E>);(<e!>,<E!>);/
+ (<e!!>,<E!!>);(<e'>,<E'>);/
+ (<e(>,<E(>);(<e)>,<E)>);/
+ (<e,(>,<E,(>);(<e->,<E->);/
+ (<e-!>,<E-!>);(<e-'>,<E-'>);/
+ (<e-.>,<E-.>);(<e-/>>,<E-/>>);/
+ (<e-?>,<E-?>);(<e-o>,<E-o>);/
+ (<e.>,<E.>);(<e2>,<E2>);/
+ (<e:>,<E:>);(<e;>,<E;>);/
+ (<e<>,<E<>);(<e/>>,<E/>>);/
+ (<e/>!>,<E/>!>);/
+ (<e/>'>,<E/>'>);/
+ (<e/>-.>,<E/>-.>);/
+ (<e/>2>,<E/>2>);/
+ (<e/>?>,<E/>?>);(<e?>,<E?>);/
+ (<ed>,<ED>);(<ez>,<EZ>);/
+ (<f>,<F>);(<f-o>,<F-o>);/
+ (<f.>,<F.>);(<f2>,<F2>);/
+ (<g>,<G>);(<g'>,<G'>);/
+ (<g(>,<G(>);(<g,>,<G,>);/
+ (<g->,<G->);(<g-o>,<G-o>);/
+ (<g.>,<G.>);(<g//>,<G//>);/
+ (<g<>,<G<>);(<g/>>,<G/>>);/
+ (<h>,<H>);(<h,>,<H,>);/
+ (<h-(>,<H-(>);(<h-.>,<H-.>);/
+ (<h-o>,<H-o>);(<h.>,<H.>);/
+ (<h//>,<H//>);(<h:>,<H:>);/
+ (<h/>>,<H/>>);(<i>,<I>);/
+ (<i!>,<I!>);(<i!!>,<I!!>);/
+ (<i'>,<I'>);(<i(>,<I(>);/
+ (<i)>,<I)>);(<i->,<I->);/
+ (<i-.>,<I-.>);(<i-?>,<I-?>);/
+ (<i-o>,<I-o>);(<i.>,<I.>);/
+ (<i2>,<I2>);(<i:>,<I:>);/
+ (<i:'>,<I:'>);(<i;>,<I;>);/
+ (<i<>,<I<>);(<i/>>,<I/>>);/
+ (<i?>,<I?>);(<ij>,<IJ>);/
+ (<j>,<J>);(<j-o>,<J-o>);/
+ (<j/>>,<J/>>);(<k>,<K>);/
+ (<k'>,<K'>);(<k,>,<K,>);/
+ (<k-.>,<K-.>);(<k-o>,<K-o>);/
+ (<k2>,<K2>);(<k<>,<K<>);/
+ (<k_>,<K_>);(<l>,<L>);/
+ (<l'>,<L'>);(<l,>,<L,>);/
+ (<l--.>,<L--.>);(<l-.>,<L-.>);/
+ (<l-/>>,<L-/>>);(<l-o>,<L-o>);/
+ (<l.>,<L.>);(<l//>,<L//>);/
+ (<l<>,<L<>);(<l_>,<L_>);/
+ (<m>,<M>);(<m'>,<M'>);/
+ (<m-.>,<M-.>);(<m-o>,<M-o>);/
+ (<m.>,<M.>);(<n>,<N>);/
+ (<n'>,<N'>);(<n,>,<N,>);/
+ (<n-.>,<N-.>);(<n-/>>,<N-/>>);/
+ (<n-o>,<N-o>);(<n.>,<N.>);/
+ (<n<>,<N<>);(<n?>,<N?>);/
+ (<ng>,<NG>);(<n_>,<N_>);/
+ (<o>,<O>);(<o!>,<O!>);/
+ (<o!!>,<O!!>);(<o">,<O">);/
+ (<o'>,<O'>);(<o(>,<O(>);/
+ (<o)>,<O)>);(<o->,<O->);/
+ (<o-!>,<O-!>);(<o-'>,<O-'>);/
+ (<o-.>,<O-.>);(<o-o>,<O-o>);/
+ (<o//>,<O//>);(<o1>,<O1>);/
+ (<o2>,<O2>);(<o9>,<O9>);/
+ (<o9!>,<O9!>);(<o9'>,<O9'>);/
+ (<o9-.>,<O9-.>);(<o92>,<O92>);/
+ (<o9?>,<O9?>);(<o:>,<O:>);/
+ (<o;>,<O;>);(<o<>,<O<>);/
+ (<o/>>,<O/>>);(<o/>!>,<O/>!>);/
+ (<o/>'>,<O/>'>);/
+ (<o/>-.>,<O/>-.>);/
+ (<o/>2>,<O/>2>);/
+ (<o/>?>,<O/>?>);(<o?>,<O?>);/
+ (<o?'>,<O?'>);(<o?:>,<O?:>);/
+ (<oe>,<OE>);(<oi>,<OI>);/
+ (<p>,<P>);(<p'>,<P'>);/
+ (<p-o>,<P-o>);(<p.>,<P.>);/
+ (<q>,<Q>);(<q-o>,<Q-o>);/
+ (<r>,<R>);(<r!!>,<R!!>);/
+ (<r'>,<R'>);(<r)>,<R)>);/
+ (<r,>,<R,>);(<r--.>,<R--.>);/
+ (<r-.>,<R-.>);(<r-o>,<R-o>);/
+ (<r.>,<R.>);(<r<>,<R<>);/
+ (<r_>,<R_>);(<s>,<S>);/
+ (<s'>,<S'>);(<s'.>,<S'.>);/
+ (<s,>,<S,>);(<s-.>,<S-.>);/
+ (<s-o>,<S-o>);(<s.>,<S.>);/
+ (<s.-.>,<S.-.>);(<s<>,<S<>);/
+ (<s<.>,<S<.>);(<s/>>,<S/>>);/
+ (<t>,<T>);(<t,>,<T,>);/
+ (<t-.>,<T-.>);(<t-/>>,<T-/>>);/
+ (<t-o>,<T-o>);(<t.>,<T.>);/
+ (<t//>,<T//>);(<t<>,<T<>);/
+ (<th>,<TH>);(<t_>,<T_>);/
+ (<u>,<U>);(<u!>,<U!>);/
+ (<u!!>,<U!!>);(<u">,<U">);/
+ (<u'>,<U'>);(<u(>,<U(>);/
+ (<u)>,<U)>);(<u->,<U->);/
+ (<u--:>,<U--:>);(<u-.>,<U-.>);/
+ (<u-:>,<U-:>);(<u-/>>,<U-/>>);/
+ (<u-?>,<U-?>);(<u-o>,<U-o>);/
+ (<u0>,<U0>);(<u2>,<U2>);/
+ (<u9>,<U9>);(<u9!>,<U9!>);/
+ (<u9'>,<U9'>);(<u9-.>,<U9-.>);/
+ (<u92>,<U92>);(<u9?>,<U9?>);/
+ (<u:>,<U:>);(<u:!>,<U:!>);/
+ (<u:'>,<U:'>);(<u:->,<U:->);/
+ (<u:<>,<U:<>);(<u;>,<U;>);/
+ (<u<>,<U<>);(<u/>>,<U/>>);/
+ (<u?>,<U?>);(<u?'>,<U?'>);/
+ (<v>,<V>);(<v-.>,<V-.>);/
+ (<v-o>,<V-o>);(<v?>,<V?>);/
+ (<w>,<W>);(<w!>,<W!>);/
+ (<w'>,<W'>);(<w-.>,<W-.>);/
+ (<w-o>,<W-o>);(<w.>,<W.>);/
+ (<w:>,<W:>);(<w/>>,<W/>>);/
+ (<x>,<X>);(<x-o>,<X-o>);/
+ (<x.>,<X.>);(<x:>,<X:>);/
+ (<y>,<Y>);(<y!>,<Y!>);/
+ (<y'>,<Y'>);(<y-.>,<Y-.>);/
+ (<y-o>,<Y-o>);(<y.>,<Y.>);/
+ (<y2>,<Y2>);(<y/>>,<Y/>>);/
+ (<y?>,<Y?>);(<z>,<Z>);/
+ (<z'>,<Z'>);(<z-.>,<Z-.>);/
+ (<z-o>,<Z-o>);(<z.>,<Z.>);/
+ (<z//>,<Z//>);(<z<>,<Z<>);/
+ (<z/>>,<Z/>>);(<z_>,<Z_>);/
+ (<a%>,<A%>);(<a*>,<A*>);/
+ (<b*>,<B*>);(<c*>,<C*>);/
+ (<d*>,<D*>);(<e%>,<E%>);/
+ (<e*>,<E*>);(<f*>,<F*>);/
+ (<g*>,<G*>);(<h*>,<H*>);/
+ (<i%>,<I%>);(<i*>,<I*>);/
+ (<j*>,<J*>);(<k*>,<K*>);/
+ (<l*>,<L*>);(<m*>,<M*>);/
+ (<n*>,<N*>);(<o%>,<O%>);/
+ (<o*>,<O*>);(<p*>,<P*>);/
+ (<q*>,<Q*>);(<r*>,<R*>);/
+ (<s*>,<S*>);(<t*>,<T*>);/
+ (<u%>,<U%>);(<u*>,<U*>);/
+ (<v*>,<V*>);(<w%>,<W%>);/
+ (<w*>,<W*>);(<x*>,<X*>);/
+ (<y%>,<Y%>);(<y*>,<Y*>);/
+ (<z*>,<Z*>);(<%'>,<%">);/
+ (<='>,<=">);(<a=>,<A=>);/
+ (<b=>,<B=>);(<c%>,<C%>);/
+ (<c3>,<C3>);(<c=>,<C=>);/
+ (<d%>,<D%>);(<d=>,<D=>);/
+ (<ds>,<DS>);(<dz>,<DZ>);/
+ (<e=>,<E=>);(<f3>,<F3>);/
+ (<f=>,<F=>);(<g%>,<G%>);/
+ (<g3>,<G3>);(<g=>,<G=>);/
+ (<h=>,<H=>);(<i=>,<I=>);/
+ (<ie>,<IE>);(<ii>,<II>);/
+ (<io>,<IO>);(<j%>,<J%>);/
+ (<j=>,<J=>);(<ja>,<JA>);/
+ (<je>,<JE>);(<ju>,<JU>);/
+ (<k=>,<K=>);(<kj>,<KJ>);/
+ (<l=>,<L=>);(<lj>,<LJ>);/
+ (<m=>,<M=>);(<n=>,<N=>);/
+ (<nj>,<NJ>);(<o3>,<O3>);/
+ (<o=>,<O=>);(<p=>,<P=>);/
+ (<r=>,<R=>);(<s%>,<S%>);/
+ (<s=>,<S=>);(<sc>,<Sc>);/
+ (<t=>,<T=>);(<ts>,<Ts>);/
+ (<u=>,<U=>);(<v3>,<V3>);/
+ (<v=>,<V=>);(<y3>,<Y3>);/
+ (<y=>,<Y=>);(<yi>,<YI>);/
+ (<z%>,<Z%>);(<z=>,<Z=>);/
+ (<*s>,<S*>)
+
+END LC_CTYPE
+
+LC_MONETARY
+int_curr_symbol "<D><K><K><SP>"
+currency_symbol "<Cu>"
+mon_decimal_point "<,>"
+mon_thousands_sep "<.>"
+mon_grouping 3;3
+positive_sign ""
+negative_sign "<->"
+int_frac_digits 2
+frac_digits 2
+p_cs_precedes 1
+p_sep_by_space 0
+n_cs_precedes 1
+n_sep_by_space 0
+p_sign_posn 1
+n_sign_posn 1
+END LC_MONETARY
+
+LC_NUMERIC
+decimal_point "<,>"
+thousands_sep "<.>"
+grouping 3;3
+END LC_NUMERIC
+
+LC_TIME
+abday "<S><u><n>";"<M><o><n>";/
+ "<T><u><e>";"<W><e><d>";/
+ "<T><h><u>";"<F><r><i>";/
+ "<S><a><t>"
+day "<S><u><n><d><a><y>";/
+ "<M><o><n><d><a><y>";/
+ "<T><u><e><s><d><a><y>";/
+ "<W><e><d><n><e><s><d><a><y>";/
+ "<T><h><u><r><s><d><a><y>";/
+ "<F><r><i><d><a><y>";/
+ "<S><a><t><u><r><d><a><y>"
+abmon "<J><a><n>";"<F><e><b>";/
+ "<M><a><r>";"<A><p><r>";/
+ "<M><a><y>";"<J><u><n>";/
+ "<J><u><l>";"<A><u><g>";/
+ "<S><e><p>";"<O><c><t>";/
+ "<N><o><v>";"<D><e><c>"
+mon "<J><a><n><u><a><r><y>";/
+ "<F><e><b><r><u><a><r><y>";/
+ "<M><a><r><c><h>";/
+ "<A><p><r><i><l>";/
+ "<M><a><y>";/
+ "<J><u><n><e>";/
+ "<J><u><l><y>";/
+ "<A><u><g><u><s><t>";/
+ "<S><e><p><t><e><m><b><e><r>";/
+ "<O><c><t><o><b><e><r>";/
+ "<N><o><v><e><m><b><e><r>";/
+ "<D><e><c><e><m><b><e><r>"
+% date formats following ISO 8601-1988
+d_t_fmt "<%><Y><-><%><m><-><%><d><T><%><T><SP><%><Z>"
+d_fmt "<%><Y><-><%><m><-><%><d>"
+t_fmt "<%><T>"
+am_pm "";""
+t_fmt_ampm ""
+END LC_TIME
+
+LC_MESSAGES
+yesexpr "<<(><1><J><j><s><S><y><Y><o><O><)/>><.><*>"
+noexpr "<<(><0><n><N><)/>><.><*>"
+END LC_MESSAGES
diff --git a/usr.bin/colldef/parse.y b/usr.bin/colldef/parse.y
new file mode 100644
index 0000000..e316e1c
--- /dev/null
+++ b/usr.bin/colldef/parse.y
@@ -0,0 +1,289 @@
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: parse.y,v 1.9 1997/06/26 11:25:17 charnier Exp $
+ */
+
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include "collate.h"
+
+extern int line_no;
+extern FILE *yyin;
+void yyerror(char *fmt, ...);
+static void usage __P((void));
+
+char map_name[FILENAME_MAX] = ".";
+
+char __collate_version[STR_LEN];
+u_char charmap_table[UCHAR_MAX + 1][STR_LEN];
+u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
+struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE];
+int chain_index;
+int prim_pri = 1, sec_pri = 1;
+#ifdef COLLATE_DEBUG
+int debug;
+#endif
+
+char *out_file = "LC_COLLATE";
+%}
+%union {
+ u_char ch;
+ u_char str[STR_LEN];
+}
+%token SUBSTITUTE WITH ORDER RANGE
+%token <str> STRING
+%token <str> CHAIN
+%token <str> DEFN
+%token <ch> CHAR
+%%
+collate : statment_list
+;
+statment_list : statment
+ | statment_list '\n' statment
+;
+statment :
+ | charmap
+ | substitute
+ | order
+;
+charmap : DEFN CHAR {
+ strcpy(charmap_table[$2], $1);
+}
+;
+substitute : SUBSTITUTE STRING WITH STRING {
+ strcpy(__collate_substitute_table[$2[0]], $4);
+}
+;
+order : ORDER order_list {
+ FILE *fp;
+ int ch;
+
+ for (ch = 0; ch < UCHAR_MAX + 1; ch++)
+ if (!__collate_char_pri_table[ch].prim)
+ yyerror("Char 0x%02x not present", ch);
+
+ fp = fopen(out_file, "w");
+ if(!fp)
+ err(EX_UNAVAILABLE, "can't open destination file %s",
+ out_file);
+
+ strcpy(__collate_version, COLLATE_VERSION);
+ fwrite(__collate_version, sizeof(__collate_version), 1, fp);
+ fwrite(__collate_substitute_table, sizeof(__collate_substitute_table), 1, fp);
+ fwrite(__collate_char_pri_table, sizeof(__collate_char_pri_table), 1, fp);
+ fwrite(__collate_chain_pri_table, sizeof(__collate_chain_pri_table), 1, fp);
+ if (fflush(fp))
+ err(EX_UNAVAILABLE, "IO error writting to destination file %s",
+ out_file);
+ fclose(fp);
+#ifdef COLLATE_DEBUG
+ if (debug)
+ collate_print_tables();
+#endif
+ exit(EX_OK);
+}
+;
+order_list : item
+ | order_list ';' item
+;
+item : CHAR {
+ if (__collate_char_pri_table[$1].prim)
+ yyerror("Char 0x%02x duplicated", $1);
+ __collate_char_pri_table[$1].prim = prim_pri++;
+}
+ | CHAIN {
+ if (chain_index >= TABLE_SIZE - 1)
+ yyerror("__collate_chain_pri_table overflow");
+ strcpy(__collate_chain_pri_table[chain_index].str, $1);
+ __collate_chain_pri_table[chain_index++].prim = prim_pri++;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+
+ if ($3 <= $1)
+ yyerror("Illegal range 0x%02x -- 0x%02x", $1, $3);
+
+ for (i = $1; i <= $3; i++) {
+ if (__collate_char_pri_table[(u_char)i].prim)
+ yyerror("Char 0x%02x duplicated", (u_char)i);
+ __collate_char_pri_table[(u_char)i].prim = prim_pri++;
+ }
+}
+ | '{' prim_order_list '}' {
+ prim_pri++;
+}
+ | '(' sec_order_list ')' {
+ prim_pri++;
+ sec_pri = 1;
+}
+;
+prim_order_list : prim_sub_item
+ | prim_order_list ',' prim_sub_item
+;
+sec_order_list : sec_sub_item
+ | sec_order_list ',' sec_sub_item
+;
+prim_sub_item : CHAR {
+ if (__collate_char_pri_table[$1].prim)
+ yyerror("Char 0x%02x duplicated", $1);
+ __collate_char_pri_table[$1].prim = prim_pri;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+
+ if ($3 <= $1)
+ yyerror("Illegal range 0x%02x -- 0x%02x",
+ $1, $3);
+
+ for (i = $1; i <= $3; i++) {
+ if (__collate_char_pri_table[(u_char)i].prim)
+ yyerror("Char 0x%02x duplicated", (u_char)i);
+ __collate_char_pri_table[(u_char)i].prim = prim_pri;
+ }
+}
+ | CHAIN {
+ if (chain_index >= TABLE_SIZE - 1)
+ yyerror("__collate_chain_pri_table overflow");
+ strcpy(__collate_chain_pri_table[chain_index].str, $1);
+ __collate_chain_pri_table[chain_index++].prim = prim_pri;
+}
+;
+sec_sub_item : CHAR {
+ if (__collate_char_pri_table[$1].prim)
+ yyerror("Char 0x%02x duplicated", $1);
+ __collate_char_pri_table[$1].prim = prim_pri;
+ __collate_char_pri_table[$1].sec = sec_pri++;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+
+ if ($3 <= $1)
+ yyerror("Illegal range 0x%02x -- 0x%02x",
+ $1, $3);
+
+ for (i = $1; i <= $3; i++) {
+ if (__collate_char_pri_table[(u_char)i].prim)
+ yyerror("Char 0x%02x duplicated", (u_char)i);
+ __collate_char_pri_table[(u_char)i].prim = prim_pri;
+ __collate_char_pri_table[(u_char)i].sec = sec_pri++;
+ }
+}
+ | CHAIN {
+ if (chain_index >= TABLE_SIZE - 1)
+ yyerror("__collate_chain_pri_table overflow");
+ strcpy(__collate_chain_pri_table[chain_index].str, $1);
+ __collate_chain_pri_table[chain_index].prim = prim_pri;
+ __collate_chain_pri_table[chain_index++].sec = sec_pri++;
+}
+;
+%%
+main(ac, av)
+ char **av;
+{
+ int ch;
+
+#ifdef COLLATE_DEBUG
+ while((ch = getopt(ac, av, ":do:I:")) != EOF) {
+#else
+ while((ch = getopt(ac, av, ":o:I:")) != EOF) {
+#endif
+ switch (ch)
+ {
+#ifdef COLLATE_DEBUG
+ case 'd':
+ debug++;
+ break;
+#endif
+ case 'o':
+ out_file = optarg;
+ break;
+
+ case 'I':
+ strcpy(map_name, optarg);
+ break;
+
+ default:
+ usage();
+ }
+ }
+ ac -= optind;
+ av += optind;
+ if(ac > 0) {
+ if((yyin = fopen(*av, "r")) == 0)
+ err(EX_UNAVAILABLE, "can't open source file %s", *av);
+ }
+ for(ch = 0; ch <= UCHAR_MAX; ch++)
+ __collate_substitute_table[ch][0] = ch;
+ yyparse();
+ return 0;
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: colldef [-o out_file] [-I map_dir] [filename]\n");
+ exit(EX_USAGE);
+}
+
+void yyerror(char *fmt, ...)
+{
+ va_list ap;
+ char msg[128];
+
+ va_start(ap, fmt);
+ vsprintf(msg, fmt, ap);
+ va_end(ap);
+ errx(EX_UNAVAILABLE, "%s near line %d", msg, line_no);
+}
+
+#ifdef COLLATE_DEBUG
+collate_print_tables()
+{
+ int i;
+ struct __collate_st_chain_pri *p2;
+
+ printf("Substitute table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ if (i != *__collate_substitute_table[i])
+ printf("\t'%c' --> \"%s\"\n", i,
+ __collate_substitute_table[i]);
+ printf("Chain priority table:\n");
+ for (p2 = __collate_chain_pri_table; p2->str[0]; p2++)
+ printf("\t\"%s\" : %d %d\n\n", p2->str, p2->prim, p2->sec);
+ printf("Char priority table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
+ __collate_char_pri_table[i].sec);
+}
+#endif
diff --git a/usr.bin/colldef/scan.l b/usr.bin/colldef/scan.l
new file mode 100644
index 0000000..3e7dd6b
--- /dev/null
+++ b/usr.bin/colldef/scan.l
@@ -0,0 +1,293 @@
+%x string name charmap defn nchar subs
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <unistd.h>
+#include <string.h>
+#include <sysexits.h>
+#include "collate.h"
+#include "y.tab.h"
+
+int line_no = 1, save_no;
+u_char buf[STR_LEN], *ptr;
+FILE *map_fp;
+extern char map_name[];
+extern u_char charmap_table[UCHAR_MAX + 1][STR_LEN];
+YY_BUFFER_STATE main_buf, map_buf;
+#ifdef FLEX_DEBUG
+YYSTYPE yylval;
+#endif /* FLEX_DEBUG */
+%}
+%%
+<INITIAL,charmap,nchar,subs>[ \t]+ ;
+<subs>\" { ptr = buf; BEGIN(string); }
+<INITIAL>\< { ptr = buf; BEGIN(name); }
+^#.*\n line_no++;
+^\n line_no++;
+<INITIAL>\\\n line_no++;
+<INITIAL,nchar>\\t { yylval.ch = '\t'; return CHAR; }
+<INITIAL,nchar>\\n { yylval.ch = '\n'; return CHAR; }
+<INITIAL,nchar>\\b { yylval.ch = '\b'; return CHAR; }
+<INITIAL,nchar>\\f { yylval.ch = '\f'; return CHAR; }
+<INITIAL,nchar>\\v { yylval.ch = '\v'; return CHAR; }
+<INITIAL,nchar>\\r { yylval.ch = '\r'; return CHAR; }
+<INITIAL,nchar>\\a { yylval.ch = '\a'; return CHAR; }
+<INITIAL,nchar>\\. { yylval.ch = yytext[1]; return CHAR; }
+<subs>\n {
+ line_no++;
+ BEGIN(INITIAL);
+ return '\n';
+}
+<INITIAL,nchar>\n {
+ line_no++;
+ if (map_fp != NULL) {
+ ptr = buf;
+ BEGIN(defn);
+ }
+ return '\n';
+}
+<INITIAL>[;,{}()] return *yytext;
+<INITIAL>substitute { BEGIN(subs); return SUBSTITUTE; }
+<subs>with return WITH;
+<INITIAL>order return ORDER;
+<INITIAL>charmap BEGIN(charmap);
+<INITIAL>;[ \t]*\.\.\.[ \t]*; return RANGE;
+<INITIAL,nchar>\\[0-7]{3} {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ yylval.ch = (u_char)v;
+ return CHAR;
+}
+<INITIAL,nchar>\\x[0-9a-z]{2} {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ yylval.ch = (u_char)v;
+ return CHAR;
+}
+<INITIAL>[^;,{}() \t\n"<]+ {
+ if(yyleng == 1) {
+ yylval.ch = *yytext;
+ return CHAR;
+ }
+ if(yyleng > STR_LEN - 1)
+ errx(EX_UNAVAILABLE, "chain buffer overflaw near line %u",
+ line_no);
+ strcpy(yylval.str, yytext);
+ return CHAIN;
+}
+<nchar>. {
+ yylval.ch = *yytext;
+ return CHAR;
+}
+<defn>[ \t]+ {
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "map expected near line %u of %s",
+ line_no, map_name);
+ *ptr = '\0';
+ strcpy(yylval.str, buf);
+ BEGIN(nchar);
+ return DEFN;
+}
+<name>\/\/ {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflaw near line %u, character '/'",
+ line_no);
+ *ptr++ = '/';
+}
+<name>\/\> {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflaw near line %u, character '>'",
+ line_no);
+ *ptr++ = '>';
+}
+<string>\\\" {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\"'",
+ line_no);
+ *ptr++ = '"';
+}
+<name>\> {
+ u_int i;
+
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "non-empty name expected near line %u",
+ line_no);
+ *ptr = '\0';
+ for (i = 0; i <= UCHAR_MAX; i++)
+ if (strcmp(charmap_table[i], buf) == 0)
+ goto findit;
+ errx(EX_UNAVAILABLE, "name <%s> not 'charmap'-defined near line %u",
+ buf, line_no);
+ findit:
+ yylval.ch = i;
+ BEGIN(INITIAL);
+ return CHAR;
+}
+<string>\" {
+ *ptr = '\0';
+ strcpy(yylval.str, buf);
+ BEGIN(subs);
+ return STRING;
+}
+<name,defn>. {
+ char *s = (map_fp != NULL) ? map_name : "input";
+
+ if (!isascii(*yytext) || !isprint(*yytext))
+ errx(EX_UNAVAILABLE, "non-ASCII or non-printable character 0x%02x not allowed in the map/name near line %u of %s",
+ *yytext, line_no, s);
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "map/name buffer overflaw near line %u of %s, character '%c'",
+ line_no, s, *yytext);
+ *ptr++ = *yytext;
+}
+<string>\\t {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\t'",
+ line_no);
+ *ptr++ = '\t';
+}
+<string>\\b {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\b'",
+ line_no);
+ *ptr++ = '\b';
+}
+<string>\\f {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\f'",
+ line_no);
+ *ptr++ = '\f';
+}
+<string>\\v {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\v'",
+ line_no);
+ *ptr++ = '\v';
+}
+<string>\\n {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\n'",
+ line_no);
+ *ptr++ = '\n';
+}
+<string>\\r {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\r'",
+ line_no);
+ *ptr++ = '\r';
+}
+<string>\\a {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '\\a'",
+ line_no);
+ *ptr++ = '\a';
+}
+<name,string,defn>\n {
+ char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "unterminated map/name/string near line %u of %s", line_no, s);
+}
+<name,string,nchar><<EOF>> {
+ char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "premature EOF in the name/string/char near line %u of %s", line_no, s);
+}
+<string>\\x[0-9a-f]{2} {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ *ptr++ = (u_char)v;
+}
+<string>\\[0-7]{3} {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ *ptr++ = (u_char)v;
+}
+<string>\\. {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '%c'",
+ line_no, yytext[1]);
+ *ptr++ = yytext[1];
+}
+<string>. {
+ if(ptr >= buf + sizeof(buf) - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflaw near line %u, character '%c'",
+ line_no, *yytext);
+ *ptr++ = *yytext;
+}
+<charmap>[^ \t\n]+ {
+ strcat(map_name, "/");
+ strcat(map_name, yytext);
+ if((map_fp = fopen(map_name, "r")) == NULL)
+ err(EX_UNAVAILABLE, "can't open 'charmap' file %s",
+ map_name);
+ save_no = line_no;
+ line_no = 1;
+ map_buf = yy_new_buffer(map_fp, YY_BUF_SIZE);
+ main_buf = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(map_buf);
+ ptr = buf;
+ BEGIN(defn);
+}
+<charmap>\n {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<charmap><<EOF>> {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<INITIAL,defn><<EOF>> {
+ if(map_fp != NULL) {
+ if (ptr != buf)
+ errx(EX_UNAVAILABLE, "premature EOF in the map near line %u of %s", line_no, map_name);
+ yy_switch_to_buffer(main_buf);
+ yy_delete_buffer(map_buf);
+ fclose(map_fp);
+ map_fp = NULL;
+ line_no = save_no;
+ BEGIN(INITIAL);
+ } else
+ yyterminate();
+}
+%%
+#ifdef FLEX_DEBUG
+main()
+{
+ while(yylex())
+ ;
+ return 0;
+}
+#endif /* FLEX_DEBUG */
diff --git a/usr.bin/colrm/colrm.c b/usr.bin/colrm/colrm.c
index 06f6232..1a50405 100644
--- a/usr.bin/colrm/colrm.c
+++ b/usr.bin/colrm/colrm.c
@@ -29,6 +29,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: colrm.c,v 1.3 1997/06/26 11:26:20 charnier Exp $
*/
#ifndef lint
@@ -43,6 +45,7 @@ static char sccsid[] = "@(#)colrm.c 8.2 (Berkeley) 5/4/95";
#include <sys/types.h>
#include <limits.h>
+#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -51,9 +54,8 @@ static char sccsid[] = "@(#)colrm.c 8.2 (Berkeley) 5/4/95";
#define TAB 8
-void err __P((const char *, ...));
void check __P((FILE *));
-void usage __P((void));
+static void usage __P((void));
int
main(argc, argv)
@@ -64,7 +66,7 @@ main(argc, argv)
register int ch;
char *p;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
@@ -78,12 +80,12 @@ main(argc, argv)
case 2:
stop = strtol(argv[1], &p, 10);
if (stop <= 0 || *p)
- err("illegal column -- %s", argv[1]);
+ errx(1, "illegal column -- %s", argv[1]);
/* FALLTHROUGH */
case 1:
start = strtol(argv[0], &p, 10);
if (start <= 0 || *p)
- err("illegal column -- %s", argv[0]);
+ errx(1, "illegal column -- %s", argv[0]);
break;
case 0:
break;
@@ -92,7 +94,7 @@ main(argc, argv)
}
if (stop && start > stop)
- err("illegal start and stop columns");
+ errx(1, "illegal start and stop columns");
for (column = 0;;) {
switch (ch = getchar()) {
@@ -127,8 +129,7 @@ check(stream)
if (feof(stream))
exit(0);
if (ferror(stream))
- err("%s: %s",
- stream == stdin ? "stdin" : "stdout", strerror(errno));
+ err(1, "%s", stream == stdin ? "stdin" : "stdout");
}
void
@@ -138,31 +139,3 @@ usage()
exit(1);
}
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "colrm: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- exit(1);
- /* NOTREACHED */
-}
diff --git a/usr.bin/column/column.c b/usr.bin/column/column.c
index 5dbab1c..cf8c7a9 100644
--- a/usr.bin/column/column.c
+++ b/usr.bin/column/column.c
@@ -85,7 +85,7 @@ main(argc, argv)
termwidth = win.ws_col;
tflag = xflag = 0;
- while ((ch = getopt(argc, argv, "c:s:tx")) != EOF)
+ while ((ch = getopt(argc, argv, "c:s:tx")) != -1)
switch(ch) {
case 'c':
termwidth = atoi(optarg);
@@ -300,6 +300,6 @@ usage()
{
(void)fprintf(stderr,
- "usage: column [-tx] [-c columns] [file ...]\n");
+ "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
exit(1);
}
diff --git a/usr.bin/comm/comm.1 b/usr.bin/comm/comm.1
index 0897430..72ee36f 100644
--- a/usr.bin/comm/comm.1
+++ b/usr.bin/comm/comm.1
@@ -80,7 +80,7 @@ printed in column number three will have one.
.Nm Comm
assumes that the files are lexically sorted; all characters
participate in line comparisons.
-.Pp
+.Sh DIAGNOSTICS
.Nm Comm
exits 0 on success, >0 if an error occurred.
.Sh SEE ALSO
@@ -91,4 +91,5 @@ exits 0 on success, >0 if an error occurred.
.Sh STANDARDS
The
.Nm comm
-command is expected to be POSIX 1003.2 compatible.
+utility conforms to
+.St -p1003.2-92 .
diff --git a/usr.bin/comm/comm.c b/usr.bin/comm/comm.c
index 82f995f..46707bb 100644
--- a/usr.bin/comm/comm.c
+++ b/usr.bin/comm/comm.c
@@ -44,9 +44,9 @@ static char copyright[] =
static char sccsid[] = "@(#)comm.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
-#include <fcntl.h>
-#include <limits.h>
+#include <err.h>
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -58,7 +58,7 @@ char *tabs[] = { "", "\t", "\t\t" };
FILE *file __P((char *));
void show __P((FILE *, char *, char *));
-void usage __P((void));
+static void usage __P((void));
int
main(argc, argv)
@@ -72,7 +72,7 @@ main(argc, argv)
char **p, line1[MAXLINELEN], line2[MAXLINELEN];
flag1 = flag2 = flag3 = 1;
- while ((ch = getopt(argc, argv, "-123")) != EOF)
+ while ((ch = getopt(argc, argv, "-123")) != -1)
switch(ch) {
case '-':
--optind;
@@ -172,16 +172,14 @@ file(name)
if (!strcmp(name, "-"))
return (stdin);
if ((fp = fopen(name, "r")) == NULL) {
- (void)fprintf(stderr, "comm: %s: %s\n", name, strerror(errno));
- exit(1);
+ err(1, "%s", name);
}
return (fp);
}
-void
+static void
usage()
{
-
(void)fprintf(stderr, "usage: comm [-123] file1 file2\n");
exit(1);
}
diff --git a/usr.bin/compile_et/Makefile b/usr.bin/compile_et/Makefile
new file mode 100644
index 0000000..f75572a
--- /dev/null
+++ b/usr.bin/compile_et/Makefile
@@ -0,0 +1,17 @@
+# $Id$
+
+PROG= compile_et
+SRCS= compile_et.c error_table.y
+CFLAGS+= -I. -I${.CURDIR}/../../lib/libcom_err
+CLEANFILES+= et_lex.lex.c y.tab.h
+DPADD+= ${LIBL}
+LDADD+= -ll
+
+beforedepend: et_lex.lex.c
+error_table.o: et_lex.lex.c
+
+.l.c:
+ ${LEX} -l -t ${.IMPSRC} > ${.TARGET}
+
+.include <bsd.prog.mk>
+
diff --git a/usr.bin/compile_et/compile_et.1 b/usr.bin/compile_et/compile_et.1
new file mode 100644
index 0000000..e5cef6a
--- /dev/null
+++ b/usr.bin/compile_et/compile_et.1
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1988 Massachusetts Institute of Technology,
+.\" Student Information Processing Board. All rights reserved.
+.\"
+.\" $Header: /home/ncvs/src/usr.bin/compile_et/compile_et.1,v 1.1 1995/01/14 22:29:30 wollman Exp $
+.\"
+.Dd November 22, 1988
+.Os
+.Dt COMPILE_ET 1
+.Sh NAME
+.Nm compile_et
+.Nd error table compiler
+.Sh SYNOPSIS
+.Nm compile_et
+.Ar file
+.Sh DESCRIPTION
+.Nm Compile_et
+converts a table listing error-code names and associated messages into
+a C source file suitable for use with the
+.Xr com_err 3
+library.
+.Pp
+The source file name must end with a suffix of ``.et''; the file
+consists of a declaration supplying the name (up to four characters
+long) of the error-code table:
+
+.Em error_table name
+
+followed by up to 256 entries of the form:
+
+.Em error_code name ,
+"
+.Em string
+"
+
+and a final
+
+.Em end
+
+to indicate the end of the table.
+.Pp
+The name of the table is used to construct the name of a subroutine
+.Em initialize_XXXX_error_table
+which must be called in order for the
+.Xr com_err 3
+library to recognize the error table.
+.Pp
+The various error codes defined are assigned sequentially increasing
+numbers (starting with a large number computed as a hash function of
+the name of the table); thus for compatibility it is suggested that
+new codes be added only to the end of an existing table, and that no
+codes be removed from tables.
+.Pp
+The names defined in the table are placed into a C header file with
+preprocessor directives defining them as integer constants of up to
+32 bits in magnitude.
+.Pp
+A C source file is also generated which should be compiled and linked
+with the object files which reference these error codes; it contains
+the text of the messages and the initialization subroutine. Both C
+files have names derived from that of the original source file, with
+the ``.et'' suffix replaced by ``.c'' and ``.h''.
+.Pp
+A ``#'' in the source file is treated as a comment character, and all
+remaining text to the end of the source line will be ignored.
+.Sh BUGS
+Since
+.Nm compile_et
+uses a very simple parser based on
+.Xr yacc 1 ,
+its error recovery leaves much to be desired.
+.Sh "SEE ALSO"
+.Xr yacc 1 ,
+.Xr com_err 3
+.Pp
+.Rs
+.%A Ken Raeburn
+.%T "A Common Error Description Library for UNIX"
+.Re
diff --git a/usr.bin/compile_et/compile_et.c b/usr.bin/compile_et/compile_et.c
new file mode 100644
index 0000000..055a9b6
--- /dev/null
+++ b/usr.bin/compile_et/compile_et.c
@@ -0,0 +1,276 @@
+/*
+ *
+ * Copyright 1986, 1987, 1988
+ * by MIT Student Information Processing Board.
+ *
+ * For copyright info, see "mit-sipb-copyright.h".
+ *
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include "mit-sipb-copyright.h"
+#include "compiler.h"
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifndef lint
+static const char copyright[] =
+ "Copyright 1987,1988 by MIT Student Information Processing Board";
+
+static const char rcsid_compile_et_c[] =
+ "$Header: /home/ncvs/src/usr.bin/compile_et/compile_et.c,v 1.3 1996/07/12 19:05:17 jkh Exp $";
+#endif
+
+extern char *gensym();
+extern char *current_token;
+extern int table_number, current;
+char buffer[BUFSIZ];
+char *table_name = (char *)NULL;
+FILE *hfile, *cfile;
+
+/* lex stuff */
+extern FILE *yyin;
+extern int yylineno;
+
+char * xmalloc (size) unsigned int size; {
+ char * p = malloc (size);
+ if (!p)
+ err(1, NULL);
+ return p;
+}
+
+static int check_arg (str_list, arg) char const *const *str_list, *arg; {
+ while (*str_list)
+ if (!strcmp(arg, *str_list++))
+ return 1;
+ return 0;
+}
+
+static const char *const debug_args[] = {
+ "d",
+ "debug",
+ 0,
+};
+
+static const char *const lang_args[] = {
+ "lang",
+ "language",
+ 0,
+};
+
+static const char *const language_names[] = {
+ "C",
+ "K&R C",
+ "C++",
+ 0,
+};
+
+static const char * const c_src_prolog[] = {
+ "static const char * const text[] = {\n",
+ 0,
+};
+
+static const char * const krc_src_prolog[] = {
+ "#ifdef __STDC__\n",
+ "#define NOARGS void\n",
+ "#else\n",
+ "#define NOARGS\n",
+ "#define const\n",
+ "#endif\n\n",
+ "static const char * const text[] = {\n",
+ 0,
+};
+
+static const char *const struct_def[] = {
+ "struct error_table {\n",
+ " char const * const * msgs;\n",
+ " long base;\n",
+ " int n_msgs;\n",
+ "};\n",
+ "struct et_list {\n",
+ " struct et_list *next;\n",
+ " const struct error_table * table;\n",
+ "};\n",
+ "extern struct et_list *_et_list;\n",
+ "\n", 0,
+};
+
+static const char warning[] =
+ "/*\n * %s:\n * This file is automatically generated; please do not edit it.\n */\n";
+
+/* pathnames */
+char c_file[MAXPATHLEN]; /* output file */
+char h_file[MAXPATHLEN]; /* output */
+
+static void usage () {
+ fprintf (stderr, "usage: compile_et ERROR_TABLE\n");
+ exit (1);
+}
+
+static void dup_err (type, one, two) char const *type, *one, *two; {
+ warnx("multiple %s specified: `%s' and `%s'", type, one, two);
+ usage ();
+}
+
+int main (argc, argv) int argc; char **argv; {
+ char *p, *ename;
+ int len;
+ char const * const *cpp;
+ int got_language = 0;
+
+ /* argument parsing */
+ debug = 0;
+ filename = 0;
+ while (argv++, --argc) {
+ char *arg = *argv;
+ if (arg[0] != '-') {
+ if (filename)
+ dup_err ("filenames", filename, arg);
+ filename = arg;
+ }
+ else {
+ arg++;
+ if (check_arg (debug_args, arg))
+ debug++;
+ else if (check_arg (lang_args, arg)) {
+ got_language++;
+ arg = *++argv, argc--;
+ if (!arg)
+ usage ();
+ if (language)
+ dup_err ("languages", language_names[(int)language], arg);
+#define check_lang(x,v) else if (!strcasecmp(arg,x)) language = v
+ check_lang ("c", lang_C);
+ check_lang ("ansi_c", lang_C);
+ check_lang ("ansi-c", lang_C);
+ check_lang ("krc", lang_KRC);
+ check_lang ("kr_c", lang_KRC);
+ check_lang ("kr-c", lang_KRC);
+ check_lang ("k&r-c", lang_KRC);
+ check_lang ("k&r_c", lang_KRC);
+ check_lang ("c++", lang_CPP);
+ check_lang ("cplusplus", lang_CPP);
+ check_lang ("c-plus-plus", lang_CPP);
+#undef check_lang
+ else {
+ errx(1, "unknown language name `%s'\n\tpick one of: C K&R-C", arg);
+ }
+ }
+ else {
+ warnx("unknown control argument -`%s'", arg);
+ usage ();
+ }
+ }
+ }
+ if (!filename)
+ usage ();
+ if (!got_language)
+ language = lang_KRC;
+ else if (language == lang_CPP) {
+ errx(1, "sorry, C++ support is not yet finished");
+ }
+
+ p = xmalloc (strlen (filename) + 5);
+ strcpy (p, filename);
+ filename = p;
+ p = strrchr(filename, '/');
+ if (p == (char *)NULL)
+ p = filename;
+ else
+ p++;
+ ename = p;
+ len = strlen (ename);
+ p += len - 3;
+ if (strcmp (p, ".et"))
+ p += 3;
+ *p++ = '.';
+ /* now p points to where "et" suffix should start */
+ /* generate new filenames */
+ strcpy (p, "c");
+ strcpy (c_file, ename);
+ *p = 'h';
+ strcpy (h_file, ename);
+ strcpy (p, "et");
+
+ yyin = fopen(filename, "r");
+ if (!yyin) {
+ perror(filename);
+ exit(1);
+ }
+
+ hfile = fopen(h_file, "w");
+ if (hfile == (FILE *)NULL) {
+ perror(h_file);
+ exit(1);
+ }
+ fprintf (hfile, warning, h_file);
+
+ cfile = fopen(c_file, "w");
+ if (cfile == (FILE *)NULL) {
+ perror(c_file);
+ exit(1);
+ }
+ fprintf (cfile, warning, c_file);
+
+ /* prologue */
+ if (language == lang_C)
+ cpp = c_src_prolog;
+ else if (language == lang_KRC)
+ cpp = krc_src_prolog;
+ else
+ abort ();
+ while (*cpp)
+ fputs (*cpp++, cfile);
+
+ /* parse it */
+ yyparse();
+ fclose(yyin); /* bye bye input file */
+
+ fputs (" 0\n};\n\n", cfile);
+ for (cpp = struct_def; *cpp; cpp++)
+ fputs (*cpp, cfile);
+ fprintf(cfile,
+ "static const struct error_table et = { text, %dL, %d };\n\n",
+ table_number, current);
+ fputs("static struct et_list link = { 0, 0 };\n\n",
+ cfile);
+ fprintf(cfile, "void initialize_%s_error_table (%s) {\n",
+ table_name, (language == lang_C) ? "void" : "NOARGS");
+ fputs(" if (!link.table) {\n", cfile);
+ fputs(" link.next = _et_list;\n", cfile);
+ fputs(" link.table = &et;\n", cfile);
+ fputs(" _et_list = &link;\n", cfile);
+ fputs(" }\n", cfile);
+ fputs("}\n", cfile);
+ fclose(cfile);
+
+ fprintf (hfile, "extern void initialize_%s_error_table ();\n",
+ table_name);
+ fprintf (hfile, "#define ERROR_TABLE_BASE_%s (%dL)\n",
+ table_name, table_number);
+ /* compatibility... */
+ fprintf (hfile, "\n/* for compatibility with older versions... */\n");
+ fprintf (hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
+ table_name, table_name);
+ fprintf (hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n", table_name,
+ table_name);
+ fclose(hfile); /* bye bye include file */
+
+ return 0;
+}
+
+int yyerror(s) char *s; {
+ fputs(s, stderr);
+ fprintf(stderr, "\nLine number %d; last token was '%s'\n",
+ yylineno, current_token);
+ return 0;
+}
+
diff --git a/usr.bin/compile_et/compiler.h b/usr.bin/compile_et/compiler.h
new file mode 100644
index 0000000..3bf568d
--- /dev/null
+++ b/usr.bin/compile_et/compiler.h
@@ -0,0 +1,19 @@
+/*
+ * definitions common to the source files of the error table compiler
+ */
+
+#ifndef __STDC__
+/* loser */
+#undef const
+#define const
+#endif
+
+enum lang {
+ lang_C, /* ANSI C (default) */
+ lang_KRC, /* C: ANSI + K&R */
+ lang_CPP /* C++ */
+};
+
+int debug; /* dump debugging info? */
+char *filename; /* error table source */
+enum lang language;
diff --git a/usr.bin/compile_et/error_table.y b/usr.bin/compile_et/error_table.y
new file mode 100644
index 0000000..c29db13
--- /dev/null
+++ b/usr.bin/compile_et/error_table.y
@@ -0,0 +1,237 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+char *str_concat(), *ds(), *quote();
+char *current_token = (char *)NULL;
+extern char *table_name;
+%}
+%union {
+ char *dynstr;
+}
+
+%token ERROR_TABLE ERROR_CODE_ENTRY END
+%token <dynstr> STRING QUOTED_STRING
+%type <dynstr> ec_name description table_id
+%{
+%}
+%start error_table
+%%
+
+error_table : ERROR_TABLE table_id error_codes END
+ { table_name = ds($2);
+ current_token = table_name;
+ put_ecs(); }
+ ;
+
+table_id : STRING
+ { current_token = $1;
+ set_table_num($1);
+ $$ = $1; }
+ ;
+
+error_codes : error_codes ec_entry
+ | ec_entry
+ ;
+
+ec_entry : ERROR_CODE_ENTRY ec_name ',' description
+ { add_ec($2, $4);
+ free($2);
+ free($4); }
+ | ERROR_CODE_ENTRY ec_name '=' STRING ',' description
+ { add_ec_val($2, $4, $6);
+ free($2);
+ free($4);
+ free($6);
+ }
+ ;
+
+ec_name : STRING
+ { $$ = ds($1);
+ current_token = $$; }
+ ;
+
+description : QUOTED_STRING
+ { $$ = ds($1);
+ current_token = $$; }
+ ;
+
+%%
+/*
+ *
+ * Copyright 1986, 1987 by the MIT Student Information Processing Board
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "internal.h"
+#include "error_table.h"
+#include "mit-sipb-copyright.h"
+
+#ifndef lint
+static char const rcsid_error_table_y[] =
+ "$Header: /home/ncvs/src/usr.bin/compile_et/error_table.y,v 1.3 1995/03/15 19:05:28 wpaul Exp $";
+#endif
+
+void *malloc(), *realloc();
+extern FILE *hfile, *cfile;
+
+static long gensym_n = 0;
+char *
+gensym(x)
+ char const *x;
+{
+ char *symbol;
+ if (!gensym_n) {
+ struct timeval tv;
+ struct timezone tzp;
+ gettimeofday(&tv, &tzp);
+ gensym_n = (tv.tv_sec%10000)*100 + tv.tv_usec/10000;
+ }
+ symbol = malloc(32 * sizeof(char));
+ gensym_n++;
+ sprintf(symbol, "et%ld", gensym_n);
+ return(symbol);
+}
+
+char *
+ds(string)
+ char const *string;
+{
+ char *rv;
+ rv = malloc(strlen(string)+1);
+ strcpy(rv, string);
+ return(rv);
+}
+
+char *
+quote(string)
+ char const *string;
+{
+ char *rv;
+ rv = malloc(strlen(string)+3);
+ strcpy(rv, "\"");
+ strcat(rv, string);
+ strcat(rv, "\"");
+ return(rv);
+}
+
+long table_number;
+int current = 0;
+char **error_codes = (char **)NULL;
+
+void
+add_ec(name, description)
+ char const *name, *description;
+{
+ fprintf(cfile, "\t\"%s\",\n", description);
+ if (error_codes == (char **)NULL) {
+ error_codes = (char **)malloc(sizeof(char *));
+ *error_codes = (char *)NULL;
+ }
+ error_codes = (char **)realloc((char *)error_codes,
+ (current + 2)*sizeof(char *));
+ error_codes[current++] = ds(name);
+ error_codes[current] = (char *)NULL;
+}
+
+void
+add_ec_val(name, val, description)
+ char const *name, *val, *description;
+{
+ const int ncurrent = atoi(val);
+ if (ncurrent < current) {
+ printf("Error code %s (%d) out of order", name,
+ current);
+ return;
+ }
+
+ while (ncurrent > current)
+ fputs("\t(char *)NULL,\n", cfile), current++;
+
+ fprintf(cfile, "\t\"%s\",\n", description);
+ if (error_codes == (char **)NULL) {
+ error_codes = (char **)malloc(sizeof(char *));
+ *error_codes = (char *)NULL;
+ }
+ error_codes = (char **)realloc((char *)error_codes,
+ (current + 2)*sizeof(char *));
+ error_codes[current++] = ds(name);
+ error_codes[current] = (char *)NULL;
+}
+
+void
+put_ecs()
+{
+ int i;
+ for (i = 0; i < current; i++) {
+ if (error_codes[i] != (char *)NULL)
+ fprintf(hfile, "#define %-40s (%ldL)\n",
+ error_codes[i], table_number + i);
+ }
+}
+
+/*
+ * char_to_num -- maps letters and numbers into a small numbering space
+ * uppercase -> 1-26
+ * lowercase -> 27-52
+ * digits -> 53-62
+ * underscore-> 63
+ */
+
+static const char char_set[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+int char_to_num(c)
+ char c;
+{
+ const char *where;
+ int diff;
+
+ where = strchr (char_set, c);
+ if (where) {
+ diff = where - char_set + 1;
+ assert (diff < (1 << ERRCODE_RANGE));
+ return diff;
+ }
+ else if (isprint (c))
+ fprintf (stderr,
+ "Illegal character `%c' in error table name\n",
+ c);
+ else
+ fprintf (stderr,
+ "Illegal character %03o in error table name\n",
+ c);
+ exit (1);
+}
+
+void
+set_table_num(string)
+ char *string;
+{
+ if (char_to_num (string[0]) > char_to_num ('z')) {
+ fprintf (stderr, "%s%s%s%s",
+ "First character of error table name must be ",
+ "a letter; name ``",
+ string, "'' rejected\n");
+ exit (1);
+ }
+ if (strlen(string) > 4) {
+ fprintf(stderr, "Table name %s too long, truncated ",
+ string);
+ string[4] = '\0';
+ fprintf(stderr, "to %s\n", string);
+ }
+ while (*string != '\0') {
+ table_number = (table_number << BITS_PER_CHAR)
+ + char_to_num(*string);
+ string++;
+ }
+ table_number = table_number << ERRCODE_RANGE;
+}
+
+#include "et_lex.lex.c"
diff --git a/usr.bin/compile_et/et_lex.lex.l b/usr.bin/compile_et/et_lex.lex.l
new file mode 100644
index 0000000..48d1b89
--- /dev/null
+++ b/usr.bin/compile_et/et_lex.lex.l
@@ -0,0 +1,26 @@
+PC [^\"]
+AN [A-Z_a-z0-9]
+%%
+
+error_table return ERROR_TABLE;
+et return ERROR_TABLE;
+error_code return ERROR_CODE_ENTRY;
+ec return ERROR_CODE_ENTRY;
+end return END;
+
+[\t\n ] ;
+
+\"{PC}*\" { register char *p; yylval.dynstr = ds(yytext+1);
+ if ( (p=rindex(yylval.dynstr, '"')) ) *p='\0';
+ return QUOTED_STRING;
+ }
+
+{AN}* { yylval.dynstr = ds(yytext); return STRING; }
+
+#.*\n ;
+
+. { return (*yytext); }
+%%
+#ifndef lint
+static char rcsid_et_lex_lex_l[] = "$Header: /home/ncvs/src/usr.bin/compile_et/et_lex.lex.l,v 1.2 1995/01/14 22:29:33 wollman Exp $";
+#endif
diff --git a/usr.bin/compile_et/mit-sipb-copyright.h b/usr.bin/compile_et/mit-sipb-copyright.h
new file mode 100644
index 0000000..2f7eb29
--- /dev/null
+++ b/usr.bin/compile_et/mit-sipb-copyright.h
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987, 1988 by the Student Information Processing Board
+ of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/usr.bin/compress/Makefile b/usr.bin/compress/Makefile
index 6a06830..0f6f5dd 100644
--- a/usr.bin/compress/Makefile
+++ b/usr.bin/compress/Makefile
@@ -3,10 +3,9 @@
PROG= compress
SRCS= compress.c zopen.c
LINKS= ${BINDIR}/compress ${BINDIR}/uncompress
-MLINKS= compress.1 uncompress.1 compress.1 zcat.1
+MLINKS= compress.1 uncompress.1
-afterinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/zcat.sh ${DESTDIR}/usr/bin/zcat
+# XXX zopen is not part of libc
+# MAN3=zopen.3
.include <bsd.prog.mk>
diff --git a/usr.bin/compress/compress.1 b/usr.bin/compress/compress.1
index 74b7348..c800269 100644
--- a/usr.bin/compress/compress.1
+++ b/usr.bin/compress/compress.1
@@ -134,7 +134,7 @@ the algorithm to adapt to the next "block" of the file.
The
.Fl b
flag is omitted for
-.Ar uncompress
+.Nm uncompress
since the
.Ar bits
parameter specified during compression
diff --git a/usr.bin/compress/compress.c b/usr.bin/compress/compress.c
index d66d224..32d9496 100644
--- a/usr.bin/compress/compress.c
+++ b/usr.bin/compress/compress.c
@@ -58,6 +58,8 @@ static char sccsid[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94";
#include <varargs.h>
#endif
+#include "zopen.h"
+
void compress __P((char *, char *, int));
void cwarn __P((const char *, ...));
void cwarnx __P((const char *, ...));
@@ -84,13 +86,13 @@ main(argc, argv)
++p;
if (!strcmp(p, "uncompress"))
style = DECOMPRESS;
- else if (!strcmp(p, "compress"))
+ else if (!strcmp(p, "compress"))
style = COMPRESS;
else
errx(1, "unknown program name");
bits = cat = 0;
- while ((ch = getopt(argc, argv, "b:cdfv")) != EOF)
+ while ((ch = getopt(argc, argv, "b:cdfv")) != -1)
switch(ch) {
case 'b':
bits = strtol(optarg, &p, 10);
diff --git a/usr.bin/compress/zopen.3 b/usr.bin/compress/zopen.3
index 853462f..3d70f25 100644
--- a/usr.bin/compress/zopen.3
+++ b/usr.bin/compress/zopen.3
@@ -38,7 +38,7 @@
.Nm zopen
.Nd compressed stream open function
.Sh SYNOPSIS
-.Fd #include <stdio.h>
+.Fd #include "zopen.h"
.Ft FILE *
.Fn zopen "const char *path" "const char *mode" "int bits"
.Sh DESCRIPTION
@@ -130,7 +130,8 @@ or
The
.Nm zopen
function
-first appeared in 4.4BSD.
+first appeared in
+.Bx 4.4 .
.Sh BUGS
The
.Fn zopen
diff --git a/usr.bin/compress/zopen.c b/usr.bin/compress/zopen.c
index b76fca6..5e5357b 100644
--- a/usr.bin/compress/zopen.c
+++ b/usr.bin/compress/zopen.c
@@ -71,6 +71,7 @@ static char sccsid[] = "@(#)zopen.c 8.1 (Berkeley) 6/27/93";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "zopen.h"
#define BITS 16 /* Default bits. */
#define HSIZE 69001 /* 95% occupancy */
@@ -254,11 +255,11 @@ zwrite(cookie, wbp, num)
goto middle;
state = S_MIDDLE;
- maxmaxcode = 1L << BITS;
+ maxmaxcode = 1L << maxbits;
if (fwrite(magic_header,
sizeof(char), sizeof(magic_header), fp) != sizeof(magic_header))
return (-1);
- tmp = (u_char)(BITS | block_compress);
+ tmp = (u_char)((maxbits) | block_compress);
if (fwrite(&tmp, sizeof(char), sizeof(tmp), fp) != sizeof(tmp))
return (-1);
@@ -707,7 +708,7 @@ zopen(fname, mode, bits)
return (NULL);
maxbits = bits ? bits : BITS; /* User settable max # bits/code. */
- maxmaxcode = 1 << BITS; /* Should NEVER generate this code. */
+ maxmaxcode = 1L << maxbits; /* Should NEVER generate this code. */
hsize = HSIZE; /* For dynamic table sizing. */
free_ent = 0; /* First unused entry. */
block_compress = BLOCK_MASK;
diff --git a/usr.bin/compress/zopen.h b/usr.bin/compress/zopen.h
new file mode 100644
index 0000000..322fd2d
--- /dev/null
+++ b/usr.bin/compress/zopen.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1996
+ * FreeBSD Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FreeBSD Inc. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL [your name] OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef _ZOPEN_H_
+#define _ZOPEN_H_
+
+FILE *zopen __P((const char *, const char *, int));
+
+#endif /* _ZOPEN_H_ */
diff --git a/usr.bin/cpp/Makefile b/usr.bin/cpp/Makefile
index 645fb42..95cf0b1 100644
--- a/usr.bin/cpp/Makefile
+++ b/usr.bin/cpp/Makefile
@@ -7,11 +7,11 @@ all nologin clean cleandir depend lint tags:
beforeinstall:
.if ${MACHINE} == "sparc"
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/cpp.notraditional.sh ${DESTDIR}/usr/bin/cpp
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/cpp.notraditional.sh ${DESTDIR}${BINDIR}/cpp
.else
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/cpp.sh ${DESTDIR}/usr/bin/cpp
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/cpp.sh ${DESTDIR}${BINDIR}/cpp
.endif
.include <bsd.prog.mk>
diff --git a/usr.bin/cpp/cpp.notraditional.sh b/usr.bin/cpp/cpp.notraditional.sh
index b30624c..7ed43f0 100644
--- a/usr.bin/cpp/cpp.notraditional.sh
+++ b/usr.bin/cpp/cpp.notraditional.sh
@@ -43,7 +43,7 @@
#
PATH=/usr/bin:/bin
CPP=/usr/libexec/gcc2/cpp
-ALST="-D__GNUC__ -$ "
+ALST="-D__GNUC__=2 -$ "
NSI=no
OPTS=""
INCS="-nostdinc"
@@ -61,7 +61,7 @@ do
INCS="$INCS $A"
;;
-U__GNUC__)
- ALST=`echo $ALST | sed -e 's/-D__GNUC__//'`
+ ALST=`echo $ALST | sed -e 's/-D__GNUC__=2//'`
;;
-*)
OPTS="$OPTS '$A'"
diff --git a/usr.bin/cpp/cpp.sh b/usr.bin/cpp/cpp.sh
index 08496ab..df09d6d 100644
--- a/usr.bin/cpp/cpp.sh
+++ b/usr.bin/cpp/cpp.sh
@@ -35,15 +35,16 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# @(#)cpp.sh 8.1 (Berkeley) 6/6/93
+# From: @(#)cpp.sh 8.1 (Berkeley) 6/6/93
+# $Id$
#
# Transitional front end to CCCP to make it behave like (Reiser) CCP:
# specifies -traditional
# doesn't search gcc-include
#
PATH=/usr/bin:/bin
-CPP=/usr/libexec/gcc2/cpp
-ALST="-traditional -D__GNUC__ -$ "
+CPP=/usr/libexec/cpp
+ALST="-traditional -D__GNUC__=2 -$ "
NSI=no
OPTS=""
INCS="-nostdinc"
@@ -61,7 +62,7 @@ do
INCS="$INCS $A"
;;
-U__GNUC__)
- ALST=`echo $ALST | sed -e 's/-D__GNUC__//'`
+ ALST=`echo $ALST | sed -e 's/-D__GNUC__=2//'`
;;
-*)
OPTS="$OPTS '$A'"
diff --git a/usr.bin/ctags/ctags.c b/usr.bin/ctags/ctags.c
index 64f7c93..725dfb5 100644
--- a/usr.bin/ctags/ctags.c
+++ b/usr.bin/ctags/ctags.c
@@ -77,6 +77,7 @@ char lbuf[LINE_MAX];
void init __P((void));
void find_entries __P((char *));
+static void usage __P((void));
int
main(argc, argv)
@@ -92,7 +93,7 @@ main(argc, argv)
char cmd[100]; /* too ugly to explain */
aflag = uflag = NO;
- while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != EOF)
+ while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
switch(ch) {
case 'B':
searchar = '?';
@@ -125,15 +126,12 @@ main(argc, argv)
break;
case '?':
default:
- goto usage;
+ usage();
}
argv += optind;
argc -= optind;
- if (!argc) {
-usage: (void)fprintf(stderr,
- "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
- exit(1);
- }
+ if (!argc)
+ usage();
init();
@@ -175,6 +173,13 @@ usage: (void)fprintf(stderr,
exit(exit_val);
}
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
+ exit(1);
+}
+
/*
* init --
* this routine sets up the boolean psuedo-functions which work by
diff --git a/usr.bin/cut/cut.1 b/usr.bin/cut/cut.1
index 97c5645..3ba43ed 100644
--- a/usr.bin/cut/cut.1
+++ b/usr.bin/cut/cut.1
@@ -46,7 +46,7 @@
.Ar
.Nm cut
.Fl f Ar list
-.Op Fl d Ar string
+.Op Fl d Ar delim
.Op Fl s
.Ar
.Sh DESCRIPTION
@@ -85,9 +85,9 @@ The options are as follows:
The
.Ar list
specifies character positions.
-.It Fl d Ar string
+.It Fl d Ar delim
Use the first character of
-.Ar string
+.Ar delim
as the field delimiter character instead of the tab character.
.It Fl f Ar list
The
diff --git a/usr.bin/cut/cut.c b/usr.bin/cut/cut.c
index 15e1524..cc57685 100644
--- a/usr.bin/cut/cut.c
+++ b/usr.bin/cut/cut.c
@@ -45,6 +45,7 @@ static char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95";
#endif /* not lint */
#include <ctype.h>
+#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@@ -59,10 +60,9 @@ int fflag;
int sflag;
void c_cut __P((FILE *, char *));
-void err __P((const char *, ...));
void f_cut __P((FILE *, char *));
void get_list __P((char *));
-void usage __P((void));
+static void usage __P((void));
int
main(argc, argv)
@@ -75,7 +75,7 @@ main(argc, argv)
dchar = '\t'; /* default delimiter is \t */
- while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF)
+ while ((ch = getopt(argc, argv, "c:d:f:s")) != -1)
switch(ch) {
case 'c':
fcn = c_cut;
@@ -110,7 +110,7 @@ main(argc, argv)
if (*argv)
for (; *argv; ++argv) {
if (!(fp = fopen(*argv, "r")))
- err("%s: %s\n", *argv, strerror(errno));
+ err(1, "%s", *argv);
fcn(fp, *argv);
(void)fclose(fp);
}
@@ -160,11 +160,11 @@ get_list(list)
}
}
if (*p)
- err("[-cf] list: illegal list value\n");
+ errx(1, "[-cf] list: illegal list value");
if (!stop || !start)
- err("[-cf] list: values may not include zero\n");
+ errx(1, "[-cf] list: values may not include zero");
if (stop > _POSIX2_LINE_MAX)
- err("[-cf] list: %d too large (max %d)\n",
+ errx(1, "[-cf] list: %d too large (max %d)",
stop, _POSIX2_LINE_MAX);
if (maxval < stop)
maxval = stop;
@@ -223,7 +223,7 @@ f_cut(fp, fname)
output = 0;
for (isdelim = 0, p = lbuf;; ++p) {
if (!(ch = *p))
- err("%s: line too long.\n", fname);
+ errx(1, "%s: line too long", fname);
/* this should work if newline is delimiter */
if (ch == sep)
isdelim = 1;
@@ -260,39 +260,11 @@ f_cut(fp, fname)
}
}
-void
+static void
usage()
{
- (void)fprintf(stderr,
-"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n");
- exit(1);
-}
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "cut: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: cut -c list [file1 ...]",
+ " cut -f list [-s] [-d delim] [file ...]");
exit(1);
- /* NOTREACHED */
}
diff --git a/usr.bin/dig/Makefile b/usr.bin/dig/Makefile
new file mode 100644
index 0000000..4ff062e
--- /dev/null
+++ b/usr.bin/dig/Makefile
@@ -0,0 +1,12 @@
+# $Id$
+
+.include "${.CURDIR}/../../usr.sbin/named/Makefile.inc"
+
+.PATH: ${BIND_DIR}/tools
+.PATH: ${BIND_DIR}/tools/nslookup
+.PATH: ${BIND_DIR}/man
+
+PROG= dig
+SRCS= dig.c list.c subr.c debug.c send.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/dirname/dirname.c b/usr.bin/dirname/dirname.c
index ca0caf0..c6ca326 100644
--- a/usr.bin/dirname/dirname.c
+++ b/usr.bin/dirname/dirname.c
@@ -55,7 +55,7 @@ main(argc, argv)
char *p;
int ch;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
@@ -117,7 +117,7 @@ main(argc, argv)
*
* This case has already been handled, as part of steps (1) and (2).
*/
-
+
/*
* (7) If there are any trailing slash characters in string, they
* shall be removed.
diff --git a/usr.bin/dnsquery/Makefile b/usr.bin/dnsquery/Makefile
new file mode 100644
index 0000000..1be409a
--- /dev/null
+++ b/usr.bin/dnsquery/Makefile
@@ -0,0 +1,10 @@
+# $Id$
+
+.include "${.CURDIR}/../../usr.sbin/named/Makefile.inc"
+
+.PATH: ${BIND_DIR}/tools
+.PATH: ${BIND_DIR}/man
+
+PROG= dnsquery
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/du/du.1 b/usr.bin/du/du.1
index 4ecce8e..e84a710 100644
--- a/usr.bin/du/du.1
+++ b/usr.bin/du/du.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)du.1 8.2 (Berkeley) 4/1/94
+.\" $Id: du.1,v 1.8 1997/02/22 19:54:52 peter Exp $
.\"
.Dd April 1, 1994
.Dt DU 1
@@ -40,7 +41,8 @@
.Sh SYNOPSIS
.Nm du
.Op Fl H | Fl L | Fl P
-.Op Fl a | Fl s
+.Op Fl a | s | d Ar depth
+.Op Fl k
.Op Fl x
.Op Ar file ...
.Sh DESCRIPTION
@@ -54,6 +56,10 @@ the current directory is displayed.
The number of blocks are in the same units as that returned by the
.Xr stat 2
system call, i.e. 512-byte blocks.
+If the
+.Fl k
+flag is specified, the number displayed is the number of 1024-byte
+blocks.
Partial numbers of blocks are rounded up.
.Pp
The options are as follows:
@@ -67,6 +73,15 @@ All symbolic links are followed.
No symbolic links are followed.
.It Fl a
Display an entry for each file in the file hierarchy.
+.It Fl d Ar depth
+Displays all directories only
+.Ar depth
+directories deep.
+.It Fl k
+Report in 1024-byte (1-Kbyte) blocks rather than the default. Note that
+this overrides the
+.Ev BLOCKSIZE
+setting from the environment.
.It Fl s
Display only the grand total for the specified files.
.It Fl x
@@ -98,12 +113,15 @@ Files having multiple hard links are counted (and displayed) a single
time per
.Nm du
execution.
-.Sh ENVIRONMENTAL VARIABLES
+.Sh ENVIRONMENT VARIABLES
.Bl -tag -width BLOCKSIZE
.It Ev BLOCKSIZE
-If the environmental variable
+If the environment variable
.Ev BLOCKSIZE
-is set, the block counts will be displayed in units of that size block.
+is set, and the
+.Fl k
+option is not specified, the block counts will be displayed in units of that
+size block.
.El
.Sh SEE ALSO
.Xr df 1 ,
@@ -114,4 +132,4 @@ is set, the block counts will be displayed in units of that size block.
A
.Nm du
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/du/du.c b/usr.bin/du/du.c
index 173ea63..995860b 100644
--- a/usr.bin/du/du.c
+++ b/usr.bin/du/du.c
@@ -57,7 +57,7 @@ static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
#include <unistd.h>
int linkchk __P((FTSENT *));
-void usage __P((void));
+static void usage __P((void));
int
main(argc, argv)
@@ -67,14 +67,15 @@ main(argc, argv)
FTS *fts;
FTSENT *p;
long blocksize;
- int ftsoptions, listdirs, listfiles;
- int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag;
+ int ftsoptions, listdirs, listfiles, depth;
+ int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag, dflag;
char **save;
save = argv;
- Hflag = Lflag = Pflag = aflag = sflag = 0;
+ Hflag = Lflag = Pflag = aflag = sflag = dflag = 0;
+ depth = INT_MAX;
ftsoptions = FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "HLPasx")) != EOF)
+ while ((ch = getopt(argc, argv, "HLPad:ksx")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@@ -91,12 +92,23 @@ main(argc, argv)
case 'a':
aflag = 1;
break;
+ case 'k':
+ putenv("BLOCKSIZE=1024");
+ break;
case 's':
sflag = 1;
break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
+ case 'd':
+ dflag = 1;
+ depth=atoi(optarg);
+ if(errno == ERANGE) {
+ (void)fprintf(stderr, "Invalid argument to option d: %s", optarg);
+ usage();
+ }
+ break;
case '?':
default:
usage();
@@ -124,12 +136,17 @@ main(argc, argv)
}
if (aflag) {
- if (sflag)
+ if (sflag || dflag)
usage();
listdirs = listfiles = 1;
- } else if (sflag)
+ } else if (sflag) {
+ if (dflag)
+ usage();
listdirs = listfiles = 0;
- else {
+ } else if (dflag) {
+ listfiles = 0;
+ listdirs = 1;
+ } else {
listfiles = 0;
listdirs = 1;
}
@@ -151,14 +168,15 @@ main(argc, argv)
case FTS_D: /* Ignore. */
break;
case FTS_DP:
- p->fts_parent->fts_number +=
+ p->fts_parent->fts_number +=
p->fts_number += p->fts_statp->st_blocks;
/*
* If listing each directory, or not listing files
* or directories and this is post-order of the
* root of a traversal, display the total.
*/
- if (listdirs || !listfiles && !p->fts_level)
+ if ((p->fts_level <= depth && listdirs) ||
+ (!listfiles && !p->fts_level))
(void)printf("%ld\t%s\n",
howmany(p->fts_number, blocksize),
p->fts_path);
@@ -213,18 +231,17 @@ linkchk(p)
if (nfiles == maxfiles && (files = realloc((char *)files,
(u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
- err(1, "");
+ err(1, "can't allocate memory");
files[nfiles].inode = ino;
files[nfiles].dev = dev;
++nfiles;
return (0);
}
-void
+static void
usage()
{
-
(void)fprintf(stderr,
- "usage: du [-H | -L | -P] [-a | -s] [-x] [file ...]\n");
+ "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n");
exit(1);
}
diff --git a/usr.bin/ee/Artistic b/usr.bin/ee/Artistic
new file mode 100644
index 0000000..fbf7989
--- /dev/null
+++ b/usr.bin/ee/Artistic
@@ -0,0 +1,117 @@
+
+
+
+
+ The "Artistic License"
+
+ Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on. (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder. A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or
+ an equivalent medium, or placing the modifications on a major archive
+ site such as uunet.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and provide
+ a separate manual page for each non-standard executable that clearly
+ documents how it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of
+ the Package with your modifications.
+
+ c) accompany any non-standard executables with their corresponding
+ Standard Version executables, giving the non-standard executables
+ non-standard names, and clearly documenting the differences in manual
+ pages (or equivalent), together with instructions on where to get
+ the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this Package.
+You may not charge a fee for this Package itself. However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whomever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.
+
+7. C subroutines supplied by you and linked into this Package in order
+to emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
diff --git a/usr.bin/ee/Makefile b/usr.bin/ee/Makefile
new file mode 100644
index 0000000..ff64348
--- /dev/null
+++ b/usr.bin/ee/Makefile
@@ -0,0 +1,27 @@
+CFLAGS+= -DCAP -DHAS_NCURSES -DHAS_UNISTD -DHAS_STDARG -DHAS_STDLIB \
+ -DHAS_CTYPE -DHAS_SYS_IOCTL -DHAS_SYS_WAIT -DSLCT_HDR
+
+PROG= ee
+LINKS= ${BINDIR}/ee ${BINDIR}/ree
+MLINKS= ee.1 ree.1
+DPADD= ${LIBNCURSES} ${LIBMYTINFO}
+LDADD= -lncurses -lmytinfo
+
+LANGS= en_US.ISO_8859-1 fr_FR.ISO_8859-1 de_DE.ISO_8859-1
+FILES= ${LANGS:S/$/.ee.cat/}
+CLEANFILES+= ${FILES}
+
+all: ${FILES}
+
+.for lang in ${LANGS}
+${lang}.ee.cat: ${.CURDIR}/nls/${lang}/ee.msg
+ gencat -new ${.TARGET} ${.ALLSRC}
+.endfor
+
+beforeinstall:
+.for lang in ${LANGS}
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${NOBINMODE} \
+ ${lang}.ee.cat ${DESTDIR}${NLSDIR}/${lang}/ee.cat
+.endfor
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ee/README b/usr.bin/ee/README
new file mode 100644
index 0000000..e150700
--- /dev/null
+++ b/usr.bin/ee/README
@@ -0,0 +1,116 @@
+ THIS MATERIAL IS PROVIDED "AS IS". THERE ARE NO WARRANTIES OF
+ ANY KIND WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE. Neither Hewlett-Packard nor
+ Hugh Mahon shall be liable for errors contained herein, nor for
+ incidental or consequential damages in connection with the
+ furnishing, performance or use of this material. Neither
+ Hewlett-Packard nor Hugh Mahon assumes any responsibility for
+ the use or reliability of this software or documentation. This
+ software and documentation is totally UNSUPPORTED. There is no
+ support contract available. Hewlett-Packard has done NO
+ Quality Assurance on ANY of the program or documentation. You
+ may find the quality of the materials inferior to supported
+ materials.
+
+ This software may be distributed under the terms of Larry Wall's
+ Artistic license, a copy of which is included in this distribution.
+ (see doc/Artistic).
+
+ This notice must be included with this software and any
+ derivatives.
+
+ Any modifications to this software by anyone but the original author
+ must be so noted.
+
+
+The editor 'ee' (easy editor) is intended to be a simple, easy to use
+terminal-based screen oriented editor that requires no instruction to
+use. Its primary use would be for people who are new to computers, or who
+use computers only for things like e-mail.
+
+ee's simplified interface is highlighted by the use of pop-up menus which
+make it possible for users to carry out tasks without the need to
+remember commands. An information window at the top of the screen shows
+the user the operations available with control-keys.
+
+ee allows users to use full eight-bit characters. If the host system has
+the capabilities, ee can use message catalogs, which would allow users to
+translate the message catalog into other languages which use eight-bit
+characters. See the file ee.i18n.guide for more details.
+
+ee relies on the virtual memory abilities of the platform it is running on
+and does not have its own memory management capabilities.
+
+I am releasing ee because I hate to see new users and non-computer types
+get frustrated by vi, and would like to see more intuitive interfaces for
+basic tools (both character-based and graphical) become more pervasive.
+Terminal capabilities and communication speeds have evolved considerably
+since the time in which vi's interface was created, allowing much more
+intuitive interfaces to be used. Since character-based I/O won't be
+completely replaced by graphical user interfaces for at least a few more
+years, I'd like to do what I can to make using computers with less
+glamorous interfaces as easy to use as possible. If terminal interfaces
+are still used in ten years, I hope neophytes won't still be stuck with
+only vi.
+
+For a text editor to be easy to use requires a certain set of abilities. In
+order for ee to work, a terminal must have the ability to position the cursor
+on the screen, and should have arrow keys that send unique sequences
+(multiple characters, the first character is an "escape", octal code
+'\033'). All of this information needs to be in a database called "terminfo"
+(System V implementations) or "termcap" (usually used for BSD systems). In
+case the arrow keys do not transmit unique sequences, motion operations are
+mapped to control keys as well, but this at least partially defeats the
+purpose. The curses package is used to handle the I/O which deals with the
+terminal's capabilities.
+
+While ee is based on curses, I have included here the source code to
+new_curse, a subset of curses developed for use with ee. 'curses' often
+will have a defect that reduces the usefulness of the editor relying upon
+it. This is unused by the FreeBSD version of ee (the existing ncurses
+library works just fine) but is included in the doc subdirectory for
+reference purposes should anyone wish to port ee to a platform for
+which the existing curses libraries are insufficient.
+
+The files doc/new_curse.[ch] contain a subset of the 'curses' library
+used by applications to handle screen output. Unfortunately, curses
+varies from system to system, so I developed new_curse to provide
+consistent behavior across systems. It works on both SystemV and BSD
+systems, and while it can sometimes be slower than other curses packages,
+it will get the information on the screen painted correctly more often
+than vendor supplied curses. Again, FreeBSD does not have this problem
+but you may find it useful on other platforms.
+
+If you experience problems with data being displayed improperly, check
+your terminal configuration, especially if you're using a terminal
+emulator, and make sure that you are using the right terminfo entry
+before rummaging through code. Terminfo entries often contain
+inaccuracies, or incomplete information, or may not totally match the
+terminal or emulator the terminal information is being used with.
+Complaints that ee isn't working quite right often end up being something
+else (like the terminal emulator being used).
+
+Both ee and new_curse were developed using K&R C (also known as "classic
+C"), but it can also be compiled with ANSI C. You should be able to
+build ee by simply typing "make".
+
+ee is the result of several conflicting design goals. While I know that it
+solves the problems of some users, I also have no doubt that some will decry
+its lack of more features. I will settle for knowing that ee does fulfill
+the needs of a minority (but still large number) of users. The goals of ee
+are:
+
+ 1. To be so easy to use as to require no instruction.
+ 2. To be easy to compile and, if necessary, port to new platforms
+ by people with relatively little knowledge of C and UNIX.
+ 3. To have a minimum number of files to be dealt with, for compile
+ and installation.
+ 4. To have enough functionality to be useful to a large number of
+ people.
+
+Hugh Mahon |___|
+h_mahon@fc.hp.com | |
+ |\ /|
+ | \/ |
+
diff --git a/usr.bin/ee/ee.1 b/usr.bin/ee/ee.1
new file mode 100644
index 0000000..91ca919
--- /dev/null
+++ b/usr.bin/ee/ee.1
@@ -0,0 +1,529 @@
+.\"
+.\"
+.\" To format this reference page, use the command:
+.\"
+.\" nroff -man ee.1
+.\"
+.\" $Header: /home/ncvs/src/usr.bin/ee/ee.1,v 1.3 1996/02/02 00:25:36 mpp Exp $
+.\"
+.\"
+.TH ee 1 "" "" "" ""
+.SH NAME
+ee \- easy editor
+.SH SYNOPSIS
+.nf
+ee [-e] [-i] [-h] [+#] [\fIfile\fR ...]
+ree [-e] [-i] [-h] [+#] [\fIfile\fR ...]
+.ta
+.fi
+.ad b
+.SH DESCRIPTION
+The command
+.I ee
+is a simple screen oriented text editor. It is always in text insertion
+mode unless there is a prompt at the bottom of the terminal, or a
+menu present (in a box in the middle of the terminal). The command
+.I ree
+is the same as
+.I ee,
+but restricted to editing the named
+file (no file operations, or shell escapes are allowed).
+.PP
+For
+.I ee
+to work properly, the environment variable
+.SM TERM
+must be set to indicate the type of terminal being used. For
+example, for an
+.SM HP 700/92
+terminal, the
+.SM TERM
+variable should be set to "70092". See your System Administrator if
+you need more information.
+.\"
+.\" options
+.\"
+.SS Options
+The following options are available from the command line:
+.PP
+.TP 4
+.B -e
+Turns off expansion of tab character to spaces.
+.TP
+.B -i
+Turns off display of information window at top of terminal.
+.TP
+.B -h
+Turns off highlighting of borders of windows and menus (improves
+performance on some terminals).
+.TP
+.B +#
+Moves the cursor to line '#' at startup.
+.br
+.\"
+.\" control keys
+.\"
+.SS "Control keys"
+To do anything other than insert text, the user must use the control
+keys (the
+.B Control
+key, represented by a "^", pressed in conjunction with an
+alphabetic key, e.g., ^a) and function keys available on the keyboard
+(such as
+.BR "Next Page" ", " "Prev Page" ,
+arrow keys, etc.).
+.PP
+Since not all terminals have function keys,
+.I ee
+has the basic cursor movement functions assigned to control keys as
+well as more intuitive keys on the keyboard when available. For
+instance, to move the cursor up, the user can use the up arrow key,
+or
+.BR ^u .
+.RS 4
+.nf
+.ta 1.4i
+.sp
+^a Prompt for the decimal value of a character to insert.
+^b Move to the bottom of the text.
+^c Get the prompt for a command.
+^d Move the cursor down.
+^e Prompt for the string to search for.
+^f Undelete the last deleted character.
+^g Move to the beginning of the line.
+^h Backspace.
+^i Tab.
+^j Insert a newline.
+^k Delete the character the cursor is sitting on.
+^l Move the cursor left.
+^m Insert a newline.
+^n Move to the next page.
+^o Move to the end of the line.
+^p Move to the previous page.
+^r Move the cursor to the right.
+^t Move to the top of the text.
+^u Move the cursor up.
+^v Undelete the last deleted word.
+^w Delete the word beginning at the cursor position.
+^x Search.
+^y Delete from the cursor position to the end of line.
+^z Undelete the last deleted line.
+^[ (ESC) Pop up menu.
+.ta
+.fi
+.RE
+.sp
+.SS "EMACS keys mode"
+.PP
+Since many shells provide an Emacs mode (for cursor movement and other editing
+operations), some bindings that may be more useful for people familiar with
+those bindings have been provided. These are accessible via the
+.B settings
+menu, or via the initialization file (see below). The mappings are as follows:
+.RS
+.nf
+.ta 1.4i
+^a Move to the beginning of the line.
+^b Back 1 character.
+^c Command prompt.
+^d Delete character the cursor is sitting on.
+^e End of line.
+^f Forward 1 character.
+^g Go back 1 page.
+^h Backspace.
+^i Tab.
+^j Undelete last deleted character.
+^k Delete line.
+^l Undelete last deleted line.
+^m Insert a newline.
+^n Move to the next line.
+^o Prompt for the decimal value of a character to insert.
+^p Previous line.
+^r Restore last deleted word.
+^t Move to the top of the text.
+^u Move to the bottom of the text.
+^v Move to the next page.
+^w Delete the word beginning at the cursor position.
+^y Prompt for the string to search for.
+^z Next word.
+^[ (ESC) Pop up menu.
+.ta
+.fi
+.RE
+.sp
+.\"
+.\" function keys
+.\"
+.SS "Function Keys"
+.RS 4
+.IP "\fBNext Page\fR"
+Move to the next page.
+.IP "\fBPrev Page\fR"
+Move to the previous page.
+.IP "\fBDelete Char\fR"
+Delete the character the cursor is on.
+.IP "\fBDelete Line\fR"
+Delete from the cursor to the end of line.
+.IP "\fBInsert line\fR"
+Insert a newline at the cursor position.
+.IP "\fBArrow keys\fR"
+Move the cursor in the direction indicated.
+.RE
+.\"
+.\" commands
+.\"
+.SS Commands
+.PP
+Some operations require more information than a single keystroke can
+provide. For the most basic operations, there is a menu that can be
+obtained by pressing the
+.SM \fBESC\fR
+key. The same operations, and more can be performed by obtaining the
+command prompt (^c) and typing in one of the commands below.
+.RS 4
+.IP "!\fBcmd\fR"
+Execute \fBcmd\fR in a shell.
+.IP "\fB0-9\fR"
+Move to the line indicated.
+.IP "\fBcase\fR"
+Make searches case sensitive.
+.IP "\fBcharacter\fR"
+Display the ascii value of the character at the cursor.
+.IP "\fBexit\fR"
+Save the edited text, and leave the editor.
+.IP "\fBexpand\fR"
+Expand tabs to spaces.
+.IP "\fBfile\fR"
+Print the name of the file.
+.IP "\fBhelp\fR"
+Display help screen.
+.IP "\fBline\fR"
+Display the current line number.
+.IP "\fBnocase\fR
+Make searches insensitive to case (the default).
+.IP "\fBnoexpand\fR"
+Don't expand tab to spaces when the TAB key is pressed.
+.IP "\fBquit\fR"
+Leave the editor without saving changes.
+.IP "\fBread\fR \fIfile\fR"
+Read the named \fIfile\fR.
+.IP "\fBwrite\fR \fIfile\fR"
+Write the text to the named \fIfile\fR.
+.RE
+.\"
+.\" menu operations
+.\"
+.SS "Menu Operations"
+.PP
+Pop-up menus can be obtained by pressing the
+.B escape
+key (or
+.B ^[
+if no
+.B escape
+key is present). When in the menu, the escape key can be
+used to leave the menu without performing any operations. Use the up and
+down arrow keys, or
+.B ^u
+for moving up and
+.B ^d
+for moving down to move to the desired items in the menu, then press
+.B return
+to perform the indicated task.
+.PP
+To the left of each menu item is a letter, which if the corresponding
+letter is pressed on the keyboard selects that menu entry.
+.PP
+The main menu in \fIee\fR is as follows:
+.RS 4
+.IP "\fBleave editor\fR"
+If changes have been made, the user will get a menu prompting whether or
+not the changes should be saved.
+.IP "\fBhelp\fR"
+Displays a help screen, with all of the keyboard operations and commands.
+.IP "\fBfile operations\fR"
+Pops up a menu for selecting whether to read a file, write to a file, or
+save the current contents of the editor, as well as send the contents of
+the editor to a print command (see the section \fBInitializing ee from a
+file\fR).
+.IP "\fBredraw screen\fR"
+Provides a means to repaint the screen if the screen has been corrupted.
+.IP "\fBsettings\fR"
+Shows the current values of the operating modes, and right margin. By
+pressing return when the cursor is on a particular item, the value can be
+changed. To leave this menu, press the \fBescape\fR key. (See \fBModes\fR
+below.)
+.IP "\fBsearch\fR"
+.br
+Pops up a menu in which the user may choose to enter a string to search
+for, or search for a string already entered.
+.IP "\fBmiscellaneous\fR"
+Pops up a menu that allows the user to format the current paragraph,
+execute a shell command, or check the spelling of the text in the editor.
+.RE
+.\"
+.\" paragraph formatting
+.\"
+.SS "Paragraph Formatting"
+.PP
+Paragraphs are defined for \fIee\fR by a block of text bounded by:
+.sp
+.RS 8
+.IP \(bu
+Begin or end of file.
+.IP \(bu
+Line with no characters, or only spaces and/or tabs.
+.IP \(bu
+Line starting with a period ('.') or right angle bracket ('>').
+.RE
+.PP
+A paragraph may be formatted two ways: explicitly by choosing the
+\fBformat paragraph\fR menu item, or by setting \fIee\fR to automatically
+format paragraphs. The automatic mode may be set via a menu, or via the
+initialization file.
+.PP
+There are three states for text operation in \fIee\fR: free-form, margins,
+and automatic formatting.
+.PP
+"Free-form" is best used for things like programming. There are no
+restrictions on the length of lines, and no formatting takes place.
+.PP
+"Margins" allows the user to type in text without having to worry about going
+beyond the right margin (the right margin may be set in the \fBsettings\fR
+menu, the default is for the margin to be the right edge of the
+terminal). This is the mode that allows the \fBformat paragraph\fR menu
+item to work.
+.PP
+"Automatic formatting" provides word-processor-like behavior. The user
+may type in text, while \fIee\fR will make sure the entire paragraph fits
+within the width of the terminal every time the user inserts a space after
+typing or deleting text. Margin observation must also be enabled in order for
+automatic formatting to occur.
+.\"
+.\" modes
+.\"
+.SS Modes
+.PP
+Although ee is a 'modeless' editor (it is in text insertion mode all the
+time), there are modes in some of the things it does. These include:
+.RS 4
+.IP "\fBtab expansion\fR"
+Tabs may be inserted as a single tab character, or replaced with spaces.
+.IP "\fBcase sensitivity\fR"
+The search operation can be sensitive to whether characters are upper- or
+lower-case, or ignore case completely.
+.IP "\fBmargins observed\fR"
+Lines can either be truncated at the right margin, or extend on forever.
+.IP "\fBauto paragraph formatting\fR"
+While typing in text, the editor can try to keep it looking reasonably well
+within the width of the screen.
+.IP "\fBeightbit characters\fR"
+Toggles whether eight bit characters are displayed as their value in angle
+brackets (e.g. "<220>") or as a character.
+.IP "\fBinfo window\fR"
+A window showing the keyboard operations that can be performed can be
+displayed or not.
+.IP"\fBemacs keys\fR"
+Control keys may be given bindings similar to emacs, or not.
+.RE
+.PP
+You may set these modes via the initialization file (see below), or with a
+menu (see above).
+.\"
+.\" spell checking
+.\"
+.SS "Spell Checking"
+.PP
+There are two ways to have the spelling in the text checked from \fIee\fR.
+One is by the traditional \fIspell\fR(1) command, the other is with the
+optional \fIispell\fR(1) command.
+.PP
+Using \fIspell\fR, the words that are not recognized will be placed at the top
+of the file. For the \fIispell\fR option, the file is written to disk,
+then \fIispell\fR run on the file, and the file read back in once
+\fIispell\fR has completed making changes to the file.
+.\"
+.\" printing
+.\"
+.SS "Printing the contents of the editor"
+.PP
+The user may select a menu item which prints the contents of the editor.
+.I ee
+pipes the text in the editor to the command specified by the
+initialization command
+.B printcommand
+(see the section
+.B Initializing ee from a file
+below). The default is to send the contents to "lp".
+.PP
+Whatever the user assigns to
+.B printcommand
+must take input from
+standard input. See your system administrator for more details.
+.\"
+.\" shell operations
+.\"
+.SS "Shell operations"
+.PP
+Shell commands can be executed from within
+.I ee
+by selecting the
+.B shell command
+item in the
+.B miscellaneous
+menu, or by placing an exclamation mark ("!") before the command to
+execute at the
+.B command:
+prompt. Additionally, the user may direct the contents of the edit buffer
+out to a shell operation (via a pipe) by using the left angle bracket
+(">"), followed by a "!" and the shell command to execute. The output of
+a shell operation can also be directed into the edit buffer by using a
+right angle bracket ("<") before the exclamation mark. These can even be
+used together to send output to a shell operation and read back the
+results into the editor. So, if the editor contained a list of words
+to be sorted, they could be sorted by typing the following at the command
+prompt:
+.RS 4
+.sp
+><!sort
+.sp
+.RE
+This would send the contents of the editor to be piped into the
+.I sort
+utility and the result would be placed into the edit buffer at the current
+cursor location. The old information would have to be deleted by the user.
+.\"
+.\" initializing ee from a file
+.\"
+.SS "Initializing ee from a file"
+.PP
+Since different users have different preferences, \fIee\fR allows some
+slight configurability. There are three possible locations for an
+initialization file for ee: the file \fI/usr/share/misc/init.ee\fR, the
+file \fI.init.ee\fR in the user's home directory, or the file \fI.init.ee\fR
+in the current directory (if different from the home
+directory). This allows system administrators to set some preferences for
+the users on a system-wide basis (for example, the \fBprint\fR command),
+and the user to customize settings for particular directories (like one
+for correspondence, and a different directory for programming).
+.PP
+The file \fI\/usr/share/misc/init.ee\fR is read first, then
+\fI$HOME/.init.ee\fR, then \fI.init.ee\fR, with the settings specified by the
+most recent file read taking precedence.
+.PP
+The following items may be entered in the initialization file:
+.RS 4
+.IP \fBcase\fR
+Sets searches to be case sensitive.
+.IP \fBnocase\fR
+Sets searches to be insensitive to case (default).
+.IP \fBexpand\fR
+Causes \fIee\fR to expand tabs to spaces (default).
+.IP \fBnoexpand\fR
+Causes \fIee\fR to insert tabs as a single character.
+.IP \fBinfo\fR
+A small information window is displayed at the top of the terminal
+(default).
+.IP \fBnoinfo\fR
+Turns off the display of the information window.
+.IP \fBmargins\fR
+Causes \fIee\fR to truncate lines at the right margin when the
+cursor passes beyond the right margin as set by the user
+while text is being inserted
+(default).
+.IP \fBnomargins\fR
+Allows lines to extend beyond the right margin.
+.IP \fBautoformat\fR
+Causes \fIee\fR to automatically try to format the current paragraph while
+text insertion is occurring.
+.IP \fBnoautoformat\fR
+Turns off automatic paragraph formatting (default).
+.IP \fBprintcommand\fR
+Allows the setting of the print command (default: "lp").
+.IP \fBrightmargin\fR
+The user can select a value for the right margin (the first column on the
+screen is zero).
+.IP \fBhighlight\fR
+Turns on highlighting border of information window and menus (default).
+.IP \fBnohighlight\fR
+Turns off highlighting of border of information window and menus.
+.IP \fBeightbit\fR
+Turns on display of eight bit characters.
+.IP \fBnoeightbit\fR
+Turns off display of eight bit characters (they are displayed as their decimal
+value inside angle brackets, e.g., "<220>").
+.IP \fBemacs\fR
+Turns on emacs key bindings.
+.IP \fBnoemacs\fR
+Turns off emacs key bindings.
+.RE
+.\"
+.\" save editor configuration
+.\"
+.SS "Save Editor Configuration"
+.PP
+When using this entry from the
+.B settings
+menu, the user may choose to save the current configuration of
+the editor (see \fBInitializing ee from a
+file\fR above) to a file named
+.I .init.ee
+in the current directory or the user's home directory. If a file named
+.I .init.ee
+already exists, it will be renamed
+.IR .init.ee.old .
+.\"
+.\" Caveats
+.\"
+.SH CAVEATS
+.PP
+THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. Neither
+Hewlett-Packard nor Hugh Mahon shall be liable
+for errors contained herein, nor for
+incidental or consequential damages in
+connection with the furnishing, performance or
+use of this material. Neither Hewlett-Packard
+nor Hugh Mahon assumes any responsibility for
+the use or reliability of this software or
+documentation. This software and
+documentation is totally UNSUPPORTED. There
+is no support contract available. Hewlett-Packard
+has done NO Quality Assurance on ANY
+of the program or documentation. You may find
+the quality of the materials inferior to
+supported materials.
+.PP
+Always make a copy of files that cannot be easily reproduced before
+editing. Save files early, and save often.
+.SS "International Code Set Support"
+.I ee
+supports single-byte character code sets (eight-bit clean).
+.SH WARNINGS
+The automatic paragraph formatting operation
+may be too slow for slower systems.
+.SH FILES
+.PP
+.I /usr/share/misc/init.ee
+.br
+.I $HOME/.init.ee
+.br
+.I .init.ee
+.SH AUTHOR
+.PP
+The software
+.I ee
+was developed by Hugh Mahon.
+.PP
+This software and documentation contains
+proprietary information which is protected by
+copyright. All rights are reserved.
+.PP
+Copyright (c) 1990, 1991, 1992, 1993, 1995 Hugh Mahon.
+.SH "SEE ALSO"
+.PP
+termcap(5), terminfo(5), environ(7), spell(1), ispell(1), lp(1)
+
diff --git a/usr.bin/ee/ee.c b/usr.bin/ee/ee.c
new file mode 100644
index 0000000..8f6650cc
--- /dev/null
+++ b/usr.bin/ee/ee.c
@@ -0,0 +1,5128 @@
+/*
+ | ee (easy editor)
+ |
+ | An easy to use, simple screen oriented editor.
+ |
+ | written by Hugh Mahon
+ |
+ | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+ | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+ | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+ | IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ | FITNESS FOR A PARTICULAR PURPOSE. Neither
+ | Hewlett-Packard nor Hugh Mahon shall be liable
+ | for errors contained herein, nor for
+ | incidental or consequential damages in
+ | connection with the furnishing, performance or
+ | use of this material. Neither Hewlett-Packard
+ | nor Hugh Mahon assumes any responsibility for
+ | the use or reliability of this software or
+ | documentation. This software and
+ | documentation is totally UNSUPPORTED. There
+ | is no support contract available. Hewlett-
+ | Packard has done NO Quality Assurance on ANY
+ | of the program or documentation. You may find
+ | the quality of the materials inferior to
+ | supported materials.
+ |
+ | This software is not a product of Hewlett-Packard, Co., or any
+ | other company. No support is implied or offered with this software.
+ | You've got the source, and you're on your own.
+ |
+ | This software may be distributed under the terms of Larry Wall's
+ | Artistic license, a copy of which is included in this distribution.
+ |
+ | This notice must be included with this software and any derivatives.
+ |
+ | This editor was purposely developed to be simple, both in
+ | interface and implementation. This editor was developed to
+ | address a specific audience: the user who is new to computers
+ | (especially UNIX).
+ |
+ | ee is not aimed at technical users; for that reason more
+ | complex features were intentionally left out. In addition,
+ | ee is intended to be compiled by people with little computer
+ | experience, which means that it needs to be small, relatively
+ | simple in implementation, and portable.
+ |
+ | This software and documentation contains
+ | proprietary information which is protected by
+ | copyright. All rights are reserved.
+ |
+ | $Header: /home/ncvs/src/usr.bin/ee/ee.c,v 1.6 1996/05/27 20:59:36 joerg Exp $
+ |
+ */
+
+char *ee_copyright_message =
+"Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995, 1996 Hugh Mahon ";
+
+char *ee_long_notice[] = {
+ "This software and documentation contains",
+ "proprietary information which is protected by",
+ "copyright. All rights are reserved."
+ };
+
+char *version = "@(#) ee, version 1.3 $Revision: 1.1.1.2 $";
+
+#ifdef NCURSE
+#include "new_curse.h"
+#elif HAS_NCURSES
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+
+#ifdef HAS_SYS_WAIT
+#include <sys/wait.h>
+#endif
+
+#ifdef HAS_STDLIB
+#include <stdlib.h>
+#endif
+
+#ifdef HAS_STDARG
+#include <stdarg.h>
+#endif
+
+#ifdef HAS_UNISTD
+#include <unistd.h>
+#endif
+
+#ifdef HAS_CTYPE
+#include <ctype.h>
+#endif
+
+
+#ifndef NO_CATGETS
+#include <locale.h>
+#include <nl_types.h>
+
+nl_catd catalog;
+#else
+#define catgetlocal(a, b) (b)
+#endif /* NO_CATGETS */
+
+#ifndef SIGCHLD
+#define SIGCHLD SIGCLD
+#endif
+
+#define TAB 9
+#define max(a, b) (a > b ? a : b)
+#define min(a, b) (a < b ? a : b)
+
+/*
+ | defines for type of data to show in info window
+ */
+
+#define CONTROL_KEYS 1
+#define COMMANDS 2
+
+struct text {
+ char *line; /* line of characters */
+ int line_number; /* line number */
+ int line_length; /* actual number of characters in the line */
+ int max_length; /* maximum number of characters the line handles */
+ struct text *next_line; /* next line of text */
+ struct text *prev_line; /* previous line of text */
+ };
+
+struct text *first_line; /* first line of current buffer */
+struct text *dlt_line; /* structure for info on deleted line */
+struct text *curr_line; /* current line cursor is on */
+struct text *tmp_line; /* temporary line pointer */
+struct text *srch_line; /* temporary pointer for search routine */
+
+struct files { /* structure to store names of files to be edited*/
+ char *name; /* name of file */
+ struct files *next_name;
+ };
+
+struct files *top_of_stack = NULL;
+
+int d_wrd_len; /* length of deleted word */
+int position; /* offset in bytes from begin of line */
+int scr_pos; /* horizontal position */
+int scr_vert; /* vertical position on screen */
+int scr_horz; /* horizontal position on screen */
+int tmp_vert, tmp_horz;
+int input_file; /* indicate to read input file */
+int recv_file; /* indicate reading a file */
+int edit; /* continue executing while true */
+int gold; /* 'gold' function key pressed */
+int fildes; /* file descriptor */
+int case_sen; /* case sensitive search flag */
+int last_line; /* last line for text display */
+int last_col; /* last column for text display */
+int horiz_offset = 0; /* offset from left edge of text */
+int clear_com_win; /* flag to indicate com_win needs clearing */
+int text_changes = FALSE; /* indicate changes have been made to text */
+int get_fd; /* file descriptor for reading a file */
+int info_window = TRUE; /* flag to indicate if help window visible */
+int info_type = CONTROL_KEYS; /* flag to indicate type of info to display */
+int expand_tabs = TRUE; /* flag for expanding tabs */
+int right_margin = 0; /* the right margin */
+int observ_margins = TRUE; /* flag for whether margins are observed */
+int shell_fork;
+int temp_stdin; /* temporary storage for stdin */
+int temp_stdout; /* temp storage for stdout descriptor */
+int temp_stderr; /* temp storage for stderr descriptor */
+int pipe_out[2]; /* pipe file desc for output */
+int pipe_in[2]; /* pipe file descriptors for input */
+int out_pipe; /* flag that info is piped out */
+int in_pipe; /* flag that info is piped in */
+int formatted = FALSE; /* flag indicating paragraph formatted */
+int auto_format = FALSE; /* flag for auto_format mode */
+int restricted = FALSE; /* flag to indicate restricted mode */
+int nohighlight = FALSE; /* turns off highlighting */
+int eightbit = TRUE; /* eight bit character flag */
+int local_LINES = 0; /* copy of LINES, to detect when win resizes */
+int local_COLS = 0; /* copy of COLS, to detect when win resizes */
+int curses_initialized = FALSE; /* flag indicating if curses has been started*/
+int emacs_keys_mode = FALSE; /* mode for if emacs key binings are used */
+
+char *point; /* points to current position in line */
+char *srch_str; /* pointer for search string */
+char *u_srch_str; /* pointer to non-case sensitive search */
+char *srch_1; /* pointer to start of suspect string */
+char *srch_2; /* pointer to next character of string */
+char *srch_3;
+char *in_file_name = NULL; /* name of input file */
+char *tmp_file; /* temporary file name */
+char d_char; /* deleted character */
+char *d_word; /* deleted word */
+char *d_line; /* deleted line */
+char in_string[513]; /* buffer for reading a file */
+char *print_command = "lp"; /* string to use for the print command */
+char *start_at_line = NULL; /* move to this line at start of session*/
+int in; /* input character */
+
+FILE *temp_fp; /* temporary file pointer */
+FILE *bit_bucket; /* file pointer to /dev/null */
+
+char *table[] = {
+ "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "\t", "^J",
+ "^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U",
+ "^V", "^W", "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_"
+ };
+
+WINDOW *com_win;
+WINDOW *text_win;
+WINDOW *help_win;
+WINDOW *info_win;
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+
+
+/*
+ | The following structure allows menu items to be flexibly declared.
+ | The first item is the string describing the selection, the second
+ | is the address of the procedure to call when the item is selected,
+ | and the third is the argument for the procedure.
+ |
+ | For those systems with i18n, the string should be accompanied by a
+ | catalog number. The 'int *' should be replaced with 'void *' on
+ | systems with that type.
+ |
+ | The first menu item will be the title of the menu, with NULL
+ | parameters for the procedure and argument, followed by the menu items.
+ |
+ | If the procedure value is NULL, the menu item is displayed, but no
+ | procedure is called when the item is selected. The number of the
+ | item will be returned. If the third (argument) parameter is -1, no
+ | argument is given to the procedure when it is called.
+ */
+
+struct menu_entries {
+ char *item_string;
+ int (*procedure)P_((struct menu_entries *));
+ struct menu_entries *ptr_argument;
+ int (*iprocedure)P_((int));
+ void (*nprocedure)P_((void));
+ unsigned int argument;
+ };
+
+int main P_((int argc, char *argv[]));
+char *resiz_line P_((int factor, struct text *rline, int rpos));
+void insert P_((int character));
+void delete P_((int disp));
+void scanline P_((char *pos));
+int tabshift P_((int temp_int));
+int out_char P_((WINDOW *window, int character, int column));
+int len_char P_((int character, int column));
+void draw_line P_((int vertical, int horiz, char *ptr, int t_pos, int length));
+void insert_line P_((int disp));
+struct text *txtalloc P_((void));
+struct files *name_alloc P_((void));
+char *next_word P_((char *string));
+void prev_word P_((void));
+void control P_((void));
+void emacs_control P_((void));
+void bottom P_((void));
+void top P_((void));
+void nextline P_((void));
+void prevline P_((void));
+void left P_((int disp));
+void right P_((int disp));
+void find_pos P_((void));
+void up P_((void));
+void down P_((void));
+void function_key P_((void));
+void print_buffer P_((void));
+void command_prompt P_((void));
+void command P_((char *cmd_str1));
+int scan P_((char *line, int offset, int column));
+char *get_string P_((char *prompt, int advance));
+int compare P_((char *string1, char *string2, int sensitive));
+void goto_line P_((char *cmd_str));
+void midscreen P_((int line, char *pnt));
+void get_options P_((int numargs, char *arguments[]));
+void check_fp P_((void));
+void get_file P_((char *file_name));
+void get_line P_((int length, char *in_string, int *append));
+void draw_screen P_((void));
+void finish P_((void));
+int quit P_((int noverify));
+void edit_abort P_((int arg));
+void delete_text P_((void));
+int write_file P_((char *file_name));
+int search P_((int display_message));
+void search_prompt P_((void));
+void del_char P_((void));
+void undel_char P_((void));
+void del_word P_((void));
+void undel_word P_((void));
+void del_line P_((void));
+void undel_line P_((void));
+void adv_word P_((void));
+void move_rel P_((char *direction, int lines));
+void eol P_((void));
+void bol P_((void));
+void adv_line P_((void));
+void sh_command P_((char *string));
+void set_up_term P_((void));
+void resize_check P_((void));
+int menu_op P_((struct menu_entries *));
+void paint_menu P_((struct menu_entries menu_list[], int max_width, int max_height, int list_size, int top_offset, WINDOW *menu_win, int off_start, int vert_size));
+void help P_((void));
+void paint_info_win P_((void));
+void no_info_window P_((void));
+void create_info_window P_((void));
+int file_op P_((int arg));
+void shell_op P_((void));
+void leave_op P_((void));
+void redraw P_((void));
+int Blank_Line P_((struct text *test_line));
+void Format P_((void));
+void ee_init P_((void));
+void dump_ee_conf P_((void));
+void echo_string P_((char *string));
+void spell_op P_((void));
+void ispell_op P_((void));
+int first_word_len P_((struct text *test_line));
+void Auto_Format P_((void));
+void modes_op P_((void));
+char *is_in_string P_((char *string, char *substring));
+char *resolve_name P_((char *name));
+int restrict_mode P_((void));
+int unique_test P_((char *string, char *list[]));
+void strings_init P_((void));
+
+#undef P_
+/*
+ | allocate space here for the strings that will be in the menu
+ */
+
+struct menu_entries modes_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, dump_ee_conf, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+char *mode_strings[10];
+
+#define NUM_MODES_ITEMS 9
+
+struct menu_entries config_dump_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries leave_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, finish, -1},
+ {"", NULL, NULL, quit, NULL, TRUE},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+#define READ_FILE 1
+#define WRITE_FILE 2
+#define SAVE_FILE 3
+
+struct menu_entries file_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, file_op, NULL, READ_FILE},
+ {"", NULL, NULL, file_op, NULL, WRITE_FILE},
+ {"", NULL, NULL, file_op, NULL, SAVE_FILE},
+ {"", NULL, NULL, NULL, print_buffer, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries search_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0},
+ {"", NULL, NULL, NULL, search_prompt, -1},
+ {"", NULL, NULL, search, NULL, TRUE},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries spell_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, spell_op, -1},
+ {"", NULL, NULL, NULL, ispell_op, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries misc_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, Format, -1},
+ {"", NULL, NULL, NULL, shell_op, -1},
+ {"", menu_op, spell_menu, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries main_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, leave_op, -1},
+ {"", NULL, NULL, NULL, help, -1},
+ {"", menu_op, file_menu, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, redraw, -1},
+ {"", NULL, NULL, NULL, modes_op, -1},
+ {"", menu_op, search_menu, NULL, NULL, -1},
+ {"", menu_op, misc_menu, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+char *help_text[22];
+char *control_keys[5];
+
+char *emacs_help_text[22];
+char *emacs_control_keys[5];
+
+char *command_strings[5];
+char *commands[30];
+char *init_strings[20];
+
+#define MENU_WARN 1
+
+#define max_alpha_char 36
+
+/*
+ | Declarations for strings for localization
+ */
+
+char *com_win_message; /* to be shown in com_win if no info window */
+char *no_file_string;
+char *ascii_code_str;
+char *printer_msg_str;
+char *command_str;
+char *file_write_prompt_str;
+char *file_read_prompt_str;
+char *char_str;
+char *unkn_cmd_str;
+char *non_unique_cmd_msg;
+char *line_num_str;
+char *line_len_str;
+char *current_file_str;
+char *usage0;
+char *usage1;
+char *usage2;
+char *usage3;
+char *usage4;
+char *file_is_dir_msg;
+char *new_file_msg;
+char *cant_open_msg;
+char *open_file_msg;
+char *file_read_fin_msg;
+char *reading_file_msg;
+char *read_only_msg;
+char *file_read_lines_msg;
+char *save_file_name_prompt;
+char *file_not_saved_msg;
+char *changes_made_prompt;
+char *yes_char;
+char *file_exists_prompt;
+char *create_file_fail_msg;
+char *writing_file_msg;
+char *file_written_msg;
+char *searching_msg;
+char *str_not_found_msg;
+char *search_prompt_str;
+char *exec_err_msg;
+char *continue_msg;
+char *menu_cancel_msg;
+char *menu_size_err_msg;
+char *press_any_key_msg;
+char *shell_prompt;
+char *formatting_msg;
+char *shell_echo_msg;
+char *spell_in_prog_msg;
+char *margin_prompt;
+char *restricted_msg;
+char *ON;
+char *OFF;
+char *HELP;
+char *WRITE;
+char *READ;
+char *LINE;
+char *FILE_str;
+char *CHARACTER;
+char *REDRAW;
+char *RESEQUENCE;
+char *AUTHOR;
+char *VERSION;
+char *CASE;
+char *NOCASE;
+char *EXPAND;
+char *NOEXPAND;
+char *Exit_string;
+char *QUIT_string;
+char *INFO;
+char *NOINFO;
+char *MARGINS;
+char *NOMARGINS;
+char *AUTOFORMAT;
+char *NOAUTOFORMAT;
+char *Echo;
+char *PRINTCOMMAND;
+char *RIGHTMARGIN;
+char *HIGHLIGHT;
+char *NOHIGHLIGHT;
+char *EIGHTBIT;
+char *NOEIGHTBIT;
+char *EMACS_string;
+char *NOEMACS_string;
+char *conf_dump_err_msg;
+char *conf_dump_success_msg;
+char *conf_not_saved_msg;
+char *ree_no_file_msg;
+char *cancel_string;
+char *menu_too_lrg_msg;
+char *more_above_str, *more_below_str;
+
+#ifndef __STDC__
+#ifndef HAS_STDLIB
+extern char *malloc();
+extern char *realloc();
+extern char *getenv();
+FILE *fopen(); /* declaration for open function */
+#endif /* HAS_STDLIB */
+#endif /* __STDC__ */
+
+int
+main(argc, argv) /* beginning of main program */
+int argc;
+char *argv[];
+{
+ int counter;
+
+ for (counter = 1; counter < 24; counter++)
+ signal(counter, SIG_IGN);
+
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGINT, edit_abort);
+
+ d_char = 0;
+ d_word = malloc(150);
+ *d_word = (char) NULL;
+ d_line = NULL;
+ dlt_line = txtalloc();
+ dlt_line->line = d_line;
+ curr_line = first_line = txtalloc();
+ curr_line->line = point = malloc(10);
+ curr_line->line_length = 1;
+ curr_line->max_length = 10;
+ curr_line->prev_line = NULL;
+ curr_line->next_line = NULL;
+ curr_line->line_number = 1;
+ srch_str = NULL;
+ u_srch_str = NULL;
+ position = 1;
+ scr_pos =0;
+ scr_vert = 0;
+ scr_horz = 0;
+ bit_bucket = fopen("/dev/null", "w");
+ edit = TRUE;
+ gold = case_sen = FALSE;
+ shell_fork = TRUE;
+ strings_init();
+ ee_init();
+ if (argc > 0 )
+ get_options(argc, argv);
+ set_up_term();
+ if (right_margin == 0)
+ right_margin = COLS - 1;
+ if (top_of_stack == NULL)
+ {
+ if (restrict_mode())
+ {
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ wprintw(com_win, ree_no_file_msg);
+ wrefresh(com_win);
+ edit_abort(0);
+ }
+ wprintw(com_win, no_file_string);
+ wrefresh(com_win);
+ }
+ else
+ check_fp();
+
+ clear_com_win = TRUE;
+
+ while(edit)
+ {
+ wrefresh(text_win);
+ in = wgetch(text_win);
+ if (in == -1)
+ exit(0);
+
+ resize_check();
+
+ if (clear_com_win)
+ {
+ clear_com_win = FALSE;
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ if (!info_window)
+ {
+ wprintw(com_win, "%s", com_win_message);
+ }
+ wrefresh(com_win);
+ }
+
+ if (in > 255)
+ function_key();
+ else if ((in == '\10') || (in == 127))
+ delete(TRUE);
+ else if ((in > 31) || (in == 9))
+ insert(in);
+ else if ((in >= 0) && (in <= 31))
+ {
+ if (emacs_keys_mode)
+ emacs_control();
+ else
+ control();
+ }
+ }
+ return(0);
+}
+
+char *
+resiz_line(factor, rline, rpos) /* resize the line to length + factor*/
+int factor; /* resize factor */
+struct text *rline; /* position in line */
+int rpos;
+{
+ char *rpoint;
+ int resiz_var;
+
+ rline->max_length += factor;
+ rpoint = rline->line = realloc(rline->line, rline->max_length );
+ for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++)
+ rpoint++;
+ return(rpoint);
+}
+
+void
+insert(character) /* insert character into line */
+int character; /* new character */
+{
+ int counter;
+ int value;
+ char *temp; /* temporary pointer */
+ char *temp2; /* temporary pointer */
+
+ if ((character == '\011') && (expand_tabs))
+ {
+ counter = len_char('\011', scr_horz);
+ for (; counter > 0; counter--)
+ insert(' ');
+ if (auto_format)
+ Auto_Format();
+ return;
+ }
+ text_changes = TRUE;
+ if ((curr_line->max_length - curr_line->line_length) < 5)
+ point = resiz_line(10, curr_line, position);
+ curr_line->line_length++;
+ temp = point;
+ counter = position;
+ while (counter < curr_line->line_length) /* find end of line */
+ {
+ counter++;
+ temp++;
+ }
+ temp++; /* increase length of line by one */
+ while (point < temp)
+ {
+ temp2=temp - 1;
+ *temp= *temp2; /* shift characters over by one */
+ temp--;
+ }
+ *point = character; /* insert new character */
+ wclrtoeol(text_win);
+ if (((character >= 0) && (character < ' ')) || (character >= 127)) /* check for TAB character*/
+ {
+ scr_pos = scr_horz += out_char(text_win, character, scr_horz);
+ point++;
+ position++;
+ }
+ else
+ {
+ waddch(text_win, character);
+ scr_pos = ++scr_horz;
+ point++;
+ position ++;
+ }
+
+ if ((observ_margins) && (right_margin < scr_pos))
+ {
+ counter = position;
+ while (scr_pos > right_margin)
+ prev_word();
+ if (scr_pos == 0)
+ {
+ while (position < counter)
+ right(TRUE);
+ }
+ else
+ {
+ counter -= position;
+ insert_line(TRUE);
+ for (value = 0; value < counter; value++)
+ right(TRUE);
+ }
+ }
+
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset += 8;
+ midscreen(scr_vert, point);
+ }
+
+ if ((auto_format) && (character == ' ') && (!formatted))
+ Auto_Format();
+ else if ((character != ' ') && (character != '\t'))
+ formatted = FALSE;
+
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+}
+
+void
+delete(disp) /* delete character */
+int disp;
+{
+ char *tp;
+ char *temp2;
+ struct text *temp_buff;
+ int temp_vert;
+ int temp_pos;
+
+ if (point != curr_line->line) /* if not at beginning of line */
+ {
+ text_changes = TRUE;
+ temp2 = tp = point;
+ tp--;
+ point--;
+ if ((*tp >= '\000') && (*tp < ' ')) /* check for TAB */
+ scanline(tp);
+ else
+ --scr_horz;
+ scr_pos = scr_horz;
+ if (in == 8)
+ d_char = *point; /* save deleted character */
+ temp_pos = --position;
+ curr_line->line_length--;
+ while (temp_pos <= curr_line->line_length)
+ {
+ temp_pos++;
+ *tp= *temp2;
+ tp++;
+ temp2++;
+ }
+ if (scr_horz < horiz_offset)
+ {
+ horiz_offset -= 8;
+ midscreen(scr_vert, point);
+ }
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ text_changes = TRUE;
+ left(disp); /* go to previous line */
+ temp_buff = curr_line->next_line;
+ point = resiz_line(temp_buff->line_length, curr_line, position);
+ if (temp_buff->next_line != NULL)
+ temp_buff->next_line->prev_line = curr_line;
+ curr_line->next_line = temp_buff->next_line;
+ temp2 = temp_buff->line;
+ if (in == 8)
+ d_char = '\n';
+ tp = point;
+ temp_pos = 1;
+ while (temp_pos < temp_buff->line_length)
+ {
+ curr_line->line_length++;
+ temp_pos++;
+ *tp = *temp2;
+ tp++;
+ temp2++;
+ }
+ *tp = (char) NULL;
+ free(temp_buff->line);
+ free(temp_buff);
+ temp_buff = curr_line;
+ temp_vert = scr_vert;
+ scr_pos = scr_horz;
+ if (scr_vert < last_line)
+ {
+ wmove(text_win, scr_vert + 1, 0);
+ wdeleteln(text_win);
+ }
+ while ((temp_buff != NULL) && (temp_vert < last_line))
+ {
+ temp_buff = temp_buff->next_line;
+ temp_vert++;
+ }
+ if ((temp_vert == last_line) && (temp_buff != NULL))
+ {
+ tp = temp_buff->line;
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ draw_line(last_line, 0, tp, 1, temp_buff->line_length);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ }
+ }
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+ formatted = FALSE;
+}
+
+void
+scanline(pos) /* find the proper horizontal position for the pointer */
+char *pos;
+{
+ int temp;
+ char *ptr;
+
+ ptr = curr_line->line;
+ temp = 0;
+ while (ptr < pos)
+ {
+ if ((*ptr >= 0) && (*ptr <= 8))
+ temp += 2;
+ else if (*ptr == 9)
+ temp += tabshift(temp);
+ else if ((*ptr >= 10) && (*ptr <= 31))
+ temp += 2;
+ else if ((*ptr >= 32) && (*ptr < 127))
+ temp++;
+ else if (*ptr == 127)
+ temp += 2;
+ else if (!eightbit)
+ temp += 5;
+ else
+ temp++;
+ ptr++;
+ }
+ scr_horz = temp;
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
+ midscreen(scr_vert, point);
+ }
+ else if (scr_horz < horiz_offset)
+ {
+ horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
+ midscreen(scr_vert, point);
+ }
+}
+
+int
+tabshift(temp_int) /* give the number of spaces to shift */
+int temp_int;
+{
+ int leftover;
+
+ leftover = ((temp_int + 1) % 8);
+ if (leftover == 0)
+ return (1);
+ else
+ return (9 - leftover);
+}
+
+int
+out_char(window, character, column) /* output non-printing character */
+WINDOW *window;
+char character;
+int column;
+{
+ int i1, i2;
+ char *string;
+ char string2[8];
+
+ if (character == TAB)
+ {
+ i1 = tabshift(column);
+ for (i2 = 0;
+ (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++)
+ {
+ waddch(window, ' ');
+ }
+ return(i1);
+ }
+ else if ((character >= '\0') && (character < ' '))
+ {
+ string = table[(int) character];
+ }
+ else if ((character < 0) || (character >= 127))
+ {
+ if (character == 127)
+ string = "^?";
+ else if (!eightbit)
+ {
+ sprintf(string2, "<%d>", (character < 0) ? (character + 256) : character);
+ string = string2;
+ }
+ else
+ {
+ waddch(window, (unsigned char)character );
+ return(1);
+ }
+ }
+ else
+ {
+ waddch(window, (unsigned char)character);
+ return(1);
+ }
+ for (i2 = 0; (string[i2] != (char) NULL) && (((column+i2+1)-horiz_offset) < last_col); i2++)
+ waddch(window, string[i2]);
+ return(strlen(string));
+}
+
+int
+len_char(character, column) /* return the length of the character */
+char character;
+int column; /* the column must be known to provide spacing for tabs */
+{
+ int length;
+
+ if (character == '\t')
+ length = tabshift(column);
+ else if ((character >= 0) && (character < 32))
+ length = 2;
+ else if ((character >= 32) && (character <= 126))
+ length = 1;
+ else if (character == 127)
+ length = 2;
+ else if (((character > 126) || (character < 0)) && (!eightbit))
+ length = 5;
+ else
+ length = 1;
+
+ return(length);
+}
+
+void
+draw_line(vertical, horiz, ptr, t_pos, length) /* redraw line from current position */
+int vertical; /* current vertical position on screen */
+int horiz; /* current horizontal position on screen */
+char *ptr; /* pointer to line */
+int t_pos; /* current position (offset in bytes) from bol */
+int length; /* length (in bytes) of line */
+{
+ int d; /* partial length of special or tab char to display */
+ char *temp; /* temporary pointer to position in line */
+ int abs_column; /* offset in screen units from begin of line */
+ int column; /* horizontal position on screen */
+ int row; /* vertical position on screen */
+ int posit; /* temporary position indicator within line */
+
+ abs_column = horiz;
+ column = horiz - horiz_offset;
+ row = vertical;
+ temp = ptr;
+ d = 0;
+ posit = t_pos;
+ if (column < 0)
+ {
+ wmove(text_win, row, 0);
+ wclrtoeol(text_win);
+ }
+ while (column < 0)
+ {
+ d = len_char(*temp, abs_column);
+ abs_column += d;
+ column += d;
+ posit++;
+ temp++;
+ }
+ wmove(text_win, row, column);
+ wclrtoeol(text_win);
+ while ((posit < length) && (column <= last_col))
+ {
+ if ((*temp < 32) || (*temp == 127))
+ {
+ column += len_char(*temp, abs_column);
+ abs_column += out_char(text_win, *temp, abs_column);
+ }
+ else
+ {
+ abs_column++;
+ column++;
+ waddch(text_win, *temp);
+ }
+ posit++;
+ temp++;
+ }
+ if (column < last_col)
+ wclrtoeol(text_win);
+ wmove(text_win, vertical, (horiz - horiz_offset));
+}
+
+void
+insert_line(disp) /* insert new line */
+int disp;
+{
+ int temp_pos;
+ int temp_pos2;
+ char *temp;
+ char *extra;
+ struct text *temp_nod;
+
+ text_changes = TRUE;
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wclrtoeol(text_win);
+ temp_nod= txtalloc();
+ temp_nod->line = extra= malloc(10);
+ temp_nod->line_length = 1;
+ temp_nod->max_length = 10;
+ temp_nod->line_number = curr_line->line_number + 1;
+ temp_nod->next_line = curr_line->next_line;
+ if (temp_nod->next_line != NULL)
+ temp_nod->next_line->prev_line = temp_nod;
+ temp_nod->prev_line = curr_line;
+ curr_line->next_line = temp_nod;
+ temp_pos2 = position;
+ temp = point;
+ if (temp_pos2 < curr_line->line_length)
+ {
+ temp_pos = 1;
+ while (temp_pos2 < curr_line->line_length)
+ {
+ if ((temp_nod->max_length - temp_nod->line_length)< 5)
+ extra = resiz_line(10, temp_nod, temp_pos);
+ temp_nod->line_length++;
+ temp_pos++;
+ temp_pos2++;
+ *extra= *temp;
+ extra++;
+ temp++;
+ }
+ temp=point;
+ *temp = (char) NULL;
+ temp = resiz_line((1 - temp_nod->line_length), curr_line, position);
+ curr_line->line_length = 1 + temp - curr_line->line;
+ }
+ curr_line->line_length = position;
+ curr_line = temp_nod;
+ *extra = (char) NULL;
+ position = 1;
+ point= curr_line->line;
+ if (disp)
+ {
+ if (scr_vert < last_line)
+ {
+ scr_vert++;
+ wclrtoeol(text_win);
+ wmove(text_win, scr_vert, 0);
+ winsertln(text_win);
+ }
+ else
+ {
+ wmove(text_win, 0,0);
+ wdeleteln(text_win);
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ }
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ draw_line(scr_vert, scr_horz, point, position,
+ curr_line->line_length);
+ }
+}
+
+struct text *txtalloc() /* allocate space for line structure */
+{
+ return((struct text *) malloc(sizeof( struct text)));
+}
+
+struct files *name_alloc() /* allocate space for file name list node */
+{
+ return((struct files *) malloc(sizeof( struct files)));
+}
+
+char *next_word(string) /* move to next word in string */
+char *string;
+{
+ while ((*string != (char) NULL) && ((*string != 32) && (*string != 9)))
+ string++;
+ while ((*string != (char) NULL) && ((*string == 32) || (*string == 9)))
+ string++;
+ return(string);
+}
+
+void
+prev_word() /* move to start of previous word in text */
+{
+ if (position != 1)
+ {
+ if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t')))
+ { /* if at the start of a word */
+ while ((position != 1) && ((*point != ' ') && (*point != '\t')))
+ left(TRUE);
+ }
+ while ((position != 1) && ((*point == ' ') || (*point == '\t')))
+ left(TRUE);
+ while ((position != 1) && ((*point != ' ') && (*point != '\t')))
+ left(TRUE);
+ if ((position != 1) && ((*point == ' ') || (*point == '\t')))
+ right(TRUE);
+ }
+ else
+ left(TRUE);
+}
+
+void
+control() /* use control for commands */
+{
+ char *string;
+
+ if (in == 1) /* control a */
+ {
+ string = get_string(ascii_code_str, TRUE);
+ if (*string != (char) NULL)
+ {
+ in = atoi(string);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ insert(in);
+ }
+ free(string);
+ }
+ else if (in == 2) /* control b */
+ bottom();
+ else if (in == 3) /* control c */
+ {
+ command_prompt();
+ }
+ else if (in == 4) /* control d */
+ down();
+ else if (in == 5) /* control e */
+ search_prompt();
+ else if (in == 6) /* control f */
+ undel_char();
+ else if (in == 7) /* control g */
+ bol();
+ else if (in == 8) /* control h */
+ delete(TRUE);
+ else if (in == 9) /* control i */
+ ;
+ else if (in == 10) /* control j */
+ insert_line(TRUE);
+ else if (in == 11) /* control k */
+ del_char();
+ else if (in == 12) /* control l */
+ left(TRUE);
+ else if (in == 13) /* control m */
+ insert_line(TRUE);
+ else if (in == 14) /* control n */
+ move_rel("d", max(5, (last_line - 5)));
+ else if (in == 15) /* control o */
+ eol();
+ else if (in == 16) /* control p */
+ move_rel("u", max(5, (last_line - 5)));
+ else if (in == 17) /* control q */
+ ;
+ else if (in == 18) /* control r */
+ right(TRUE);
+ else if (in == 19) /* control s */
+ ;
+ else if (in == 20) /* control t */
+ top();
+ else if (in == 21) /* control u */
+ up();
+ else if (in == 22) /* control v */
+ undel_word();
+ else if (in == 23) /* control w */
+ del_word();
+ else if (in == 24) /* control x */
+ search(TRUE);
+ else if (in == 25) /* control y */
+ del_line();
+ else if (in == 26) /* control z */
+ undel_line();
+ else if (in == 27) /* control [ (escape) */
+ {
+ menu_op(main_menu);
+ }
+}
+
+/*
+ | Emacs control-key bindings
+ */
+
+void
+emacs_control()
+{
+ char *string;
+
+ if (in == 1) /* control a */
+ bol();
+ else if (in == 2) /* control b */
+ left(TRUE);
+ else if (in == 3) /* control c */
+ {
+ command_prompt();
+ }
+ else if (in == 4) /* control d */
+ del_char();
+ else if (in == 5) /* control e */
+ eol();
+ else if (in == 6) /* control f */
+ right(TRUE);
+ else if (in == 7) /* control g */
+ move_rel("u", max(5, (last_line - 5)));
+ else if (in == 8) /* control h */
+ delete(TRUE);
+ else if (in == 9) /* control i */
+ ;
+ else if (in == 10) /* control j */
+ undel_char();
+ else if (in == 11) /* control k */
+ del_line();
+ else if (in == 12) /* control l */
+ undel_line();
+ else if (in == 13) /* control m */
+ insert_line(TRUE);
+ else if (in == 14) /* control n */
+ down();
+ else if (in == 15) /* control o */
+ {
+ string = get_string(ascii_code_str, TRUE);
+ if (*string != (char) NULL)
+ {
+ in = atoi(string);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ insert(in);
+ }
+ free(string);
+ }
+ else if (in == 16) /* control p */
+ up();
+ else if (in == 17) /* control q */
+ ;
+ else if (in == 18) /* control r */
+ undel_word();
+ else if (in == 19) /* control s */
+ ;
+ else if (in == 20) /* control t */
+ top();
+ else if (in == 21) /* control u */
+ bottom();
+ else if (in == 22) /* control v */
+ move_rel("d", max(5, (last_line - 5)));
+ else if (in == 23) /* control w */
+ del_word();
+ else if (in == 24) /* control x */
+ search(TRUE);
+ else if (in == 25) /* control y */
+ search_prompt();
+ else if (in == 26) /* control z */
+ adv_word();
+ else if (in == 27) /* control [ (escape) */
+ {
+ menu_op(main_menu);
+ }
+}
+
+void
+bottom() /* go to bottom of file */
+{
+ while (curr_line->next_line != NULL)
+ curr_line = curr_line->next_line;
+ point = curr_line->line;
+ if (horiz_offset)
+ horiz_offset = 0;
+ position = 1;
+ midscreen(last_line, point);
+ scr_pos = scr_horz;
+}
+
+void
+top() /* go to top of file */
+{
+ while (curr_line->prev_line != NULL)
+ curr_line = curr_line->prev_line;
+ point = curr_line->line;
+ if (horiz_offset)
+ horiz_offset = 0;
+ position = 1;
+ midscreen(0, point);
+ scr_pos = scr_horz;
+}
+
+void
+nextline() /* move pointers to start of next line */
+{
+ curr_line = curr_line->next_line;
+ point = curr_line->line;
+ position = 1;
+ if (scr_vert == last_line)
+ {
+ wmove(text_win, 0,0);
+ wdeleteln(text_win);
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ draw_line(last_line,0,point,1,curr_line->line_length);
+ }
+ else
+ scr_vert++;
+}
+
+void
+prevline() /* move pointers to start of previous line*/
+{
+ curr_line = curr_line->prev_line;
+ point = curr_line->line;
+ position = 1;
+ if (scr_vert == 0)
+ {
+ winsertln(text_win);
+ draw_line(0,0,point,1,curr_line->line_length);
+ }
+ else
+ scr_vert--;
+ while (position < curr_line->line_length)
+ {
+ position++;
+ point++;
+ }
+}
+
+void
+left(disp) /* move left one character */
+int disp;
+{
+ if (point != curr_line->line) /* if not at begin of line */
+ {
+ point--;
+ position--;
+ scanline(point);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ scr_pos = scr_horz;
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ if (!disp)
+ {
+ curr_line = curr_line->prev_line;
+ point = curr_line->line + curr_line->line_length;
+ position = curr_line->line_length;
+ return;
+ }
+ position = 1;
+ prevline();
+ scanline(point);
+ scr_pos = scr_horz;
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ }
+}
+
+void
+right(disp) /* move right one character */
+int disp;
+{
+ if (position < curr_line->line_length)
+ {
+ point++;
+ position++;
+ scanline(point);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ scr_pos = scr_horz;
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ if (!disp)
+ {
+ curr_line = curr_line->next_line;
+ point = curr_line->line;
+ position = 1;
+ return;
+ }
+ nextline();
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ position = 1;
+ }
+}
+
+void
+find_pos() /* move to the same column as on other line */
+{
+ scr_horz = 0;
+ position = 1;
+ while ((scr_horz < scr_pos) && (position < curr_line->line_length))
+ {
+ if (*point == 9)
+ scr_horz += tabshift(scr_horz);
+ else if ((*point >= '\0') && (*point < ' '))
+ scr_horz += 2;
+ else
+ scr_horz++;
+ position++;
+ point++;
+ }
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
+ midscreen(scr_vert, point);
+ }
+ else if (scr_horz < horiz_offset)
+ {
+ horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
+ midscreen(scr_vert, point);
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+up() /* move up one line */
+{
+ if (curr_line->prev_line != NULL)
+ {
+ prevline();
+ point = curr_line->line;
+ find_pos();
+ }
+}
+
+void
+down() /* move down one line */
+{
+ if (curr_line->next_line != NULL)
+ {
+ nextline();
+ find_pos();
+ }
+}
+
+void
+function_key() /* process function key */
+{
+ if (in == KEY_LEFT)
+ left(TRUE);
+ else if (in == KEY_RIGHT)
+ right(TRUE);
+ else if ( in == KEY_HOME)
+ top();
+ else if ( in == KEY_UP)
+ up();
+ else if (in == KEY_DOWN)
+ down();
+ else if (in == KEY_NPAGE)
+ move_rel("d", max( 5, (last_line - 5)));
+ else if (in == KEY_PPAGE)
+ move_rel("u", max(5, (last_line - 5)));
+ else if (in == KEY_DL)
+ del_line();
+ else if (in == KEY_DC)
+ del_char();
+ else if (in == KEY_BACKSPACE)
+ delete(TRUE);
+ else if (in == KEY_IL)
+ { /* insert a line before current line */
+ insert_line(TRUE);
+ left(TRUE);
+ }
+ else if (in == KEY_F(1))
+ gold = !gold;
+ else if (in == KEY_F(2))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ undel_line();
+ }
+ else
+ undel_char();
+ }
+ else if (in == KEY_F(3))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ undel_word();
+ }
+ else
+ del_word();
+ }
+ else if (in == KEY_F(4))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ paint_info_win();
+ midscreen(scr_vert, point);
+ }
+ else
+ adv_word();
+ }
+ else if (in == KEY_F(5))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ search_prompt();
+ }
+ else
+ search(TRUE);
+ }
+ else if (in == KEY_F(6))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ bottom();
+ }
+ else
+ top();
+ }
+ else if (in == KEY_F(7))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ eol();
+ }
+ else
+ bol();
+ }
+ else if (in == KEY_F(8))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ command_prompt();
+ }
+ else
+ adv_line();
+ }
+}
+
+void
+print_buffer()
+{
+ char buffer[256];
+
+ sprintf(buffer, ">!%s", print_command);
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, printer_msg_str, print_command);
+ wrefresh(com_win);
+ command(buffer);
+}
+
+void
+command_prompt()
+{
+ char *cmd_str;
+ int result;
+
+ info_type = COMMANDS;
+ paint_info_win();
+ cmd_str = get_string(command_str, TRUE);
+ if ((result = unique_test(cmd_str, commands)) != 1)
+ {
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ if (result == 0)
+ wprintw(com_win, unkn_cmd_str, cmd_str);
+ else
+ wprintw(com_win, non_unique_cmd_msg);
+
+ wrefresh(com_win);
+
+ info_type = CONTROL_KEYS;
+ paint_info_win();
+
+ if (cmd_str != NULL)
+ free(cmd_str);
+ return;
+ }
+ command(cmd_str);
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ info_type = CONTROL_KEYS;
+ paint_info_win();
+ if (cmd_str != NULL)
+ free(cmd_str);
+}
+
+void
+command(cmd_str1) /* process commands from keyboard */
+char *cmd_str1;
+{
+ char *cmd_str2 = NULL;
+ char *cmd_str = cmd_str1;
+
+ clear_com_win = TRUE;
+ if (compare(cmd_str, HELP, FALSE))
+ help();
+ else if (compare(cmd_str, WRITE, FALSE))
+ {
+ if (restrict_mode())
+ {
+ return;
+ }
+ cmd_str = next_word(cmd_str);
+ if (*cmd_str == (char) NULL)
+ {
+ cmd_str = cmd_str2 = get_string(file_write_prompt_str, TRUE);
+ }
+ tmp_file = resolve_name(cmd_str);
+ write_file(tmp_file);
+ if (tmp_file != cmd_str)
+ free(tmp_file);
+ }
+ else if (compare(cmd_str, READ, FALSE))
+ {
+ if (restrict_mode())
+ {
+ return;
+ }
+ cmd_str = next_word(cmd_str);
+ if (*cmd_str == (char) NULL)
+ {
+ cmd_str = cmd_str2 = get_string(file_read_prompt_str, TRUE);
+ }
+ tmp_file = cmd_str;
+ recv_file = TRUE;
+ tmp_file = resolve_name(cmd_str);
+ check_fp();
+ if (tmp_file != cmd_str)
+ free(tmp_file);
+ }
+ else if (compare(cmd_str, LINE, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, line_num_str, curr_line->line_number);
+ wprintw(com_win, line_len_str, curr_line->line_length);
+ }
+ else if (compare(cmd_str, FILE_str, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ if (in_file_name == NULL)
+ wprintw(com_win, no_file_string);
+ else
+ wprintw(com_win, current_file_str, in_file_name);
+ }
+ else if ((*cmd_str >= '0') && (*cmd_str <= '9'))
+ goto_line(cmd_str);
+ else if (compare(cmd_str, CHARACTER, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ if (*point >= '\0')
+ wprintw(com_win, char_str, *point);
+ else
+ wprintw(com_win, char_str, (*point + 256));
+ }
+ else if (compare(cmd_str, REDRAW, FALSE))
+ redraw();
+ else if (compare(cmd_str, RESEQUENCE, FALSE))
+ {
+ tmp_line = first_line->next_line;
+ while (tmp_line != NULL)
+ {
+ tmp_line->line_number = tmp_line->prev_line->line_number + 1;
+ tmp_line = tmp_line->next_line;
+ }
+ }
+ else if (compare(cmd_str, AUTHOR, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, "written by Hugh Mahon");
+ }
+ else if (compare(cmd_str, VERSION, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, "%s", version);
+ }
+ else if (compare(cmd_str, CASE, FALSE))
+ case_sen = TRUE;
+ else if (compare(cmd_str, NOCASE, FALSE))
+ case_sen = FALSE;
+ else if (compare(cmd_str, EXPAND, FALSE))
+ expand_tabs = TRUE;
+ else if (compare(cmd_str, NOEXPAND, FALSE))
+ expand_tabs = FALSE;
+ else if (compare(cmd_str, Exit_string, FALSE))
+ finish();
+ else if (compare(cmd_str, QUIT_string, FALSE))
+ quit(0);
+ else if (*cmd_str == '!')
+ {
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == 9))
+ cmd_str = next_word(cmd_str);
+ sh_command(cmd_str);
+ }
+ else if ((*cmd_str == '<') && (!in_pipe))
+ {
+ in_pipe = TRUE;
+ shell_fork = FALSE;
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == '\t'))
+ cmd_str = next_word(cmd_str);
+ command(cmd_str);
+ in_pipe = FALSE;
+ shell_fork = TRUE;
+ }
+ else if ((*cmd_str == '>') && (!out_pipe))
+ {
+ out_pipe = TRUE;
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == '\t'))
+ cmd_str = next_word(cmd_str);
+ command(cmd_str);
+ out_pipe = FALSE;
+ }
+ else
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, unkn_cmd_str, cmd_str);
+ }
+ if (cmd_str2 != NULL)
+ free(cmd_str2);
+}
+
+int
+scan(line, offset, column) /* determine horizontal position for get_string */
+char *line;
+int offset;
+int column;
+{
+ char *stemp;
+ int i;
+ int j;
+
+ stemp = line;
+ i = 0;
+ j = column;
+ while (i < offset)
+ {
+ i++;
+ j += len_char(*stemp, j);
+ stemp++;
+ }
+ return(j);
+}
+
+char *
+get_string(prompt, advance) /* read string from input on command line */
+char *prompt; /* string containing user prompt message */
+int advance; /* if true, skip leading spaces and tabs */
+{
+ char *string;
+ char *tmp_string;
+ char *nam_str;
+ char *g_point;
+ int tmp_int;
+ int g_horz, g_position, g_pos;
+ int esc_flag;
+
+ g_point = tmp_string = malloc(512);
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ waddstr(com_win, prompt);
+ wrefresh(com_win);
+ nam_str = tmp_string;
+ clear_com_win = TRUE;
+ g_horz = g_position = scan(prompt, strlen(prompt), 0);
+ g_pos = 0;
+ do
+ {
+ esc_flag = FALSE;
+ in = wgetch(com_win);
+ if (in == -1)
+ exit(0);
+ if (((in == 8) || (in == 127) || (in == KEY_BACKSPACE)) && (g_pos > 0))
+ {
+ tmp_int = g_horz;
+ g_pos--;
+ g_horz = scan(g_point, g_pos, g_position);
+ tmp_int = tmp_int - g_horz;
+ for (; 0 < tmp_int; tmp_int--)
+ {
+ if ((g_horz+tmp_int) < (last_col - 1))
+ {
+ waddch(com_win, '\010');
+ waddch(com_win, ' ');
+ waddch(com_win, '\010');
+ }
+ }
+ nam_str--;
+ }
+ else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r') && (in < 256))
+ {
+ if (in == '\026') /* control-v, accept next character verbatim */
+ { /* allows entry of ^m, ^j, and ^h */
+ esc_flag = TRUE;
+ in = wgetch(com_win);
+ if (in == -1)
+ exit(0);
+ }
+ *nam_str = in;
+ g_pos++;
+ if (((in < ' ') || (in > 126)) && (g_horz < (last_col - 1)))
+ g_horz += out_char(com_win, in, g_horz);
+ else
+ {
+ g_horz++;
+ if (g_horz < (last_col - 1))
+ waddch(com_win, in);
+ }
+ nam_str++;
+ }
+ wrefresh(com_win);
+ if (esc_flag)
+ in = (char) NULL;
+ } while ((in != '\n') && (in != '\r'));
+ *nam_str = (char) NULL;
+ nam_str = tmp_string;
+ if (((*nam_str == ' ') || (*nam_str == 9)) && (advance))
+ nam_str = next_word(nam_str);
+ string = malloc(strlen(nam_str) + 1);
+ strcpy(string, nam_str);
+ free(tmp_string);
+ wrefresh(com_win);
+ return(string);
+}
+
+int
+compare(string1, string2, sensitive) /* compare two strings */
+char *string1;
+char *string2;
+int sensitive;
+{
+ char *strng1;
+ char *strng2;
+ int tmp;
+ int equal;
+
+ strng1 = string1;
+ strng2 = string2;
+ tmp = 0;
+ if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == (char) NULL) || (*strng2 == (char) NULL))
+ return(FALSE);
+ equal = TRUE;
+ while (equal)
+ {
+ if (sensitive)
+ {
+ if (*strng1 != *strng2)
+ equal = FALSE;
+ }
+ else
+ {
+ if (toupper(*strng1) != toupper(*strng2))
+ equal = FALSE;
+ }
+ strng1++;
+ strng2++;
+ if ((*strng1 == (char) NULL) || (*strng2 == (char) NULL) || (*strng1 == ' ') || (*strng2 == ' '))
+ break;
+ tmp++;
+ }
+ return(equal);
+}
+
+void
+goto_line(cmd_str)
+char *cmd_str;
+{
+ int number;
+ int i;
+ char *ptr;
+ char *direction;
+ struct text *t_line;
+
+ ptr = cmd_str;
+ i= 0;
+ while ((*ptr >='0') && (*ptr <= '9'))
+ {
+ i= i * 10 + (*ptr - '0');
+ ptr++;
+ }
+ number = i;
+ i = 0;
+ t_line = curr_line;
+ while ((t_line->line_number > number) && (t_line->prev_line != NULL))
+ {
+ i++;
+ t_line = t_line->prev_line;
+ direction = "u";
+ }
+ while ((t_line->line_number < number) && (t_line->next_line != NULL))
+ {
+ i++;
+ direction = "d";
+ t_line = t_line->next_line;
+ }
+ if ((i < 30) && (i > 0))
+ {
+ move_rel(direction, i);
+ }
+ else
+ {
+ curr_line = t_line;
+ point = curr_line->line;
+ position = 1;
+ midscreen((last_line / 2), point);
+ scr_pos = scr_horz;
+ }
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, line_num_str, curr_line->line_number);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+midscreen(line, pnt) /* put current line in middle of screen */
+int line;
+char *pnt;
+{
+ struct text *mid_line;
+ int i;
+
+ line = min(line, last_line);
+ mid_line = curr_line;
+ for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++)
+ curr_line = curr_line->prev_line;
+ scr_vert = scr_horz = 0;
+ wmove(text_win, 0, 0);
+ draw_screen();
+ scr_vert = i;
+ curr_line = mid_line;
+ scanline(pnt);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+get_options(numargs, arguments) /* get arguments from command line */
+int numargs;
+char *arguments[];
+{
+ char *buff;
+ int count;
+ struct files *temp_names;
+ char *name;
+ char *ptr;
+
+ /*
+ | see if editor was invoked as 'ree' (restricted mode)
+ */
+
+ if (!(name = strrchr(arguments[0], '/')))
+ name = arguments[0];
+ else
+ name++;
+ if (!strcmp(name, "ree"))
+ restricted = TRUE;
+
+ top_of_stack = NULL;
+ input_file = FALSE;
+ recv_file = FALSE;
+ count = 1;
+ while (count < numargs)
+ {
+ buff = arguments[count];
+ if (!strcmp("-i", buff))
+ {
+ info_window = FALSE;
+ }
+ else if (!strcmp("-e", buff))
+ {
+ expand_tabs = FALSE;
+ }
+ else if (!strcmp("-h", buff))
+ {
+ nohighlight = TRUE;
+ }
+ else if (!strcmp("-?", buff))
+ {
+ fprintf(stderr, usage0, arguments[0]);
+ fprintf(stderr, usage1);
+ fprintf(stderr, usage2);
+ fprintf(stderr, usage3);
+ fprintf(stderr, usage4);
+ exit(1);
+ }
+ else if (*buff == '+')
+ {
+ buff++;
+ start_at_line = buff;
+ }
+
+ else
+ {
+ if (top_of_stack == NULL)
+ {
+ temp_names = top_of_stack = name_alloc();
+ }
+ else
+ {
+ temp_names->next_name = name_alloc();
+ temp_names = temp_names->next_name;
+ }
+ ptr = temp_names->name = malloc(strlen(buff) + 1);
+ while (*buff != (char) NULL)
+ {
+ *ptr = *buff;
+ buff++;
+ ptr++;
+ }
+ *ptr = (char) NULL;
+ temp_names->next_name = NULL;
+ input_file = TRUE;
+ recv_file = TRUE;
+ }
+ count++;
+ }
+}
+
+void
+check_fp() /* open or close files according to flags */
+{
+ int line_num;
+ int temp;
+ struct stat buf;
+
+ clear_com_win = TRUE;
+ tmp_vert = scr_vert;
+ tmp_horz = scr_horz;
+ tmp_line = curr_line;
+ if (input_file)
+ {
+ in_file_name = tmp_file = top_of_stack->name;
+ top_of_stack = top_of_stack->next_name;
+ }
+ temp = stat(tmp_file, &buf);
+ buf.st_mode &= ~07777;
+ if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0))
+ {
+ wprintw(com_win, file_is_dir_msg, tmp_file);
+ wrefresh(com_win);
+ if (input_file)
+ {
+ quit(0);
+ return;
+ }
+ else
+ return;
+ }
+ if ((get_fd = open(tmp_file, O_RDONLY)) == -1)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ if (input_file)
+ wprintw(com_win, new_file_msg, tmp_file);
+ else
+ wprintw(com_win, cant_open_msg, tmp_file);
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wrefresh(text_win);
+ recv_file = FALSE;
+ input_file = FALSE;
+ return;
+ }
+ else
+ get_file(tmp_file);
+
+ recv_file = FALSE;
+ line_num = curr_line->line_number;
+ scr_vert = tmp_vert;
+ scr_horz = tmp_horz;
+ if (input_file)
+ curr_line= first_line;
+ else
+ curr_line = tmp_line;
+ point = curr_line->line;
+ draw_screen();
+ if (input_file)
+ {
+ input_file = FALSE;
+ if (start_at_line != NULL)
+ {
+ line_num = atoi(start_at_line) - 1;
+ move_rel("d", line_num);
+ line_num = 0;
+ start_at_line = NULL;
+ }
+ }
+ else
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ text_changes = TRUE;
+ if ((tmp_file != NULL) && (*tmp_file != (char) NULL))
+ wprintw(com_win, file_read_fin_msg, tmp_file);
+ }
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wrefresh(text_win);
+}
+
+void
+get_file(file_name) /* read specified file into current buffer */
+char *file_name;
+{
+ int can_read; /* file has at least one character */
+ int length; /* length of line read by read */
+ int append; /* should text be appended to current line */
+ struct text *temp_line;
+ char ro_flag = FALSE;
+
+ if (recv_file) /* if reading a file */
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, reading_file_msg, file_name);
+ if (access(file_name, 2)) /* check permission to write */
+ {
+ if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT))
+ {
+ wprintw(com_win, read_only_msg);
+ ro_flag = TRUE;
+ }
+ }
+ wrefresh(com_win);
+ }
+ if (curr_line->line_length > 1) /* if current line is not blank */
+ {
+ insert_line(FALSE);
+ left(FALSE);
+ append = FALSE;
+ }
+ else
+ append = TRUE;
+ can_read = FALSE; /* test if file has any characters */
+ while (((length = read(get_fd, in_string, 512)) != 0) && (length != -1))
+ {
+ can_read = TRUE; /* if set file has at least 1 character */
+ get_line(length, in_string, &append);
+ }
+ if ((can_read) && (curr_line->line_length == 1))
+ {
+ temp_line = curr_line->prev_line;
+ temp_line->next_line = curr_line->next_line;
+ if (temp_line->next_line != NULL)
+ temp_line->next_line->prev_line = temp_line;
+ if (curr_line->line != NULL)
+ free(curr_line->line);
+ free(curr_line);
+ curr_line = temp_line;
+ }
+ if (input_file) /* if this is the file to be edited display number of lines */
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number);
+ if (ro_flag)
+ wprintw(com_win, read_only_msg);
+ wrefresh(com_win);
+ }
+ else if (can_read) /* not input_file and file is non-zero size */
+ text_changes = TRUE;
+
+ if (recv_file) /* if reading a file */
+ {
+ in = EOF;
+ }
+}
+
+void
+get_line(length, in_string, append) /* read string and split into lines */
+int length; /* length of string read by read */
+char *in_string; /* string read by read */
+int *append; /* TRUE if must append more text to end of current line */
+{
+ char *str1;
+ char *str2;
+ int num; /* offset from start of string */
+ int char_count; /* length of new line (or added portion */
+ int temp_counter; /* temporary counter value */
+ struct text *tline; /* temporary pointer to new line */
+ int first_time; /* if TRUE, the first time through the loop */
+
+ str2 = in_string;
+ num = 0;
+ first_time = TRUE;
+ while (num < length)
+ {
+ if (!first_time)
+ {
+ if (num < length)
+ {
+ str2++;
+ num++;
+ }
+ }
+ else
+ first_time = FALSE;
+ str1 = str2;
+ char_count = 1;
+ /* find end of line */
+ while ((*str2 != '\n') && (num < length))
+ {
+ str2++;
+ num++;
+ char_count++;
+ }
+ if (!(*append)) /* if not append to current line, insert new one */
+ {
+ tline = txtalloc(); /* allocate data structure for next line */
+ tline->line_number = curr_line->line_number + 1;
+ tline->next_line = curr_line->next_line;
+ tline->prev_line = curr_line;
+ curr_line->next_line = tline;
+ if (tline->next_line != NULL)
+ tline->next_line->prev_line = tline;
+ curr_line = tline;
+ curr_line->line = point = (char *) malloc(char_count);
+ curr_line->line_length = char_count;
+ curr_line->max_length = char_count;
+ }
+ else
+ {
+ point = resiz_line(char_count, curr_line, curr_line->line_length);
+ curr_line->line_length += (char_count - 1);
+ }
+ for (temp_counter = 1; temp_counter < char_count; temp_counter++)
+ {
+ *point = *str1;
+ point++;
+ str1++;
+ }
+ *point = (char) NULL;
+ *append = FALSE;
+ if ((num == length) && (*str2 != '\n'))
+ *append = TRUE;
+ }
+}
+
+void
+draw_screen() /* redraw the screen from current postion */
+{
+ struct text *temp_line;
+ char *line_out;
+ int temp_vert;
+
+ temp_line = curr_line;
+ temp_vert = scr_vert;
+ wclrtobot(text_win);
+ while ((temp_line != NULL) && (temp_vert <= last_line))
+ {
+ line_out = temp_line->line;
+ draw_line(temp_vert, 0, line_out, 1, temp_line->line_length);
+ temp_vert++;
+ temp_line = temp_line->next_line;
+ }
+ wmove(text_win, temp_vert, 0);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+finish() /* prepare to exit edit session */
+{
+ char *file_name = in_file_name;
+
+ /*
+ | changes made here should be reflected in the 'save'
+ | portion of file_op()
+ */
+
+ if ((file_name == NULL) || (*file_name == (char) NULL))
+ file_name = get_string(save_file_name_prompt, TRUE);
+
+ if ((file_name == NULL) || (*file_name == (char) NULL))
+ {
+ wmove(com_win, 0, 0);
+ wprintw(com_win, file_not_saved_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return;
+ }
+
+ tmp_file = resolve_name(file_name);
+ if (tmp_file != file_name)
+ {
+ free(file_name);
+ file_name = tmp_file;
+ }
+
+ if (write_file(file_name))
+ {
+ text_changes = FALSE;
+ quit(0);
+ }
+}
+
+int
+quit(noverify) /* exit editor */
+int noverify;
+{
+ char *ans;
+
+ touchwin(text_win);
+ wrefresh(text_win);
+ if ((text_changes) && (!noverify))
+ {
+ ans = get_string(changes_made_prompt, TRUE);
+ if (toupper(*ans) == toupper(*yes_char))
+ text_changes = FALSE;
+ else
+ return(0);
+ free(ans);
+ }
+ if (top_of_stack == NULL)
+ {
+ if (info_window)
+ wrefresh(info_win);
+ wrefresh(com_win);
+ resetty();
+ endwin();
+ putchar('\n');
+ exit(0);
+ }
+ else
+ {
+ delete_text();
+ recv_file = TRUE;
+ input_file = TRUE;
+ check_fp();
+ }
+ return(0);
+}
+
+void
+edit_abort(arg)
+int arg;
+{
+ wrefresh(com_win);
+ resetty();
+ endwin();
+ putchar('\n');
+ exit(1);
+}
+
+void
+delete_text()
+{
+ while (curr_line->next_line != NULL)
+ curr_line = curr_line->next_line;
+ while (curr_line != first_line)
+ {
+ free(curr_line->line);
+ curr_line = curr_line->prev_line;
+ free(curr_line->next_line);
+ }
+ curr_line->next_line = NULL;
+ *curr_line->line = (char) NULL;
+ curr_line->line_length = 1;
+ curr_line->line_number = 1;
+ point = curr_line->line;
+ scr_pos = scr_vert = scr_horz = 0;
+ position = 1;
+}
+
+int
+write_file(file_name)
+char *file_name;
+{
+ char cr;
+ char *tmp_point;
+ struct text *out_line;
+ int lines, charac;
+ int temp_pos;
+ int write_flag = TRUE;
+
+ charac = lines = 0;
+ if ((in_file_name == NULL) || strcmp(in_file_name, file_name))
+ {
+ if ((temp_fp = fopen(file_name, "r")))
+ {
+ tmp_point = get_string(file_exists_prompt, TRUE);
+ if (toupper(*tmp_point) == toupper(*yes_char))
+ write_flag = TRUE;
+ else
+ write_flag = FALSE;
+ fclose(temp_fp);
+ free(tmp_point);
+ }
+ }
+
+ clear_com_win = TRUE;
+
+ if (write_flag)
+ {
+ if ((temp_fp = fopen(file_name, "w")) == NULL)
+ {
+ clear_com_win = TRUE;
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, create_file_fail_msg, file_name);
+ wrefresh(com_win);
+ return(FALSE);
+ }
+ else
+ {
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, writing_file_msg, file_name);
+ wrefresh(com_win);
+ cr = '\n';
+ out_line = first_line;
+ while (out_line != NULL)
+ {
+ temp_pos = 1;
+ tmp_point= out_line->line;
+ while (temp_pos < out_line->line_length)
+ {
+ putc(*tmp_point, temp_fp);
+ tmp_point++;
+ temp_pos++;
+ }
+ charac += out_line->line_length;
+ out_line = out_line->next_line;
+ putc(cr, temp_fp);
+ lines++;
+ }
+ fclose(temp_fp);
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, file_written_msg, file_name, lines, charac);
+ wrefresh(com_win);
+ return(TRUE);
+ }
+ }
+ else
+ return(FALSE);
+}
+
+int
+search(display_message) /* search for string in srch_str */
+int display_message;
+{
+ int lines_moved;
+ int iter;
+ int found;
+
+ if ((srch_str == NULL) || (*srch_str == (char) NULL))
+ return(FALSE);
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, searching_msg);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ }
+ lines_moved = 0;
+ found = FALSE;
+ srch_line = curr_line;
+ srch_1 = point;
+ if (position < curr_line->line_length)
+ srch_1++;
+ iter = position + 1;
+ while ((!found) && (srch_line != NULL))
+ {
+ while ((iter < srch_line->line_length) && (!found))
+ {
+ srch_2 = srch_1;
+ if (case_sen) /* if case sensitive */
+ {
+ srch_3 = srch_str;
+ while ((*srch_2 == *srch_3) && (*srch_3 != (char) NULL))
+ {
+ found = TRUE;
+ srch_2++;
+ srch_3++;
+ } /* end while */
+ }
+ else /* if not case sensitive */
+ {
+ srch_3 = u_srch_str;
+ while ((toupper(*srch_2) == *srch_3) && (*srch_3 != (char) NULL))
+ {
+ found = TRUE;
+ srch_2++;
+ srch_3++;
+ }
+ } /* end else */
+ if (!((*srch_3 == (char) NULL) && (found)))
+ {
+ found = FALSE;
+ if (iter < srch_line->line_length)
+ srch_1++;
+ iter++;
+ }
+ }
+ if (!found)
+ {
+ srch_line = srch_line->next_line;
+ if (srch_line != NULL)
+ srch_1 = srch_line->line;
+ iter = 1;
+ lines_moved++;
+ }
+ }
+ if (found)
+ {
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ }
+ if (lines_moved == 0)
+ {
+ while (position < iter)
+ right(TRUE);
+ }
+ else
+ {
+ if (lines_moved < 30)
+ {
+ move_rel("d", lines_moved);
+ while (position < iter)
+ right(TRUE);
+ }
+ else
+ {
+ curr_line = srch_line;
+ point = srch_1;
+ position = iter;
+ scanline(point);
+ scr_pos = scr_horz;
+ midscreen((last_line / 2), point);
+ }
+ }
+ }
+ else
+ {
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, str_not_found_msg, srch_str);
+ wrefresh(com_win);
+ }
+ wmove(text_win, scr_vert,(scr_horz - horiz_offset));
+ }
+ return(found);
+}
+
+void
+search_prompt() /* prompt and read search string (srch_str) */
+{
+ if (srch_str != NULL)
+ free(srch_str);
+ if ((u_srch_str != NULL) && (*u_srch_str != (char) NULL))
+ free(u_srch_str);
+ srch_str = get_string(search_prompt_str, FALSE);
+ gold = FALSE;
+ srch_3 = srch_str;
+ srch_1 = u_srch_str = malloc(strlen(srch_str) + 1);
+ while (*srch_3 != (char) NULL)
+ {
+ *srch_1 = toupper(*srch_3);
+ srch_1++;
+ srch_3++;
+ }
+ *srch_1 = (char) NULL;
+ search(TRUE);
+}
+
+void
+del_char() /* delete current character */
+{
+ in = 8; /* backspace */
+ if (position < curr_line->line_length) /* if not end of line */
+ {
+ position++;
+ point++;
+ scanline(point);
+ delete(TRUE);
+ }
+ else
+ {
+ right(FALSE);
+ delete(FALSE);
+ }
+}
+
+void
+undel_char() /* undelete last deleted character */
+{
+ if (d_char == '\n') /* insert line if last del_char deleted eol */
+ insert_line(TRUE);
+ else
+ {
+ in = d_char;
+ insert(in);
+ }
+}
+
+void
+del_word() /* delete word in front of cursor */
+{
+ int tposit;
+ int difference;
+ char *d_word2;
+ char *d_word3;
+ char tmp_char;
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = malloc(curr_line->line_length);
+ tmp_char = d_char;
+ d_word3 = point;
+ d_word2 = d_word;
+ tposit = position;
+ while ((tposit < curr_line->line_length) &&
+ ((*d_word3 != ' ') && (*d_word3 != '\t')))
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ while ((tposit < curr_line->line_length) &&
+ ((*d_word3 == ' ') || (*d_word3 == '\t')))
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ *d_word2 = (char) NULL;
+ d_wrd_len = difference = d_word2 - d_word;
+ d_word2 = point;
+ while (tposit < curr_line->line_length)
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ curr_line->line_length -= difference;
+ *d_word2 = (char) NULL;
+ draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
+ d_char = tmp_char;
+ text_changes = TRUE;
+ formatted = FALSE;
+}
+
+void
+undel_word() /* undelete last deleted word */
+{
+ int temp;
+ int tposit;
+ char *tmp_old_ptr;
+ char *tmp_space;
+ char *tmp_ptr;
+ char *d_word_ptr;
+
+ /*
+ | resize line to handle undeleted word
+ */
+ if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5)
+ point = resiz_line(d_wrd_len, curr_line, position);
+ tmp_ptr = tmp_space = malloc(curr_line->line_length + d_wrd_len);
+ d_word_ptr = d_word;
+ temp = 1;
+ /*
+ | copy d_word contents into temp space
+ */
+ while (temp <= d_wrd_len)
+ {
+ temp++;
+ *tmp_ptr = *d_word_ptr;
+ tmp_ptr++;
+ d_word_ptr++;
+ }
+ tmp_old_ptr = point;
+ tposit = position;
+ /*
+ | copy contents of line from curent position to eol into
+ | temp space
+ */
+ while (tposit < curr_line->line_length)
+ {
+ temp++;
+ tposit++;
+ *tmp_ptr = *tmp_old_ptr;
+ tmp_ptr++;
+ tmp_old_ptr++;
+ }
+ curr_line->line_length += d_wrd_len;
+ tmp_old_ptr = point;
+ *tmp_ptr = (char) NULL;
+ tmp_ptr = tmp_space;
+ tposit = 1;
+ /*
+ | now copy contents from temp space back to original line
+ */
+ while (tposit < temp)
+ {
+ tposit++;
+ *tmp_old_ptr = *tmp_ptr;
+ tmp_ptr++;
+ tmp_old_ptr++;
+ }
+ *tmp_old_ptr = (char) NULL;
+ free(tmp_space);
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+}
+
+void
+del_line() /* delete from cursor to end of line */
+{
+ char *dl1;
+ char *dl2;
+ int tposit;
+
+ if (d_line != NULL)
+ free(d_line);
+ d_line = malloc(curr_line->line_length);
+ dl1 = d_line;
+ dl2 = point;
+ tposit = position;
+ while (tposit < curr_line->line_length)
+ {
+ *dl1 = *dl2;
+ dl1++;
+ dl2++;
+ tposit++;
+ }
+ dlt_line->line_length = 1 + tposit - position;
+ *dl1 = (char) NULL;
+ *point = (char) NULL;
+ curr_line->line_length = position;
+ wclrtoeol(text_win);
+ if (curr_line->next_line != NULL)
+ {
+ right(FALSE);
+ delete(FALSE);
+ }
+ text_changes = TRUE;
+}
+
+void
+undel_line() /* undelete last deleted line */
+{
+ char *ud1;
+ char *ud2;
+ int tposit;
+
+ insert_line(TRUE);
+ left(TRUE);
+ point = resiz_line(dlt_line->line_length, curr_line, position);
+ curr_line->line_length += dlt_line->line_length - 1;
+ ud1 = point;
+ ud2 = d_line;
+ tposit = 1;
+ while (tposit < dlt_line->line_length)
+ {
+ tposit++;
+ *ud1 = *ud2;
+ ud1++;
+ ud2++;
+ }
+ *ud1 = (char) NULL;
+ draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
+}
+
+void
+adv_word() /* advance to next word */
+{
+while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9)))
+ right(TRUE);
+while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9)))
+ right(TRUE);
+}
+
+void
+move_rel(direction, lines) /* move relative to current line */
+char *direction;
+int lines;
+{
+ int i;
+ char *tmp;
+
+ if (*direction == 'u')
+ {
+ scr_pos = 0;
+ while (position > 1)
+ left(TRUE);
+ for (i = 0; i < lines; i++)
+ {
+ up();
+ }
+ if ((last_line > 5) && ( scr_vert < 4))
+ {
+ tmp = point;
+ tmp_line = curr_line;
+ for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++)
+ {
+ up();
+ }
+ scr_vert = scr_vert + i;
+ curr_line = tmp_line;
+ point = tmp;
+ scanline(point);
+ }
+ }
+ else
+ {
+ if ((position != 1) && (curr_line->next_line != NULL))
+ {
+ nextline();
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ }
+ else
+ adv_line();
+ for (i = 1; i < lines; i++)
+ {
+ down();
+ }
+ if ((last_line > 10) && (scr_vert > (last_line - 5)))
+ {
+ tmp = point;
+ tmp_line = curr_line;
+ for (i=0; (i<5) && (curr_line->next_line != NULL); i++)
+ {
+ down();
+ }
+ scr_vert = scr_vert - i;
+ curr_line = tmp_line;
+ point = tmp;
+ scanline(point);
+ }
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+eol() /* go to end of line */
+{
+ if (position < curr_line->line_length)
+ {
+ while (position < curr_line->line_length)
+ right(TRUE);
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ right(TRUE);
+ while (position < curr_line->line_length)
+ right(TRUE);
+ }
+}
+
+void
+bol() /* move to beginning of line */
+{
+ if (point != curr_line->line)
+ {
+ while (point != curr_line->line)
+ left(TRUE);
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ scr_pos = 0;
+ up();
+ }
+}
+
+void
+adv_line() /* advance to beginning of next line */
+{
+ if ((point != curr_line->line) || (scr_pos > 0))
+ {
+ while (position < curr_line->line_length)
+ right(TRUE);
+ right(TRUE);
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ scr_pos = 0;
+ down();
+ }
+}
+
+void
+sh_command(string) /* execute shell command */
+char *string; /* string containing user command */
+{
+ char *temp_point;
+ char *last_slash;
+ char *path; /* directory path to executable */
+ int parent; /* zero if child, child's pid if parent */
+ int value;
+ int return_val;
+ struct text *line_holder;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+
+ if (!(path = getenv("SHELL")))
+ path = "/bin/sh";
+ last_slash = temp_point = path;
+ while (*temp_point != (char) NULL)
+ {
+ if (*temp_point == '/')
+ last_slash = ++temp_point;
+ else
+ temp_point++;
+ }
+
+ /*
+ | if in_pipe is true, then output of the shell operation will be
+ | read by the editor, and curses doesn't need to be turned off
+ */
+
+ if (!in_pipe)
+ {
+ keypad(com_win, FALSE);
+ keypad(text_win, FALSE);
+ echo();
+ nl();
+ noraw();
+ resetty();
+
+#ifndef NCURSE
+ endwin();
+#endif
+ }
+
+ if (in_pipe)
+ {
+ pipe(pipe_in); /* create a pipe */
+ parent = fork();
+ if (!parent) /* if the child */
+ {
+/*
+ | child process which will fork and exec shell command (if shell output is
+ | to be read by editor)
+ */
+ in_pipe = FALSE;
+/*
+ | redirect stdout to pipe
+ */
+ temp_stdout = dup(1);
+ close(1);
+ dup(pipe_in[1]);
+/*
+ | redirect stderr to pipe
+ */
+ temp_stderr = dup(2);
+ close(2);
+ dup(pipe_in[1]);
+ close(pipe_in[1]);
+ /*
+ | child will now continue down 'if (!in_pipe)'
+ | path below
+ */
+ }
+ else /* if the parent */
+ {
+/*
+ | prepare editor to read from the pipe
+ */
+ signal(SIGCHLD, SIG_IGN);
+ line_holder = curr_line;
+ tmp_vert = scr_vert;
+ close(pipe_in[1]);
+ get_fd = pipe_in[0];
+ get_file("");
+ close(pipe_in[0]);
+ scr_vert = tmp_vert;
+ scr_horz = scr_pos = 0;
+ position = 1;
+ curr_line = line_holder;
+ point = curr_line->line;
+ out_pipe = FALSE;
+ signal(SIGCHLD, SIG_DFL);
+/*
+ | since flag "in_pipe" is still TRUE, the path which waits for the child
+ | process to die will be avoided.
+ | (the pipe is closed, no more output can be expected)
+ */
+ }
+ }
+ if (!in_pipe)
+ {
+ signal(SIGINT, SIG_IGN);
+ if (out_pipe)
+ {
+ pipe(pipe_out);
+ }
+/*
+ | fork process which will exec command
+ */
+ parent = fork();
+ if (!parent) /* if the child */
+ {
+ if (shell_fork)
+ putchar('\n');
+ if (out_pipe)
+ {
+/*
+ | prepare the child process (soon to exec a shell command) to read from the
+ | pipe (which will be output from the editor's buffer)
+ */
+ close(0);
+ dup(pipe_out[0]);
+ close(pipe_out[0]);
+ close(pipe_out[1]);
+ }
+ for (value = 1; value < 24; value++)
+ signal(value, SIG_DFL);
+ execl(path, last_slash, "-c", string, NULL);
+ printf(exec_err_msg, path);
+ exit(-1);
+ }
+ else /* if the parent */
+ {
+ if (out_pipe)
+ {
+/*
+ | output the contents of the buffer to the pipe (to be read by the
+ | process forked and exec'd above as stdin)
+ */
+ close(pipe_out[0]);
+ line_holder = first_line;
+ while (line_holder != NULL)
+ {
+ write(pipe_out[1], line_holder->line, (line_holder->line_length-1));
+ write(pipe_out[1], "\n", 1);
+ line_holder = line_holder->next_line;
+ }
+ close(pipe_out[1]);
+ out_pipe = FALSE;
+ }
+ do
+ {
+ return_val = wait((int *) 0);
+ }
+ while ((return_val != parent) && (return_val != -1));
+/*
+ | if this process is actually the child of the editor, exit. Here's how it
+ | works:
+ | The editor forks a process. If output must be sent to the command to be
+ | exec'd another process is forked, and that process (the child's child)
+ | will exec the command. In this case, "shell_fork" will be FALSE. If no
+ | output is to be performed to the shell command, "shell_fork" will be TRUE.
+ | If this is the editor process, shell_fork will be true, otherwise this is
+ | the child of the edit process.
+ */
+ if (!shell_fork)
+ exit(0);
+ }
+ signal(SIGINT, edit_abort);
+ }
+ if (shell_fork)
+ {
+ printf(continue_msg);
+ fflush(stdout);
+ while ((in = getchar()) != '\n')
+ ;
+ }
+
+ if (!in_pipe)
+ {
+ fixterm();
+ noecho();
+ nonl();
+ raw();
+ keypad(text_win, TRUE);
+ keypad(com_win, TRUE);
+ if (info_window)
+ clearok(info_win, TRUE);
+ }
+
+ redraw();
+}
+
+void
+set_up_term() /* set up the terminal for operating with ae */
+{
+ if (!curses_initialized)
+ {
+ initscr();
+ savetty();
+ noecho();
+ raw();
+ nonl();
+ curses_initialized = TRUE;
+ }
+
+ if (((LINES > 15) && (COLS >= 80)) && info_window)
+ last_line = LINES - 8;
+ else
+ {
+ info_window = FALSE;
+ last_line = LINES - 2;
+ }
+
+ idlok(stdscr, TRUE);
+ com_win = newwin(1, COLS, (LINES - 1), 0);
+ keypad(com_win, TRUE);
+ idlok(com_win, TRUE);
+ wrefresh(com_win);
+ if (!info_window)
+ text_win = newwin((LINES - 1), COLS, 0, 0);
+ else
+ text_win = newwin((LINES - 7), COLS, 6, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ wrefresh(text_win);
+ help_win = newwin((LINES - 1), COLS, 0, 0);
+ keypad(help_win, TRUE);
+ idlok(help_win, TRUE);
+ if (info_window)
+ {
+ info_type = CONTROL_KEYS;
+ info_win = newwin(6, COLS, 0, 0);
+ werase(info_win);
+ paint_info_win();
+ }
+
+ last_col = COLS - 1;
+ local_LINES = LINES;
+ local_COLS = COLS;
+}
+
+void
+resize_check()
+{
+ if ((LINES == local_LINES) && (COLS == local_COLS))
+ return;
+
+ if (info_window)
+ delwin(info_win);
+ delwin(text_win);
+ delwin(com_win);
+ delwin(help_win);
+ set_up_term();
+ redraw();
+ wrefresh(text_win);
+}
+
+static char item_alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789 ";
+
+int
+menu_op(menu_list)
+struct menu_entries menu_list[];
+{
+ WINDOW *temp_win;
+ int max_width, max_height;
+ int x_off, y_off;
+ int counter;
+ int length;
+ int input;
+ int temp;
+ int list_size;
+ int top_offset; /* offset from top where menu items start */
+ int vert_pos; /* vertical position */
+ int vert_size; /* vertical size for menu list item display */
+ int off_start = 1; /* offset from start of menu items to start display */
+
+
+ /*
+ | determine number and width of menu items
+ */
+
+ list_size = 1;
+ while (menu_list[list_size + 1].item_string != NULL)
+ list_size++;
+ max_width = 0;
+ for (counter = 0; counter <= list_size; counter++)
+ {
+ if ((length = strlen(menu_list[counter].item_string)) > max_width)
+ max_width = length;
+ }
+ max_width += 3;
+ max_width = max(max_width, strlen(cancel_string));
+ max_width = max(max_width, max(strlen(more_above_str), strlen(more_below_str)));
+ max_width += 6;
+
+ /*
+ | make sure that window is large enough to handle menu
+ | if not, print error message and return to calling function
+ */
+
+ if (max_width > COLS)
+ {
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ wprintw(com_win, menu_too_lrg_msg);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(0);
+ }
+
+ top_offset = 0;
+
+ if (list_size > LINES)
+ {
+ max_height = LINES;
+ if (max_height > 11)
+ vert_size = max_height - 8;
+ else
+ vert_size = max_height;
+ }
+ else
+ {
+ vert_size = list_size;
+ max_height = list_size;
+ }
+
+ if (LINES >= (vert_size + 8))
+ {
+ if (menu_list[0].argument != MENU_WARN)
+ max_height = vert_size + 8;
+ else
+ max_height = vert_size + 7;
+ top_offset = 4;
+ }
+ x_off = (COLS - max_width) / 2;
+ y_off = (LINES - max_height - 1) / 2;
+ temp_win = newwin(max_height, max_width, y_off, x_off);
+ keypad(temp_win, TRUE);
+
+ paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size);
+
+ counter = 1;
+ vert_pos = 0;
+ do
+ {
+ if (off_start > 2)
+ wmove(temp_win, (1 + counter + top_offset - off_start), 3);
+ else
+ wmove(temp_win, (counter + top_offset - off_start), 3);
+
+ wrefresh(temp_win);
+ in = wgetch(temp_win);
+ input = in;
+ if (input == -1)
+ exit(0);
+
+ if (((tolower(input) >= 'a') && (tolower(input) <= 'z')) ||
+ ((input >= '0') && (input <= '9')))
+ {
+ if ((tolower(input) >= 'a') && (tolower(input) <= 'z'))
+ {
+ temp = 1 + tolower(input) - 'a';
+ }
+ else if ((input >= '0') && (input <= '9'))
+ {
+ temp = (2 + 'z' - 'a') + (input - '0');
+ }
+
+ if (temp <= list_size)
+ {
+ input = '\n';
+ counter = temp;
+ }
+ }
+ else
+ {
+ switch (input)
+ {
+ case ' ': /* space */
+ case '\004': /* ^d, down */
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ counter++;
+ if (counter > list_size)
+ counter = 1;
+ break;
+ case '\010': /* ^h, backspace*/
+ case '\025': /* ^u, up */
+ case 127: /* ^?, delete */
+ case KEY_BACKSPACE:
+ case KEY_LEFT:
+ case KEY_UP:
+ counter--;
+ if (counter == 0)
+ counter = list_size;
+ break;
+ case '\033': /* escape key */
+ if (menu_list[0].argument != MENU_WARN)
+ counter = 0;
+ break;
+ case '\014': /* ^l */
+ case '\022': /* ^r, redraw */
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win,
+ off_start, vert_size);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (((list_size - off_start) >= (vert_size - 1)) &&
+ (counter > (off_start + vert_size - 3)) &&
+ (off_start > 1))
+ {
+ if (counter == list_size)
+ off_start = (list_size - vert_size) + 2;
+ else
+ off_start++;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ else if ((list_size != vert_size) &&
+ (counter > (off_start + vert_size - 2)))
+ {
+ if (counter == list_size)
+ off_start = 2 + (list_size - vert_size);
+ else if (off_start == 1)
+ off_start = 3;
+ else
+ off_start++;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ else if (counter < off_start)
+ {
+ if (counter <= 2)
+ off_start = 1;
+ else
+ off_start = counter;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ }
+ while ((input != '\r') && (input != '\n') && (counter != 0));
+
+ werase(temp_win);
+ wrefresh(temp_win);
+ delwin(temp_win);
+
+ if ((menu_list[counter].procedure != NULL) ||
+ (menu_list[counter].iprocedure != NULL) ||
+ (menu_list[counter].nprocedure != NULL))
+ {
+ if (menu_list[counter].argument != -1)
+ (*menu_list[counter].iprocedure)(menu_list[counter].argument);
+ else if (menu_list[counter].ptr_argument != NULL)
+ (*menu_list[counter].procedure)(menu_list[counter].ptr_argument);
+ else
+ (*menu_list[counter].nprocedure)();
+ }
+
+ if (info_window)
+ paint_info_win();
+ redraw();
+
+ return(counter);
+}
+
+void
+paint_menu(menu_list, max_width, max_height, list_size, top_offset, menu_win,
+ off_start, vert_size)
+struct menu_entries menu_list[];
+int max_width, max_height, list_size, top_offset;
+WINDOW *menu_win;
+int off_start, vert_size;
+{
+ int counter, temp_int;
+
+ werase(menu_win);
+
+ /*
+ | output top and bottom portions of menu box only if window
+ | large enough
+ */
+
+ if (max_height > vert_size)
+ {
+ wmove(menu_win, 1, 1);
+ if (!nohighlight)
+ wstandout(menu_win);
+ waddch(menu_win, '+');
+ for (counter = 0; counter < (max_width - 4); counter++)
+ waddch(menu_win, '-');
+ waddch(menu_win, '+');
+
+ wmove(menu_win, (max_height - 2), 1);
+ waddch(menu_win, '+');
+ for (counter = 0; counter < (max_width - 4); counter++)
+ waddch(menu_win, '-');
+ waddch(menu_win, '+');
+ wstandend(menu_win);
+ wmove(menu_win, 2, 3);
+ waddstr(menu_win, menu_list[0].item_string);
+ wmove(menu_win, (max_height - 3), 3);
+ if (menu_list[0].argument != MENU_WARN)
+ waddstr(menu_win, cancel_string);
+ }
+ if (!nohighlight)
+ wstandout(menu_win);
+
+ for (counter = 0; counter < (vert_size + top_offset); counter++)
+ {
+ if (top_offset == 4)
+ {
+ temp_int = counter + 2;
+ }
+ else
+ temp_int = counter;
+
+ wmove(menu_win, temp_int, 1);
+ waddch(menu_win, '|');
+ wmove(menu_win, temp_int, (max_width - 2));
+ waddch(menu_win, '|');
+ }
+ wstandend(menu_win);
+
+ if (list_size > vert_size)
+ {
+ if (off_start >= 3)
+ {
+ temp_int = 1;
+ wmove(menu_win, top_offset, 3);
+ waddstr(menu_win, more_above_str);
+ }
+ else
+ temp_int = 0;
+
+ for (counter = off_start;
+ ((temp_int + counter - off_start) < (vert_size - 1));
+ counter++)
+ {
+ wmove(menu_win, (top_offset + temp_int +
+ (counter - off_start)), 3);
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ waddstr(menu_win, menu_list[counter].item_string);
+ }
+
+ wmove(menu_win, (top_offset + (vert_size - 1)), 3);
+
+ if (counter == list_size)
+ {
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ wprintw(menu_win, menu_list[counter].item_string);
+ }
+ else
+ wprintw(menu_win, more_below_str);
+ }
+ else
+ {
+ for (counter = 1; counter <= list_size; counter++)
+ {
+ wmove(menu_win, (top_offset + counter - 1), 3);
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ waddstr(menu_win, menu_list[counter].item_string);
+ }
+ }
+}
+
+void
+help()
+{
+ int counter;
+
+ werase(help_win);
+ clearok(help_win, TRUE);
+ for (counter = 0; counter < 22; counter++)
+ {
+ wmove(help_win, counter, 0);
+ waddstr(help_win, (emacs_keys_mode) ?
+ emacs_help_text[counter] : help_text[counter]);
+ }
+ wrefresh(help_win);
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ wprintw(com_win, press_any_key_msg);
+ wrefresh(com_win);
+ counter = wgetch(com_win);
+ if (counter == -1)
+ exit(0);
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ werase(help_win);
+ wrefresh(help_win);
+ wrefresh(com_win);
+ redraw();
+}
+
+void
+paint_info_win()
+{
+ int counter;
+
+ if (!info_window)
+ return;
+
+ werase(info_win);
+ for (counter = 0; counter < 5; counter++)
+ {
+ wmove(info_win, counter, 0);
+ wclrtoeol(info_win);
+ if (info_type == CONTROL_KEYS)
+ waddstr(info_win, (emacs_keys_mode) ?
+ emacs_control_keys[counter] : control_keys[counter]);
+ else if (info_type == COMMANDS)
+ waddstr(info_win, command_strings[counter]);
+ }
+ wmove(info_win, 5, 0);
+ if (!nohighlight)
+ wstandout(info_win);
+ waddstr(info_win, "===============================================================================");
+ wstandend(info_win);
+ wrefresh(info_win);
+}
+
+void
+no_info_window()
+{
+ if (!info_window)
+ return;
+ delwin(info_win);
+ delwin(text_win);
+ info_window = FALSE;
+ last_line = LINES - 2;
+ text_win = newwin((LINES - 1), COLS, 0, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ clearok(text_win, TRUE);
+ midscreen(scr_vert, point);
+ wrefresh(text_win);
+ clear_com_win = TRUE;
+}
+
+void
+create_info_window()
+{
+ if (info_window)
+ return;
+ last_line = LINES - 8;
+ delwin(text_win);
+ text_win = newwin((LINES - 7), COLS, 6, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ werase(text_win);
+ info_window = TRUE;
+ info_win = newwin(6, COLS, 0, 0);
+ werase(info_win);
+ info_type = CONTROL_KEYS;
+ midscreen(min(scr_vert, last_line), point);
+ clearok(info_win, TRUE);
+ paint_info_win();
+ wrefresh(text_win);
+ clear_com_win = TRUE;
+}
+
+int
+file_op(arg)
+int arg;
+{
+ char *string;
+ int flag;
+
+ if (restrict_mode())
+ {
+ return(0);
+ }
+
+ if (arg == READ_FILE)
+ {
+ string = get_string(file_read_prompt_str, TRUE);
+ recv_file = TRUE;
+ tmp_file = resolve_name(string);
+ check_fp();
+ if (tmp_file != string)
+ free(tmp_file);
+ free(string);
+ }
+ else if (arg == WRITE_FILE)
+ {
+ string = get_string(file_write_prompt_str, TRUE);
+ tmp_file = resolve_name(string);
+ write_file(tmp_file);
+ if (tmp_file != string)
+ free(tmp_file);
+ free(string);
+ }
+ else if (arg == SAVE_FILE)
+ {
+ /*
+ | changes made here should be reflected in finish()
+ */
+
+ if (in_file_name)
+ flag = TRUE;
+ else
+ flag = FALSE;
+
+ string = in_file_name;
+ if ((string == NULL) || (*string == (char) NULL))
+ string = get_string(save_file_name_prompt, TRUE);
+ if ((string == NULL) || (*string == (char) NULL))
+ {
+ wmove(com_win, 0, 0);
+ wprintw(com_win, file_not_saved_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(0);
+ }
+ if (!flag)
+ {
+ tmp_file = resolve_name(string);
+ if (tmp_file != string)
+ {
+ free(string);
+ string = tmp_file;
+ }
+ }
+ if (write_file(string))
+ {
+ in_file_name = string;
+ text_changes = FALSE;
+ }
+ else if (!flag)
+ free(string);
+ }
+ return(0);
+}
+
+void
+shell_op()
+{
+ char *string;
+
+ if (((string = get_string(shell_prompt, TRUE)) != NULL) &&
+ (*string != (char) NULL))
+ {
+ sh_command(string);
+ free(string);
+ }
+}
+
+void
+leave_op()
+{
+ if (text_changes)
+ {
+ menu_op(leave_menu);
+ }
+ else
+ quit(TRUE);
+}
+
+void
+redraw()
+{
+ if (info_window)
+ {
+ clearok(info_win, TRUE);
+ paint_info_win();
+ }
+ else
+ clearok(text_win, TRUE);
+ midscreen(scr_vert, point);
+}
+
+/*
+ | The following routines will "format" a paragraph (as defined by a
+ | block of text with blank lines before and after the block).
+ */
+
+int
+Blank_Line(test_line) /* test if line has any non-space characters */
+struct text *test_line;
+{
+ char *line;
+ int length;
+
+ if (test_line == NULL)
+ return(TRUE);
+
+ length = 1;
+ line = test_line->line;
+
+ /*
+ | To handle troff/nroff documents, consider a line with a
+ | period ('.') in the first column to be blank. To handle mail
+ | messages with included text, consider a line with a '>' blank.
+ */
+
+ if ((*line == '.') || (*line == '>'))
+ return(TRUE);
+
+ while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length))
+ {
+ length++;
+ line++;
+ }
+ if (length != test_line->line_length)
+ return(FALSE);
+ else
+ return(TRUE);
+}
+
+void
+Format() /* format the paragraph according to set margins */
+{
+ int string_count;
+ int offset;
+ int temp_case;
+ int status;
+ int tmp_af;
+ int counter;
+ char *line;
+ char *tmp_srchstr;
+ char *temp1, *temp2;
+ char *temp_dword;
+ char temp_d_char = d_char;
+
+/*
+ | if observ_margins is not set, or the current line is blank,
+ | do not format the current paragraph
+ */
+
+ if ((!observ_margins) || (Blank_Line(curr_line)))
+ return;
+
+/*
+ | save the currently set flags, and clear them
+ */
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | get current position in paragraph, so after formatting, the cursor
+ | will be in the same relative position
+ */
+
+ tmp_af = auto_format;
+ auto_format = FALSE;
+ offset = position;
+ if (position != 1)
+ prev_word();
+ temp_dword = d_word;
+ d_word = NULL;
+ temp_case = case_sen;
+ case_sen = TRUE;
+ tmp_srchstr = srch_str;
+ temp2 = srch_str = (char *) malloc(1 + curr_line->line_length - position);
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ offset -= position;
+ counter = position;
+ line = temp1 = point;
+ while ((*temp1 != (char) NULL) && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
+ {
+ *temp2 = *temp1;
+ temp2++;
+ temp1++;
+ counter++;
+ }
+ *temp2 = (char) NULL;
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+ string_count = 0;
+ status = TRUE;
+ while ((line != point) && (status))
+ {
+ status = search(FALSE);
+ string_count++;
+ }
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | now get back to the start of the paragraph to start formatting
+ */
+
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+ observ_margins = FALSE;
+
+/*
+ | Start going through lines, putting spaces at end of lines if they do
+ | not already exist. Append lines together to get one long line, and
+ | eliminate spacing at begin of lines.
+ */
+
+ while (!Blank_Line(curr_line->next_line))
+ {
+ eol();
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+ del_char();
+ if ((*point == ' ') || (*point == '\t'))
+ del_word();
+ }
+
+/*
+ | Now there is one long line. Eliminate extra spaces within the line
+ | after the first word (so as not to blow away any indenting the user
+ | may have put in).
+ */
+
+ bol();
+ adv_word();
+ while (position < curr_line->line_length)
+ {
+ if ((*point == ' ') && (*(point + 1) == ' '))
+ del_char();
+ else
+ right(TRUE);
+ }
+
+/*
+ | Now make sure there are two spaces after a '.'.
+ */
+
+ bol();
+ while (position < curr_line->line_length)
+ {
+ if ((*point == '.') && (*(point + 1) == ' '))
+ {
+ right(TRUE);
+ insert(' ');
+ insert(' ');
+ while (*point == ' ')
+ del_char();
+ }
+ right(TRUE);
+ }
+
+ observ_margins = TRUE;
+ bol();
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | create lines between margins
+ */
+
+ while (position < curr_line->line_length)
+ {
+ while ((scr_pos < right_margin) && (position < curr_line->line_length))
+ right(TRUE);
+ if (position < curr_line->line_length)
+ {
+ prev_word();
+ if (position == 1)
+ adv_word();
+ insert_line(TRUE);
+ }
+ }
+
+/*
+ | go back to begin of paragraph, put cursor back to original position
+ */
+
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+/*
+ | find word cursor was in
+ */
+
+ while ((status) && (string_count > 0))
+ {
+ search(FALSE);
+ string_count--;
+ }
+
+/*
+ | offset the cursor to where it was before from the start of the word
+ */
+
+ while (offset > 0)
+ {
+ offset--;
+ right(TRUE);
+ }
+
+/*
+ | reset flags and strings to what they were before formatting
+ */
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = temp_dword;
+ case_sen = temp_case;
+ free(srch_str);
+ srch_str = tmp_srchstr;
+ d_char = temp_d_char;
+ auto_format = tmp_af;
+
+ midscreen(scr_vert, point);
+ werase(com_win);
+ wrefresh(com_win);
+}
+
+char *init_name[3] = {
+ "/usr/share/misc/init.ee",
+ NULL,
+ ".init.ee"
+ };
+
+void
+ee_init() /* check for init file and read it if it exists */
+{
+ FILE *init_file;
+ char *string;
+ char *str1;
+ char *str2;
+ char *home;
+ int counter;
+ int temp_int;
+
+ string = getenv("HOME");
+ if (!string)
+ string = "/root"; /* Set to reasonable default so we don't crash */
+ str1 = home = malloc(strlen(string)+10);
+ strcpy(home, string);
+ strcat(home, "/.init.ee");
+ init_name[1] = home;
+ string = malloc(512);
+
+ for (counter = 0; counter < 3; counter++)
+ {
+ if (!(access(init_name[counter], 4)))
+ {
+ init_file = fopen(init_name[counter], "r");
+ while ((str2 = fgets(string, 512, init_file)) != NULL)
+ {
+ str1 = str2 = string;
+ while (*str2 != '\n')
+ str2++;
+ *str2 = (char) NULL;
+
+ if (unique_test(string, init_strings) != 1)
+ continue;
+
+ if (compare(str1, CASE, FALSE))
+ case_sen = TRUE;
+ else if (compare(str1, NOCASE, FALSE))
+ case_sen = FALSE;
+ else if (compare(str1, EXPAND, FALSE))
+ expand_tabs = TRUE;
+ else if (compare(str1, NOEXPAND, FALSE))
+ expand_tabs = FALSE;
+ else if (compare(str1, INFO, FALSE))
+ info_window = TRUE;
+ else if (compare(str1, NOINFO, FALSE))
+ info_window = FALSE;
+ else if (compare(str1, MARGINS, FALSE))
+ observ_margins = TRUE;
+ else if (compare(str1, NOMARGINS, FALSE))
+ observ_margins = FALSE;
+ else if (compare(str1, AUTOFORMAT, FALSE))
+ {
+ auto_format = TRUE;
+ observ_margins = TRUE;
+ }
+ else if (compare(str1, NOAUTOFORMAT, FALSE))
+ auto_format = FALSE;
+ else if (compare(str1, Echo, FALSE))
+ {
+ str1 = next_word(str1);
+ if (*str1 != (char) NULL)
+ echo_string(str1);
+ }
+ else if (compare(str1, PRINTCOMMAND, FALSE))
+ {
+ str1 = next_word(str1);
+ print_command = malloc(strlen(str1)+1);
+ strcpy(print_command, str1);
+ }
+ else if (compare(str1, RIGHTMARGIN, FALSE))
+ {
+ str1 = next_word(str1);
+ if ((*str1 >= '0') && (*str1 <= '9'))
+ {
+ temp_int = atoi(str1);
+ if (temp_int > 0)
+ right_margin = temp_int;
+ }
+ }
+ else if (compare(str1, HIGHLIGHT, FALSE))
+ nohighlight = FALSE;
+ else if (compare(str1, NOHIGHLIGHT, FALSE))
+ nohighlight = TRUE;
+ else if (compare(str1, EIGHTBIT, FALSE))
+ eightbit = TRUE;
+ else if (compare(str1, NOEIGHTBIT, FALSE))
+ eightbit = FALSE;
+ else if (compare(str1, EMACS_string, FALSE))
+ emacs_keys_mode = TRUE;
+ else if (compare(str1, NOEMACS_string, FALSE))
+ emacs_keys_mode = FALSE;
+ }
+ fclose(init_file);
+ }
+ }
+ free(string);
+ free(home);
+}
+
+/*
+ | Save current configuration to .init.ee file in the current directory.
+ */
+
+void
+dump_ee_conf()
+{
+ FILE *init_file;
+ FILE *old_init_file = NULL;
+ char *file_name = ".init.ee";
+ char *home_dir = "~/.init.ee";
+ char buffer[512];
+ struct stat buf;
+ char *string;
+ int length;
+ int option = 0;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+
+ option = menu_op(config_dump_menu);
+
+ werase(com_win);
+ wmove(com_win, 0, 0);
+
+ if (option == 0)
+ {
+ wprintw(com_win, conf_not_saved_msg);
+ wrefresh(com_win);
+ return;
+ }
+ else if (option == 2)
+ file_name = resolve_name(home_dir);
+
+ /*
+ | If a .init.ee file exists, move it to .init.ee.old.
+ */
+
+ if (stat(file_name, &buf) != -1)
+ {
+ sprintf(buffer, "%s.old", file_name);
+ unlink(buffer);
+ link(file_name, buffer);
+ unlink(file_name);
+ old_init_file = fopen(buffer, "r");
+ }
+
+ init_file = fopen(file_name, "w");
+ if (init_file == NULL)
+ {
+ wprintw(com_win, conf_dump_err_msg);
+ wrefresh(com_win);
+ return;
+ }
+
+ if (old_init_file != NULL)
+ {
+ /*
+ | Copy non-configuration info into new .init.ee file.
+ */
+ while ((string = fgets(buffer, 512, old_init_file)) != NULL)
+ {
+ length = strlen(string);
+ string[length - 1] = (char) NULL;
+
+ if (unique_test(string, init_strings) == 1)
+ {
+ if (compare(string, Echo, FALSE))
+ {
+ fprintf(init_file, "%s\n", string);
+ }
+ }
+ else
+ fprintf(init_file, "%s\n", string);
+ }
+
+ fclose(old_init_file);
+ }
+
+ fprintf(init_file, "%s\n", case_sen ? CASE : NOCASE);
+ fprintf(init_file, "%s\n", expand_tabs ? EXPAND : NOEXPAND);
+ fprintf(init_file, "%s\n", info_window ? INFO : NOINFO );
+ fprintf(init_file, "%s\n", observ_margins ? MARGINS : NOMARGINS );
+ fprintf(init_file, "%s\n", auto_format ? AUTOFORMAT : NOAUTOFORMAT );
+ fprintf(init_file, "%s %s\n", PRINTCOMMAND, print_command);
+ fprintf(init_file, "%s %d\n", RIGHTMARGIN, right_margin);
+ fprintf(init_file, "%s\n", nohighlight ? NOHIGHLIGHT : HIGHLIGHT );
+ fprintf(init_file, "%s\n", eightbit ? EIGHTBIT : NOEIGHTBIT );
+ fprintf(init_file, "%s\n", emacs_keys_mode ? EMACS_string : NOEMACS_string );
+
+ fclose(init_file);
+
+ wprintw(com_win, conf_dump_success_msg, file_name);
+ wrefresh(com_win);
+
+ if ((option == 2) && (file_name != home_dir))
+ {
+ free(file_name);
+ }
+}
+
+void
+echo_string(string) /* echo the given string */
+char *string;
+{
+ char *temp;
+ int Counter;
+
+ temp = string;
+ while (*temp != (char) NULL)
+ {
+ if (*temp == '\\')
+ {
+ temp++;
+ if (*temp == 'n')
+ putchar('\n');
+ else if (*temp == 't')
+ putchar('\t');
+ else if (*temp == 'b')
+ putchar('\b');
+ else if (*temp == 'r')
+ putchar('\r');
+ else if (*temp == 'f')
+ putchar('\f');
+ else if ((*temp == 'e') || (*temp == 'E'))
+ putchar('\033'); /* escape */
+ else if (*temp == '\\')
+ putchar('\\');
+ else if (*temp == '\'')
+ putchar('\'');
+ else if ((*temp >= '0') && (*temp <= '9'))
+ {
+ Counter = 0;
+ while ((*temp >= '0') && (*temp <= '9'))
+ {
+ Counter = (8 * Counter) + (*temp - '0');
+ temp++;
+ }
+ putchar(Counter);
+ temp--;
+ }
+ temp++;
+ }
+ else
+ {
+ putchar(*temp);
+ temp++;
+ }
+ }
+
+ fflush(stdout);
+}
+
+void
+spell_op() /* check spelling of words in the editor */
+{
+ if (restrict_mode())
+ {
+ return;
+ }
+ top(); /* go to top of file */
+ insert_line(FALSE); /* create two blank lines */
+ insert_line(FALSE);
+ top();
+ command(shell_echo_msg);
+ adv_line();
+ wmove(com_win, 0, 0);
+ wprintw(com_win, spell_in_prog_msg);
+ wrefresh(com_win);
+ command("<>!spell"); /* send contents of buffer to command 'spell'
+ and read the results back into the editor */
+}
+
+void
+ispell_op()
+{
+ char name[128];
+ char string[256];
+ int pid;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+ pid = getpid();
+ sprintf(name, "/tmp/ee.%d", pid);
+ if (write_file(name))
+ {
+ sprintf(string, "ispell %s", name);
+ sh_command(string);
+ delete_text();
+ tmp_file = name;
+ recv_file = TRUE;
+ check_fp();
+ unlink(name);
+ }
+}
+
+int
+first_word_len(test_line)
+struct text *test_line;
+{
+ int counter;
+ char *pnt;
+
+ if (test_line == NULL)
+ return(0);
+
+ pnt = test_line->line;
+ if ((pnt == NULL) || (*pnt == (char) NULL) ||
+ (*pnt == '.') || (*pnt == '>'))
+ return(0);
+
+ if ((*pnt == ' ') || (*pnt == '\t'))
+ {
+ pnt = next_word(pnt);
+ }
+
+ if (*pnt == (char) NULL)
+ return(0);
+
+ counter = 0;
+ while ((*pnt != (char) NULL) && ((*pnt != ' ') && (*pnt != '\t')))
+ {
+ pnt++;
+ counter++;
+ }
+ while ((*pnt != (char) NULL) && ((*pnt == ' ') || (*pnt == '\t')))
+ {
+ pnt++;
+ counter++;
+ }
+ return(counter);
+}
+
+void
+Auto_Format() /* format the paragraph according to set margins */
+{
+ int string_count;
+ int offset;
+ int temp_case;
+ int word_len;
+ int temp_dwl;
+ int tmp_d_line_length;
+ int leave_loop = FALSE;
+ int status;
+ int counter;
+ char not_blank;
+ char *line;
+ char *tmp_srchstr;
+ char *temp1, *temp2;
+ char *temp_dword;
+ char temp_d_char = d_char;
+ char *tmp_d_line;
+
+/*
+ | if observ_margins is not set, or the current line is blank,
+ | do not format the current paragraph
+ */
+
+ if ((!observ_margins) || (Blank_Line(curr_line)))
+ return;
+
+/*
+ | get current position in paragraph, so after formatting, the cursor
+ | will be in the same relative position
+ */
+
+ tmp_d_line = d_line;
+ tmp_d_line_length = dlt_line->line_length;
+ d_line = NULL;
+ auto_format = FALSE;
+ offset = position;
+ if ((position != 1) && ((*point == ' ') || (*point == '\t') || (position == curr_line->line_length) || (*point == (char) NULL)))
+ prev_word();
+ temp_dword = d_word;
+ temp_dwl = d_wrd_len;
+ d_wrd_len = 0;
+ d_word = NULL;
+ temp_case = case_sen;
+ case_sen = TRUE;
+ tmp_srchstr = srch_str;
+ temp2 = srch_str = (char *) malloc(1 + curr_line->line_length - position);
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ offset -= position;
+ counter = position;
+ line = temp1 = point;
+ while ((*temp1 != (char) NULL) && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
+ {
+ *temp2 = *temp1;
+ temp2++;
+ temp1++;
+ counter++;
+ }
+ *temp2 = (char) NULL;
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+ string_count = 0;
+ status = TRUE;
+ while ((line != point) && (status))
+ {
+ status = search(FALSE);
+ string_count++;
+ }
+
+/*
+ | now get back to the start of the paragraph to start checking
+ */
+
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+/*
+ | Start going through lines, putting spaces at end of lines if they do
+ | not already exist. Check line length, and move words to the next line
+ | if they cross the margin. Then get words from the next line if they
+ | will fit in before the margin.
+ */
+
+ counter = 0;
+
+ while (!leave_loop)
+ {
+ if (position != curr_line->line_length)
+ eol();
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+
+ not_blank = FALSE;
+
+ /*
+ | fill line if first word on next line will fit
+ | in the line without crossing the margin
+ */
+
+ while ((curr_line->next_line != NULL) &&
+ ((word_len = first_word_len(curr_line->next_line)) > 0)
+ && ((scr_pos + word_len) < right_margin))
+ {
+ adv_line();
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ del_word();
+ if (position != 1)
+ bol();
+
+ /*
+ | We know this line was not blank before, so
+ | make sure that it doesn't have one of the
+ | leading characters that indicate the line
+ | should not be modified.
+ |
+ | We also know that this character should not
+ | be left as the first character of this line.
+ */
+
+ if ((Blank_Line(curr_line)) &&
+ (curr_line->line[0] != '.') &&
+ (curr_line->line[0] != '>'))
+ {
+ del_line();
+ not_blank = FALSE;
+ }
+ else
+ not_blank = TRUE;
+
+ /*
+ | go to end of previous line
+ */
+ left(TRUE);
+ undel_word();
+ eol();
+ /*
+ | make sure there's a space at the end of the line
+ */
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+ }
+
+ /*
+ | make sure line does not cross right margin
+ */
+
+ while (right_margin <= scr_pos)
+ {
+ prev_word();
+ if (position != 1)
+ {
+ del_word();
+ if (Blank_Line(curr_line->next_line))
+ insert_line(TRUE);
+ else
+ adv_line();
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ undel_word();
+ not_blank = TRUE;
+ if (position != 1)
+ bol();
+ left(TRUE);
+ }
+ }
+
+ if ((!Blank_Line(curr_line->next_line)) || (not_blank))
+ {
+ adv_line();
+ counter++;
+ }
+ else
+ leave_loop = TRUE;
+ }
+
+/*
+ | go back to begin of paragraph, put cursor back to original position
+ */
+
+ if (position != 1)
+ bol();
+ while ((counter-- > 0) || (!Blank_Line(curr_line->prev_line)))
+ bol();
+
+/*
+ | find word cursor was in
+ */
+
+ status = TRUE;
+ while ((status) && (string_count > 0))
+ {
+ status = search(FALSE);
+ string_count--;
+ }
+
+/*
+ | offset the cursor to where it was before from the start of the word
+ */
+
+ while (offset > 0)
+ {
+ offset--;
+ right(TRUE);
+ }
+
+ if ((string_count > 0) && (offset < 0))
+ {
+ while (offset < 0)
+ {
+ offset++;
+ left(TRUE);
+ }
+ }
+
+/*
+ | reset flags and strings to what they were before formatting
+ */
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = temp_dword;
+ d_wrd_len = temp_dwl;
+ case_sen = temp_case;
+ free(srch_str);
+ srch_str = tmp_srchstr;
+ d_char = temp_d_char;
+ auto_format = TRUE;
+ dlt_line->line_length = tmp_d_line_length;
+ d_line = tmp_d_line;
+
+ formatted = TRUE;
+ midscreen(scr_vert, point);
+}
+
+void
+modes_op()
+{
+ int ret_value;
+ int counter;
+ char *string;
+
+ do
+ {
+ sprintf(modes_menu[1].item_string, "%s %s", mode_strings[1],
+ (expand_tabs ? ON : OFF));
+ sprintf(modes_menu[2].item_string, "%s %s", mode_strings[2],
+ (case_sen ? ON : OFF));
+ sprintf(modes_menu[3].item_string, "%s %s", mode_strings[3],
+ (observ_margins ? ON : OFF));
+ sprintf(modes_menu[4].item_string, "%s %s", mode_strings[4],
+ (auto_format ? ON : OFF));
+ sprintf(modes_menu[5].item_string, "%s %s", mode_strings[5],
+ (eightbit ? ON : OFF));
+ sprintf(modes_menu[6].item_string, "%s %s", mode_strings[6],
+ (info_window ? ON : OFF));
+ sprintf(modes_menu[7].item_string, "%s %s", mode_strings[7],
+ (emacs_keys_mode ? ON : OFF));
+ sprintf(modes_menu[8].item_string, "%s %d", mode_strings[8],
+ right_margin);
+
+ ret_value = menu_op(modes_menu);
+
+ switch (ret_value)
+ {
+ case 1:
+ expand_tabs = !expand_tabs;
+ break;
+ case 2:
+ case_sen = !case_sen;
+ break;
+ case 3:
+ observ_margins = !observ_margins;
+ break;
+ case 4:
+ auto_format = !auto_format;
+ if (auto_format)
+ observ_margins = TRUE;
+ break;
+ case 5:
+ eightbit = !eightbit;
+ redraw();
+ wnoutrefresh(text_win);
+ break;
+ case 6:
+ if (info_window)
+ no_info_window();
+ else
+ create_info_window();
+ break;
+ case 7:
+ emacs_keys_mode = !emacs_keys_mode;
+ if (info_window)
+ paint_info_win();
+ break;
+ case 8:
+ string = get_string(margin_prompt, TRUE);
+ if (string != NULL)
+ {
+ counter = atoi(string);
+ if (counter > 0)
+ right_margin = counter;
+ free(string);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while (ret_value != 0);
+}
+
+char *
+is_in_string(string, substring) /* a strchr() look-alike for systems without
+ strchr() */
+char * string, *substring;
+{
+ char *full, *sub;
+
+ for (sub = substring; (sub != NULL) && (*sub != (char)NULL); sub++)
+ {
+ for (full = string; (full != NULL) && (*full != (char)NULL);
+ full++)
+ {
+ if (*sub == *full)
+ return(full);
+ }
+ }
+ return(NULL);
+}
+
+/*
+ | handle names of the form "~/file", "~user/file",
+ | "$HOME/foo", "~/$FOO", etc.
+ */
+
+char *
+resolve_name(name)
+char *name;
+{
+ char long_buffer[1024];
+ char short_buffer[128];
+ char *buffer;
+ char *slash;
+ char *tmp;
+ char *start_of_var;
+ int offset;
+ int index;
+ int counter;
+ struct passwd *user;
+
+ if (name[0] == '~')
+ {
+ if (name[1] == '/')
+ {
+ index = getuid();
+ user = (struct passwd *) getpwuid(index);
+ slash = name + 1;
+ }
+ else
+ {
+ slash = strchr(name, '/');
+ if (slash == NULL)
+ return(name);
+ *slash = (char) NULL;
+ user = (struct passwd *) getpwnam((name + 1));
+ *slash = '/';
+ }
+ if (user == NULL)
+ {
+ return(name);
+ }
+ buffer = malloc(strlen(user->pw_dir) + strlen(slash) + 1);
+ strcpy(buffer, user->pw_dir);
+ strcat(buffer, slash);
+ }
+ else
+ buffer = name;
+
+ if (is_in_string(buffer, "$"))
+ {
+ tmp = buffer;
+ index = 0;
+
+ while ((*tmp != (char) NULL) && (index < 1024))
+ {
+
+ while ((*tmp != (char) NULL) && (*tmp != '$') &&
+ (index < 1024))
+ {
+ long_buffer[index] = *tmp;
+ tmp++;
+ index++;
+ }
+
+ if ((*tmp == '$') && (index < 1024))
+ {
+ counter = 0;
+ start_of_var = tmp;
+ tmp++;
+ if (*tmp == '{') /* } */ /* bracketed variable name */
+ {
+ tmp++; /* { */
+ while ((*tmp != (char) NULL) &&
+ (*tmp != '}') &&
+ (counter < 128))
+ {
+ short_buffer[counter] = *tmp;
+ counter++;
+ tmp++;
+ } /* { */
+ if (*tmp == '}')
+ tmp++;
+ }
+ else
+ {
+ while ((*tmp != (char) NULL) &&
+ (*tmp != '/') &&
+ (*tmp != '$') &&
+ (counter < 128))
+ {
+ short_buffer[counter] = *tmp;
+ counter++;
+ tmp++;
+ }
+ }
+ short_buffer[counter] = (char) NULL;
+ if ((slash = getenv(short_buffer)) != NULL)
+ {
+ offset = strlen(slash);
+ if ((offset + index) < 1024)
+ strcpy(&long_buffer[index], slash);
+ index += offset;
+ }
+ else
+ {
+ while ((start_of_var != tmp) && (index < 1024))
+ {
+ long_buffer[index] = *start_of_var;
+ start_of_var++;
+ index++;
+ }
+ }
+ }
+ }
+
+ if (index == 1024)
+ return(buffer);
+ else
+ long_buffer[index] = (char) NULL;
+
+ if (name != buffer)
+ free(buffer);
+ buffer = malloc(index + 1);
+ strcpy(buffer, long_buffer);
+ }
+
+ return(buffer);
+}
+
+int
+restrict_mode()
+{
+ if (!restricted)
+ return(FALSE);
+
+ wmove(com_win, 0, 0);
+ wprintw(com_win, restricted_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(TRUE);
+}
+
+/*
+ | The following routine tests the input string against the list of
+ | strings, to determine if the string is a unique match with one of the
+ | valid values.
+ */
+
+int
+unique_test(string, list)
+char *string;
+char *list[];
+{
+ int counter;
+ int num_match;
+ int result;
+
+ num_match = 0;
+ counter = 0;
+ while (list[counter] != NULL)
+ {
+ result = compare(string, list[counter], FALSE);
+ if (result)
+ num_match++;
+ counter++;
+ }
+ return(num_match);
+}
+
+#ifndef NO_CATGETS
+/*
+ | Get the catalog entry, and if it got it from the catalog,
+ | make a copy, since the buffer will be overwritten by the
+ | next call to catgets().
+ */
+
+char *
+catgetlocal(number, string)
+int number;
+char *string;
+{
+ char *temp1;
+ char *temp2;
+
+ temp1 = catgets(catalog, 1, number, string);
+ if (temp1 != string)
+ {
+ temp2 = malloc(strlen(temp1) + 1);
+ strcpy(temp2, temp1);
+ temp1 = temp2;
+ }
+ return(temp1);
+}
+#endif /* NO_CATGETS */
+
+/*
+ | The following is to allow for using message catalogs which allow
+ | the software to be 'localized', that is, to use different languages
+ | all with the same binary. For more information, see your system
+ | documentation, or the X/Open Internationalization Guide.
+ */
+
+void
+strings_init()
+{
+ int counter;
+
+#ifndef NO_CATGETS
+ setlocale(LC_ALL, "");
+ catalog = catopen("ee", 0);
+#endif /* NO_CATGETS */
+
+ modes_menu[0].item_string = catgetlocal( 1, "modes menu");
+ mode_strings[1] = catgetlocal( 2, "tabs to spaces ");
+ mode_strings[2] = catgetlocal( 3, "case sensitive search");
+ mode_strings[3] = catgetlocal( 4, "margins observed ");
+ mode_strings[4] = catgetlocal( 5, "auto-paragraph format");
+ mode_strings[5] = catgetlocal( 6, "eightbit characters ");
+ mode_strings[6] = catgetlocal( 7, "info window ");
+ mode_strings[8] = catgetlocal( 8, "right margin ");
+ leave_menu[0].item_string = catgetlocal( 9, "leave menu");
+ leave_menu[1].item_string = catgetlocal( 10, "save changes");
+ leave_menu[2].item_string = catgetlocal( 11, "no save");
+ file_menu[0].item_string = catgetlocal( 12, "file menu");
+ file_menu[1].item_string = catgetlocal( 13, "read a file");
+ file_menu[2].item_string = catgetlocal( 14, "write a file");
+ file_menu[3].item_string = catgetlocal( 15, "save file");
+ file_menu[4].item_string = catgetlocal( 16, "print editor contents");
+ search_menu[0].item_string = catgetlocal( 17, "search menu");
+ search_menu[1].item_string = catgetlocal( 18, "search for ...");
+ search_menu[2].item_string = catgetlocal( 19, "search");
+ spell_menu[0].item_string = catgetlocal( 20, "spell menu");
+ spell_menu[1].item_string = catgetlocal( 21, "use 'spell'");
+ spell_menu[2].item_string = catgetlocal( 22, "use 'ispell'");
+ misc_menu[0].item_string = catgetlocal( 23, "miscellaneous menu");
+ misc_menu[1].item_string = catgetlocal( 24, "format paragraph");
+ misc_menu[2].item_string = catgetlocal( 25, "shell command");
+ misc_menu[3].item_string = catgetlocal( 26, "check spelling");
+ main_menu[0].item_string = catgetlocal( 27, "main menu");
+ main_menu[1].item_string = catgetlocal( 28, "leave editor");
+ main_menu[2].item_string = catgetlocal( 29, "help");
+ main_menu[3].item_string = catgetlocal( 30, "file operations");
+ main_menu[4].item_string = catgetlocal( 31, "redraw screen");
+ main_menu[5].item_string = catgetlocal( 32, "settings");
+ main_menu[6].item_string = catgetlocal( 33, "search");
+ main_menu[7].item_string = catgetlocal( 34, "miscellaneous");
+ help_text[0] = catgetlocal( 35, "Control keys: ");
+ help_text[1] = catgetlocal( 36, "^a ascii code ^i tab ^r right ");
+ help_text[2] = catgetlocal( 37, "^b bottom of text ^j newline ^t top of text ");
+ help_text[3] = catgetlocal( 38, "^c command ^k delete char ^u up ");
+ help_text[4] = catgetlocal( 39, "^d down ^l left ^v undelete word ");
+ help_text[5] = catgetlocal( 40, "^e search prompt ^m newline ^w delete word ");
+ help_text[6] = catgetlocal( 41, "^f undelete char ^n next page ^x search ");
+ help_text[7] = catgetlocal( 42, "^g begin of line ^o end of line ^y delete line ");
+ help_text[8] = catgetlocal( 43, "^h backspace ^p prev page ^z undelete line ");
+ help_text[9] = catgetlocal( 44, "^[ (escape) menu ESC-Enter: exit ee ");
+ help_text[10] = catgetlocal( 45, " ");
+ help_text[11] = catgetlocal( 46, "Commands: ");
+ help_text[12] = catgetlocal( 47, "help : get this info file : print file name ");
+ help_text[13] = catgetlocal( 48, "read : read a file char : ascii code of char ");
+ help_text[14] = catgetlocal( 49, "write : write a file case : case sensitive search ");
+ help_text[15] = catgetlocal( 50, "exit : leave and save nocase : case insensitive search ");
+ help_text[16] = catgetlocal( 51, "quit : leave, no save !cmd : execute \"cmd\" in shell ");
+ help_text[17] = catgetlocal( 52, "line : display line # 0-9 : go to line \"#\" ");
+ help_text[18] = catgetlocal( 53, "expand : expand tabs noexpand: do not expand tabs ");
+ help_text[19] = catgetlocal( 54, " ");
+ help_text[20] = catgetlocal( 55, " ee [-i] [-e] [-h] [file(s)] ");
+ help_text[21] = catgetlocal( 56, " -i : no information window -e : do not expand tabs -h : no highlight ");
+ control_keys[0] = catgetlocal( 57, "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page ");
+ control_keys[1] = catgetlocal( 58, "^a ascii code ^x search ^z undelete line ^d down ^n next page ");
+ control_keys[2] = catgetlocal( 59, "^b bottom of text ^g begin of line ^w delete word ^l left ");
+ control_keys[3] = catgetlocal( 60, "^t top of text ^o end of line ^v undelete word ^r right ");
+ control_keys[4] = catgetlocal( 61, "^c command ^k delete char ^f undelete char ESC-Enter: exit ee ");
+ command_strings[0] = catgetlocal( 62, "help : get help info |file : print file name |line : print line # ");
+ command_strings[1] = catgetlocal( 63, "read : read a file |char : ascii code of char |0-9 : go to line \"#\"");
+ command_strings[2] = catgetlocal( 64, "write: write a file |case : case sensitive search |exit : leave and save ");
+ command_strings[3] = catgetlocal( 65, "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save");
+ command_strings[4] = catgetlocal( 66, "expand: expand tabs |noexpand: do not expand tabs ");
+ com_win_message = catgetlocal( 67, " press Escape (^[) for menu");
+ no_file_string = catgetlocal( 68, "no file");
+ ascii_code_str = catgetlocal( 69, "ascii code: ");
+ printer_msg_str = catgetlocal( 70, "sending contents of buffer to \"%s\" ");
+ command_str = catgetlocal( 71, "command: ");
+ file_write_prompt_str = catgetlocal( 72, "name of file to write: ");
+ file_read_prompt_str = catgetlocal( 73, "name of file to read: ");
+ char_str = catgetlocal( 74, "character = %d");
+ unkn_cmd_str = catgetlocal( 75, "unknown command \"%s\"");
+ non_unique_cmd_msg = catgetlocal( 76, "entered command is not unique");
+ line_num_str = catgetlocal( 77, "line %d ");
+ line_len_str = catgetlocal( 78, "length = %d");
+ current_file_str = catgetlocal( 79, "current file is \"%s\" ");
+ usage0 = catgetlocal( 80, "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n");
+ usage1 = catgetlocal( 81, " -i turn off info window\n");
+ usage2 = catgetlocal( 82, " -e do not convert tabs to spaces\n");
+ usage3 = catgetlocal( 83, " -h do not use highlighting\n");
+ file_is_dir_msg = catgetlocal( 84, "file \"%s\" is a directory");
+ new_file_msg = catgetlocal( 85, "new file \"%s\"");
+ cant_open_msg = catgetlocal( 86, "can't open \"%s\"");
+ open_file_msg = catgetlocal( 87, "file \"%s\", %d lines");
+ file_read_fin_msg = catgetlocal( 88, "finished reading file \"%s\"");
+ reading_file_msg = catgetlocal( 89, "reading file \"%s\"");
+ read_only_msg = catgetlocal( 90, ", read only");
+ file_read_lines_msg = catgetlocal( 91, "file \"%s\", %d lines");
+ save_file_name_prompt = catgetlocal( 92, "enter name of file: ");
+ file_not_saved_msg = catgetlocal( 93, "no filename entered: file not saved");
+ changes_made_prompt = catgetlocal( 94, "changes have been made, are you sure? (y/n [n]) ");
+ yes_char = catgetlocal( 95, "y");
+ file_exists_prompt = catgetlocal( 96, "file already exists, overwrite? (y/n) [n] ");
+ create_file_fail_msg = catgetlocal( 97, "unable to create file \"%s\"");
+ writing_file_msg = catgetlocal( 98, "writing file \"%s\"");
+ file_written_msg = catgetlocal( 99, "\"%s\" %d lines, %d characters");
+ searching_msg = catgetlocal( 100, " ...searching");
+ str_not_found_msg = catgetlocal( 101, "string \"%s\" not found");
+ search_prompt_str = catgetlocal( 102, "search for: ");
+ exec_err_msg = catgetlocal( 103, "could not exec %s\n");
+ continue_msg = catgetlocal( 104, "press return to continue ");
+ menu_cancel_msg = catgetlocal( 105, "press Esc to cancel");
+ menu_size_err_msg = catgetlocal( 106, "menu too large for window");
+ press_any_key_msg = catgetlocal( 107, "press any key to continue ");
+ shell_prompt = catgetlocal( 108, "shell command: ");
+ formatting_msg = catgetlocal( 109, "...formatting paragraph...");
+ shell_echo_msg = catgetlocal( 110, "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-");
+ spell_in_prog_msg = catgetlocal( 111, "sending contents of edit buffer to 'spell'");
+ margin_prompt = catgetlocal( 112, "right margin is: ");
+ restricted_msg = catgetlocal( 113, "restricted mode: unable to perform requested operation");
+ ON = catgetlocal( 114, "ON");
+ OFF = catgetlocal( 115, "OFF");
+ HELP = catgetlocal( 116, "HELP");
+ WRITE = catgetlocal( 117, "WRITE");
+ READ = catgetlocal( 118, "READ");
+ LINE = catgetlocal( 119, "LINE");
+ FILE_str = catgetlocal( 120, "FILE");
+ CHARACTER = catgetlocal( 121, "CHARACTER");
+ REDRAW = catgetlocal( 122, "REDRAW");
+ RESEQUENCE = catgetlocal( 123, "RESEQUENCE");
+ AUTHOR = catgetlocal( 124, "AUTHOR");
+ VERSION = catgetlocal( 125, "VERSION");
+ CASE = catgetlocal( 126, "CASE");
+ NOCASE = catgetlocal( 127, "NOCASE");
+ EXPAND = catgetlocal( 128, "EXPAND");
+ NOEXPAND = catgetlocal( 129, "NOEXPAND");
+ Exit_string = catgetlocal( 130, "EXIT");
+ QUIT_string = catgetlocal( 131, "QUIT");
+ INFO = catgetlocal( 132, "INFO");
+ NOINFO = catgetlocal( 133, "NOINFO");
+ MARGINS = catgetlocal( 134, "MARGINS");
+ NOMARGINS = catgetlocal( 135, "NOMARGINS");
+ AUTOFORMAT = catgetlocal( 136, "AUTOFORMAT");
+ NOAUTOFORMAT = catgetlocal( 137, "NOAUTOFORMAT");
+ Echo = catgetlocal( 138, "ECHO");
+ PRINTCOMMAND = catgetlocal( 139, "PRINTCOMMAND");
+ RIGHTMARGIN = catgetlocal( 140, "RIGHTMARGIN");
+ HIGHLIGHT = catgetlocal( 141, "HIGHLIGHT");
+ NOHIGHLIGHT = catgetlocal( 142, "NOHIGHLIGHT");
+ EIGHTBIT = catgetlocal( 143, "EIGHTBIT");
+ NOEIGHTBIT = catgetlocal( 144, "NOEIGHTBIT");
+ /*
+ | additions
+ */
+ mode_strings[7] = catgetlocal( 145, "emacs key bindings ");
+ emacs_help_text[0] = help_text[0];
+ emacs_help_text[1] = catgetlocal( 146, "^a beginning of line ^i tab ^r restore word ");
+ emacs_help_text[2] = catgetlocal( 147, "^b back 1 char ^j undel char ^t top of text ");
+ emacs_help_text[3] = catgetlocal( 148, "^c command ^k delete line ^u bottom of text ");
+ emacs_help_text[4] = catgetlocal( 149, "^d delete char ^l undelete line ^v next page ");
+ emacs_help_text[5] = catgetlocal( 150, "^e end of line ^m newline ^w delete word ");
+ emacs_help_text[6] = catgetlocal( 151, "^f forward 1 char ^n next line ^x search ");
+ emacs_help_text[7] = catgetlocal( 152, "^g go back 1 page ^o ascii char insert ^y search prompt ");
+ emacs_help_text[8] = catgetlocal( 153, "^h backspace ^p prev line ^z next word ");
+ emacs_help_text[9] = help_text[9];
+ emacs_help_text[10] = help_text[10];
+ emacs_help_text[11] = help_text[11];
+ emacs_help_text[12] = help_text[12];
+ emacs_help_text[13] = help_text[13];
+ emacs_help_text[14] = help_text[14];
+ emacs_help_text[15] = help_text[15];
+ emacs_help_text[16] = help_text[16];
+ emacs_help_text[17] = help_text[17];
+ emacs_help_text[18] = help_text[18];
+ emacs_help_text[19] = help_text[19];
+ emacs_help_text[20] = help_text[20];
+ emacs_help_text[21] = help_text[21];
+ emacs_control_keys[0] = catgetlocal( 154, "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page");
+ emacs_control_keys[1] = catgetlocal( 155, "^o ascii code ^x search ^l undelete line ^n next li ^v next page");
+ emacs_control_keys[2] = catgetlocal( 156, "^u end of file ^a begin of line ^w delete word ^b back 1 char ");
+ emacs_control_keys[3] = catgetlocal( 157, "^t top of text ^e end of line ^r restore word ^f forward 1 char ");
+ emacs_control_keys[4] = catgetlocal( 158, "^c command ^d delete char ^j undelete char ^z next word ");
+ EMACS_string = catgetlocal( 159, "EMACS");
+ NOEMACS_string = catgetlocal( 160, "NOEMACS");
+ usage4 = catgetlocal( 161, " +# put cursor at line #\n");
+ conf_dump_err_msg = catgetlocal( 162, "unable to open .init.ee for writing, no configuration saved!");
+ conf_dump_success_msg = catgetlocal( 163, "ee configuration saved in file %s");
+ modes_menu[9].item_string = catgetlocal( 164, "save editor configuration");
+ config_dump_menu[0].item_string = catgetlocal( 165, "save ee configuration");
+ config_dump_menu[1].item_string = catgetlocal( 166, "save in current directory");
+ config_dump_menu[2].item_string = catgetlocal( 167, "save in home directory");
+ conf_not_saved_msg = catgetlocal( 168, "ee configuration not saved");
+ ree_no_file_msg = catgetlocal( 169, "must specify a file when invoking ree");
+ cancel_string = catgetlocal( 170, "press Esc to cancel");
+ menu_too_lrg_msg = catgetlocal( 180, "menu too large for window");
+ more_above_str = catgetlocal( 181, "^^more^^");
+ more_below_str = catgetlocal( 182, "VVmoreVV");
+
+ commands[0] = HELP;
+ commands[1] = WRITE;
+ commands[2] = READ;
+ commands[3] = LINE;
+ commands[4] = FILE_str;
+ commands[5] = REDRAW;
+ commands[6] = RESEQUENCE;
+ commands[7] = AUTHOR;
+ commands[8] = VERSION;
+ commands[9] = CASE;
+ commands[10] = NOCASE;
+ commands[11] = EXPAND;
+ commands[12] = NOEXPAND;
+ commands[13] = Exit_string;
+ commands[14] = QUIT_string;
+ commands[15] = "<";
+ commands[16] = ">";
+ commands[17] = "!";
+ commands[18] = "0";
+ commands[19] = "1";
+ commands[20] = "2";
+ commands[21] = "3";
+ commands[22] = "4";
+ commands[23] = "5";
+ commands[24] = "6";
+ commands[25] = "7";
+ commands[26] = "8";
+ commands[27] = "9";
+ commands[28] = CHARACTER;
+ commands[29] = NULL;
+ init_strings[0] = CASE;
+ init_strings[1] = NOCASE;
+ init_strings[2] = EXPAND;
+ init_strings[3] = NOEXPAND;
+ init_strings[4] = INFO;
+ init_strings[5] = NOINFO;
+ init_strings[6] = MARGINS;
+ init_strings[7] = NOMARGINS;
+ init_strings[8] = AUTOFORMAT;
+ init_strings[9] = NOAUTOFORMAT;
+ init_strings[10] = Echo;
+ init_strings[11] = PRINTCOMMAND;
+ init_strings[12] = RIGHTMARGIN;
+ init_strings[13] = HIGHLIGHT;
+ init_strings[14] = NOHIGHLIGHT;
+ init_strings[15] = EIGHTBIT;
+ init_strings[16] = NOEIGHTBIT;
+ init_strings[17] = EMACS_string;
+ init_strings[18] = NOEMACS_string;
+ init_strings[19] = NULL;
+
+ /*
+ | allocate space for strings here for settings menu
+ */
+
+ for (counter = 1; counter < NUM_MODES_ITEMS; counter++)
+ {
+ modes_menu[counter].item_string = malloc(80);
+ }
+
+#ifndef NO_CATGETS
+ catclose(catalog);
+#endif /* NO_CATGETS */
+}
+
diff --git a/usr.bin/ee/ee.i18n.guide b/usr.bin/ee/ee.i18n.guide
new file mode 100644
index 0000000..0850c2e
--- /dev/null
+++ b/usr.bin/ee/ee.i18n.guide
@@ -0,0 +1,141 @@
+Easy Editor ("ee") provides the ability to translate the messages displayed to
+the user and the commands entered. This is done via message catalogs,
+following X/Open standards. ee only supports eight bit characters.
+
+(The name ee.i18n.guide is for "ee internationalization guide". The i18n
+abbreviation is used because there are 18 characters between the first
+letter ("i") and last ("n") of "internationalization".)
+
+All of the messages, warnings, information, and commands, are contained in the
+message catalog. Each numbered entry represents an individual string used by
+ee. Some strings contain formatting information for formatted print
+statements, which are of the form "%s", or "%d", these must be preserved in
+the translation, or the correct information will not be displayed. For those
+strings containing multiple formatting codes, the order of each item must be
+preserved as well.
+
+Message content
+1 title for modes, or settings menu
+2 - 8 entries for modes menu, each line should be the same length
+ (padded with spaces)
+9 - 34 other menu titles and entries
+35 - 56 help screen
+57 - 61 actions assigned to control keys
+62 - 66 commands information
+67 message displayed when info window turned off
+68 indication that no file name was entered when invoking ee
+69 prompt for decimal value of character to be entered
+70 message displaying the print command being invoked
+71 prompt for command
+72 prompt for name of file to be written
+73 prompt for name of file to be read
+74 string used to display the decimal value of the character
+ the cursor is on
+75 string displaying an unrecognized command
+76 string indicating that the command entered is not a unique
+ substring of a valid command
+77 string indicating the current line number
+78 string for displaying the length of the line
+79 string for displaying the name of the file
+80 - 83 strings showing how to invoke ee, and its options
+84 message indicating that the file entered is a directory, not a
+ text file
+85 message informing that the entered file does not yet exist
+86 message informing that the file can't be opened (because of
+ permission problems)
+87 message after file has been read with the file name and number
+ of lines read
+88 message indicating that the file has been read
+89 message indicating that the file is being read
+90 message indicating that permissions only allow the file to be
+ read, not written
+91 message after file has been read with the file name and number
+ of lines read
+92 prompt for name of file to be saved (used when no name was
+ entered for a file to edit)
+93 message indicating that the file was not written, since no
+ name was entered at the prompt
+94 prompt asking user if changes should not be saved ("yes_char"
+ will be expected for affirmative response)
+95 "yes" character, single character expected to confirm action
+ (can be upper or lower case, will be converted to upper-case
+ during test)
+96 prompt
+97 error message
+98 message indicating that the named file is being written
+99 message indicating the name of the file written, the number of
+ lines, and the number of characters (order of items must be
+ maintained)
+100 search in progress message
+101 message that the string was not found
+102 prompt for search
+103 message that string could not be executed
+104 self-explanatory
+105 message for menus, indicating that the Escape character will
+ allow the user to exit the menu
+106 error message indicating the menu won't fit on the screen
+107 self-explanatory
+108 prompt for shell command
+109 message displayed while formatting a paragraph
+110 string which places message for spell checking at top of
+ buffer (the portions 'list of unrecognized words' and
+ '-=-=-=-=-=-' may be replaced, but the rest must remain the
+ same)
+111 message informing that spell checking is in progress
+112 prompt for right margin
+113 error informing user that operation is not permitted in ree
+114 string indicating mode is turned 'on' in modes menu
+115 string indicating mode is turned 'off' in modes menu
+116 - 131 strings used for commands (some also used for initialization)
+132 - 144 strings used for initialization
+145 entry for settings menu for emacs key bindings settings
+146 - 153 help screen entries for emacs key bindings info
+154 - 158 info window entries for emacs key bindings info
+159 string for turning on emacs key bindings in the init file
+160 string for turning off emacs key bindings in the init file
+
+Care should be taken when translating commands and initialization keywords
+because the algorithm used for detecting uniqueness of entered commands
+will not be able to distinguish words that are not unique before the end
+of the shorter word, for example, it would not be able to distinguish the
+command 'abcd' from 'abcde'.
+
+After translating the messages, use the 'gencat' command to create the compiled
+catalog used when running the software. The standard syntax would be:
+
+ gencat ee.cat ee.msg
+
+Where ee.msg is the file containing the translations, and ee.cat is the
+compiled catalog. If the file ee.cat does not exist, it will be created.
+Check the documentation for your system for proper syntax.
+
+Message catalog placement varies from system to system. A common location
+for message catalogs is in /usr/lib/nls. In this directory are
+directories with the names of other languages. The default language is
+'C'. There is also an environment variable, named NLSPATH used to
+determine where message catalogs can be found. This variable is similar
+to the PATH variable used for commands, but with some differences. The
+NLSPATH variable must have the ability to handle different names for
+languages and the catalog files, so it has field descriptors for these. A
+typical setting for NLSPATH could be:
+
+ NLSPATH=/usr/lib/nls/%L/%N.cat:/usr/local/lib/nls/%L/%N.cat
+
+Where "%L" is the field descriptor for the language (obtained from the
+LANG environment variable) and "%N" is the name of the file (with the
+".cat" appended by the path variable, it is not passed from the requesting
+program). The colon (:) is used to separate paths, so in the above
+example there are two paths possible for message catalogs. You may wish
+to maintain catalogs for applications that are not supported by your
+system vendor in a location unique for you, and this is facilitated by the
+NLSPATH variable. Remember to set and export both the LANG and NLSPATH
+variables for each user that expects to use localization either in a
+system-wide profile or in each user's profile. See your system
+documentation for more information.
+
+The message catalog supplied with ee also uses the '$quote' directive to
+specify a quote around strings to ensure proper padding. This directive
+may not be supported on all systems, and lead to quotes being included in
+the string used in ee, which will cause incorrect behavior. If the
+'$quote' directive is not supported by your system's gencat command, edit
+the msg file to remove the leading and trailing quotation marks.
diff --git a/usr.bin/ee/ee.msg b/usr.bin/ee/ee.msg
new file mode 100644
index 0000000..6c5ef75
--- /dev/null
+++ b/usr.bin/ee/ee.msg
@@ -0,0 +1,179 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/hugh/sources/old_ae/RCS/ee.msg,v 1.6 1995/10/16 05:20:50 hugh Exp $
+$
+$
+$set 1
+$quote "
+1 "modes menu"
+2 "tabs to spaces "
+3 "case sensitive search"
+4 "margins observed "
+5 "auto-paragraph format"
+6 "eightbit characters "
+7 "info window "
+8 "right margin "
+9 "leave menu"
+10 "save changes"
+11 "no save"
+12 "file menu"
+13 "read a file"
+14 "write a file"
+15 "save file"
+16 "print editor contents"
+17 "search menu"
+18 "search for ..."
+19 "search"
+20 "spell menu"
+21 "use 'spell'"
+22 "use 'ispell'"
+23 "miscellaneous menu"
+24 "format paragraph"
+25 "shell command"
+26 "check spelling"
+27 "main menu"
+28 "leave editor"
+29 "help"
+30 "file operations"
+31 "redraw screen"
+32 "settings"
+33 "search"
+34 "miscellaneous"
+35 "Control keys: "
+36 "^a ascii code ^i tab ^r right "
+37 "^b bottom of text ^j newline ^t top of text "
+38 "^c command ^k delete char ^u up "
+39 "^d down ^l left ^v undelete word "
+40 "^e search prompt ^m newline ^w delete word "
+41 "^f undelete char ^n next page ^x search "
+42 "^g begin of line ^o end of line ^y delete line "
+43 "^h backspace ^p prev page ^z undelete line "
+44 "^[ (escape) menu "
+45 " "
+46 "Commands: "
+47 "help : get this info file : print file name "
+48 "read : read a file char : ascii code of char "
+49 "write : write a file case : case sensitive search "
+50 "exit : leave and save nocase : case insensitive search "
+51 "quit : leave, no save !cmd : execute \"cmd\" in shell "
+52 "line : display line # 0-9 : go to line \"#\" "
+53 "expand : expand tabs noexpand: do not expand tabs "
+54 " "
+55 " ee [-i] [-e] [-h] [file(s)] "
+56 " -i : no information window -e : do not expand tabs -h : no highlight "
+57 "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "
+58 "^a ascii code ^x search ^z undelete line ^d down ^n next page "
+59 "^b bottom of text ^g begin of line ^w delete word ^l left "
+60 "^t top of text ^o end of line ^v undelete word ^r right "
+61 "^c command ^k delete char ^f undelete char "
+62 "help : get help info |file : print file name |line : print line # "
+63 "read : read a file |char : ascii code of char |0-9 : go to line \"#\""
+64 "write: write a file |case : case sensitive search |exit : leave and save "
+65 "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"
+66 "expand: expand tabs |noexpand: do not expand tabs "
+67 " press Escape (^[) for menu"
+68 "no file"
+69 "ascii code: "
+70 "sending contents of buffer to \"%s\" "
+71 "command: "
+72 "name of file to write: "
+73 "name of file to read: "
+74 "character = %d"
+75 "unknown command \"%s\""
+76 "entered command is not unique"
+77 "line %d "
+78 "length = %d"
+79 "current file is \"%s\" "
+80 "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"
+81 " -i turn off info window\n"
+82 " -e do not convert tabs to spaces\n"
+83 " -h do not use highlighting\n"
+84 "file \"%s\" is a directory"
+85 "new file \"%s\""
+86 "can't open \"%s\""
+87 "file \"%s\", %d lines"
+88 "finished reading file \"%s\""
+89 "reading file \"%s\""
+90 ", read only"
+91 "file \"%s\", %d lines"
+92 "enter name of file: "
+93 "no filename entered: file not saved"
+94 "changes have been made, are you sure? (y/n [n]) "
+95 "y"
+96 "file already exists, overwrite? (y/n) [n] "
+97 "unable to create file \"%s\""
+98 "writing file \"%s\""
+99 "\"%s\" %d lines, %d characters"
+100 " ...searching"
+101 "string \"%s\" not found"
+102 "search for: "
+103 "could not exec %s\n"
+104 "press return to continue "
+105 "press Esc to cancel"
+106 "menu too large for window"
+107 "press any key to continue "
+108 "shell command: "
+109 "...formatting paragraph..."
+110 "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-"
+111 "sending contents of edit buffer to 'spell'"
+112 "right margin is: "
+113 "restricted mode: unable to perform requested operation"
+114 "ON"
+115 "OFF"
+116 "HELP"
+117 "WRITE"
+118 "READ"
+119 "LINE"
+120 "FILE"
+121 "CHARACTER"
+122 "REDRAW"
+123 "RESEQUENCE"
+124 "AUTHOR"
+125 "VERSION"
+126 "CASE"
+127 "NOCASE"
+128 "EXPAND"
+129 "NOEXPAND"
+130 "EXIT"
+131 "QUIT"
+132 "INFO"
+133 "NOINFO"
+134 "MARGINS"
+135 "NOMARGINS"
+136 "AUTOFORMAT"
+137 "NOAUTOFORMAT"
+138 "ECHO"
+139 "PRINTCOMMAND"
+140 "RIGHTMARGIN"
+141 "HIGHLIGHT"
+142 "NOHIGHLIGHT"
+143 "EIGHTBIT"
+144 "NOEIGHTBIT"
+145 "emacs key bindings "
+146 "^a beginning of line ^i tab ^r restore word "
+147 "^b back 1 char ^j undel char ^t top of text "
+148 "^c command ^k delete line ^u bottom of text "
+149 "^d delete char ^l undelete line ^v next page "
+150 "^e end of line ^m newline ^w delete word "
+151 "^f forward 1 char ^n next line ^x search "
+152 "^g go back 1 page ^o ascii char insert ^y search prompt "
+153 "^h backspace ^p prev line ^z next word "
+154 "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page"
+155 "^o ascii code ^x search ^l undelete line ^n next li ^v next page"
+156 "^u end of file ^a begin of line ^w delete word ^b back 1 char "
+157 "^t top of text ^e end of line ^r restore word ^f forward 1 char "
+158 "^c command ^d delete char ^j undelete char ^z next word "
+159 "EMACS"
+160 "NOEMACS"
+161 " +# put cursor at line #\n"
+162 "unable to open .init.ee for writing, no configuration saved!"
+163 "ee configuration saved in file %s"
+164 "save editor configuration"
+165 "save ee configuration"
+166 "save in current directory"
+167 "save in home directory"
+168 "ee configuration not saved"
+169 "must specify a file when invoking ree"
diff --git a/usr.bin/ee/new_curse.c b/usr.bin/ee/new_curse.c
new file mode 100644
index 0000000..91c1078
--- /dev/null
+++ b/usr.bin/ee/new_curse.c
@@ -0,0 +1,3574 @@
+/*
+ | new_curse.c
+ |
+ | A subset of curses developed for use with ae.
+ |
+ | written by Hugh Mahon
+ |
+ | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+ | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+ | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+ | IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ | FITNESS FOR A PARTICULAR PURPOSE. Neither
+ | Hewlett-Packard nor Hugh Mahon shall be liable
+ | for errors contained herein, nor for
+ | incidental or consequential damages in
+ | connection with the furnishing, performance or
+ | use of this material. Neither Hewlett-Packard
+ | nor Hugh Mahon assumes any responsibility for
+ | the use or reliability of this software or
+ | documentation. This software and
+ | documentation is totally UNSUPPORTED. There
+ | is no support contract available. Hewlett-
+ | Packard has done NO Quality Assurance on ANY
+ | of the program or documentation. You may find
+ | the quality of the materials inferior to
+ | supported materials.
+ |
+ | This software is not a product of Hewlett-Packard, Co., or any
+ | other company. No support is implied or offered with this software.
+ | You've got the source, and you're on your own.
+ |
+ | This software may be distributed under the terms of Larry Wall's
+ | Artistic license, a copy of which is included in this distribution.
+ |
+ | This notice must be included with this software and any derivatives.
+ |
+ | Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon
+ | All are rights reserved.
+ |
+ | $Header: /home/ncvs/src/usr.bin/ee/doc/new_curse.c,v 1.1.1.1 1995/08/30 07:28:06 jkh Exp $
+ |
+ */
+
+char *copyright_message[] = { "Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon",
+ "All rights are reserved."};
+
+char * new_curse_name= "@(#) new_curse.c $Revision: 1.1.1.1 $";
+
+#include "new_curse.h"
+#include <signal.h>
+#include <fcntl.h>
+
+#ifdef SYS5
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef BSD_SELECT
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef SLCT_HDR
+#include <sys/select.h> /* on AIX */
+#endif /* SLCT_HDR */
+
+#endif /* BSD_SELECT */
+
+#ifdef HAS_STDLIB
+#include <stdlib.h>
+#endif
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAS_UNISTD
+#include <unistd.h>
+#endif
+
+#ifdef HAS_SYS_IOCTL
+#include <sys/ioctl.h>
+#endif
+
+
+WINDOW *curscr;
+static WINDOW *virtual_scr;
+WINDOW *stdscr;
+WINDOW *last_window_refreshed;
+
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+#endif
+
+#define min(a, b) (a < b ? a : b)
+
+#ifndef CAP
+#define String_Out(table, stack, place) Info_Out(table, stack, place)
+#else
+#define String_Out(table, stack, place) Cap_Out(table, stack, place)
+#endif
+
+#define bw__ 0 /* booleans */
+#define am__ 1
+#define xb__ 2
+#define xs__ 3 /* hp glitch (standout not erased by overwrite) */
+#define xn__ 4
+#define eo__ 5
+#define gn__ 6 /* generic type terminal */
+#define hc__ 7 /* hardcopy terminal */
+#define km__ 8
+#define hs__ 9
+#define in__ 10
+#define da__ 11
+#define db__ 12
+#define mi__ 13 /* safe to move during insert mode */
+#define ms__ 14 /* safe to move during standout mode */
+#define os__ 15
+#define es__ 16
+#define xt__ 17
+#define hz__ 18 /* hazeltine glitch */
+#define ul__ 19
+#define xo__ 20
+#define chts__ 21
+#define nxon__ 22
+#define nrrmc__ 23
+#define npc__ 24
+#define mc5i__ 25
+
+#define co__ 0 /* number of columns */ /* numbers */
+#define it__ 1 /* spaces per tab */
+#define li__ 2 /* number of lines */
+#define lm__ 3
+#define sg__ 4 /* magic cookie glitch */
+#define pb__ 5
+#define vt__ 6
+#define ws__ 7
+
+#define cols__ 0
+#define lines__ 2
+#define xmc__ 4
+#define vt__ 6
+#define wsl__ 7
+#define nlab__ 8
+#define lh__ 9
+#define lw__ 10
+
+#define bt__ 0 /* back tab */ /* strings */
+#define bl__ 1 /* bell */
+#define cr__ 2 /* carriage return */
+#define cs__ 3 /* change scroll region */
+#define ct__ 4 /* clear all tab stops */
+#define cl__ 5 /* clear screen and home cursor */
+#define ce__ 6 /* clear to end of line */
+#define cd__ 7 /* clear to end of display */
+#define ch__ 8 /* set cursor column */
+#define CC__ 9 /* term, settable cmd char in */
+#define cm__ 10 /* screen rel cursor motion, row, column */
+#define do__ 11 /* down one line */
+#define ho__ 12 /* home cursor */
+#define vi__ 13 /* make cursor invisible */
+#define le__ 14 /* move cursor left one space */
+#define CM__ 15 /* memory rel cursor addressing */
+#define ve__ 16 /* make cursor appear normal */
+#define nd__ 17 /* non-destructive space (cursor right) */
+#define ll__ 18 /* last line, first col */
+#define up__ 19 /* cursor up */
+#define vs__ 20
+#define dc__ 21 /* delete character */
+#define dl__ 22 /* delete line */
+#define ds__ 23
+#define hd__ 24
+#define as__ 25
+#define mb__ 26
+#define md__ 27 /* turn on bold */
+#define ti__ 28
+#define dm__ 29 /* turn on delete mode */
+#define mh__ 30 /* half bright mode */
+#define im__ 31 /* insert mode */
+#define mk__ 32
+#define mp__ 33
+#define mr__ 34
+#define so__ 35 /* enter standout mode */
+#define us__ 36
+#define ec__ 37
+#define ae__ 38
+#define me__ 39
+#define te__ 40
+#define ed__ 41
+#define ei__ 42 /* exit insert mode */
+#define se__ 43 /* exit standout mode */
+#define ue__ 44
+#define vb__ 45
+#define ff__ 46
+#define fs__ 47
+#define i1__ 48
+#define i2__ 49
+#define i3__ 50
+#define if__ 51
+#define ic__ 52
+#define al__ 53
+#define ip__ 54
+#define kb__ 55 /* backspace key */
+#define ka__ 56
+#define kC__ 57
+#define kt__ 58
+#define kD__ 59
+#define kL__ 60
+#define kd__ 61
+#define kM__ 62
+#define kE__ 63
+#define kS__ 64
+#define k0__ 65
+#define k1__ 66
+#define kf10__ 67
+#define k2__ 68
+#define k3__ 69
+#define k4__ 70
+#define k5__ 71
+#define k6__ 72
+#define k7__ 73
+#define k8__ 74
+#define k9__ 75
+#define kh__ 76
+#define kI__ 77
+#define kA__ 78
+#define kl__ 79
+#define kH__ 80
+#define kN__ 81
+#define kP__ 82
+#define kr__ 83
+#define kF__ 84
+#define kR__ 85
+#define kT__ 86
+#define ku__ 87 /* key up */
+#define ke__ 88
+#define ks__ 89
+#define l0__ 90
+#define l1__ 91
+#define la__ 92
+#define l2__ 93
+#define l3__ 94
+#define l4__ 95
+#define l5__ 96
+#define l6__ 97
+#define l7__ 98
+#define l8__ 99
+#define l9__ 100
+#define mo__ 101
+#define mm__ 102
+#define nw__ 103
+#define pc__ 104
+#define DC__ 105
+#define DL__ 106
+#define DO__ 107
+#define IC__ 118
+#define SF__ 109
+#define AL__ 110
+#define LE__ 111
+#define RI__ 112
+#define SR__ 113
+#define UP__ 114
+#define pk__ 115
+#define pl__ 116
+#define px__ 117
+#define ps__ 118
+#define pf__ 119
+#define po__ 120
+#define rp__ 121
+#define r1__ 122
+#define r2__ 123
+#define r3__ 124
+#define rf__ 125
+#define rc__ 126
+#define cv__ 127
+#define sc__ 128
+#define sf__ 129
+#define sr__ 130
+#define sa__ 131 /* sgr */
+#define st__ 132
+#define wi__ 133
+#define ta__ 134
+#define ts__ 135
+#define uc__ 136
+#define hu__ 137
+#define iP__ 138
+#define K1__ 139
+#define K2__ 140
+#define K3__ 141
+#define K4__ 142
+#define K5__ 143
+#define pO__ 144
+#define ml__ 145
+#define mu__ 146
+#define rmp__ 145
+#define acsc__ 146
+#define pln__ 147
+#define kcbt__ 148
+#define smxon__ 149
+#define rmxon__ 150
+#define smam__ 151
+#define rmam__ 152
+#define xonc__ 153
+#define xoffc__ 154
+#define enacs__ 155
+#define smln__ 156
+#define rmln__ 157
+#define kbeg__ 158
+#define kcan__ 159
+#define kclo__ 160
+#define kcmd__ 161
+#define kcpy__ 162
+#define kcrt__ 163
+#define kend__ 164
+#define kent__ 165
+#define kext__ 166
+#define kfnd__ 167
+#define khlp__ 168
+#define kmrk__ 169
+#define kmsg__ 170
+#define kmov__ 171
+#define knxt__ 172
+#define kopn__ 173
+#define kopt__ 174
+#define kprv__ 175
+#define kprt__ 176
+#define krdo__ 177
+#define kref__ 178
+#define krfr__ 179
+#define krpl__ 180
+#define krst__ 181
+#define kres__ 182
+#define ksav__ 183
+#define kspd__ 184
+#define kund__ 185
+#define kBEG__ 186
+#define kCAN__ 187
+#define kCMD__ 188
+#define kCPY__ 189
+#define kCRT__ 190
+#define kDC__ 191
+#define kDL__ 192
+#define kslt__ 193
+#define kEND__ 194
+#define kEOL__ 195
+#define kEXT__ 196
+#define kFND__ 197
+#define kHLP__ 198
+#define kHOM__ 199
+#define kIC__ 200
+#define kLFT__ 201
+#define kMSG__ 202
+#define kMOV__ 203
+#define kNXT__ 204
+#define kOPT__ 205
+#define kPRV__ 206
+#define kPRT__ 207
+#define kRDO__ 208
+#define kRPL__ 209
+#define kRIT__ 210
+#define kRES__ 211
+#define kSAV__ 212
+#define kSPD__ 213
+#define kUND__ 214
+#define rfi__ 215
+#define kf11__ 216
+#define kf12__ 217
+#define kf13__ 218
+#define kf14__ 219
+#define kf15__ 220
+#define kf16__ 221
+#define kf17__ 222
+#define kf18__ 223
+#define kf19__ 224
+#define kf20__ 225
+#define kf21__ 226
+#define kf22__ 227
+#define kf23__ 228
+#define kf24__ 229
+#define kf25__ 230
+#define kf26__ 231
+#define kf27__ 232
+#define kf28__ 233
+#define kf29__ 234
+#define kf30__ 235
+#define kf31__ 236
+#define kf32__ 237
+#define kf33__ 238
+#define kf34__ 239
+#define kf35__ 240
+#define kf36__ 241
+#define kf37__ 242
+#define kf38__ 243
+#define kf39__ 244
+#define kf40__ 245
+#define kf41__ 246
+#define kf42__ 247
+#define kf43__ 248
+#define kf44__ 249
+#define kf45__ 250
+#define kf46__ 251
+#define kf47__ 252
+#define kf48__ 253
+#define kf49__ 254
+#define kf50__ 255
+#define kf51__ 256
+#define kf52__ 257
+#define kf53__ 258
+#define kf54__ 259
+#define kf55__ 260
+#define kf56__ 261
+#define kf57__ 262
+#define kf58__ 263
+#define kf59__ 264
+#define kf60__ 265
+#define kf61__ 266
+#define kf62__ 267
+#define kf63__ 268
+#define el1__ 269
+#define mgc__ 270
+#define smgl__ 271
+#define smgr__ 272
+
+#ifdef CAP
+char *Boolean_names[] = {
+"bw", "am", "xb", "xs", "xn", "eo", "gn", "hc", "km", "hs", "in", "da", "db",
+"mi", "ms", "os", "es", "xt", "hz", "ul", "xo", "HC", "nx", "NR", "NP", "5i"
+};
+
+char *Number_names[] = {
+"co#", "it#", "li#", "lm#", "sg#", "pb#", "vt#", "ws#", "Nl#", "lh#", "lw#"
+};
+
+char *String_names[] = {
+"bt=", "bl=", "cr=", "cs=", "ct=", "cl=", "ce=", "cd=", "ch=", "CC=", "cm=",
+"do=", "ho=", "vi=", "le=", "CM=", "ve=", "nd=", "ll=", "up=", "vs=", "dc=",
+"dl=", "ds=", "hd=", "as=", "mb=", "md=", "ti=", "dm=", "mh=", "im=", "mk=",
+"mp=", "mr=", "so=", "us=", "ec=", "ae=", "me=", "te=", "ed=", "ei=", "se=",
+"ue=", "vb=", "ff=", "fs=", "i1=", "i2=", "i3=", "if=", "ic=", "al=", "ip=",
+"kb=", "ka=", "kC=", "kt=", "kD=", "kL=", "kd=", "kM=", "kE=", "kS=", "k0=",
+"k1=", "k;=", "k2=", "k3=", "k4=", "k5=", "k6=", "k7=", "k8=", "k9=", "kh=",
+"kI=", "kA=", "kl=", "kH=", "kN=", "kP=", "kr=", "kF=", "kR=", "kT=", "ku=",
+"ke=", "ks=", "l0=", "l1=", "la=", "l2=", "l3=", "l4=", "l5=", "l6=", "l7=",
+"l8=", "l9=", "mo=", "mm=", "nw=", "pc=", "DC=", "DL=", "DO=", "IC=", "SF=",
+"AL=", "LE=", "RI=", "SR=", "UP=", "pk=", "pl=", "px=", "ps=", "pf=", "po=",
+"rp=", "r1=", "r2=", "r3=", "rf=", "rc=", "cv=", "sc=", "sf=", "sr=", "sa=",
+"st=", "wi=", "ta=", "ts=", "uc=", "hu=", "iP=", "K1=", "K3=", "K2=", "K4=",
+"K5=", "pO=", "rP=", "ac=", "pn=", "kB=", "SX=", "RX=", "SA=", "RA=", "XN=",
+"XF=", "eA=", "LO=", "LF=", "@1=", "@2=", "@3=", "@4=", "@5=", "@6=", "@7=",
+"@8=", "@9=", "@0=", "%1=", "%2=", "%3=", "%4=", "%5=", "%6=", "%7=", "%8=",
+"%9=", "%0=", "&1=", "&2=", "&3=", "&4=", "&5=", "&6=", "&7=", "&8=", "&9=",
+"&0=", "*1=", "*2=", "*3=", "*4=", "*5=", "*6=", "*7=", "*8=", "*9=", "*0=",
+"#1=", "#2=", "#3=", "#4=", "%a=", "%b=", "%c=", "%d=", "%e=", "%f=", "%g=",
+"%h=", "%i=", "%j=", "!1=", "!2=", "!3=", "RF=", "F1=", "F2=", "F3=", "F4=",
+"F5=", "F6=", "F7=", "F8=", "F9=", "FA=", "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=", "Fa=", "Fb=",
+"Fc=", "Fd=", "Fe=", "Ff=", "Fg=", "Fh=", "Fi=", "Fj=", "Fk=", "Fl=", "Fm=",
+"Fn=", "Fo=", "Fp=", "Fq=", "Fr=", "cb=", "MC=", "ML=", "MR="
+};
+#endif
+
+char *new_curse = "October 1987";
+
+char in_buff[100]; /* buffer for ungetch */
+int bufp; /* next free position in in_buff */
+
+char *TERMINAL_TYPE = NULL; /* terminal type to be gotten from environment */
+int CFOUND = FALSE;
+int Data_Line_len = 0;
+int Max_Key_len; /* max length of a sequence sent by a key */
+char *Data_Line = NULL;
+char *TERM_PATH = NULL;
+char *TERM_data_ptr = NULL;
+char *Term_File_name = NULL; /* name of file containing terminal description */
+FILE *TFP; /* file pointer to file with terminal des. */
+int Fildes; /* file descriptor for terminfo file */
+int STAND = FALSE; /* is standout mode activated? */
+int TERM_INFO = FALSE; /* is terminfo being used (TRUE), or termcap (FALSE) */
+int Time_Out; /* set when time elapsed while trying to read function key */
+int Curr_x; /* current x position on screen */
+int Curr_y; /* current y position on the screen */
+int LINES;
+int COLS;
+int Move_It; /* flag to move cursor if magic cookie glitch */
+int initialized = FALSE; /* tells whether new_curse is initialized */
+float speed;
+float chars_per_millisecond;
+int Repaint_screen; /* if an operation to change screen impossible, repaint screen */
+int Intr; /* storeage for interrupt character */
+int Parity; /* 0 = no parity, 1 = odd parity, 2 = even parity */
+int Noblock; /* for BSD systems */
+int Num_bits; /* number of bits per character */
+int Flip_Bytes; /* some systems have byte order reversed */
+int interrupt_flag = FALSE; /* set true if SIGWINCH received */
+
+#ifndef CAP
+char *Strings;
+#endif
+
+struct KEYS {
+ int length; /* length of string sent by key */
+ char *string; /* string sent by key */
+ int value; /* CURSES value of key (9-bit) */
+ };
+
+struct KEY_STACK {
+ struct KEYS *element;
+ struct KEY_STACK *next;
+ };
+
+struct KEY_STACK *KEY_TOS = NULL;
+struct KEY_STACK *KEY_POINT;
+
+struct Parameters {
+ int value;
+ struct Parameters *next;
+ };
+
+int Key_vals[] = {
+ 0407, 0526, 0515, 0525, 0512, 0510, 0402, 0514, 0517, 0516, 0410, 0411,
+ 0422, 0412, 0413, 0414, 0415, 0416, 0417, 0420, 0421, 0406, 0513, 0511,
+ 0404, 0533, 0522, 0523, 0405, 0520, 0521, 0524, 0403,
+ 0534, 0535, 0536, 0537, 0540, 0541, 0542, 0543, 0544, 0545, 0546, 0547,
+ 0550, 0527, 0551, 0552, 0553, 0554, 0555, 0556, 0557, 0560, 0561, 0562,
+ 0532, 0563, 0564, 0565, 0566, 0567, 0570, 0571, 0627, 0630, 0572, 0573,
+ 0574, 0575, 0576, 0577, 0600, 0601, 0602, 0603, 0604, 0605, 0606, 0607,
+ 0610, 0611, 0612, 0613, 0614, 0615, 0616, 0617, 0620, 0621, 0622, 0623,
+ 0624, 0625, 0626, 0423, 0424, 0425, 0426, 0427, 0430, 0431,
+ 0432, 0433, 0434, 0435, 0436, 0437, 0440, 0441, 0442, 0443, 0444, 0445,
+ 0446, 0447, 0450, 0451, 0452, 0453, 0454, 0455, 0456, 0457, 0460, 0461,
+ 0462, 0463, 0464, 0465, 0466, 0467, 0470, 0471, 0472, 0473, 0474, 0475,
+ 0476, 0477, 0500, 0501, 0502, 0503, 0504, 0505, 0506, 0507
+};
+
+int attributes_set[9];
+
+#ifdef SYS5
+struct termio Terminal;
+struct termio Saved_tty;
+#else
+struct sgttyb Terminal;
+struct sgttyb Saved_tty;
+#endif
+
+char *tc_;
+
+int Booleans[128];
+int Numbers[128];
+char *String_table[1024];
+
+int *virtual_lines;
+
+static char nc_scrolling_ability = FALSE;
+
+#ifdef CAP
+
+#if __STDC__ || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif /* __STDC__ */
+
+int tc_Get_int P_((int));
+void CAP_PARSE P_((void));
+void Find_term P_((void));
+
+#undef P_
+
+#endif /* CAP */
+
+
+#ifndef __STDC__
+#ifndef HAS_STDLIB
+extern char *fgets();
+extern char *malloc();
+extern char *getenv();
+FILE *fopen(); /* declaration for open function */
+#endif /* HAS_STDLIB */
+#endif /* __STDC__ */
+
+#ifdef SIGWINCH
+
+/*
+ | Copy the contents of one window to another.
+ */
+
+void
+copy_window(origin, destination)
+WINDOW *origin, *destination;
+{
+ int row, column;
+ struct _line *orig, *dest;
+
+ orig = origin->first_line;
+ dest = destination->first_line;
+
+ for (row = 0;
+ row < (min(origin->Num_lines, destination->Num_lines));
+ row++)
+ {
+ for (column = 0;
+ column < (min(origin->Num_cols, destination->Num_cols));
+ column++)
+ {
+ dest->row[column] = orig->row[column];
+ dest->attributes[column] = orig->attributes[column];
+ }
+ dest->changed = orig->changed;
+ dest->scroll = orig->scroll;
+ dest->last_char = min(orig->last_char, destination->Num_cols);
+ orig = orig->next_screen;
+ dest = dest->next_screen;
+ }
+ destination->LX = min((destination->Num_cols - 1), origin->LX);
+ destination->LY = min((destination->Num_lines - 1), origin->LY);
+ destination->Attrib = origin->Attrib;
+ destination->scroll_up = origin->scroll_up;
+ destination->scroll_down = origin->scroll_down;
+ destination->SCROLL_CLEAR = origin->SCROLL_CLEAR;
+}
+
+void
+reinitscr(foo)
+int foo;
+{
+ WINDOW *local_virt;
+ WINDOW *local_std;
+ WINDOW *local_cur;
+
+ signal(SIGWINCH, reinitscr);
+#ifdef TIOCGWINSZ
+ if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
+ {
+ if (ws.ws_row == LINES && ws.ws_col == COLS)
+ return;
+ if (ws.ws_row > 0)
+ LINES = ws.ws_row;
+ if (ws.ws_col > 0)
+ COLS = ws.ws_col;
+ }
+#endif /* TIOCGWINSZ */
+ local_virt = newwin(LINES, COLS, 0, 0);
+ local_std = newwin(LINES, COLS, 0, 0);
+ local_cur = newwin(LINES, COLS, 0, 0);
+ copy_window(virtual_scr, local_virt);
+ copy_window(stdscr, local_std);
+ copy_window(curscr, local_cur);
+ delwin(virtual_scr);
+ delwin(stdscr);
+ delwin(curscr);
+ virtual_scr = local_virt;
+ stdscr = local_std;
+ curscr = local_cur;
+ free(virtual_lines);
+ virtual_lines = (int *) malloc(LINES * (sizeof(int)));
+ interrupt_flag = TRUE;
+}
+#endif /* SIGWINCH */
+
+void
+initscr() /* initialize terminal for operations */
+{
+ int value;
+ char *lines_string;
+ char *columns_string;
+#ifdef CAP
+ char *pointer;
+#endif /* CAP */
+
+#ifdef DIAG
+printf("starting initscr \n");fflush(stdout);
+#endif
+ if (initialized)
+ return;
+#ifdef BSD_SELECT
+ setbuf(stdin, NULL);
+#endif /* BSD_SELECT */
+ Flip_Bytes = FALSE;
+ Parity = 0;
+ Time_Out = FALSE;
+ bufp = 0;
+ Move_It = FALSE;
+ Noblock = FALSE;
+#ifdef SYS5
+ value = ioctl(0, TCGETA, &Terminal);
+ if (Terminal.c_cflag & PARENB)
+ {
+ if (Terminal.c_cflag & PARENB)
+ Parity = 1;
+ else
+ Parity = 2;
+ }
+ if ((Terminal.c_cflag & CS8) == CS8)
+ {
+ Num_bits = 8;
+ }
+ else if ((Terminal.c_cflag & CS7) == CS7)
+ Num_bits = 7;
+ else if ((Terminal.c_cflag & CS6) == CS6)
+ Num_bits = 6;
+ else
+ Num_bits = 5;
+ value = Terminal.c_cflag & 037;
+ switch (value) {
+ case 01: speed = 50.0;
+ break;
+ case 02: speed = 75.0;
+ break;
+ case 03: speed = 110.0;
+ break;
+ case 04: speed = 134.5;
+ break;
+ case 05: speed = 150.0;
+ break;
+ case 06: speed = 200.0;
+ break;
+ case 07: speed = 300.0;
+ break;
+ case 010: speed = 600.0;
+ break;
+ case 011: speed = 900.0;
+ break;
+ case 012: speed = 1200.0;
+ break;
+ case 013: speed = 1800.0;
+ break;
+ case 014: speed = 2400.0;
+ break;
+ case 015: speed = 3600.0;
+ break;
+ case 016: speed = 4800.0;
+ break;
+ case 017: speed = 7200.0;
+ break;
+ case 020: speed = 9600.0;
+ break;
+ case 021: speed = 19200.0;
+ break;
+ case 022: speed = 38400.0;
+ break;
+ default: speed = 0.0;
+ }
+#else
+ value = ioctl(0, TIOCGETP, &Terminal);
+ if (Terminal.sg_flags & EVENP)
+ Parity = 2;
+ else if (Terminal.sg_flags & ODDP)
+ Parity = 1;
+ value = Terminal.sg_ospeed;
+ switch (value) {
+ case 01: speed = 50.0;
+ break;
+ case 02: speed = 75.0;
+ break;
+ case 03: speed = 110.0;
+ break;
+ case 04: speed = 134.5;
+ break;
+ case 05: speed = 150.0;
+ break;
+ case 06: speed = 200.0;
+ break;
+ case 07: speed = 300.0;
+ break;
+ case 010: speed = 600.0;
+ break;
+ case 011: speed = 1200.0;
+ break;
+ case 012: speed = 1800.0;
+ break;
+ case 013: speed = 2400.0;
+ break;
+ case 014: speed = 4800.0;
+ break;
+ case 015: speed = 9600.0;
+ break;
+ default: speed = 0.0;
+ }
+#endif
+ chars_per_millisecond = (0.001 * speed) / 8.0;
+ TERMINAL_TYPE = getenv("TERM");
+ if (TERMINAL_TYPE == NULL)
+ {
+ printf("unknown terminal type\n");
+ exit(0);
+ }
+#ifndef CAP
+ Fildes = -1;
+ TERM_PATH = getenv("TERMINFO");
+ if (TERM_PATH != NULL)
+ {
+ Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
+ Term_File_name = malloc(Data_Line_len);
+ sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ }
+ if (Fildes == -1)
+ {
+ TERM_PATH = "/usr/lib/terminfo";
+ Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
+ Term_File_name = malloc(Data_Line_len);
+ sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ }
+ if (Fildes == -1)
+ {
+ TERM_PATH = "/usr/share/lib/terminfo";
+ Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
+ Term_File_name = malloc(Data_Line_len);
+ sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ }
+ if (Fildes == -1)
+ {
+ free(Term_File_name);
+ Term_File_name = NULL;
+ }
+ else
+ TERM_INFO = INFO_PARSE();
+#else
+ /*
+ | termcap information can be in the TERMCAP env variable, if so
+ | use that, otherwise check the /etc/termcap file
+ */
+ if ((pointer = Term_File_name = getenv("TERMCAP")) != NULL)
+ {
+ if (*Term_File_name != '/')
+ Term_File_name = "/etc/termcap";
+ }
+ else
+ {
+ Term_File_name = "/etc/termcap";
+ }
+ if ((TFP = fopen(Term_File_name, "r")) == NULL)
+ {
+ printf("unable to open /etc/termcap file \n");
+ exit(0);
+ }
+ for (value = 0; value < 1024; value++)
+ String_table[value] = NULL;
+ for (value = 0; value < 128; value++)
+ Booleans[value] = 0;
+ for (value = 0; value < 128; value++)
+ Numbers[value] = 0;
+ Data_Line = malloc(512);
+ if (pointer && *pointer != '/')
+ {
+ TERM_data_ptr = pointer;
+ CAP_PARSE();
+ }
+ else
+ {
+ Find_term();
+ CAP_PARSE();
+ }
+#endif
+ if (String_table[pc__] == NULL)
+ String_table[pc__] = "\0";
+ if ((String_table[cm__] == NULL) || (Booleans[hc__]))
+ {
+ fprintf(stderr, "sorry, unable to use this terminal type for screen editing\n");
+ exit(0);
+ }
+ Key_Get();
+ LINES = Numbers[li__];
+ COLS = Numbers[co__];
+ if ((lines_string = getenv("LINES")) != NULL)
+ {
+ value = atoi(lines_string);
+ if (value > 0)
+ LINES = value;
+ }
+ if ((columns_string = getenv("COLUMNS")) != NULL)
+ {
+ value = atoi(columns_string);
+ if (value > 0)
+ COLS = value;
+ }
+#ifdef TIOCGWINSZ
+ /*
+ | get the window size
+ */
+ if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
+ {
+ if (ws.ws_row > 0)
+ LINES = ws.ws_row;
+ if (ws.ws_col > 0)
+ COLS = ws.ws_col;
+ }
+#endif
+ virtual_scr = newwin(LINES, COLS, 0, 0);
+ stdscr = newwin(LINES, COLS, 0, 0);
+ curscr = newwin(LINES, COLS, 0, 0);
+ wmove(stdscr, 0, 0);
+ werase(stdscr);
+ Repaint_screen = TRUE;
+ initialized = TRUE;
+ virtual_lines = (int *) malloc(LINES * (sizeof(int)));
+
+#ifdef SIGWINCH
+ /*
+ | reset size of windows and LINES and COLS if term window
+ | changes size
+ */
+ signal(SIGWINCH, reinitscr);
+#endif /* SIGWINCH */
+
+ /*
+ | check if scrolling is available
+ */
+
+ nc_scrolling_ability = ((String_table[al__] != NULL) &&
+ (String_table[dl__])) || ((String_table[cs__])
+ && (String_table[sr__]));
+
+}
+
+#ifndef CAP
+int
+Get_int() /* get a two-byte integer from the terminfo file */
+{
+ int High_byte;
+ int Low_byte;
+ int temp;
+
+ Low_byte = *((unsigned char *) TERM_data_ptr++);
+ High_byte = *((unsigned char *) TERM_data_ptr++);
+ if (Flip_Bytes)
+ {
+ temp = Low_byte;
+ Low_byte = High_byte;
+ High_byte = temp;
+ }
+ if ((High_byte == 255) && (Low_byte == 255))
+ return (-1);
+ else
+ return(Low_byte + (High_byte * 256));
+}
+
+int
+INFO_PARSE() /* parse off the data in the terminfo data file */
+{
+ int offset;
+ int magic_number = 0;
+ int counter = 0;
+ int Num_names = 0;
+ int Num_bools = 0;
+ int Num_ints = 0;
+ int Num_strings = 0;
+ int string_table_len = 0;
+ char *temp_ptr;
+
+ TERM_data_ptr = Data_Line = malloc((10240 * (sizeof(char))));
+ Data_Line_len = read(Fildes, Data_Line, 10240);
+ if ((Data_Line_len >= 10240) || (Data_Line_len < 0))
+ return(0);
+ /*
+ | get magic number
+ */
+ magic_number = Get_int();
+ /*
+ | if magic number not right, reverse byte order and check again
+ */
+ if (magic_number != 282)
+ {
+ Flip_Bytes = TRUE;
+ TERM_data_ptr--;
+ TERM_data_ptr--;
+ magic_number = Get_int();
+ if (magic_number != 282)
+ return(0);
+ }
+ /*
+ | get the number of each type in the terminfo data file
+ */
+ Num_names = Get_int();
+ Num_bools = Get_int();
+ Num_ints = Get_int();
+ Num_strings = Get_int();
+ string_table_len = Get_int();
+ Strings = malloc(string_table_len);
+ while (Num_names > 0)
+ {
+ TERM_data_ptr++;
+ Num_names--;
+ }
+ counter = 0;
+ while (Num_bools)
+ {
+ Num_bools--;
+ Booleans[counter++] = *TERM_data_ptr++;
+ }
+ if (((unsigned int) TERM_data_ptr) & 1) /* force alignment */
+ TERM_data_ptr++;
+ counter = 0;
+ while (Num_ints)
+ {
+ Num_ints--;
+ Numbers[counter] = Get_int();
+ counter++;
+ }
+ temp_ptr = TERM_data_ptr + Num_strings + Num_strings;
+ memcpy(Strings, temp_ptr, string_table_len);
+ counter = bt__;
+ while (Num_strings)
+ {
+ Num_strings--;
+ if ((offset=Get_int()) != -1)
+ {
+ if (String_table[counter] == NULL)
+ String_table[counter] = Strings + offset;
+ }
+ else
+ String_table[counter] = NULL;
+ counter++;
+ }
+ close(Fildes);
+ free(Data_Line);
+ return(TRUE);
+}
+#endif /* ifndef CAP */
+
+int
+AtoI() /* convert ascii text to integers */
+{
+ int Temp;
+
+ Temp = 0;
+ while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Temp = (Temp * 10) + (*TERM_data_ptr - '0');
+ TERM_data_ptr++;
+ }
+ return(Temp);
+}
+
+void
+Key_Get() /* create linked list with all key sequences obtained from terminal database */
+{
+ int Counter;
+ int Klen;
+ int key_def;
+ struct KEY_STACK *Spoint;
+
+ Max_Key_len = 0;
+ Counter = 0;
+ key_def = kb__;
+ while (key_def <= kf63__)
+ {
+ if (key_def == ke__)
+ key_def = K1__;
+ else if (key_def == (K5__ + 1))
+ key_def = kcbt__;
+ else if (key_def == (kcbt__ + 1))
+ key_def = kbeg__;
+ else if (key_def == (kUND__ + 1))
+ key_def = kf11__;
+ if (String_table[key_def] != NULL)
+ {
+ if (KEY_TOS == NULL)
+ Spoint = KEY_TOS = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ else
+ {
+ Spoint = KEY_TOS;
+ while (Spoint->next != NULL)
+ Spoint = Spoint->next;
+ Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ Spoint = Spoint->next;
+ }
+ Spoint->next = NULL;
+ Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
+ Spoint->element->string = String_table[key_def];
+ Spoint->element->length = strlen(String_table[key_def]);
+ Spoint->element->value = Key_vals[Counter];
+ Klen = strlen(Spoint->element->string);
+ if (Klen > Max_Key_len)
+ Max_Key_len = Klen;
+ /*
+ | Some terminal types accept keystrokes of the form
+ | \E[A and \EOA, substituting '[' for 'O'. Make a
+ | duplicate of such key strings (since the
+ | database will only have one version) so new_curse
+ | can understand both.
+ */
+ if ((Spoint->element->length > 1) &&
+ ((String_table[key_def][1] == '[') ||
+ (String_table[key_def][1] == 'O')))
+ {
+ Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ Spoint = Spoint->next;
+ Spoint->next = NULL;
+ Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
+ Spoint->element->length = strlen(String_table[key_def]);
+ Spoint->element->string = malloc(Spoint->element->length + 1);
+ strcpy(Spoint->element->string, String_table[key_def]);
+ Spoint->element->value = Key_vals[Counter];
+ Klen = strlen(Spoint->element->string);
+ if (Klen > Max_Key_len)
+ Max_Key_len = Klen;
+
+ if (String_table[key_def][1] == '[')
+ Spoint->element->string[1] = 'O';
+ else
+ Spoint->element->string[1] = '[';
+ }
+ }
+ key_def++;
+ Counter++;
+ }
+}
+
+#ifdef CAP
+char *
+String_Get(param) /* read the string */
+char *param;
+{
+ char *String;
+ char *Temp;
+ int Counter;
+
+ if (param == NULL)
+ {
+ while (*TERM_data_ptr != '=')
+ TERM_data_ptr++;
+ Temp = ++TERM_data_ptr;
+ Counter = 1;
+ while ((*Temp != ':') && (*Temp != (char)NULL))
+ {
+ Counter++;
+ Temp++;
+ }
+ if (Counter == 1) /* no data */
+ return(NULL);
+ String = Temp = malloc(Counter);
+ while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
+ {
+ if (*TERM_data_ptr == '\\')
+ {
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == 'n')
+ *Temp = '\n';
+ else if (*TERM_data_ptr == 't')
+ *Temp = '\t';
+ else if (*TERM_data_ptr == 'b')
+ *Temp = '\b';
+ else if (*TERM_data_ptr == 'r')
+ *Temp = '\r';
+ else if (*TERM_data_ptr == 'f')
+ *Temp = '\f';
+ else if ((*TERM_data_ptr == 'e') || (*TERM_data_ptr == 'E'))
+ *Temp = '\033'; /* escape */
+ else if (*TERM_data_ptr == '\\')
+ *Temp = '\\';
+ else if (*TERM_data_ptr == '\'')
+ *Temp = '\'';
+ else if ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Counter = 0;
+ while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Counter = (8 * Counter) + (*TERM_data_ptr - '0');
+ TERM_data_ptr++; /* ? */
+ }
+ *Temp = Counter;
+ TERM_data_ptr--;
+ }
+ TERM_data_ptr++;
+ Temp++;
+ }
+ else if (*TERM_data_ptr == '^')
+ {
+ TERM_data_ptr++;
+ if ((*TERM_data_ptr >= '@') && (*TERM_data_ptr <= '_'))
+ *Temp = *TERM_data_ptr - '@';
+ else if (*TERM_data_ptr == '?')
+ *Temp = 127;
+ TERM_data_ptr++;
+ Temp++;
+ }
+ else
+ *Temp++ = *TERM_data_ptr++;
+ }
+ *Temp = (char)NULL;
+ param = String;
+ }
+ else
+ {
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != ':'))
+ TERM_data_ptr++;
+ }
+ return(param);
+}
+
+int
+tc_Get_int(param) /* read the integer */
+int param;
+{
+ int Itemp;
+
+ if (param == 0)
+ {
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '#'))
+ TERM_data_ptr++;
+ TERM_data_ptr++;
+ Itemp = AtoI();
+ param = Itemp;
+ }
+ else
+ {
+ while (*TERM_data_ptr != ':')
+ TERM_data_ptr++;
+ }
+ return(param);
+}
+
+void
+Find_term() /* find terminal description in termcap file */
+{
+ char *Name;
+ char *Ftemp;
+
+ Ftemp = Name = malloc(strlen(TERMINAL_TYPE + 1) + 1);
+ strcpy(Name, TERMINAL_TYPE);
+ while (*Ftemp != (char)NULL)
+ Ftemp++;
+ *Ftemp++ = '|';
+ *Ftemp = (char)NULL;
+ CFOUND = FALSE;
+ Data_Line_len = strlen(TERMINAL_TYPE) + 1;
+ while ((!CFOUND) && ((TERM_data_ptr=fgets(Data_Line, 512, TFP)) != NULL))
+ {
+ if ((*TERM_data_ptr != ' ') && (*TERM_data_ptr != '\t') && (*TERM_data_ptr != '#'))
+ {
+ while ((!CFOUND) && (*TERM_data_ptr != (char)NULL))
+ {
+ CFOUND = !strncmp(TERM_data_ptr, Name, Data_Line_len);
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '|') && (*TERM_data_ptr != '#') && (*TERM_data_ptr != ':'))
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == '|')
+ TERM_data_ptr++;
+ else if (!CFOUND)
+ *TERM_data_ptr = (char)NULL;
+ }
+ }
+ }
+ if (!CFOUND)
+ {
+ printf("terminal type %s not found\n", TERMINAL_TYPE);
+ exit(0);
+ }
+}
+
+void
+CAP_PARSE() /* parse off the data in the termcap data file */
+{
+ int offset;
+ int found;
+
+ do
+ {
+ while (*TERM_data_ptr != (char)NULL)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < 26); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, Boolean_names[offset], 2))
+ {
+ found = TRUE;
+ Booleans[offset] = TRUE;
+ }
+ }
+ if (!found)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < lw__); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, Number_names[offset], 3))
+ {
+ found = TRUE;
+ Numbers[offset] = tc_Get_int(Numbers[offset]);
+ }
+ }
+ }
+ if (!found)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < smgr__); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, String_names[offset], 3))
+ {
+ found = TRUE;
+ String_table[offset] = String_Get(String_table[offset]);
+ }
+ }
+ }
+
+ if (!strncmp(TERM_data_ptr, "tc=", 3))
+ tc_ = String_Get(NULL);
+ while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == ':')
+ TERM_data_ptr++;
+ }
+ } while (((TERM_data_ptr = fgets(Data_Line, 512, TFP)) != NULL) && ((*TERM_data_ptr == ' ') || (*TERM_data_ptr == '\t')));
+ if (tc_ != NULL)
+ {
+ TERMINAL_TYPE = tc_;
+ rewind(TFP);
+ Find_term();
+ free(tc_);
+ tc_ = NULL;
+ CAP_PARSE();
+ }
+ else
+ fclose(TFP);
+}
+#endif /* ifdef CAP */
+
+struct _line *
+Screenalloc(columns)
+int columns;
+{
+ int i;
+ struct _line *tmp;
+
+ tmp = (struct _line *) malloc(sizeof (struct _line));
+ tmp->row = malloc(columns + 1);
+ tmp->attributes = malloc(columns + 1);
+ tmp->prev_screen = NULL;
+ tmp->next_screen = NULL;
+ for (i = 0; i < columns; i++)
+ {
+ tmp->row[i] = ' ';
+ tmp->attributes[i] = (char) NULL;
+ }
+ tmp->scroll = tmp->changed = FALSE;
+ tmp->row[0] = (char) NULL;
+ tmp->attributes[0] = (char) NULL;
+ tmp->row[columns] = (char) NULL;
+ tmp->attributes[columns] = (char) NULL;
+ tmp->last_char = 0;
+ return(tmp);
+}
+
+WINDOW *newwin(lines, cols, start_l, start_c)
+int lines, cols; /* number of lines and columns to be in window */
+int start_l, start_c; /* starting line and column to be inwindow */
+{
+ WINDOW *Ntemp;
+ struct _line *temp_screen;
+ int i;
+
+ Ntemp = (WINDOW *) malloc(sizeof(WINDOW));
+ Ntemp->SR = start_l;
+ Ntemp->SC = start_c;
+ Ntemp->Num_lines = lines;
+ Ntemp->Num_cols = cols;
+ Ntemp->LX = 0;
+ Ntemp->LY = 0;
+ Ntemp->scroll_down = Ntemp->scroll_up = 0;
+ Ntemp->SCROLL_CLEAR = FALSE;
+ Ntemp->Attrib = FALSE;
+ Ntemp->first_line = temp_screen = Screenalloc(cols);
+ Ntemp->first_line->number = 0;
+ for (i = 1; i < lines; i++)
+ {
+ temp_screen->next_screen = Screenalloc(cols);
+ temp_screen->next_screen->number = i;
+ temp_screen->next_screen->prev_screen = temp_screen;
+ temp_screen = temp_screen->next_screen;
+ }
+ Ntemp->first_line->prev_screen = NULL;
+ temp_screen->next_screen = NULL;
+ return(Ntemp);
+}
+
+#ifdef CAP
+void
+Cap_Out(string, p_list, place) /* interpret the output string if necessary */
+char *string;
+int p_list[]; /* stack of values */
+int place; /* place keeper of top of stack */
+{
+ char *Otemp; /* temporary string pointer to parse output */
+ int delay;
+ int p1, p2, temp;
+ float chars;
+
+ if (string == NULL)
+ return;
+
+ if (p_list != NULL)
+ {
+ p1 = p_list[--place];
+ p2 = p_list[--place];
+ }
+ delay = 0;
+ Otemp = string;
+ if ((*Otemp >= '0') && (*Otemp <= '9'))
+ {
+ delay = atoi(Otemp);
+ while ((*Otemp >= '0') && (*Otemp <= '9'))
+ Otemp++;
+ if (*Otemp == '*')
+ Otemp++;
+ }
+ while (*Otemp != (char)NULL)
+ {
+ if (*Otemp == '%')
+ {
+ Otemp++;
+ if ((*Otemp == 'd') || (*Otemp == '2') || (*Otemp == '3') || (*Otemp == '.') || (*Otemp == '+'))
+ {
+ if (*Otemp == 'd')
+ printf("%d", p1);
+ else if (*Otemp == '2')
+ printf("%02d", p1);
+ else if (*Otemp == '3')
+ printf("%03d", p1);
+ else if (*Otemp == '+')
+ {
+ Otemp++;
+ p1 += *Otemp;
+ putchar(p1);
+ }
+ else if (*Otemp == '.')
+ putchar(p1);
+ p1 = p2;
+ p2 = 0;
+ }
+ else if (*Otemp == '>')
+ {
+ Otemp++;
+ if (p1 > *Otemp)
+ {
+ Otemp++;
+ p1 += *Otemp;
+ }
+ else
+ Otemp++;
+ }
+ else if (*Otemp == 'r')
+ {
+ temp = p1;
+ p1 = p2;
+ p2 = temp;
+ }
+ else if (*Otemp == 'i')
+ {
+ p1++;
+ p2++;
+ }
+ else if (*Otemp == '%')
+ putchar(*Otemp);
+ else if (*Otemp == 'n')
+ {
+ p1 ^= 0140;
+ p2 ^= 0140;
+ }
+ else if (*Otemp == 'B')
+ {
+ p1 = (16 * (p1/10)) + (p1 % 10);
+ p2 = (16 * (p2/10)) + (p2 % 10);
+ }
+ else if (*Otemp == 'D')
+ {
+ p1 = (p1 - 2 * (p1 % 16));
+ p2 = (p2 - 2 * (p2 % 16));
+ }
+ }
+ else
+ putchar (*Otemp);
+ Otemp++;
+ }
+ if (delay != 0)
+ {
+ chars = delay * chars_per_millisecond;
+ delay = chars;
+ if ((chars - delay) > 0.0)
+ delay++;
+ for (; delay > 0; delay--)
+ putchar(*String_table[pc__]);
+ }
+ fflush(stdout);
+}
+
+#else
+
+ char *Otemp; /* temporary string pointer to parse output */
+ float chars;
+ int p[10];
+ int variable[27];
+
+int
+Operation(Temp_Stack, place) /* handle conditional operations */
+int Temp_Stack[];
+int place;
+{
+ int temp;
+
+ if (*Otemp == 'd')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ printf("%d", temp);
+ }
+ else if (!strncmp(Otemp, "2d", 2))
+ {
+ temp = Temp_Stack[--place];
+ printf("%2d", temp);
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "3d", 2))
+ {
+ temp = Temp_Stack[--place];
+ printf("%0d", temp);
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "02d", 3))
+ {
+ temp = Temp_Stack[--place];
+ printf("%02d", temp);
+ Otemp++;
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "03d", 3))
+ {
+ temp = Temp_Stack[--place];
+ printf("%03d", temp);
+ Otemp++;
+ Otemp++;
+ Otemp++;
+ }
+ else if (*Otemp == '+')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp += Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '-')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp -= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '*')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp *= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '/')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp /= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == 'm')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp %= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '&')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp &= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '|')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp |= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '^')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp ^= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '=')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = (temp == Temp_Stack[--place]);
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '>')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = temp > Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '<')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = temp < Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == 'c')
+ {
+ Otemp++;
+ putchar(Temp_Stack[--place]);
+ }
+ else if (*Otemp == 'i')
+ {
+ Otemp++;
+ p[1]++;
+ p[2]++;
+ }
+ else if (*Otemp == '%')
+ {
+ putchar(*Otemp);
+ Otemp++;
+ }
+ else if (*Otemp == '!')
+ {
+ temp = ! Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ Otemp++;
+ }
+ else if (*Otemp == '~')
+ {
+ temp = ~Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ Otemp++;
+ }
+ else if (*Otemp == 'p')
+ {
+ Otemp++;
+ Temp_Stack[place++] = p[*Otemp - '0'];
+ Otemp++;
+ }
+ else if (*Otemp == 'P')
+ {
+ Otemp++;
+ Temp_Stack[place++] = variable[*Otemp - 'a'];
+ Otemp++;
+ }
+ else if (*Otemp == 'g')
+ {
+ Otemp++;
+ variable[*Otemp - 'a'] = Temp_Stack[--place];
+ Otemp++;
+ }
+ else if (*Otemp == '\'')
+ {
+ Otemp++;
+ Temp_Stack[place++] = *Otemp;
+ Otemp++;
+ Otemp++;
+ }
+ else if (*Otemp == '{')
+ {
+ Otemp++;
+ temp = atoi(Otemp);
+ Temp_Stack[place++] = temp;
+ while (*Otemp != '}')
+ Otemp++;
+ Otemp++;
+ }
+ return(place);
+}
+
+void
+Info_Out(string, p_list, place) /* interpret the output string if necessary */
+char *string;
+int p_list[];
+int place;
+{
+ char *tchar;
+ int delay;
+ int temp;
+ int Cond_FLAG;
+ int EVAL;
+ int Cond_Stack[128];
+ int Cond_place;
+ int Stack[128];
+ int Top_of_stack;
+
+ if (string == NULL)
+ return;
+
+ Cond_FLAG = FALSE;
+ Cond_place = 0;
+ Top_of_stack = 0;
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0;
+ p[4] = 0;
+ p[5] = 0;
+ p[6] = 0;
+ p[7] = 0;
+ p[8] = 0;
+ p[9] = 0;
+ if (p_list != NULL)
+ {
+ for (temp = 1; (place != 0); temp++)
+ {
+ p[temp] = p_list[--place];
+ }
+ }
+ delay = 0;
+ Otemp = string;
+ while (*Otemp != (char) NULL)
+ {
+ if (*Otemp == '%')
+ {
+ Otemp++;
+ if ((*Otemp == '?') || (*Otemp == 't') || (*Otemp == 'e') || (*Otemp == ';'))
+ {
+ if (*Otemp == '?')
+ {
+ Otemp++;
+ Cond_FLAG = TRUE;
+ EVAL = TRUE;
+ while (EVAL)
+ {
+ /*
+ | find the end of the
+ | conditional statement
+ */
+ while ((strncmp(Otemp, "%t", 2)) && (*Otemp != (char) NULL))
+ {
+ /*
+ | move past '%'
+ */
+ Otemp++;
+ Cond_place = Operation(Cond_Stack, Cond_place);
+ }
+
+ /*
+ | if condition is true
+ */
+ if ((Cond_place > 0) && (Cond_Stack[Cond_place-1]))
+ {
+ /*
+ | end conditional
+ | parsing
+ */
+ EVAL = FALSE;
+ Otemp++;
+ Otemp++;
+ }
+ else /* condition is false */
+ {
+ /*
+ | find 'else' or end
+ | of if statement
+ */
+ while ((strncmp(Otemp, "%e", 2)) && (strncmp(Otemp, "%;", 2)) && (*Otemp != (char) NULL))
+ Otemp++;
+ /*
+ | if an 'else' found
+ */
+ if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%e", 2)))
+ {
+ Otemp++;
+ Otemp++;
+ tchar = Otemp;
+ /*
+ | check for 'then' part
+ */
+ while ((*tchar != (char) NULL) && (strncmp(tchar, "%t", 2)) && (strncmp(tchar, "%;", 2)))
+ tchar++;
+ /*
+ | if end of string
+ */
+ if (*tchar == (char) NULL)
+ {
+ EVAL = FALSE;
+ Cond_FLAG = FALSE;
+ Otemp = tchar;
+ }
+ /*
+ | if end of if found,
+ | set up to parse
+ | info
+ */
+ else if (!strncmp(tchar, "%;", 2))
+ EVAL = FALSE;
+ /*
+ | otherwise, check
+ | conditional in
+ | 'else'
+ */
+ }
+ /*
+ | if end of if found,
+ | get out of if
+ | statement
+ */
+ else if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%;", 2)))
+ {
+ EVAL = FALSE;
+ Otemp++;
+ Otemp++;
+ }
+ else /* Otemp == NULL */
+ {
+ EVAL = FALSE;
+ Cond_FLAG = FALSE;
+ }
+ }
+ }
+ }
+ else
+ {
+ Otemp++;
+ Cond_FLAG = FALSE;
+ if (*Otemp != ';')
+ {
+ while ((*Otemp != (char) NULL) && (strncmp(Otemp, "%;", 2)))
+ Otemp++;
+ if (*Otemp != (char) NULL)
+ {
+ Otemp++;
+ Otemp++;
+ }
+ }
+ else
+ Otemp++;
+ }
+ }
+ else
+ {
+ Top_of_stack = Operation(Stack, Top_of_stack);
+ }
+ }
+ else if (!strncmp(Otemp, "$<", 2))
+ {
+ Otemp++;
+ Otemp++;
+ delay = atoi(Otemp);
+ while (*Otemp != '>')
+ Otemp++;
+ Otemp++;
+ chars = delay * chars_per_millisecond;
+ delay = chars;
+ if ((chars - delay) > 0.0)
+ delay++;
+ if (String_table[pc__] == NULL)
+ temp = 0;
+ else
+ temp = *String_table[pc__];
+ for (; delay > 0; delay--)
+ putc(temp, stdout);
+ }
+ else
+ {
+ putchar(*Otemp);
+ Otemp++;
+ }
+ }
+ fflush(stdout);
+}
+#endif
+
+void
+wmove(window, row, column) /* move cursor to indicated position in window */
+WINDOW *window;
+int row, column;
+{
+ if ((row < window->Num_lines) && (column < window->Num_cols))
+ {
+ window->LX = column;
+ window->LY = row;
+ }
+}
+
+void
+clear_line(line, column, cols)
+struct _line *line;
+int column;
+int cols;
+{
+ int j;
+
+ if (column > line->last_char)
+ line->row[line->last_char] = ' ';
+ line->last_char = column;
+ line->row[column] = (char) NULL;
+ line->attributes[column] = (char) NULL;
+ line->changed = TRUE;
+ for (j = column + 1; j < cols; j++)
+ {
+ line->row[j] = ' ';
+ line->attributes[j] = (char) NULL;
+ }
+}
+
+void
+werase(window) /* clear the specified window */
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR = CLEAR;
+ window->scroll_up = window->scroll_down = 0;
+ for (i = 0, tmp = window->first_line; i < window->Num_lines; i++, tmp = tmp->next_screen)
+ clear_line(tmp, 0, window->Num_cols);
+}
+
+void
+wclrtoeol(window) /* erase from current cursor position to end of line */
+WINDOW *window;
+{
+ int column, row;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR = CHANGE;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ clear_line(tmp, column, window->Num_cols);
+}
+
+void
+wrefresh(window) /* flush all previous output */
+WINDOW *window;
+{
+ wnoutrefresh(window);
+#ifdef DIAG
+{
+ struct _line *temp;
+ int value;
+ fprintf(stderr, "columns=%d, lines=%d, SC=%d, SR=%d\n",window->Num_cols, window->Num_lines, window->SC, window->SR);
+ for (value = 0, temp = window->first_line; value < window->Num_lines; value++, temp = temp->next_screen)
+ {
+ if (temp->number == -1)
+ fprintf(stderr, "line moved ");
+ if (temp->scroll)
+ fprintf(stderr, "scroll_x is set: ");
+ fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
+ }
+ fprintf(stderr, "+-------------------- virtual screen ----------------------------------------+\n");
+ fprintf(stderr, "columns=%d, lines=%d \n",virtual_scr->Num_cols, virtual_scr->Num_lines);
+ for (value = 0, temp = virtual_scr->first_line; value < virtual_scr->Num_lines; value++, temp = temp->next_screen)
+ {
+ if (temp->number == -1)
+ fprintf(stderr, "line moved ");
+ if (temp->scroll)
+ fprintf(stderr, "scroll_x is set: ");
+ fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
+ }
+ fprintf(stderr, "columns=%d, lines=%d \n",curscr->Num_cols, curscr->Num_lines);
+ for (value = 0, temp = curscr->first_line; value < curscr->Num_lines; value++, temp = temp->next_screen)
+ fprintf(stderr, "line=%s|\n", temp->row);
+}
+#endif
+ doupdate();
+ virtual_scr->SCROLL_CLEAR = FALSE;
+ virtual_scr->scroll_down = virtual_scr->scroll_up = 0;
+ fflush(stdout);
+}
+
+void
+touchwin(window)
+WINDOW *window;
+{
+ struct _line *user_line;
+ int line_counter = 0;
+
+ for (line_counter = 0, user_line = window->first_line;
+ line_counter < window->Num_lines; line_counter++)
+ {
+ user_line->changed = TRUE;
+ }
+ window->SCROLL_CLEAR = TRUE;
+}
+
+void
+wnoutrefresh(window)
+WINDOW *window;
+{
+ struct _line *user_line;
+ struct _line *virtual_line;
+ int line_counter = 0;
+ int user_col = 0;
+ int virt_col = 0;
+
+ if (window->SR >= virtual_scr->Num_lines)
+ return;
+ user_line = window->first_line;
+ virtual_line = virtual_scr->first_line;
+ virtual_scr->SCROLL_CLEAR = window->SCROLL_CLEAR;
+ virtual_scr->LX = window->LX + window->SC;
+ virtual_scr->LY = window->LY + window->SR;
+ virtual_scr->scroll_up = window->scroll_up;
+ virtual_scr->scroll_down = window->scroll_down;
+ if ((last_window_refreshed == window) && (!window->SCROLL_CLEAR))
+ return;
+ for (line_counter = 0; line_counter < window->SR; line_counter++)
+ {
+ virtual_line = virtual_line->next_screen;
+ }
+ for (line_counter = 0; (line_counter < window->Num_lines)
+ && ((line_counter + window->SR) < virtual_scr->Num_lines);
+ line_counter++)
+ {
+ if ((last_window_refreshed != window) || (user_line->changed) || ((SCROLL | CLEAR) & window->SCROLL_CLEAR))
+ {
+ for (user_col = 0, virt_col = window->SC;
+ (virt_col < virtual_scr->Num_cols)
+ && (user_col < window->Num_cols);
+ virt_col++, user_col++)
+ {
+ virtual_line->row[virt_col] = user_line->row[user_col];
+ virtual_line->attributes[virt_col] = user_line->attributes[user_col];
+ }
+ }
+ if (virtual_scr->Num_cols != window->Num_cols)
+ {
+ if (virtual_line->last_char < (user_line->last_char + window->SC))
+ {
+ if (virtual_line->row[virtual_line->last_char] == (char) NULL)
+ virtual_line->row[virtual_line->last_char] = ' ';
+ virtual_line->last_char =
+ min(virtual_scr->Num_cols,
+ (user_line->last_char + window->SC));
+ }
+ else if (virtual_line->last_char > (user_line->last_char + window->SC))
+ {
+ virtual_line->row[min(virtual_scr->Num_cols,
+ (user_line->last_char + window->SC))] = ' ';
+ }
+ }
+ else
+ virtual_line->last_char = user_line->last_char;
+ virtual_line->row[virtual_line->last_char] = (char) NULL;
+ virtual_line->changed = user_line->changed;
+ virtual_line = virtual_line->next_screen;
+ user_line = user_line->next_screen;
+ }
+ window->SCROLL_CLEAR = FALSE;
+ window->scroll_up = window->scroll_down = 0;
+ last_window_refreshed = window;
+}
+
+void
+flushinp() /* flush input */
+{
+}
+
+void
+ungetch(c) /* push a character back on input */
+int c;
+{
+ if (bufp < 100)
+ in_buff[bufp++] = c;
+}
+
+#ifdef BSD_SELECT
+int
+timed_getchar()
+{
+ struct timeval tv;
+ fd_set fds;
+ int ret_val;
+ int nfds = 1;
+ char temp;
+
+ FD_ZERO(&fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000; /* half a second */
+ FD_SET(0, &fds);
+ Time_Out = FALSE; /* just in case */
+
+ ret_val = select(nfds, &fds, 0, 0, &tv);
+
+ /*
+ | if ret_val is less than zero, there was no input
+ | otherwise, get a character and return it
+ */
+
+ if (ret_val <= 0)
+ {
+ Time_Out = TRUE;
+ return(-1);
+ }
+
+ return(read(0, &temp, 1)? temp : -1);
+}
+#endif
+
+int
+wgetch(window) /* get character from specified window */
+WINDOW *window;
+{
+ int in_value;
+ char temp;
+#ifndef SYS5
+ int old_arg;
+#endif /* SYS5 */
+
+#ifdef BSD_SELECT
+ if (Noblock)
+ in_value = ((bufp > 0) ? in_buff[--bufp] : timed_getchar());
+ else
+ in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
+#else /* BSD_SELECT */
+#ifdef SYS5
+ in_value = ((bufp > 0) ? in_buff[--bufp] :
+ (read(0, &temp, 1)> 0) ? temp : -1);
+#else /* SYS5 */
+ if (Noblock)
+ {
+ Time_Out = FALSE;
+ old_arg = fcntl(0, F_GETFL, 0);
+ in_value = fcntl(0, F_SETFL, old_arg | FNDELAY);
+ }
+ in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
+ if (Noblock)
+ {
+ fcntl(0, F_SETFL, old_arg);
+ if (Time_Out)
+ in_value = -1;
+ }
+#endif /* SYS5 */
+#endif /* BSD_SELECT */
+
+ if (in_value != -1)
+ {
+ in_value &= 0xff;
+ if ((Parity) && (Num_bits < 8))
+ /* strip eighth bit if parity in use */
+ in_value &= 0177;
+ }
+ else if (interrupt_flag)
+ {
+ interrupt_flag = FALSE;
+ in_value = wgetch(window);
+ }
+
+ if ((in_value == '\033') || (in_value == '\037'))/* escape character */
+ in_value = Get_key(in_value);
+ return(in_value);
+}
+
+#ifndef BSD_SELECT
+void
+Clear(arg) /* notify that time out has occurred */
+int arg;
+{
+ Time_Out = TRUE;
+#ifdef DEBUG
+fprintf(stderr, "inside Clear()\n");
+fflush(stderr);
+#endif /* DEBUG */
+}
+#endif /* BSD_SELECT */
+
+int
+Get_key(first_char) /* try to decode key sequence */
+int first_char; /* first character of sequence */
+{
+ int in_char;
+ int Count;
+ char string[128];
+ char *Gtemp;
+ int Found;
+#ifdef SYS5
+ struct termio Gterminal;
+#else
+ struct sgttyb Gterminal;
+#endif
+ struct KEY_STACK *St_point;
+#if (!defined( BSD_SELECT)) || (!defined(SYS5))
+ int value;
+#endif /* BSD_SELECT */
+
+ Count = 0;
+ Gtemp = string;
+ string[Count++] = first_char;
+ string[Count] = (char) NULL;
+ Time_Out = FALSE;
+#ifndef BSD_SELECT
+ signal(SIGALRM, Clear);
+ value = alarm(1);
+#endif /* BSD_SELECT */
+ Noblock = TRUE;
+#ifdef SYS5
+ Gterminal.c_cc[VTIME] = 0; /* timeout value */
+ Gterminal.c_lflag &= ~ICANON; /* disable canonical operation */
+ Gterminal.c_lflag &= ~ECHO; /* disable echo */
+#endif
+ Count = 1;
+ Found = FALSE;
+ while ((Count < Max_Key_len) && (!Time_Out) && (!Found))
+ {
+ in_char = wgetch(stdscr);
+#ifdef DEBUG
+fprintf(stderr, "back in GetKey()\n");
+fflush(stderr);
+#endif /* DEBUG */
+ if (in_char != -1)
+ {
+ string[Count++] = in_char;
+ string[Count] = (char) NULL;
+ St_point = KEY_TOS;
+ while ((St_point != NULL) && (!Found))
+ {
+ if (!strcmp(string, St_point->element->string))
+ Found = TRUE;
+ else
+ St_point = St_point->next;
+ }
+ }
+ }
+#ifndef BSD_SELECT
+ if (!Time_Out)
+ value = alarm(0);
+#endif /* BSD_SELECT */
+#ifdef SYS5
+/* value = ioctl(0, TCSETA, &Terminal);*/
+#else
+ value = ioctl(0, TIOCSETP, &Terminal);
+/* value = fcntl(0, F_SETFL, old_arg);*/
+#endif
+ Noblock = FALSE;
+ if (Found)
+ {
+ return(St_point->element->value);
+ }
+ else
+ {
+ while (Count > 1)
+ {
+ if ((string[--Count] != -1) &&
+ ((unsigned char) (string[Count]) != 255))
+ {
+#ifdef DIAG
+fprintf(stderr, "ungetting character %d\n", string[Count]);fflush(stdout);
+#endif
+ ungetch(string[Count]);
+ }
+ }
+ return(first_char);
+ }
+}
+
+void
+waddch(window, c) /* output the character in the specified window */
+WINDOW *window;
+int c;
+{
+ int row, column;
+ int shift; /* number of spaces to shift if a tab */
+ struct _line *tmpline;
+
+#ifdef DIAG
+/*printf("starting waddch \n");fflush(stdout);*/
+#endif
+ row = window->LY;
+ column = window->LX;
+ if (c == '\t')
+ {
+ shift = (column + 1) % 8;
+ if (shift == 0)
+ shift++;
+ else
+ shift = 9 - shift;
+ while (shift > 0)
+ {
+ shift--;
+ waddch(window, ' ');
+ }
+ }
+ else if ((column < window->Num_cols) && (row < window->Num_lines))
+ {
+ if ((c == '~') && (Booleans[hz__]))
+ c = '@';
+
+ if (( c != '\b') && (c != '\n') && (c != '\r'))
+ {
+ row = 0;
+ tmpline = window->first_line;
+ while (row < window->LY)
+ {
+ row++;
+ tmpline = tmpline->next_screen;
+ }
+ tmpline->row[column] = c;
+ tmpline->attributes[column] = window->Attrib;
+ tmpline->changed = TRUE;
+ if (column >= tmpline->last_char)
+ {
+ if (column > tmpline->last_char)
+ tmpline->row[tmpline->last_char] = ' ';
+ tmpline->row[column + 1] = (char) NULL;
+ tmpline->attributes[column + 1] = (char) NULL;
+ tmpline->last_char = column + 1;
+ }
+ }
+ if (c == '\n')
+ {
+ wclrtoeol(window);
+ window->LX = window->Num_cols;
+ }
+ else if (c == '\r')
+ window->LX = 0;
+ else if (c == '\b')
+ window->LX--;
+ else
+ window->LX++;
+ }
+ if (window->LX >= window->Num_cols)
+ {
+ window->LX = 0;
+ window->LY++;
+ if (window->LY >= window->Num_lines)
+ {
+ window->LY = window->Num_lines - 1;
+/* window->LY = row;
+ wmove(window, 0, 0);
+ wdeleteln(window);
+ wmove(window, row, 0);*/
+ }
+ }
+ window->SCROLL_CLEAR = CHANGE;
+}
+
+void
+winsertln(window) /* insert a blank line into the specified window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+ struct _line *tmp1;
+
+ window->scroll_down += 1;
+ window->SCROLL_CLEAR = SCROLL;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; (row < window->Num_lines) && (tmp->next_screen != NULL); row++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = NULL;
+ tmp1 = tmp;
+ clear_line(tmp1, 0, window->Num_cols);
+ tmp1->number = -1;
+ for (row = 0, tmp = window->first_line; (row < window->LY) && (tmp->next_screen != NULL); row++)
+ tmp = tmp->next_screen;
+ if ((window->LY == (window->Num_lines - 1)) && (window->Num_lines > 1))
+ {
+ tmp1->next_screen = tmp->next_screen;
+ tmp->next_screen = tmp1;
+ tmp->changed = TRUE;
+ tmp->next_screen->prev_screen = tmp;
+ }
+ else if (window->Num_lines > 1)
+ {
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp1;
+ tmp1->prev_screen = tmp->prev_screen;
+ tmp->prev_screen = tmp1;
+ tmp1->next_screen = tmp;
+ tmp->changed = TRUE;
+ tmp->scroll = DOWN;
+ }
+ if (window->LY == 0)
+ window->first_line = tmp1;
+}
+
+void
+wdeleteln(window) /* delete a line in the specified window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+ struct _line *tmpline;
+
+ if (window->Num_lines > 1)
+ {
+ window->scroll_up += 1;
+ window->SCROLL_CLEAR = SCROLL;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ if (window->LY == 0)
+ window->first_line = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ {
+ tmp->next_screen->changed = TRUE;
+ tmp->next_screen->scroll = UP;
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ }
+ tmpline = tmp;
+ clear_line(tmpline, 0, window->Num_cols);
+ tmpline->number = -1;
+ for (row = 0, tmp = window->first_line; tmp->next_screen != NULL; row++)
+ tmp = tmp->next_screen;
+ if (tmp != NULL)
+ {
+ tmp->next_screen = tmpline;
+ tmp->next_screen->prev_screen = tmp;
+ tmp->changed = TRUE;
+ tmp = tmp->next_screen;
+ }
+ else
+ tmp = tmpline;
+ tmp->next_screen = NULL;
+ }
+ else
+ {
+ clear_line(window->first_line, 0, window->Num_cols);
+ }
+}
+
+void
+wclrtobot(window) /* delete from current position to end of the window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR |= CLEAR;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ clear_line(tmp, column, window->Num_cols);
+ for (row = (window->LY + 1); row < window->Num_lines; row++)
+ {
+ tmp = tmp->next_screen;
+ clear_line(tmp, 0, window->Num_cols);
+ }
+ wmove(window, row, column);
+}
+
+void
+wstandout(window) /* begin standout mode in window */
+WINDOW *window;
+{
+ if (Numbers[sg__] < 1) /* if not magic cookie glitch */
+ window->Attrib |= A_STANDOUT;
+}
+
+void
+wstandend(window) /* end standout mode in window */
+WINDOW *window;
+{
+ window->Attrib &= ~A_STANDOUT;
+}
+
+void
+waddstr(window, string) /* write 'string' in window */
+WINDOW *window;
+char *string;
+{
+ char *wstring;
+
+ for (wstring = string; *wstring != (char) NULL; wstring++)
+ waddch(window, *wstring);
+}
+
+void
+clearok(window, flag) /* erase screen and redraw at next refresh */
+WINDOW *window;
+int flag;
+{
+ Repaint_screen = TRUE;
+}
+
+void
+echo() /* turn on echoing */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag |= ECHO; /* enable echo */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags |= ECHO; /* enable echo */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+noecho() /* turn off echoing */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag &= ~ECHO; /* disable echo */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags &= ~ECHO; /* disable echo */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+raw() /* set to read characters immediately */
+{
+ int value;
+
+#ifdef SYS5
+ Intr = Terminal.c_cc[VINTR]; /* get the interrupt character */
+ Terminal.c_lflag &= ~ICANON; /* disable canonical operation */
+ Terminal.c_lflag &= ~ISIG; /* disable signal checking */
+#ifdef FLUSHO
+ Terminal.c_lflag &= ~FLUSHO;
+#endif
+#ifdef PENDIN
+ Terminal.c_lflag &= ~PENDIN;
+#endif
+#ifdef IEXTEN
+ Terminal.c_lflag &= ~IEXTEN;
+#endif
+ Terminal.c_cc[VMIN] = 1; /* minimum of one character */
+ Terminal.c_cc[VTIME] = 255; /* timeout value */
+ Terminal.c_cc[VINTR] = 0; /* eliminate interrupt */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags |= RAW; /* enable raw mode */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+noraw() /* set to normal character read mode */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag |= ICANON; /* enable canonical operation */
+ Terminal.c_lflag |= ISIG; /* enable signal checking */
+ Terminal.c_cc[VEOF] = 4; /* EOF character = 4 */
+ Terminal.c_cc[VEOL] = (char) NULL; /* EOL = 0 */
+ Terminal.c_cc[VINTR] = Intr; /* reset interrupt char */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags &= ~RAW; /* disable raw mode */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+/* old_arg = fcntl(0, F_GETFL, 0);
+ value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
+#endif
+}
+
+void
+nl()
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_iflag |= ICRNL; /* enable carriage-return to line-feed mapping */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+nonl()
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_iflag &= ~ICRNL; /* disable carriage-return to line-feed mapping */
+ Terminal.c_iflag &= ~IGNCR; /* do not ignore carriage-return */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+saveterm()
+{
+}
+
+void
+fixterm()
+{
+}
+
+void
+resetterm()
+{
+}
+
+void
+nodelay(window, flag)
+WINDOW *window;
+int flag;
+{
+}
+
+void
+idlok(window, flag)
+WINDOW *window;
+int flag;
+{
+}
+
+void
+keypad(window, flag)
+WINDOW *window;
+int flag;
+{
+ if (flag)
+ String_Out(String_table[ks__], NULL, 0);
+ else
+ String_Out(String_table[ke__], NULL, 0);
+}
+
+void
+savetty() /* save current tty stats */
+{
+ int value;
+
+#ifdef SYS5
+ value = ioctl(0, TCGETA, &Saved_tty); /* set characteristics */
+#else
+ value = ioctl(0, TIOCGETP, &Saved_tty); /* set characteristics */
+#endif
+}
+
+void
+resetty() /* restore previous tty stats */
+{
+ int value;
+
+#ifdef SYS5
+ value = ioctl(0, TCSETA, &Saved_tty); /* set characteristics */
+#else
+ value = ioctl(0, TIOCSETP, &Saved_tty); /* set characteristics */
+#endif
+}
+
+void
+endwin() /* end windows */
+{
+ keypad(stdscr, FALSE);
+ free(stdscr);
+ initialized = FALSE;
+ delwin(curscr);
+ delwin(virtual_scr);
+ delwin(stdscr);
+#ifndef SYS5
+{
+ int old_arg, value;
+/* old_arg = fcntl(0, F_GETFL, 0);
+ value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
+}
+#endif
+}
+
+void
+delwin(window) /* delete the window structure */
+WINDOW *window;
+{
+ int i;
+
+ for (i = 1; (i < window->Num_lines) && (window->first_line->next_screen != NULL); i++)
+ {
+ window->first_line = window->first_line->next_screen;
+ free(window->first_line->prev_screen->row);
+ free(window->first_line->prev_screen->attributes);
+ free(window->first_line->prev_screen);
+ }
+ if (window == last_window_refreshed)
+ last_window_refreshed = 0;
+ if (window->first_line != NULL)
+ {
+ free(window->first_line->row);
+ free(window->first_line->attributes);
+ free(window->first_line);
+ free(window);
+ }
+}
+
+#ifndef __STDC__
+void
+wprintw(va_alist)
+va_dcl
+#else /* __STDC__ */
+void
+wprintw(WINDOW *window, const char *format, ...)
+#endif /* __STDC__ */
+{
+#ifndef __STDC__
+ WINDOW *window;
+ char *format;
+ va_list ap;
+#else
+ va_list ap;
+#endif
+ int value;
+ char *fpoint;
+ char *wtemp;
+
+#ifndef __STDC__
+ va_start(ap);
+ window = va_arg(ap, WINDOW *);
+ format = va_arg(ap, char *);
+#else /* __STDC__ */
+ va_start(ap, format);
+#endif /* __STDC__ */
+
+ fpoint = (char *) format;
+ while (*fpoint != (char) NULL)
+ {
+ if (*fpoint == '%')
+ {
+ fpoint++;
+ if (*fpoint == 'd')
+ {
+ value = va_arg(ap, int);
+ iout(window, value);
+ }
+ else if (*fpoint == 'c')
+ {
+ value = va_arg(ap, int);
+ waddch(window, value);
+ }
+ else if (*fpoint == 's')
+ {
+ wtemp = va_arg(ap, char *);
+ waddstr(window, wtemp);
+ }
+ fpoint++;
+ }
+ else if (*fpoint == '\\')
+ {
+ fpoint++;
+ if (*fpoint == 'n')
+ waddch(window, '\n');
+ else if ((*fpoint >= '0') && (*fpoint <= '9'))
+ {
+ value = 0;
+ while ((*fpoint >= '0') && (*fpoint <= '9'))
+ {
+ value = (value * 8) + (*fpoint - '0');
+ fpoint++;
+ }
+ waddch(window, value);
+ }
+ fpoint++;
+ }
+ else
+ waddch(window, *fpoint++);
+ }
+#ifdef __STDC__
+ va_end(ap);
+#endif /* __STDC__ */
+}
+
+void
+iout(window, value) /* output characters */
+WINDOW *window;
+int value;
+{
+ int i;
+
+ if ((i = value / 10) != 0)
+ iout(window, i);
+ waddch(window, ((value % 10) + '0'));
+}
+
+int
+Comp_line(line1, line2) /* compare lines */
+struct _line *line1;
+struct _line *line2;
+{
+ int count1, count2;
+ int i;
+ char *att1, *att2;
+ char *c1, *c2;
+
+ c1 = line1->row;
+ c2 = line2->row;
+ att1 = line1->attributes;
+ att2 = line2->attributes;
+ count2 = strlen(c1) + 1;
+ count1 = strlen(c2) + 1;
+ if (count1 > count2)
+ {
+ i = count2;
+ count2 = count1;
+ count1 = i;
+ }
+ if (count2 > (count1 + count1))
+ return(2);
+ i = 0;
+ while ((c1[i] != (char) NULL) && (c2[i] != (char) NULL) && (c1[i] == c2[i]) && (att1[i] == att2[i]))
+ i++;
+ count1 = i + 1;
+ if ((count1 == 1) && (count2 == 1))
+ count1 = 0; /* both lines blank */
+ else if (count2 == count1)
+ count1 = -1; /* equal */
+ else
+ count1 = count2 / count1; /* lines unequal */
+ return(count1);
+}
+
+struct _line *
+Insert_line(row, end_row, window) /* insert line into screen */
+int row;
+int end_row;
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+ struct _line *tmp1;
+
+ for (i = 0, tmp = curscr->first_line; i < window->SR; i++)
+ tmp = tmp->next_screen;
+ if ((end_row + window->SR) == 0)
+ curscr->first_line = curscr->first_line->next_screen;
+ top_of_win = tmp;
+ /*
+ | find bottom line to delete
+ */
+ for (i = 0, tmp = top_of_win; (tmp->next_screen != NULL) && (i < end_row); i++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ tmp1 = tmp;
+ /*
+ | clear deleted line
+ */
+ clear_line(tmp, 0, window->Num_cols);
+ tmp1->number = -1;
+ for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
+ tmp = tmp->next_screen;
+ top_of_win = tmp;
+ for (i = 0, tmp = top_of_win; i < row; i++)
+ tmp = tmp->next_screen;
+ if ((tmp->prev_screen != NULL) && (window->Num_lines > 0))
+ tmp->prev_screen->next_screen = tmp1;
+ tmp1->prev_screen = tmp->prev_screen;
+ tmp->prev_screen = tmp1;
+ tmp1->next_screen = tmp;
+ if ((row + window->SR) == 0)
+ curscr->first_line = tmp1;
+ if (tmp1->next_screen != NULL)
+ tmp1 = tmp1->next_screen;
+
+ if ((!String_table[cs__]) && (end_row < window->Num_lines))
+ {
+ Position(window, (window->SR + end_row), 0);
+ String_Out(String_table[dl__], NULL, 0);
+ }
+ Position(window, (window->SR + row), 0);
+ if (String_table[al__] != NULL)
+ String_Out(String_table[al__], NULL, 0);
+ else
+ String_Out(String_table[sr__], NULL, 0);
+
+ for (i = 0, top_of_win = curscr->first_line; (top_of_win->next_screen != NULL) && (i < window->SR); i++)
+ top_of_win = top_of_win->next_screen;
+ return(tmp1);
+}
+
+
+struct _line *
+Delete_line(row, end_row, window) /* delete a line on screen */
+int row;
+int end_row;
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+ struct _line *tmp1;
+ struct _line *tmp2;
+
+ i = 0;
+ tmp = curscr->first_line;
+ while (i < window->SR)
+ {
+ i++;
+ tmp = tmp->next_screen;
+ }
+ /*
+ | find line to delete
+ */
+ top_of_win = tmp;
+ if ((row + window->SR) == 0)
+ curscr->first_line = top_of_win->next_screen;
+ for (i = 0, tmp = top_of_win; i < row; i++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ tmp2 = tmp->next_screen;
+ tmp1 = tmp;
+ /*
+ | clear deleted line
+ */
+ clear_line(tmp1, 0, window->Num_cols);
+ tmp1->number = -1;
+ /*
+ | find location to insert deleted line
+ */
+ for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
+ tmp = tmp->next_screen;
+ top_of_win = tmp;
+ for (i = 0, tmp = top_of_win; (i < end_row) && (tmp->next_screen != NULL); i++)
+ tmp = tmp->next_screen;
+ tmp1->next_screen = tmp;
+ tmp1->prev_screen = tmp->prev_screen;
+ if (tmp1->prev_screen != NULL)
+ tmp1->prev_screen->next_screen = tmp1;
+ tmp->prev_screen = tmp1;
+
+ Position(window, (window->SR + row), 0);
+ String_Out(String_table[dl__], NULL, 0);
+ if ((!String_table[cs__]) && (end_row < window->Num_lines))
+ {
+ Position(window, (window->SR + end_row), 0);
+ String_Out(String_table[al__], NULL, 0);
+ }
+ else if ((String_table[cs__] != NULL) && (String_table[dl__] == NULL))
+ {
+ Position(window, (window->SR + end_row), 0);
+ putchar('\n');
+ }
+
+ if (row == (window->Num_lines-1))
+ tmp2 = tmp1;
+ if ((row + window->SR) == 0)
+ curscr->first_line = top_of_win = tmp2;
+ return(tmp2);
+}
+
+void
+CLEAR_TO_EOL(window, row, column)
+WINDOW *window;
+int row, column;
+{
+ int x, y;
+ struct _line *tmp1;
+
+ for (y = 0, tmp1 = curscr->first_line; (y < (window->SR+row)) && (tmp1->next_screen != NULL); y++)
+ tmp1 = tmp1->next_screen;
+ for (x = column; x<window->Num_cols; x++)
+ {
+ tmp1->row[x] = ' ';
+ tmp1->attributes[x] = (char) NULL;
+ }
+ tmp1->row[column] = (char) NULL;
+ tmp1->last_char = column;
+ if (column < COLS)
+ {
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(window, row, column);
+ attribute_off();
+ }
+ if (String_table[ce__] != NULL)
+ String_Out(String_table[ce__], NULL, 0);
+ else
+ {
+ for (x = column; x < window->Num_cols; x++)
+ putchar(' ');
+ Curr_x = x;
+ }
+ }
+}
+
+int
+check_delete(window, line, offset, pointer_new, pointer_old)
+WINDOW *window;
+int line, offset;
+struct _line *pointer_new, *pointer_old;
+{
+ int end_old;
+ int end_new;
+ int k;
+ int changed;
+ char *old_lin;
+ char *new_lin;
+ char *old_att;
+ char *new_att;
+
+ changed = FALSE;
+ new_lin = pointer_new->row;
+ new_att = pointer_new->attributes;
+ old_lin = pointer_old->row;
+ old_att = pointer_old->attributes;
+ end_old = end_new = offset;
+ while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (old_lin[end_old] != (char) NULL) && (new_lin[end_old] != (char) NULL))
+ end_old++;
+ if (old_lin[end_old] != (char) NULL)
+ {
+ k = 0;
+ while ((old_lin[end_old+k] == new_lin[end_new+k]) && (new_att[end_new+k] == old_att[end_old+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10))
+ k++;
+ if ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0)))
+ {
+ if (new_lin[end_new+k] == (char) NULL)
+ {
+ Position(window, line, (end_new+k));
+ CLEAR_TO_EOL(window, line, (end_new+k));
+ }
+ Position(window, line, offset);
+ for (k = offset; k < end_old; k++)
+ Char_del(old_lin, old_att, offset, window->Num_cols);
+ while ((old_lin[offset] != (char) NULL) && (offset < COLS))
+ offset++;
+ pointer_old->last_char = offset;
+ changed = TRUE;
+ }
+ }
+ return(changed);
+}
+
+int
+check_insert(window, line, offset, pointer_new, pointer_old)
+WINDOW *window;
+int line, offset;
+struct _line *pointer_new, *pointer_old;
+{
+ int changed;
+ int end_old, end_new;
+ int k;
+ int same = FALSE;
+ int old_off;
+ int insert;
+ char *old_lin;
+ char *new_lin;
+ char *old_att;
+ char *new_att;
+
+ changed = FALSE;
+ new_lin = pointer_new->row;
+ new_att = pointer_new->attributes;
+ old_lin = pointer_old->row;
+ old_att = pointer_old->attributes;
+ end_old = end_new = offset;
+ while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (new_lin[end_new] != (char) NULL) && (old_lin[end_new] != (char) NULL))
+ end_new++;
+ if (new_lin[end_new] != (char) NULL)
+ {
+ k = 0;
+ while ((old_lin[end_old+k] == new_lin[end_new+k]) && (old_att[end_old+k] == new_att[end_new+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10))
+ k++;
+ /*
+ | check for commonality between rest of lines (are the old
+ | and new lines the same, except for a chunk in the middle?)
+ | if the rest of the lines are common, do not insert text
+ */
+ old_off = end_new;
+ while ((old_lin[old_off] != (char) NULL) && (new_lin[old_off] != (char) NULL) && (old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
+ old_off++;
+ if ((old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
+ same = TRUE;
+ if ((!same) && ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0))))
+ {
+ Position(window, line, offset);
+ insert = FALSE;
+ if (String_table[ic__] == NULL)
+ {
+ String_Out(String_table[im__], NULL, 0);
+ insert = TRUE;
+ }
+ for (k = offset; k < end_new; k++)
+ {
+ if (!insert)
+ String_Out(String_table[ic__], NULL, 0);
+ Char_ins(old_lin, old_att, new_lin[k], new_att[k], k, window->Num_cols);
+ }
+ if (insert)
+ String_Out(String_table[ei__], NULL, 0);
+ while ((old_lin[offset] != (char) NULL) && (offset < COLS))
+ offset++;
+ pointer_old->last_char = offset;
+ changed = TRUE;
+ }
+ }
+ return(changed);
+}
+
+void
+doupdate()
+{
+ WINDOW *window;
+ int similar;
+ int diff;
+ int begin_old, begin_new;
+ int end_old, end_new;
+ int count1, j;
+ int from_top, tmp_ft, offset;
+ int changed;
+ int first_time;
+ int first_same;
+ int last_same;
+ int list[10];
+
+ struct _line *curr;
+ struct _line *virt;
+ struct _line *old;
+
+ struct _line *new;
+
+ char *cur_lin;
+ char *vrt_lin;
+ char *cur_att;
+ char *vrt_att;
+ char *att1, *att2;
+ char *c1, *c2;
+
+ window = virtual_scr;
+
+ if (Repaint_screen)
+ {
+ if (String_table[cl__])
+ String_Out(String_table[cl__], NULL, 0);
+ else
+ {
+ from_top = 0;
+ while (from_top < LINES)
+ {
+ Position(curscr, from_top, 0);
+ if (String_table[ce__] != NULL)
+ String_Out(String_table[ce__], NULL, 0);
+ else
+ {
+ for (j = 0; j < window->Num_cols; j++)
+ putchar(' ');
+ }
+ from_top++;
+ }
+ }
+ for (from_top = 0, curr = curscr->first_line; from_top < curscr->Num_lines; from_top++, curr = curr->next_screen)
+ {
+ Position(curscr, from_top, 0);
+ for (j = 0; (curr->row[j] != (char) NULL) && (j < curscr->Num_cols); j++)
+ {
+ Char_out(curr->row[j], curr->attributes[j], curr->row, curr->attributes, j);
+ }
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(curscr, from_top, j);
+ attribute_off();
+ }
+ }
+ Repaint_screen = FALSE;
+ }
+
+ similar = 0;
+ diff = FALSE;
+ top_of_win = curscr->first_line;
+
+ for (from_top = 0, curr = top_of_win, virt = window->first_line;
+ from_top < window->Num_lines; from_top++)
+ {
+ virtual_lines[from_top] = TRUE;
+ if ((similar = Comp_line(curr, virt)) > 0)
+ {
+ virtual_lines[from_top] = FALSE;
+ diff = TRUE;
+ }
+ curr = curr->next_screen;
+ virt = virt->next_screen;
+ }
+
+ from_top = 0;
+ virt = window->first_line;
+ curr = top_of_win;
+ similar = 0;
+ /*
+ | if the window has lines that are different
+ */
+ if (diff)
+ {
+ last_same = -1;
+ changed = FALSE;
+ for (first_same = window->Num_lines;
+ (first_same > from_top) && (virtual_lines[first_same - 1]);
+ first_same--)
+ ;
+ count1 = first_same - 1;
+ for (last_same = 0;
+ (last_same < window->Num_lines) && (virtual_lines[last_same]== FALSE);
+ last_same++)
+ ;
+ while ((from_top < first_same) && nc_scrolling_ability)
+ /* check entire lines for diffs */
+ {
+
+
+ if (from_top >= last_same)
+ {
+ for (last_same = from_top;
+ (last_same < window->Num_lines) &&
+ (virtual_lines[last_same] == FALSE);
+ last_same++)
+ ;
+ }
+ if (!virtual_lines[from_top])
+ {
+ diff = TRUE;
+ /*
+ | check for lines deleted (scroll up)
+ */
+ for (tmp_ft = from_top+1, old = curr->next_screen;
+ ((window->scroll_up) && (diff) &&
+ (tmp_ft < last_same) &&
+ (!virtual_lines[tmp_ft]));
+ tmp_ft++)
+ {
+ if ((Comp_line(old, virt) == -1) && (!virtual_lines[from_top]))
+ {
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = from_top;
+ list[0] = min((last_same - 1), (window->Num_lines - 1));
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ for (offset = (tmp_ft - from_top); (offset > 0); offset--)
+ {
+ old = Delete_line(from_top, min((last_same - 1), (window->Num_lines - 1)), window);
+ diff = FALSE;
+ }
+
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = 0;
+ list[0] = LINES;
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ top_of_win = curscr->first_line;
+ curr = top_of_win;
+ for (offset = 0; offset < from_top; offset++)
+ curr = curr->next_screen;
+ for (offset = from_top, old=curr, new=virt;
+ offset < window->Num_lines;
+ old=old->next_screen, new=new->next_screen,
+ offset++)
+ {
+ similar = Comp_line(old, new);
+ virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
+ }
+ }
+ else
+ old = old->next_screen;
+ }
+ /*
+ | check for lines inserted (scroll down)
+ */
+ for (tmp_ft = from_top-1, old = curr->prev_screen;
+ ((window->scroll_down) && (tmp_ft >= 0) &&
+ (diff) &&
+ (!virtual_lines[tmp_ft]));
+ tmp_ft--)
+ {
+ if (Comp_line(old, virt) == -1)
+ {
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = tmp_ft;
+ list[0] = min((last_same - 1), (window->Num_lines - 1));
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ for (offset = (from_top - tmp_ft); (offset > 0); offset--)
+ {
+ old = Insert_line(tmp_ft, min((last_same - 1), (window->Num_lines -1)), window);
+ diff = FALSE;
+ }
+
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = 0;
+ list[0] = LINES;
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ top_of_win = curscr->first_line;
+ curr = top_of_win;
+ for (offset = 0; offset < from_top; offset++)
+ curr = curr->next_screen;
+ for (offset = from_top, old=curr, new=virt;
+ offset < window->Num_lines;
+ old=old->next_screen, new=new->next_screen,
+ offset++)
+ {
+ similar = Comp_line(old, new);
+ virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
+ }
+ }
+ else
+ old = old->prev_screen;
+ }
+ }
+ from_top++;
+ curr = curr->next_screen;
+ virt = virt->next_screen;
+ }
+ }
+
+ for (from_top = 0, curr = curscr->first_line; from_top < window->SR; from_top++)
+ curr = curr->next_screen;
+ top_of_win = curr;
+ for (from_top = 0, curr = top_of_win, virt = window->first_line; from_top < window->Num_lines; from_top++, curr = curr->next_screen, virt = virt->next_screen)
+ {
+ if (((String_table[ic__]) || (String_table[im__])) && (String_table[dc__]) && (curr->row[0] != (char) NULL))
+ {
+ j = 0;
+ first_time = TRUE;
+ vrt_lin = virt->row;
+ vrt_att = virt->attributes;
+ cur_lin = curr->row;
+ cur_att = curr->attributes;
+ while ((vrt_lin[j] != (char) NULL) && (j < window->Num_cols))
+ {
+ if ((STAND) && (Booleans[xs__]))
+ {
+ while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL) && (vrt_att[j]))
+ j++;
+ if ((STAND) && (!vrt_att[j]))
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ attribute_off();
+ }
+ }
+ else
+ {
+ while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL))
+ j++;
+ }
+ if ((vrt_att[j] != cur_att[j]) && (cur_att[j]) && (Booleans[xs__]))
+ {
+ Position(window, from_top, j);
+/* CLEAR_TO_EOL(window, from_top, j);*/
+ attribute_off();
+ attribute_off();
+ }
+ if (vrt_lin[j] != (char) NULL)
+ {
+ begin_new = j;
+ begin_old = j;
+ end_old = j;
+ end_new = j;
+ if ((first_time) && (virt->changed))
+ {
+ if (curr->last_char <= virt->last_char)
+ changed = check_insert(window, from_top, j, virt, curr);
+ }
+ changed = check_delete(window, from_top, j, virt, curr);
+ first_time = FALSE;
+ virt->changed = FALSE;
+ if (!changed)
+ changed = check_insert(window, from_top, j, virt, curr);
+ if (((!changed) || (cur_lin[j] != vrt_lin[j]) || (cur_att[j] != vrt_att[j])) && (j < window->Num_cols))
+ {
+ if ((vrt_lin[j] == ' ') && (cur_lin[j] == (char) NULL) && (vrt_att[j] == cur_att[j]))
+ cur_lin[j] = ' ';
+ else
+ {
+ Position(window, from_top, j);
+ Char_out(vrt_lin[j], vrt_att[j], cur_lin, cur_att, j);
+ }
+ }
+ if ((vrt_lin[j] != (char) NULL))
+ j++;
+ }
+ if ((STAND) && (!vrt_att[j]))
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ }
+ }
+ if ((vrt_lin[j] == (char) NULL) && (cur_lin[j] != (char) NULL))
+ {
+ Position(window, from_top, j);
+ CLEAR_TO_EOL(window, from_top, j);
+ }
+ }
+ else /*if ((similar != -1) && (similar != 0))*/
+ {
+ j = 0;
+ c1 = curr->row;
+ att1 = curr->attributes;
+ c2 = virt->row;
+ att2 = virt->attributes;
+ while ((j < window->Num_cols) && (c2[j] != (char) NULL))
+ {
+ while ((c1[j] == c2[j]) && (att1[j] == att2[j]) && (j < window->Num_cols) && (c2[j] != (char) NULL))
+ j++;
+ begin_old = j;
+ begin_new = j;
+ if ((j < window->Num_cols) && (c2[j] != (char) NULL))
+ {
+ Position(window, from_top, begin_old);
+ CLEAR_TO_EOL(window, from_top, j);
+ Position(window, from_top, begin_old);
+ for (j = begin_old; (c2[j] != (char) NULL) && (j < window->Num_cols); j++)
+ Char_out(c2[j], att2[j], c1, att1, j);
+ }
+ }
+ if ((c2[j] == (char) NULL) && (c1[j] != (char) NULL))
+ {
+ Position(window, from_top, j);
+ CLEAR_TO_EOL(window, from_top, j);
+ }
+ }
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ }
+ virt->number = from_top;
+ }
+ Position(window, window->LY, window->LX);
+}
+
+void
+Position(window, row, col) /* position the cursor for output on the screen */
+WINDOW *window;
+int row;
+int col;
+{
+ int list[10];
+ int place;
+
+ int pos_row;
+ int pos_column;
+
+ pos_row = row + window->SR;
+ pos_column = col + window->SC;
+ if ((pos_row != Curr_y) || (pos_column != Curr_x))
+ {
+ if (String_table[cm__] != NULL) /* && (row < window->Num_lines) && (column < window->Num_cols))*/
+ {
+ place = 0;
+ list[place++] = pos_column;
+ list[place++] = pos_row;
+ String_Out(String_table[cm__], list, place);
+ if ((STAND) && (!Booleans[ms__]))
+ attribute_on();
+ }
+ Curr_x = pos_column;
+ Curr_y = pos_row;
+ }
+}
+
+void
+Char_del(line, attrib, offset, maxlen) /* delete chars from line */
+char *line;
+char *attrib;
+int offset;
+int maxlen;
+{
+ int one, two;
+
+ for (one = offset, two = offset+1; (line[one] != (char) NULL) && (one < maxlen); one++, two++)
+ {
+ line[one] = line[two];
+ attrib[one] = attrib[two];
+ }
+ String_Out(String_table[dc__], NULL, 0);
+}
+
+void
+Char_ins(line, attrib, newc, newatt, offset, maxlen) /* insert chars in line */
+char *line;
+char *attrib;
+char newc;
+char newatt;
+int offset;
+int maxlen;
+{
+ int one, two;
+
+ one = 0;
+ while ((line[one] != (char) NULL) && (one < (maxlen - 2)))
+ one++;
+ for (two = one + 1; (two > offset); one--, two--)
+ {
+ line[two] = line[one];
+ attrib[two] = attrib[one];
+ }
+ line[offset] = newc;
+ attrib[offset] = newatt;
+ Char_out(newc, newatt, line, attrib, offset);
+}
+
+void
+attribute_on()
+{
+ if (String_table[sa__])
+ {
+ attributes_set[0] = 1;
+ String_Out(String_table[sa__], attributes_set, 1);
+ }
+ else if (String_table[so__])
+ String_Out(String_table[so__], NULL, 0);
+}
+
+void
+attribute_off()
+{
+ if (String_table[me__])
+ String_Out(String_table[me__], NULL, 0);
+ else if (String_table[sa__])
+ {
+ attributes_set[0] = 0;
+ String_Out(String_table[sa__], attributes_set, 1);
+ }
+ else if (String_table[se__])
+ String_Out(String_table[se__], NULL, 0);
+}
+
+void
+Char_out(newc, newatt, line, attrib, offset) /* output character with proper attribute */
+char newc;
+char newatt;
+char *line;
+char *attrib;
+int offset;
+{
+
+
+ if ((newatt) && (!STAND))
+ {
+ STAND = TRUE;
+ attribute_on();
+ }
+ else if ((STAND) && (!newatt))
+ {
+ STAND = FALSE;
+ attribute_off();
+ }
+
+ if ((newatt) && (STAND) && (Booleans[xs__]))
+ {
+ attribute_on();
+ }
+
+ if (!((Curr_y >= (LINES - 1)) && (Curr_x >= (COLS - 1))))
+ {
+ putchar(newc);
+ line[offset] = newc;
+ attrib[offset] = newatt;
+ }
+ Curr_x++;
+}
+
diff --git a/usr.bin/ee/new_curse.h b/usr.bin/ee/new_curse.h
new file mode 100644
index 0000000..86a8574
--- /dev/null
+++ b/usr.bin/ee/new_curse.h
@@ -0,0 +1,255 @@
+/*
+ | new_curse.h
+ |
+ | A subset of curses developed for use with ae.
+ |
+ | written by Hugh Mahon
+ |
+ | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+ | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+ | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+ | IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ | FITNESS FOR A PARTICULAR PURPOSE. Neither
+ | Hewlett-Packard nor Hugh Mahon shall be liable
+ | for errors contained herein, nor for
+ | incidental or consequential damages in
+ | connection with the furnishing, performance or
+ | use of this material. Neither Hewlett-Packard
+ | nor Hugh Mahon assumes any responsibility for
+ | the use or reliability of this software or
+ | documentation. This software and
+ | documentation is totally UNSUPPORTED. There
+ | is no support contract available. Hewlett-
+ | Packard has done NO Quality Assurance on ANY
+ | of the program or documentation. You may find
+ | the quality of the materials inferior to
+ | supported materials.
+ |
+ | This software is not a product of Hewlett-Packard, Co., or any
+ | other company. No support is implied or offered with this software.
+ | You've got the source, and you're on your own.
+ |
+ | This software may be distributed under the terms of Larry Wall's
+ | Artistic license, a copy of which is included in this distribution.
+ |
+ | This notice must be included with this software and any derivatives.
+ |
+ | Copyright (c) 1986, 1987, 1988, 1991, 1995 Hugh Mahon
+ | All are rights reserved.
+ |
+ */
+
+#include <stdio.h>
+
+#ifdef SYS5
+#include <termio.h>
+#else
+#include <sgtty.h>
+#include <fcntl.h>
+#endif
+
+#define KEY_BREAK 0401
+#define KEY_DOWN 0402
+#define KEY_UP 0403
+#define KEY_LEFT 0404
+#define KEY_RIGHT 0405
+#define KEY_HOME 0406
+#define KEY_BACKSPACE 0407
+#define KEY_F0 0410
+#define KEY_F(n) (KEY_F0+(n))
+#define KEY_DL 0510
+#define KEY_IL 0511
+#define KEY_DC 0512
+#define KEY_IC 0513
+#define KEY_EIC 0514
+#define KEY_CLEAR 0515
+#define KEY_EOS 0516
+#define KEY_EOL 0517
+#define KEY_SF 0520
+#define KEY_SR 0521
+#define KEY_NPAGE 0522
+#define KEY_PPAGE 0523
+#define KEY_STAB 0524
+#define KEY_CTAB 0525
+#define KEY_CATAB 0526
+#define KEY_ENTER 0527
+#define KEY_SRESET 0530
+#define KEY_RESET 0531
+#define KEY_PRINT 0532
+#define KEY_LL 0533
+#define KEY_A1 0534
+#define KEY_A3 0535
+#define KEY_B2 0536
+#define KEY_C1 0537
+#define KEY_C3 0540
+#define KEY_BTAB 0541
+#define KEY_BEG 0542
+#define KEY_CANCEL 0543
+#define KEY_CLOSE 0544
+#define KEY_COMMAND 0545
+#define KEY_COPY 0546
+#define KEY_CREATE 0547
+#define KEY_END 0550
+#define KEY_EXIT 0551
+#define KEY_FIND 0552
+#define KEY_HELP 0553
+#define KEY_MARK 0554
+#define KEY_MESSAGE 0555
+#define KEY_MOVE 0556
+#define KEY_NEXT 0557
+#define KEY_OPEN 0560
+#define KEY_OPTIONS 0561
+#define KEY_PREVIOUS 0562
+#define KEY_REDO 0563
+#define KEY_REFERENCE 0564
+#define KEY_REFRESH 0565
+#define KEY_REPLACE 0566
+#define KEY_RESTART 0567
+#define KEY_RESUME 0570
+#define KEY_SAVE 0571
+#define KEY_SBEG 0572
+#define KEY_SCANCEL 0573
+#define KEY_SCOMMAND 0574
+#define KEY_SCOPY 0575
+#define KEY_SCREATE 0576
+#define KEY_SDC 0577
+#define KEY_SDL 0600
+#define KEY_SELECT 0601
+#define KEY_SEND 0602
+#define KEY_SEOL 0603
+#define KEY_SEXIT 0604
+#define KEY_SFIND 0605
+#define KEY_SHELP 0606
+#define KEY_SHOME 0607
+#define KEY_SIC 0610
+#define KEY_SLEFT 0611
+#define KEY_SMESSAGE 0612
+#define KEY_SMOVE 0613
+#define KEY_SNEXT 0614
+#define KEY_SOPTIONS 0615
+#define KEY_SPREVIOUS 0616
+#define KEY_SPRINT 0617
+#define KEY_SREDO 0620
+#define KEY_SREPLACE 0621
+#define KEY_SRIGHT 0622
+#define KEY_SRSUME 0623
+#define KEY_SSAVE 0624
+#define KEY_SSUSPEND 0625
+#define KEY_SUNDO 0626
+#define KEY_SUSPEND 0627
+#define KEY_UNDO 0630
+
+#define TRUE 1
+#define FALSE 0
+
+#define A_STANDOUT 0001 /* standout mode */
+#define SCROLL 1 /* text has been scrolled */
+#define CLEAR 2 /* window has been cleared */
+#define CHANGE 3 /* window has been changed */
+#define UP 1 /* direction of scroll */
+#define DOWN 2
+
+struct _line {
+ struct _line *next_screen;
+ struct _line *prev_screen;
+ char *row;
+ char *attributes;
+ int last_char;
+ int changed;
+ int scroll;
+ int number;
+ };
+
+struct _line *top_of_win;
+
+typedef struct WIND {
+ int SR; /* starting row */
+ int SC; /* starting column */
+ int LC; /* last column */
+ int LX; /* last cursor column position */
+ int LY; /* last cursor row position */
+ int Attrib; /* attributes active in window */
+ int Num_lines; /* number of lines */
+ int Num_cols; /* number of columns */
+ int scroll_up; /* number of lines moved */
+ int scroll_down;
+ int SCROLL_CLEAR; /* indicates that window has been scrolled or cleared */
+ struct _line *first_line;
+ } WINDOW;
+
+extern WINDOW *curscr;
+extern WINDOW *stdscr;
+
+extern int LINES, COLS;
+
+#if __STDC__ || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+
+extern void copy_window P_((WINDOW *origin, WINDOW *destination));
+extern void reinitscr P_((int));
+extern void initscr P_((void));
+extern int Get_int P_((void));
+extern int INFO_PARSE P_((void));
+extern int AtoI P_((void));
+extern void Key_Get P_((void));
+extern struct _line *Screenalloc P_((int columns));
+extern WINDOW *newwin P_((int lines, int cols, int start_l, int start_c));
+extern int Operation P_((int Temp_Stack[], int place));
+extern void Info_Out P_((char *string, int p_list[], int place));
+extern void wmove P_((WINDOW *window, int row, int column));
+extern void clear_line P_((struct _line *line, int column, int cols));
+extern void werase P_((WINDOW *window));
+extern void wclrtoeol P_((WINDOW *window));
+extern void wrefresh P_((WINDOW *window));
+extern void touchwin P_((WINDOW *window));
+extern void wnoutrefresh P_((WINDOW *window));
+extern void flushinp P_((void));
+extern void ungetch P_((int c));
+extern int wgetch P_((WINDOW *window));
+extern void Clear P_((int));
+extern int Get_key P_((int first_char));
+extern void waddch P_((WINDOW *window, int c));
+extern void winsertln P_((WINDOW *window));
+extern void wdeleteln P_((WINDOW *window));
+extern void wclrtobot P_((WINDOW *window));
+extern void wstandout P_((WINDOW *window));
+extern void wstandend P_((WINDOW *window));
+extern void waddstr P_((WINDOW *window, char *string));
+extern void clearok P_((WINDOW *window, int flag));
+extern void echo P_((void));
+extern void noecho P_((void));
+extern void raw P_((void));
+extern void noraw P_((void));
+extern void nl P_((void));
+extern void nonl P_((void));
+extern void saveterm P_((void));
+extern void fixterm P_((void));
+extern void resetterm P_((void));
+extern void nodelay P_((WINDOW *window, int flag));
+extern void idlok P_((WINDOW *window, int flag));
+extern void keypad P_((WINDOW *window, int flag));
+extern void savetty P_((void));
+extern void resetty P_((void));
+extern void endwin P_((void));
+extern void delwin P_((WINDOW *window));
+extern void wprintw P_((WINDOW *window, const char* format, ...));
+extern void iout P_((WINDOW *window, int value));
+extern int Comp_line P_((struct _line *line1, struct _line *line2));
+extern struct _line *Insert_line P_((int row, int end_row, WINDOW *window));
+extern struct _line *Delete_line P_((int row, int end_row, WINDOW *window));
+extern void CLEAR_TO_EOL P_((WINDOW *window, int row, int column));
+extern int check_delete P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old));
+extern int check_insert P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old));
+extern void doupdate P_((void));
+extern void Position P_((WINDOW *window, int row, int col));
+extern void Char_del P_((char *line, char *attrib, int offset, int maxlen));
+extern void Char_ins P_((char *line, char *attrib, int newc, int newatt, int offset, int maxlen));
+extern void attribute_on P_((void));
+extern void attribute_off P_((void));
+extern void Char_out P_((int newc, int newatt, char *line, char *attrib, int offset));
+
+#undef P_
+
diff --git a/usr.bin/ee/nls/de_DE.ISO8859-1/ee.msg b/usr.bin/ee/nls/de_DE.ISO8859-1/ee.msg
new file mode 100644
index 0000000..aab616d
--- /dev/null
+++ b/usr.bin/ee/nls/de_DE.ISO8859-1/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/ncvs/src/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg,v 1.3 1996/12/29 10:54:30 joerg Exp $
+$
+$set 1
+$quote "
+1 "Modus-Menü"
+2 "Tab -> Leerzeichen "
+3 "Suche ohne Groß/Klein"
+4 "Ränder beachten "
+5 "Automatische Absätze "
+6 "8-Bit Zeichen (Uml.) "
+7 "Hilfefenster "
+8 "rechter Rand "
+9 "Ende-Menü"
+10 "Speichern"
+11 "Verwerfen"
+12 "Dateimenü"
+13 "Öffnen"
+14 "Schreiben in Datei"
+15 "Speichern"
+16 "Aktuellen Inhalt drucken"
+17 "Textsuche"
+18 "Suche nach ..."
+19 "Suchen"
+20 "Rechtschreibung"
+21 "'spell' benutzen"
+22 "'ispell' benutzen"
+23 "Verschiedenes"
+24 "Absatz formatieren"
+25 "Unix-Kommando"
+26 "Rechtschreibung prüfen"
+27 "Hauptmenü"
+28 "Editor beenden"
+29 "Hilfe"
+30 "Dateioperationen"
+31 "Bildschirm regenerieren"
+32 "Einstellungen"
+33 "Suche"
+34 "Verschiedenes"
+35 "Steuertasten: "
+36 "^a ASCII-Code direkt ^i Tabulator ^r nach rechts "
+37 "^b Ende des Textes ^j neue Zeile ^t Anfang des Textes "
+38 "^c Befehl ^k Zeichen löschen ^u hoch "
+39 "^d runter ^l nach links ^v Wort zurückholen "
+40 "^e Textsuche (Menü) ^m neue Zeile ^w Wort löschen "
+41 "^f Zeichen zurückholen ^n nächste Seite ^x Weitersuchen "
+42 "^g zum Zeilenanfang ^o zum Zeilenende ^y Zeile löschen "
+43 "^h Rückschritt ^p vorige Seite ^z Zeile zurückholen "
+44 "^[ (Escape) Menü ESC-Enter: ee beenden "
+45 " "
+46 "Befehle: "
+47 "hilfe : diese Hilfe anzeigen datei : Dateinamen anzeigen "
+48 "lesen : Datei öffnen zeichen : ASCII-Code anzeigen "
+49 "schreiben:Datei schreiben grosskl : Suche mit Groß/Kleinschr."
+50 "ende : Sichern und Beenden klein : Suche ohne Groß/Klein. "
+51 "abbruch : Abbruch ohne Sichern !bef : Unix-Befehl \"bef\" ausf. "
+52 "zeile : Zeilennummer anzeigen 0-9 : Zur angegebenen Zeile "
+53 "leer : Tabulat. in Leerz. wandeln tabs : Tabulatoren belassen "
+54 " "
+55 " ee [-i] [-e] [-h] [datei(en)] "
+56 " -i : ohne Hilfefenster -e : Tabulatoren lassen -h : k. Hervorheb."
+57 "^[ (Escape) Menü ^e Textsuche ^y Zeile löschen ^u hoch ^p Seite zur. "
+58 "^a ASCII-Code ^x Weitersuchen ^z Zeile rückhl. ^d runter ^n Seite vor "
+59 "^b Textende ^g Zeilenanfang ^w Wort löschen ^l links "
+60 "^t Textanfang ^o Zeilenende ^v Wort rückhol. ^r rechts "
+61 "^c Befehl ^k Zeichen lösch. ^f Zeichen rückholen ESC-Enter: Ende ee "
+62 "hilfe: Hilfe |datei : Dateiname anzeigen |zeile: Zeilennumer "
+63 "lesen: Datei lesen |zeichen:ASCII-Code des Zeichens |0-9 : zur Zeile "
+64 "schre: Datei schreib. |grosskl:Suche mit Groß/Klein |ende : Speichern,Ende "
+65 "!bef : Unix-\"bef\" |klein: Suche ohne Groß/Klein |abbr : Abbruch "
+66 "leer : Tab -> Leerz. |tabs : Tabulatoren belassen "
+67 " Escape (^[) drücken für Menü"
+68 "Keine Datei"
+69 "ASCII-Code: "
+70 "Pufferinhalt nach \"%s\" schreiben "
+71 "Befehl: "
+72 "Dateiname zum Schreiben: "
+73 "Dateiname zum Lesen: "
+74 "Zeichen = %d"
+75 "Unbekannter Befehl \"%s\""
+76 "Angegebener Befehl ist nicht eindeutig"
+77 "Zeile %d "
+78 "Länge = %d"
+79 "Aktuelle Datei ist \"%s\" "
+80 "Benutzung: %s [-i] [-e] [-h] [+zeilennummer] [dateien]\n"
+81 " -i Hilfefenster ausschalten\n"
+82 " -e Tabulatoren nicht in Leerzeichen wandeln\n"
+83 " -h keine Hervorhebungen\n"
+84 "Datei \"%s\" ist ein Verzeichnis"
+85 "Neue Datei \"%s\""
+86 "Datei \"%s\" kann nicht geöffnet werden"
+87 "Datei \"%s\", %d Zeilen"
+88 "Lesen der Datei \"%s\" beendet"
+89 "Lese die Datei \"%s\""
+90 ", schreibgeschützt"
+91 "Datei \"%s\", %d Zeilen"
+92 "Dateinamen eingeben: "
+93 "Kein Name angegeben; Datei nicht gespeichert"
+94 "Pufferinhalt geändert, wirklich verlassen? (j/n [n]) "
+95 "j"
+96 "Datei existiert bereits, überschreiben? (j/n) [n] "
+97 "Datei \"%s\" kann nicht erzeugt werden"
+98 "Schreibe Datei \"%s\""
+99 "\"%s\" %d Zeilen, %d Zeichen"
+100 " ...Suche läuft"
+101 "Zeichenfolge \"%s\" nicht gefunden"
+102 "Suchen nach: "
+103 "Kann %s nicht ausführen\n"
+104 "Bitte die Eingabetaste drücken "
+105 "Escape zum Beenden"
+106 "Menü ist zu groß für das Fenster"
+107 "eine beliebige Taste drücken "
+108 "Unix-Befehl: "
+109 "...formatiere Absatz..."
+110 "<!echo 'Liste der nicht gefundenen Wörter'; echo -=-=-=-=-=-"
+111 "Sende den Pufferinhalt an 'spell'"
+112 "Rechter Rand: "
+113 "Eingeschränkter Modus: gewünschte Operation unzulässig"
+114 "EIN"
+115 "AUS"
+116 "HILFE"
+117 "SCHREIBEN"
+118 "LESEN"
+119 "ZEILE"
+120 "DATEI"
+121 "ZEICHEN"
+122 "REGENERIEREN"
+123 "UMNUMERIEREN"
+124 "AUTOR"
+125 "VERSION"
+126 "GROSSKL"
+127 "KLEIN"
+128 "LEER"
+129 "TABS"
+130 "ENDE"
+131 "ABBRUCH"
+132 "INFO"
+133 "[INFO]"
+134 "RAND"
+135 "[RAND]"
+136 "FORMAT."
+137 "[FORMAT.]"
+138 "ECHO"
+139 "DRUCKBEFEHL"
+140 "RECHTERRAND"
+141 "HERVORHEB."
+142 "[HERVORHEB.]"
+143 "8-BIT"
+144 "[8-BIT]"
+145 "Emacs-Tastenbelegung "
+146 "^a Zeilenanfang ^i Tabulator ^r Wort zurückholen "
+147 "^b ein Zeichen zurück ^j Zeichen zurückholen ^t Textanfang "
+148 "^c Befehl ^k Zeile löschen ^u Textende "
+149 "^d Zeichen löschen ^l Zeile zurückholen ^v nächste Seite "
+150 "^e Zeilenendee ^m neue Zeile ^w Wort löschen "
+151 "^f ein Zeichen vorwärts ^n neue Zeile ^x Weitersuchen "
+152 "^g vorige Seite ^o ASCII-Zeichen einfü. ^y Textsuche "
+153 "^h Rückschritt ^p vorige Zeile ^z nächstes Wort "
+154 "^[ (Escape) Menü ^y Suchtext eing. ^k Zeile löschen ^p vor.Zeile ^g vor.Seite"
+155 "^o ASCII-Zeichen ^x Weitersuchen ^l Zeile rückhol ^n nä. Zeile ^v nä. Seite"
+156 "^u Textende ^a Zeilenanfang ^w Wort löschen ^b ein Zeichen zurück "
+157 "^t Textanfang ^e Zeilenende ^r Wort rückhol. ^f ein Zeichen vor "
+158 "^c Befehl ^d Zeichen lösch. ^j Zeich. rückh. ^z nächstes Wort "
+159 "EMACS"
+160 "[EMACS]"
+161 " +<zahl> Zeiger auf Zeile <zahl> setzen"
+162 "Kann die Datei .init.ee nicht schreiben, Konfiguration nicht gespeichert!"
+163 "ee-Konfiguration in Datei %s gespeichert"
+164 "speichere Editor-Konfiguration"
+165 "speichere ee-Konfiguration"
+166 "speichern im aktuellen Verzeichnis"
+167 "speichern im Home-Verzeichnis"
+168 "ee-Konfiguration nicht gespeichert"
+169 "beim Aufruf von ree muß ein Dateiname angegeben werden"
+170 "Esc zum Verlassen"
+180 "Menü zu groß für den Bildschirm"
+181 "^^weiter^^"
+182 "VVweiterVV"
diff --git a/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg b/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg
new file mode 100644
index 0000000..aab616d
--- /dev/null
+++ b/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/ncvs/src/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg,v 1.3 1996/12/29 10:54:30 joerg Exp $
+$
+$set 1
+$quote "
+1 "Modus-Menü"
+2 "Tab -> Leerzeichen "
+3 "Suche ohne Groß/Klein"
+4 "Ränder beachten "
+5 "Automatische Absätze "
+6 "8-Bit Zeichen (Uml.) "
+7 "Hilfefenster "
+8 "rechter Rand "
+9 "Ende-Menü"
+10 "Speichern"
+11 "Verwerfen"
+12 "Dateimenü"
+13 "Öffnen"
+14 "Schreiben in Datei"
+15 "Speichern"
+16 "Aktuellen Inhalt drucken"
+17 "Textsuche"
+18 "Suche nach ..."
+19 "Suchen"
+20 "Rechtschreibung"
+21 "'spell' benutzen"
+22 "'ispell' benutzen"
+23 "Verschiedenes"
+24 "Absatz formatieren"
+25 "Unix-Kommando"
+26 "Rechtschreibung prüfen"
+27 "Hauptmenü"
+28 "Editor beenden"
+29 "Hilfe"
+30 "Dateioperationen"
+31 "Bildschirm regenerieren"
+32 "Einstellungen"
+33 "Suche"
+34 "Verschiedenes"
+35 "Steuertasten: "
+36 "^a ASCII-Code direkt ^i Tabulator ^r nach rechts "
+37 "^b Ende des Textes ^j neue Zeile ^t Anfang des Textes "
+38 "^c Befehl ^k Zeichen löschen ^u hoch "
+39 "^d runter ^l nach links ^v Wort zurückholen "
+40 "^e Textsuche (Menü) ^m neue Zeile ^w Wort löschen "
+41 "^f Zeichen zurückholen ^n nächste Seite ^x Weitersuchen "
+42 "^g zum Zeilenanfang ^o zum Zeilenende ^y Zeile löschen "
+43 "^h Rückschritt ^p vorige Seite ^z Zeile zurückholen "
+44 "^[ (Escape) Menü ESC-Enter: ee beenden "
+45 " "
+46 "Befehle: "
+47 "hilfe : diese Hilfe anzeigen datei : Dateinamen anzeigen "
+48 "lesen : Datei öffnen zeichen : ASCII-Code anzeigen "
+49 "schreiben:Datei schreiben grosskl : Suche mit Groß/Kleinschr."
+50 "ende : Sichern und Beenden klein : Suche ohne Groß/Klein. "
+51 "abbruch : Abbruch ohne Sichern !bef : Unix-Befehl \"bef\" ausf. "
+52 "zeile : Zeilennummer anzeigen 0-9 : Zur angegebenen Zeile "
+53 "leer : Tabulat. in Leerz. wandeln tabs : Tabulatoren belassen "
+54 " "
+55 " ee [-i] [-e] [-h] [datei(en)] "
+56 " -i : ohne Hilfefenster -e : Tabulatoren lassen -h : k. Hervorheb."
+57 "^[ (Escape) Menü ^e Textsuche ^y Zeile löschen ^u hoch ^p Seite zur. "
+58 "^a ASCII-Code ^x Weitersuchen ^z Zeile rückhl. ^d runter ^n Seite vor "
+59 "^b Textende ^g Zeilenanfang ^w Wort löschen ^l links "
+60 "^t Textanfang ^o Zeilenende ^v Wort rückhol. ^r rechts "
+61 "^c Befehl ^k Zeichen lösch. ^f Zeichen rückholen ESC-Enter: Ende ee "
+62 "hilfe: Hilfe |datei : Dateiname anzeigen |zeile: Zeilennumer "
+63 "lesen: Datei lesen |zeichen:ASCII-Code des Zeichens |0-9 : zur Zeile "
+64 "schre: Datei schreib. |grosskl:Suche mit Groß/Klein |ende : Speichern,Ende "
+65 "!bef : Unix-\"bef\" |klein: Suche ohne Groß/Klein |abbr : Abbruch "
+66 "leer : Tab -> Leerz. |tabs : Tabulatoren belassen "
+67 " Escape (^[) drücken für Menü"
+68 "Keine Datei"
+69 "ASCII-Code: "
+70 "Pufferinhalt nach \"%s\" schreiben "
+71 "Befehl: "
+72 "Dateiname zum Schreiben: "
+73 "Dateiname zum Lesen: "
+74 "Zeichen = %d"
+75 "Unbekannter Befehl \"%s\""
+76 "Angegebener Befehl ist nicht eindeutig"
+77 "Zeile %d "
+78 "Länge = %d"
+79 "Aktuelle Datei ist \"%s\" "
+80 "Benutzung: %s [-i] [-e] [-h] [+zeilennummer] [dateien]\n"
+81 " -i Hilfefenster ausschalten\n"
+82 " -e Tabulatoren nicht in Leerzeichen wandeln\n"
+83 " -h keine Hervorhebungen\n"
+84 "Datei \"%s\" ist ein Verzeichnis"
+85 "Neue Datei \"%s\""
+86 "Datei \"%s\" kann nicht geöffnet werden"
+87 "Datei \"%s\", %d Zeilen"
+88 "Lesen der Datei \"%s\" beendet"
+89 "Lese die Datei \"%s\""
+90 ", schreibgeschützt"
+91 "Datei \"%s\", %d Zeilen"
+92 "Dateinamen eingeben: "
+93 "Kein Name angegeben; Datei nicht gespeichert"
+94 "Pufferinhalt geändert, wirklich verlassen? (j/n [n]) "
+95 "j"
+96 "Datei existiert bereits, überschreiben? (j/n) [n] "
+97 "Datei \"%s\" kann nicht erzeugt werden"
+98 "Schreibe Datei \"%s\""
+99 "\"%s\" %d Zeilen, %d Zeichen"
+100 " ...Suche läuft"
+101 "Zeichenfolge \"%s\" nicht gefunden"
+102 "Suchen nach: "
+103 "Kann %s nicht ausführen\n"
+104 "Bitte die Eingabetaste drücken "
+105 "Escape zum Beenden"
+106 "Menü ist zu groß für das Fenster"
+107 "eine beliebige Taste drücken "
+108 "Unix-Befehl: "
+109 "...formatiere Absatz..."
+110 "<!echo 'Liste der nicht gefundenen Wörter'; echo -=-=-=-=-=-"
+111 "Sende den Pufferinhalt an 'spell'"
+112 "Rechter Rand: "
+113 "Eingeschränkter Modus: gewünschte Operation unzulässig"
+114 "EIN"
+115 "AUS"
+116 "HILFE"
+117 "SCHREIBEN"
+118 "LESEN"
+119 "ZEILE"
+120 "DATEI"
+121 "ZEICHEN"
+122 "REGENERIEREN"
+123 "UMNUMERIEREN"
+124 "AUTOR"
+125 "VERSION"
+126 "GROSSKL"
+127 "KLEIN"
+128 "LEER"
+129 "TABS"
+130 "ENDE"
+131 "ABBRUCH"
+132 "INFO"
+133 "[INFO]"
+134 "RAND"
+135 "[RAND]"
+136 "FORMAT."
+137 "[FORMAT.]"
+138 "ECHO"
+139 "DRUCKBEFEHL"
+140 "RECHTERRAND"
+141 "HERVORHEB."
+142 "[HERVORHEB.]"
+143 "8-BIT"
+144 "[8-BIT]"
+145 "Emacs-Tastenbelegung "
+146 "^a Zeilenanfang ^i Tabulator ^r Wort zurückholen "
+147 "^b ein Zeichen zurück ^j Zeichen zurückholen ^t Textanfang "
+148 "^c Befehl ^k Zeile löschen ^u Textende "
+149 "^d Zeichen löschen ^l Zeile zurückholen ^v nächste Seite "
+150 "^e Zeilenendee ^m neue Zeile ^w Wort löschen "
+151 "^f ein Zeichen vorwärts ^n neue Zeile ^x Weitersuchen "
+152 "^g vorige Seite ^o ASCII-Zeichen einfü. ^y Textsuche "
+153 "^h Rückschritt ^p vorige Zeile ^z nächstes Wort "
+154 "^[ (Escape) Menü ^y Suchtext eing. ^k Zeile löschen ^p vor.Zeile ^g vor.Seite"
+155 "^o ASCII-Zeichen ^x Weitersuchen ^l Zeile rückhol ^n nä. Zeile ^v nä. Seite"
+156 "^u Textende ^a Zeilenanfang ^w Wort löschen ^b ein Zeichen zurück "
+157 "^t Textanfang ^e Zeilenende ^r Wort rückhol. ^f ein Zeichen vor "
+158 "^c Befehl ^d Zeichen lösch. ^j Zeich. rückh. ^z nächstes Wort "
+159 "EMACS"
+160 "[EMACS]"
+161 " +<zahl> Zeiger auf Zeile <zahl> setzen"
+162 "Kann die Datei .init.ee nicht schreiben, Konfiguration nicht gespeichert!"
+163 "ee-Konfiguration in Datei %s gespeichert"
+164 "speichere Editor-Konfiguration"
+165 "speichere ee-Konfiguration"
+166 "speichern im aktuellen Verzeichnis"
+167 "speichern im Home-Verzeichnis"
+168 "ee-Konfiguration nicht gespeichert"
+169 "beim Aufruf von ree muß ein Dateiname angegeben werden"
+170 "Esc zum Verlassen"
+180 "Menü zu groß für den Bildschirm"
+181 "^^weiter^^"
+182 "VVweiterVV"
diff --git a/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg b/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg
new file mode 100644
index 0000000..e1364c0
--- /dev/null
+++ b/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/ncvs/src/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg,v 1.2 1996/05/27 21:00:00 joerg Exp $
+$
+$set 1
+$quote "
+1 "modes menu"
+2 "tabs to spaces "
+3 "case sensitive search"
+4 "margins observed "
+5 "auto-paragraph format"
+6 "eightbit characters "
+7 "info window "
+8 "right margin "
+9 "leave menu"
+10 "save changes"
+11 "no save"
+12 "file menu"
+13 "read a file"
+14 "write a file"
+15 "save file"
+16 "print editor contents"
+17 "search menu"
+18 "search for ..."
+19 "search"
+20 "spell menu"
+21 "use 'spell'"
+22 "use 'ispell'"
+23 "miscellaneous menu"
+24 "format paragraph"
+25 "shell command"
+26 "check spelling"
+27 "main menu"
+28 "leave editor"
+29 "help"
+30 "file operations"
+31 "redraw screen"
+32 "settings"
+33 "search"
+34 "miscellaneous"
+35 "Control keys: "
+36 "^a ascii code ^i tab ^r right "
+37 "^b bottom of text ^j newline ^t top of text "
+38 "^c command ^k delete char ^u up "
+39 "^d down ^l left ^v undelete word "
+40 "^e search prompt ^m newline ^w delete word "
+41 "^f undelete char ^n next page ^x search "
+42 "^g begin of line ^o end of line ^y delete line "
+43 "^h backspace ^p prev page ^z undelete line "
+44 "^[ (escape) menu ESC-Enter: exit ee "
+45 " "
+46 "Commands: "
+47 "help : get this info file : print file name "
+48 "read : read a file char : ascii code of char "
+49 "write : write a file case : case sensitive search "
+50 "exit : leave and save nocase : case insensitive search "
+51 "quit : leave, no save !cmd : execute \"cmd\" in shell "
+52 "line : display line # 0-9 : go to line \"#\" "
+53 "expand : expand tabs noexpand: do not expand tabs "
+54 " "
+55 " ee [-i] [-e] [-h] [file(s)] "
+56 " -i : no information window -e : do not expand tabs -h : no highlight "
+57 "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "
+58 "^a ascii code ^x search ^z undelete line ^d down ^n next page "
+59 "^b bottom of text ^g begin of line ^w delete word ^l left "
+60 "^t top of text ^o end of line ^v undelete word ^r right "
+61 "^c command ^k delete char ^f undelete char ESC-Enter: exit ee "
+62 "help : get help info |file : print file name |line : print line # "
+63 "read : read a file |char : ascii code of char |0-9 : go to line \"#\""
+64 "write: write a file |case : case sensitive search |exit : leave and save "
+65 "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"
+66 "expand: expand tabs |noexpand: do not expand tabs "
+67 " press Escape (^[) for menu"
+68 "no file"
+69 "ascii code: "
+70 "sending contents of buffer to \"%s\" "
+71 "command: "
+72 "name of file to write: "
+73 "name of file to read: "
+74 "character = %d"
+75 "unknown command \"%s\""
+76 "entered command is not unique"
+77 "line %d "
+78 "length = %d"
+79 "current file is \"%s\" "
+80 "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"
+81 " -i turn off info window\n"
+82 " -e do not convert tabs to spaces\n"
+83 " -h do not use highlighting\n"
+84 "file \"%s\" is a directory"
+85 "new file \"%s\""
+86 "can't open \"%s\""
+87 "file \"%s\", %d lines"
+88 "finished reading file \"%s\""
+89 "reading file \"%s\""
+90 ", read only"
+91 "file \"%s\", %d lines"
+92 "enter name of file: "
+93 "no filename entered: file not saved"
+94 "changes have been made, are you sure? (y/n [n]) "
+95 "y"
+96 "file already exists, overwrite? (y/n) [n] "
+97 "unable to create file \"%s\""
+98 "writing file \"%s\""
+99 "\"%s\" %d lines, %d characters"
+100 " ...searching"
+101 "string \"%s\" not found"
+102 "search for: "
+103 "could not exec %s\n"
+104 "press return to continue "
+105 "press Esc to cancel"
+106 "menu too large for window"
+107 "press any key to continue "
+108 "shell command: "
+109 "...formatting paragraph..."
+110 "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-"
+111 "sending contents of edit buffer to 'spell'"
+112 "right margin is: "
+113 "restricted mode: unable to perform requested operation"
+114 "ON"
+115 "OFF"
+116 "HELP"
+117 "WRITE"
+118 "READ"
+119 "LINE"
+120 "FILE"
+121 "CHARACTER"
+122 "REDRAW"
+123 "RESEQUENCE"
+124 "AUTHOR"
+125 "VERSION"
+126 "CASE"
+127 "NOCASE"
+128 "EXPAND"
+129 "NOEXPAND"
+130 "EXIT"
+131 "QUIT"
+132 "INFO"
+133 "NOINFO"
+134 "MARGINS"
+135 "NOMARGINS"
+136 "AUTOFORMAT"
+137 "NOAUTOFORMAT"
+138 "ECHO"
+139 "PRINTCOMMAND"
+140 "RIGHTMARGIN"
+141 "HIGHLIGHT"
+142 "NOHIGHLIGHT"
+143 "EIGHTBIT"
+144 "NOEIGHTBIT"
+145 "emacs key bindings "
+146 "^a beginning of line ^i tab ^r restore word "
+147 "^b back 1 char ^j undel char ^t top of text "
+148 "^c command ^k delete line ^u bottom of text "
+149 "^d delete char ^l undelete line ^v next page "
+150 "^e end of line ^m newline ^w delete word "
+151 "^f forward 1 char ^n next line ^x search "
+152 "^g go back 1 page ^o ascii char insert ^y search prompt "
+153 "^h backspace ^p prev line ^z next word "
+154 "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page"
+155 "^o ascii code ^x search ^l undelete line ^n next li ^v next page"
+156 "^u end of file ^a begin of line ^w delete word ^b back 1 char "
+157 "^t top of text ^e end of line ^r restore word ^f forward 1 char "
+158 "^c command ^d delete char ^j undelete char ^z next word "
+159 "EMACS"
+160 "NOEMACS"
+161 " +# put cursor at line #\n"
+162 "unable to open .init.ee for writing, no configuration saved!"
+163 "ee configuration saved in file %s"
+164 "save editor configuration"
+165 "save ee configuration"
+166 "save in current directory"
+167 "save in home directory"
+168 "ee configuration not saved"
+169 "must specify a file when invoking ree"
+170 "press Esc to cancel"
+180 "menu too large for window"
+181 "^^more^^"
+182 "VVmoreVV"
diff --git a/usr.bin/ee/nls/en_US.US-ASCII/ee.msg b/usr.bin/ee/nls/en_US.US-ASCII/ee.msg
new file mode 100644
index 0000000..e1364c0
--- /dev/null
+++ b/usr.bin/ee/nls/en_US.US-ASCII/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/ncvs/src/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg,v 1.2 1996/05/27 21:00:00 joerg Exp $
+$
+$set 1
+$quote "
+1 "modes menu"
+2 "tabs to spaces "
+3 "case sensitive search"
+4 "margins observed "
+5 "auto-paragraph format"
+6 "eightbit characters "
+7 "info window "
+8 "right margin "
+9 "leave menu"
+10 "save changes"
+11 "no save"
+12 "file menu"
+13 "read a file"
+14 "write a file"
+15 "save file"
+16 "print editor contents"
+17 "search menu"
+18 "search for ..."
+19 "search"
+20 "spell menu"
+21 "use 'spell'"
+22 "use 'ispell'"
+23 "miscellaneous menu"
+24 "format paragraph"
+25 "shell command"
+26 "check spelling"
+27 "main menu"
+28 "leave editor"
+29 "help"
+30 "file operations"
+31 "redraw screen"
+32 "settings"
+33 "search"
+34 "miscellaneous"
+35 "Control keys: "
+36 "^a ascii code ^i tab ^r right "
+37 "^b bottom of text ^j newline ^t top of text "
+38 "^c command ^k delete char ^u up "
+39 "^d down ^l left ^v undelete word "
+40 "^e search prompt ^m newline ^w delete word "
+41 "^f undelete char ^n next page ^x search "
+42 "^g begin of line ^o end of line ^y delete line "
+43 "^h backspace ^p prev page ^z undelete line "
+44 "^[ (escape) menu ESC-Enter: exit ee "
+45 " "
+46 "Commands: "
+47 "help : get this info file : print file name "
+48 "read : read a file char : ascii code of char "
+49 "write : write a file case : case sensitive search "
+50 "exit : leave and save nocase : case insensitive search "
+51 "quit : leave, no save !cmd : execute \"cmd\" in shell "
+52 "line : display line # 0-9 : go to line \"#\" "
+53 "expand : expand tabs noexpand: do not expand tabs "
+54 " "
+55 " ee [-i] [-e] [-h] [file(s)] "
+56 " -i : no information window -e : do not expand tabs -h : no highlight "
+57 "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "
+58 "^a ascii code ^x search ^z undelete line ^d down ^n next page "
+59 "^b bottom of text ^g begin of line ^w delete word ^l left "
+60 "^t top of text ^o end of line ^v undelete word ^r right "
+61 "^c command ^k delete char ^f undelete char ESC-Enter: exit ee "
+62 "help : get help info |file : print file name |line : print line # "
+63 "read : read a file |char : ascii code of char |0-9 : go to line \"#\""
+64 "write: write a file |case : case sensitive search |exit : leave and save "
+65 "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"
+66 "expand: expand tabs |noexpand: do not expand tabs "
+67 " press Escape (^[) for menu"
+68 "no file"
+69 "ascii code: "
+70 "sending contents of buffer to \"%s\" "
+71 "command: "
+72 "name of file to write: "
+73 "name of file to read: "
+74 "character = %d"
+75 "unknown command \"%s\""
+76 "entered command is not unique"
+77 "line %d "
+78 "length = %d"
+79 "current file is \"%s\" "
+80 "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"
+81 " -i turn off info window\n"
+82 " -e do not convert tabs to spaces\n"
+83 " -h do not use highlighting\n"
+84 "file \"%s\" is a directory"
+85 "new file \"%s\""
+86 "can't open \"%s\""
+87 "file \"%s\", %d lines"
+88 "finished reading file \"%s\""
+89 "reading file \"%s\""
+90 ", read only"
+91 "file \"%s\", %d lines"
+92 "enter name of file: "
+93 "no filename entered: file not saved"
+94 "changes have been made, are you sure? (y/n [n]) "
+95 "y"
+96 "file already exists, overwrite? (y/n) [n] "
+97 "unable to create file \"%s\""
+98 "writing file \"%s\""
+99 "\"%s\" %d lines, %d characters"
+100 " ...searching"
+101 "string \"%s\" not found"
+102 "search for: "
+103 "could not exec %s\n"
+104 "press return to continue "
+105 "press Esc to cancel"
+106 "menu too large for window"
+107 "press any key to continue "
+108 "shell command: "
+109 "...formatting paragraph..."
+110 "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-"
+111 "sending contents of edit buffer to 'spell'"
+112 "right margin is: "
+113 "restricted mode: unable to perform requested operation"
+114 "ON"
+115 "OFF"
+116 "HELP"
+117 "WRITE"
+118 "READ"
+119 "LINE"
+120 "FILE"
+121 "CHARACTER"
+122 "REDRAW"
+123 "RESEQUENCE"
+124 "AUTHOR"
+125 "VERSION"
+126 "CASE"
+127 "NOCASE"
+128 "EXPAND"
+129 "NOEXPAND"
+130 "EXIT"
+131 "QUIT"
+132 "INFO"
+133 "NOINFO"
+134 "MARGINS"
+135 "NOMARGINS"
+136 "AUTOFORMAT"
+137 "NOAUTOFORMAT"
+138 "ECHO"
+139 "PRINTCOMMAND"
+140 "RIGHTMARGIN"
+141 "HIGHLIGHT"
+142 "NOHIGHLIGHT"
+143 "EIGHTBIT"
+144 "NOEIGHTBIT"
+145 "emacs key bindings "
+146 "^a beginning of line ^i tab ^r restore word "
+147 "^b back 1 char ^j undel char ^t top of text "
+148 "^c command ^k delete line ^u bottom of text "
+149 "^d delete char ^l undelete line ^v next page "
+150 "^e end of line ^m newline ^w delete word "
+151 "^f forward 1 char ^n next line ^x search "
+152 "^g go back 1 page ^o ascii char insert ^y search prompt "
+153 "^h backspace ^p prev line ^z next word "
+154 "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page"
+155 "^o ascii code ^x search ^l undelete line ^n next li ^v next page"
+156 "^u end of file ^a begin of line ^w delete word ^b back 1 char "
+157 "^t top of text ^e end of line ^r restore word ^f forward 1 char "
+158 "^c command ^d delete char ^j undelete char ^z next word "
+159 "EMACS"
+160 "NOEMACS"
+161 " +# put cursor at line #\n"
+162 "unable to open .init.ee for writing, no configuration saved!"
+163 "ee configuration saved in file %s"
+164 "save editor configuration"
+165 "save ee configuration"
+166 "save in current directory"
+167 "save in home directory"
+168 "ee configuration not saved"
+169 "must specify a file when invoking ree"
+170 "press Esc to cancel"
+180 "menu too large for window"
+181 "^^more^^"
+182 "VVmoreVV"
diff --git a/usr.bin/ee/nls/fr_FR.ISO8859-1/ee.msg b/usr.bin/ee/nls/fr_FR.ISO8859-1/ee.msg
new file mode 100644
index 0000000..2fa3b27
--- /dev/null
+++ b/usr.bin/ee/nls/fr_FR.ISO8859-1/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Id$
+$
+$set 1
+$quote "
+1 "menu de configuration "
+2 "tabulation -> espaces "
+3 "recherche sensible aux maj/min "
+4 "respect des marges "
+5 "formattage automatique des paragraphes"
+6 "caractères 8 bits "
+7 "fenêtre d'informations "
+8 "marge de droite "
+9 "menu de sortie"
+10 "enregistrer les modifications"
+11 "ne pas enregistrer"
+12 "menu fichiers"
+13 "lire un fichier"
+14 "écrire un fichier"
+15 "enregistrer un fichier"
+16 "imprimer le contenu de l'éditeur"
+17 "menu recherche"
+18 "recherche de..."
+19 "rechercher"
+20 "menu correcteur orthographique"
+21 "utiliser 'spell'"
+22 "utiliser 'ispell'"
+23 "menu divers"
+24 "formatter le paragraphe"
+25 "commande du shell"
+26 "vérifier l'orthographe"
+27 "menu principal"
+28 "quitter l'éditeur"
+29 "aide"
+30 "opérations sur les fichiers"
+31 "rafraîchir l'écran"
+32 "configuration"
+33 "recherche"
+34 "divers"
+35 "Contrôle + touche: "
+36 "^a code ascii ^i tabulation ^r droite "
+37 "^b fin du texte ^j nouvelle ligne ^t début du texte "
+38 "^c commande ^k effacer caractère ^u haut "
+39 "^d bas ^l gauche ^v annuler effacement mot "
+40 "^e entrer recherche ^m nouvelle ligne ^w effacer un mot "
+41 "^f annuler eff. caract. ^n page suivante ^x recherche "
+42 "^g début de ligne ^o fin de ligne ^y effacer ligne "
+43 "^h arrière ^p page précédente ^z annuler effacement ligne"
+44 "^[ (échappement) menu ESC-Enter: quitter ee "
+45 " "
+46 "Commandes: "
+47 "aide : pour cet écran d'info fichier: donne le nom du fichier "
+48 "lire : lire un fichier caract : code ascii d'un caractère"
+49 "écrire : créer un fichier minmaj : recherche sensible aux maj/min"
+50 "fin : quitter et enregistrer pasmin : recherche insensible aux maj/min"
+51 "quitter: quitter, ne pas enregistrer !cmd : exécute \"cmd\" par le shell"
+52 "ligne : indique le numéro de ligne 0-9 : aller à la ligne \"#\" "
+53 "tabs : étendre les tabulations pastabs: ne pas étendre les tabulations"
+54 " "
+55 " ee [-i] [-e] [-h] [fichier(s)] "
+56 " -i : pas de fenêtre d'info -e : ne pas étendre les tabs -h : pas de surbrillance"
+57 "^[ (échap.) menu ^e rechercher... ^y efface ligne ^u haut ^p page préc."
+58 "^a code ascii ^x rechercher ^z annul. eff. ligne ^d bas ^n page suiv."
+59 "^b fin du texte ^g début de ligne ^w efface mot ^l gauche "
+60 "^t début du texte ^o fin de ligne ^v annul. eff. mot ^r droite "
+61 "^c commande ^k efface caract. ^f annul. eff. caract. ESC-Enter: quitter "
+62 "aide: fenêtre d'aide |fichier: nom du fichier |ligne: numéro de ligne"
+63 "lire: lecture fichier|caract : code ascii du car. |0-9: aller ligne \"#\""
+64 "écrire: crée un fich. |minmaj: rech. sensible min/maj|fin: quitte et sauve"
+65 "!cmd: shell \"cmd\" |pasmin: rech. insens. min/maj |quitte: quitte sans sauver"
+66 "tabs: étend les tabs |pastabs: n'étend pas les tabulations"
+67 " pressez sur échap. (^[) pour le menu"
+68 "pas de fichier"
+69 "code ascii : "
+70 "le contenu du buffer est imprimé sur \"%s\" "
+71 "commande : "
+72 "nom du fichier à créer : "
+73 "nom du fichier à lire : "
+74 "caractère = %d"
+75 "commande inconnue : \"%s\""
+76 "la commande tapée est ambiguë"
+77 "ligne %d "
+78 "longueur = %d"
+79 "le fichier courant est \"%s\" "
+80 "utilisation : %s [-i] [-e] [-h] [+numéro_de_ligne] [fichier(s)]\n"
+81 " -i supprime la fenêtre d'informations\n"
+82 " -e ne convertit pas les tabs en espaces\n"
+83 " -h n'utilise pas de surbrillance\n"
+84 "le fichier \"%s\" est un répertoire"
+85 "nouveau fichier \"%s\""
+86 "impossible de d'ouvrir \"%s\""
+87 "fichier \"%s\", %d lignes"
+88 "le fichier \"%s\" a été lu"
+89 "lecture du fichier \"%s\""
+90 ", lecture seule"
+91 "fichier \"%s\", %d lignes"
+92 "entrez un nom de fichier : "
+93 "pas de nom de fichier donné : fichier non enregistré"
+94 "des changements ont été effectués, êtes vous sûr ? (o/n [n]) "
+95 "o"
+96 "le fichier existe déjà, réécrire ? (o/n) [n] "
+97 "impossible de créer le fichier \"%s\""
+98 "écriture du fichier \"%s\""
+99 "\"%s\" %d lignes, %d caractères"
+100 " ...recherche"
+101 "chaîne \"%s\" non trouvée"
+102 "rechercher : "
+103 "impossible d'exécuter %s\n"
+104 "tapez entrée pour continuer "
+105 "pressez sur échap. pour annuler"
+106 "menu trop grand pour la fenêtre"
+107 "appuyez sur une touche pour continuer "
+108 "commande du shell : "
+109 "...formattage du paragraphe..."
+110 "<!echo 'liste des mots non reconnus'; echo -=-=-=-=-=-"
+111 "envoi du contenu du buffer à 'spell'"
+112 "colonne de la marge de droite : "
+113 "mode restreint : impossible d'effectuer l'opération demandée"
+114 "OUI"
+115 "NON"
+116 "AIDE"
+117 "ECRIRE"
+118 "LIRE"
+119 "LIGNE"
+120 "FICHIER"
+121 "CARACTERE"
+122 "RAFRAICHIR"
+123 "RENUMEROTER"
+124 "AUTEUR"
+125 "VERSION"
+126 "MINMAJ"
+127 "PASMINMAJ"
+128 "TABS"
+129 "PASTABS"
+130 "FIN"
+131 "QUITTE"
+132 "INFO"
+133 "PASINFO"
+134 "MARGES"
+135 "PASMARGES"
+136 "AUTOFORMAT"
+137 "PASAUTOFORMAT"
+138 "ECHO"
+139 "COMMANDEIMPRESSION"
+140 "MARGEDROITE"
+141 "SURBRILLANT"
+142 "PASSURBRILLANT"
+143 "8BIT"
+144 "PAS8BIT"
+145 "caractères de contrôle comme emacs "
+146 "^a début de ligne ^i tabulation ^r annule effacement mot "
+147 "^b arrière ^j annule eff. caract. ^t début du texte "
+148 "^c commande ^k efface ligne ^u fin du texte "
+149 "^d efface caractère ^l annule eff. ligne ^v page suivante "
+150 "^e fin de ligne ^m nouvelle ligne ^w effacer un mot "
+151 "^f caractère suivant ^n ligne suivante ^x recherche "
+152 "^g page précédente ^o insère caract. ascii ^y rechercher... "
+153 "^h efface en arrière ^p ligne précédente ^z mot suivant "
+154 "^[ (échap.) menu ^y rechercher... ^k efface ligne ^p ligne préc ^g page préc"
+155 "^o code ascii ^x recherche ^l annul. eff.li ^n ligne suiv ^v page suiv"
+156 "^u fin du fichier ^a début de ligne ^w efface mot ^b arrière "
+157 "^t début du texte ^e fin de ligne ^r annul.eff.mot ^f avance 1 caractère "
+158 "^c commande ^d efface caract. ^j annul.eff.car ^z mot suivant "
+159 "EMACS"
+160 "PASEMACS"
+161 " +# positionne le curseur sur la ligne #\n"
+162 "impossible d'écrire .init.ee, configuration non sauvée !"
+163 "configuration de ee sauvée en %s"
+164 "sauvegarde configuration de l'éditeur"
+165 "sauvegarde configuration de ee"
+166 "sauvegarde dans le répertoire courant"
+167 "sauvegarde dans le répertoire d'acceuil"
+168 "configuration de ee non sauvée"
+169 "nom de fichier manquant pour ree"
+170 "appuyez sur échap. pour annuler"
+180 "menu trop large pour la fenêtre"
+181 "^^encore^^"
+182 "VVencoreVV"
diff --git a/usr.bin/ee/nls/fr_FR.ISO_8859-1/ee.msg b/usr.bin/ee/nls/fr_FR.ISO_8859-1/ee.msg
new file mode 100644
index 0000000..2fa3b27
--- /dev/null
+++ b/usr.bin/ee/nls/fr_FR.ISO_8859-1/ee.msg
@@ -0,0 +1,182 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Id$
+$
+$set 1
+$quote "
+1 "menu de configuration "
+2 "tabulation -> espaces "
+3 "recherche sensible aux maj/min "
+4 "respect des marges "
+5 "formattage automatique des paragraphes"
+6 "caractères 8 bits "
+7 "fenêtre d'informations "
+8 "marge de droite "
+9 "menu de sortie"
+10 "enregistrer les modifications"
+11 "ne pas enregistrer"
+12 "menu fichiers"
+13 "lire un fichier"
+14 "écrire un fichier"
+15 "enregistrer un fichier"
+16 "imprimer le contenu de l'éditeur"
+17 "menu recherche"
+18 "recherche de..."
+19 "rechercher"
+20 "menu correcteur orthographique"
+21 "utiliser 'spell'"
+22 "utiliser 'ispell'"
+23 "menu divers"
+24 "formatter le paragraphe"
+25 "commande du shell"
+26 "vérifier l'orthographe"
+27 "menu principal"
+28 "quitter l'éditeur"
+29 "aide"
+30 "opérations sur les fichiers"
+31 "rafraîchir l'écran"
+32 "configuration"
+33 "recherche"
+34 "divers"
+35 "Contrôle + touche: "
+36 "^a code ascii ^i tabulation ^r droite "
+37 "^b fin du texte ^j nouvelle ligne ^t début du texte "
+38 "^c commande ^k effacer caractère ^u haut "
+39 "^d bas ^l gauche ^v annuler effacement mot "
+40 "^e entrer recherche ^m nouvelle ligne ^w effacer un mot "
+41 "^f annuler eff. caract. ^n page suivante ^x recherche "
+42 "^g début de ligne ^o fin de ligne ^y effacer ligne "
+43 "^h arrière ^p page précédente ^z annuler effacement ligne"
+44 "^[ (échappement) menu ESC-Enter: quitter ee "
+45 " "
+46 "Commandes: "
+47 "aide : pour cet écran d'info fichier: donne le nom du fichier "
+48 "lire : lire un fichier caract : code ascii d'un caractère"
+49 "écrire : créer un fichier minmaj : recherche sensible aux maj/min"
+50 "fin : quitter et enregistrer pasmin : recherche insensible aux maj/min"
+51 "quitter: quitter, ne pas enregistrer !cmd : exécute \"cmd\" par le shell"
+52 "ligne : indique le numéro de ligne 0-9 : aller à la ligne \"#\" "
+53 "tabs : étendre les tabulations pastabs: ne pas étendre les tabulations"
+54 " "
+55 " ee [-i] [-e] [-h] [fichier(s)] "
+56 " -i : pas de fenêtre d'info -e : ne pas étendre les tabs -h : pas de surbrillance"
+57 "^[ (échap.) menu ^e rechercher... ^y efface ligne ^u haut ^p page préc."
+58 "^a code ascii ^x rechercher ^z annul. eff. ligne ^d bas ^n page suiv."
+59 "^b fin du texte ^g début de ligne ^w efface mot ^l gauche "
+60 "^t début du texte ^o fin de ligne ^v annul. eff. mot ^r droite "
+61 "^c commande ^k efface caract. ^f annul. eff. caract. ESC-Enter: quitter "
+62 "aide: fenêtre d'aide |fichier: nom du fichier |ligne: numéro de ligne"
+63 "lire: lecture fichier|caract : code ascii du car. |0-9: aller ligne \"#\""
+64 "écrire: crée un fich. |minmaj: rech. sensible min/maj|fin: quitte et sauve"
+65 "!cmd: shell \"cmd\" |pasmin: rech. insens. min/maj |quitte: quitte sans sauver"
+66 "tabs: étend les tabs |pastabs: n'étend pas les tabulations"
+67 " pressez sur échap. (^[) pour le menu"
+68 "pas de fichier"
+69 "code ascii : "
+70 "le contenu du buffer est imprimé sur \"%s\" "
+71 "commande : "
+72 "nom du fichier à créer : "
+73 "nom du fichier à lire : "
+74 "caractère = %d"
+75 "commande inconnue : \"%s\""
+76 "la commande tapée est ambiguë"
+77 "ligne %d "
+78 "longueur = %d"
+79 "le fichier courant est \"%s\" "
+80 "utilisation : %s [-i] [-e] [-h] [+numéro_de_ligne] [fichier(s)]\n"
+81 " -i supprime la fenêtre d'informations\n"
+82 " -e ne convertit pas les tabs en espaces\n"
+83 " -h n'utilise pas de surbrillance\n"
+84 "le fichier \"%s\" est un répertoire"
+85 "nouveau fichier \"%s\""
+86 "impossible de d'ouvrir \"%s\""
+87 "fichier \"%s\", %d lignes"
+88 "le fichier \"%s\" a été lu"
+89 "lecture du fichier \"%s\""
+90 ", lecture seule"
+91 "fichier \"%s\", %d lignes"
+92 "entrez un nom de fichier : "
+93 "pas de nom de fichier donné : fichier non enregistré"
+94 "des changements ont été effectués, êtes vous sûr ? (o/n [n]) "
+95 "o"
+96 "le fichier existe déjà, réécrire ? (o/n) [n] "
+97 "impossible de créer le fichier \"%s\""
+98 "écriture du fichier \"%s\""
+99 "\"%s\" %d lignes, %d caractères"
+100 " ...recherche"
+101 "chaîne \"%s\" non trouvée"
+102 "rechercher : "
+103 "impossible d'exécuter %s\n"
+104 "tapez entrée pour continuer "
+105 "pressez sur échap. pour annuler"
+106 "menu trop grand pour la fenêtre"
+107 "appuyez sur une touche pour continuer "
+108 "commande du shell : "
+109 "...formattage du paragraphe..."
+110 "<!echo 'liste des mots non reconnus'; echo -=-=-=-=-=-"
+111 "envoi du contenu du buffer à 'spell'"
+112 "colonne de la marge de droite : "
+113 "mode restreint : impossible d'effectuer l'opération demandée"
+114 "OUI"
+115 "NON"
+116 "AIDE"
+117 "ECRIRE"
+118 "LIRE"
+119 "LIGNE"
+120 "FICHIER"
+121 "CARACTERE"
+122 "RAFRAICHIR"
+123 "RENUMEROTER"
+124 "AUTEUR"
+125 "VERSION"
+126 "MINMAJ"
+127 "PASMINMAJ"
+128 "TABS"
+129 "PASTABS"
+130 "FIN"
+131 "QUITTE"
+132 "INFO"
+133 "PASINFO"
+134 "MARGES"
+135 "PASMARGES"
+136 "AUTOFORMAT"
+137 "PASAUTOFORMAT"
+138 "ECHO"
+139 "COMMANDEIMPRESSION"
+140 "MARGEDROITE"
+141 "SURBRILLANT"
+142 "PASSURBRILLANT"
+143 "8BIT"
+144 "PAS8BIT"
+145 "caractères de contrôle comme emacs "
+146 "^a début de ligne ^i tabulation ^r annule effacement mot "
+147 "^b arrière ^j annule eff. caract. ^t début du texte "
+148 "^c commande ^k efface ligne ^u fin du texte "
+149 "^d efface caractère ^l annule eff. ligne ^v page suivante "
+150 "^e fin de ligne ^m nouvelle ligne ^w effacer un mot "
+151 "^f caractère suivant ^n ligne suivante ^x recherche "
+152 "^g page précédente ^o insère caract. ascii ^y rechercher... "
+153 "^h efface en arrière ^p ligne précédente ^z mot suivant "
+154 "^[ (échap.) menu ^y rechercher... ^k efface ligne ^p ligne préc ^g page préc"
+155 "^o code ascii ^x recherche ^l annul. eff.li ^n ligne suiv ^v page suiv"
+156 "^u fin du fichier ^a début de ligne ^w efface mot ^b arrière "
+157 "^t début du texte ^e fin de ligne ^r annul.eff.mot ^f avance 1 caractère "
+158 "^c commande ^d efface caract. ^j annul.eff.car ^z mot suivant "
+159 "EMACS"
+160 "PASEMACS"
+161 " +# positionne le curseur sur la ligne #\n"
+162 "impossible d'écrire .init.ee, configuration non sauvée !"
+163 "configuration de ee sauvée en %s"
+164 "sauvegarde configuration de l'éditeur"
+165 "sauvegarde configuration de ee"
+166 "sauvegarde dans le répertoire courant"
+167 "sauvegarde dans le répertoire d'acceuil"
+168 "configuration de ee non sauvée"
+169 "nom de fichier manquant pour ree"
+170 "appuyez sur échap. pour annuler"
+180 "menu trop large pour la fenêtre"
+181 "^^encore^^"
+182 "VVencoreVV"
diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c
index 2c72ddb..8894dd0 100644
--- a/usr.bin/env/env.c
+++ b/usr.bin/env/env.c
@@ -49,6 +49,8 @@ static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94";
extern char **environ;
+static void usage __P((void));
+
int
main(argc, argv)
int argc;
@@ -58,7 +60,7 @@ main(argc, argv)
char *cleanenv[1];
int ch;
- while ((ch = getopt(argc, argv, "-")) != EOF)
+ while ((ch = getopt(argc, argv, "-")) != -1)
switch(ch) {
case '-':
environ = cleanenv;
@@ -66,9 +68,7 @@ main(argc, argv)
break;
case '?':
default:
- (void)fprintf(stderr,
- "usage: env [-] [name=value ...] [command]\n");
- exit(1);
+ usage();
}
for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
(void)setenv(*argv, ++p, 1);
@@ -80,3 +80,11 @@ main(argc, argv)
(void)printf("%s\n", *ep);
exit(0);
}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: env [-] [name=value ...] [command]\n");
+ exit(1);
+}
diff --git a/usr.bin/error/error.1 b/usr.bin/error/error.1
index ad7adf8..69f182b 100644
--- a/usr.bin/error/error.1
+++ b/usr.bin/error/error.1
@@ -95,7 +95,7 @@ Thus the suffix list:
.Pp
allows
.Nm error
-to touch files ending with ``.c'', ``.y'', ``.foo*'' and ``.y''.
+to touch files ending with ``.c'', ``.y'', ``.foo*'' and ``.h''.
.It Fl s
Print out
.Em statistics
diff --git a/usr.bin/error/error.h b/usr.bin/error/error.h
index 7ceb2a2..d72e5bf 100644
--- a/usr.bin/error/error.h
+++ b/usr.bin/error/error.h
@@ -119,7 +119,7 @@ extern char *scriptname;
extern boolean query;
extern boolean terse;
int inquire(); /* inquire for yes/no */
-/*
+/*
* codes for inquire() to return
*/
#define Q_NO 1 /* 'N' */
@@ -171,7 +171,7 @@ extern struct lang_desc lang_table[];
#define ERRORNAME "/.errorrc"
int nignored;
char **names_ignored;
-/*
+/*
* Structure definition for a full error
*/
typedef struct edesc Edesc;
@@ -193,7 +193,7 @@ struct edesc{
*/
extern int nerrors;
extern Eptr er_head;
-extern Eptr *errors;
+extern Eptr *errors;
/*
* Resources for each of the files mentioned
*/
diff --git a/usr.bin/error/input.c b/usr.bin/error/input.c
index a83013a..6edd5f7 100644
--- a/usr.bin/error/input.c
+++ b/usr.bin/error/input.c
@@ -102,7 +102,7 @@ eaterrors(r_errorc, r_errorv)
else
errorclass = catchall();
if (wordc)
- erroradd(wordc, wordv+1, errorclass, C_UNKNOWN);
+ erroradd(wordc, wordv+1, errorclass, C_UNKNOWN);
}
#ifdef FULLDEBUG
printf("%d errorentrys\n", nerrors);
@@ -176,7 +176,7 @@ Errorclass onelong()
if (strcmp(wordv[1], "Assembler:") == 0){
/* assembler always alerts us to what happened*/
language = INAS; return(C_SYNC);
- } else
+ } else
if (strcmp(wordv[1], "Undefined:") == 0){
/* loader complains about unknown symbols*/
language = INLD; return(C_SYNC);
@@ -206,7 +206,7 @@ Errorclass onelong()
Errorclass cpp()
{
- /*
+ /*
* Now attempt a cpp error message match
* Examples:
* ./morse.h: 23: undefined control
@@ -297,7 +297,7 @@ Errorclass lint0()
/*
* Attempt a match for the new lint style normal compiler
* error messages, of the form
- *
+ *
* printf("%s(%d): %s\n", filename, linenumber, message);
*/
if (wordc >= 2){
@@ -371,7 +371,7 @@ Errorclass lint2()
*
* bufp defined( "./metric.h"(10) ), but never used
*/
- if ( (lastchar(wordv[2]) == '(' /* ')' */ )
+ if ( (lastchar(wordv[2]) == '(' /* ')' */ )
&& (strcmp(wordv[4], "),") == 0) ){
language = INLINT;
if (persperdexplode(wordv[3], &line, &file)){
@@ -461,13 +461,13 @@ Errorclass ri()
* Match an error message produced by ri; here is the
* procedure yanked from the distributed version of ri
* April 24, 1980.
- *
+ *
* serror(str, x1, x2, x3)
* char str[];
* char *x1, *x2, *x3;
* {
* extern int yylineno;
- *
+ *
* putc('"', stdout);
* fputs(srcfile, stdout);
* putc('"', stdout);
diff --git a/usr.bin/error/main.c b/usr.bin/error/main.c
index fe20c37..0ba1be6 100644
--- a/usr.bin/error/main.c
+++ b/usr.bin/error/main.c
@@ -73,7 +73,7 @@ int errorsort();
void onintr();
/*
* error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile]
- *
+ *
* -T: terse output
*
* -I: the following name, `ignorename' contains a list of
@@ -155,7 +155,7 @@ main(argc, argv)
ignorename = argv[1];
break;
}
- }
+ }
if (notouch)
suffixlist = 0;
if (argc > 1){
diff --git a/usr.bin/error/pi.c b/usr.bin/error/pi.c
index 67778a4..4fd70f9 100644
--- a/usr.bin/error/pi.c
+++ b/usr.bin/error/pi.c
@@ -80,7 +80,7 @@ static char **c_header = &unk_hdr[0];
* define msg = .*
* define digit = [0-9]
* definename = .*
- * define date_format letter*3 letter*3 (digit | (digit digit))
+ * define date_format letter*3 letter*3 (digit | (digit digit))
* (digit | (digit digit)):digit*2 digit*4
*
* {e,E} (piptr) (msg) Encounter an error during textual scan
@@ -91,7 +91,7 @@ static char **c_header = &unk_hdr[0];
* ... (msg) When refer to the previous line
* 'In' ('procedure'|'function'|'program') (name):
* pi is now complaining about 2nd pass errors.
- *
+ *
* Here is the output from a compilation
*
*
@@ -291,7 +291,7 @@ Errorclass pi()
*
* Turns into a message of the form:
* filename (header) letter - message
- *
+ *
* First, see if it is a message referring to more than
* one line number. Only of the form:
* %s undefined on line%s
diff --git a/usr.bin/error/subr.c b/usr.bin/error/subr.c
index 6346e04..29b416a 100644
--- a/usr.bin/error/subr.c
+++ b/usr.bin/error/subr.c
@@ -206,7 +206,7 @@ boolean persperdexplode(string, r_perd, r_pers)
*r_pers = strsave(string);
*cp = '(';
return(TRUE);
- }
+ }
}
return(FALSE);
}
@@ -237,7 +237,7 @@ boolean qpersperdexplode(string, r_perd, r_pers)
*r_pers = strsave(string + 1);
*(cp - 1) = '"';
return(TRUE);
- }
+ }
}
return(FALSE);
}
@@ -383,7 +383,7 @@ int wordvcmp(wordv1, wordc, wordv2)
}
return(0); /* they are equal */
}
-
+
/*
* splice a 0 basedword vector onto the tail of a
* new wordv, allowing the first emptyhead slots to be empty
diff --git a/usr.bin/error/touch.c b/usr.bin/error/touch.c
index b4348a1..a21c72d 100644
--- a/usr.bin/error/touch.c
+++ b/usr.bin/error/touch.c
@@ -37,6 +37,7 @@ static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/param.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
@@ -514,7 +515,7 @@ execvarg(n_pissed_on, r_argc, r_argv)
FILE *o_touchedfile; /* the old file */
FILE *n_touchedfile; /* the new file */
char *o_name;
-char n_name[64];
+char n_name[MAXPATHLEN];
char *canon_name = _PATH_TMP;
int o_lineno;
int n_lineno;
@@ -526,6 +527,8 @@ boolean tempfileopen = FALSE;
boolean edit(name)
char *name;
{
+ int fd;
+
o_name = name;
if ( (o_touchedfile = fopen(name, "r")) == NULL){
fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
@@ -533,8 +536,11 @@ boolean edit(name)
return(TRUE);
}
(void)strcpy(n_name, canon_name);
- (void)mktemp(n_name);
- if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
+ (void)strcat(n_name,"error.XXXXXX");
+ fd = mkstemp(n_name);
+ if ( fd < 0 || (n_touchedfile = fdopen(fd, "w")) == NULL) {
+ if (fd >= 0)
+ close(fd);
fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
processname, name);
return(TRUE);
diff --git a/usr.bin/expand/expand.c b/usr.bin/expand/expand.c
index c3a00e7..9d92f41 100644
--- a/usr.bin/expand/expand.c
+++ b/usr.bin/expand/expand.c
@@ -38,16 +38,29 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
+#if 0
static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
+#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
/*
* expand - expand tabs to equivalent spaces
*/
int nstops;
int tabstops[100];
+static void getstops __P((char *));
+static void usage __P((void));
+
+int
main(argc, argv)
int argc;
char *argv[];
@@ -55,12 +68,27 @@ main(argc, argv)
register int c, column;
register int n;
- argc--, argv++;
- do {
- while (argc > 0 && argv[0][0] == '-') {
- getstops(argv[0]);
- argc--, argv++;
+ /* handle obsolete syntax */
+ while (argc > 1 && argv[1][0] && isdigit(argv[1][1])) {
+ getstops(&argv[1][1]);
+ argc--; argv++;
+ }
+
+ while ((c = getopt (argc, argv, "t:")) != -1) {
+ switch (c) {
+ case 't':
+ getstops(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
}
+ }
+ argc -= optind;
+ argv += optind;
+
+ do {
if (argc > 0) {
if (freopen(argv[0], "r", stdin) == NULL) {
perror(argv[0]);
@@ -69,12 +97,8 @@ main(argc, argv)
argc--, argv++;
}
column = 0;
- for (;;) {
- c = getc(stdin);
- if (c == -1)
- break;
+ while ((c = getchar()) != EOF) {
switch (c) {
-
case '\t':
if (nstops == 0) {
do {
@@ -125,13 +149,13 @@ main(argc, argv)
exit(0);
}
+static void
getstops(cp)
register char *cp;
{
register int i;
nstops = 0;
- cp++;
for (;;) {
i = 0;
while (*cp >= '0' && *cp <= '9')
@@ -146,7 +170,15 @@ bad:
tabstops[nstops++] = i;
if (*cp == 0)
break;
- if (*cp++ != ',')
+ if (*cp != ',' && *cp != ' ')
goto bad;
+ cp++;
}
}
+
+static void
+usage()
+{
+ (void)fprintf (stderr, "usage: expand [-t tablist] [file ...]\n");
+ exit(1);
+}
diff --git a/usr.bin/f2c/Makefile b/usr.bin/f2c/Makefile
new file mode 100644
index 0000000..87a6c34
--- /dev/null
+++ b/usr.bin/f2c/Makefile
@@ -0,0 +1,35 @@
+# Makefile for f2c, a Fortran 77 to C converter
+
+PROG= f2c
+
+CFLAGS += -DANSI_Libraries -I${.CURDIR} -I.
+SHELL = /bin/sh
+
+SRCSd = main.c init.c gram.c lex.c proc.c equiv.c data.c format.c \
+ expr.c exec.c intr.c io.c misc.c error.c mem.c names.c \
+ output.c p1output.c pread.c put.c putpcc.c vax.c formatdata.c \
+ parse_args.c niceprintf.c cds.c sysdep.c version.c
+SRCS = $(SRCSd) # malloc.c
+
+GRAMFILES = ${.CURDIR}/gram.head ${.CURDIR}/gram.dcl ${.CURDIR}/gram.expr\
+ ${.CURDIR}/gram.exec ${.CURDIR}/gram.io
+
+gram.c: ${GRAMFILES} ${.CURDIR}/defs.h tokdefs.h
+ (sed < tokdefs.h "s/#define/%token/" ; \
+ cat ${GRAMFILES}) > gram.in
+ $(YACC) $(YFLAGS) gram.in
+ echo "# expect 4 shift/reduce conflicts"
+ sed 's/^# line.*/\/* & *\//' y.tab.c >gram.c
+ rm -f gram.in y.tab.c
+
+tokdefs.h: ${.CURDIR}/tokens
+ grep -n . <${.CURDIR}/tokens | sed "s/\([^:]*\):\(.*\)/#define \2 \1/" >tokdefs.h
+
+CLEANFILES+=\
+ gram.c tokdefs.h y.tab.h
+
+beforeinstall:
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/f2c.h \
+ ${DESTDIR}/usr/include
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/f2c/Notice b/usr.bin/f2c/Notice
new file mode 100644
index 0000000..8db1d7b
--- /dev/null
+++ b/usr.bin/f2c/Notice
@@ -0,0 +1,23 @@
+/****************************************************************
+Copyright 1990 - 1997 by AT&T Bell Laboratories and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T Bell Laboratories or
+Bellcore or any of their entities not be used in advertising or
+publicity pertaining to distribution of the software without
+specific, written prior permission.
+
+AT&T and Bellcore disclaim all warranties with regard to this
+software, including all implied warranties of merchantability
+and fitness. In no event shall AT&T or Bellcore be liable for
+any special, indirect or consequential damages or any damages
+whatsoever resulting from loss of use, data or profits, whether
+in an action of contract, negligence or other tortious action,
+arising out of or in connection with the use or performance of
+this software.
+****************************************************************/
+
diff --git a/usr.bin/f2c/README b/usr.bin/f2c/README
new file mode 100644
index 0000000..8267bea
--- /dev/null
+++ b/usr.bin/f2c/README
@@ -0,0 +1,168 @@
+Type "make" to check the validity of the f2c source and compile f2c.
+
+On a PC, you may need to compile xsum.c with -DMSDOS (i.e., with
+MSDOS #defined).
+
+If your compiler does not understand ANSI/ISO C syntax (i.e., if
+you have a K&R C compiler), compile with -DKR_headers .
+
+On non-Unix systems where files have separate binary and text modes,
+you may need to "make xsumr.out" rather than "make xsum.out".
+
+If (in accordance with what follows) you need to any of the source
+files (excluding the makefile), first issue a "make xsum.out" (or, if
+appropriate, "make xsumr.out") to check the validity of the f2c source,
+then make your changes, then type "make f2c".
+
+The file usignal.h is for the benefit of strictly ANSI include files
+on a UNIX system -- the ANSI signal.h does not define SIGHUP or SIGQUIT.
+You may need to modify usignal.h if you are not running f2c on a UNIX
+system.
+
+Should you get the message "xsum0.out xsum1.out differ", see what lines
+are different (`diff xsum0.out xsum1.out`) and ask netlib
+(e.g., netlib@netlib.bell-labs.com) to send you the files in question,
+plus the current xsum0.out (which may have changed) "from f2c/src".
+For example, if exec.c and expr.c have incorrect check sums, you would
+send netlib the message
+ send exec.c expr.c xsum0.out from f2c/src
+You can also ftp these files from netlib.bell-labs.com; for more
+details, ask netlib@netlib.bell-labs.com to "send readme from f2c".
+
+On some systems, the malloc and free in malloc.c let f2c run faster
+than do the standard malloc and free. Other systems may not tolerate
+redefinition of malloc and free (though changes of 8 Nov. 1994 may
+render this less of a problem than hitherto). If yours is such a
+system, you may either modify the makefile appropriately (remove
+"malloc.o" from the "OBJECTS =" assignment), or simply execute
+ cc -c -DCRAY malloc.c
+before typing "make". Still other systems have a -lmalloc that
+provides performance competitive with that from malloc.c; you may
+wish to compare the two on your system. In general, if f2c faults
+when you first try to run it, try compiling malloc.c with -DCRAY;
+this is necessary with at least one version of Linux (but not with
+others).
+
+On some BSD systems, you may need to create a file named "string.h"
+whose single line is
+#include <strings.h>
+you may need to add " -Dstrchr=index" to the "CFLAGS =" assignment
+in the makefile, and you may need to add " memset.o" to the "OBJECTS ="
+assignment in the makefile -- see the comments in memset.c .
+
+For non-UNIX systems, you may need to change some things in sysdep.c,
+such as the choice of intermediate file names.
+
+On some systems, you may need to modify parts of sysdep.h (which is
+included by defs.h). In particular, for Sun 4.1 systems and perhaps
+some others, you need to comment out the typedef of size_t. For some
+systems (e.g., IRIX 4.0.1 and AIX) it is better to add
+#define ANSI_Libraries
+to the beginning of sysdep.h (or to supply -DANSI_Libraries in the
+makefile).
+
+Alas, some systems #define __STDC__ but do not provide a true standard
+(ANSI or ISO) C environment, e.g. do not provide stdlib.h . If yours
+is such a system, then (a) you should complain loudly to your vendor
+about __STDC__ being erroneously defined, and (b) you should insert
+#undef __STDC__
+at the beginning of sysdep.h . You may need to make other adjustments.
+
+For some non-ANSI versions of stdio, you must change the values given
+to binread and binwrite in sysdep.c from "rb" and "wb" to "r" and "w".
+You may need to make this change if you run f2c and get an error
+message of the form
+ Compiler error ... cannot open intermediate file ...
+
+On many systems, it is best to combine libF77 and libI77 into a single
+library, say libf2c, as suggested in "readme from f2c". If you do not
+do this, then you should adjust the definition of link_msg in sysdep.c
+appropriately (e.g., replacing "-lf2c" by "-lF77 -lI77"). On Unix
+systems, the easiest way to create libf2c.a is to make libF77/libF77.a
+and libI77/libI77.a (after reading and heeding libF77/README and
+libI77/README), and then to say
+
+ cp libF77/libF77.a libf2c.a
+ ar ruv libf2c.a libI77/*.o
+ ranlib libf2c.a
+
+The last step, ranlib, may not be necessary on your system. On
+other systems, just compile all the .c files in libF77 and libI77,
+and put the resulting objects (except one or both of the Version
+objects) into a library, called perhaps f2c.lib .
+
+In general, under Linux it is necessary to compile libI77 with
+-DNON_UNIX_STDIO . Under at least one variant of Linux, you can make
+and install a shared-library version of libf2c by compiling libI77
+with -DNON_UNIX_STDIO, creating libf2c.a as above, and then executing
+
+ mkdir t
+ ln lib?77/*.o t
+ cd t; cc -shared -o ../libf2c.so -Wl,-soname,libf2c.so.1 *.o
+ cd ..
+ rm -r t
+ rm /usr/lib/libf2c*
+ mv libf2c.a libf2c.so /usr/lib
+ cd /usr/lib
+ ln libf2c.so libf2c.so.1
+ ln libf2c.so libf2c.so.1.0.0
+
+On some other systems, /usr/local/lib is the appropriate installation
+directory.
+
+
+Some older C compilers object to
+ typedef void (*foo)();
+or to
+ typedef void zap;
+ zap (*foo)();
+If yours is such a compiler, change the definition of VOID in
+f2c.h from void to int.
+
+For convenience with systems that use control-Z to denote end-of-file,
+f2c treats control-Z characters (ASCII 26, '\x1a') that appear at the
+beginning of a line as an end-of-file indicator. You can disable this
+test by compiling lex.c with NO_EOF_CHAR_CHECK #defined, or can
+change control-Z to some other character by #defining EOF_CHAR to
+be the desired value.
+
+
+If your machine has IEEE, VAX, or IBM-mainframe arithmetic, but your
+printf is inaccurate (e.g., with Symantec C++ version 6.0,
+printf("%.17g",12.) prints 12.000000000000001), you can make f2c print
+correctly rounded numbers by compiling with -DUSE_DTOA and adding
+dtoa.o g_fmt.o to the makefile's OBJECTS = line, so it becomes
+
+ OBJECTS = $(OBJECTSd) malloc.o dtoa.o g_fmt.o
+
+Also add the rule
+
+ dtoa.o: dtoa.c
+ $(CC) -c $(CFLAGS) -DMALLOC=ckalloc -DIEEE... dtoa.c
+
+(without the initial tab) to the makefile, where IEEE... is one of
+IEEE_MC68k, IEEE_8087, VAX, or IBM, depending on your machine's
+arithmetic. See the comments near the start of dtoa.c.
+
+The relevant source files, dtoa.c and g_fmt.c, are available
+separately from netlib's fp directory. For example, you could
+send the E-mail message
+
+ send dtoa.c g_fmt.c from fp
+
+to netlib@netlib.bell-labs.com (or use anonymous ftp from
+netlib.bell-labs.com and look in directory /netlib/fp).
+
+The makefile has a rule for creating tokdefs.h. If you cannot use the
+makefile, an alternative is to extract tokdefs.h from the beginning of
+gram.c: it's the first 100 lines.
+
+
+Please send bug reports to dmg@bell-labs.com . The old index file
+(now called "readme" due to unfortunate changes in netlib conventions:
+"send readme from f2c") will report recent changes in the recent-change
+log at its end; all changes will be shown in the "changes" file
+("send changes from f2c"). To keep current source, you will need to
+request xsum0.out and version.c, in addition to the changed source
+files. Changes first appear on netlib@netlib.bell-labs.com, and in due
+time propagate to the other netlib sites that are kept current.
diff --git a/usr.bin/f2c/cds.c b/usr.bin/f2c/cds.c
new file mode 100644
index 0000000..e5bacaa
--- /dev/null
+++ b/usr.bin/f2c/cds.c
@@ -0,0 +1,195 @@
+/****************************************************************
+Copyright 1990, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* Put strings representing decimal floating-point numbers
+ * into canonical form: always have a decimal point or
+ * exponent field; if using an exponent field, have the
+ * number before it start with a digit and decimal point
+ * (if the number has more than one digit); only have an
+ * exponent field if it saves space.
+ *
+ * Arrange that the return value, rv, satisfies rv[0] == '-' || rv[-1] == '-' .
+ */
+
+#include "defs.h"
+
+ char *
+#ifdef KR_headers
+cds(s, z0)
+ char *s;
+ char *z0;
+#else
+cds(char *s, char *z0)
+#endif
+{
+ int ea, esign, et, i, k, nd = 0, sign = 0, tz;
+ char c, *z;
+ char ebuf[24];
+ long ex = 0;
+ static char etype[Table_size], *db;
+ static int dblen = 64;
+
+ if (!db) {
+ etype['E'] = 1;
+ etype['e'] = 1;
+ etype['D'] = 1;
+ etype['d'] = 1;
+ etype['+'] = 2;
+ etype['-'] = 3;
+ db = Alloc(dblen);
+ }
+
+ while((c = *s++) == '0');
+ if (c == '-')
+ { sign = 1; c = *s++; }
+ else if (c == '+')
+ c = *s++;
+ k = strlen(s) + 2;
+ if (k >= dblen) {
+ do dblen <<= 1;
+ while(k >= dblen);
+ free(db);
+ db = Alloc(dblen);
+ }
+ if (etype[(unsigned char)c] >= 2)
+ while(c == '0') c = *s++;
+ tz = 0;
+ while(c >= '0' && c <= '9') {
+ if (c == '0')
+ tz++;
+ else {
+ if (nd)
+ for(; tz; --tz)
+ db[nd++] = '0';
+ else
+ tz = 0;
+ db[nd++] = c;
+ }
+ c = *s++;
+ }
+ ea = -tz;
+ if (c == '.') {
+ while((c = *s++) >= '0' && c <= '9') {
+ if (c == '0')
+ tz++;
+ else {
+ if (tz) {
+ ea += tz;
+ if (nd)
+ for(; tz; --tz)
+ db[nd++] = '0';
+ else
+ tz = 0;
+ }
+ db[nd++] = c;
+ ea++;
+ }
+ }
+ }
+ if (et = etype[(unsigned char)c]) {
+ esign = et == 3;
+ c = *s++;
+ if (et == 1) {
+ if(etype[(unsigned char)c] > 1) {
+ if (c == '-')
+ esign = 1;
+ c = *s++;
+ }
+ }
+ while(c >= '0' && c <= '9') {
+ ex = 10*ex + (c - '0');
+ c = *s++;
+ }
+ if (esign)
+ ex = -ex;
+ }
+ switch(c) {
+ case 0:
+ break;
+#ifndef VAX
+ case 'i':
+ case 'I':
+ Fatal("Overflow evaluating constant expression.");
+ case 'n':
+ case 'N':
+ Fatal("Constant expression yields NaN.");
+#endif
+ default:
+ Fatal("unexpected character in cds.");
+ }
+ ex -= ea;
+ if (!nd) {
+ if (!z0)
+ z0 = mem(4,0);
+ strcpy(z0, "-0.");
+ sign = 0;
+ }
+ else if (ex > 2 || ex + nd < -2) {
+ sprintf(ebuf, "%ld", ex + nd - 1);
+ k = strlen(ebuf) + nd + 3;
+ if (nd > 1)
+ k++;
+ if (!z0)
+ z0 = mem(k,0);
+ z = z0;
+ *z++ = '-';
+ *z++ = *db;
+ if (nd > 1) {
+ *z++ = '.';
+ for(k = 1; k < nd; k++)
+ *z++ = db[k];
+ }
+ *z++ = 'e';
+ strcpy(z, ebuf);
+ }
+ else {
+ k = (int)(ex + nd);
+ i = nd + 3;
+ if (k < 0)
+ i -= k;
+ else if (ex > 0)
+ i += ex;
+ if (!z0)
+ z0 = mem(i,0);
+ z = z0;
+ *z++ = '-';
+ if (ex >= 0) {
+ for(k = 0; k < nd; k++)
+ *z++ = db[k];
+ while(--ex >= 0)
+ *z++ = '0';
+ *z++ = '.';
+ }
+ else {
+ for(i = 0; i < k;)
+ *z++ = db[i++];
+ *z++ = '.';
+ while(++k <= 0)
+ *z++ = '0';
+ while(i < nd)
+ *z++ = db[i++];
+ }
+ *z = 0;
+ }
+ return sign ? z0 : z0+1;
+ }
diff --git a/usr.bin/f2c/data.c b/usr.bin/f2c/data.c
new file mode 100644
index 0000000..7454039
--- /dev/null
+++ b/usr.bin/f2c/data.c
@@ -0,0 +1,493 @@
+/****************************************************************
+Copyright 1990, 1993 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+
+/* ROUTINES CALLED DURING DATA AND PARAMETER STATEMENT PROCESSING */
+
+static char datafmt[] = "%s\t%09ld\t%d";
+static char *cur_varname;
+
+/* another initializer, called from parser */
+ void
+#ifdef KR_headers
+dataval(repp, valp)
+ register expptr repp;
+ register expptr valp;
+#else
+dataval(register expptr repp, register expptr valp)
+#endif
+{
+ int i, nrep;
+ ftnint elen;
+ register Addrp p;
+
+ if (parstate < INDATA) {
+ frexpr(repp);
+ goto ret;
+ }
+ if(repp == NULL)
+ nrep = 1;
+ else if (ISICON(repp) && repp->constblock.Const.ci >= 0)
+ nrep = repp->constblock.Const.ci;
+ else
+ {
+ err("invalid repetition count in DATA statement");
+ frexpr(repp);
+ goto ret;
+ }
+ frexpr(repp);
+
+ if( ! ISCONST(valp) ) {
+ if (valp->tag == TADDR
+ && valp->addrblock.uname_tag == UNAM_CONST) {
+ /* kludge */
+ frexpr(valp->addrblock.memoffset);
+ valp->tag = TCONST;
+ }
+ else {
+ err("non-constant initializer");
+ goto ret;
+ }
+ }
+
+ if(toomanyinit) goto ret;
+ for(i = 0 ; i < nrep ; ++i)
+ {
+ p = nextdata(&elen);
+ if(p == NULL)
+ {
+ if (lineno != err_lineno)
+ err("too many initializers");
+ toomanyinit = YES;
+ goto ret;
+ }
+ setdata((Addrp)p, (Constp)valp, elen);
+ frexpr((expptr)p);
+ }
+
+ret:
+ frexpr(valp);
+}
+
+
+ Addrp
+#ifdef KR_headers
+nextdata(elenp)
+ ftnint *elenp;
+#else
+nextdata(ftnint *elenp)
+#endif
+{
+ register struct Impldoblock *ip;
+ struct Primblock *pp;
+ register Namep np;
+ register struct Rplblock *rp;
+ tagptr p;
+ expptr neltp;
+ register expptr q;
+ int skip;
+ ftnint off, vlen;
+
+ while(curdtp)
+ {
+ p = (tagptr)curdtp->datap;
+ if(p->tag == TIMPLDO)
+ {
+ ip = &(p->impldoblock);
+ if(ip->implb==NULL || ip->impub==NULL || ip->varnp==NULL)
+ fatali("bad impldoblock 0%o", (int) ip);
+ if(ip->isactive)
+ ip->varvp->Const.ci += ip->impdiff;
+ else
+ {
+ q = fixtype(cpexpr(ip->implb));
+ if( ! ISICON(q) )
+ goto doerr;
+ ip->varvp = (Constp) q;
+
+ if(ip->impstep)
+ {
+ q = fixtype(cpexpr(ip->impstep));
+ if( ! ISICON(q) )
+ goto doerr;
+ ip->impdiff = q->constblock.Const.ci;
+ frexpr(q);
+ }
+ else
+ ip->impdiff = 1;
+
+ q = fixtype(cpexpr(ip->impub));
+ if(! ISICON(q))
+ goto doerr;
+ ip->implim = q->constblock.Const.ci;
+ frexpr(q);
+
+ ip->isactive = YES;
+ rp = ALLOC(Rplblock);
+ rp->rplnextp = rpllist;
+ rpllist = rp;
+ rp->rplnp = ip->varnp;
+ rp->rplvp = (expptr) (ip->varvp);
+ rp->rpltag = TCONST;
+ }
+
+ if( (ip->impdiff>0 && (ip->varvp->Const.ci <= ip->implim))
+ || (ip->impdiff<0 && (ip->varvp->Const.ci >= ip->implim)) )
+ { /* start new loop */
+ curdtp = ip->datalist;
+ goto next;
+ }
+
+ /* clean up loop */
+
+ if(rpllist)
+ {
+ rp = rpllist;
+ rpllist = rpllist->rplnextp;
+ free( (charptr) rp);
+ }
+ else
+ Fatal("rpllist empty");
+
+ frexpr((expptr)ip->varvp);
+ ip->isactive = NO;
+ curdtp = curdtp->nextp;
+ goto next;
+ }
+
+ pp = (struct Primblock *) p;
+ np = pp->namep;
+ cur_varname = np->fvarname;
+ skip = YES;
+
+ if(p->primblock.argsp==NULL && np->vdim!=NULL)
+ { /* array initialization */
+ q = (expptr) mkaddr(np);
+ off = typesize[np->vtype] * curdtelt;
+ if(np->vtype == TYCHAR)
+ off *= np->vleng->constblock.Const.ci;
+ q->addrblock.memoffset =
+ mkexpr(OPPLUS, q->addrblock.memoffset, mkintcon(off) );
+ if( (neltp = np->vdim->nelt) && ISCONST(neltp))
+ {
+ if(++curdtelt < neltp->constblock.Const.ci)
+ skip = NO;
+ }
+ else
+ err("attempt to initialize adjustable array");
+ }
+ else
+ q = mklhs((struct Primblock *)cpexpr((expptr)pp), 0);
+ if(skip)
+ {
+ curdtp = curdtp->nextp;
+ curdtelt = 0;
+ }
+ if(q->headblock.vtype == TYCHAR)
+ if(ISICON(q->headblock.vleng))
+ *elenp = q->headblock.vleng->constblock.Const.ci;
+ else {
+ err("initialization of string of nonconstant length");
+ continue;
+ }
+ else *elenp = typesize[q->headblock.vtype];
+
+ if (np->vstg == STGBSS) {
+ vlen = np->vtype==TYCHAR
+ ? np->vleng->constblock.Const.ci
+ : typesize[np->vtype];
+ if(vlen > 0)
+ np->vstg = STGINIT;
+ }
+ return( (Addrp) q );
+
+doerr:
+ err("nonconstant implied DO parameter");
+ frexpr(q);
+ curdtp = curdtp->nextp;
+
+next:
+ curdtelt = 0;
+ }
+
+ return(NULL);
+}
+
+
+
+LOCAL FILEP dfile;
+
+ void
+#ifdef KR_headers
+setdata(varp, valp, elen)
+ register Addrp varp;
+ register Constp valp;
+ ftnint elen;
+#else
+setdata(register Addrp varp, register Constp valp, ftnint elen)
+#endif
+{
+ struct Constblock con;
+ register int type;
+ int i, k, valtype;
+ ftnint offset;
+ char *varname;
+ static Addrp badvar;
+ register unsigned char *s;
+ static int last_lineno;
+ static char *last_varname;
+
+ if (varp->vstg == STGCOMMON) {
+ if (!(dfile = blkdfile))
+ dfile = blkdfile = opf(blkdfname, textwrite);
+ }
+ else {
+ if (procclass == CLBLOCK) {
+ if (varp != badvar) {
+ badvar = varp;
+ warn1("%s is not in a COMMON block",
+ varp->uname_tag == UNAM_NAME
+ ? varp->user.name->fvarname
+ : "???");
+ }
+ return;
+ }
+ if (!(dfile = initfile))
+ dfile = initfile = opf(initfname, textwrite);
+ }
+ varname = dataname(varp->vstg, varp->memno);
+ offset = varp->memoffset->constblock.Const.ci;
+ type = varp->vtype;
+ valtype = valp->vtype;
+ if(type!=TYCHAR && valtype==TYCHAR)
+ {
+ if(! ftn66flag
+ && (last_varname != cur_varname || last_lineno != lineno)) {
+ /* prevent multiple warnings */
+ last_lineno = lineno;
+ warn1(
+ "non-character datum %.42s initialized with character string",
+ last_varname = cur_varname);
+ }
+ varp->vleng = ICON(typesize[type]);
+ varp->vtype = type = TYCHAR;
+ }
+ else if( (type==TYCHAR && valtype!=TYCHAR) ||
+ (cktype(OPASSIGN,type,valtype) == TYERROR) )
+ {
+ err("incompatible types in initialization");
+ return;
+ }
+ if(type == TYADDR)
+ con.Const.ci = valp->Const.ci;
+ else if(type != TYCHAR)
+ {
+ if(valtype == TYUNKNOWN)
+ con.Const.ci = valp->Const.ci;
+ else consconv(type, &con, valp);
+ }
+
+ k = 1;
+
+ switch(type)
+ {
+ case TYLOGICAL:
+ case TYINT1:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ dataline(varname, offset, type);
+ prconi(dfile, con.Const.ci);
+ break;
+
+ case TYADDR:
+ dataline(varname, offset, type);
+ prcona(dfile, con.Const.ci);
+ break;
+
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ k = 2;
+ case TYREAL:
+ case TYDREAL:
+ dataline(varname, offset, type);
+ prconr(dfile, &con, k);
+ break;
+
+ case TYCHAR:
+ k = valp -> vleng -> constblock.Const.ci;
+ if (elen < k)
+ k = elen;
+ s = (unsigned char *)valp->Const.ccp;
+ for(i = 0 ; i < k ; ++i) {
+ dataline(varname, offset++, TYCHAR);
+ fprintf(dfile, "\t%d\n", *s++);
+ }
+ k = elen - valp->vleng->constblock.Const.ci;
+ if(k > 0) {
+ dataline(varname, offset, TYBLANK);
+ fprintf(dfile, "\t%d\n", k);
+ }
+ break;
+
+ default:
+ badtype("setdata", type);
+ }
+
+}
+
+
+
+/*
+ output form of name is padded with blanks and preceded
+ with a storage class digit
+*/
+ char*
+#ifdef KR_headers
+dataname(stg, memno)
+ int stg;
+ long memno;
+#else
+dataname(int stg, long memno)
+#endif
+{
+ static char varname[64];
+ register char *s, *t;
+ char buf[16];
+
+ if (stg == STGCOMMON) {
+ varname[0] = '2';
+ sprintf(s = buf, "Q.%ld", memno);
+ }
+ else {
+ varname[0] = stg==STGEQUIV ? '1' : '0';
+ s = memname(stg, memno);
+ }
+ t = varname + 1;
+ while(*t++ = *s++);
+ *t = 0;
+ return(varname);
+}
+
+
+
+
+ void
+#ifdef KR_headers
+frdata(p0)
+ chainp p0;
+#else
+frdata(chainp p0)
+#endif
+{
+ register struct Chain *p;
+ register tagptr q;
+
+ for(p = p0 ; p ; p = p->nextp)
+ {
+ q = (tagptr)p->datap;
+ if(q->tag == TIMPLDO)
+ {
+ if(q->impldoblock.isbusy)
+ return; /* circular chain completed */
+ q->impldoblock.isbusy = YES;
+ frdata(q->impldoblock.datalist);
+ free( (charptr) q);
+ }
+ else
+ frexpr(q);
+ }
+
+ frchain( &p0);
+}
+
+
+ void
+#ifdef KR_headers
+dataline(varname, offset, type)
+ char *varname;
+ ftnint offset;
+ int type;
+#else
+dataline(char *varname, ftnint offset, int type)
+#endif
+{
+ fprintf(dfile, datafmt, varname, offset, type);
+}
+
+ void
+#ifdef KR_headers
+make_param(p, e)
+ register struct Paramblock *p;
+ expptr e;
+#else
+make_param(register struct Paramblock *p, expptr e)
+#endif
+{
+ register expptr q;
+ Constp qc;
+
+ if (p->vstg == STGARG)
+ errstr("Dummy argument %.50s appears in a parameter statement.",
+ p->fvarname);
+ p->vclass = CLPARAM;
+ impldcl((Namep)p);
+ if (e->headblock.vtype != TYCHAR)
+ e = putx(fixtype(e));
+ p->paramval = q = mkconv(p->vtype, e);
+ if (p->vtype == TYCHAR) {
+ if (q->tag == TEXPR)
+ p->paramval = q = fixexpr((Exprp)q);
+ if (q->tag == TADDR && q->addrblock.uname_tag == UNAM_CONST) {
+ qc = mkconst(TYCHAR);
+ qc->Const = q->addrblock.user.Const;
+ qc->vleng = q->addrblock.vleng;
+ q->addrblock.vleng = 0;
+ frexpr(q);
+ p->paramval = q = (expptr)qc;
+ }
+ if (!ISCONST(q) || q->constblock.vtype != TYCHAR) {
+ errstr("invalid value for character parameter %s",
+ p->fvarname);
+ return;
+ }
+ if (!(e = p->vleng))
+ p->vleng = ICON(q->constblock.vleng->constblock.Const.ci
+ + q->constblock.Const.ccp1.blanks);
+ else if (q->constblock.vleng->constblock.Const.ci
+ > e->constblock.Const.ci) {
+ q->constblock.vleng->constblock.Const.ci
+ = e->constblock.Const.ci;
+ q->constblock.Const.ccp1.blanks = 0;
+ }
+ else
+ q->constblock.Const.ccp1.blanks
+ = e->constblock.Const.ci
+ - q->constblock.vleng->constblock.Const.ci;
+ }
+ }
diff --git a/usr.bin/f2c/defines.h b/usr.bin/f2c/defines.h
new file mode 100644
index 0000000..1ed4537
--- /dev/null
+++ b/usr.bin/f2c/defines.h
@@ -0,0 +1,300 @@
+#define PDP11 4
+
+#define BIGGEST_CHAR 0x7f /* Assumes 32-bit arithmetic */
+#define BIGGEST_SHORT 0x7fff /* Assumes 32-bit arithmetic */
+#define BIGGEST_LONG 0x7fffffff /* Assumes 32-bit arithmetic */
+
+#define M(x) (1<<x) /* Mask (x) returns 2^x */
+
+#define ALLOC(x) (struct x *) ckalloc((int)sizeof(struct x))
+#define ALLEXPR (expptr) ckalloc((int)sizeof(union Expression) )
+typedef int *ptr;
+typedef char *charptr;
+typedef FILE *FILEP;
+typedef int flag;
+typedef char field; /* actually need only 4 bits */
+typedef long int ftnint;
+#define LOCAL static
+
+#define NO 0
+#define YES 1
+
+#define CNULL (char *) 0 /* Character string null */
+#define PNULL (ptr) 0
+#define CHNULL (chainp) 0 /* Chain null */
+#define ENULL (expptr) 0
+
+
+/* BAD_MEMNO - used to distinguish between long string constants and other
+ constants in the table */
+
+#define BAD_MEMNO -32768
+
+
+/* block tag values -- syntactic stuff */
+
+#define TNAME 1
+#define TCONST 2
+#define TEXPR 3
+#define TADDR 4
+#define TPRIM 5 /* Primitive datum - should not appear in an
+ expptr variable, it should have already been
+ identified */
+#define TLIST 6
+#define TIMPLDO 7
+#define TERROR 8
+
+
+/* parser states - order is important, since there are several tests for
+ state < INDATA */
+
+#define OUTSIDE 0
+#define INSIDE 1
+#define INDCL 2
+#define INDATA 3
+#define INEXEC 4
+
+/* procedure classes */
+
+#define PROCMAIN 1
+#define PROCBLOCK 2
+#define PROCSUBR 3
+#define PROCFUNCT 4
+
+
+/* storage classes -- vstg values. BSS and INIT are used in the later
+ merge pass over identifiers; and they are entered differently into the
+ symbol table */
+
+#define STGUNKNOWN 0
+#define STGARG 1 /* adjustable dimensions */
+#define STGAUTO 2 /* for stack references */
+#define STGBSS 3 /* uninitialized storage (normal variables) */
+#define STGINIT 4 /* initialized storage */
+#define STGCONST 5
+#define STGEXT 6 /* external storage */
+#define STGINTR 7 /* intrinsic (late decision) reference. See
+ chapter 5 of the Fortran 77 standard */
+#define STGSTFUNCT 8
+#define STGCOMMON 9
+#define STGEQUIV 10
+#define STGREG 11 /* register - the outermost DO loop index will be
+ in a register (because the compiler is one
+ pass, it can't know where the innermost loop is
+ */
+#define STGLENG 12
+#define STGNULL 13
+#define STGMEMNO 14 /* interemediate-file pointer to constant table */
+
+/* name classes -- vclass values, also procclass values */
+
+#define CLUNKNOWN 0
+#define CLPARAM 1 /* Parameter - macro definition */
+#define CLVAR 2 /* variable */
+#define CLENTRY 3
+#define CLMAIN 4
+#define CLBLOCK 5
+#define CLPROC 6
+#define CLNAMELIST 7 /* in data with this tag, the vdcldone flag should
+ be ignored (according to vardcl()) */
+
+
+/* vprocclass values -- there is some overlap with the vclass values given
+ above */
+
+#define PUNKNOWN 0
+#define PEXTERNAL 1
+#define PINTRINSIC 2
+#define PSTFUNCT 3
+#define PTHISPROC 4 /* here to allow recursion - further distinction
+ is given in the CL tag (those just above).
+ This applies to the presence of the name of a
+ function used within itself. The function name
+ means either call the function again, or assign
+ some value to the storage allocated to the
+ function's return value. */
+
+/* control stack codes - these are part of a state machine which handles
+ the nesting of blocks (i.e. what to do about the ELSE statement) */
+
+#define CTLDO 1
+#define CTLIF 2
+#define CTLELSE 3
+#define CTLIFX 4
+
+
+/* operators for both Fortran input and C output. They are common because
+ so many are shared between the trees */
+
+#define OPPLUS 1
+#define OPMINUS 2
+#define OPSTAR 3
+#define OPSLASH 4
+#define OPPOWER 5
+#define OPNEG 6
+#define OPOR 7
+#define OPAND 8
+#define OPEQV 9
+#define OPNEQV 10
+#define OPNOT 11
+#define OPCONCAT 12
+#define OPLT 13
+#define OPEQ 14
+#define OPGT 15
+#define OPLE 16
+#define OPNE 17
+#define OPGE 18
+#define OPCALL 19
+#define OPCCALL 20
+#define OPASSIGN 21
+#define OPPLUSEQ 22
+#define OPSTAREQ 23
+#define OPCONV 24
+#define OPLSHIFT 25
+#define OPMOD 26
+#define OPCOMMA 27
+#define OPQUEST 28
+#define OPCOLON 29
+#define OPABS 30
+#define OPMIN 31
+#define OPMAX 32
+#define OPADDR 33
+#define OPCOMMA_ARG 34
+#define OPBITOR 35
+#define OPBITAND 36
+#define OPBITXOR 37
+#define OPBITNOT 38
+#define OPRSHIFT 39
+#define OPWHATSIN 40 /* dereferencing operator */
+#define OPMINUSEQ 41 /* assignment operators */
+#define OPSLASHEQ 42
+#define OPMODEQ 43
+#define OPLSHIFTEQ 44
+#define OPRSHIFTEQ 45
+#define OPBITANDEQ 46
+#define OPBITXOREQ 47
+#define OPBITOREQ 48
+#define OPPREINC 49 /* Preincrement (++x) operator */
+#define OPPREDEC 50 /* Predecrement (--x) operator */
+#define OPDOT 51 /* structure field reference */
+#define OPARROW 52 /* structure pointer field reference */
+#define OPNEG1 53 /* simple negation under forcedouble */
+#define OPDMIN 54 /* min(a,b) macro under forcedouble */
+#define OPDMAX 55 /* max(a,b) macro under forcedouble */
+#define OPASSIGNI 56 /* assignment for inquire stmt */
+#define OPIDENTITY 57 /* for turning TADDR into TEXPR */
+#define OPCHARCAST 58 /* for casting to char * (in I/O stmts) */
+#define OPDABS 59 /* abs macro under forcedouble */
+#define OPMIN2 60 /* min(a,b) macro */
+#define OPMAX2 61 /* max(a,b) macro */
+#define OPBITTEST 62 /* btest */
+#define OPBITCLR 63 /* ibclr */
+#define OPBITSET 64 /* ibset */
+#define OPQBITCLR 65 /* ibclr, integer*8 */
+#define OPQBITSET 66 /* ibset, integer*8 */
+#define OPBITBITS 67 /* ibits */
+#define OPBITSH 68 /* ishft */
+#define OPBITSHC 69 /* ishftc */
+
+/* label type codes -- used with the ASSIGN statement */
+
+#define LABUNKNOWN 0
+#define LABEXEC 1
+#define LABFORMAT 2
+#define LABOTHER 3
+
+
+/* INTRINSIC function codes*/
+
+#define INTREND 0
+#define INTRCONV 1
+#define INTRMIN 2
+#define INTRMAX 3
+#define INTRGEN 4 /* General intrinsic, e.g. cos v. dcos, zcos, ccos */
+#define INTRSPEC 5
+#define INTRBOOL 6
+#define INTRCNST 7 /* constants, e.g. bigint(1.0) v. bigint (1d0) */
+#define INTRBGEN 8 /* bit manipulation */
+
+
+/* I/O statement codes - these all form Integer Constants, and are always
+ reevaluated */
+
+#define IOSTDIN ICON(5)
+#define IOSTDOUT ICON(6)
+#define IOSTDERR ICON(0)
+
+#define IOSBAD (-1)
+#define IOSPOSITIONAL 0
+#define IOSUNIT 1
+#define IOSFMT 2
+
+#define IOINQUIRE 1
+#define IOOPEN 2
+#define IOCLOSE 3
+#define IOREWIND 4
+#define IOBACKSPACE 5
+#define IOENDFILE 6
+#define IOREAD 7
+#define IOWRITE 8
+
+
+/* User name tags -- these identify the form of the original identifier
+ stored in a struct Addrblock structure (in the user field). */
+
+#define UNAM_UNKNOWN 0 /* Not specified */
+#define UNAM_NAME 1 /* Local symbol, store in the hash table */
+#define UNAM_IDENT 2 /* Character string not stored elsewhere */
+#define UNAM_EXTERN 3 /* External reference; check symbol table
+ using memno as index */
+#define UNAM_CONST 4 /* Constant value */
+#define UNAM_CHARP 5 /* pointer to string */
+#define UNAM_REF 6 /* subscript reference with -s */
+
+
+#define IDENT_LEN 31 /* Maximum length user.ident */
+#define MAXNAMELEN 50 /* Maximum Fortran name length */
+
+/* type masks - TYLOGICAL defined in ftypes */
+
+#define MSKLOGICAL M(TYLOGICAL)|M(TYLOGICAL1)|M(TYLOGICAL2)
+#define MSKADDR M(TYADDR)
+#define MSKCHAR M(TYCHAR)
+#ifdef TYQUAD
+#define MSKINT M(TYINT1)|M(TYSHORT)|M(TYLONG)|M(TYQUAD)
+#else
+#define MSKINT M(TYINT1)|M(TYSHORT)|M(TYLONG)
+#endif
+#define MSKREAL M(TYREAL)|M(TYDREAL) /* DREAL means Double Real */
+#define MSKCOMPLEX M(TYCOMPLEX)|M(TYDCOMPLEX)
+#define MSKSTATIC (M(STGINIT)|M(STGBSS)|M(STGCOMMON)|M(STGEQUIV)|M(STGCONST))
+
+/* miscellaneous macros */
+
+/* ONEOF (x, y) -- x is the number of one of the OR'ed masks in y (i.e., x is
+ the log of one of the OR'ed masks in y) */
+
+#define ONEOF(x,y) (M(x) & (y))
+#define ISCOMPLEX(z) ONEOF(z, MSKCOMPLEX)
+#define ISREAL(z) ONEOF(z, MSKREAL)
+#define ISNUMERIC(z) ONEOF(z, MSKINT|MSKREAL|MSKCOMPLEX)
+#define ISICON(z) (z->tag==TCONST && ISINT(z->constblock.vtype))
+#define ISLOGICAL(z) ONEOF(z, MSKLOGICAL)
+
+/* ISCHAR assumes that z has some kind of structure, i.e. is not null */
+
+#define ISCHAR(z) (z->headblock.vtype==TYCHAR)
+#define ISINT(z) ONEOF(z, MSKINT) /* z is a tag, i.e. a mask number */
+#define ISCONST(z) (z->tag==TCONST)
+#define ISERROR(z) (z->tag==TERROR)
+#define ISPLUSOP(z) (z->tag==TEXPR && z->exprblock.opcode==OPPLUS)
+#define ISSTAROP(z) (z->tag==TEXPR && z->exprblock.opcode==OPSTAR)
+#define ISONE(z) (ISICON(z) && z->constblock.Const.ci==1)
+#define INT(z) ONEOF(z, MSKINT|MSKCHAR) /* has INT storage in real life */
+#define ICON(z) mkintcon( (ftnint)(z) )
+
+/* NO66 -- F77 feature is being used
+ NOEXT -- F77 extension is being used */
+
+#define NO66(s) if(no66flag) err66(s)
+#define NOEXT(s) if(noextflag) errext(s)
diff --git a/usr.bin/f2c/defs.h b/usr.bin/f2c/defs.h
new file mode 100644
index 0000000..2d80862
--- /dev/null
+++ b/usr.bin/f2c/defs.h
@@ -0,0 +1,1055 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "sysdep.h"
+
+#include "ftypes.h"
+#include "defines.h"
+#include "machdefs.h"
+
+#define MAXDIM 20
+#define MAXINCLUDES 10
+#define MAXLITERALS 200 /* Max number of constants in the literal
+ pool */
+#define MAXCTL 20
+#define MAXHASH 401
+#define MAXSTNO 801
+#define MAXEXT 200
+#define MAXEQUIV 150
+#define MAXLABLIST 258 /* Max number of labels in an alternate
+ return CALL or computed GOTO */
+#define MAXCONTIN 99 /* Max continuation lines */
+
+/* These are the primary pointer types used in the compiler */
+
+typedef union Expression *expptr, *tagptr;
+typedef struct Chain *chainp;
+typedef struct Addrblock *Addrp;
+typedef struct Constblock *Constp;
+typedef struct Exprblock *Exprp;
+typedef struct Nameblock *Namep;
+
+extern FILEP infile;
+extern FILEP diagfile;
+extern FILEP textfile;
+extern FILEP asmfile;
+extern FILEP c_file; /* output file for all functions; extern
+ declarations will have to be prepended */
+extern FILEP pass1_file; /* Temp file to hold the function bodies
+ read on pass 1 */
+extern FILEP expr_file; /* Debugging file */
+extern FILEP initfile; /* Intermediate data file pointer */
+extern FILEP blkdfile; /* BLOCK DATA file */
+
+extern int current_ftn_file;
+extern int maxcontin;
+
+extern char *blkdfname, *initfname, *sortfname;
+extern long headoffset; /* Since the header block requires data we
+ don't know about until AFTER each
+ function has been processed, we keep a
+ pointer to the current (dummy) header
+ block (at the top of the assembly file)
+ here */
+
+extern char main_alias[]; /* name given to PROGRAM psuedo-op */
+extern char *token;
+extern int maxtoklen, toklen;
+extern long err_lineno, lineno;
+extern char *infname;
+extern int needkwd;
+extern struct Labelblock *thislabel;
+
+/* Used to allow runtime expansion of internal tables. In particular,
+ these values can exceed their associated constants */
+
+extern int maxctl;
+extern int maxequiv;
+extern int maxstno;
+extern int maxhash;
+extern int maxext;
+
+extern flag nowarnflag;
+extern flag ftn66flag; /* Generate warnings when weird f77
+ features are used (undeclared dummy
+ procedure, non-char initialized with
+ string, 1-dim subscript in EQUIV) */
+extern flag no66flag; /* Generate an error when a generic
+ function (f77 feature) is used */
+extern flag noextflag; /* Generate an error when an extension to
+ Fortran 77 is used (hex/oct/bin
+ constants, automatic, static, double
+ complex types) */
+extern flag zflag; /* enable double complex intrinsics */
+extern flag shiftcase;
+extern flag undeftype;
+extern flag shortsubs; /* Use short subscripts on arrays? */
+extern flag onetripflag; /* if true, always execute DO loop body */
+extern flag checksubs;
+extern flag debugflag;
+extern int nerr;
+extern int nwarn;
+
+extern int parstate;
+extern flag headerdone; /* True iff the current procedure's header
+ data has been written */
+extern int blklevel;
+extern flag saveall;
+extern flag substars; /* True iff some formal parameter is an
+ asterisk */
+extern int impltype[ ];
+extern ftnint implleng[ ];
+extern int implstg[ ];
+
+extern int tycomplex, tyint, tyioint, tyreal;
+extern int tylog, tylogical; /* TY____ of the implementation of logical.
+ This will be LONG unless '-2' is given
+ on the command line */
+extern int type_choice[];
+extern char *typename[];
+
+extern int typesize[]; /* size (in bytes) of an object of each
+ type. Indexed by TY___ macros */
+extern int typealign[];
+extern int proctype; /* Type of return value in this procedure */
+extern char * procname; /* External name of the procedure, or last ENTRY name */
+extern int rtvlabel[ ]; /* Return value labels, indexed by TY___ macros */
+extern Addrp retslot;
+extern Addrp xretslot[];
+extern int cxslot; /* Complex return argument slot (frame pointer offset)*/
+extern int chslot; /* Character return argument slot (fp offset) */
+extern int chlgslot; /* Argument slot for length of character buffer */
+extern int procclass; /* Class of the current procedure: either CLPROC,
+ CLMAIN, CLBLOCK or CLUNKNOWN */
+extern ftnint procleng; /* Length of function return value (e.g. char
+ string length). If this is -1, then the length is
+ not known at compile time */
+extern int nentry; /* Number of entry points (other than the original
+ function call) into this procedure */
+extern flag multitype; /* YES iff there is more than one return value
+ possible */
+extern int blklevel;
+extern long lastiolabno;
+extern long lastlabno;
+extern int lastvarno;
+extern int lastargslot; /* integer offset pointing to the next free
+ location for an argument to the current routine */
+extern int argloc;
+extern int autonum[]; /* for numbering
+ automatic variables, e.g. temporaries */
+extern int retlabel;
+extern int ret0label;
+extern int dorange; /* Number of the label which terminates
+ the innermost DO loop */
+extern int regnum[ ]; /* Numbers of DO indicies named in
+ regnamep (below) */
+extern Namep regnamep[ ]; /* List of DO indicies in registers */
+extern int maxregvar; /* number of elts in regnamep */
+extern int highregvar; /* keeps track of the highest register
+ number used by DO index allocator */
+extern int nregvar; /* count of DO indicies in registers */
+
+extern chainp templist[];
+extern int maxdim;
+extern chainp earlylabs;
+extern chainp holdtemps;
+extern struct Entrypoint *entries;
+extern struct Rplblock *rpllist;
+extern struct Chain *curdtp;
+extern ftnint curdtelt;
+extern chainp allargs; /* union of args in entries */
+extern int nallargs; /* total number of args */
+extern int nallchargs; /* total number of character args */
+extern flag toomanyinit; /* True iff too many initializers in a
+ DATA statement */
+
+extern flag inioctl;
+extern int iostmt;
+extern Addrp ioblkp;
+extern int nioctl;
+extern int nequiv;
+extern int eqvstart; /* offset to eqv number to guarantee uniqueness
+ and prevent <something> from going negative */
+extern int nintnames;
+
+/* Chain of tagged blocks */
+
+struct Chain
+ {
+ chainp nextp;
+ char * datap; /* Tagged block */
+ };
+
+extern chainp chains;
+
+/* Recall that field is intended to hold four-bit characters */
+
+/* This structure exists only to defeat the type checking */
+
+struct Headblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg;
+ expptr vleng; /* Expression for length of char string -
+ this may be a constant, or an argument
+ generated by mkarg() */
+ } ;
+
+/* Control construct info (for do loops, else, etc) */
+
+struct Ctlframe
+ {
+ unsigned ctltype:8;
+ unsigned dostepsign:8; /* 0 - variable, 1 - pos, 2 - neg */
+ unsigned dowhile:1;
+ int ctlabels[4]; /* Control labels, defined below */
+ int dolabel; /* label marking end of this DO loop */
+ Namep donamep; /* DO index variable */
+ expptr doinit; /* for use with -onetrip */
+ expptr domax; /* constant or temp variable holding MAX
+ loop value; or expr of while(expr) */
+ expptr dostep; /* expression */
+ Namep loopname;
+ };
+#define endlabel ctlabels[0]
+#define elselabel ctlabels[1]
+#define dobodylabel ctlabels[1]
+#define doposlabel ctlabels[2]
+#define doneglabel ctlabels[3]
+extern struct Ctlframe *ctls; /* Keeps info on DO and BLOCK IF
+ structures - this is the stack
+ bottom */
+extern struct Ctlframe *ctlstack; /* Pointer to current nesting
+ level */
+extern struct Ctlframe *lastctl; /* Point to end of
+ dynamically-allocated array */
+
+typedef struct {
+ int type;
+ chainp cp;
+ } Atype;
+
+typedef struct {
+ int defined, dnargs, nargs, changes;
+ Atype atypes[1];
+ } Argtypes;
+
+/* External Symbols */
+
+struct Extsym
+ {
+ char *fextname; /* Fortran version of external name */
+ char *cextname; /* C version of external name */
+ field extstg; /* STG -- should be COMMON, UNKNOWN or EXT
+ */
+ unsigned extype:4; /* for transmitting type to output routines */
+ unsigned used_here:1; /* Boolean - true on the second pass
+ through a function if the block has
+ been referenced */
+ unsigned exused:1; /* Has been used (for help with error msgs
+ about externals typed differently in
+ different modules) */
+ unsigned exproto:1; /* type specified in a .P file */
+ unsigned extinit:1; /* Procedure has been defined,
+ or COMMON has DATA */
+ unsigned extseen:1; /* True if previously referenced */
+ chainp extp; /* List of identifiers in the common
+ block for this function, stored as
+ Namep (hash table pointers) */
+ chainp allextp; /* List of lists of identifiers; we keep one
+ list for each layout of this common block */
+ int curno; /* current number for this common block,
+ used for constructing appending _nnn
+ to the common block name */
+ int maxno; /* highest curno value for this common block */
+ ftnint extleng;
+ ftnint maxleng;
+ Argtypes *arginfo;
+ };
+typedef struct Extsym Extsym;
+
+extern Extsym *extsymtab; /* External symbol table */
+extern Extsym *nextext;
+extern Extsym *lastext;
+extern int complex_seen, dcomplex_seen;
+
+/* Statement labels */
+
+struct Labelblock
+ {
+ int labelno; /* Internal label */
+ unsigned blklevel:8; /* level of nesting, for branch-in-loop
+ checking */
+ unsigned labused:1;
+ unsigned fmtlabused:1;
+ unsigned labinacc:1; /* inaccessible? (i.e. has its scope
+ vanished) */
+ unsigned labdefined:1; /* YES or NO */
+ unsigned labtype:2; /* LAB{FORMAT,EXEC,etc} */
+ ftnint stateno; /* Original label */
+ char *fmtstring; /* format string */
+ };
+
+extern struct Labelblock *labeltab; /* Label table - keeps track of
+ all labels, including undefined */
+extern struct Labelblock *labtabend;
+extern struct Labelblock *highlabtab;
+
+/* Entry point list */
+
+struct Entrypoint
+ {
+ struct Entrypoint *entnextp;
+ Extsym *entryname; /* Name of this ENTRY */
+ chainp arglist;
+ int typelabel; /* Label for function exit; this
+ will return the proper type of
+ object */
+ Namep enamep; /* External name */
+ };
+
+/* Primitive block, or Primary block. This is a general template returned
+ by the parser, which will be interpreted in context. It is a template
+ for an identifier (variable name, function name), parenthesized
+ arguments (array subscripts, function parameters) and substring
+ specifications. */
+
+struct Primblock
+ {
+ field tag;
+ field vtype;
+ unsigned parenused:1; /* distinguish (a) from a */
+ Namep namep; /* Pointer to structure Nameblock */
+ struct Listblock *argsp;
+ expptr fcharp; /* first-char-index-pointer (in
+ substring) */
+ expptr lcharp; /* last-char-index-pointer (in
+ substring) */
+ };
+
+
+struct Hashentry
+ {
+ int hashval;
+ Namep varp;
+ };
+extern struct Hashentry *hashtab; /* Hash table */
+extern struct Hashentry *lasthash;
+
+struct Intrpacked /* bits for intrinsic function description */
+ {
+ unsigned f1:4;
+ unsigned f2:4;
+ unsigned f3:7;
+ unsigned f4:1;
+ };
+
+struct Nameblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg;
+ expptr vleng; /* length of character string, if applicable */
+ char *fvarname; /* name in the Fortran source */
+ char *cvarname; /* name in the resulting C */
+ chainp vlastdim; /* datap points to new_vars entry for the */
+ /* system variable, if any, storing the final */
+ /* dimension; we zero the datap if this */
+ /* variable is needed */
+ unsigned vprocclass:3; /* P____ macros - selects the varxptr
+ field below */
+ unsigned vdovar:1; /* "is it a DO variable?" for register
+ and multi-level loop checking */
+ unsigned vdcldone:1; /* "do I think I'm done?" - set when the
+ context is sufficient to determine its
+ status */
+ unsigned vadjdim:1; /* "adjustable dimension?" - needed for
+ information about copies */
+ unsigned vsave:1;
+ unsigned vimpldovar:1; /* used to prevent erroneous error messages
+ for variables used only in DATA stmt
+ implicit DOs */
+ unsigned vis_assigned:1;/* True if this variable has had some
+ label ASSIGNED to it; hence
+ varxptr.assigned_values is valid */
+ unsigned vimplstg:1; /* True if storage type is assigned implicitly;
+ this allows a COMMON variable to participate
+ in a DIMENSION before the COMMON declaration.
+ */
+ unsigned vcommequiv:1; /* True if EQUIVALENCEd onto STGCOMMON */
+ unsigned vfmt_asg:1; /* True if char *var_fmt needed */
+ unsigned vpassed:1; /* True if passed as a character-variable arg */
+ unsigned vknownarg:1; /* True if seen in a previous entry point */
+ unsigned visused:1; /* True if variable is referenced -- so we */
+ /* can omit variables that only appear in DATA */
+ unsigned vnamelist:1; /* Appears in a NAMELIST */
+ unsigned vimpltype:1; /* True if implicitly typed and not
+ invoked as a function or subroutine
+ (so we can consistently type procedures
+ declared external and passed as args
+ but never invoked).
+ */
+ unsigned vtypewarned:1; /* so we complain just once about
+ changed types of external procedures */
+ unsigned vinftype:1; /* so we can restore implicit type to a
+ procedure if it is invoked as a function
+ after being given a different type by -it */
+ unsigned vinfproc:1; /* True if -it infers this to be a procedure */
+ unsigned vcalled:1; /* has been invoked */
+ unsigned vdimfinish:1; /* need to invoke dim_finish() */
+ unsigned vrefused:1; /* Need to #define name_ref (for -s) */
+ unsigned vsubscrused:1; /* Need to #define name_subscr (for -2) */
+ unsigned veqvadjust:1; /* voffset has been adjusted for equivalence */
+
+/* The vardesc union below is used to store the number of an intrinsic
+ function (when vstg == STGINTR and vprocclass == PINTRINSIC), or to
+ store the index of this external symbol in extsymtab (when vstg ==
+ STGEXT and vprocclass == PEXTERNAL) */
+
+ union {
+ int varno; /* Return variable for a function.
+ This is used when a function is
+ assigned a return value. Also
+ used to point to the COMMON
+ block, when this is a field of
+ that block. Also points to
+ EQUIV block when STGEQUIV */
+ struct Intrpacked intrdesc; /* bits for intrinsic function*/
+ } vardesc;
+ struct Dimblock *vdim; /* points to the dimensions if they exist */
+ ftnint voffset; /* offset in a storage block (the variable
+ name will be "v.%d", voffset in a
+ common blck on the vax). Also holds
+ pointers for automatic variables. When
+ STGEQUIV, this is -(offset from array
+ base) */
+ union {
+ chainp namelist; /* points to names in the NAMELIST,
+ if this is a NAMELIST name */
+ chainp vstfdesc; /* points to (formals, expr) pair */
+ chainp assigned_values; /* list of integers, each being a
+ statement label assigned to
+ this variable in the current function */
+ } varxptr;
+ int argno; /* for multiple entries */
+ Argtypes *arginfo;
+ };
+
+
+/* PARAMETER statements */
+
+struct Paramblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg;
+ expptr vleng;
+ char *fvarname;
+ char *cvarname;
+ expptr paramval;
+ } ;
+
+
+/* Expression block */
+
+struct Exprblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg;
+ expptr vleng; /* in the case of a character expression, this
+ value is inherited from the children */
+ unsigned opcode;
+ expptr leftp;
+ expptr rightp;
+ int typefixed;
+ };
+
+
+union Constant
+ {
+ struct {
+ char *ccp0;
+ ftnint blanks;
+ } ccp1;
+ ftnint ci; /* Constant longeger */
+ double cd[2];
+ char *cds[2];
+ };
+#define ccp ccp1.ccp0
+
+struct Constblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg; /* vstg = 1 when using Const.cds */
+ expptr vleng;
+ union Constant Const;
+ };
+
+
+struct Listblock
+ {
+ field tag;
+ field vtype;
+ chainp listp;
+ };
+
+
+
+/* Address block - this is the FINAL form of identifiers before being
+ sent to pass 2. We'll want to add the original identifier here so that it can
+ be preserved in the translation.
+
+ An example identifier is q.7. The "q" refers to the storage class
+ (field vstg), the 7 to the variable number (int memno). */
+
+struct Addrblock
+ {
+ field tag;
+ field vtype;
+ field vclass;
+ field vstg;
+ expptr vleng;
+ /* put union...user here so the beginning of an Addrblock
+ * is the same as a Constblock.
+ */
+ union {
+ Namep name; /* contains a pointer into the hash table */
+ char ident[IDENT_LEN + 1]; /* C string form of identifier */
+ char *Charp;
+ union Constant Const; /* Constant value */
+ struct {
+ double dfill[2];
+ field vstg1;
+ } kludge; /* so we can distinguish string vs binary
+ * floating-point constants */
+ } user;
+ long memno; /* when vstg == STGCONST, this is the
+ numeric part of the assembler label
+ where the constant value is stored */
+ expptr memoffset; /* used in subscript computations, usually */
+ unsigned istemp:1; /* used in stack management of temporary
+ variables */
+ unsigned isarray:1; /* used to show that memoffset is
+ meaningful, even if zero */
+ unsigned ntempelt:10; /* for representing temporary arrays, as
+ in concatenation */
+ unsigned dbl_builtin:1; /* builtin to be declared double */
+ unsigned charleng:1; /* so saveargtypes can get i/o calls right */
+ unsigned cmplx_sub:1; /* used in complex arithmetic under -s */
+ unsigned skip_offset:1; /* used in complex arithmetic under -s */
+ unsigned parenused:1; /* distinguish (a) from a */
+ ftnint varleng; /* holds a copy of a constant length which
+ is stored in the vleng field (e.g.
+ a double is 8 bytes) */
+ int uname_tag; /* Tag describing which of the unions()
+ below to use */
+ char *Field; /* field name when dereferencing a struct */
+}; /* struct Addrblock */
+
+
+/* Errorbock - placeholder for errors, to allow the compilation to
+ continue */
+
+struct Errorblock
+ {
+ field tag;
+ field vtype;
+ };
+
+
+/* Implicit DO block, especially related to DATA statements. This block
+ keeps track of the compiler's location in the implicit DO while it's
+ running. In particular, the isactive and isbusy flags tell where
+ it is */
+
+struct Impldoblock
+ {
+ field tag;
+ unsigned isactive:1;
+ unsigned isbusy:1;
+ Namep varnp;
+ Constp varvp;
+ chainp impdospec;
+ expptr implb;
+ expptr impub;
+ expptr impstep;
+ ftnint impdiff;
+ ftnint implim;
+ struct Chain *datalist;
+ };
+
+
+/* Each of these components has a first field called tag. This union
+ exists just for allocation simplicity */
+
+union Expression
+ {
+ field tag;
+ struct Addrblock addrblock;
+ struct Constblock constblock;
+ struct Errorblock errorblock;
+ struct Exprblock exprblock;
+ struct Headblock headblock;
+ struct Impldoblock impldoblock;
+ struct Listblock listblock;
+ struct Nameblock nameblock;
+ struct Paramblock paramblock;
+ struct Primblock primblock;
+ } ;
+
+
+
+struct Dimblock
+ {
+ int ndim;
+ expptr nelt; /* This is NULL if the array is unbounded */
+ expptr baseoffset; /* a constant or local variable holding
+ the offset in this procedure */
+ expptr basexpr; /* expression for comuting the offset, if
+ it's not constant. If this is
+ non-null, the register named in
+ baseoffset will get initialized to this
+ value in the procedure's prolog */
+ struct
+ {
+ expptr dimsize; /* constant or register holding the size
+ of this dimension */
+ expptr dimexpr; /* as above in basexpr, this is an
+ expression for computing a variable
+ dimension */
+ } dims[1]; /* Dimblocks are allocated with enough
+ space for this to become dims[ndim] */
+ };
+
+
+/* Statement function identifier stack - this holds the name and value of
+ the parameters in a statement function invocation. For example,
+
+ f(x,y,z)=x+y+z
+ .
+ .
+ y = f(1,2,3)
+
+ generates a stack of depth 3, with <x 1>, <y 2>, <z 3> AT THE INVOCATION, NOT
+ at the definition */
+
+struct Rplblock /* name replacement block */
+ {
+ struct Rplblock *rplnextp;
+ Namep rplnp; /* Name of the formal parameter */
+ expptr rplvp; /* Value of the actual parameter */
+ expptr rplxp; /* Initialization of temporary variable,
+ if required; else null */
+ int rpltag; /* Tag on the value of the actual param */
+ };
+
+
+
+/* Equivalence block */
+
+struct Equivblock
+ {
+ struct Eqvchain *equivs; /* List (Eqvchain) of primblocks
+ holding variable identifiers */
+ flag eqvinit;
+ long eqvtop;
+ long eqvbottom;
+ int eqvtype;
+ } ;
+#define eqvleng eqvtop
+
+extern struct Equivblock *eqvclass;
+
+
+struct Eqvchain
+ {
+ struct Eqvchain *eqvnextp;
+ union
+ {
+ struct Primblock *eqvlhs;
+ Namep eqvname;
+ } eqvitem;
+ long eqvoffset;
+ } ;
+
+
+
+/* For allocation purposes only, and to keep lint quiet. In particular,
+ don't count on the tag being able to tell you which structure is used */
+
+
+/* There is a tradition in Fortran that the compiler not generate the same
+ bit pattern more than is necessary. This structure is used to do just
+ that; if two integer constants have the same bit pattern, just generate
+ it once. This could be expanded to optimize without regard to type, by
+ removing the type check in putconst() */
+
+struct Literal
+ {
+ short littype;
+ short lituse; /* usage count */
+ long litnum; /* numeric part of the assembler
+ label for this constant value */
+ union {
+ ftnint litival;
+ double litdval[2];
+ ftnint litival2[2]; /* length, nblanks for strings */
+ } litval;
+ char *cds[2];
+ };
+
+extern struct Literal *litpool;
+extern int maxliterals, nliterals;
+extern char Letters[];
+#define letter(x) Letters[x]
+
+struct Dims { expptr lb, ub; };
+
+extern int forcedouble; /* force real functions to double */
+extern int doin_setbound; /* special handling for array bounds */
+extern int Ansi;
+extern char hextoi_tab[];
+#define hextoi(x) hextoi_tab[(x) & 0xff]
+extern char *casttypes[], *ftn_types[], *protorettypes[], *usedcasts[];
+extern int Castargs, infertypes;
+extern FILE *protofile;
+extern char binread[], binwrite[], textread[], textwrite[];
+extern char *ei_first, *ei_last, *ei_next;
+extern char *wh_first, *wh_last, *wh_next;
+extern char *halign, *outbuf, *outbtail;
+extern flag keepsubs;
+#ifdef TYQUAD
+extern flag use_tyquad;
+#endif
+extern int n_keywords;
+extern char *c_keywords[];
+
+#ifdef KR_headers
+#define Argdcl(x) ()
+#define Void /* void */
+#else
+#define Argdcl(x) x
+#define Void void
+#endif
+
+char* Alloc Argdcl((int));
+char* Argtype Argdcl((int, char*));
+void Fatal Argdcl((char*));
+struct Impldoblock* mkiodo Argdcl((chainp, chainp));
+tagptr Inline Argdcl((int, int, chainp));
+struct Labelblock* execlab Argdcl((long));
+struct Labelblock* mklabel Argdcl((long));
+struct Listblock* mklist Argdcl((chainp));
+void Un_link_all Argdcl((int));
+void add_extern_to_list Argdcl((Addrp, chainp*));
+int addressable Argdcl((tagptr));
+tagptr addrof Argdcl((tagptr));
+char* addunder Argdcl((char*));
+Addrp autovar Argdcl((int, int, tagptr, char*));
+void backup Argdcl((char*, char*));
+void bad_atypes Argdcl((Argtypes*, char*, int, int, int, char*, char*));
+int badchleng Argdcl((tagptr));
+void badop Argdcl((char*, int));
+void badstg Argdcl((char*, int));
+void badtag Argdcl((char*, int));
+void badthing Argdcl((char*, char*, int));
+void badtype Argdcl((char*, int));
+Addrp builtin Argdcl((int, char*, int));
+char* c_name Argdcl((char*, int));
+tagptr call0 Argdcl((int, char*));
+tagptr call1 Argdcl((int, char*, tagptr));
+tagptr call2 Argdcl((int, char*, tagptr, tagptr));
+tagptr call3 Argdcl((int, char*, tagptr, tagptr, tagptr));
+tagptr call4 Argdcl((int, char*, tagptr, tagptr, tagptr, tagptr));
+tagptr callk Argdcl((int, char*, chainp));
+void cast_args Argdcl((int, chainp));
+char* cds Argdcl((char*, char*));
+void changedtype Argdcl((Namep));
+ptr ckalloc Argdcl((int));
+int cktype Argdcl((int, int, int));
+void clf Argdcl((FILEP*, char*, int));
+int cmpstr Argdcl((char*, char*, long, long));
+char* c_type_decl Argdcl((int, int));
+Extsym* comblock Argdcl((char*));
+char* comm_union_name Argdcl((int));
+void consconv Argdcl((int, Constp, Constp));
+void consnegop Argdcl((Constp));
+int conssgn Argdcl((tagptr));
+char* convic Argdcl((long));
+void copy_data Argdcl((chainp));
+char* copyn Argdcl((int, char*));
+char* copys Argdcl((char*));
+tagptr cpblock Argdcl((int, char*));
+tagptr cpexpr Argdcl((tagptr));
+void cpn Argdcl((int, char*, char*));
+char* cpstring Argdcl((char*));
+void dataline Argdcl((char*, long, int));
+char* dataname Argdcl((int, long));
+void dataval Argdcl((tagptr, tagptr));
+void dclerr Argdcl((char*, Namep));
+void def_commons Argdcl((FILEP));
+void def_start Argdcl((FILEP, char*, char*, char*));
+void deregister Argdcl((Namep));
+void do_uninit_equivs Argdcl((FILEP, ptr));
+void doequiv(Void);
+int dofork(Void);
+void doinclude Argdcl((char*));
+void doio Argdcl((chainp));
+void done Argdcl((int));
+void donmlist(Void);
+int dsort Argdcl((char*, char*));
+char* dtos Argdcl((double));
+void elif_out Argdcl((FILEP, tagptr));
+void end_else_out Argdcl((FILEP));
+void enddcl(Void);
+void enddo Argdcl((int));
+void endio(Void);
+void endioctl(Void);
+void endproc(Void);
+void entrypt Argdcl((int, int, long, Extsym*, chainp));
+int eqn Argdcl((int, char*, char*));
+char* equiv_name Argdcl((int, char*));
+void err Argdcl((char*));
+void err66 Argdcl((char*));
+void errext Argdcl((char*));
+void erri Argdcl((char*, int));
+void errl Argdcl((char*, long));
+tagptr errnode(Void);
+void errstr Argdcl((char*, char*));
+void exarif Argdcl((tagptr, struct Labelblock*, struct Labelblock*, struct Labelblock*));
+void exasgoto Argdcl((Namep));
+void exassign Argdcl((Namep, struct Labelblock*));
+void excall Argdcl((Namep, struct Listblock*, int, struct Labelblock**));
+void exdo Argdcl((int, Namep, chainp));
+void execerr Argdcl((char*, char*));
+void exelif Argdcl((tagptr));
+void exelse(Void);
+void exenddo Argdcl((Namep));
+void exendif(Void);
+void exequals Argdcl((struct Primblock*, tagptr));
+void exgoto Argdcl((struct Labelblock*));
+void exif Argdcl((tagptr));
+void exreturn Argdcl((tagptr));
+void exstop Argdcl((int, tagptr));
+void extern_out Argdcl((FILEP, Extsym*));
+void fatali Argdcl((char*, int));
+void fatalstr Argdcl((char*, char*));
+void ffilecopy Argdcl((FILEP, FILEP));
+void fileinit(Void);
+int fixargs Argdcl((int, struct Listblock*));
+tagptr fixexpr Argdcl((Exprp));
+tagptr fixtype Argdcl((tagptr));
+char* flconst Argdcl((char*, char*));
+void flline(Void);
+void fmt_init(Void);
+void fmtname Argdcl((Namep, Addrp));
+int fmtstmt Argdcl((struct Labelblock*));
+tagptr fold Argdcl((tagptr));
+void frchain Argdcl((chainp*));
+void frdata Argdcl((chainp));
+void freetemps(Void);
+void freqchain Argdcl((struct Equivblock*));
+void frexchain Argdcl((chainp*));
+void frexpr Argdcl((tagptr));
+void frrpl(Void);
+void frtemp Argdcl((Addrp));
+char* gmem Argdcl((int, int));
+void hashclear(Void);
+chainp hookup Argdcl((chainp, chainp));
+expptr imagpart Argdcl((Addrp));
+void impldcl Argdcl((Namep));
+int in_vector Argdcl((char*, char**, int));
+void incomm Argdcl((Extsym*, Namep));
+void inferdcl Argdcl((Namep, int));
+int inilex Argdcl((char*));
+void initkey(Void);
+int inregister Argdcl((Namep));
+long int commlen Argdcl((chainp));
+long int convci Argdcl((int, char*));
+long int iarrlen Argdcl((Namep));
+long int lencat Argdcl((expptr));
+long int lmax Argdcl((long, long));
+long int lmin Argdcl((long, long));
+long int wr_char_len Argdcl((FILEP, struct Dimblock*, int, int));
+Addrp intraddr Argdcl((Namep));
+tagptr intrcall Argdcl((Namep, struct Listblock*, int));
+int intrfunct Argdcl((char*));
+void ioclause Argdcl((int, expptr));
+int iocname(Void);
+int is_negatable Argdcl((Constp));
+int isaddr Argdcl((tagptr));
+int isnegative_const Argdcl((Constp));
+int isstatic Argdcl((tagptr));
+chainp length_comp Argdcl((struct Entrypoint*, int));
+int lengtype Argdcl((int, long));
+char* lexline Argdcl((ptr));
+void list_arg_types Argdcl((FILEP, struct Entrypoint*, chainp, int, char*));
+void list_decls Argdcl((FILEP));
+void list_init_data Argdcl((FILE **, char *, FILE *));
+void listargs Argdcl((FILEP, struct Entrypoint*, int, chainp));
+char* lit_name Argdcl((struct Literal*));
+int log_2 Argdcl((long));
+char* lower_string Argdcl((char*, char*));
+int main Argdcl((int, char**));
+expptr make_int_expr Argdcl((expptr));
+void make_param Argdcl((struct Paramblock*, tagptr));
+void many Argdcl((char*, char, int));
+void margin_printf Argdcl((FILEP, char*, ...));
+int maxtype Argdcl((int, int));
+char* mem Argdcl((int, int));
+void mem_init(Void);
+char* memname Argdcl((int, long));
+Addrp memversion Argdcl((Namep));
+tagptr mkaddcon Argdcl((long));
+Addrp mkaddr Argdcl((Namep));
+Addrp mkarg Argdcl((int, int));
+tagptr mkbitcon Argdcl((int, int, char*));
+chainp mkchain Argdcl((char*, chainp));
+Constp mkconst Argdcl((int));
+tagptr mkconv Argdcl((int, tagptr));
+tagptr mkcxcon Argdcl((tagptr, tagptr));
+tagptr mkexpr Argdcl((int, tagptr, tagptr));
+Extsym* mkext Argdcl((char*, char*));
+Extsym* mkext1 Argdcl((char*, char*));
+Addrp mkfield Argdcl((Addrp, char*, int));
+tagptr mkfunct Argdcl((tagptr));
+tagptr mkintcon Argdcl((long));
+tagptr mklhs Argdcl((struct Primblock*, int));
+tagptr mklogcon Argdcl((int));
+Namep mkname Argdcl((char*));
+Addrp mkplace Argdcl((Namep));
+tagptr mkprim Argdcl((Namep, struct Listblock*, chainp));
+tagptr mkrealcon Argdcl((int, char*));
+Addrp mkscalar Argdcl((Namep));
+void mkstfunct Argdcl((struct Primblock*, tagptr));
+tagptr mkstrcon Argdcl((int, char*));
+Addrp mktmp Argdcl((int, tagptr));
+Addrp mktmp0 Argdcl((int, tagptr));
+Addrp mktmpn Argdcl((int, int, tagptr));
+void namelist Argdcl((Namep));
+int ncat Argdcl((expptr));
+void negate_const Argdcl((Constp));
+void new_endif(Void);
+Extsym* newentry Argdcl((Namep, int));
+long newlabel(Void);
+void newproc(Void);
+Addrp nextdata Argdcl((long*));
+void nice_printf Argdcl((FILEP, char*, ...));
+void not_both Argdcl((char*));
+void np_init(Void);
+int oneof_stg Argdcl((Namep, int, int));
+int op_assign Argdcl((int));
+tagptr opconv Argdcl((tagptr, int));
+FILEP opf Argdcl((char*, char*));
+void out_addr Argdcl((FILEP, Addrp));
+void out_asgoto Argdcl((FILEP, tagptr));
+void out_call Argdcl((FILEP, int, int, tagptr, tagptr, tagptr));
+void out_const Argdcl((FILEP, Constp));
+void out_else Argdcl((FILEP));
+void out_for Argdcl((FILEP, tagptr, tagptr, tagptr));
+void out_init(Void);
+void outbuf_adjust(Void);
+void p1_label Argdcl((long));
+void prcona Argdcl((FILEP, long));
+void prconi Argdcl((FILEP, long));
+void prconr Argdcl((FILEP, Constp, int));
+void procinit(Void);
+void procode Argdcl((FILEP));
+void prolog Argdcl((FILEP, chainp));
+void protowrite Argdcl((FILEP, int, char*, struct Entrypoint*, chainp));
+expptr prune_left_conv Argdcl((expptr));
+int put_one_arg Argdcl((int, char*, char**, char*, char*));
+expptr putassign Argdcl((expptr, expptr));
+Addrp putchop Argdcl((tagptr));
+void putcmgo Argdcl((tagptr, int, struct Labelblock**));
+Addrp putconst Argdcl((Constp));
+tagptr putcxop Argdcl((tagptr));
+void puteq Argdcl((expptr, expptr));
+void putexpr Argdcl((expptr));
+void puthead Argdcl((char*, int));
+void putif Argdcl((tagptr, int));
+void putout Argdcl((tagptr));
+expptr putsteq Argdcl((Addrp, Addrp));
+void putwhile Argdcl((tagptr));
+tagptr putx Argdcl((tagptr));
+void r8fix(Void);
+int rdlong Argdcl((FILEP, long*));
+int rdname Argdcl((FILEP, ptr, char*));
+void read_Pfiles Argdcl((char**));
+Addrp realpart Argdcl((Addrp));
+chainp revchain Argdcl((chainp));
+int same_expr Argdcl((tagptr, tagptr));
+int same_ident Argdcl((tagptr, tagptr));
+void save_argtypes Argdcl((chainp, Argtypes**, Argtypes**, int, char*, int, int, int, int));
+void saveargtypes Argdcl((Exprp));
+void set_externs(Void);
+void set_tmp_names(Void);
+void setbound Argdcl((Namep, int, struct Dims*));
+void setdata Argdcl((Addrp, Constp, long));
+void setext Argdcl((Namep));
+void setfmt Argdcl((struct Labelblock*));
+void setimpl Argdcl((int, long, int, int));
+void setintr Argdcl((Namep));
+void settype Argdcl((Namep, int, long));
+void sigcatch Argdcl((int));
+void sserr Argdcl((Namep));
+void start_formatting(Void);
+void startioctl(Void);
+void startproc Argdcl((Extsym*, int));
+void startrw(Void);
+char* string_num Argdcl((char*, long));
+int struct_eq Argdcl((chainp, chainp));
+tagptr subcheck Argdcl((Namep, tagptr));
+tagptr suboffset Argdcl((struct Primblock*));
+int type_fixup Argdcl((Argtypes*, Atype*, int));
+void unamstring Argdcl((Addrp, char*));
+void unclassifiable(Void);
+void vardcl Argdcl((Namep));
+void warn Argdcl((char*));
+void warn1 Argdcl((char*, char*));
+void warni Argdcl((char*, int));
+void wr_abbrevs Argdcl((FILEP, int, chainp));
+char* wr_ardecls Argdcl((FILE*, struct Dimblock*, long));
+void wr_array_init Argdcl((FILEP, int, chainp));
+void wr_common_decls Argdcl((FILEP));
+void wr_equiv_init Argdcl((FILEP, int, chainp*, int));
+void wr_globals Argdcl((FILEP));
+void wr_nv_ident_help Argdcl((FILEP, Addrp));
+void wr_struct Argdcl((FILEP, chainp));
+void wronginf Argdcl((Namep));
+void yyerror Argdcl((char*));
+int yylex(Void);
+int yyparse(Void);
+
+#ifdef USE_DTOA
+#define atof(x) strtod(x,0)
+void g_fmt Argdcl((char*, double));
+#endif
diff --git a/usr.bin/f2c/equiv.c b/usr.bin/f2c/equiv.c
new file mode 100644
index 0000000..0b7c94c
--- /dev/null
+++ b/usr.bin/f2c/equiv.c
@@ -0,0 +1,413 @@
+/****************************************************************
+Copyright 1990, 1993-6 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+
+static void eqvcommon Argdcl((struct Equivblock*, int, long int));
+static void eqveqv Argdcl((int, int, long int));
+static int nsubs Argdcl((struct Listblock*));
+
+/* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */
+
+/* called at end of declarations section to process chains
+ created by EQUIVALENCE statements
+ */
+ void
+doequiv(Void)
+{
+ register int i;
+ int inequiv; /* True if one namep occurs in
+ several EQUIV declarations */
+ int comno; /* Index into Extsym table of the last
+ COMMON block seen (implicitly assuming
+ that only one will be given) */
+ int ovarno;
+ ftnint comoffset; /* Index into the COMMON block */
+ ftnint offset; /* Offset from array base */
+ ftnint leng;
+ register struct Equivblock *equivdecl;
+ register struct Eqvchain *q;
+ struct Primblock *primp;
+ register Namep np;
+ int k, k1, ns, pref, t;
+ chainp cp;
+ extern int type_pref[];
+ char *s;
+
+ for(i = 0 ; i < nequiv ; ++i)
+ {
+
+/* Handle each equivalence declaration */
+
+ equivdecl = &eqvclass[i];
+ equivdecl->eqvbottom = equivdecl->eqvtop = 0;
+ comno = -1;
+
+
+
+ for(q = equivdecl->equivs ; q ; q = q->eqvnextp)
+ {
+ offset = 0;
+ if (!(primp = q->eqvitem.eqvlhs))
+ continue;
+ vardcl(np = primp->namep);
+ if(primp->argsp || primp->fcharp)
+ {
+ expptr offp;
+
+/* Pad ones onto the end of an array declaration when needed */
+
+ if(np->vdim!=NULL && np->vdim->ndim>1 &&
+ nsubs(primp->argsp)==1 )
+ {
+ if(! ftn66flag)
+ warni
+ ("1-dim subscript in EQUIVALENCE, %d-dim declared",
+ np -> vdim -> ndim);
+ cp = NULL;
+ ns = np->vdim->ndim;
+ while(--ns > 0)
+ cp = mkchain((char *)ICON(1), cp);
+ primp->argsp->listp->nextp = cp;
+ }
+
+ offp = suboffset(primp);
+ if(ISICON(offp))
+ offset = offp->constblock.Const.ci;
+ else {
+ dclerr
+ ("nonconstant subscript in equivalence ",
+ np);
+ np = NULL;
+ }
+ frexpr(offp);
+ }
+
+/* Free up the primblock, since we now have a hash table (Namep) entry */
+
+ frexpr((expptr)primp);
+
+ if(np && (leng = iarrlen(np))<0)
+ {
+ dclerr("adjustable in equivalence", np);
+ np = NULL;
+ }
+
+ if(np) switch(np->vstg)
+ {
+ case STGUNKNOWN:
+ case STGBSS:
+ case STGEQUIV:
+ break;
+
+ case STGCOMMON:
+
+/* The code assumes that all COMMON references in a given EQUIVALENCE will
+ be to the same COMMON block, and will all be consistent */
+
+ comno = np->vardesc.varno;
+ comoffset = np->voffset + offset;
+ break;
+
+ default:
+ dclerr("bad storage class in equivalence", np);
+ np = NULL;
+ break;
+ }
+
+ if(np)
+ {
+ q->eqvoffset = offset;
+
+/* eqvbottom gets the largest difference between the array base address
+ and the address specified in the EQUIV declaration */
+
+ equivdecl->eqvbottom =
+ lmin(equivdecl->eqvbottom, -offset);
+
+/* eqvtop gets the largest difference between the end of the array and
+ the address given in the EQUIVALENCE */
+
+ equivdecl->eqvtop =
+ lmax(equivdecl->eqvtop, leng-offset);
+ }
+ q->eqvitem.eqvname = np;
+ }
+
+/* Now all equivalenced variables are in the hash table with the proper
+ offset, and eqvtop and eqvbottom are set. */
+
+ if(comno >= 0)
+
+/* Get rid of all STGEQUIVS, they will be mapped onto STGCOMMON variables
+ */
+
+ eqvcommon(equivdecl, comno, comoffset);
+ else for(q = equivdecl->equivs ; q ; q = q->eqvnextp)
+ {
+ if(np = q->eqvitem.eqvname)
+ {
+ inequiv = NO;
+ if(np->vstg==STGEQUIV)
+ if( (ovarno = np->vardesc.varno) == i)
+ {
+
+/* Can't EQUIV different elements of the same array */
+
+ if(np->voffset + q->eqvoffset != 0)
+ dclerr
+ ("inconsistent equivalence", np);
+ }
+ else {
+ offset = np->voffset;
+ inequiv = YES;
+ }
+
+ np->vstg = STGEQUIV;
+ np->vardesc.varno = i;
+ np->voffset = - q->eqvoffset;
+
+ if(inequiv)
+
+/* Combine 2 equivalence declarations */
+
+ eqveqv(i, ovarno, q->eqvoffset + offset);
+ }
+ }
+ }
+
+/* Now each equivalence declaration is distinct (all connections have been
+ merged in eqveqv()), and some may be empty. */
+
+ for(i = 0 ; i < nequiv ; ++i)
+ {
+ equivdecl = & eqvclass[i];
+ if(equivdecl->eqvbottom!=0 || equivdecl->eqvtop!=0) {
+
+/* a live chain */
+
+ k = TYCHAR;
+ pref = 1;
+ for(q = equivdecl->equivs ; q; q = q->eqvnextp)
+ if ((np = q->eqvitem.eqvname)
+ && !np->veqvadjust) {
+ np->veqvadjust = 1;
+ np->voffset -= equivdecl->eqvbottom;
+ t = typealign[k1 = np->vtype];
+ if (pref < type_pref[k1]) {
+ k = k1;
+ pref = type_pref[k1];
+ }
+ if(np->voffset % t != 0) {
+ dclerr("bad alignment forced by equivalence", np);
+ --nerr; /* don't give bad return code for this */
+ }
+ }
+ equivdecl->eqvtype = k;
+ }
+ freqchain(equivdecl);
+ }
+}
+
+
+
+
+
+/* put equivalence chain p at common block comno + comoffset */
+
+ LOCAL void
+#ifdef KR_headers
+eqvcommon(p, comno, comoffset)
+ struct Equivblock *p;
+ int comno;
+ ftnint comoffset;
+#else
+eqvcommon(struct Equivblock *p, int comno, ftnint comoffset)
+#endif
+{
+ int ovarno;
+ ftnint k, offq;
+ register Namep np;
+ register struct Eqvchain *q;
+
+ if(comoffset + p->eqvbottom < 0)
+ {
+ errstr("attempt to extend common %s backward",
+ extsymtab[comno].fextname);
+ freqchain(p);
+ return;
+ }
+
+ if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng)
+ extsymtab[comno].extleng = k;
+
+
+ for(q = p->equivs ; q ; q = q->eqvnextp)
+ if(np = q->eqvitem.eqvname)
+ {
+ switch(np->vstg)
+ {
+ case STGUNKNOWN:
+ case STGBSS:
+ np->vstg = STGCOMMON;
+ np->vcommequiv = 1;
+ np->vardesc.varno = comno;
+
+/* np -> voffset will point to the base of the array */
+
+ np->voffset = comoffset - q->eqvoffset;
+ break;
+
+ case STGEQUIV:
+ ovarno = np->vardesc.varno;
+
+/* offq will point to the current element, even if it's in an array */
+
+ offq = comoffset - q->eqvoffset - np->voffset;
+ np->vstg = STGCOMMON;
+ np->vcommequiv = 1;
+ np->vardesc.varno = comno;
+
+/* np -> voffset will point to the base of the array */
+
+ np->voffset += offq;
+ if(ovarno != (p - eqvclass))
+ eqvcommon(&eqvclass[ovarno], comno, offq);
+ break;
+
+ case STGCOMMON:
+ if(comno != np->vardesc.varno ||
+ comoffset != np->voffset+q->eqvoffset)
+ dclerr("inconsistent common usage", np);
+ break;
+
+
+ default:
+ badstg("eqvcommon", np->vstg);
+ }
+ }
+
+ freqchain(p);
+ p->eqvbottom = p->eqvtop = 0;
+}
+
+
+/* Move all items on ovarno chain to the front of nvarno chain.
+ * adjust offsets of ovarno elements and top and bottom of nvarno chain
+ */
+
+ LOCAL void
+#ifdef KR_headers
+eqveqv(nvarno, ovarno, delta)
+ int nvarno;
+ int ovarno;
+ ftnint delta;
+#else
+eqveqv(int nvarno, int ovarno, ftnint delta)
+#endif
+{
+ register struct Equivblock *neweqv, *oldeqv;
+ register Namep np;
+ struct Eqvchain *q, *q1;
+
+ neweqv = eqvclass + nvarno;
+ oldeqv = eqvclass + ovarno;
+ neweqv->eqvbottom = lmin(neweqv->eqvbottom, oldeqv->eqvbottom - delta);
+ neweqv->eqvtop = lmax(neweqv->eqvtop, oldeqv->eqvtop - delta);
+ oldeqv->eqvbottom = oldeqv->eqvtop = 0;
+
+ for(q = oldeqv->equivs ; q ; q = q1)
+ {
+ q1 = q->eqvnextp;
+ if( (np = q->eqvitem.eqvname) && np->vardesc.varno==ovarno)
+ {
+ q->eqvnextp = neweqv->equivs;
+ neweqv->equivs = q;
+ q->eqvoffset += delta;
+ np->vardesc.varno = nvarno;
+ np->voffset -= delta;
+ }
+ else free( (charptr) q);
+ }
+ oldeqv->equivs = NULL;
+}
+
+
+
+ void
+#ifdef KR_headers
+freqchain(p)
+ register struct Equivblock *p;
+#else
+freqchain(register struct Equivblock *p)
+#endif
+{
+ register struct Eqvchain *q, *oq;
+
+ for(q = p->equivs ; q ; q = oq)
+ {
+ oq = q->eqvnextp;
+ free( (charptr) q);
+ }
+ p->equivs = NULL;
+}
+
+
+
+
+
+/* nsubs -- number of subscripts in this arglist (just the length of the
+ list) */
+
+ LOCAL int
+#ifdef KR_headers
+nsubs(p)
+ register struct Listblock *p;
+#else
+nsubs(register struct Listblock *p)
+#endif
+{
+ register int n;
+ register chainp q;
+
+ n = 0;
+ if(p)
+ for(q = p->listp ; q ; q = q->nextp)
+ ++n;
+
+ return(n);
+}
+
+ struct Primblock *
+#ifdef KR_headers
+primchk(e) expptr e;
+#else
+primchk(expptr e)
+#endif
+{
+ if (e->headblock.tag != TPRIM) {
+ err("Invalid name in EQUIVALENCE.");
+ return 0;
+ }
+ return &e->primblock;
+ }
diff --git a/usr.bin/f2c/error.c b/usr.bin/f2c/error.c
new file mode 100644
index 0000000..0899d82
--- /dev/null
+++ b/usr.bin/f2c/error.c
@@ -0,0 +1,347 @@
+/****************************************************************
+Copyright 1990, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+
+ void
+#ifdef KR_headers
+warni(s, t)
+ char *s;
+ int t;
+#else
+warni(char *s, int t)
+#endif
+{
+ char buf[100];
+ sprintf(buf,s,t);
+ warn(buf);
+ }
+
+ void
+#ifdef KR_headers
+warn1(s, t)
+ char *s;
+ char *t;
+#else
+warn1(char *s, char *t)
+#endif
+{
+ char buff[100];
+ sprintf(buff, s, t);
+ warn(buff);
+}
+
+ void
+#ifdef KR_headers
+warn(s)
+ char *s;
+#else
+warn(char *s)
+#endif
+{
+ if(nowarnflag)
+ return;
+ if (infname && *infname)
+ fprintf(diagfile, "Warning on line %ld of %s: %s\n",
+ lineno, infname, s);
+ else
+ fprintf(diagfile, "Warning on line %ld: %s\n", lineno, s);
+ fflush(diagfile);
+ ++nwarn;
+}
+
+ void
+#ifdef KR_headers
+errstr(s, t)
+ char *s;
+ char *t;
+#else
+errstr(char *s, char *t)
+#endif
+{
+ char buff[100];
+ sprintf(buff, s, t);
+ err(buff);
+}
+
+
+ void
+#ifdef KR_headers
+erri(s, t)
+ char *s;
+ int t;
+#else
+erri(char *s, int t)
+#endif
+{
+ char buff[100];
+ sprintf(buff, s, t);
+ err(buff);
+}
+
+ void
+#ifdef KR_headers
+errl(s, t)
+ char *s;
+ long t;
+#else
+errl(char *s, long t)
+#endif
+{
+ char buff[100];
+ sprintf(buff, s, t);
+ err(buff);
+}
+
+ char *err_proc = 0;
+
+ void
+#ifdef KR_headers
+err(s)
+ char *s;
+#else
+err(char *s)
+#endif
+{
+ if (err_proc)
+ fprintf(diagfile,
+ "Error processing %s before line %ld",
+ err_proc, lineno);
+ else
+ fprintf(diagfile, "Error on line %ld", lineno);
+ if (infname && *infname)
+ fprintf(diagfile, " of %s", infname);
+ fprintf(diagfile, ": %s\n", s);
+ fflush(diagfile);
+ ++nerr;
+}
+
+ void
+#ifdef KR_headers
+yyerror(s)
+ char *s;
+#else
+yyerror(char *s)
+#endif
+{
+ err(s);
+}
+
+
+ void
+#ifdef KR_headers
+dclerr(s, v)
+ char *s;
+ Namep v;
+#else
+dclerr(char *s, Namep v)
+#endif
+{
+ char buff[100];
+
+ if(v)
+ {
+ sprintf(buff, "Declaration error for %s: %s", v->fvarname, s);
+ err(buff);
+ }
+ else
+ errstr("Declaration error %s", s);
+}
+
+
+ void
+#ifdef KR_headers
+execerr(s, n)
+ char *s;
+ char *n;
+#else
+execerr(char *s, char *n)
+#endif
+{
+ char buf1[100], buf2[100];
+
+ sprintf(buf1, "Execution error %s", s);
+ sprintf(buf2, buf1, n);
+ err(buf2);
+}
+
+
+ void
+#ifdef KR_headers
+Fatal(t)
+ char *t;
+#else
+Fatal(char *t)
+#endif
+{
+ fprintf(diagfile, "Compiler error line %ld", lineno);
+ if (infname)
+ fprintf(diagfile, " of %s", infname);
+ fprintf(diagfile, ": %s\n", t);
+ done(3);
+}
+
+
+
+ void
+#ifdef KR_headers
+fatalstr(t, s)
+ char *t;
+ char *s;
+#else
+fatalstr(char *t, char *s)
+#endif
+{
+ char buff[100];
+ sprintf(buff, t, s);
+ Fatal(buff);
+}
+
+
+ void
+#ifdef KR_headers
+fatali(t, d)
+ char *t;
+ int d;
+#else
+fatali(char *t, int d)
+#endif
+{
+ char buff[100];
+ sprintf(buff, t, d);
+ Fatal(buff);
+}
+
+
+ void
+#ifdef KR_headers
+badthing(thing, r, t)
+ char *thing;
+ char *r;
+ int t;
+#else
+badthing(char *thing, char *r, int t)
+#endif
+{
+ char buff[50];
+ sprintf(buff, "Impossible %s %d in routine %s", thing, t, r);
+ Fatal(buff);
+}
+
+
+ void
+#ifdef KR_headers
+badop(r, t)
+ char *r;
+ int t;
+#else
+badop(char *r, int t)
+#endif
+{
+ badthing("opcode", r, t);
+}
+
+
+ void
+#ifdef KR_headers
+badtag(r, t)
+ char *r;
+ int t;
+#else
+badtag(char *r, int t)
+#endif
+{
+ badthing("tag", r, t);
+}
+
+
+
+
+ void
+#ifdef KR_headers
+badstg(r, t)
+ char *r;
+ int t;
+#else
+badstg(char *r, int t)
+#endif
+{
+ badthing("storage class", r, t);
+}
+
+
+
+ void
+#ifdef KR_headers
+badtype(r, t)
+ char *r;
+ int t;
+#else
+badtype(char *r, int t)
+#endif
+{
+ badthing("type", r, t);
+}
+
+ void
+#ifdef KR_headers
+many(s, c, n)
+ char *s;
+ char c;
+ int n;
+#else
+many(char *s, char c, int n)
+#endif
+{
+ char buff[250];
+
+ sprintf(buff,
+ "Too many %s.\nTable limit now %d.\nTry rerunning with the -N%c%d option.\n",
+ s, n, c, 2*n);
+ Fatal(buff);
+}
+
+ void
+#ifdef KR_headers
+err66(s)
+ char *s;
+#else
+err66(char *s)
+#endif
+{
+ errstr("Fortran 77 feature used: %s", s);
+ --nerr;
+}
+
+
+ void
+#ifdef KR_headers
+errext(s)
+ char *s;
+#else
+errext(char *s)
+#endif
+{
+ errstr("f2c extension used: %s", s);
+ --nerr;
+}
diff --git a/usr.bin/f2c/exec.c b/usr.bin/f2c/exec.c
new file mode 100644
index 0000000..5e3d7b2
--- /dev/null
+++ b/usr.bin/f2c/exec.c
@@ -0,0 +1,934 @@
+/****************************************************************
+Copyright 1990, 1993 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "p1defs.h"
+#include "names.h"
+
+static void exar2 Argdcl((int, tagptr, struct Labelblock*, struct Labelblock*));
+static void popctl Argdcl((void));
+static void pushctl Argdcl((int));
+
+/* Logical IF codes
+*/
+
+ void
+#ifdef KR_headers
+exif(p)
+ expptr p;
+#else
+exif(expptr p)
+#endif
+{
+ pushctl(CTLIF);
+ putif(p, 0); /* 0 => if, not elseif */
+}
+
+
+ void
+#ifdef KR_headers
+exelif(p)
+ expptr p;
+#else
+exelif(expptr p)
+#endif
+{
+ if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
+ putif(p, 1); /* 1 ==> elseif */
+ else
+ execerr("elseif out of place", CNULL);
+}
+
+
+
+
+ void
+exelse(Void)
+{
+ register struct Ctlframe *c;
+
+ for(c = ctlstack; c->ctltype == CTLIFX; --c);
+ if(c->ctltype == CTLIF) {
+ p1_else ();
+ c->ctltype = CTLELSE;
+ }
+ else
+ execerr("else out of place", CNULL);
+ }
+
+ void
+#ifdef KR_headers
+exendif()
+#else
+exendif()
+#endif
+{
+ while(ctlstack->ctltype == CTLIFX) {
+ popctl();
+ p1else_end();
+ }
+ if(ctlstack->ctltype == CTLIF) {
+ popctl();
+ p1_endif ();
+ }
+ else if(ctlstack->ctltype == CTLELSE) {
+ popctl();
+ p1else_end ();
+ }
+ else
+ execerr("endif out of place", CNULL);
+ }
+
+
+ void
+#ifdef KR_headers
+new_endif()
+#else
+new_endif()
+#endif
+{
+ if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
+ pushctl(CTLIFX);
+ else
+ err("new_endif bug");
+ }
+
+/* pushctl -- Start a new control construct, initialize the labels (to
+ zero) */
+
+ LOCAL void
+#ifdef KR_headers
+pushctl(code)
+ int code;
+#else
+pushctl(int code)
+#endif
+{
+ register int i;
+
+ if(++ctlstack >= lastctl)
+ many("loops or if-then-elses", 'c', maxctl);
+ ctlstack->ctltype = code;
+ for(i = 0 ; i < 4 ; ++i)
+ ctlstack->ctlabels[i] = 0;
+ ctlstack->dowhile = 0;
+ ctlstack->domax = ctlstack->dostep = 0; /* in case of errors */
+ ++blklevel;
+}
+
+
+ LOCAL void
+popctl(Void)
+{
+ if( ctlstack-- < ctls )
+ Fatal("control stack empty");
+ --blklevel;
+}
+
+
+
+/* poplab -- update the flags in labeltab */
+
+ LOCAL void
+poplab(Void)
+{
+ register struct Labelblock *lp;
+
+ for(lp = labeltab ; lp < highlabtab ; ++lp)
+ if(lp->labdefined)
+ {
+ /* mark all labels in inner blocks unreachable */
+ if(lp->blklevel > blklevel)
+ lp->labinacc = YES;
+ }
+ else if(lp->blklevel > blklevel)
+ {
+ /* move all labels referred to in inner blocks out a level */
+ lp->blklevel = blklevel;
+ }
+}
+
+
+/* BRANCHING CODE
+*/
+ void
+#ifdef KR_headers
+exgoto(lab)
+ struct Labelblock *lab;
+#else
+exgoto(struct Labelblock *lab)
+#endif
+{
+ lab->labused = 1;
+ p1_goto (lab -> stateno);
+}
+
+
+
+
+
+
+ void
+#ifdef KR_headers
+exequals(lp, rp)
+ register struct Primblock *lp;
+ register expptr rp;
+#else
+exequals(register struct Primblock *lp, register expptr rp)
+#endif
+{
+ if(lp->tag != TPRIM)
+ {
+ err("assignment to a non-variable");
+ frexpr((expptr)lp);
+ frexpr(rp);
+ }
+ else if(lp->namep->vclass!=CLVAR && lp->argsp)
+ {
+ if(parstate >= INEXEC)
+ errstr("statement function %.62s amid executables.",
+ lp->namep->fvarname);
+ mkstfunct(lp, rp);
+ }
+ else if (lp->vtype == TYSUBR)
+ err("illegal use of subroutine name");
+ else
+ {
+ expptr new_lp, new_rp;
+
+ if(parstate < INDATA)
+ enddcl();
+ new_lp = mklhs (lp, keepsubs);
+ new_rp = fixtype (rp);
+ puteq(new_lp, new_rp);
+ }
+}
+
+
+
+/* Make Statement Function */
+
+long laststfcn = -1, thisstno;
+int doing_stmtfcn;
+
+ void
+#ifdef KR_headers
+mkstfunct(lp, rp)
+ struct Primblock *lp;
+ expptr rp;
+#else
+mkstfunct(struct Primblock *lp, expptr rp)
+#endif
+{
+ register struct Primblock *p;
+ register Namep np;
+ chainp args;
+
+ laststfcn = thisstno;
+ np = lp->namep;
+ if(np->vclass == CLUNKNOWN)
+ np->vclass = CLPROC;
+ else
+ {
+ dclerr("redeclaration of statement function", np);
+ return;
+ }
+ np->vprocclass = PSTFUNCT;
+ np->vstg = STGSTFUNCT;
+
+/* Set the type of the function */
+
+ impldcl(np);
+ if (np->vtype == TYCHAR && !np->vleng)
+ err("character statement function with length (*)");
+ args = (lp->argsp ? lp->argsp->listp : CHNULL);
+ np->varxptr.vstfdesc = mkchain((char *)args, (chainp)rp);
+
+ for(doing_stmtfcn = 1 ; args ; args = args->nextp)
+
+/* It is an error for the formal parameters to have arguments or
+ subscripts */
+
+ if( ((tagptr)(args->datap))->tag!=TPRIM ||
+ (p = (struct Primblock *)(args->datap) )->argsp ||
+ p->fcharp || p->lcharp ) {
+ err("non-variable argument in statement function definition");
+ args->datap = 0;
+ }
+ else
+ {
+
+/* Replace the name on the left-hand side */
+
+ args->datap = (char *)p->namep;
+ vardcl(p -> namep);
+ free((char *)p);
+ }
+ doing_stmtfcn = 0;
+}
+
+ static void
+#ifdef KR_headers
+mixed_type(np)
+ Namep np;
+#else
+mixed_type(Namep np)
+#endif
+{
+ char buf[128];
+ sprintf(buf, "%s function %.90s invoked as subroutine",
+ ftn_types[np->vtype], np->fvarname);
+ warn(buf);
+ }
+
+ void
+#ifdef KR_headers
+excall(name, args, nstars, labels)
+ Namep name;
+ struct Listblock *args;
+ int nstars;
+ struct Labelblock **labels;
+#else
+excall(Namep name, struct Listblock *args, int nstars, struct Labelblock **labels)
+#endif
+{
+ register expptr p;
+
+ if (name->vtype != TYSUBR) {
+ if (name->vinfproc && !name->vcalled) {
+ name->vtype = TYSUBR;
+ frexpr(name->vleng);
+ name->vleng = 0;
+ }
+ else if (!name->vimpltype && name->vtype != TYUNKNOWN)
+ mixed_type(name);
+ else
+ settype(name, TYSUBR, (ftnint)0);
+ }
+ p = mkfunct( mkprim(name, args, CHNULL) );
+ if (p->tag == TERROR)
+ return;
+
+/* Subroutines and their identifiers acquire the type INT */
+
+ p->exprblock.vtype = p->exprblock.leftp->headblock.vtype = TYINT;
+
+/* Handle the alternate return mechanism */
+
+ if(nstars > 0)
+ putcmgo(putx(fixtype(p)), nstars, labels);
+ else
+ putexpr(p);
+}
+
+
+ void
+#ifdef KR_headers
+exstop(stop, p)
+ int stop;
+ register expptr p;
+#else
+exstop(int stop, register expptr p)
+#endif
+{
+ char *str;
+ int n;
+
+ if(p)
+ {
+ if( ! ISCONST(p) )
+ {
+ execerr("pause/stop argument must be constant", CNULL);
+ frexpr(p);
+ p = mkstrcon(0, CNULL);
+ }
+ else if( ISINT(p->constblock.vtype) )
+ {
+ str = convic(p->constblock.Const.ci);
+ n = strlen(str);
+ if(n > 0)
+ {
+ p->constblock.Const.ccp = copyn(n, str);
+ p->constblock.Const.ccp1.blanks = 0;
+ p->constblock.vtype = TYCHAR;
+ p->constblock.vleng = (expptr) ICON(n);
+ }
+ else
+ p = (expptr) mkstrcon(0, CNULL);
+ }
+ else if(p->constblock.vtype != TYCHAR)
+ {
+ execerr("pause/stop argument must be integer or string", CNULL);
+ p = (expptr) mkstrcon(0, CNULL);
+ }
+ }
+ else p = (expptr) mkstrcon(0, CNULL);
+
+ {
+ expptr subr_call;
+
+ subr_call = call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p);
+ putexpr( subr_call );
+ }
+}
+
+/* DO LOOP CODE */
+
+#define DOINIT par[0]
+#define DOLIMIT par[1]
+#define DOINCR par[2]
+
+
+/* Macros for ctlstack -> dostepsign */
+
+#define VARSTEP 0
+#define POSSTEP 1
+#define NEGSTEP 2
+
+
+/* exdo -- generate DO loop code. In the case of a variable increment,
+ positive increment tests are placed above the body, negative increment
+ tests are placed below (see enddo() ) */
+
+ void
+#ifdef KR_headers
+exdo(range, loopname, spec)
+ int range;
+ Namep loopname;
+ chainp spec;
+#else
+exdo(int range, Namep loopname, chainp spec)
+#endif
+ /* range = end label */
+ /* input spec must have at least 2 exprs */
+{
+ register expptr p;
+ register Namep np;
+ chainp cp; /* loops over the fields in spec */
+ register int i;
+ int dotype; /* type of the index variable */
+ int incsign; /* sign of the increment, if it's constant
+ */
+ Addrp dovarp; /* loop index variable */
+ expptr doinit; /* constant or register for init param */
+ expptr par[3]; /* local specification parameters */
+
+ expptr init, test, inc; /* Expressions in the resulting FOR loop */
+
+
+ test = ENULL;
+
+ pushctl(CTLDO);
+ dorange = ctlstack->dolabel = range;
+ ctlstack->loopname = loopname;
+
+/* Declare the loop index */
+
+ np = (Namep)spec->datap;
+ ctlstack->donamep = NULL;
+ if (!np) { /* do while */
+ ctlstack->dowhile = 1;
+#if 0
+ if (loopname) {
+ if (loopname->vtype == TYUNKNOWN) {
+ loopname->vdcldone = 1;
+ loopname->vclass = CLLABEL;
+ loopname->vprocclass = PLABEL;
+ loopname->vtype = TYLABEL;
+ }
+ if (loopname->vtype == TYLABEL)
+ if (loopname->vdovar)
+ dclerr("already in use as a loop name",
+ loopname);
+ else
+ loopname->vdovar = 1;
+ else
+ dclerr("already declared; cannot be a loop name",
+ loopname);
+ }
+#endif
+ putwhile((expptr)spec->nextp);
+ NOEXT("do while");
+ spec->nextp = 0;
+ frchain(&spec);
+ return;
+ }
+ if(np->vdovar)
+ {
+ errstr("nested loops with variable %s", np->fvarname);
+ ctlstack->donamep = NULL;
+ return;
+ }
+
+/* Create a memory-resident version of the index variable */
+
+ dovarp = mkplace(np);
+ if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) )
+ {
+ err("bad type on do variable");
+ return;
+ }
+ ctlstack->donamep = np;
+
+ np->vdovar = YES;
+
+/* Now dovarp points to the index to be used within the loop, dostgp
+ points to the one which may need to be stored */
+
+ dotype = dovarp->vtype;
+
+/* Count the input specifications and type-check each one independently;
+ this just eliminates non-numeric values from the specification */
+
+ for(i=0 , cp = spec->nextp ; cp!=NULL && i<3 ; cp = cp->nextp)
+ {
+ p = par[i++] = fixtype((tagptr)cp->datap);
+ if( ! ONEOF(p->headblock.vtype, MSKINT|MSKREAL) )
+ {
+ err("bad type on DO parameter");
+ return;
+ }
+ }
+
+ frchain(&spec);
+ switch(i)
+ {
+ case 0:
+ case 1:
+ err("too few DO parameters");
+ return;
+
+ default:
+ err("too many DO parameters");
+ return;
+
+ case 2:
+ DOINCR = (expptr) ICON(1);
+
+ case 3:
+ break;
+ }
+
+
+/* Now all of the local specification fields are set, but their types are
+ not yet consistent */
+
+/* Declare the loop initialization value, casting it properly and declaring a
+ register if need be */
+
+ ctlstack->doinit = 0;
+ if (ISCONST (DOINIT) || !onetripflag)
+/* putx added 6-29-89 (mwm), not sure if fixtype is required, but I doubt it
+ since mkconv is called just before */
+ doinit = putx (mkconv (dotype, DOINIT));
+ else {
+ if (onetripflag)
+ ctlstack->doinit = doinit = (expptr) mktmp0(dotype, ENULL);
+ else
+ doinit = (expptr) mktmp(dotype, ENULL);
+ puteq (cpexpr (doinit), DOINIT);
+ } /* else */
+
+/* Declare the loop ending value, casting it to the type of the index
+ variable */
+
+ if( ISCONST(DOLIMIT) )
+ ctlstack->domax = mkconv(dotype, DOLIMIT);
+ else {
+ ctlstack->domax = (expptr) mktmp0(dotype, ENULL);
+ puteq (cpexpr (ctlstack -> domax), DOLIMIT);
+ } /* else */
+
+/* Declare the loop increment value, casting it to the type of the index
+ variable */
+
+ if( ISCONST(DOINCR) )
+ {
+ ctlstack->dostep = mkconv(dotype, DOINCR);
+ if( (incsign = conssgn(ctlstack->dostep)) == 0)
+ err("zero DO increment");
+ ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP);
+ }
+ else
+ {
+ ctlstack->dostep = (expptr) mktmp0(dotype, ENULL);
+ ctlstack->dostepsign = VARSTEP;
+ puteq (cpexpr (ctlstack -> dostep), DOINCR);
+ }
+
+/* All data is now properly typed and in the ctlstack, except for the
+ initial value. Assignments of temps have been generated already */
+
+ switch (ctlstack -> dostepsign) {
+ case VARSTEP:
+ test = mkexpr (OPQUEST, mkexpr (OPLT,
+ cpexpr (ctlstack -> dostep), ICON(0)),
+ mkexpr (OPCOLON,
+ mkexpr (OPGE, cpexpr((expptr)dovarp),
+ cpexpr (ctlstack -> domax)),
+ mkexpr (OPLE, cpexpr((expptr)dovarp),
+ cpexpr (ctlstack -> domax))));
+ break;
+ case POSSTEP:
+ test = mkexpr (OPLE, cpexpr((expptr)dovarp),
+ cpexpr (ctlstack -> domax));
+ break;
+ case NEGSTEP:
+ test = mkexpr (OPGE, cpexpr((expptr)dovarp),
+ cpexpr (ctlstack -> domax));
+ break;
+ default:
+ erri ("exdo: bad dostepsign '%d'", ctlstack -> dostepsign);
+ break;
+ } /* switch (ctlstack -> dostepsign) */
+
+ if (onetripflag)
+ test = mkexpr (OPOR, test,
+ mkexpr (OPEQ, cpexpr((expptr)dovarp), cpexpr (doinit)));
+ init = mkexpr (OPASSIGN, cpexpr((expptr)dovarp),
+ ctlstack->doinit ? cpexpr(doinit) : doinit);
+ inc = mkexpr (OPPLUSEQ, (expptr)dovarp, cpexpr (ctlstack -> dostep));
+
+ if (!onetripflag && ISCONST (ctlstack -> domax) && ISCONST (doinit)
+ && ctlstack -> dostepsign != VARSTEP) {
+ expptr tester;
+
+ tester = mkexpr (OPMINUS, cpexpr (doinit),
+ cpexpr (ctlstack -> domax));
+ if (incsign == conssgn (tester))
+ warn ("DO range never executed");
+ frexpr (tester);
+ } /* if !onetripflag && */
+
+ p1_for (init, test, inc);
+}
+
+ void
+#ifdef KR_headers
+exenddo(np)
+ Namep np;
+#else
+exenddo(Namep np)
+#endif
+{
+ Namep np1;
+ int here;
+ struct Ctlframe *cf;
+
+ if( ctlstack < ctls )
+ goto misplaced;
+ here = ctlstack->dolabel;
+ if (ctlstack->ctltype != CTLDO
+ || here >= 0 && (!thislabel || thislabel->labelno != here)) {
+ misplaced:
+ err("misplaced ENDDO");
+ return;
+ }
+ if (np != ctlstack->loopname) {
+ if (np1 = ctlstack->loopname)
+ errstr("expected \"enddo %s\"", np1->fvarname);
+ else
+ err("expected unnamed ENDDO");
+ for(cf = ctls; cf < ctlstack; cf++)
+ if (cf->ctltype == CTLDO && cf->loopname == np) {
+ here = cf->dolabel;
+ break;
+ }
+ }
+ enddo(here);
+ }
+
+ void
+#ifdef KR_headers
+enddo(here)
+ int here;
+#else
+enddo(int here)
+#endif
+{
+ register struct Ctlframe *q;
+ Namep np; /* name of the current DO index */
+ Addrp ap;
+ register int i;
+ register expptr e;
+
+/* Many DO's can end at the same statement, so keep looping over all
+ nested indicies */
+
+ while(here == dorange)
+ {
+ if(np = ctlstack->donamep)
+ {
+ p1for_end ();
+
+/* Now we're done with all of the tests, and the loop has terminated.
+ Store the index value back in long-term memory */
+
+ if(ap = memversion(np))
+ puteq((expptr)ap, (expptr)mkplace(np));
+ for(i = 0 ; i < 4 ; ++i)
+ ctlstack->ctlabels[i] = 0;
+ deregister(ctlstack->donamep);
+ ctlstack->donamep->vdovar = NO;
+ /* ctlstack->dostep and ctlstack->domax can be zero */
+ /* with sufficiently bizarre (erroneous) syntax */
+ if (e = ctlstack->dostep)
+ if (e->tag == TADDR && e->addrblock.istemp)
+ frtemp((Addrp)e);
+ else
+ frexpr(e);
+ if (e = ctlstack->domax)
+ if (e->tag == TADDR && e->addrblock.istemp)
+ frtemp((Addrp)e);
+ else
+ frexpr(e);
+ if (e = ctlstack->doinit)
+ frtemp((Addrp)e);
+ }
+ else if (ctlstack->dowhile)
+ p1for_end ();
+
+/* Set dorange to the closing label of the next most enclosing DO loop
+ */
+
+ popctl();
+ poplab();
+ dorange = 0;
+ for(q = ctlstack ; q>=ctls ; --q)
+ if(q->ctltype == CTLDO)
+ {
+ dorange = q->dolabel;
+ break;
+ }
+ }
+}
+
+ void
+#ifdef KR_headers
+exassign(vname, labelval)
+ register Namep vname;
+ struct Labelblock *labelval;
+#else
+exassign(register Namep vname, struct Labelblock *labelval)
+#endif
+{
+ Addrp p;
+ register Addrp q;
+ char *fs;
+ register chainp cp, cpprev;
+ register ftnint k, stno;
+
+ p = mkplace(vname);
+ if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) {
+ err("noninteger assign variable");
+ return;
+ }
+
+ /* If the label hasn't been defined, then we do things twice:
+ * once for an executable stmt label, once for a format
+ */
+
+ /* code for executable label... */
+
+/* Now store the assigned value in a list associated with this variable.
+ This will be used later to generate a switch() statement in the C output */
+
+ fs = labelval->fmtstring;
+ if (!labelval->labdefined || !fs) {
+
+ if (vname -> vis_assigned == 0) {
+ vname -> varxptr.assigned_values = CHNULL;
+ vname -> vis_assigned = 1;
+ }
+
+ /* don't duplicate labels... */
+
+ stno = labelval->stateno;
+ cpprev = 0;
+ for(k = 0, cp = vname->varxptr.assigned_values;
+ cp; cpprev = cp, cp = cp->nextp, k++)
+ if ((ftnint)cp->datap == stno)
+ break;
+ if (!cp) {
+ cp = mkchain((char *)stno, CHNULL);
+ if (cpprev)
+ cpprev->nextp = cp;
+ else
+ vname->varxptr.assigned_values = cp;
+ labelval->labused = 1;
+ }
+ putout(mkexpr(OPASSIGN, (expptr)p, mkintcon(k)));
+ }
+
+ /* Code for FORMAT label... */
+
+ if (!labelval->labdefined || fs) {
+
+ labelval->fmtlabused = 1;
+ p = ALLOC(Addrblock);
+ p->tag = TADDR;
+ p->vtype = TYCHAR;
+ p->vstg = STGAUTO;
+ p->memoffset = ICON(0);
+ fmtname(vname, p);
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ q->vtype = TYCHAR;
+ q->vstg = STGAUTO;
+ q->ntempelt = 1;
+ q->memoffset = ICON(0);
+ q->uname_tag = UNAM_IDENT;
+ sprintf(q->user.ident, "fmt_%ld", labelval->stateno);
+ putout(mkexpr(OPASSIGN, (expptr)p, (expptr)q));
+ }
+
+} /* exassign */
+
+
+ void
+#ifdef KR_headers
+exarif(expr, neglab, zerlab, poslab)
+ expptr expr;
+ struct Labelblock *neglab;
+ struct Labelblock *zerlab;
+ struct Labelblock *poslab;
+#else
+exarif(expptr expr, struct Labelblock *neglab, struct Labelblock *zerlab, struct Labelblock *poslab)
+#endif
+{
+ register int lm, lz, lp;
+
+ lm = neglab->stateno;
+ lz = zerlab->stateno;
+ lp = poslab->stateno;
+ expr = fixtype(expr);
+
+ if( ! ONEOF(expr->headblock.vtype, MSKINT|MSKREAL) )
+ {
+ err("invalid type of arithmetic if expression");
+ frexpr(expr);
+ }
+ else
+ {
+ if (lm == lz && lz == lp)
+ exgoto (neglab);
+ else if(lm == lz)
+ exar2(OPLE, expr, neglab, poslab);
+ else if(lm == lp)
+ exar2(OPNE, expr, neglab, zerlab);
+ else if(lz == lp)
+ exar2(OPGE, expr, zerlab, neglab);
+ else {
+ expptr t;
+
+ if (!addressable (expr)) {
+ t = (expptr) mktmp(expr -> headblock.vtype, ENULL);
+ expr = mkexpr (OPASSIGN, cpexpr (t), expr);
+ } else
+ t = (expptr) cpexpr (expr);
+
+ p1_if(putx(fixtype(mkexpr (OPLT, expr, ICON (0)))));
+ exgoto(neglab);
+ p1_elif (mkexpr (OPEQ, t, ICON (0)));
+ exgoto(zerlab);
+ p1_else ();
+ exgoto(poslab);
+ p1else_end ();
+ } /* else */
+ }
+}
+
+
+
+/* exar2 -- Do arithmetic IF for only 2 distinct labels; if !(e.op.0)
+ goto l2 else goto l1. If this seems backwards, that's because it is,
+ in order to make the 1 pass algorithm work. */
+
+ LOCAL void
+#ifdef KR_headers
+exar2(op, e, l1, l2)
+ int op;
+ expptr e;
+ struct Labelblock *l1;
+ struct Labelblock *l2;
+#else
+exar2(int op, expptr e, struct Labelblock *l1, struct Labelblock *l2)
+#endif
+{
+ expptr comp;
+
+ comp = mkexpr (op, e, ICON (0));
+ p1_if(putx(fixtype(comp)));
+ exgoto(l1);
+ p1_else ();
+ exgoto(l2);
+ p1else_end ();
+}
+
+
+/* exreturn -- return the value in p from a SUBROUTINE call -- used to
+ implement the alternate return mechanism */
+
+ void
+#ifdef KR_headers
+exreturn(p)
+ register expptr p;
+#else
+exreturn(register expptr p)
+#endif
+{
+ if(procclass != CLPROC)
+ warn("RETURN statement in main or block data");
+ if(p && (proctype!=TYSUBR || procclass!=CLPROC) )
+ {
+ err("alternate return in nonsubroutine");
+ p = 0;
+ }
+
+ if (p || proctype == TYSUBR) {
+ if (p == ENULL) p = ICON (0);
+ p = mkconv (TYLONG, fixtype (p));
+ p1_subr_ret (p);
+ } /* if p || proctype == TYSUBR */
+ else
+ p1_subr_ret((expptr)retslot);
+}
+
+
+ void
+#ifdef KR_headers
+exasgoto(labvar)
+ Namep labvar;
+#else
+exasgoto(Namep labvar)
+#endif
+{
+ register Addrp p;
+
+ p = mkplace(labvar);
+ if( ! ISINT(p->vtype) )
+ err("assigned goto variable must be integer");
+ else {
+ p1_asgoto (p);
+ } /* else */
+}
diff --git a/usr.bin/f2c/expr.c b/usr.bin/f2c/expr.c
new file mode 100644
index 0000000..59ea9b6
--- /dev/null
+++ b/usr.bin/f2c/expr.c
@@ -0,0 +1,3436 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "output.h"
+#include "names.h"
+
+typedef struct { double dreal, dimag; } dcomplex;
+
+static void consbinop Argdcl((int, int, Constp, Constp, Constp));
+static void conspower Argdcl((Constp, Constp, long int));
+static void zdiv Argdcl((dcomplex*, dcomplex*, dcomplex*));
+static tagptr mkpower Argdcl((tagptr));
+static tagptr stfcall Argdcl((Namep, struct Listblock*));
+
+extern char dflttype[26];
+extern int htype;
+
+/* little routines to create constant blocks */
+
+ Constp
+#ifdef KR_headers
+mkconst(t)
+ register int t;
+#else
+mkconst(register int t)
+#endif
+{
+ register Constp p;
+
+ p = ALLOC(Constblock);
+ p->tag = TCONST;
+ p->vtype = t;
+ return(p);
+}
+
+
+/* mklogcon -- Make Logical Constant */
+
+ expptr
+#ifdef KR_headers
+mklogcon(l)
+ register int l;
+#else
+mklogcon(register int l)
+#endif
+{
+ register Constp p;
+
+ p = mkconst(tylog);
+ p->Const.ci = l;
+ return( (expptr) p );
+}
+
+
+
+/* mkintcon -- Make Integer Constant */
+
+ expptr
+#ifdef KR_headers
+mkintcon(l)
+ ftnint l;
+#else
+mkintcon(ftnint l)
+#endif
+{
+ register Constp p;
+
+ p = mkconst(tyint);
+ p->Const.ci = l;
+ return( (expptr) p );
+}
+
+
+
+
+/* mkaddcon -- Make Address Constant, given integer value */
+
+ expptr
+#ifdef KR_headers
+mkaddcon(l)
+ register long l;
+#else
+mkaddcon(register long l)
+#endif
+{
+ register Constp p;
+
+ p = mkconst(TYADDR);
+ p->Const.ci = l;
+ return( (expptr) p );
+}
+
+
+
+/* mkrealcon -- Make Real Constant. The type t is assumed
+ to be TYREAL or TYDREAL */
+
+ expptr
+#ifdef KR_headers
+mkrealcon(t, d)
+ register int t;
+ char *d;
+#else
+mkrealcon(register int t, char *d)
+#endif
+{
+ register Constp p;
+
+ p = mkconst(t);
+ p->Const.cds[0] = cds(d,CNULL);
+ p->vstg = 1;
+ return( (expptr) p );
+}
+
+
+/* mkbitcon -- Make bit constant. Reads the input string, which is
+ assumed to correctly specify a number in base 2^shift (where shift
+ is the input parameter). shift may not exceed 4, i.e. only binary,
+ quad, octal and hex bases may be input. Constants may not exceed 32
+ bits, or whatever the size of (struct Constblock).ci may be. */
+
+ expptr
+#ifdef KR_headers
+mkbitcon(shift, leng, s)
+ int shift;
+ int leng;
+ char *s;
+#else
+mkbitcon(int shift, int leng, char *s)
+#endif
+{
+ register Constp p;
+ register long x, y, z;
+ int len;
+ char buff[100], *fmt, *s0 = s;
+ static char *kind[3] = { "Binary", "Hex", "Octal" };
+
+ p = mkconst(TYLONG);
+ x = y = 0;
+ while(--leng >= 0)
+ if(*s != ' ') {
+ z = x;
+ x = (x << shift) | hextoi(*s++);
+ y |= (((unsigned long)x) >> shift) - z;
+ }
+ /* Don't change the type to short for short constants, as
+ * that is dangerous -- there is no syntax for long constants
+ * with small values.
+ */
+ p->Const.ci = x;
+ if (y) {
+ if (--shift == 3)
+ shift = 1;
+ if ((len = (int)leng) > 60)
+ sprintf(buff, "%s constant '%.60s' truncated.",
+ kind[shift], s0);
+ else
+ sprintf(buff, "%s constant '%.*s' truncated.",
+ kind[shift], len, s0);
+ err(buff);
+ }
+ return( (expptr) p );
+}
+
+
+
+
+
+/* mkstrcon -- Make string constant. Allocates storage and initializes
+ the memory for a copy of the input Fortran-string. */
+
+ expptr
+#ifdef KR_headers
+mkstrcon(l, v)
+ int l;
+ register char *v;
+#else
+mkstrcon(int l, register char *v)
+#endif
+{
+ register Constp p;
+ register char *s;
+
+ p = mkconst(TYCHAR);
+ p->vleng = ICON(l);
+ p->Const.ccp = s = (char *) ckalloc(l+1);
+ p->Const.ccp1.blanks = 0;
+ while(--l >= 0)
+ *s++ = *v++;
+ *s = '\0';
+ return( (expptr) p );
+}
+
+
+
+/* mkcxcon -- Make complex contsant. A complex number is a pair of
+ values, each of which may be integer, real or double. */
+
+ expptr
+#ifdef KR_headers
+mkcxcon(realp, imagp)
+ register expptr realp;
+ register expptr imagp;
+#else
+mkcxcon(register expptr realp, register expptr imagp)
+#endif
+{
+ int rtype, itype;
+ register Constp p;
+
+ rtype = realp->headblock.vtype;
+ itype = imagp->headblock.vtype;
+
+ if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) )
+ {
+ p = mkconst( (rtype==TYDREAL||itype==TYDREAL)
+ ? TYDCOMPLEX : tycomplex);
+ if (realp->constblock.vstg || imagp->constblock.vstg) {
+ p->vstg = 1;
+ p->Const.cds[0] = ISINT(rtype)
+ ? string_num("", realp->constblock.Const.ci)
+ : realp->constblock.vstg
+ ? realp->constblock.Const.cds[0]
+ : dtos(realp->constblock.Const.cd[0]);
+ p->Const.cds[1] = ISINT(itype)
+ ? string_num("", imagp->constblock.Const.ci)
+ : imagp->constblock.vstg
+ ? imagp->constblock.Const.cds[0]
+ : dtos(imagp->constblock.Const.cd[0]);
+ }
+ else {
+ p->Const.cd[0] = ISINT(rtype)
+ ? realp->constblock.Const.ci
+ : realp->constblock.Const.cd[0];
+ p->Const.cd[1] = ISINT(itype)
+ ? imagp->constblock.Const.ci
+ : imagp->constblock.Const.cd[0];
+ }
+ }
+ else
+ {
+ err("invalid complex constant");
+ p = (Constp)errnode();
+ }
+
+ frexpr(realp);
+ frexpr(imagp);
+ return( (expptr) p );
+}
+
+
+/* errnode -- Allocate a new error block */
+
+ expptr
+errnode(Void)
+{
+ struct Errorblock *p;
+ p = ALLOC(Errorblock);
+ p->tag = TERROR;
+ p->vtype = TYERROR;
+ return( (expptr) p );
+}
+
+
+
+
+
+/* mkconv -- Make type conversion. Cast expression p into type t.
+ Note that casting to a character copies only the first sizeof(char)
+ bytes. */
+
+ expptr
+#ifdef KR_headers
+mkconv(t, p)
+ register int t;
+ register expptr p;
+#else
+mkconv(register int t, register expptr p)
+#endif
+{
+ register expptr q;
+ register int pt, charwarn = 1;
+
+ if (t >= 100) {
+ t -= 100;
+ charwarn = 0;
+ }
+ if(t==TYUNKNOWN || t==TYERROR)
+ badtype("mkconv", t);
+ pt = p->headblock.vtype;
+
+/* Casting to the same type is a no-op */
+
+ if(t == pt)
+ return(p);
+
+/* If we're casting a constant which is not in the literal table ... */
+
+ else if( ISCONST(p) && pt!=TYADDR && pt != TYCHAR
+ || p->tag == TADDR && p->addrblock.uname_tag == UNAM_CONST)
+ {
+ if (ISINT(t) && ISINT(pt) || ISREAL(t) && ISREAL(pt)) {
+ /* avoid trouble with -i2 */
+ p->headblock.vtype = t;
+ return p;
+ }
+ q = (expptr) mkconst(t);
+ consconv(t, &q->constblock, &p->constblock );
+ if (p->tag == TADDR)
+ q->constblock.vstg = p->addrblock.user.kludge.vstg1;
+ frexpr(p);
+ }
+ else {
+ if (pt == TYCHAR && t != TYADDR && charwarn
+ && (!halign || p->tag != TADDR
+ || p->addrblock.uname_tag != UNAM_CONST))
+ warn(
+ "ichar([first char. of] char. string) assumed for conversion to numeric");
+ q = opconv(p, t);
+ }
+
+ if(t == TYCHAR)
+ q->constblock.vleng = ICON(1);
+ return(q);
+}
+
+
+
+/* opconv -- Convert expression p to type t using the main
+ expression evaluator; returns an OPCONV expression, I think 14-jun-88 mwm */
+
+ expptr
+#ifdef KR_headers
+opconv(p, t)
+ expptr p;
+ int t;
+#else
+opconv(expptr p, int t)
+#endif
+{
+ register expptr q;
+
+ if (t == TYSUBR)
+ err("illegal use of subroutine name");
+ q = mkexpr(OPCONV, p, ENULL);
+ q->headblock.vtype = t;
+ return(q);
+}
+
+
+
+/* addrof -- Create an ADDR expression operation */
+
+ expptr
+#ifdef KR_headers
+addrof(p)
+ expptr p;
+#else
+addrof(expptr p)
+#endif
+{
+ return( mkexpr(OPADDR, p, ENULL) );
+}
+
+
+
+/* cpexpr - Returns a new copy of input expression p */
+
+ tagptr
+#ifdef KR_headers
+cpexpr(p)
+ register tagptr p;
+#else
+cpexpr(register tagptr p)
+#endif
+{
+ register tagptr e;
+ int tag;
+ register chainp ep, pp;
+
+/* This table depends on the ordering of the T macros, e.g. TNAME */
+
+ static int blksize[ ] =
+ {
+ 0,
+ sizeof(struct Nameblock),
+ sizeof(struct Constblock),
+ sizeof(struct Exprblock),
+ sizeof(struct Addrblock),
+ sizeof(struct Primblock),
+ sizeof(struct Listblock),
+ sizeof(struct Impldoblock),
+ sizeof(struct Errorblock)
+ };
+
+ if(p == NULL)
+ return(NULL);
+
+/* TNAMEs are special, and don't get copied. Each name in the current
+ symbol table has a unique TNAME structure. */
+
+ if( (tag = p->tag) == TNAME)
+ return(p);
+
+ e = cpblock(blksize[p->tag], (char *)p);
+
+ switch(tag)
+ {
+ case TCONST:
+ if(e->constblock.vtype == TYCHAR)
+ {
+ e->constblock.Const.ccp =
+ copyn((int)e->constblock.vleng->constblock.Const.ci+1,
+ e->constblock.Const.ccp);
+ e->constblock.vleng =
+ (expptr) cpexpr(e->constblock.vleng);
+ }
+ case TERROR:
+ break;
+
+ case TEXPR:
+ e->exprblock.leftp = (expptr) cpexpr(p->exprblock.leftp);
+ e->exprblock.rightp = (expptr) cpexpr(p->exprblock.rightp);
+ break;
+
+ case TLIST:
+ if(pp = p->listblock.listp)
+ {
+ ep = e->listblock.listp =
+ mkchain((char *)cpexpr((tagptr)pp->datap), CHNULL);
+ for(pp = pp->nextp ; pp ; pp = pp->nextp)
+ ep = ep->nextp =
+ mkchain((char *)cpexpr((tagptr)pp->datap),
+ CHNULL);
+ }
+ break;
+
+ case TADDR:
+ e->addrblock.vleng = (expptr) cpexpr(e->addrblock.vleng);
+ e->addrblock.memoffset = (expptr)cpexpr(e->addrblock.memoffset);
+ e->addrblock.istemp = NO;
+ break;
+
+ case TPRIM:
+ e->primblock.argsp = (struct Listblock *)
+ cpexpr((expptr)e->primblock.argsp);
+ e->primblock.fcharp = (expptr) cpexpr(e->primblock.fcharp);
+ e->primblock.lcharp = (expptr) cpexpr(e->primblock.lcharp);
+ break;
+
+ default:
+ badtag("cpexpr", tag);
+ }
+
+ return(e);
+}
+
+/* frexpr -- Free expression -- frees up memory used by expression p */
+
+ void
+#ifdef KR_headers
+frexpr(p)
+ register tagptr p;
+#else
+frexpr(register tagptr p)
+#endif
+{
+ register chainp q;
+
+ if(p == NULL)
+ return;
+
+ switch(p->tag)
+ {
+ case TCONST:
+ if( ISCHAR(p) )
+ {
+ free( (charptr) (p->constblock.Const.ccp) );
+ frexpr(p->constblock.vleng);
+ }
+ break;
+
+ case TADDR:
+ if (p->addrblock.vtype > TYERROR) /* i/o block */
+ break;
+ frexpr(p->addrblock.vleng);
+ frexpr(p->addrblock.memoffset);
+ break;
+
+ case TERROR:
+ break;
+
+/* TNAME blocks don't get free'd - probably because they're pointed to in
+ the hash table. 14-Jun-88 -- mwm */
+
+ case TNAME:
+ return;
+
+ case TPRIM:
+ frexpr((expptr)p->primblock.argsp);
+ frexpr(p->primblock.fcharp);
+ frexpr(p->primblock.lcharp);
+ break;
+
+ case TEXPR:
+ frexpr(p->exprblock.leftp);
+ if(p->exprblock.rightp)
+ frexpr(p->exprblock.rightp);
+ break;
+
+ case TLIST:
+ for(q = p->listblock.listp ; q ; q = q->nextp)
+ frexpr((tagptr)q->datap);
+ frchain( &(p->listblock.listp) );
+ break;
+
+ default:
+ badtag("frexpr", p->tag);
+ }
+
+ free( (charptr) p );
+}
+
+ void
+#ifdef KR_headers
+wronginf(np)
+ Namep np;
+#else
+wronginf(Namep np)
+#endif
+{
+ int c, k;
+ warn1("fixing wrong type inferred for %.65s", np->fvarname);
+ np->vinftype = 0;
+ c = letter(np->fvarname[0]);
+ if ((np->vtype = impltype[c]) == TYCHAR
+ && (k = implleng[c]))
+ np->vleng = ICON(k);
+ }
+
+/* fix up types in expression; replace subtrees and convert
+ names to address blocks */
+
+ expptr
+#ifdef KR_headers
+fixtype(p)
+ register tagptr p;
+#else
+fixtype(register tagptr p)
+#endif
+{
+
+ if(p == 0)
+ return(0);
+
+ switch(p->tag)
+ {
+ case TCONST:
+ if(ONEOF(p->constblock.vtype,MSKINT|MSKLOGICAL|MSKADDR|
+ MSKREAL) )
+ return( (expptr) p);
+
+ return( (expptr) putconst((Constp)p) );
+
+ case TADDR:
+ p->addrblock.memoffset = fixtype(p->addrblock.memoffset);
+ return( (expptr) p);
+
+ case TERROR:
+ return( (expptr) p);
+
+ default:
+ badtag("fixtype", p->tag);
+
+/* This case means that fixexpr can't call fixtype with any expr,
+ only a subexpr of its parameter. */
+
+ case TEXPR:
+ if (((Exprp)p)->typefixed)
+ return (expptr)p;
+ return( fixexpr((Exprp)p) );
+
+ case TLIST:
+ return( (expptr) p );
+
+ case TPRIM:
+ if(p->primblock.argsp && p->primblock.namep->vclass!=CLVAR)
+ {
+ if(p->primblock.namep->vtype == TYSUBR)
+ {
+ err("function invocation of subroutine");
+ return( errnode() );
+ }
+ else {
+ if (p->primblock.namep->vinftype)
+ wronginf(p->primblock.namep);
+ return( mkfunct(p) );
+ }
+ }
+
+/* The lack of args makes p a function name, substring reference
+ or variable name. */
+
+ else return mklhs((struct Primblock *) p, keepsubs);
+ }
+}
+
+
+ int
+#ifdef KR_headers
+badchleng(p)
+ register expptr p;
+#else
+badchleng(register expptr p)
+#endif
+{
+ if (!p->headblock.vleng) {
+ if (p->headblock.tag == TADDR
+ && p->addrblock.uname_tag == UNAM_NAME)
+ errstr("bad use of character*(*) variable %.60s",
+ p->addrblock.user.name->fvarname);
+ else
+ err("Bad use of character*(*)");
+ return 1;
+ }
+ return 0;
+ }
+
+
+ static expptr
+#ifdef KR_headers
+cplenexpr(p)
+ expptr p;
+#else
+cplenexpr(expptr p)
+#endif
+{
+ expptr rv;
+
+ if (badchleng(p))
+ return ICON(1);
+ rv = cpexpr(p->headblock.vleng);
+ if (ISCONST(p) && p->constblock.vtype == TYCHAR)
+ rv->constblock.Const.ci += p->constblock.Const.ccp1.blanks;
+ return rv;
+ }
+
+
+/* special case tree transformations and cleanups of expression trees.
+ Parameter p should have a TEXPR tag at its root, else an error is
+ returned */
+
+ expptr
+#ifdef KR_headers
+fixexpr(p)
+ register Exprp p;
+#else
+fixexpr(register Exprp p)
+#endif
+{
+ expptr lp;
+ register expptr rp;
+ register expptr q;
+ char *hsave;
+ int opcode, ltype, rtype, ptype, mtype;
+
+ if( ISERROR(p) || p->typefixed )
+ return( (expptr) p );
+ else if(p->tag != TEXPR)
+ badtag("fixexpr", p->tag);
+ opcode = p->opcode;
+
+/* First set the types of the left and right subexpressions */
+
+ lp = p->leftp;
+ if (!ISCONST(lp) || lp->constblock.vtype != TYCHAR)
+ lp = p->leftp = fixtype(lp);
+ ltype = lp->headblock.vtype;
+
+ if(opcode==OPASSIGN && lp->tag!=TADDR)
+ {
+ err("left side of assignment must be variable");
+ eret:
+ frexpr((expptr)p);
+ return( errnode() );
+ }
+
+ if(rp = p->rightp)
+ {
+ if (!ISCONST(rp) || rp->constblock.vtype != TYCHAR)
+ rp = p->rightp = fixtype(rp);
+ rtype = rp->headblock.vtype;
+ }
+ else
+ rtype = 0;
+
+ if(ltype==TYERROR || rtype==TYERROR)
+ goto eret;
+
+/* Now work on the whole expression */
+
+ /* force folding if possible */
+
+ if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) )
+ {
+ q = opcode == OPCONV && lp->constblock.vtype == p->vtype
+ ? lp : mkexpr(opcode, lp, rp);
+
+/* mkexpr is expected to reduce constant expressions */
+
+ if( ISCONST(q) ) {
+ p->leftp = p->rightp = 0;
+ frexpr((expptr)p);
+ return(q);
+ }
+ free( (charptr) q ); /* constants did not fold */
+ }
+
+ if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR)
+ goto eret;
+
+ if (ltype == TYCHAR && ISCONST(lp)) {
+ if (opcode == OPCONV) {
+ hsave = halign;
+ halign = 0;
+ lp = (expptr)putconst((Constp)lp);
+ halign = hsave;
+ }
+ else
+ lp = (expptr)putconst((Constp)lp);
+ p->leftp = lp;
+ }
+ if (rtype == TYCHAR && ISCONST(rp))
+ p->rightp = rp = (expptr)putconst((Constp)rp);
+
+ switch(opcode)
+ {
+ case OPCONCAT:
+ if(p->vleng == NULL)
+ p->vleng = mkexpr(OPPLUS, cplenexpr(lp),
+ cplenexpr(rp) );
+ break;
+
+ case OPASSIGN:
+ if (rtype == TYREAL || ISLOGICAL(ptype)
+ || rtype == TYDREAL && ltype == TYREAL && !ISCONST(rp))
+ break;
+ case OPPLUSEQ:
+ case OPSTAREQ:
+ if(ltype == rtype)
+ break;
+ if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) )
+ break;
+ if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) )
+ break;
+ if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT)
+ && typesize[ltype]>=typesize[rtype] )
+ break;
+
+/* Cast the right hand side to match the type of the expression */
+
+ p->rightp = fixtype( mkconv(ptype, rp) );
+ break;
+
+ case OPSLASH:
+ if( ISCOMPLEX(rtype) )
+ {
+ p = (Exprp) call2(ptype,
+
+/* Handle double precision complex variables */
+
+ ptype == TYCOMPLEX ? "c_div" : "z_div",
+ mkconv(ptype, lp), mkconv(ptype, rp) );
+ break;
+ }
+ case OPPLUS:
+ case OPMINUS:
+ case OPSTAR:
+ case OPMOD:
+ if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) ||
+ (rtype==TYREAL && ! ISCONST(rp) ) ))
+ break;
+ if( ISCOMPLEX(ptype) )
+ break;
+
+/* Cast both sides of the expression to match the type of the whole
+ expression. */
+
+ if(ltype != ptype && (ltype < TYINT1 || ptype > TYDREAL))
+ p->leftp = fixtype(mkconv(ptype,lp));
+ if(rtype != ptype && (rtype < TYINT1 || ptype > TYDREAL))
+ p->rightp = fixtype(mkconv(ptype,rp));
+ break;
+
+ case OPPOWER:
+ rp = mkpower((expptr)p);
+ if (rp->tag == TEXPR)
+ rp->exprblock.typefixed = 1;
+ return rp;
+
+ case OPLT:
+ case OPLE:
+ case OPGT:
+ case OPGE:
+ case OPEQ:
+ case OPNE:
+ if(ltype == rtype)
+ break;
+ if (htype) {
+ if (ltype == TYCHAR) {
+ p->leftp = fixtype(mkconv(rtype,lp));
+ break;
+ }
+ if (rtype == TYCHAR) {
+ p->rightp = fixtype(mkconv(ltype,rp));
+ break;
+ }
+ }
+ mtype = cktype(OPMINUS, ltype, rtype);
+ if(mtype==TYDREAL && (ltype==TYREAL || rtype==TYREAL))
+ break;
+ if( ISCOMPLEX(mtype) )
+ break;
+ if(ltype != mtype)
+ p->leftp = fixtype(mkconv(mtype,lp));
+ if(rtype != mtype)
+ p->rightp = fixtype(mkconv(mtype,rp));
+ break;
+
+ case OPCONV:
+ ptype = cktype(OPCONV, p->vtype, ltype);
+ if(lp->tag==TEXPR && lp->exprblock.opcode==OPCOMMA
+ && !ISCOMPLEX(ptype))
+ {
+ lp->exprblock.rightp =
+ fixtype( mkconv(ptype, lp->exprblock.rightp) );
+ free( (charptr) p );
+ p = (Exprp) lp;
+ }
+ break;
+
+ case OPADDR:
+ if(lp->tag==TEXPR && lp->exprblock.opcode==OPADDR)
+ Fatal("addr of addr");
+ break;
+
+ case OPCOMMA:
+ case OPQUEST:
+ case OPCOLON:
+ break;
+
+ case OPMIN:
+ case OPMAX:
+ case OPMIN2:
+ case OPMAX2:
+ case OPDMIN:
+ case OPDMAX:
+ case OPABS:
+ case OPDABS:
+ ptype = p->vtype;
+ break;
+
+ default:
+ break;
+ }
+
+ p->vtype = ptype;
+ p->typefixed = 1;
+ return((expptr) p);
+}
+
+
+/* fix an argument list, taking due care for special first level cases */
+
+ int
+#ifdef KR_headers
+fixargs(doput, p0)
+ int doput;
+ struct Listblock *p0;
+#else
+fixargs(int doput, struct Listblock *p0)
+#endif
+ /* doput is true if constants need to be passed by reference */
+{
+ register chainp p;
+ register tagptr q, t;
+ register int qtag;
+ int nargs;
+
+ nargs = 0;
+ if(p0)
+ for(p = p0->listp ; p ; p = p->nextp)
+ {
+ ++nargs;
+ q = (tagptr)p->datap;
+ qtag = q->tag;
+ if(qtag == TCONST)
+ {
+
+/* Call putconst() to store values in a constant table. Since even
+ constants must be passed by reference, this can optimize on the storage
+ required */
+
+ p->datap = doput ? (char *)putconst((Constp)q)
+ : (char *)q;
+ continue;
+ }
+
+/* Take a function name and turn it into an Addr. This only happens when
+ nothing else has figured out the function beforehand */
+
+ if (qtag == TPRIM && q->primblock.argsp == 0) {
+ if (q->primblock.namep->vclass==CLPROC
+ && q->primblock.namep->vprocclass != PTHISPROC) {
+ p->datap = (char *)mkaddr(q->primblock.namep);
+ continue;
+ }
+
+ if (q->primblock.namep->vdim != NULL) {
+ p->datap = (char *)mkscalar(q->primblock.namep);
+ if ((q->primblock.fcharp||q->primblock.lcharp)
+ && (q->primblock.namep->vtype != TYCHAR
+ || q->primblock.namep->vdim))
+ sserr(q->primblock.namep);
+ continue;
+ }
+
+ if (q->primblock.namep->vdovar
+ && (t = (tagptr) memversion(q->primblock.namep))) {
+ p->datap = (char *)fixtype(t);
+ continue;
+ }
+ }
+ p->datap = (char *)fixtype(q);
+ }
+ return(nargs);
+}
+
+
+
+/* mkscalar -- only called by fixargs above, and by some routines in
+ io.c */
+
+ Addrp
+#ifdef KR_headers
+mkscalar(np)
+ register Namep np;
+#else
+mkscalar(register Namep np)
+#endif
+{
+ register Addrp ap;
+
+ vardcl(np);
+ ap = mkaddr(np);
+
+ /* The prolog causes array arguments to point to the
+ * (0,...,0) element, unless subscript checking is on.
+ */
+ if( !checksubs && np->vstg==STGARG)
+ {
+ register struct Dimblock *dp;
+ dp = np->vdim;
+ frexpr(ap->memoffset);
+ ap->memoffset = mkexpr(OPSTAR,
+ (np->vtype==TYCHAR ?
+ cpexpr(np->vleng) :
+ (tagptr)ICON(typesize[np->vtype]) ),
+ cpexpr(dp->baseoffset) );
+ }
+ return(ap);
+}
+
+
+ static void
+#ifdef KR_headers
+adjust_arginfo(np)
+ register Namep np;
+#else
+adjust_arginfo(register Namep np)
+#endif
+ /* adjust arginfo to omit the length arg for the
+ arg that we now know to be a character-valued
+ function */
+{
+ struct Entrypoint *ep;
+ register chainp args;
+ Argtypes *at;
+
+ for(ep = entries; ep; ep = ep->entnextp)
+ for(args = ep->arglist; args; args = args->nextp)
+ if (np == (Namep)args->datap
+ && (at = ep->entryname->arginfo))
+ --at->nargs;
+ }
+
+
+ expptr
+#ifdef KR_headers
+mkfunct(p0)
+ expptr p0;
+#else
+mkfunct(expptr p0)
+#endif
+{
+ register struct Primblock *p = (struct Primblock *)p0;
+ struct Entrypoint *ep;
+ Addrp ap;
+ Extsym *extp;
+ register Namep np;
+ register expptr q;
+ extern chainp new_procs;
+ int k, nargs;
+ int class;
+
+ if(p->tag != TPRIM)
+ return( errnode() );
+
+ np = p->namep;
+ class = np->vclass;
+
+
+ if(class == CLUNKNOWN)
+ {
+ np->vclass = class = CLPROC;
+ if(np->vstg == STGUNKNOWN)
+ {
+ if(np->vtype!=TYSUBR && (k = intrfunct(np->fvarname))
+ && (zflag || !(*(struct Intrpacked *)&k).f4
+ || dcomplex_seen))
+ {
+ np->vstg = STGINTR;
+ np->vardesc.varno = k;
+ np->vprocclass = PINTRINSIC;
+ }
+ else
+ {
+ extp = mkext(np->fvarname,
+ addunder(np->cvarname));
+ extp->extstg = STGEXT;
+ np->vstg = STGEXT;
+ np->vardesc.varno = extp - extsymtab;
+ np->vprocclass = PEXTERNAL;
+ }
+ }
+ else if(np->vstg==STGARG)
+ {
+ if(np->vtype == TYCHAR) {
+ adjust_arginfo(np);
+ if (np->vpassed) {
+ char wbuf[160], *who;
+ who = np->fvarname;
+ sprintf(wbuf, "%s%s%s\n\t%s%s%s",
+ "Character-valued dummy procedure ",
+ who, " not declared EXTERNAL.",
+ "Code may be wrong for previous function calls having ",
+ who, " as a parameter.");
+ warn(wbuf);
+ }
+ }
+ np->vprocclass = PEXTERNAL;
+ }
+ }
+
+ if(class != CLPROC) {
+ if (np->vstg == STGCOMMON)
+ fatalstr(
+ "Cannot invoke common variable %.50s as a function.",
+ np->fvarname);
+ errstr("%.80s cannot be called.", np->fvarname);
+ goto error;
+ }
+
+/* F77 doesn't allow subscripting of function calls */
+
+ if(p->fcharp || p->lcharp)
+ {
+ err("no substring of function call");
+ goto error;
+ }
+ impldcl(np);
+ np->vimpltype = 0; /* invoking as function ==> inferred type */
+ np->vcalled = 1;
+ nargs = fixargs( np->vprocclass!=PINTRINSIC, p->argsp);
+
+ switch(np->vprocclass)
+ {
+ case PEXTERNAL:
+ if(np->vtype == TYUNKNOWN)
+ {
+ dclerr("attempt to use untyped function", np);
+ np->vtype = dflttype[letter(np->fvarname[0])];
+ }
+ ap = mkaddr(np);
+ if (!extsymtab[np->vardesc.varno].extseen) {
+ new_procs = mkchain((char *)np, new_procs);
+ extsymtab[np->vardesc.varno].extseen = 1;
+ }
+call:
+ q = mkexpr(OPCALL, (expptr)ap, (expptr)p->argsp);
+ q->exprblock.vtype = np->vtype;
+ if(np->vleng)
+ q->exprblock.vleng = (expptr) cpexpr(np->vleng);
+ break;
+
+ case PINTRINSIC:
+ q = intrcall(np, p->argsp, nargs);
+ break;
+
+ case PSTFUNCT:
+ q = stfcall(np, p->argsp);
+ break;
+
+ case PTHISPROC:
+ warn("recursive call");
+
+/* entries is the list of multiple entry points */
+
+ for(ep = entries ; ep ; ep = ep->entnextp)
+ if(ep->enamep == np)
+ break;
+ if(ep == NULL)
+ Fatal("mkfunct: impossible recursion");
+
+ ap = builtin(np->vtype, ep->entryname->cextname, -2);
+ /* the negative last arg prevents adding */
+ /* this name to the list of used builtins */
+ goto call;
+
+ default:
+ fatali("mkfunct: impossible vprocclass %d",
+ (int) (np->vprocclass) );
+ }
+ free( (charptr) p );
+ return(q);
+
+error:
+ frexpr((expptr)p);
+ return( errnode() );
+}
+
+
+
+ static expptr
+#ifdef KR_headers
+stfcall(np, actlist)
+ Namep np;
+ struct Listblock *actlist;
+#else
+stfcall(Namep np, struct Listblock *actlist)
+#endif
+{
+ register chainp actuals;
+ int nargs;
+ chainp oactp, formals;
+ int type;
+ expptr Ln, Lq, q, q1, rhs, ap;
+ Namep tnp;
+ register struct Rplblock *rp;
+ struct Rplblock *tlist;
+
+ if (np->arginfo) {
+ errstr("statement function %.66s calls itself.",
+ np->fvarname);
+ return ICON(0);
+ }
+ np->arginfo = (Argtypes *)np; /* arbitrary nonzero value */
+ if(actlist)
+ {
+ actuals = actlist->listp;
+ free( (charptr) actlist);
+ }
+ else
+ actuals = NULL;
+ oactp = actuals;
+
+ nargs = 0;
+ tlist = NULL;
+ if( (type = np->vtype) == TYUNKNOWN)
+ {
+ dclerr("attempt to use untyped statement function", np);
+ type = np->vtype = dflttype[letter(np->fvarname[0])];
+ }
+ formals = (chainp) np->varxptr.vstfdesc->datap;
+ rhs = (expptr) (np->varxptr.vstfdesc->nextp);
+
+ /* copy actual arguments into temporaries */
+ while(actuals!=NULL && formals!=NULL)
+ {
+ if (!(tnp = (Namep) formals->datap)) {
+ /* buggy statement function declaration */
+ q = ICON(1);
+ goto done;
+ }
+ rp = ALLOC(Rplblock);
+ rp->rplnp = tnp;
+ ap = fixtype((tagptr)actuals->datap);
+ if(tnp->vtype==ap->headblock.vtype && tnp->vtype!=TYCHAR
+ && (ap->tag==TCONST || ap->tag==TADDR) )
+ {
+
+/* If actuals are constants or variable names, no temporaries are required */
+ rp->rplvp = (expptr) ap;
+ rp->rplxp = NULL;
+ rp->rpltag = ap->tag;
+ }
+ else {
+ rp->rplvp = (expptr) mktmp(tnp->vtype, tnp->vleng);
+ rp -> rplxp = NULL;
+ putexpr ( mkexpr(OPASSIGN, cpexpr(rp->rplvp), ap));
+ if((rp->rpltag = rp->rplvp->tag) == TERROR)
+ err("disagreement of argument types in statement function call");
+ }
+ rp->rplnextp = tlist;
+ tlist = rp;
+ actuals = actuals->nextp;
+ formals = formals->nextp;
+ ++nargs;
+ }
+
+ if(actuals!=NULL || formals!=NULL)
+ err("statement function definition and argument list differ");
+
+ /*
+ now push down names involved in formal argument list, then
+ evaluate rhs of statement function definition in this environment
+*/
+
+ if(tlist) /* put tlist in front of the rpllist */
+ {
+ for(rp = tlist; rp->rplnextp; rp = rp->rplnextp)
+ ;
+ rp->rplnextp = rpllist;
+ rpllist = tlist;
+ }
+
+/* So when the expression finally gets evaled, that evaluator must read
+ from the globl rpllist 14-jun-88 mwm */
+
+ q = (expptr) mkconv(type, fixtype(cpexpr(rhs)) );
+
+ /* get length right of character-valued statement functions... */
+ if (type == TYCHAR
+ && (Ln = np->vleng)
+ && q->tag != TERROR
+ && (Lq = q->exprblock.vleng)
+ && (Lq->tag != TCONST
+ || Ln->constblock.Const.ci != Lq->constblock.Const.ci)) {
+ q1 = (expptr) mktmp(type, Ln);
+ putexpr ( mkexpr(OPASSIGN, cpexpr(q1), q));
+ q = q1;
+ }
+
+ /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */
+ while(--nargs >= 0)
+ {
+ if(rpllist->rplxp)
+ q = mkexpr(OPCOMMA, rpllist->rplxp, q);
+ rp = rpllist->rplnextp;
+ frexpr(rpllist->rplvp);
+ free((char *)rpllist);
+ rpllist = rp;
+ }
+ done:
+ frchain( &oactp );
+ np->arginfo = 0;
+ return(q);
+}
+
+
+static int replaced;
+
+/* mkplace -- Figure out the proper storage class for the input name and
+ return an addrp with the appropriate stuff */
+
+ Addrp
+#ifdef KR_headers
+mkplace(np)
+ register Namep np;
+#else
+mkplace(register Namep np)
+#endif
+{
+ register Addrp s;
+ register struct Rplblock *rp;
+ int regn;
+
+ /* is name on the replace list? */
+
+ for(rp = rpllist ; rp ; rp = rp->rplnextp)
+ {
+ if(np == rp->rplnp)
+ {
+ replaced = 1;
+ if(rp->rpltag == TNAME)
+ {
+ np = (Namep) (rp->rplvp);
+ break;
+ }
+ else return( (Addrp) cpexpr(rp->rplvp) );
+ }
+ }
+
+ /* is variable a DO index in a register ? */
+
+ if(np->vdovar && ( (regn = inregister(np)) >= 0) )
+ if(np->vtype == TYERROR)
+ return((Addrp) errnode() );
+ else
+ {
+ s = ALLOC(Addrblock);
+ s->tag = TADDR;
+ s->vstg = STGREG;
+ s->vtype = TYIREG;
+ s->memno = regn;
+ s->memoffset = ICON(0);
+ s -> uname_tag = UNAM_NAME;
+ s -> user.name = np;
+ return(s);
+ }
+
+ if (np->vclass == CLPROC && np->vprocclass != PTHISPROC)
+ errstr("external %.60s used as a variable", np->fvarname);
+ vardcl(np);
+ return(mkaddr(np));
+}
+
+ static expptr
+#ifdef KR_headers
+subskept(p, a)
+ struct Primblock *p;
+ Addrp a;
+#else
+subskept(struct Primblock *p, Addrp a)
+#endif
+{
+ expptr ep;
+ struct Listblock *Lb;
+ chainp cp;
+
+ if (a->uname_tag != UNAM_NAME)
+ erri("subskept: uname_tag %d", a->uname_tag);
+ a->user.name->vrefused = 1;
+ a->user.name->visused = 1;
+ a->uname_tag = UNAM_REF;
+ Lb = (struct Listblock *)cpexpr((tagptr)p->argsp);
+ for(cp = Lb->listp; cp; cp = cp->nextp)
+ cp->datap = (char *)putx(fixtype((tagptr)cp->datap));
+ if (a->vtype == TYCHAR) {
+ ep = p->fcharp ? mkexpr(OPMINUS, cpexpr(p->fcharp), ICON(1))
+ : ICON(0);
+ Lb->listp = mkchain((char *)ep, Lb->listp);
+ }
+ return (expptr)Lb;
+ }
+
+ static int doing_vleng;
+
+/* mklhs -- Compute the actual address of the given expression; account
+ for array subscripts, stack offset, and substring offsets. The f -> C
+ translator will need this only to worry about the subscript stuff */
+
+ expptr
+#ifdef KR_headers
+mklhs(p, subkeep)
+ register struct Primblock *p;
+ int subkeep;
+#else
+mklhs(register struct Primblock *p, int subkeep)
+#endif
+{
+ register Addrp s;
+ Namep np;
+
+ if(p->tag != TPRIM)
+ return( (expptr) p );
+ np = p->namep;
+
+ replaced = 0;
+ s = mkplace(np);
+ if(s->tag!=TADDR || s->vstg==STGREG)
+ {
+ free( (charptr) p );
+ return( (expptr) s );
+ }
+ s->parenused = p->parenused;
+
+ /* compute the address modified by subscripts */
+
+ if (!replaced)
+ s->memoffset = (subkeep && np->vdim
+ && (np->vdim->ndim > 1 || np->vtype == TYCHAR
+ && (!ISCONST(np->vleng)
+ || np->vleng->constblock.Const.ci != 1)))
+ ? subskept(p,s)
+ : mkexpr(OPPLUS, s->memoffset, suboffset(p) );
+ frexpr((expptr)p->argsp);
+ p->argsp = NULL;
+
+ /* now do substring part */
+
+ if(p->fcharp || p->lcharp)
+ {
+ if(np->vtype != TYCHAR)
+ sserr(np);
+ else {
+ if(p->lcharp == NULL)
+ p->lcharp = (expptr)(
+ /* s->vleng == 0 only with errors */
+ s->vleng ? cpexpr(s->vleng) : ICON(1));
+ if(p->fcharp) {
+ doing_vleng = 1;
+ s->vleng = fixtype(mkexpr(OPMINUS,
+ p->lcharp,
+ mkexpr(OPMINUS, p->fcharp, ICON(1) )));
+ doing_vleng = 0;
+ }
+ else {
+ frexpr(s->vleng);
+ s->vleng = p->lcharp;
+ }
+ }
+ }
+
+ s->vleng = fixtype( s->vleng );
+ s->memoffset = fixtype( s->memoffset );
+ free( (charptr) p );
+ return( (expptr) s );
+}
+
+
+
+
+
+/* deregister -- remove a register allocation from the list; assumes that
+ names are deregistered in stack order (LIFO order - Last In First Out) */
+
+ void
+#ifdef KR_headers
+deregister(np)
+ Namep np;
+#else
+deregister(Namep np)
+#endif
+{
+ if(nregvar>0 && regnamep[nregvar-1]==np)
+ {
+ --nregvar;
+ }
+}
+
+
+
+
+/* memversion -- moves a DO index REGISTER into a memory location; other
+ objects are passed through untouched */
+
+ Addrp
+#ifdef KR_headers
+memversion(np)
+ register Namep np;
+#else
+memversion(register Namep np)
+#endif
+{
+ register Addrp s;
+
+ if(np->vdovar==NO || (inregister(np)<0) )
+ return(NULL);
+ np->vdovar = NO;
+ s = mkplace(np);
+ np->vdovar = YES;
+ return(s);
+}
+
+
+
+/* inregister -- looks for the input name in the global list regnamep */
+
+ int
+#ifdef KR_headers
+inregister(np)
+ register Namep np;
+#else
+inregister(register Namep np)
+#endif
+{
+ register int i;
+
+ for(i = 0 ; i < nregvar ; ++i)
+ if(regnamep[i] == np)
+ return( regnum[i] );
+ return(-1);
+}
+
+
+
+/* suboffset -- Compute the offset from the start of the array, given the
+ subscripts as arguments */
+
+ expptr
+#ifdef KR_headers
+suboffset(p)
+ register struct Primblock *p;
+#else
+suboffset(register struct Primblock *p)
+#endif
+{
+ int n;
+ expptr si, size;
+ chainp cp;
+ expptr e, e1, offp, prod;
+ struct Dimblock *dimp;
+ expptr sub[MAXDIM+1];
+ register Namep np;
+
+ np = p->namep;
+ offp = ICON(0);
+ n = 0;
+ if(p->argsp)
+ for(cp = p->argsp->listp ; cp ; cp = cp->nextp)
+ {
+ si = fixtype(cpexpr((tagptr)cp->datap));
+ if (!ISINT(si->headblock.vtype)) {
+ NOEXT("non-integer subscript");
+ si = mkconv(TYLONG, si);
+ }
+ sub[n++] = si;
+ if(n > maxdim)
+ {
+ erri("more than %d subscripts", maxdim);
+ break;
+ }
+ }
+
+ dimp = np->vdim;
+ if(n>0 && dimp==NULL)
+ errstr("subscripts on scalar variable %.68s", np->fvarname);
+ else if(dimp && dimp->ndim!=n)
+ errstr("wrong number of subscripts on %.68s", np->fvarname);
+ else if(n > 0)
+ {
+ prod = sub[--n];
+ while( --n >= 0)
+ prod = mkexpr(OPPLUS, sub[n],
+ mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) );
+ if(checksubs || np->vstg!=STGARG)
+ prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
+
+/* Add in the run-time bounds check */
+
+ if(checksubs)
+ prod = subcheck(np, prod);
+ size = np->vtype == TYCHAR ?
+ (expptr) cpexpr(np->vleng) : ICON(typesize[np->vtype]);
+ prod = mkexpr(OPSTAR, prod, size);
+ offp = mkexpr(OPPLUS, offp, prod);
+ }
+
+/* Check for substring indicator */
+
+ if(p->fcharp && np->vtype==TYCHAR) {
+ e = p->fcharp;
+ e1 = mkexpr(OPMINUS, cpexpr(e), ICON(1));
+ if (!ISCONST(e) && (e->tag != TPRIM || e->primblock.argsp)) {
+ e = (expptr)mktmp(TYLONG, ENULL);
+ putout(putassign(cpexpr(e), e1));
+ p->fcharp = mkexpr(OPPLUS, cpexpr(e), ICON(1));
+ e1 = e;
+ }
+ offp = mkexpr(OPPLUS, offp, e1);
+ }
+ return(offp);
+}
+
+
+
+
+ expptr
+#ifdef KR_headers
+subcheck(np, p)
+ Namep np;
+ register expptr p;
+#else
+subcheck(Namep np, register expptr p)
+#endif
+{
+ struct Dimblock *dimp;
+ expptr t, checkvar, checkcond, badcall;
+
+ dimp = np->vdim;
+ if(dimp->nelt == NULL)
+ return(p); /* don't check arrays with * bounds */
+ np->vlastdim = 0;
+ if( ISICON(p) )
+ {
+
+/* check for negative (constant) offset */
+
+ if(p->constblock.Const.ci < 0)
+ goto badsub;
+ if( ISICON(dimp->nelt) )
+
+/* see if constant offset exceeds the array declaration */
+
+ if(p->constblock.Const.ci < dimp->nelt->constblock.Const.ci)
+ return(p);
+ else
+ goto badsub;
+ }
+
+/* We know that the subscript offset p or dimp -> nelt is not a constant.
+ Now find a register to use for run-time bounds checking */
+
+ if(p->tag==TADDR && p->addrblock.vstg==STGREG)
+ {
+ checkvar = (expptr) cpexpr(p);
+ t = p;
+ }
+ else {
+ checkvar = (expptr) mktmp(p->headblock.vtype, ENULL);
+ t = mkexpr(OPASSIGN, cpexpr(checkvar), p);
+ }
+ checkcond = mkexpr(OPLT, t, cpexpr(dimp->nelt) );
+ if( ! ISICON(p) )
+ checkcond = mkexpr(OPAND, checkcond,
+ mkexpr(OPLE, ICON(0), cpexpr(checkvar)) );
+
+/* Construct the actual test */
+
+ badcall = call4(p->headblock.vtype, "s_rnge",
+ mkstrcon(strlen(np->fvarname), np->fvarname),
+ mkconv(TYLONG, cpexpr(checkvar)),
+ mkstrcon(strlen(procname), procname),
+ ICON(lineno) );
+ badcall->exprblock.opcode = OPCCALL;
+ p = mkexpr(OPQUEST, checkcond,
+ mkexpr(OPCOLON, checkvar, badcall));
+
+ return(p);
+
+badsub:
+ frexpr(p);
+ errstr("subscript on variable %s out of range", np->fvarname);
+ return ( ICON(0) );
+}
+
+
+
+
+ Addrp
+#ifdef KR_headers
+mkaddr(p)
+ register Namep p;
+#else
+mkaddr(register Namep p)
+#endif
+{
+ Extsym *extp;
+ register Addrp t;
+ int k;
+
+ switch( p->vstg)
+ {
+ case STGAUTO:
+ if(p->vclass == CLPROC && p->vprocclass == PTHISPROC)
+ return (Addrp) cpexpr((expptr)xretslot[p->vtype]);
+ goto other;
+
+ case STGUNKNOWN:
+ if(p->vclass != CLPROC)
+ break; /* Error */
+ extp = mkext(p->fvarname, addunder(p->cvarname));
+ extp->extstg = STGEXT;
+ p->vstg = STGEXT;
+ p->vardesc.varno = extp - extsymtab;
+ p->vprocclass = PEXTERNAL;
+ if ((extp->exproto || infertypes)
+ && (p->vtype == TYUNKNOWN || p->vimpltype)
+ && (k = extp->extype))
+ inferdcl(p, k);
+
+
+ case STGCOMMON:
+ case STGEXT:
+ case STGBSS:
+ case STGINIT:
+ case STGEQUIV:
+ case STGARG:
+ case STGLENG:
+ other:
+ t = ALLOC(Addrblock);
+ t->tag = TADDR;
+
+ t->vclass = p->vclass;
+ t->vtype = p->vtype;
+ t->vstg = p->vstg;
+ t->memno = p->vardesc.varno;
+ t->memoffset = ICON(p->voffset);
+ if (p->vdim)
+ t->isarray = 1;
+ if(p->vleng)
+ {
+ t->vleng = (expptr) cpexpr(p->vleng);
+ if( ISICON(t->vleng) )
+ t->varleng = t->vleng->constblock.Const.ci;
+ }
+
+/* Keep the original name around for the C code generation */
+
+ t -> uname_tag = UNAM_NAME;
+ t -> user.name = p;
+ return(t);
+
+ case STGINTR:
+
+ return ( intraddr (p));
+
+ case STGSTFUNCT:
+
+ errstr("invalid use of statement function %.64s.", p->fvarname);
+ return putconst((Constp)ICON(0));
+ }
+ badstg("mkaddr", p->vstg);
+ /* NOT REACHED */ return 0;
+}
+
+
+
+
+/* mkarg -- create storage for a new parameter. This is called when a
+ function returns a string (for the return value, which is the first
+ parameter), or when a variable-length string is passed to a function. */
+
+ Addrp
+#ifdef KR_headers
+mkarg(type, argno)
+ int type;
+ int argno;
+#else
+mkarg(int type, int argno)
+#endif
+{
+ register Addrp p;
+
+ p = ALLOC(Addrblock);
+ p->tag = TADDR;
+ p->vtype = type;
+ p->vclass = CLVAR;
+
+/* TYLENG is the type of the field holding the length of a character string */
+
+ p->vstg = (type==TYLENG ? STGLENG : STGARG);
+ p->memno = argno;
+ return(p);
+}
+
+
+
+
+/* mkprim -- Create a PRIM (primary/primitive) block consisting of a
+ Nameblock (or Paramblock), arguments (actual params or array
+ subscripts) and substring bounds. Requires that v have lots of
+ extra (uninitialized) storage, since it could be a paramblock or
+ nameblock */
+
+ expptr
+#ifdef KR_headers
+mkprim(v0, args, substr)
+ Namep v0;
+ struct Listblock *args;
+ chainp substr;
+#else
+mkprim(Namep v0, struct Listblock *args, chainp substr)
+#endif
+{
+ typedef union {
+ struct Paramblock paramblock;
+ struct Nameblock nameblock;
+ struct Headblock headblock;
+ } *Primu;
+ register Primu v = (Primu)v0;
+ register struct Primblock *p;
+
+ if(v->headblock.vclass == CLPARAM)
+ {
+
+/* v is to be a Paramblock */
+
+ if(args || substr)
+ {
+ errstr("no qualifiers on parameter name %s",
+ v->paramblock.fvarname);
+ frexpr((expptr)args);
+ if(substr)
+ {
+ frexpr((tagptr)substr->datap);
+ frexpr((tagptr)substr->nextp->datap);
+ frchain(&substr);
+ }
+ frexpr((expptr)v);
+ return( errnode() );
+ }
+ return( (expptr) cpexpr(v->paramblock.paramval) );
+ }
+
+ p = ALLOC(Primblock);
+ p->tag = TPRIM;
+ p->vtype = v->nameblock.vtype;
+
+/* v is to be a Nameblock */
+
+ p->namep = (Namep) v;
+ p->argsp = args;
+ if(substr)
+ {
+ p->fcharp = (expptr) substr->datap;
+ p->lcharp = (expptr) substr->nextp->datap;
+ frchain(&substr);
+ }
+ return( (expptr) p);
+}
+
+
+
+/* vardcl -- attempt to fill out the Name template for variable v.
+ This function is called on identifiers known to be variables or
+ recursive references to the same function */
+
+ void
+#ifdef KR_headers
+vardcl(v)
+ register Namep v;
+#else
+vardcl(register Namep v)
+#endif
+{
+ struct Dimblock *t;
+ expptr neltp;
+ extern int doing_stmtfcn;
+
+ if(v->vclass == CLUNKNOWN) {
+ v->vclass = CLVAR;
+ if (v->vinftype) {
+ v->vtype = TYUNKNOWN;
+ if (v->vdcldone) {
+ v->vdcldone = 0;
+ impldcl(v);
+ }
+ }
+ }
+ if(v->vdcldone)
+ return;
+ if(v->vclass == CLNAMELIST)
+ return;
+
+ if(v->vtype == TYUNKNOWN)
+ impldcl(v);
+ else if(v->vclass!=CLVAR && v->vprocclass!=PTHISPROC)
+ {
+ dclerr("used as variable", v);
+ return;
+ }
+ if(v->vstg==STGUNKNOWN) {
+ if (doing_stmtfcn) {
+ /* neither declare this variable if its only use */
+ /* is in defining a stmt function, nor complain */
+ /* that it is never used */
+ v->vimpldovar = 1;
+ return;
+ }
+ v->vstg = implstg[ letter(v->fvarname[0]) ];
+ v->vimplstg = 1;
+ }
+
+/* Compute the actual storage location, i.e. offsets from base addresses,
+ possibly the stack pointer */
+
+ switch(v->vstg)
+ {
+ case STGBSS:
+ v->vardesc.varno = ++lastvarno;
+ break;
+ case STGAUTO:
+ if(v->vclass==CLPROC && v->vprocclass==PTHISPROC)
+ break;
+ if(t = v->vdim)
+ if( (neltp = t->nelt) && ISCONST(neltp) ) ;
+ else
+ dclerr("adjustable automatic array", v);
+ break;
+
+ default:
+ break;
+ }
+ v->vdcldone = YES;
+}
+
+
+
+/* Set the implicit type declaration of parameter p based on its first
+ letter */
+
+ void
+#ifdef KR_headers
+impldcl(p)
+ register Namep p;
+#else
+impldcl(register Namep p)
+#endif
+{
+ register int k;
+ int type;
+ ftnint leng;
+
+ if(p->vdcldone || (p->vclass==CLPROC && p->vprocclass==PINTRINSIC) )
+ return;
+ if(p->vtype == TYUNKNOWN)
+ {
+ k = letter(p->fvarname[0]);
+ type = impltype[ k ];
+ leng = implleng[ k ];
+ if(type == TYUNKNOWN)
+ {
+ if(p->vclass == CLPROC)
+ return;
+ dclerr("attempt to use undefined variable", p);
+ type = dflttype[k];
+ leng = 0;
+ }
+ settype(p, type, leng);
+ p->vimpltype = 1;
+ }
+}
+
+ void
+#ifdef KR_headers
+inferdcl(np, type)
+ Namep np;
+ int type;
+#else
+inferdcl(Namep np, int type)
+#endif
+{
+ int k = impltype[letter(np->fvarname[0])];
+ if (k != type) {
+ np->vinftype = 1;
+ np->vtype = type;
+ frexpr(np->vleng);
+ np->vleng = 0;
+ }
+ np->vimpltype = 0;
+ np->vinfproc = 1;
+ }
+
+ LOCAL int
+#ifdef KR_headers
+zeroconst(e)
+ expptr e;
+#else
+zeroconst(expptr e)
+#endif
+{
+ register Constp c = (Constp) e;
+ if (c->tag == TCONST)
+ switch(c->vtype) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ return c->Const.ci == 0;
+
+ case TYREAL:
+ case TYDREAL:
+ if (c->vstg == 1)
+ return !strcmp(c->Const.cds[0],"0.");
+ return c->Const.cd[0] == 0.;
+
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if (c->vstg == 1)
+ return !strcmp(c->Const.cds[0],"0.")
+ && !strcmp(c->Const.cds[1],"0.");
+ return c->Const.cd[0] == 0. && c->Const.cd[1] == 0.;
+ }
+ return 0;
+ }
+
+
+#define ICONEQ(z, c) (ISICON(z) && z->constblock.Const.ci==c)
+#define COMMUTE { e = lp; lp = rp; rp = e; }
+
+/* mkexpr -- Make expression, and simplify constant subcomponents (tree
+ order is not preserved). Assumes that lp is nonempty, and uses
+ fold() to simplify adjacent constants */
+
+ expptr
+#ifdef KR_headers
+mkexpr(opcode, lp, rp)
+ int opcode;
+ register expptr lp;
+ register expptr rp;
+#else
+mkexpr(int opcode, register expptr lp, register expptr rp)
+#endif
+{
+ register expptr e, e1;
+ int etype;
+ int ltype, rtype;
+ int ltag, rtag;
+ long L;
+ static long divlineno;
+
+ ltype = lp->headblock.vtype;
+ ltag = lp->tag;
+ if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+ {
+ rtype = rp->headblock.vtype;
+ rtag = rp->tag;
+ }
+ else rtype = 0;
+
+ etype = cktype(opcode, ltype, rtype);
+ if(etype == TYERROR)
+ goto error;
+
+ switch(opcode)
+ {
+ /* check for multiplication by 0 and 1 and addition to 0 */
+
+ case OPSTAR:
+ if( ISCONST(lp) )
+ COMMUTE
+
+ if( ISICON(rp) )
+ {
+ if(rp->constblock.Const.ci == 0)
+ goto retright;
+ goto mulop;
+ }
+ break;
+
+ case OPSLASH:
+ case OPMOD:
+ if( zeroconst(rp) && lineno != divlineno ) {
+ warn("attempted division by zero");
+ divlineno = lineno;
+ }
+ if(opcode == OPMOD)
+ break;
+
+/* Handle multiplying or dividing by 1, -1 */
+
+mulop:
+ if( ISICON(rp) )
+ {
+ if(rp->constblock.Const.ci == 1)
+ goto retleft;
+
+ if(rp->constblock.Const.ci == -1)
+ {
+ frexpr(rp);
+ return( mkexpr(OPNEG, lp, ENULL) );
+ }
+ }
+
+/* Group all constants together. In particular,
+
+ (x * CONST1) * CONST2 ==> x * (CONST1 * CONST2)
+ (x * CONST1) / CONST2 ==> x * (CONST1 / CONST2)
+*/
+
+ if (!ISINT(etype) || lp->tag != TEXPR || !lp->exprblock.rightp
+ || !ISICON(lp->exprblock.rightp))
+ break;
+
+ if (lp->exprblock.opcode == OPLSHIFT) {
+ L = 1 << lp->exprblock.rightp->constblock.Const.ci;
+ if (opcode == OPSTAR || ISICON(rp) &&
+ !(L % rp->constblock.Const.ci)) {
+ lp->exprblock.opcode = OPSTAR;
+ lp->exprblock.rightp->constblock.Const.ci = L;
+ }
+ }
+
+ if (lp->exprblock.opcode == OPSTAR) {
+ if(opcode == OPSTAR)
+ e = mkexpr(OPSTAR, lp->exprblock.rightp, rp);
+ else if(ISICON(rp) &&
+ (lp->exprblock.rightp->constblock.Const.ci %
+ rp->constblock.Const.ci) == 0)
+ e = mkexpr(OPSLASH, lp->exprblock.rightp, rp);
+ else break;
+
+ e1 = lp->exprblock.leftp;
+ free( (charptr) lp );
+ return( mkexpr(OPSTAR, e1, e) );
+ }
+ break;
+
+
+ case OPPLUS:
+ if( ISCONST(lp) )
+ COMMUTE
+ goto addop;
+
+ case OPMINUS:
+ if( ICONEQ(lp, 0) )
+ {
+ frexpr(lp);
+ return( mkexpr(OPNEG, rp, ENULL) );
+ }
+
+ if( ISCONST(rp) && is_negatable((Constp)rp))
+ {
+ opcode = OPPLUS;
+ consnegop((Constp)rp);
+ }
+
+/* Group constants in an addition expression (also subtraction, since the
+ subtracted value was negated above). In particular,
+
+ (x + CONST1) + CONST2 ==> x + (CONST1 + CONST2)
+*/
+
+addop:
+ if( ISICON(rp) )
+ {
+ if(rp->constblock.Const.ci == 0)
+ goto retleft;
+ if( ISPLUSOP(lp) && ISICON(lp->exprblock.rightp) )
+ {
+ e = mkexpr(OPPLUS, lp->exprblock.rightp, rp);
+ e1 = lp->exprblock.leftp;
+ free( (charptr) lp );
+ return( mkexpr(OPPLUS, e1, e) );
+ }
+ }
+ if (opcode == OPMINUS && (ISINT(etype) || doing_vleng)) {
+ /* check for (i [+const]) - (i [+const]) */
+ if (lp->tag == TPRIM)
+ e = lp;
+ else if (lp->tag == TEXPR && lp->exprblock.opcode == OPPLUS
+ && lp->exprblock.rightp->tag == TCONST) {
+ e = lp->exprblock.leftp;
+ if (e->tag != TPRIM)
+ break;
+ }
+ else
+ break;
+ if (e->primblock.argsp)
+ break;
+ if (rp->tag == TPRIM)
+ e1 = rp;
+ else if (rp->tag == TEXPR && rp->exprblock.opcode == OPPLUS
+ && rp->exprblock.rightp->tag == TCONST) {
+ e1 = rp->exprblock.leftp;
+ if (e1->tag != TPRIM)
+ break;
+ }
+ else
+ break;
+ if (e->primblock.namep != e1->primblock.namep
+ || e1->primblock.argsp)
+ break;
+ L = e == lp ? 0 : lp->exprblock.rightp->constblock.Const.ci;
+ if (e1 != rp)
+ L -= rp->exprblock.rightp->constblock.Const.ci;
+ frexpr(lp);
+ frexpr(rp);
+ return ICON(L);
+ }
+
+ break;
+
+
+ case OPPOWER:
+ break;
+
+/* Eliminate outermost double negations */
+
+ case OPNEG:
+ case OPNEG1:
+ if(ltag==TEXPR && lp->exprblock.opcode==OPNEG)
+ {
+ e = lp->exprblock.leftp;
+ free( (charptr) lp );
+ return(e);
+ }
+ break;
+
+/* Eliminate outermost double NOTs */
+
+ case OPNOT:
+ if(ltag==TEXPR && lp->exprblock.opcode==OPNOT)
+ {
+ e = lp->exprblock.leftp;
+ free( (charptr) lp );
+ return(e);
+ }
+ break;
+
+ case OPCALL:
+ case OPCCALL:
+ etype = ltype;
+ if(rp!=NULL && rp->listblock.listp==NULL)
+ {
+ free( (charptr) rp );
+ rp = NULL;
+ }
+ break;
+
+ case OPAND:
+ case OPOR:
+ if( ISCONST(lp) )
+ COMMUTE
+
+ if( ISCONST(rp) )
+ {
+ if(rp->constblock.Const.ci == 0)
+ if(opcode == OPOR)
+ goto retleft;
+ else
+ goto retright;
+ else if(opcode == OPOR)
+ goto retright;
+ else
+ goto retleft;
+ }
+ case OPEQV:
+ case OPNEQV:
+
+ case OPBITAND:
+ case OPBITOR:
+ case OPBITXOR:
+ case OPBITNOT:
+ case OPLSHIFT:
+ case OPRSHIFT:
+ case OPBITTEST:
+ case OPBITCLR:
+ case OPBITSET:
+#ifdef TYQUAD
+ case OPQBITCLR:
+ case OPQBITSET:
+#endif
+
+ case OPLT:
+ case OPGT:
+ case OPLE:
+ case OPGE:
+ case OPEQ:
+ case OPNE:
+
+ case OPCONCAT:
+ break;
+ case OPMIN:
+ case OPMAX:
+ case OPMIN2:
+ case OPMAX2:
+ case OPDMIN:
+ case OPDMAX:
+
+ case OPASSIGN:
+ case OPASSIGNI:
+ case OPPLUSEQ:
+ case OPSTAREQ:
+ case OPMINUSEQ:
+ case OPSLASHEQ:
+ case OPMODEQ:
+ case OPLSHIFTEQ:
+ case OPRSHIFTEQ:
+ case OPBITANDEQ:
+ case OPBITXOREQ:
+ case OPBITOREQ:
+
+ case OPCONV:
+ case OPADDR:
+ case OPWHATSIN:
+
+ case OPCOMMA:
+ case OPCOMMA_ARG:
+ case OPQUEST:
+ case OPCOLON:
+ case OPDOT:
+ case OPARROW:
+ case OPIDENTITY:
+ case OPCHARCAST:
+ case OPABS:
+ case OPDABS:
+ break;
+
+ default:
+ badop("mkexpr", opcode);
+ }
+
+ e = (expptr) ALLOC(Exprblock);
+ e->exprblock.tag = TEXPR;
+ e->exprblock.opcode = opcode;
+ e->exprblock.vtype = etype;
+ e->exprblock.leftp = lp;
+ e->exprblock.rightp = rp;
+ if(ltag==TCONST && (rp==0 || rtag==TCONST) )
+ e = fold(e);
+ return(e);
+
+retleft:
+ frexpr(rp);
+ if (lp->tag == TPRIM)
+ lp->primblock.parenused = 1;
+ return(lp);
+
+retright:
+ frexpr(lp);
+ if (rp->tag == TPRIM)
+ rp->primblock.parenused = 1;
+ return(rp);
+
+error:
+ frexpr(lp);
+ if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+ frexpr(rp);
+ return( errnode() );
+}
+
+#define ERR(s) { errs = s; goto error; }
+
+/* cktype -- Check and return the type of the expression */
+
+#ifdef KR_headers
+cktype(op, lt, rt)
+ register int op;
+ register int lt;
+ register int rt;
+#else
+cktype(register int op, register int lt, register int rt)
+#endif
+{
+ char *errs;
+
+ if(lt==TYERROR || rt==TYERROR)
+ goto error1;
+
+ if(lt==TYUNKNOWN)
+ return(TYUNKNOWN);
+ if(rt==TYUNKNOWN)
+
+/* If not unary operation, return UNKNOWN */
+
+ if(!is_unary_op (op) && op != OPCALL && op != OPCCALL)
+ return(TYUNKNOWN);
+
+ switch(op)
+ {
+ case OPPLUS:
+ case OPMINUS:
+ case OPSTAR:
+ case OPSLASH:
+ case OPPOWER:
+ case OPMOD:
+ if( ISNUMERIC(lt) && ISNUMERIC(rt) )
+ return( maxtype(lt, rt) );
+ ERR("nonarithmetic operand of arithmetic operator")
+
+ case OPNEG:
+ case OPNEG1:
+ if( ISNUMERIC(lt) )
+ return(lt);
+ ERR("nonarithmetic operand of negation")
+
+ case OPNOT:
+ if(ISLOGICAL(lt))
+ return(lt);
+ ERR("NOT of nonlogical")
+
+ case OPAND:
+ case OPOR:
+ case OPEQV:
+ case OPNEQV:
+ if(ISLOGICAL(lt) && ISLOGICAL(rt))
+ return( maxtype(lt, rt) );
+ ERR("nonlogical operand of logical operator")
+
+ case OPLT:
+ case OPGT:
+ case OPLE:
+ case OPGE:
+ case OPEQ:
+ case OPNE:
+ if(lt==TYCHAR || rt==TYCHAR || ISLOGICAL(lt) || ISLOGICAL(rt))
+ {
+ if(lt != rt){
+ if (htype
+ && (lt == TYCHAR && ISNUMERIC(rt)
+ || rt == TYCHAR && ISNUMERIC(lt)))
+ return TYLOGICAL;
+ ERR("illegal comparison")
+ }
+ }
+
+ else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) )
+ {
+ if(op!=OPEQ && op!=OPNE)
+ ERR("order comparison of complex data")
+ }
+
+ else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) )
+ ERR("comparison of nonarithmetic data")
+ case OPBITTEST:
+ return(TYLOGICAL);
+
+ case OPCONCAT:
+ if(lt==TYCHAR && rt==TYCHAR)
+ return(TYCHAR);
+ ERR("concatenation of nonchar data")
+
+ case OPCALL:
+ case OPCCALL:
+ case OPIDENTITY:
+ return(lt);
+
+ case OPADDR:
+ case OPCHARCAST:
+ return(TYADDR);
+
+ case OPCONV:
+ if(rt == 0)
+ return(0);
+ if(lt==TYCHAR && ISINT(rt) )
+ return(TYCHAR);
+ if (ISLOGICAL(lt) && ISLOGICAL(rt))
+ return lt;
+ case OPASSIGN:
+ case OPASSIGNI:
+ case OPMINUSEQ:
+ case OPPLUSEQ:
+ case OPSTAREQ:
+ case OPSLASHEQ:
+ case OPMODEQ:
+ case OPLSHIFTEQ:
+ case OPRSHIFTEQ:
+ case OPBITANDEQ:
+ case OPBITXOREQ:
+ case OPBITOREQ:
+ if( ISINT(lt) && rt==TYCHAR)
+ return(lt);
+ if (ISLOGICAL(lt) && ISLOGICAL(rt) && op == OPASSIGN)
+ return lt;
+ if(lt==TYCHAR || rt==TYCHAR || ISLOGICAL(lt) || ISLOGICAL(rt))
+ if((op!=OPASSIGN && op != OPPLUSEQ && op != OPMINUSEQ)
+ || (lt!=rt))
+ {
+ ERR("impossible conversion")
+ }
+ return(lt);
+
+ case OPMIN:
+ case OPMAX:
+ case OPDMIN:
+ case OPDMAX:
+ case OPMIN2:
+ case OPMAX2:
+ case OPBITOR:
+ case OPBITAND:
+ case OPBITXOR:
+ case OPBITNOT:
+ case OPLSHIFT:
+ case OPRSHIFT:
+ case OPWHATSIN:
+ case OPABS:
+ case OPDABS:
+ return(lt);
+
+ case OPBITCLR:
+ case OPBITSET:
+ if (lt < TYLONG)
+ lt = TYLONG;
+ return(lt);
+#ifdef TYQUAD
+ case OPQBITCLR:
+ case OPQBITSET:
+ return TYQUAD;
+#endif
+
+ case OPCOMMA:
+ case OPCOMMA_ARG:
+ case OPQUEST:
+ case OPCOLON: /* Only checks the rightmost type because
+ of C language definition (rightmost
+ comma-expr is the value of the expr) */
+ return(rt);
+
+ case OPDOT:
+ case OPARROW:
+ return (lt);
+ default:
+ badop("cktype", op);
+ }
+error:
+ err(errs);
+error1:
+ return(TYERROR);
+}
+
+ static void
+intovfl(Void)
+{ err("overflow simplifying integer constants."); }
+
+/* fold -- simplifies constant expressions; it assumes that e -> leftp and
+ e -> rightp are TCONST or NULL */
+
+ expptr
+#ifdef KR_headers
+fold(e)
+ register expptr e;
+#else
+fold(register expptr e)
+#endif
+{
+ Constp p;
+ register expptr lp, rp;
+ int etype, mtype, ltype, rtype, opcode;
+ int i, bl, ll, lr;
+ char *q, *s;
+ struct Constblock lcon, rcon;
+ ftnint L;
+ double d;
+
+ opcode = e->exprblock.opcode;
+ etype = e->exprblock.vtype;
+
+ lp = e->exprblock.leftp;
+ ltype = lp->headblock.vtype;
+ rp = e->exprblock.rightp;
+
+ if(rp == 0)
+ switch(opcode)
+ {
+ case OPNOT:
+ lp->constblock.Const.ci = ! lp->constblock.Const.ci;
+ retlp:
+ e->exprblock.leftp = 0;
+ frexpr(e);
+ return(lp);
+
+ case OPBITNOT:
+ lp->constblock.Const.ci = ~ lp->constblock.Const.ci;
+ goto retlp;
+
+ case OPNEG:
+ case OPNEG1:
+ consnegop((Constp)lp);
+ goto retlp;
+
+ case OPCONV:
+ case OPADDR:
+ return(e);
+
+ case OPABS:
+ case OPDABS:
+ switch(ltype) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ if ((L = lp->constblock.Const.ci) < 0) {
+ lp->constblock.Const.ci = -L;
+ if (L != -lp->constblock.Const.ci)
+ intovfl();
+ }
+ goto retlp;
+ case TYREAL:
+ case TYDREAL:
+ if (lp->constblock.vstg) {
+ s = lp->constblock.Const.cds[0];
+ if (*s == '-')
+ lp->constblock.Const.cds[0] = s + 1;
+ goto retlp;
+ }
+ if ((d = lp->constblock.Const.cd[0]) < 0.)
+ lp->constblock.Const.cd[0] = -d;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ return e; /* lazy way out */
+ }
+ default:
+ badop("fold", opcode);
+ }
+
+ rtype = rp->headblock.vtype;
+
+ p = ALLOC(Constblock);
+ p->tag = TCONST;
+ p->vtype = etype;
+ p->vleng = e->exprblock.vleng;
+
+ switch(opcode)
+ {
+ case OPCOMMA:
+ case OPCOMMA_ARG:
+ case OPQUEST:
+ case OPCOLON:
+ goto ereturn;
+
+ case OPAND:
+ p->Const.ci = lp->constblock.Const.ci &&
+ rp->constblock.Const.ci;
+ break;
+
+ case OPOR:
+ p->Const.ci = lp->constblock.Const.ci ||
+ rp->constblock.Const.ci;
+ break;
+
+ case OPEQV:
+ p->Const.ci = lp->constblock.Const.ci ==
+ rp->constblock.Const.ci;
+ break;
+
+ case OPNEQV:
+ p->Const.ci = lp->constblock.Const.ci !=
+ rp->constblock.Const.ci;
+ break;
+
+ case OPBITAND:
+ p->Const.ci = lp->constblock.Const.ci &
+ rp->constblock.Const.ci;
+ break;
+
+ case OPBITOR:
+ p->Const.ci = lp->constblock.Const.ci |
+ rp->constblock.Const.ci;
+ break;
+
+ case OPBITXOR:
+ p->Const.ci = lp->constblock.Const.ci ^
+ rp->constblock.Const.ci;
+ break;
+
+ case OPLSHIFT:
+ p->Const.ci = lp->constblock.Const.ci <<
+ rp->constblock.Const.ci;
+ if ((((unsigned long)p->Const.ci) >> rp->constblock.Const.ci)
+ != lp->constblock.Const.ci)
+ intovfl();
+ break;
+
+ case OPRSHIFT:
+ p->Const.ci = (unsigned long)lp->constblock.Const.ci >>
+ rp->constblock.Const.ci;
+ break;
+
+ case OPBITTEST:
+ p->Const.ci = (lp->constblock.Const.ci &
+ 1L << rp->constblock.Const.ci) != 0;
+ break;
+
+ case OPBITCLR:
+ p->Const.ci = lp->constblock.Const.ci &
+ ~(1L << rp->constblock.Const.ci);
+ break;
+
+ case OPBITSET:
+ p->Const.ci = lp->constblock.Const.ci |
+ 1L << rp->constblock.Const.ci;
+ break;
+
+ case OPCONCAT:
+ ll = lp->constblock.vleng->constblock.Const.ci;
+ lr = rp->constblock.vleng->constblock.Const.ci;
+ bl = lp->constblock.Const.ccp1.blanks;
+ p->Const.ccp = q = (char *) ckalloc(ll+lr+bl);
+ p->Const.ccp1.blanks = rp->constblock.Const.ccp1.blanks;
+ p->vleng = ICON(ll+lr+bl);
+ s = lp->constblock.Const.ccp;
+ for(i = 0 ; i < ll ; ++i)
+ *q++ = *s++;
+ for(i = 0 ; i < bl ; i++)
+ *q++ = ' ';
+ s = rp->constblock.Const.ccp;
+ for(i = 0; i < lr; ++i)
+ *q++ = *s++;
+ break;
+
+
+ case OPPOWER:
+ if( !ISINT(rtype)
+ || rp->constblock.Const.ci < 0 && zeroconst(lp))
+ goto ereturn;
+ conspower(p, (Constp)lp, rp->constblock.Const.ci);
+ break;
+
+ case OPSLASH:
+ if (zeroconst(rp))
+ goto ereturn;
+ /* no break */
+
+ default:
+ if(ltype == TYCHAR)
+ {
+ lcon.Const.ci = cmpstr(lp->constblock.Const.ccp,
+ rp->constblock.Const.ccp,
+ lp->constblock.vleng->constblock.Const.ci,
+ rp->constblock.vleng->constblock.Const.ci);
+ rcon.Const.ci = 0;
+ mtype = tyint;
+ }
+ else {
+ mtype = maxtype(ltype, rtype);
+ consconv(mtype, &lcon, &lp->constblock);
+ consconv(mtype, &rcon, &rp->constblock);
+ }
+ consbinop(opcode, mtype, p, &lcon, &rcon);
+ break;
+ }
+
+ frexpr(e);
+ return( (expptr) p );
+ ereturn:
+ free((char *)p);
+ return e;
+}
+
+
+
+/* assign constant l = r , doing coercion */
+
+ void
+#ifdef KR_headers
+consconv(lt, lc, rc)
+ int lt;
+ register Constp lc;
+ register Constp rc;
+#else
+consconv(int lt, register Constp lc, register Constp rc)
+#endif
+{
+ int rt = rc->vtype;
+ register union Constant *lv = &lc->Const, *rv = &rc->Const;
+
+ lc->vtype = lt;
+ if (ONEOF(lt, MSKREAL|MSKCOMPLEX) && ONEOF(rt, MSKREAL|MSKCOMPLEX)) {
+ memcpy((char *)lv, (char *)rv, sizeof(union Constant));
+ lc->vstg = rc->vstg;
+ if (ISCOMPLEX(lt) && ISREAL(rt)) {
+ if (rc->vstg)
+ lv->cds[1] = cds("0",CNULL);
+ else
+ lv->cd[1] = 0.;
+ }
+ return;
+ }
+ lc->vstg = 0;
+
+ switch(lt)
+ {
+
+/* Casting to character means just copying the first sizeof (character)
+ bytes into a new 1 character string. This is weird. */
+
+ case TYCHAR:
+ *(lv->ccp = (char *) ckalloc(1)) = rv->ci;
+ lv->ccp1.blanks = 0;
+ break;
+
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ if(rt == TYCHAR)
+ lv->ci = rv->ccp[0];
+ else if( ISINT(rt) )
+ lv->ci = rv->ci;
+ else lv->ci = rc->vstg ? atof(rv->cds[0]) : rv->cd[0];
+
+ break;
+
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ lv->cd[1] = 0.;
+ lv->cd[0] = rv->ci;
+ break;
+
+ case TYREAL:
+ case TYDREAL:
+ lv->cd[0] = rv->ci;
+ break;
+
+ case TYLOGICAL:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ lv->ci = rv->ci;
+ break;
+ }
+}
+
+
+
+/* Negate constant value -- changes the input node's value */
+
+ void
+#ifdef KR_headers
+consnegop(p)
+ register Constp p;
+#else
+consnegop(register Constp p)
+#endif
+{
+ register char *s;
+ ftnint L;
+
+ if (p->vstg) {
+ if (ISCOMPLEX(p->vtype)) {
+ s = p->Const.cds[1];
+ p->Const.cds[1] = *s == '-' ? s+1
+ : *s == '0' ? s : s-1;
+ }
+ s = p->Const.cds[0];
+ p->Const.cds[0] = *s == '-' ? s+1
+ : *s == '0' ? s : s-1;
+ return;
+ }
+ switch(p->vtype)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ p->Const.ci = -(L = p->Const.ci);
+ if (L != -p->Const.ci)
+ intovfl();
+ break;
+
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ p->Const.cd[1] = - p->Const.cd[1];
+ /* fall through and do the real parts */
+ case TYREAL:
+ case TYDREAL:
+ p->Const.cd[0] = - p->Const.cd[0];
+ break;
+ default:
+ badtype("consnegop", p->vtype);
+ }
+}
+
+
+
+/* conspower -- Expand out an exponentiation */
+
+ LOCAL void
+#ifdef KR_headers
+conspower(p, ap, n)
+ Constp p;
+ Constp ap;
+ ftnint n;
+#else
+conspower(Constp p, Constp ap, ftnint n)
+#endif
+{
+ register union Constant *powp = &p->Const;
+ register int type;
+ struct Constblock x, x0;
+
+ if (n == 1) {
+ memcpy((char *)powp, (char *)&ap->Const, sizeof(ap->Const));
+ return;
+ }
+
+ switch(type = ap->vtype) /* pow = 1 */
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ powp->ci = 1;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ powp->cd[1] = 0;
+ case TYREAL:
+ case TYDREAL:
+ powp->cd[0] = 1;
+ break;
+ default:
+ badtype("conspower", type);
+ }
+
+ if(n == 0)
+ return;
+ switch(type) /* x0 = ap */
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ x0.Const.ci = ap->Const.ci;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ x0.Const.cd[1] =
+ ap->vstg ? atof(ap->Const.cds[1]) : ap->Const.cd[1];
+ case TYREAL:
+ case TYDREAL:
+ x0.Const.cd[0] =
+ ap->vstg ? atof(ap->Const.cds[0]) : ap->Const.cd[0];
+ break;
+ }
+ x0.vtype = type;
+ x0.vstg = 0;
+ if(n < 0)
+ {
+ n = -n;
+ if( ISINT(type) )
+ {
+ switch(ap->Const.ci) {
+ case 0:
+ err("0 ** negative number");
+ return;
+ case 1:
+ case -1:
+ goto mult;
+ }
+ err("integer ** negative number");
+ return;
+ }
+ else if (!x0.Const.cd[0]
+ && (!ISCOMPLEX(type) || !x0.Const.cd[1])) {
+ err("0.0 ** negative number");
+ return;
+ }
+ consbinop(OPSLASH, type, &x, p, &x0);
+ }
+ else
+ mult: consbinop(OPSTAR, type, &x, p, &x0);
+
+ for( ; ; )
+ {
+ if(n & 01)
+ consbinop(OPSTAR, type, p, p, &x);
+ if(n >>= 1)
+ consbinop(OPSTAR, type, &x, &x, &x);
+ else
+ break;
+ }
+}
+
+
+
+/* do constant operation cp = a op b -- assumes that ap and bp have data
+ matching the input type */
+
+ LOCAL void
+#ifdef KR_headers
+consbinop(opcode, type, cpp, app, bpp)
+ int opcode;
+ int type;
+ Constp cpp;
+ Constp app;
+ Constp bpp;
+#else
+consbinop(int opcode, int type, Constp cpp, Constp app, Constp bpp)
+#endif
+{
+ register union Constant *ap = &app->Const,
+ *bp = &bpp->Const,
+ *cp = &cpp->Const;
+ int k;
+ double ad[2], bd[2], temp;
+ ftnint a, b;
+
+ cpp->vstg = 0;
+
+ if (ONEOF(type, MSKREAL|MSKCOMPLEX)) {
+ ad[0] = app->vstg ? atof(ap->cds[0]) : ap->cd[0];
+ bd[0] = bpp->vstg ? atof(bp->cds[0]) : bp->cd[0];
+ if (ISCOMPLEX(type)) {
+ ad[1] = app->vstg ? atof(ap->cds[1]) : ap->cd[1];
+ bd[1] = bpp->vstg ? atof(bp->cds[1]) : bp->cd[1];
+ }
+ }
+ switch(opcode)
+ {
+ case OPPLUS:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = ap->ci + bp->ci;
+ if (ap->ci != cp->ci - bp->ci)
+ intovfl();
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ cp->cd[1] = ad[1] + bd[1];
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] + bd[0];
+ break;
+ }
+ break;
+
+ case OPMINUS:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = ap->ci - bp->ci;
+ if (ap->ci != bp->ci + cp->ci)
+ intovfl();
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ cp->cd[1] = ad[1] - bd[1];
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] - bd[0];
+ break;
+ }
+ break;
+
+ case OPSTAR:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = (a = ap->ci) * (b = bp->ci);
+ if (a && cp->ci / a != b)
+ intovfl();
+ break;
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] * bd[0];
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ temp = ad[0] * bd[0] - ad[1] * bd[1] ;
+ cp->cd[1] = ad[0] * bd[1] + ad[1] * bd[0] ;
+ cp->cd[0] = temp;
+ break;
+ }
+ break;
+ case OPSLASH:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = ap->ci / bp->ci;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] / bd[0];
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ zdiv((dcomplex*)cp, (dcomplex*)ad, (dcomplex*)bd);
+ break;
+ }
+ break;
+
+ case OPMOD:
+ if( ISINT(type) )
+ {
+ cp->ci = ap->ci % bp->ci;
+ break;
+ }
+ else
+ Fatal("inline mod of noninteger");
+
+ case OPMIN2:
+ case OPDMIN:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = ap->ci <= bp->ci ? ap->ci : bp->ci;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] <= bd[0] ? ad[0] : bd[0];
+ break;
+ default:
+ Fatal("inline min of exected type");
+ }
+ break;
+
+ case OPMAX2:
+ case OPDMAX:
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp->ci = ap->ci >= bp->ci ? ap->ci : bp->ci;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ cp->cd[0] = ad[0] >= bd[0] ? ad[0] : bd[0];
+ break;
+ default:
+ Fatal("inline max of exected type");
+ }
+ break;
+
+ default: /* relational ops */
+ switch(type)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ if(ap->ci < bp->ci)
+ k = -1;
+ else if(ap->ci == bp->ci)
+ k = 0;
+ else k = 1;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ if(ad[0] < bd[0])
+ k = -1;
+ else if(ad[0] == bd[0])
+ k = 0;
+ else k = 1;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if(ad[0] == bd[0] &&
+ ad[1] == bd[1] )
+ k = 0;
+ else k = 1;
+ break;
+ case TYLOGICAL:
+ k = ap->ci - bp->ci;
+ }
+
+ switch(opcode)
+ {
+ case OPEQ:
+ cp->ci = (k == 0);
+ break;
+ case OPNE:
+ cp->ci = (k != 0);
+ break;
+ case OPGT:
+ cp->ci = (k == 1);
+ break;
+ case OPLT:
+ cp->ci = (k == -1);
+ break;
+ case OPGE:
+ cp->ci = (k >= 0);
+ break;
+ case OPLE:
+ cp->ci = (k <= 0);
+ break;
+ }
+ break;
+ }
+}
+
+
+
+/* conssgn - returns the sign of a Fortran constant */
+
+#ifdef KR_headers
+conssgn(p)
+ register expptr p;
+#else
+conssgn(register expptr p)
+#endif
+{
+ register char *s;
+
+ if( ! ISCONST(p) )
+ Fatal( "sgn(nonconstant)" );
+
+ switch(p->headblock.vtype)
+ {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ if(p->constblock.Const.ci > 0) return(1);
+ if(p->constblock.Const.ci < 0) return(-1);
+ return(0);
+
+ case TYREAL:
+ case TYDREAL:
+ if (p->constblock.vstg) {
+ s = p->constblock.Const.cds[0];
+ if (*s == '-')
+ return -1;
+ if (*s == '0')
+ return 0;
+ return 1;
+ }
+ if(p->constblock.Const.cd[0] > 0) return(1);
+ if(p->constblock.Const.cd[0] < 0) return(-1);
+ return(0);
+
+
+/* The sign of a complex number is 0 iff the number is 0 + 0i, else it's 1 */
+
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if (p->constblock.vstg)
+ return *p->constblock.Const.cds[0] != '0'
+ && *p->constblock.Const.cds[1] != '0';
+ return(p->constblock.Const.cd[0]!=0 || p->constblock.Const.cd[1]!=0);
+
+ default:
+ badtype( "conssgn", p->constblock.vtype);
+ }
+ /* NOT REACHED */ return 0;
+}
+
+char *powint[ ] = {
+ "pow_ii",
+#ifdef TYQUAD
+ "pow_qq",
+#endif
+ "pow_ri", "pow_di", "pow_ci", "pow_zi" };
+
+ LOCAL expptr
+#ifdef KR_headers
+mkpower(p)
+ register expptr p;
+#else
+mkpower(register expptr p)
+#endif
+{
+ register expptr q, lp, rp;
+ int ltype, rtype, mtype, tyi;
+
+ lp = p->exprblock.leftp;
+ rp = p->exprblock.rightp;
+ ltype = lp->headblock.vtype;
+ rtype = rp->headblock.vtype;
+
+ if (lp->tag == TADDR)
+ lp->addrblock.parenused = 0;
+
+ if (rp->tag == TADDR)
+ rp->addrblock.parenused = 0;
+
+ if(ISICON(rp))
+ {
+ if(rp->constblock.Const.ci == 0)
+ {
+ frexpr(p);
+ if( ISINT(ltype) )
+ return( ICON(1) );
+ else if (ISREAL (ltype))
+ return mkconv (ltype, ICON (1));
+ else
+ return( (expptr) putconst((Constp)
+ mkconv(ltype, ICON(1))) );
+ }
+ if(rp->constblock.Const.ci < 0)
+ {
+ if( ISINT(ltype) )
+ {
+ frexpr(p);
+ err("integer**negative");
+ return( errnode() );
+ }
+ rp->constblock.Const.ci = - rp->constblock.Const.ci;
+ p->exprblock.leftp = lp
+ = fixexpr((Exprp)mkexpr(OPSLASH, ICON(1), lp));
+ }
+ if(rp->constblock.Const.ci == 1)
+ {
+ frexpr(rp);
+ free( (charptr) p );
+ return(lp);
+ }
+
+ if( ONEOF(ltype, MSKINT|MSKREAL) ) {
+ p->exprblock.vtype = ltype;
+ return(p);
+ }
+ }
+ if( ISINT(rtype) )
+ {
+ if(ltype==TYSHORT && rtype==TYSHORT && (!ISCONST(lp) || tyint==TYSHORT) )
+ q = call2(TYSHORT, "pow_hh", lp, rp);
+ else {
+ if(ONEOF(ltype,M(TYINT1)|M(TYSHORT)))
+ {
+ ltype = TYLONG;
+ lp = mkconv(TYLONG,lp);
+ }
+#ifdef TYQUAD
+ if (ltype == TYQUAD)
+ rp = mkconv(TYQUAD,rp);
+ else
+#endif
+ rp = mkconv(TYLONG,rp);
+ if (ISCONST(rp)) {
+ tyi = tyint;
+ tyint = TYLONG;
+ rp = (expptr)putconst((Constp)rp);
+ tyint = tyi;
+ }
+ q = call2(ltype, powint[ltype-TYLONG], lp, rp);
+ }
+ }
+ else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) {
+ extern int callk_kludge;
+ callk_kludge = TYDREAL;
+ q = call2(mtype, "pow_dd", mkconv(TYDREAL,lp), mkconv(TYDREAL,rp));
+ callk_kludge = 0;
+ }
+ else {
+ q = call2(TYDCOMPLEX, "pow_zz",
+ mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp));
+ if(mtype == TYCOMPLEX)
+ q = mkconv(TYCOMPLEX, q);
+ }
+ free( (charptr) p );
+ return(q);
+}
+
+
+/* Complex Division. Same code as in Runtime Library
+*/
+
+
+ LOCAL void
+#ifdef KR_headers
+zdiv(c, a, b)
+ register dcomplex *c;
+ register dcomplex *a;
+ register dcomplex *b;
+#else
+zdiv(register dcomplex *c, register dcomplex *a, register dcomplex *b)
+#endif
+{
+ double ratio, den;
+ double abr, abi;
+
+ if( (abr = b->dreal) < 0.)
+ abr = - abr;
+ if( (abi = b->dimag) < 0.)
+ abi = - abi;
+ if( abr <= abi )
+ {
+ if(abi == 0)
+ Fatal("complex division by zero");
+ ratio = b->dreal / b->dimag ;
+ den = b->dimag * (1 + ratio*ratio);
+ c->dreal = (a->dreal*ratio + a->dimag) / den;
+ c->dimag = (a->dimag*ratio - a->dreal) / den;
+ }
+
+ else
+ {
+ ratio = b->dimag / b->dreal ;
+ den = b->dreal * (1 + ratio*ratio);
+ c->dreal = (a->dreal + a->dimag*ratio) / den;
+ c->dimag = (a->dimag - a->dreal*ratio) / den;
+ }
+}
+
+
+ void
+#ifdef KR_headers
+sserr(np) Namep np;
+#else
+sserr(Namep np)
+#endif
+{
+ errstr(np->vtype == TYCHAR
+ ? "substring of character array %.70s"
+ : "substring of noncharacter %.73s", np->fvarname);
+ }
diff --git a/usr.bin/f2c/f2c.1 b/usr.bin/f2c/f2c.1
new file mode 100644
index 0000000..4011fcb
--- /dev/null
+++ b/usr.bin/f2c/f2c.1
@@ -0,0 +1,301 @@
+.\" mdoc translation of the f2c.1 manpage (deprecated -man format) supplied
+.\" with f2c. The original manpage did not have a copyright statement, but
+.\" the file /usr/src/bin/f2c/Notice states:
+.\"
+.\"/****************************************************************
+.\"Copyright 1990 - 1997 by AT&T Bell Laboratories and Bellcore.
+.\"
+.\"Permission to use, copy, modify, and distribute this software
+.\"and its documentation for any purpose and without fee is hereby
+.\"granted, provided that the above copyright notice appear in all
+.\"copies and that both that the copyright notice and this
+.\"permission notice and warranty disclaimer appear in supporting
+.\"documentation, and that the names of AT&T Bell Laboratories or
+.\"Bellcore or any of their entities not be used in advertising or
+.\"publicity pertaining to distribution of the software without
+.\"specific, written prior permission.
+.\"
+.\"AT&T and Bellcore disclaim all warranties with regard to this
+.\"software, including all implied warranties of merchantability
+.\"and fitness. In no event shall AT&T or Bellcore be liable for
+.\"any special, indirect or consequential damages or any damages
+.\"whatsoever resulting from loss of use, data or profits, whether
+.\"in an action of contract, negligence or other tortious action,
+.\"arising out of or in connection with the use or performance of
+.\"this software.
+.\"****************************************************************/
+.\"
+.Dd April 19, 1996
+.Os "AT&T Bell Lab and Bellcore"
+.Dt F2C 1
+.Sh NAME
+.Nm f2c
+.Nd Convert Fortran 77 to C or C++
+.Sh SYNOPSIS
+.Nm f2c
+.Op Fl AaCcEfgpRrsUuw
+.Op Fl C++
+.Op Fl cd
+.Op Fl d Ar dir
+.Op Fl ec
+.Op Fl e1c
+.Op Fl ext
+.Op Fl h Ns Op Cm d
+.Op Fl \&I2
+.Op Fl \&i2
+.Op Fl i90
+.Op Fl kr Ns Op Cm d
+.Op Fl o Ar name
+.Op Fl onetrip
+.Op Fl P Ns Op Cm s
+.Op Fl r8
+.Op Fl 72
+.Op Fl T Ar dir
+.Op Fl w8
+.Op Fl W Ns Ar n
+.Op Fl z
+.Op Fl !bs
+.Op Fl !c
+.Op Fl !I
+.Op Fl !i8
+.Op Fl !it
+.Op Fl !P
+.Ar file ...
+.Sh DESCRIPTION
+.Nm F2c
+converts Fortran 77 source code in
+.Ar files
+with names ending in
+.So \&.f Sc
+or
+.So \&.F Sc
+to C (or C++) source files in the current directory, with
+.So \&.c Sc
+substituted for the final
+.So \&.f Sc
+or
+.So \&.F Sc .
+If no Fortran files are named,
+.Nm f2c
+reads Fortran from standard input and writes C on standard output.
+.Ar File
+names that end with
+.So \&.p Sc
+or
+.So \&.P Sc
+are taken to be prototype files, as produced by option
+.Fl P ,
+and are read first.
+.Sh OPTIONS
+.Bl -tag -width flag
+.It Fl A
+Produce ANSI C. Default is old-style C.
+.It Fl a
+Make local variables automatic rather than static unless they appear in a
+DATA , EQUIVALENCE , NAMELIST , or SAVE statement.
+.It Fl C
+Compile code to check that subscripts are within declared array bounds.
+.It Fl C++
+Output C++ code.
+.It Fl c
+Include original Fortran source as comments.
+.It Fl cd
+Do not recognize cdabs, cdcos, cdexp, cdlog, cdsin, and
+cdsqrt as synonyms for the double complex intrinsics
+zabs, zcos, zexp, zlog, zsin, and zsqrt, respectively.
+.It Fl d Ar dir
+Write `.c' files in directory
+.Ar dir
+instead of the current directory
+.It Fl E
+Declare uninitialized COMMON to be Extern (overridably defined in
+.Pa f2c.h
+as
+.Em extern
+).
+.It Fl ec
+Place uninitialized COMMON blocks in separate files:
+COMMON ABC appears in file abc_com.c .
+Option
+.Fl e1c
+bundles the separate files
+into the output file, with comments that give an unbundling
+.Xr sed 1
+script.
+.It Fl e1c
+See
+.Fl ec .
+.It Fl ext
+Complain about Fortran 77 extensions.
+.It Fl f
+Assume free-format input: accept text after column 72 and do not
+pad fixed-format lines shorter than 72 characters with blanks.
+.It Fl 72
+Treat text appearing after column 72 as an error.
+.It Fl g
+Include original Fortran line numbers in
+.Sy #line
+lines.
+.It Fl h Ns Op Cm d
+Emulate Fortran 66's treatment of Hollerith: try to align character strings on
+word (or, if the option is
+.Fl hd ,
+on double-word) boundaries.
+.It Fl \&I2
+Render INTEGER and LOGICAL as short, INTEGER*4 as long int. Assume the
+default
+.Em libF77
+and
+.Em libI77
+allow only INTEGER*4 (and no LOGICAL) variables in INQUIREs. Option
+.Fl \&I4
+confirms the default rendering of INTEGER as long int.
+.It Fl \&i2
+Similar to
+.Fl \&I2 ,
+but assume a modified
+.Em libF77
+and
+.Em libI77
+(compiled with
+.Fl Df2c_i2 ),
+so INTEGER and LOGICAL variables may be assigned by INQUIRE and array lengths
+are stored in short ints
+.It Fl i90
+Do not recognize the Fortran 90 bit-manipulation intrinsics btest,
+iand, ibclr, ibits, ibset, ieor, ior, ishft, and ishftc.
+.It Fl kr Ns Op Cm d
+Use temporary values to enforce Fortran expression evaluation
+where K&R (first edition) parenthesization rules allow rearrangement.
+If the option is
+.Fl krd ,
+use double precision temporaries even for single-precision operands.
+.It Fl o Ar name
+The C source code is written into file
+.Ar name .
+.It Fl onetrip
+Compile DO loops that are performed at least once if reached. (Fortran 77 DO
+loops are not performed at all if the upper limit is smaller than the lower
+limit.)
+.It Fl P Ns Op Cm s
+Write a
+.Ar file Ns \&.P
+of ANSI (or C++) prototypes for definitions in each input
+.Ar file Ns \&.f
+or
+.Ar file Ns \&.F .
+When reading Fortran from standard input, write prototypes at the beginning of
+standard output. Option
+.Fl Ps
+implies
+.Fl P
+and gives exit status 4 if rerunning
+.Nm f2c
+may change prototypes or declarations.
+.It Fl p
+Supply preprocessor definitions to make common-block members look like local
+variables.
+.It Fl R
+Do not promote REAL functions and operations to DOUBLE PRECISION. Option
+.Fl !R
+confirms the default, which imitates Fortran 77.
+.It Fl r
+Cast values of REAL functions (including intrinsics) to REAL.
+.It Fl r8
+Promote REAL to DOUBLE PRECISION, COMPLEX to DOUBLE COMPLEX.
+.It Fl s
+Preserve multidimensional subscripts.
+.It Fl T Ar dir
+Put temporary files in directory
+.Ar dir .
+.It Fl U
+Honor the case of variable and external names. Fortran keywords must be in
+.Em lower
+case.
+.It Fl u
+Make the default type of a variable
+.So undefined Sc
+rather than using the default Fortran rules.
+.It Fl w
+Suppress all warning messages. If the option is
+.Fl w66 ,
+only Fortran 66 compatibility warnings are suppressed.
+.It Fl w8
+Suppress warnings when COMMON or EQUIVALENCE forces odd-word alignment of
+doubles.
+.It Fl W Ns Ar n
+Assume
+.Ar n
+characters/word (default 4) when initializing numeric variables with character
+data.
+.It Fl z
+Do not implicitly recognize DOUBLE COMPLEX.
+.It Fl !bs
+Do not recognize
+.Em backslash
+escapes
+(\e", \e', \e0, \e\e, \eb, \ef, \en, \er, \et, \ev) in character strings.
+.It Fl !c
+Inhibit C output, but produce
+.Fl P
+output.
+.It Fl !I
+Reject
+.Sy include
+statements.
+.It Fl !i8
+Disallow INTEGER*8.
+.It Fl !it
+Don't infer types of untyped EXTERNAL procedures from use as parameters to
+previously defined or prototyped procedures.
+.It Fl !P
+Do not attempt to infer ANSI or C++ prototypes from usage.
+.El
+.Pp
+Object code should be loaded by with
+.Xr ld 1
+or
+.Xr cc 1
+and the following libraries need to specified:
+.Fl lf2c lm .
+.Sh FILES
+.Ar file Ns \&.[fF]
+input file
+
+.Ar file Ns \&.c
+output file
+
+.Pa /usr/include/f2c.h
+header file
+
+.Pa /usr/lib/libf2c.a
+intrinsic function library and Fortran 77 I/O library
+
+.Sh "SEE ALSO"
+.Rs
+.%A S. I. Feldman
+.%A P. J. Weinberger
+.%T A Portable Fortran 77 Compiler
+.%B UNIX Time Sharing System Programmer's Manual
+.%V Volume 2
+.%D 1990
+.%O AT&T Bell Laboratories
+.%N Tenth Edition
+.Re
+.Sh DIAGNOSTICS
+The diagnostics produced by
+.Nm f2c
+are intended to be
+self-explanatory.
+.Sh BUGS
+Floating-point constant expressions are simplified in
+the floating-point arithmetic of the machine running
+.Nm f2c
+so they are typically accurate to at most 16 or 17 decimal places.
+.Pp
+Untypable EXTERNAL functions are declared int.
+.Pp
+There are several undocumented valid options for
+.Nm f2c .
+These options are discussed at the top of
+.Pa /usr/src/usr.bin/f2c/main.c .
diff --git a/usr.bin/f2c/f2c.h b/usr.bin/f2c/f2c.h
new file mode 100644
index 0000000..6514cd9
--- /dev/null
+++ b/usr.bin/f2c/f2c.h
@@ -0,0 +1,223 @@
+/* f2c.h -- Standard Fortran to C header file */
+
+/** barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed."
+
+ - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */
+
+#ifndef F2C_INCLUDE
+#define F2C_INCLUDE
+
+typedef long int integer;
+typedef unsigned long uinteger;
+typedef char *address;
+typedef short int shortint;
+typedef float real;
+typedef double doublereal;
+typedef struct { real r, i; } complex;
+typedef struct { doublereal r, i; } doublecomplex;
+typedef long int logical;
+typedef short int shortlogical;
+typedef char logical1;
+typedef char integer1;
+#if 0 /* Adjust for integer*8. */
+typedef long long longint; /* system-dependent */
+typedef unsigned long long ulongint; /* system-dependent */
+#define qbit_clear(a,b) ((a) & ~((ulongint)1 << (b)))
+#define qbit_set(a,b) ((a) | ((ulongint)1 << (b)))
+#endif
+
+#define TRUE_ (1)
+#define FALSE_ (0)
+
+/* Extern is for use with -E */
+#ifndef Extern
+#define Extern extern
+#endif
+
+/* I/O stuff */
+
+#ifdef f2c_i2
+/* for -i2 */
+typedef short flag;
+typedef short ftnlen;
+typedef short ftnint;
+#else
+typedef long int flag;
+typedef long int ftnlen;
+typedef long int ftnint;
+#endif
+
+/*external read, write*/
+typedef struct
+{ flag cierr;
+ ftnint ciunit;
+ flag ciend;
+ char *cifmt;
+ ftnint cirec;
+} cilist;
+
+/*internal read, write*/
+typedef struct
+{ flag icierr;
+ char *iciunit;
+ flag iciend;
+ char *icifmt;
+ ftnint icirlen;
+ ftnint icirnum;
+} icilist;
+
+/*open*/
+typedef struct
+{ flag oerr;
+ ftnint ounit;
+ char *ofnm;
+ ftnlen ofnmlen;
+ char *osta;
+ char *oacc;
+ char *ofm;
+ ftnint orl;
+ char *oblnk;
+} olist;
+
+/*close*/
+typedef struct
+{ flag cerr;
+ ftnint cunit;
+ char *csta;
+} cllist;
+
+/*rewind, backspace, endfile*/
+typedef struct
+{ flag aerr;
+ ftnint aunit;
+} alist;
+
+/* inquire */
+typedef struct
+{ flag inerr;
+ ftnint inunit;
+ char *infile;
+ ftnlen infilen;
+ ftnint *inex; /*parameters in standard's order*/
+ ftnint *inopen;
+ ftnint *innum;
+ ftnint *innamed;
+ char *inname;
+ ftnlen innamlen;
+ char *inacc;
+ ftnlen inacclen;
+ char *inseq;
+ ftnlen inseqlen;
+ char *indir;
+ ftnlen indirlen;
+ char *infmt;
+ ftnlen infmtlen;
+ char *inform;
+ ftnint informlen;
+ char *inunf;
+ ftnlen inunflen;
+ ftnint *inrecl;
+ ftnint *innrec;
+ char *inblank;
+ ftnlen inblanklen;
+} inlist;
+
+#define VOID void
+
+union Multitype { /* for multiple entry points */
+ integer1 g;
+ shortint h;
+ integer i;
+ /* longint j; */
+ real r;
+ doublereal d;
+ complex c;
+ doublecomplex z;
+ };
+
+typedef union Multitype Multitype;
+
+/*typedef long int Long;*/ /* No longer used; formerly in Namelist */
+
+struct Vardesc { /* for Namelist */
+ char *name;
+ char *addr;
+ ftnlen *dims;
+ int type;
+ };
+typedef struct Vardesc Vardesc;
+
+struct Namelist {
+ char *name;
+ Vardesc **vars;
+ int nvars;
+ };
+typedef struct Namelist Namelist;
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+#define dabs(x) (doublereal)abs(x)
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+#define dmin(a,b) (doublereal)min(a,b)
+#define dmax(a,b) (doublereal)max(a,b)
+#define bit_test(a,b) ((a) >> (b) & 1)
+#define bit_clear(a,b) ((a) & ~((uinteger)1 << (b)))
+#define bit_set(a,b) ((a) | ((uinteger)1 << (b)))
+
+/* procedure parameter types for -A and -C++ */
+
+#define F2C_proc_par_types 1
+#ifdef __cplusplus
+typedef int /* Unknown procedure type */ (*U_fp)(...);
+typedef shortint (*J_fp)(...);
+typedef integer (*I_fp)(...);
+typedef real (*R_fp)(...);
+typedef doublereal (*D_fp)(...), (*E_fp)(...);
+typedef /* Complex */ VOID (*C_fp)(...);
+typedef /* Double Complex */ VOID (*Z_fp)(...);
+typedef logical (*L_fp)(...);
+typedef shortlogical (*K_fp)(...);
+typedef /* Character */ VOID (*H_fp)(...);
+typedef /* Subroutine */ int (*S_fp)(...);
+#else
+typedef int /* Unknown procedure type */ (*U_fp)();
+typedef shortint (*J_fp)();
+typedef integer (*I_fp)();
+typedef real (*R_fp)();
+typedef doublereal (*D_fp)(), (*E_fp)();
+typedef /* Complex */ VOID (*C_fp)();
+typedef /* Double Complex */ VOID (*Z_fp)();
+typedef logical (*L_fp)();
+typedef shortlogical (*K_fp)();
+typedef /* Character */ VOID (*H_fp)();
+typedef /* Subroutine */ int (*S_fp)();
+#endif
+/* E_fp is for real functions when -R is not specified */
+typedef VOID C_f; /* complex function */
+typedef VOID H_f; /* character function */
+typedef VOID Z_f; /* double complex function */
+typedef doublereal E_f; /* real function with -R not specified */
+
+/* undef any lower-case symbols that your C compiler predefines, e.g.: */
+
+#ifndef Skip_f2c_Undefs
+#undef cray
+#undef gcos
+#undef mc68010
+#undef mc68020
+#undef mips
+#undef pdp11
+#undef sgi
+#undef sparc
+#undef sun
+#undef sun2
+#undef sun3
+#undef sun4
+#undef u370
+#undef u3b
+#undef u3b2
+#undef u3b5
+#undef unix
+#undef vax
+#endif
+#endif
diff --git a/usr.bin/f2c/format.c b/usr.bin/f2c/format.c
new file mode 100644
index 0000000..bcd9b99
--- /dev/null
+++ b/usr.bin/f2c/format.c
@@ -0,0 +1,2524 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* Format.c -- this file takes an intermediate file (generated by pass 1
+ of the translator) and some state information about the contents of that
+ file, and generates C program text. */
+
+#include "defs.h"
+#include "p1defs.h"
+#include "format.h"
+#include "output.h"
+#include "names.h"
+#include "iob.h"
+
+int c_output_line_length = DEF_C_LINE_LENGTH;
+
+int last_was_label; /* Boolean used to generate semicolons
+ when a label terminates a block */
+static char this_proc_name[52]; /* Name of the current procedure. This is
+ probably too simplistic to handle
+ multiple entry points */
+
+static tagptr do_format Argdcl((FILEP, FILEP));
+static void do_p1_1while Argdcl((FILEP));
+static void do_p1_2while Argdcl((FILEP, FILEP));
+static tagptr do_p1_addr Argdcl((FILEP, FILEP));
+static void do_p1_asgoto Argdcl((FILEP, FILEP));
+static tagptr do_p1_charp Argdcl((FILEP));
+static void do_p1_comment Argdcl((FILEP, FILEP));
+static void do_p1_comp_goto Argdcl((FILEP, FILEP));
+static tagptr do_p1_const Argdcl((FILEP));
+static void do_p1_elif Argdcl((FILEP, FILEP));
+static void do_p1_else Argdcl((FILEP));
+static void do_p1_elseifstart Argdcl((FILEP));
+static void do_p1_end_for Argdcl((FILEP));
+static void do_p1_endelse Argdcl((FILEP));
+static void do_p1_endif Argdcl((FILEP));
+static tagptr do_p1_expr Argdcl((FILEP, FILEP));
+static tagptr do_p1_extern Argdcl((FILEP));
+static void do_p1_for Argdcl((FILEP, FILEP));
+static void do_p1_fortran Argdcl((FILEP, FILEP));
+static void do_p1_goto Argdcl((FILEP, FILEP));
+static tagptr do_p1_head Argdcl((FILEP, FILEP));
+static tagptr do_p1_ident Argdcl((FILEP));
+static void do_p1_if Argdcl((FILEP, FILEP));
+static void do_p1_label Argdcl((FILEP, FILEP));
+static tagptr do_p1_list Argdcl((FILEP, FILEP));
+static tagptr do_p1_literal Argdcl((FILEP));
+static tagptr do_p1_name_pointer Argdcl((FILEP));
+static void do_p1_set_line Argdcl((FILEP));
+static void do_p1_subr_ret Argdcl((FILEP, FILEP));
+static int get_p1_token Argdcl((FILEP));
+static int p1get_const Argdcl((FILEP, int, Constp*));
+static int p1getd Argdcl((FILEP, long int*));
+static int p1getf Argdcl((FILEP, char**));
+static int p1getn Argdcl((FILEP, int, char**));
+static int p1gets Argdcl((FILEP, char*, int));
+static void proto Argdcl((FILEP, Argtypes*, char*));
+
+extern chainp assigned_fmts;
+char filename[P1_FILENAME_MAX];
+extern int gflag, sharp_line;
+int gflag1;
+extern char *parens;
+
+ void
+start_formatting(Void)
+{
+ FILE *infile;
+ static int wrote_one = 0;
+ extern int usedefsforcommon;
+ extern char *p1_file, *p1_bakfile;
+
+ this_proc_name[0] = '\0';
+ last_was_label = 0;
+ ei_next = ei_first;
+ wh_next = wh_first;
+
+ (void) fclose (pass1_file);
+ if ((infile = fopen (p1_file, binread)) == NULL)
+ Fatal("start_formatting: couldn't open the intermediate file\n");
+
+ if (wrote_one)
+ nice_printf (c_file, "\n");
+
+ while (!feof (infile)) {
+ expptr this_expr;
+
+ this_expr = do_format (infile, c_file);
+ if (this_expr) {
+ out_and_free_statement (c_file, this_expr);
+ } /* if this_expr */
+ } /* while !feof infile */
+
+ (void) fclose (infile);
+
+ if (last_was_label)
+ nice_printf (c_file, ";\n");
+
+ prev_tab (c_file);
+ gflag1 = sharp_line = 0;
+ if (this_proc_name[0])
+ nice_printf (c_file, "} /* %s */\n", this_proc_name);
+
+
+/* Write the #undefs for common variable reference */
+
+ if (usedefsforcommon) {
+ Extsym *ext;
+ int did_one = 0;
+
+ for (ext = extsymtab; ext < nextext; ext++)
+ if (ext -> extstg == STGCOMMON && ext -> used_here) {
+ ext -> used_here = 0;
+ if (!did_one)
+ nice_printf (c_file, "\n");
+ wr_abbrevs(c_file, 0, ext->extp);
+ did_one = 1;
+ ext -> extp = CHNULL;
+ } /* if */
+
+ if (did_one)
+ nice_printf (c_file, "\n");
+ } /* if usedefsforcommon */
+
+ other_undefs(c_file);
+
+ wrote_one = 1;
+
+/* For debugging only */
+
+ if (debugflag && (pass1_file = fopen (p1_bakfile, binwrite)))
+ if (infile = fopen (p1_file, binread)) {
+ ffilecopy (infile, pass1_file);
+ fclose (infile);
+ fclose (pass1_file);
+ } /* if infile */
+
+/* End of "debugging only" */
+
+ scrub(p1_file); /* optionally unlink */
+
+ if ((pass1_file = fopen (p1_file, binwrite)) == NULL)
+ err ("start_formatting: couldn't reopen the pass1 file");
+
+} /* start_formatting */
+
+
+ static void
+#ifdef KR_headers
+put_semi(outfile)
+ FILE *outfile;
+#else
+put_semi(FILE *outfile)
+#endif
+{
+ nice_printf (outfile, ";\n");
+ last_was_label = 0;
+ }
+
+#define SEM_CHECK(x) if (last_was_label) put_semi(x)
+
+/* do_format -- takes an input stream (a file in pass1 format) and writes
+ the appropriate C code to outfile when possible. When reading an
+ expression, the expression tree is returned instead. */
+
+ static expptr
+#ifdef KR_headers
+do_format(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_format(FILE *infile, FILE *outfile)
+#endif
+{
+ int token_type, was_c_token;
+ expptr retval = ENULL;
+
+ token_type = get_p1_token (infile);
+ was_c_token = 1;
+ switch (token_type) {
+ case P1_COMMENT:
+ do_p1_comment (infile, outfile);
+ was_c_token = 0;
+ break;
+ case P1_SET_LINE:
+ do_p1_set_line (infile);
+ was_c_token = 0;
+ break;
+ case P1_FILENAME:
+ p1gets(infile, filename, P1_FILENAME_MAX);
+ was_c_token = 0;
+ break;
+ case P1_NAME_POINTER:
+ retval = do_p1_name_pointer (infile);
+ break;
+ case P1_CONST:
+ retval = do_p1_const (infile);
+ break;
+ case P1_EXPR:
+ retval = do_p1_expr (infile, outfile);
+ break;
+ case P1_IDENT:
+ retval = do_p1_ident(infile);
+ break;
+ case P1_CHARP:
+ retval = do_p1_charp(infile);
+ break;
+ case P1_EXTERN:
+ retval = do_p1_extern (infile);
+ break;
+ case P1_HEAD:
+ gflag1 = sharp_line = 0;
+ retval = do_p1_head (infile, outfile);
+ gflag1 = sharp_line = gflag;
+ break;
+ case P1_LIST:
+ retval = do_p1_list (infile, outfile);
+ break;
+ case P1_LITERAL:
+ retval = do_p1_literal (infile);
+ break;
+ case P1_LABEL:
+ do_p1_label (infile, outfile);
+ /* last_was_label = 1; -- now set in do_p1_label */
+ was_c_token = 0;
+ break;
+ case P1_ASGOTO:
+ do_p1_asgoto (infile, outfile);
+ break;
+ case P1_GOTO:
+ do_p1_goto (infile, outfile);
+ break;
+ case P1_IF:
+ do_p1_if (infile, outfile);
+ break;
+ case P1_ELSE:
+ SEM_CHECK(outfile);
+ do_p1_else (outfile);
+ break;
+ case P1_ELIF:
+ SEM_CHECK(outfile);
+ do_p1_elif (infile, outfile);
+ break;
+ case P1_ENDIF:
+ SEM_CHECK(outfile);
+ do_p1_endif (outfile);
+ break;
+ case P1_ENDELSE:
+ SEM_CHECK(outfile);
+ do_p1_endelse (outfile);
+ break;
+ case P1_ADDR:
+ retval = do_p1_addr (infile, outfile);
+ break;
+ case P1_SUBR_RET:
+ do_p1_subr_ret (infile, outfile);
+ break;
+ case P1_COMP_GOTO:
+ do_p1_comp_goto (infile, outfile);
+ break;
+ case P1_FOR:
+ do_p1_for (infile, outfile);
+ break;
+ case P1_ENDFOR:
+ SEM_CHECK(outfile);
+ do_p1_end_for (outfile);
+ break;
+ case P1_WHILE1START:
+ do_p1_1while(outfile);
+ break;
+ case P1_WHILE2START:
+ do_p1_2while(infile, outfile);
+ break;
+ case P1_PROCODE:
+ procode(outfile);
+ break;
+ case P1_ELSEIFSTART:
+ SEM_CHECK(outfile);
+ do_p1_elseifstart(outfile);
+ break;
+ case P1_FORTRAN:
+ do_p1_fortran(infile, outfile);
+ /* no break; */
+ case P1_EOF:
+ was_c_token = 0;
+ break;
+ case P1_UNKNOWN:
+ Fatal("do_format: Unknown token type in intermediate file");
+ break;
+ default:
+ Fatal("do_format: Bad token type in intermediate file");
+ break;
+ } /* switch */
+
+ if (was_c_token)
+ last_was_label = 0;
+ return retval;
+} /* do_format */
+
+
+ static void
+#ifdef KR_headers
+do_p1_comment(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_comment(FILE *infile, FILE *outfile)
+#endif
+{
+ extern int c_output_line_length, in_comment;
+
+ char storage[COMMENT_BUFFER_SIZE + 1];
+ int length;
+
+ if (!p1gets(infile, storage, COMMENT_BUFFER_SIZE + 1))
+ return;
+
+ length = strlen (storage);
+
+ gflag1 = sharp_line = 0;
+ in_comment = 1;
+ if (length > c_output_line_length - 6)
+ margin_printf(outfile, "/*%s*/\n", storage);
+ else
+ margin_printf(outfile, length ? "/* %s */\n" : "\n", storage);
+ in_comment = 0;
+ gflag1 = sharp_line = gflag;
+} /* do_p1_comment */
+
+ static void
+#ifdef KR_headers
+do_p1_set_line(infile)
+ FILE *infile;
+#else
+do_p1_set_line(FILE *infile)
+#endif
+{
+ int status;
+ long new_line_number = -1;
+
+ status = p1getd (infile, &new_line_number);
+
+ if (status == EOF)
+ err ("do_p1_set_line: Missing line number at end of file\n");
+ else if (status == 0 || new_line_number == -1)
+ errl("do_p1_set_line: Illegal line number in intermediate file: %ld\n",
+ new_line_number);
+ else {
+ lineno = new_line_number;
+ }
+} /* do_p1_set_line */
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_name_pointer(infile)
+ FILE *infile;
+#else
+do_p1_name_pointer(FILE *infile)
+#endif
+{
+ Namep namep = (Namep) NULL;
+ int status;
+
+ status = p1getd (infile, (long *) &namep);
+
+ if (status == EOF)
+ err ("do_p1_name_pointer: Missing pointer at end of file\n");
+ else if (status == 0 || namep == (Namep) NULL)
+ erri ("do_p1_name_pointer: Illegal name pointer in p1 file: '%x'\n",
+ (int) namep);
+
+ return (expptr) namep;
+} /* do_p1_name_pointer */
+
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_const(infile)
+ FILE *infile;
+#else
+do_p1_const(FILE *infile)
+#endif
+{
+ struct Constblock *c = (struct Constblock *) NULL;
+ long type = -1;
+ int status;
+
+ status = p1getd (infile, &type);
+
+ if (status == EOF)
+ err ("do_p1_const: Missing constant type at end of file\n");
+ else if (status == 0)
+ errl("do_p1_const: Illegal constant type in p1 file: %ld\n", type);
+ else {
+ status = p1get_const (infile, (int)type, &c);
+
+ if (status == EOF) {
+ err ("do_p1_const: Missing constant value at end of file\n");
+ c = (struct Constblock *) NULL;
+ } else if (status == 0) {
+ err ("do_p1_const: Illegal constant value in p1 file\n");
+ c = (struct Constblock *) NULL;
+ } /* else */
+ } /* else */
+ return (expptr) c;
+} /* do_p1_const */
+
+ void
+#ifdef KR_headers
+addrlit(addrp)
+ Addrp addrp;
+#else
+addrlit(Addrp addrp)
+#endif
+{
+ long memno = addrp->memno;
+ struct Literal *litp, *lastlit;
+
+ lastlit = litpool + nliterals;
+ for (litp = litpool; litp < lastlit; litp++)
+ if (litp->litnum == memno) {
+ addrp->vtype = litp->littype;
+ *((union Constant *) &(addrp->user)) =
+ *((union Constant *) &(litp->litval));
+ addrp->vstg = STGMEMNO;
+ return;
+ }
+ err("addrlit failure!");
+ }
+
+ static expptr
+#ifdef KR_headers
+do_p1_literal(infile)
+ FILE *infile;
+#else
+do_p1_literal(FILE *infile)
+#endif
+{
+ int status;
+ long memno;
+ Addrp addrp;
+
+ status = p1getd (infile, &memno);
+
+ if (status == EOF)
+ err ("do_p1_literal: Missing memno at end of file");
+ else if (status == 0)
+ err ("do_p1_literal: Missing memno in p1 file");
+ else {
+ addrp = ALLOC (Addrblock);
+ addrp -> tag = TADDR;
+ addrp -> vtype = TYUNKNOWN;
+ addrp -> Field = NULL;
+ addrp -> memno = memno;
+ addrlit(addrp);
+ addrp -> uname_tag = UNAM_CONST;
+ } /* else */
+
+ return (expptr) addrp;
+} /* do_p1_literal */
+
+
+ static void
+#ifdef KR_headers
+do_p1_label(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_label(FILE *infile, FILE *outfile)
+#endif
+{
+ int status;
+ ftnint stateno;
+ struct Labelblock *L;
+ char *fmt;
+
+ status = p1getd (infile, &stateno);
+
+ if (status == EOF)
+ err ("do_p1_label: Missing label at end of file");
+ else if (status == 0)
+ err ("do_p1_label: Missing label in p1 file ");
+ else if (stateno < 0) { /* entry */
+ margin_printf(outfile, "\n%s:\n", user_label(stateno));
+ last_was_label = 1;
+ }
+ else {
+ L = labeltab + stateno;
+ if (L->labused) {
+ fmt = "%s:\n";
+ last_was_label = 1;
+ }
+ else
+ fmt = "/* %s: */\n";
+ margin_printf(outfile, fmt, user_label(L->stateno));
+ } /* else */
+} /* do_p1_label */
+
+
+
+ static void
+#ifdef KR_headers
+do_p1_asgoto(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_asgoto(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr expr;
+
+ expr = do_format (infile, outfile);
+ out_asgoto (outfile, expr);
+
+} /* do_p1_asgoto */
+
+
+ static void
+#ifdef KR_headers
+do_p1_goto(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_goto(FILE *infile, FILE *outfile)
+#endif
+{
+ int status;
+ long stateno;
+
+ status = p1getd (infile, &stateno);
+
+ if (status == EOF)
+ err ("do_p1_goto: Missing goto label at end of file");
+ else if (status == 0)
+ err ("do_p1_goto: Missing goto label in p1 file");
+ else {
+ nice_printf (outfile, "goto %s;\n", user_label (stateno));
+ } /* else */
+} /* do_p1_goto */
+
+
+ static void
+#ifdef KR_headers
+do_p1_if(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_if(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr cond;
+
+ do {
+ cond = do_format (infile, outfile);
+ } while (cond == ENULL);
+
+ out_if (outfile, cond);
+} /* do_p1_if */
+
+
+ static void
+#ifdef KR_headers
+do_p1_else(outfile)
+ FILE *outfile;
+#else
+do_p1_else(FILE *outfile)
+#endif
+{
+ out_else (outfile);
+} /* do_p1_else */
+
+
+ static void
+#ifdef KR_headers
+do_p1_elif(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_elif(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr cond;
+
+ do {
+ cond = do_format (infile, outfile);
+ } while (cond == ENULL);
+
+ elif_out (outfile, cond);
+} /* do_p1_elif */
+
+ static void
+#ifdef KR_headers
+do_p1_endif(outfile)
+ FILE *outfile;
+#else
+do_p1_endif(FILE *outfile)
+#endif
+{
+ endif_out (outfile);
+} /* do_p1_endif */
+
+
+ static void
+#ifdef KR_headers
+do_p1_endelse(outfile)
+ FILE *outfile;
+#else
+do_p1_endelse(FILE *outfile)
+#endif
+{
+ end_else_out (outfile);
+} /* do_p1_endelse */
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_addr(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_addr(FILE *infile, FILE *outfile)
+#endif
+{
+ Addrp addrp = (Addrp) NULL;
+ int status;
+
+ status = p1getn (infile, (int)sizeof(struct Addrblock), (char **) &addrp);
+
+ if (status == EOF)
+ err ("do_p1_addr: Missing Addrp at end of file");
+ else if (status == 0)
+ err ("do_p1_addr: Missing Addrp in p1 file");
+ else if (addrp == (Addrp) NULL)
+ err ("do_p1_addr: Null addrp in p1 file");
+ else if (addrp -> tag != TADDR)
+ erri ("do_p1_addr: bad tag in p1 file '%d'", addrp -> tag);
+ else {
+ addrp -> vleng = do_format (infile, outfile);
+ addrp -> memoffset = do_format (infile, outfile);
+ }
+
+ return (expptr) addrp;
+} /* do_p1_addr */
+
+
+
+ static void
+#ifdef KR_headers
+do_p1_subr_ret(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_subr_ret(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr retval;
+
+ nice_printf (outfile, "return ");
+ retval = do_format (infile, outfile);
+ if (!multitype)
+ if (retval)
+ expr_out (outfile, retval);
+
+ nice_printf (outfile, ";\n");
+} /* do_p1_subr_ret */
+
+
+
+ static void
+#ifdef KR_headers
+do_p1_comp_goto(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_comp_goto(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr index;
+ expptr labels;
+
+ index = do_format (infile, outfile);
+
+ if (index == ENULL) {
+ err ("do_p1_comp_goto: no expression for computed goto");
+ return;
+ } /* if index == ENULL */
+
+ labels = do_format (infile, outfile);
+
+ if (labels && labels -> tag != TLIST)
+ erri ("do_p1_comp_goto: expected list, got tag '%d'", labels -> tag);
+ else
+ compgoto_out (outfile, index, labels);
+} /* do_p1_comp_goto */
+
+
+ static void
+#ifdef KR_headers
+do_p1_for(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_for(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr init, test, inc;
+
+ init = do_format (infile, outfile);
+ test = do_format (infile, outfile);
+ inc = do_format (infile, outfile);
+
+ out_for (outfile, init, test, inc);
+} /* do_p1_for */
+
+ static void
+#ifdef KR_headers
+do_p1_end_for(outfile)
+ FILE *outfile;
+#else
+do_p1_end_for(FILE *outfile)
+#endif
+{
+ out_end_for (outfile);
+} /* do_p1_end_for */
+
+
+ static void
+#ifdef KR_headers
+do_p1_fortran(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_fortran(FILE *infile, FILE *outfile)
+#endif
+{
+ char buf[P1_STMTBUFSIZE];
+ if (!p1gets(infile, buf, P1_STMTBUFSIZE))
+ return;
+ /* bypass nice_printf nonsense */
+ fprintf(outfile, "/*< %s >*/\n", buf+1); /* + 1 to skip by '$' */
+ }
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_expr(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_expr(FILE *infile, FILE *outfile)
+#endif
+{
+ int status;
+ long opcode, type;
+ struct Exprblock *result = (struct Exprblock *) NULL;
+
+ status = p1getd (infile, &opcode);
+
+ if (status == EOF)
+ err ("do_p1_expr: Missing expr opcode at end of file");
+ else if (status == 0)
+ err ("do_p1_expr: Missing expr opcode in p1 file");
+ else {
+
+ status = p1getd (infile, &type);
+
+ if (status == EOF)
+ err ("do_p1_expr: Missing expr type at end of file");
+ else if (status == 0)
+ err ("do_p1_expr: Missing expr type in p1 file");
+ else if (opcode == 0)
+ return ENULL;
+ else {
+ result = ALLOC (Exprblock);
+
+ result -> tag = TEXPR;
+ result -> vtype = type;
+ result -> opcode = opcode;
+ result -> vleng = do_format (infile, outfile);
+
+ if (is_unary_op (opcode))
+ result -> leftp = do_format (infile, outfile);
+ else if (is_binary_op (opcode)) {
+ result -> leftp = do_format (infile, outfile);
+ result -> rightp = do_format (infile, outfile);
+ } else
+ errl("do_p1_expr: Illegal opcode %ld", opcode);
+ } /* else */
+ } /* else */
+
+ return (expptr) result;
+} /* do_p1_expr */
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_ident(infile)
+ FILE *infile;
+#else
+do_p1_ident(FILE *infile)
+#endif
+{
+ Addrp addrp;
+ int status;
+ long vtype, vstg;
+
+ addrp = ALLOC (Addrblock);
+ addrp -> tag = TADDR;
+
+ status = p1getd (infile, &vtype);
+ if (status == EOF)
+ err ("do_p1_ident: Missing identifier type at end of file\n");
+ else if (status == 0 || vtype < 0 || vtype >= NTYPES)
+ errl("do_p1_ident: Bad type in intermediate file: %ld\n", vtype);
+ else
+ addrp -> vtype = vtype;
+
+ status = p1getd (infile, &vstg);
+ if (status == EOF)
+ err ("do_p1_ident: Missing identifier storage at end of file\n");
+ else if (status == 0 || vstg < 0 || vstg > STGNULL)
+ errl("do_p1_ident: Bad storage in intermediate file: %ld\n", vtype);
+ else
+ addrp -> vstg = vstg;
+
+ status = p1gets(infile, addrp->user.ident, IDENT_LEN);
+
+ if (status == EOF)
+ err ("do_p1_ident: Missing ident string at end of file");
+ else if (status == 0)
+ err ("do_p1_ident: Missing ident string in intermediate file");
+ addrp->uname_tag = UNAM_IDENT;
+ return (expptr) addrp;
+} /* do_p1_ident */
+
+ static expptr
+#ifdef KR_headers
+do_p1_charp(infile)
+ FILE *infile;
+#else
+do_p1_charp(FILE *infile)
+#endif
+{
+ Addrp addrp;
+ int status;
+ long vtype, vstg;
+ char buf[64];
+
+ addrp = ALLOC (Addrblock);
+ addrp -> tag = TADDR;
+
+ status = p1getd (infile, &vtype);
+ if (status == EOF)
+ err ("do_p1_ident: Missing identifier type at end of file\n");
+ else if (status == 0 || vtype < 0 || vtype >= NTYPES)
+ errl("do_p1_ident: Bad type in intermediate file: %ld\n", vtype);
+ else
+ addrp -> vtype = vtype;
+
+ status = p1getd (infile, &vstg);
+ if (status == EOF)
+ err ("do_p1_ident: Missing identifier storage at end of file\n");
+ else if (status == 0 || vstg < 0 || vstg > STGNULL)
+ errl("do_p1_ident: Bad storage in intermediate file: %ld\n", vtype);
+ else
+ addrp -> vstg = vstg;
+
+ status = p1gets(infile, buf, (int)sizeof(buf));
+
+ if (status == EOF)
+ err ("do_p1_ident: Missing charp ident string at end of file");
+ else if (status == 0)
+ err ("do_p1_ident: Missing charp ident string in intermediate file");
+ addrp->uname_tag = UNAM_CHARP;
+ addrp->user.Charp = strcpy(mem(strlen(buf)+1,0), buf);
+ return (expptr) addrp;
+}
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_extern(infile)
+ FILE *infile;
+#else
+do_p1_extern(FILE *infile)
+#endif
+{
+ Addrp addrp;
+
+ addrp = ALLOC (Addrblock);
+ if (addrp) {
+ int status;
+
+ addrp->tag = TADDR;
+ addrp->vstg = STGEXT;
+ addrp->uname_tag = UNAM_EXTERN;
+ status = p1getd (infile, &(addrp -> memno));
+ if (status == EOF)
+ err ("do_p1_extern: Missing memno at end of file");
+ else if (status == 0)
+ err ("do_p1_extern: Missing memno in intermediate file");
+ if (addrp->vtype = extsymtab[addrp->memno].extype)
+ addrp->vclass = CLPROC;
+ } /* if addrp */
+
+ return (expptr) addrp;
+} /* do_p1_extern */
+
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_head(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_head(FILE *infile, FILE *outfile)
+#endif
+{
+ int status;
+ int add_n_;
+ long class;
+ char storage[256];
+
+ status = p1getd (infile, &class);
+ if (status == EOF)
+ err ("do_p1_head: missing header class at end of file");
+ else if (status == 0)
+ err ("do_p1_head: missing header class in p1 file");
+ else {
+ status = p1gets (infile, storage, (int)sizeof(storage));
+ if (status == EOF || status == 0)
+ storage[0] = '\0';
+ } /* else */
+
+ if (class == CLPROC || class == CLMAIN) {
+ chainp lengths;
+
+ add_n_ = nentry > 1;
+ lengths = length_comp(entries, add_n_);
+
+ if (!add_n_ && protofile && class != CLMAIN)
+ protowrite(protofile, proctype, storage, entries, lengths);
+
+ if (class == CLMAIN)
+ nice_printf (outfile, "/* Main program */ ");
+ else
+ nice_printf(outfile, "%s ", multitype ? "VOID"
+ : c_type_decl(proctype, 1));
+
+ nice_printf(outfile, add_n_ ? "%s0_" : "%s", storage);
+ if (!Ansi) {
+ listargs(outfile, entries, add_n_, lengths);
+ nice_printf (outfile, "\n");
+ }
+ list_arg_types (outfile, entries, lengths, add_n_, "\n");
+ nice_printf (outfile, "{\n");
+ frchain(&lengths);
+ next_tab (outfile);
+ strcpy(this_proc_name, storage);
+ list_decls (outfile);
+
+ } else if (class == CLBLOCK)
+ next_tab (outfile);
+ else
+ errl("do_p1_head: got class %ld", class);
+
+ return NULL;
+} /* do_p1_head */
+
+
+ static expptr
+#ifdef KR_headers
+do_p1_list(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_list(FILE *infile, FILE *outfile)
+#endif
+{
+ long tag, type, count;
+ int status;
+ expptr result;
+
+ status = p1getd (infile, &tag);
+ if (status == EOF)
+ err ("do_p1_list: missing list tag at end of file");
+ else if (status == 0)
+ err ("do_p1_list: missing list tag in p1 file");
+ else {
+ status = p1getd (infile, &type);
+ if (status == EOF)
+ err ("do_p1_list: missing list type at end of file");
+ else if (status == 0)
+ err ("do_p1_list: missing list type in p1 file");
+ else {
+ status = p1getd (infile, &count);
+ if (status == EOF)
+ err ("do_p1_list: missing count at end of file");
+ else if (status == 0)
+ err ("do_p1_list: missing count in p1 file");
+ } /* else */
+ } /* else */
+
+ result = (expptr) ALLOC (Listblock);
+ if (result) {
+ chainp pointer;
+
+ result -> tag = tag;
+ result -> listblock.vtype = type;
+
+/* Assume there will be enough data */
+
+ if (count--) {
+ pointer = result->listblock.listp =
+ mkchain((char *)do_format(infile, outfile), CHNULL);
+ while (count--) {
+ pointer -> nextp =
+ mkchain((char *)do_format(infile, outfile), CHNULL);
+ pointer = pointer -> nextp;
+ } /* while (count--) */
+ } /* if (count) */
+ } /* if (result) */
+
+ return result;
+} /* do_p1_list */
+
+
+ chainp
+#ifdef KR_headers
+length_comp(e, add_n)
+ struct Entrypoint *e;
+ int add_n;
+#else
+length_comp(struct Entrypoint *e, int add_n)
+#endif
+ /* get lengths of characters args */
+{
+ chainp lengths;
+ chainp args, args1;
+ Namep arg, np;
+ int nchargs;
+ Argtypes *at;
+ Atype *a;
+ extern int init_ac[TYSUBR+1];
+
+ if (!e)
+ return 0; /* possible only with errors */
+ args = args1 = add_n ? allargs : e->arglist;
+ nchargs = 0;
+ for (lengths = NULL; args; args = args -> nextp)
+ if (arg = (Namep)args->datap) {
+ if (arg->vclass == CLUNKNOWN)
+ arg->vclass = CLVAR;
+ if (arg->vtype == TYCHAR && arg->vclass != CLPROC) {
+ lengths = mkchain((char *)arg, lengths);
+ nchargs++;
+ }
+ }
+ if (!add_n && (np = e->enamep)) {
+ /* one last check -- by now we know all we ever will
+ * about external args...
+ */
+ save_argtypes(e->arglist, &e->entryname->arginfo,
+ &np->arginfo, 0, np->fvarname, STGEXT, nchargs,
+ np->vtype, 1);
+ at = e->entryname->arginfo;
+ a = at->atypes + init_ac[np->vtype];
+ for(; args1; a++, args1 = args1->nextp) {
+ frchain(&a->cp);
+ if (arg = (Namep)args1->datap)
+ switch(arg->vclass) {
+ case CLPROC:
+ if (arg->vimpltype
+ && a->type >= 300)
+ a->type = TYUNKNOWN + 200;
+ break;
+ case CLUNKNOWN:
+ a->type %= 100;
+ }
+ }
+ }
+ return revchain(lengths);
+ }
+
+ void
+#ifdef KR_headers
+listargs(outfile, entryp, add_n_, lengths)
+ FILE *outfile;
+ struct Entrypoint *entryp;
+ int add_n_;
+ chainp lengths;
+#else
+listargs(FILE *outfile, struct Entrypoint *entryp, int add_n_, chainp lengths)
+#endif
+{
+ chainp args;
+ char *s;
+ Namep arg;
+ int did_one = 0;
+
+ nice_printf (outfile, "(");
+
+ if (add_n_) {
+ nice_printf(outfile, "n__");
+ did_one = 1;
+ args = allargs;
+ }
+ else {
+ if (!entryp)
+ return; /* possible only with errors */
+ args = entryp->arglist;
+ }
+
+ if (multitype)
+ {
+ nice_printf(outfile, ", ret_val");
+ did_one = 1;
+ args = allargs;
+ }
+ else if (ONEOF(proctype, MSKCOMPLEX|MSKCHAR))
+ {
+ s = xretslot[proctype]->user.ident;
+ nice_printf(outfile, did_one ? ", %s" : "%s",
+ *s == '(' /*)*/ ? "r_v" : s);
+ did_one = 1;
+ if (proctype == TYCHAR)
+ nice_printf (outfile, ", ret_val_len");
+ }
+ for (; args; args = args -> nextp)
+ if (arg = (Namep)args->datap) {
+ nice_printf (outfile, "%s", did_one ? ", " : "");
+ out_name (outfile, arg);
+ did_one = 1;
+ }
+
+ for (args = lengths; args; args = args -> nextp)
+ nice_printf(outfile, ", %s",
+ new_arg_length((Namep)args->datap));
+ nice_printf (outfile, ")");
+} /* listargs */
+
+
+ void
+#ifdef KR_headers
+list_arg_types(outfile, entryp, lengths, add_n_, finalnl)
+ FILE *outfile;
+ struct Entrypoint *entryp;
+ chainp lengths;
+ int add_n_;
+ char *finalnl;
+#else
+list_arg_types(FILE *outfile, struct Entrypoint *entryp, chainp lengths, int add_n_, char *finalnl)
+#endif
+{
+ chainp args;
+ int last_type = -1, last_class = -1;
+ int did_one = 0, done_one, is_ext;
+ char *s, *sep = "", *sep1;
+
+ if (outfile == (FILE *) NULL) {
+ err ("list_arg_types: null output file");
+ return;
+ } else if (entryp == (struct Entrypoint *) NULL) {
+ err ("list_arg_types: null procedure entry pointer");
+ return;
+ } /* else */
+
+ if (Ansi) {
+ done_one = 0;
+ sep1 = ", ";
+ nice_printf(outfile, "(" /*)*/);
+ }
+ else {
+ done_one = 1;
+ sep1 = ";\n";
+ }
+ args = entryp->arglist;
+ if (add_n_) {
+ nice_printf(outfile, "int n__");
+ did_one = done_one;
+ sep = sep1;
+ args = allargs;
+ }
+ if (multitype) {
+ nice_printf(outfile, "%sMultitype *ret_val", sep);
+ did_one = done_one;
+ sep = sep1;
+ }
+ else if (ONEOF (proctype, MSKCOMPLEX|MSKCHAR)) {
+ s = xretslot[proctype]->user.ident;
+ nice_printf(outfile, "%s%s *%s", sep, c_type_decl(proctype, 0),
+ *s == '(' /*)*/ ? "r_v" : s);
+ did_one = done_one;
+ sep = sep1;
+ if (proctype == TYCHAR)
+ nice_printf (outfile, "%sftnlen ret_val_len", sep);
+ } /* if ONEOF proctype */
+ for (; args; args = args -> nextp) {
+ Namep arg = (Namep) args->datap;
+
+/* Scalars are passed by reference, and arrays will have their lower bound
+ adjusted, so nearly everything is printed with a star in front. The
+ exception is character lengths, which are passed by value. */
+
+ if (arg) {
+ int type = arg -> vtype, class = arg -> vclass;
+
+ if (class == CLPROC)
+ if (arg->vimpltype)
+ type = Castargs ? TYUNKNOWN : TYSUBR;
+ else if (type == TYREAL && forcedouble && !Castargs)
+ type = TYDREAL;
+
+ if (type == last_type && class == last_class && did_one)
+ nice_printf (outfile, ", ");
+ else
+ if ((is_ext = class == CLPROC) && Castargs)
+ nice_printf(outfile, "%s%s ", sep,
+ usedcasts[type] = casttypes[type]);
+ else
+ nice_printf(outfile, "%s%s ", sep,
+ c_type_decl(type, is_ext));
+ if (class == CLPROC)
+ if (Castargs)
+ out_name(outfile, arg);
+ else {
+ nice_printf(outfile, "(*");
+ out_name(outfile, arg);
+ nice_printf(outfile, ") %s", parens);
+ }
+ else {
+ nice_printf (outfile, "*");
+ out_name (outfile, arg);
+ }
+
+ last_type = type;
+ last_class = class;
+ did_one = done_one;
+ sep = sep1;
+ } /* if (arg) */
+ } /* for args = entryp -> arglist */
+
+ for (args = lengths; args; args = args -> nextp)
+ nice_printf(outfile, "%sftnlen %s", sep,
+ new_arg_length((Namep)args->datap));
+ if (did_one)
+ nice_printf (outfile, ";\n");
+ else if (Ansi)
+ nice_printf(outfile,
+ /*((*/ sep != sep1 && Ansi == 1 ? "void)%s" : ")%s",
+ finalnl);
+} /* list_arg_types */
+
+ static void
+#ifdef KR_headers
+write_formats(outfile)
+ FILE *outfile;
+#else
+write_formats(FILE *outfile)
+#endif
+{
+ register struct Labelblock *lp;
+ int first = 1;
+ char *fs;
+
+ for(lp = labeltab ; lp < highlabtab ; ++lp)
+ if (lp->fmtlabused) {
+ if (first) {
+ first = 0;
+ nice_printf(outfile, "/* Format strings */\n");
+ }
+ nice_printf(outfile, "static char fmt_%ld[] = \"",
+ lp->stateno);
+ if (!(fs = lp->fmtstring))
+ fs = "";
+ nice_printf(outfile, "%s\";\n", fs);
+ }
+ if (!first)
+ nice_printf(outfile, "\n");
+ }
+
+ static void
+#ifdef KR_headers
+write_ioblocks(outfile)
+ FILE *outfile;
+#else
+write_ioblocks(FILE *outfile)
+#endif
+{
+ register iob_data *L;
+ register char *f, **s, *sep;
+
+ nice_printf(outfile, "/* Fortran I/O blocks */\n");
+ L = iob_list = (iob_data *)revchain((chainp)iob_list);
+ do {
+ nice_printf(outfile, "static %s %s = { ",
+ L->type, L->name);
+ sep = 0;
+ for(s = L->fields; f = *s; s++) {
+ if (sep)
+ nice_printf(outfile, sep);
+ sep = ", ";
+ if (*f == '"') { /* kludge */
+ nice_printf(outfile, "\"");
+ nice_printf(outfile, "%s\"", f+1);
+ }
+ else
+ nice_printf(outfile, "%s", f);
+ }
+ nice_printf(outfile, " };\n");
+ }
+ while(L = L->next);
+ nice_printf(outfile, "\n\n");
+ }
+
+ static void
+#ifdef KR_headers
+write_assigned_fmts(outfile)
+ FILE *outfile;
+#else
+write_assigned_fmts(FILE *outfile)
+#endif
+{
+ register chainp cp;
+ Namep np;
+ char *comma, *type;
+ int did_one = 0;
+
+ cp = assigned_fmts = revchain(assigned_fmts);
+ nice_printf(outfile, "/* Assigned format variables */\n");
+ do {
+ np = (Namep)cp->datap;
+ if (did_one == np->vstg) {
+ comma = ", ";
+ type = "";
+ }
+ else {
+ comma = did_one ? ";\n" : "";
+ type = np->vstg == STGAUTO ? "char " : "static char ";
+ did_one = np->vstg;
+ }
+ nice_printf(outfile, "%s%s*%s_fmt", comma, type, np->fvarname);
+ }
+ while(cp = cp->nextp);
+ nice_printf(outfile, ";\n\n");
+ }
+
+ static char *
+#ifdef KR_headers
+to_upper(s)
+ register char *s;
+#else
+to_upper(register char *s)
+#endif
+{
+ static char buf[64];
+ register char *t = buf;
+ register int c;
+ while(*t++ = (c = *s++) >= 'a' && c <= 'z' ? c + 'A' - 'a' : c);
+ return buf;
+ }
+
+
+/* This routine creates static structures representing a namelist.
+ Declarations of the namelist and related structures are:
+
+ struct Vardesc {
+ char *name;
+ char *addr;
+ ftnlen *dims; /* laid out as struct dimensions below *//*
+ int type;
+ };
+ typedef struct Vardesc Vardesc;
+
+ struct Namelist {
+ char *name;
+ Vardesc **vars;
+ int nvars;
+ };
+
+ struct dimensions
+ {
+ ftnlen numberofdimensions;
+ ftnlen numberofelements
+ ftnlen baseoffset;
+ ftnlen span[numberofdimensions-1];
+ };
+
+ If dims is not null, then the corner element of the array is at
+ addr. However, the element with subscripts (i1,...,in) is at
+ addr + sizeoftype * (i1+span[0]*(i2+span[1]*...) - dimp->baseoffset)
+*/
+
+ static void
+#ifdef KR_headers
+write_namelists(nmch, outfile)
+ chainp nmch;
+ FILE *outfile;
+#else
+write_namelists(chainp nmch, FILE *outfile)
+#endif
+{
+ Namep var;
+ struct Hashentry *entry;
+ struct Dimblock *dimp;
+ int i, nd, type;
+ char *comma, *name;
+ register chainp q;
+ register Namep v;
+ extern int typeconv[];
+
+ nice_printf(outfile, "/* Namelist stuff */\n\n");
+ for (entry = hashtab; entry < lasthash; ++entry) {
+ if (!(v = entry->varp) || !v->vnamelist)
+ continue;
+ type = v->vtype;
+ name = v->cvarname;
+ if (dimp = v->vdim) {
+ nd = dimp->ndim;
+ nice_printf(outfile,
+ "static ftnlen %s_dims[] = { %d, %ld, %ld",
+ name, nd,
+ dimp->nelt->constblock.Const.ci,
+ dimp->baseoffset->constblock.Const.ci);
+ for(i = 0, --nd; i < nd; i++)
+ nice_printf(outfile, ", %ld",
+ dimp->dims[i].dimsize->constblock.Const.ci);
+ nice_printf(outfile, " };\n");
+ }
+ nice_printf(outfile, "static Vardesc %s_dv = { \"%s\", %s",
+ name, to_upper(v->fvarname),
+ type == TYCHAR ? ""
+ : (dimp || oneof_stg(v,v->vstg,
+ M(STGEQUIV)|M(STGCOMMON)))
+ ? "(char *)" : "(char *)&");
+ out_name(outfile, v);
+ nice_printf(outfile, dimp ? ", %s_dims" : ", (ftnlen *)0", name);
+ nice_printf(outfile, ", %ld };\n",
+ type != TYCHAR ? (long)typeconv[type]
+ : -v->vleng->constblock.Const.ci);
+ }
+
+ do {
+ var = (Namep)nmch->datap;
+ name = var->cvarname;
+ nice_printf(outfile, "\nstatic Vardesc *%s_vl[] = ", name);
+ comma = "{";
+ i = 0;
+ for(q = var->varxptr.namelist ; q ; q = q->nextp) {
+ v = (Namep)q->datap;
+ if (!v->vnamelist)
+ continue;
+ i++;
+ nice_printf(outfile, "%s &%s_dv", comma, v->cvarname);
+ comma = ",";
+ }
+ nice_printf(outfile, " };\n");
+ nice_printf(outfile,
+ "static Namelist %s = { \"%s\", %s_vl, %d };\n",
+ name, to_upper(var->fvarname), name, i);
+ }
+ while(nmch = nmch->nextp);
+ nice_printf(outfile, "\n");
+ }
+
+/* fixextype tries to infer from usage in previous procedures
+ the type of an external procedure declared
+ external and passed as an argument but never typed or invoked.
+ */
+
+ static int
+#ifdef KR_headers
+fixexttype(var)
+ Namep var;
+#else
+fixexttype(Namep var)
+#endif
+{
+ Extsym *e;
+ int type, type1;
+
+ type = var->vtype;
+ e = &extsymtab[var->vardesc.varno];
+ if ((type1 = e->extype) && type == TYUNKNOWN)
+ return var->vtype = type1;
+ if (var->visused) {
+ if (e->exused && type != type1)
+ changedtype(var);
+ e->exused = 1;
+ e->extype = type;
+ }
+ return type;
+ }
+
+ static void
+#ifdef KR_headers
+ref_defs(outfile, refdefs)
+ FILE *outfile;
+ chainp refdefs;
+#else
+ref_defs(FILE *outfile, chainp refdefs)
+#endif
+{
+ chainp cp;
+ int eb, i, j, n;
+ struct Dimblock *dimp;
+ expptr b, vl;
+ Namep var;
+ char *amp, *comma;
+
+ margin_printf(outfile, "\n");
+ for(cp = refdefs = revchain(refdefs); cp; cp = cp->nextp) {
+ var = (Namep)cp->datap;
+ cp->datap = 0;
+ amp = "_subscr";
+ if (!(eb = var->vsubscrused)) {
+ var->vrefused = 0;
+ if (!ISCOMPLEX(var->vtype))
+ amp = "_ref";
+ }
+ def_start(outfile, var->cvarname, amp, CNULL);
+ dimp = var->vdim;
+ vl = 0;
+ comma = "(";
+ amp = "";
+ if (var->vtype == TYCHAR) {
+ amp = "&";
+ vl = var->vleng;
+ if (ISCONST(vl) && vl->constblock.Const.ci == 1)
+ vl = 0;
+ nice_printf(outfile, "%sa_0", comma);
+ comma = ",";
+ }
+ n = dimp->ndim;
+ for(i = 1; i <= n; i++, comma = ",")
+ nice_printf(outfile, "%sa_%d", comma, i);
+ nice_printf(outfile, ") %s", amp);
+ if (var->vsubscrused)
+ var->vsubscrused = 0;
+ else if (!ISCOMPLEX(var->vtype)) {
+ out_name(outfile, var);
+ nice_printf(outfile, "[%s", vl ? "(" : "");
+ }
+ for(j = 2; j < n; j++)
+ nice_printf(outfile, "(");
+ while(--i > 1) {
+ nice_printf(outfile, "(a_%d)%s*", i, i == n ? "" : ")");
+ expr_out(outfile, cpexpr(dimp->dims[i-2].dimsize));
+ nice_printf(outfile, " + ");
+ }
+ nice_printf(outfile, "a_1");
+ if (var->vtype == TYCHAR) {
+ if (vl) {
+ nice_printf(outfile, ")*");
+ expr_out(outfile, cpexpr(vl));
+ }
+ nice_printf(outfile, " + a_0");
+ }
+ if ((var->vstg != STGARG /* || checksubs */ )
+ && (b = dimp->baseoffset)) {
+ b = cpexpr(b);
+ if (var->vtype == TYCHAR)
+ b = mkexpr(OPSTAR, cpexpr(var->vleng), b);
+ nice_printf(outfile, " - ");
+ expr_out(outfile, b);
+ }
+ if (ISCOMPLEX(var->vtype)) {
+ margin_printf(outfile, "\n");
+ def_start(outfile, var->cvarname, "_ref", CNULL);
+ comma = "(";
+ for(i = 1; i <= n; i++, comma = ",")
+ nice_printf(outfile, "%sa_%d", comma, i);
+ nice_printf(outfile, ") %s[%s_subscr",
+ var->cvarname, var->cvarname);
+ comma = "(";
+ for(i = 1; i <= n; i++, comma = ",")
+ nice_printf(outfile, "%sa_%d", comma, i);
+ nice_printf(outfile, ")");
+ }
+ margin_printf(outfile, "]\n" + eb);
+ }
+ nice_printf(outfile, "\n");
+ frchain(&refdefs);
+ }
+
+ void
+#ifdef KR_headers
+list_decls(outfile)
+ FILE *outfile;
+#else
+list_decls(FILE *outfile)
+#endif
+{
+ extern chainp used_builtins;
+ extern struct Hashentry *hashtab;
+ struct Hashentry *entry;
+ int write_header = 1;
+ int last_class = -1, last_stg = -1;
+ Namep var;
+ int Alias, Define, did_one, last_type, type;
+ extern int def_equivs, useauto;
+ extern chainp new_vars; /* Compiler-generated locals */
+ chainp namelists = 0, refdefs = 0;
+ char *ctype;
+ int useauto1 = useauto && !saveall;
+ long x;
+ extern int hsize;
+
+/* First write out the statically initialized data */
+
+ if (initfile)
+ list_init_data(&initfile, initfname, outfile);
+
+/* Next come formats */
+ write_formats(outfile);
+
+/* Now write out the system-generated identifiers */
+
+ if (new_vars || nequiv) {
+ chainp args, next_var, this_var;
+ chainp nv[TYVOID], nv1[TYVOID];
+ int i, j;
+ Addrp Var;
+ Namep arg;
+
+ /* zap unused dimension variables */
+
+ for(args = allargs; args; args = args->nextp) {
+ arg = (Namep)args->datap;
+ if (this_var = arg->vlastdim) {
+ frexpr((tagptr)this_var->datap);
+ this_var->datap = 0;
+ }
+ }
+
+ /* sort new_vars by type, skipping entries just zapped */
+
+ for(i = TYADDR; i < TYVOID; i++)
+ nv[i] = 0;
+ for(this_var = new_vars; this_var; this_var = next_var) {
+ next_var = this_var->nextp;
+ if (Var = (Addrp)this_var->datap) {
+ if (!(this_var->nextp = nv[j = Var->vtype]))
+ nv1[j] = this_var;
+ nv[j] = this_var;
+ }
+ else {
+ this_var->nextp = 0;
+ frchain(&this_var);
+ }
+ }
+ new_vars = 0;
+ for(i = TYVOID; --i >= TYADDR;)
+ if (this_var = nv[i]) {
+ nv1[i]->nextp = new_vars;
+ new_vars = this_var;
+ }
+
+ /* write the declarations */
+
+ did_one = 0;
+ last_type = -1;
+
+ for (this_var = new_vars; this_var; this_var = this_var -> nextp) {
+ Var = (Addrp) this_var->datap;
+
+ if (Var == (Addrp) NULL)
+ err ("list_decls: null variable");
+ else if (Var -> tag != TADDR)
+ erri ("list_decls: bad tag on new variable '%d'",
+ Var -> tag);
+
+ type = nv_type (Var);
+ if (Var->vstg == STGINIT
+ || Var->uname_tag == UNAM_IDENT
+ && *Var->user.ident == ' '
+ && multitype)
+ continue;
+ if (!did_one)
+ nice_printf (outfile, "/* System generated locals */\n");
+
+ if (last_type == type && did_one)
+ nice_printf (outfile, ", ");
+ else {
+ if (did_one)
+ nice_printf (outfile, ";\n");
+ nice_printf (outfile, "%s ",
+ c_type_decl (type, Var -> vclass == CLPROC));
+ } /* else */
+
+/* Character type is really a string type. Put out a '*' for parameters
+ with unknown length and functions returning character */
+
+ if (Var -> vtype == TYCHAR && (!ISICON ((Var -> vleng))
+ || Var -> vclass == CLPROC))
+ nice_printf (outfile, "*");
+
+ write_nv_ident(outfile, (Addrp)this_var->datap);
+ if (Var -> vtype == TYCHAR && Var->vclass != CLPROC &&
+ ISICON((Var -> vleng))
+ && (i = Var->vleng->constblock.Const.ci) > 0)
+ nice_printf (outfile, "[%d]", i);
+
+ did_one = 1;
+ last_type = nv_type (Var);
+ } /* for this_var */
+
+/* Handle the uninitialized equivalences */
+
+ do_uninit_equivs (outfile, &did_one);
+
+ if (did_one)
+ nice_printf (outfile, ";\n\n");
+ } /* if new_vars */
+
+/* Write out builtin declarations */
+
+ if (used_builtins) {
+ chainp cp;
+ Extsym *es;
+
+ last_type = -1;
+ did_one = 0;
+
+ nice_printf (outfile, "/* Builtin functions */");
+
+ for (cp = used_builtins; cp; cp = cp -> nextp) {
+ Addrp e = (Addrp)cp->datap;
+
+ switch(type = e->vtype) {
+ case TYDREAL:
+ case TYREAL:
+ /* if (forcedouble || e->dbl_builtin) */
+ /* libF77 currently assumes everything double */
+ type = TYDREAL;
+ ctype = "double";
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ type = TYVOID;
+ /* no break */
+ default:
+ ctype = c_type_decl(type, 0);
+ }
+
+ if (did_one && last_type == type)
+ nice_printf(outfile, ", ");
+ else
+ nice_printf(outfile, "%s\n%s ", did_one ? ";" : "", ctype);
+
+ extern_out(outfile, es = &extsymtab[e -> memno]);
+ proto(outfile, es->arginfo, es->fextname);
+ last_type = type;
+ did_one = 1;
+ } /* for cp = used_builtins */
+
+ nice_printf (outfile, ";\n\n");
+ } /* if used_builtins */
+
+ last_type = -1;
+ for (entry = hashtab; entry < lasthash; ++entry) {
+ var = entry -> varp;
+
+ if (var) {
+ int procclass = var -> vprocclass;
+ char *comment = NULL;
+ int stg = var -> vstg;
+ int class = var -> vclass;
+ type = var -> vtype;
+
+ if (var->vrefused)
+ refdefs = mkchain((char *)var, refdefs);
+ if (var->vsubscrused)
+ if (ISCOMPLEX(var->vtype))
+ var->vsubscrused = 0;
+ else
+ refdefs = mkchain((char *)var, refdefs);
+ if (ONEOF(stg, M(STGARG)|M(STGLENG)|M(STGINIT)))
+ continue;
+
+ if (useauto1 && stg == STGBSS && !var->vsave)
+ stg = STGAUTO;
+
+ switch (class) {
+ case CLVAR:
+ break;
+ case CLPROC:
+ switch(procclass) {
+ case PTHISPROC:
+ extsymtab[var->vardesc.varno].extype = type;
+ continue;
+ case PSTFUNCT:
+ case PINTRINSIC:
+ continue;
+ case PUNKNOWN:
+ err ("list_decls: unknown procedure class");
+ continue;
+ case PEXTERNAL:
+ if (stg == STGUNKNOWN) {
+ warn1(
+ "%.64s declared EXTERNAL but never used.",
+ var->fvarname);
+ /* to retain names declared EXTERNAL */
+ /* but not referenced, change */
+ /* "continue" to "stg = STGEXT" */
+ continue;
+ }
+ else
+ type = fixexttype(var);
+ }
+ break;
+ case CLUNKNOWN:
+ /* declared but never used */
+ continue;
+ case CLPARAM:
+ continue;
+ case CLNAMELIST:
+ if (var->visused)
+ namelists = mkchain((char *)var, namelists);
+ continue;
+ default:
+ erri("list_decls: can't handle class '%d' yet",
+ class);
+ Fatal(var->fvarname);
+ continue;
+ } /* switch */
+
+ /* Might be equivalenced to a common. If not, don't process */
+ if (stg == STGCOMMON && !var->vcommequiv)
+ continue;
+
+/* Only write the header if system-generated locals, builtins, or
+ uninitialized equivs were already output */
+
+ if (write_header == 1 && (new_vars || nequiv || used_builtins)
+ && oneof_stg ( var, stg,
+ M(STGBSS)|M(STGEXT)|M(STGAUTO)|M(STGCOMMON)|M(STGEQUIV))) {
+ nice_printf (outfile, "/* Local variables */\n");
+ write_header = 2;
+ }
+
+
+ Alias = oneof_stg(var, stg, M(STGEQUIV)|M(STGCOMMON));
+ if (Define = (Alias && def_equivs)) {
+ if (!write_header)
+ nice_printf(outfile, ";\n");
+ def_start(outfile, var->cvarname, CNULL, "(");
+ goto Alias1;
+ }
+ else if (type == last_type && class == last_class &&
+ stg == last_stg && !write_header)
+ nice_printf (outfile, ", ");
+ else {
+ if (!write_header && ONEOF(stg, M(STGBSS)|
+ M(STGEXT)|M(STGAUTO)|M(STGEQUIV)|M(STGCOMMON)))
+ nice_printf (outfile, ";\n");
+
+ switch (stg) {
+ case STGARG:
+ case STGLENG:
+ /* Part of the argument list, don't write them out
+ again */
+ continue; /* Go back to top of the loop */
+ case STGBSS:
+ case STGEQUIV:
+ case STGCOMMON:
+ nice_printf (outfile, "static ");
+ break;
+ case STGEXT:
+ nice_printf (outfile, "extern ");
+ break;
+ case STGAUTO:
+ break;
+ case STGINIT:
+ case STGUNKNOWN:
+ /* Don't want to touch the initialized data, that will
+ be handled elsewhere. Unknown data have
+ already been complained about, so skip them */
+ continue;
+ default:
+ erri("list_decls: can't handle storage class %d",
+ stg);
+ continue;
+ } /* switch */
+
+ if (type == TYCHAR && halign && class != CLPROC
+ && ISICON(var->vleng)) {
+ nice_printf(outfile, "struct { %s fill; char val",
+ halign);
+ x = wr_char_len(outfile, var->vdim,
+ var->vleng->constblock.Const.ci, 1);
+ if (x %= hsize)
+ nice_printf(outfile, "; char fill2[%ld]",
+ hsize - x);
+ nice_printf(outfile, "; } %s_st;\n", var->cvarname);
+ def_start(outfile, var->cvarname, CNULL, var->cvarname);
+ margin_printf(outfile, "_st.val\n");
+ last_type = -1;
+ write_header = 2;
+ continue;
+ }
+ nice_printf(outfile, "%s ",
+ c_type_decl(type, class == CLPROC));
+ } /* else */
+
+/* Character type is really a string type. Put out a '*' for variable
+ length strings, and also for equivalences */
+
+ if (type == TYCHAR && class != CLPROC
+ && (!var->vleng || !ISICON (var -> vleng))
+ || oneof_stg(var, stg, M(STGEQUIV)|M(STGCOMMON)))
+ nice_printf (outfile, "*%s", var->cvarname);
+ else {
+ nice_printf (outfile, "%s", var->cvarname);
+ if (class == CLPROC) {
+ Argtypes *at;
+ if (!(at = var->arginfo)
+ && var->vprocclass == PEXTERNAL)
+ at = extsymtab[var->vardesc.varno].arginfo;
+ proto(outfile, at, var->fvarname);
+ }
+ else if (type == TYCHAR && ISICON ((var -> vleng)))
+ wr_char_len(outfile, var->vdim,
+ (int)var->vleng->constblock.Const.ci, 0);
+ else if (var -> vdim &&
+ !oneof_stg (var, stg, M(STGEQUIV)|M(STGCOMMON)))
+ comment = wr_ardecls(outfile, var->vdim, 1L);
+ }
+
+ if (comment)
+ nice_printf (outfile, "%s", comment);
+ Alias1:
+ if (Alias) {
+ char *amp, *lp, *name, *rp;
+ ftnint voff = var -> voffset;
+ int et0, expr_type, k;
+ Extsym *E;
+ struct Equivblock *eb;
+ char buf[16];
+
+/* We DON'T want to use oneof_stg here, because we need to distinguish
+ between them */
+
+ if (stg == STGEQUIV) {
+ name = equiv_name(k = var->vardesc.varno, CNULL);
+ eb = eqvclass + k;
+ if (eb->eqvinit) {
+ amp = "&";
+ et0 = TYERROR;
+ }
+ else {
+ amp = "";
+ et0 = eb->eqvtype;
+ }
+ expr_type = et0;
+ }
+ else {
+ E = &extsymtab[var->vardesc.varno];
+ sprintf(name = buf, "%s%d", E->cextname, E->curno);
+ expr_type = type;
+ et0 = -1;
+ amp = "&";
+ } /* else */
+
+ if (!Define)
+ nice_printf (outfile, " = ");
+ if (voff) {
+ k = typesize[type];
+ switch((int)(voff % k)) {
+ case 0:
+ voff /= k;
+ expr_type = type;
+ break;
+ case SZSHORT:
+ case SZSHORT+SZLONG:
+ expr_type = TYSHORT;
+ voff /= SZSHORT;
+ break;
+ case SZLONG:
+ expr_type = TYLONG;
+ voff /= SZLONG;
+ break;
+ default:
+ expr_type = TYCHAR;
+ }
+ }
+
+ if (expr_type == type) {
+ lp = rp = "";
+ if (et0 == -1 && !voff)
+ goto cast;
+ }
+ else {
+ lp = "(";
+ rp = ")";
+ cast:
+ nice_printf(outfile, "(%s *)", c_type_decl(type, 0));
+ }
+
+/* Now worry about computing the offset */
+
+ if (voff) {
+ if (expr_type == et0)
+ nice_printf (outfile, "%s%s + %ld%s",
+ lp, name, voff, rp);
+ else
+ nice_printf(outfile, "%s(%s *)%s%s + %ld%s", lp,
+ c_type_decl (expr_type, 0), amp,
+ name, voff, rp);
+ } else
+ nice_printf(outfile, "%s%s", amp, name);
+/* Always put these at the end of the line */
+ last_type = last_class = last_stg = -1;
+ write_header = 0;
+ if (Define) {
+ margin_printf(outfile, ")\n");
+ write_header = 2;
+ }
+ continue;
+ }
+ write_header = 0;
+ last_type = type;
+ last_class = class;
+ last_stg = stg;
+ } /* if (var) */
+ } /* for (entry = hashtab */
+
+ if (!write_header)
+ nice_printf (outfile, ";\n\n");
+ else if (write_header == 2)
+ nice_printf(outfile, "\n");
+
+/* Next, namelists, which may reference equivs */
+
+ if (namelists) {
+ write_namelists(namelists = revchain(namelists), outfile);
+ frchain(&namelists);
+ }
+
+/* Finally, ioblocks (which may reference equivs and namelists) */
+ if (iob_list)
+ write_ioblocks(outfile);
+ if (assigned_fmts)
+ write_assigned_fmts(outfile);
+
+ if (refdefs)
+ ref_defs(outfile, refdefs);
+
+} /* list_decls */
+
+ void
+#ifdef KR_headers
+do_uninit_equivs(outfile, did_one)
+ FILE *outfile;
+ int *did_one;
+#else
+do_uninit_equivs(FILE *outfile, int *did_one)
+#endif
+{
+ extern int nequiv;
+ struct Equivblock *eqv, *lasteqv = eqvclass + nequiv;
+ int k, last_type = -1, t;
+
+ for (eqv = eqvclass; eqv < lasteqv; eqv++)
+ if (!eqv -> eqvinit && eqv -> eqvtop != eqv -> eqvbottom) {
+ if (!*did_one)
+ nice_printf (outfile, "/* System generated locals */\n");
+ t = eqv->eqvtype;
+ if (last_type == t)
+ nice_printf (outfile, ", ");
+ else {
+ if (*did_one)
+ nice_printf (outfile, ";\n");
+ nice_printf (outfile, "static %s ", c_type_decl(t, 0));
+ k = typesize[t];
+ } /* else */
+ nice_printf(outfile, "%s", equiv_name((int)(eqv - eqvclass), CNULL));
+ nice_printf(outfile, "[%ld]",
+ (eqv->eqvtop - eqv->eqvbottom + k - 1) / k);
+ last_type = t;
+ *did_one = 1;
+ } /* if !eqv -> eqvinit */
+} /* do_uninit_equivs */
+
+
+/* wr_ardecls -- Writes the brackets and size for an array
+ declaration. Because of the inner workings of the compiler,
+ multi-dimensional arrays get mapped directly into a one-dimensional
+ array, so we have to compute the size of the array here. When the
+ dimension is greater than 1, a string comment about the original size
+ is returned */
+
+ char *
+#ifdef KR_headers
+wr_ardecls(outfile, dimp, size)
+ FILE *outfile;
+ struct Dimblock *dimp;
+ long size;
+#else
+wr_ardecls(FILE *outfile, struct Dimblock *dimp, long size)
+#endif
+{
+ int i, k;
+ ftnint j;
+ static char buf[1000];
+
+ if (dimp == (struct Dimblock *) NULL)
+ return NULL;
+
+ sprintf(buf, "\t/* was "); /* would like to say k = sprintf(...), but */
+ k = strlen(buf); /* BSD doesn't return char transmitted count */
+
+ for (i = 0; i < dimp -> ndim; i++) {
+ expptr this_size = dimp -> dims[i].dimsize;
+
+ if (ISCONST(this_size)) {
+ if (ISINT(this_size->constblock.vtype))
+ j = this_size -> constblock.Const.ci;
+ else if (ISREAL(this_size->constblock.vtype))
+ j = (ftnint)this_size -> constblock.Const.cd[0];
+ else
+ goto non_const;
+ size *= j;
+ sprintf(buf+k, "[%ld]", j);
+ k += strlen(buf+k);
+ /* BSD prevents getting strlen from sprintf */
+ }
+ else {
+ non_const:
+ err ("wr_ardecls: nonconstant array size");
+ }
+ } /* for i = 0 */
+
+ nice_printf (outfile, "[%ld]", size);
+ strcat(buf+k, " */");
+
+ return (i > 1) ? buf : NULL;
+} /* wr_ardecls */
+
+
+
+/* ----------------------------------------------------------------------
+
+ The following routines read from the p1 intermediate file. If
+ that format changes, only these routines need be changed
+
+ ---------------------------------------------------------------------- */
+
+ static int
+#ifdef KR_headers
+get_p1_token(infile)
+ FILE *infile;
+#else
+get_p1_token(FILE *infile)
+#endif
+{
+ int token = P1_UNKNOWN;
+
+/* NOT PORTABLE!! */
+
+ if (fscanf (infile, "%d", &token) == EOF)
+ return P1_EOF;
+
+/* Skip over the ": " */
+
+ if (getc (infile) != '\n')
+ getc (infile);
+
+ return token;
+} /* get_p1_token */
+
+
+
+/* Returns a (null terminated) string from the input file */
+
+ static int
+#ifdef KR_headers
+p1gets(fp, str, size)
+ FILE *fp;
+ char *str;
+ int size;
+#else
+p1gets(FILE *fp, char *str, int size)
+#endif
+{
+ char c;
+
+ if (str == NULL)
+ return 0;
+
+ if ((c = getc (fp)) != ' ')
+ ungetc (c, fp);
+
+ if (fgets (str, size, fp)) {
+ int length;
+
+ str[size - 1] = '\0';
+ length = strlen (str);
+
+/* Get rid of the newline */
+
+ if (str[length - 1] == '\n')
+ str[length - 1] = '\0';
+ return 1;
+
+ } else if (feof (fp))
+ return EOF;
+ else
+ return 0;
+} /* p1gets */
+
+
+ static int
+#ifdef KR_headers
+p1get_const(infile, type, resultp)
+ FILE *infile;
+ int type;
+ struct Constblock **resultp;
+#else
+p1get_const(FILE *infile, int type, struct Constblock **resultp)
+#endif
+{
+ int status;
+ struct Constblock *result;
+
+ if (type != TYCHAR) {
+ *resultp = result = ALLOC(Constblock);
+ result -> tag = TCONST;
+ result -> vtype = type;
+ }
+
+ switch (type) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+ case TYLOGICAL:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ status = p1getd (infile, &(result -> Const.ci));
+ break;
+ case TYREAL:
+ case TYDREAL:
+ status = p1getf(infile, &result->Const.cds[0]);
+ result->vstg = 1;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ status = p1getf(infile, &result->Const.cds[0]);
+ if (status && status != EOF)
+ status = p1getf(infile, &result->Const.cds[1]);
+ result->vstg = 1;
+ break;
+ case TYCHAR:
+ status = fscanf(infile, "%lx", resultp);
+ break;
+ default:
+ erri ("p1get_const: bad constant type '%d'", type);
+ status = 0;
+ break;
+ } /* switch */
+
+ return status;
+} /* p1get_const */
+
+ static int
+#ifdef KR_headers
+p1getd(infile, result)
+ FILE *infile;
+ long *result;
+#else
+p1getd(FILE *infile, long *result)
+#endif
+{
+ return fscanf (infile, "%ld", result);
+} /* p1getd */
+
+ static int
+#ifdef KR_headers
+p1getf(infile, result)
+ FILE *infile;
+ char **result;
+#else
+p1getf(FILE *infile, char **result)
+#endif
+{
+
+ char buf[1324];
+ register int k;
+
+ k = fscanf (infile, "%s", buf);
+ if (k < 1)
+ k = EOF;
+ else
+ strcpy(*result = mem(strlen(buf)+1,0), buf);
+ return k;
+}
+
+ static int
+#ifdef KR_headers
+p1getn(infile, count, result)
+ FILE *infile;
+ int count;
+ char **result;
+#else
+p1getn(FILE *infile, int count, char **result)
+#endif
+{
+
+ char *bufptr;
+
+ bufptr = (char *) ckalloc (count);
+
+ if (result)
+ *result = bufptr;
+
+ for (; !feof (infile) && count > 0; count--)
+ *bufptr++ = getc (infile);
+
+ return feof (infile) ? EOF : 1;
+} /* p1getn */
+
+ static void
+#ifdef KR_headers
+proto(outfile, at, fname)
+ FILE *outfile;
+ Argtypes *at;
+ char *fname;
+#else
+proto(FILE *outfile, Argtypes *at, char *fname)
+#endif
+{
+ int i, j, k, n;
+ char *comma;
+ Atype *atypes;
+ Namep np;
+ chainp cp;
+
+ if (at) {
+ /* Correct types that we learn on the fly, e.g.
+ subroutine gotcha(foo)
+ external foo
+ call zap(...,foo,...)
+ call foo(...)
+ */
+ atypes = at->atypes;
+ n = at->defined ? at->dnargs : at->nargs;
+ for(i = 0; i++ < n; atypes++) {
+ if (!(cp = atypes->cp))
+ continue;
+ j = atypes->type;
+ do {
+ np = (Namep)cp->datap;
+ k = np->vtype;
+ if (np->vclass == CLPROC) {
+ if (!np->vimpltype && k)
+ k += 200;
+ else {
+ if (j >= 300)
+ j = TYUNKNOWN + 200;
+ continue;
+ }
+ }
+ if (j == k)
+ continue;
+ if (j >= 300
+ || j == 200 && k >= 200)
+ j = k;
+ else {
+ if (at->nargs >= 0)
+ bad_atypes(at,fname,i,j,k,""," and");
+ goto break2;
+ }
+ }
+ while(cp = cp->nextp);
+ atypes->type = j;
+ frchain(&atypes->cp);
+ }
+ }
+ break2:
+ if (parens) {
+ nice_printf(outfile, parens);
+ return;
+ }
+
+ if (!at || (n = at-> defined ? at->dnargs : at->nargs) < 0) {
+ nice_printf(outfile, Ansi == 1 ? "()" : "(...)");
+ return;
+ }
+
+ if (n == 0) {
+ nice_printf(outfile, Ansi == 1 ? "(void)" : "()");
+ return;
+ }
+
+ atypes = at->atypes;
+ nice_printf(outfile, "(");
+ comma = "";
+ for(; --n >= 0; atypes++) {
+ k = atypes->type;
+ if (k == TYADDR)
+ nice_printf(outfile, "%schar **", comma);
+ else if (k >= 200) {
+ k -= 200;
+ nice_printf(outfile, "%s%s", comma,
+ usedcasts[k] = casttypes[k]);
+ }
+ else if (k >= 100)
+ nice_printf(outfile,
+ k == TYCHAR + 100 ? "%s%s *" : "%s%s",
+ comma, c_type_decl(k-100, 0));
+ else
+ nice_printf(outfile, "%s%s *", comma,
+ c_type_decl(k, 0));
+ comma = ", ";
+ }
+ nice_printf(outfile, ")");
+ }
+
+ void
+#ifdef KR_headers
+protowrite(protofile, type, name, e, lengths)
+ FILE *protofile;
+ int type;
+ char *name;
+ struct Entrypoint *e;
+ chainp lengths;
+#else
+protowrite(FILE *protofile, int type, char *name, struct Entrypoint *e, chainp lengths)
+#endif
+{
+ extern char used_rets[];
+ int asave;
+
+ if (!(asave = Ansi))
+ Castargs = Ansi = 1;
+ nice_printf(protofile, "extern %s %s", protorettypes[type], name);
+ list_arg_types(protofile, e, lengths, 0, ";\n");
+ used_rets[type] = 1;
+ if (!(Ansi = asave))
+ Castargs = 0;
+ }
+
+ static void
+#ifdef KR_headers
+do_p1_1while(outfile)
+ FILE *outfile;
+#else
+do_p1_1while(FILE *outfile)
+#endif
+{
+ if (*wh_next) {
+ nice_printf(outfile,
+ "for(;;) { /* while(complicated condition) */\n" /*}*/ );
+ next_tab(outfile);
+ }
+ else
+ nice_printf(outfile, "while(" /*)*/ );
+ }
+
+ static void
+#ifdef KR_headers
+do_p1_2while(infile, outfile)
+ FILE *infile;
+ FILE *outfile;
+#else
+do_p1_2while(FILE *infile, FILE *outfile)
+#endif
+{
+ expptr test;
+
+ test = do_format(infile, outfile);
+ if (*wh_next)
+ nice_printf(outfile, "if (!(");
+ expr_out(outfile, test);
+ if (*wh_next++)
+ nice_printf(outfile, "))\n\tbreak;\n");
+ else {
+ nice_printf(outfile, /*(*/ ") {\n");
+ next_tab(outfile);
+ }
+ }
+
+ static void
+#ifdef KR_headers
+do_p1_elseifstart(outfile)
+ FILE *outfile;
+#else
+do_p1_elseifstart(FILE *outfile)
+#endif
+{ /* with sufficiently illegal input, ei_next == ei_last == 0 is possible */
+ if (ei_next < ei_last && *ei_next++) {
+ prev_tab(outfile);
+ nice_printf(outfile, /*{*/
+ "} else /* if(complicated condition) */ {\n" /*}*/ );
+ next_tab(outfile);
+ }
+ }
diff --git a/usr.bin/f2c/format.h b/usr.bin/f2c/format.h
new file mode 100644
index 0000000..3de97f6
--- /dev/null
+++ b/usr.bin/f2c/format.h
@@ -0,0 +1,12 @@
+#define DEF_C_LINE_LENGTH 77
+/* actual max will be 79 */
+
+extern int c_output_line_length; /* max # chars per line in C source
+ code */
+
+chainp data_value Argdcl((FILEP, long int, int));
+int do_init_data Argdcl((FILEP, FILEP));
+void list_init_data Argdcl((FILEP*, char*, FILEP));
+char* wr_ardecls Argdcl((FILEP, struct Dimblock*, long int));
+void wr_one_init Argdcl((FILEP, char*, chainp*, int));
+void wr_output_values Argdcl((FILEP, Namep, chainp));
diff --git a/usr.bin/f2c/formatdata.c b/usr.bin/f2c/formatdata.c
new file mode 100644
index 0000000..501463a
--- /dev/null
+++ b/usr.bin/f2c/formatdata.c
@@ -0,0 +1,1166 @@
+/****************************************************************
+Copyright 1990, 1991, 1993-6 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "output.h"
+#include "names.h"
+#include "format.h"
+
+#define MAX_INIT_LINE 100
+#define NAME_MAX 64
+
+static int memno2info Argdcl((int, Namep*));
+
+ extern char *initbname;
+
+ void
+#ifdef KR_headers
+list_init_data(Infile, Inname, outfile)
+ FILE **Infile;
+ char *Inname;
+ FILE *outfile;
+#else
+list_init_data(FILE **Infile, char *Inname, FILE *outfile)
+#endif
+{
+ FILE *sortfp;
+ int status;
+
+ fclose(*Infile);
+ *Infile = 0;
+
+ if (status = dsort(Inname, sortfname))
+ fatali ("sort failed, status %d", status);
+
+ scrub(Inname); /* optionally unlink Inname */
+
+ if ((sortfp = fopen(sortfname, textread)) == NULL)
+ Fatal("Couldn't open sorted initialization data");
+
+ do_init_data(outfile, sortfp);
+ fclose(sortfp);
+ scrub(sortfname);
+
+/* Insert a blank line after any initialized data */
+
+ nice_printf (outfile, "\n");
+
+ if (debugflag && infname)
+ /* don't back block data file up -- it won't be overwritten */
+ backup(initfname, initbname);
+} /* list_init_data */
+
+
+
+/* do_init_data -- returns YES when at least one declaration has been
+ written */
+
+ int
+#ifdef KR_headers
+do_init_data(outfile, infile)
+ FILE *outfile;
+ FILE *infile;
+#else
+do_init_data(FILE *outfile, FILE *infile)
+#endif
+{
+ char varname[NAME_MAX], ovarname[NAME_MAX];
+ ftnint offset;
+ ftnint type;
+ int vargroup; /* 0 --> init, 1 --> equiv, 2 --> common */
+ int did_one = 0; /* True when one has been output */
+ chainp values = CHNULL; /* Actual data values */
+ int keepit = 0;
+ Namep np;
+
+ ovarname[0] = '\0';
+
+ while (rdname (infile, &vargroup, varname) && rdlong (infile, &offset)
+ && rdlong (infile, &type)) {
+ if (strcmp (varname, ovarname)) {
+
+ /* If this is a new variable name, the old initialization has been
+ completed */
+
+ wr_one_init(outfile, ovarname, &values, keepit);
+
+ strcpy (ovarname, varname);
+ values = CHNULL;
+ if (vargroup == 0) {
+ if (memno2info(atoi(varname+2), &np)) {
+ if (((Addrp)np)->uname_tag != UNAM_NAME) {
+ err("do_init_data: expected NAME");
+ goto Keep;
+ }
+ np = ((Addrp)np)->user.name;
+ }
+ if (!(keepit = np->visused) && !np->vimpldovar)
+ warn1("local variable %s never used",
+ np->fvarname);
+ }
+ else {
+ Keep:
+ keepit = 1;
+ }
+ if (keepit && !did_one) {
+ nice_printf (outfile, "/* Initialized data */\n\n");
+ did_one = YES;
+ }
+ } /* if strcmp */
+
+ values = mkchain((char *)data_value(infile, offset, (int)type), values);
+ } /* while */
+
+/* Write out the last declaration */
+
+ wr_one_init (outfile, ovarname, &values, keepit);
+
+ return did_one;
+} /* do_init_data */
+
+
+ ftnint
+#ifdef KR_headers
+wr_char_len(outfile, dimp, n, extra1)
+ FILE *outfile;
+ struct Dimblock *dimp;
+ int n;
+ int extra1;
+#else
+wr_char_len(FILE *outfile, struct Dimblock *dimp, int n, int extra1)
+#endif
+{
+ int i, nd;
+ expptr e;
+ ftnint j, rv;
+
+ if (!dimp) {
+ nice_printf (outfile, extra1 ? "[%d+1]" : "[%d]", n);
+ return n + extra1;
+ }
+ nice_printf(outfile, "[%d", n);
+ nd = dimp->ndim;
+ rv = n;
+ for(i = 0; i < nd; i++) {
+ e = dimp->dims[i].dimsize;
+ if (ISCONST(e)) {
+ if (ISINT(e->constblock.vtype))
+ j = e->constblock.Const.ci;
+ else if (ISREAL(e->constblock.vtype))
+ j = (ftnint)e->constblock.Const.cd[0];
+ else
+ goto non_const;
+ nice_printf(outfile, "*%ld", j);
+ rv *= j;
+ }
+ else {
+ non_const:
+ err ("wr_char_len: nonconstant array size");
+ }
+ }
+ /* extra1 allows for stupid C compilers that complain about
+ * too many initializers in
+ * char x[2] = "ab";
+ */
+ nice_printf(outfile, extra1 ? "+1]" : "]");
+ return extra1 ? rv+1 : rv;
+ }
+
+ static int ch_ar_dim = -1; /* length of each element of char string array */
+ static int eqvmemno; /* kludge */
+
+ static void
+#ifdef KR_headers
+write_char_init(outfile, Values, namep)
+ FILE *outfile;
+ chainp *Values;
+ Namep namep;
+#else
+write_char_init(FILE *outfile, chainp *Values, Namep namep)
+#endif
+{
+ struct Equivblock *eqv;
+ long size;
+ struct Dimblock *dimp;
+ int i, nd, type;
+ ftnint j;
+ expptr ds;
+
+ if (!namep)
+ return;
+ if(nequiv >= maxequiv)
+ many("equivalences", 'q', maxequiv);
+ eqv = &eqvclass[nequiv];
+ eqv->eqvbottom = 0;
+ type = namep->vtype;
+ size = type == TYCHAR
+ ? namep->vleng->constblock.Const.ci
+ : typesize[type];
+ if (dimp = namep->vdim)
+ for(i = 0, nd = dimp->ndim; i < nd; i++) {
+ ds = dimp->dims[i].dimsize;
+ if (ISCONST(ds)) {
+ if (ISINT(ds->constblock.vtype))
+ j = ds->constblock.Const.ci;
+ else if (ISREAL(ds->constblock.vtype))
+ j = (ftnint)ds->constblock.Const.cd[0];
+ else
+ goto non_const;
+ size *= j;
+ }
+ else {
+ non_const:
+ err("write_char_values: nonconstant array size");
+ }
+ }
+ *Values = revchain(*Values);
+ eqv->eqvtop = size;
+ eqvmemno = ++lastvarno;
+ eqv->eqvtype = type;
+ wr_equiv_init(outfile, nequiv, Values, 0);
+ def_start(outfile, namep->cvarname, CNULL, "");
+ if (type == TYCHAR)
+ margin_printf(outfile, "((char *)&equiv_%d)\n\n", eqvmemno);
+ else
+ margin_printf(outfile, dimp
+ ? "((%s *)&equiv_%d)\n\n" : "(*(%s *)&equiv_%d)\n\n",
+ c_type_decl(type,0), eqvmemno);
+ }
+
+/* wr_one_init -- outputs the initialization of the variable pointed to
+ by info. When is_addr is true, info is an Addrp; otherwise,
+ treat it as a Namep */
+
+ void
+#ifdef KR_headers
+wr_one_init(outfile, varname, Values, keepit)
+ FILE *outfile;
+ char *varname;
+ chainp *Values;
+ int keepit;
+#else
+wr_one_init(FILE *outfile, char *varname, chainp *Values, int keepit)
+#endif
+{
+ static int memno;
+ static union {
+ Namep name;
+ Addrp addr;
+ } info;
+ Namep namep;
+ int is_addr, size, type;
+ ftnint last, loc;
+ int is_scalar = 0;
+ char *array_comment = NULL, *name;
+ chainp cp, values;
+ extern char datachar[];
+ static int e1[3] = {1, 0, 1};
+ ftnint x;
+ extern int hsize;
+
+ if (!keepit)
+ goto done;
+ if (varname == NULL || varname[1] != '.')
+ goto badvar;
+
+/* Get back to a meaningful representation; find the given memno in one
+ of the appropriate tables (user-generated variables in the hash table,
+ system-generated variables in a separate list */
+
+ memno = atoi(varname + 2);
+ switch(varname[0]) {
+ case 'q':
+ /* Must subtract eqvstart when the source file
+ * contains more than one procedure.
+ */
+ wr_equiv_init(outfile, eqvmemno = memno - eqvstart, Values, 0);
+ goto done;
+ case 'Q':
+ /* COMMON initialization (BLOCK DATA) */
+ wr_equiv_init(outfile, memno, Values, 1);
+ goto done;
+ case 'v':
+ break;
+ default:
+ badvar:
+ errstr("wr_one_init: unknown variable name '%s'", varname);
+ goto done;
+ }
+
+ is_addr = memno2info (memno, &info.name);
+ if (info.name == (Namep) NULL) {
+ err ("wr_one_init -- unknown variable");
+ return;
+ }
+ if (is_addr) {
+ if (info.addr -> uname_tag != UNAM_NAME) {
+ erri ("wr_one_init -- couldn't get name pointer; tag is %d",
+ info.addr -> uname_tag);
+ namep = (Namep) NULL;
+ nice_printf (outfile, " /* bad init data */");
+ } else
+ namep = info.addr -> user.name;
+ } else
+ namep = info.name;
+
+ /* check for character initialization */
+
+ *Values = values = revchain(*Values);
+ type = info.name->vtype;
+ if (type == TYCHAR) {
+ for(last = 0; values; values = values->nextp) {
+ cp = (chainp)values->datap;
+ loc = (ftnint)cp->datap;
+ if (loc > last) {
+ write_char_init(outfile, Values, namep);
+ goto done;
+ }
+ last = (int)cp->nextp->datap == TYBLANK
+ ? loc + (int)cp->nextp->nextp->datap
+ : loc + 1;
+ }
+ if (halign && info.name->tag == TNAME) {
+ nice_printf(outfile, "static struct { %s fill; char val",
+ halign);
+ x = wr_char_len(outfile, namep->vdim, ch_ar_dim =
+ info.name -> vleng -> constblock.Const.ci, 1);
+ if (x %= hsize)
+ nice_printf(outfile, "; char fill2[%ld]", hsize - x);
+ name = info.name->cvarname;
+ nice_printf(outfile, "; } %s_st = { 0,", name);
+ wr_output_values(outfile, namep, *Values);
+ nice_printf(outfile, " };\n");
+ ch_ar_dim = -1;
+ def_start(outfile, name, CNULL, name);
+ margin_printf(outfile, "_st.val\n");
+ goto done;
+ }
+ }
+ else {
+ size = typesize[type];
+ loc = 0;
+ for(; values; values = values->nextp) {
+ if ((int)((chainp)values->datap)->nextp->datap == TYCHAR) {
+ write_char_init(outfile, Values, namep);
+ goto done;
+ }
+ last = ((long) ((chainp) values->datap)->datap) / size;
+ if (last - loc > 4) {
+ write_char_init(outfile, Values, namep);
+ goto done;
+ }
+ loc = last;
+ }
+ }
+ values = *Values;
+
+ nice_printf (outfile, "static %s ", c_type_decl (type, 0));
+
+ if (is_addr)
+ write_nv_ident (outfile, info.addr);
+ else
+ out_name (outfile, info.name);
+
+ if (namep)
+ is_scalar = namep -> vdim == (struct Dimblock *) NULL;
+
+ if (namep && !is_scalar)
+ array_comment = type == TYCHAR
+ ? 0 : wr_ardecls(outfile, namep->vdim, 1L);
+
+ if (type == TYCHAR)
+ if (ISICON (info.name -> vleng))
+
+/* We'll make single strings one character longer, so that we can use the
+ standard C initialization. All this does is pad an extra zero onto the
+ end of the string */
+ wr_char_len(outfile, namep->vdim, ch_ar_dim =
+ info.name -> vleng -> constblock.Const.ci, e1[Ansi]);
+ else
+ err ("variable length character initialization");
+
+ if (array_comment)
+ nice_printf (outfile, "%s", array_comment);
+
+ nice_printf (outfile, " = ");
+ wr_output_values (outfile, namep, values);
+ ch_ar_dim = -1;
+ nice_printf (outfile, ";\n");
+ done:
+ frchain(Values);
+} /* wr_one_init */
+
+
+
+
+ chainp
+#ifdef KR_headers
+data_value(infile, offset, type)
+ FILE *infile;
+ ftnint offset;
+ int type;
+#else
+data_value(FILE *infile, ftnint offset, int type)
+#endif
+{
+ char line[MAX_INIT_LINE + 1], *pointer;
+ chainp vals, prev_val;
+ char *newval;
+
+ if (fgets (line, MAX_INIT_LINE, infile) == NULL) {
+ err ("data_value: error reading from intermediate file");
+ return CHNULL;
+ } /* if fgets */
+
+/* Get rid of the trailing newline */
+
+ if (line[0])
+ line[strlen (line) - 1] = '\0';
+
+#define iswhite(x) (isspace (x) || (x) == ',')
+
+ pointer = line;
+ prev_val = vals = CHNULL;
+
+ while (*pointer) {
+ register char *end_ptr, old_val;
+
+/* Move pointer to the start of the next word */
+
+ while (*pointer && iswhite (*pointer))
+ pointer++;
+ if (*pointer == '\0')
+ break;
+
+/* Move end_ptr to the end of the current word */
+
+ for (end_ptr = pointer + 1; *end_ptr && !iswhite (*end_ptr);
+ end_ptr++)
+ ;
+
+ old_val = *end_ptr;
+ *end_ptr = '\0';
+
+/* Add this value to the end of the list */
+
+ if (ONEOF(type, MSKREAL|MSKCOMPLEX))
+ newval = cpstring(pointer);
+ else
+ newval = (char *)atol(pointer);
+ if (vals) {
+ prev_val->nextp = mkchain(newval, CHNULL);
+ prev_val = prev_val -> nextp;
+ } else
+ prev_val = vals = mkchain(newval, CHNULL);
+ *end_ptr = old_val;
+ pointer = end_ptr;
+ } /* while *pointer */
+
+ return mkchain((char *)offset, mkchain((char *)LONG_CAST type, vals));
+} /* data_value */
+
+ static void
+overlapping(Void)
+{
+ extern char *filename0;
+ static int warned = 0;
+
+ if (warned)
+ return;
+ warned = 1;
+
+ fprintf(stderr, "Error");
+ if (filename0)
+ fprintf(stderr, " in file %s", filename0);
+ fprintf(stderr, ": overlapping initializations\n");
+ nerr++;
+ }
+
+ static void make_one_const Argdcl((int, union Constant*, chainp));
+ static long charlen;
+
+ void
+#ifdef KR_headers
+wr_output_values(outfile, namep, values)
+ FILE *outfile;
+ Namep namep;
+ chainp values;
+#else
+wr_output_values(FILE *outfile, Namep namep, chainp values)
+#endif
+{
+ int type = TYUNKNOWN;
+ struct Constblock Const;
+ static expptr Vlen;
+
+ if (namep)
+ type = namep -> vtype;
+
+/* Handle array initializations away from scalars */
+
+ if (namep && namep -> vdim)
+ wr_array_init (outfile, namep -> vtype, values);
+
+ else if (values->nextp && type != TYCHAR)
+ overlapping();
+
+ else {
+ make_one_const(type, &Const.Const, values);
+ Const.vtype = type;
+ Const.vstg = ONEOF(type, MSKREAL|MSKCOMPLEX) != 0;
+ if (type== TYCHAR) {
+ if (!Vlen)
+ Vlen = ICON(0);
+ Const.vleng = Vlen;
+ Vlen->constblock.Const.ci = charlen;
+ out_const (outfile, &Const);
+ free (Const.Const.ccp);
+ }
+ else
+ out_const (outfile, &Const);
+ }
+ }
+
+
+ void
+#ifdef KR_headers
+wr_array_init(outfile, type, values)
+ FILE *outfile;
+ int type;
+ chainp values;
+#else
+wr_array_init(FILE *outfile, int type, chainp values)
+#endif
+{
+ int size = typesize[type];
+ long index, main_index = 0;
+ int k;
+
+ if (type == TYCHAR) {
+ nice_printf(outfile, "\"");
+ k = 0;
+ if (Ansi != 1)
+ ch_ar_dim = -1;
+ }
+ else
+ nice_printf (outfile, "{ ");
+ while (values) {
+ struct Constblock Const;
+
+ index = ((long) ((chainp) values->datap)->datap) / size;
+ while (index > main_index) {
+
+/* Fill with zeros. The structure shorthand works because the compiler
+ will expand the "0" in braces to fill the size of the entire structure
+ */
+
+ switch (type) {
+ case TYREAL:
+ case TYDREAL:
+ nice_printf (outfile, "0.0,");
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ nice_printf (outfile, "{0},");
+ break;
+ case TYCHAR:
+ nice_printf(outfile, " ");
+ break;
+ default:
+ nice_printf (outfile, "0,");
+ break;
+ } /* switch */
+ main_index++;
+ } /* while index > main_index */
+
+ if (index < main_index)
+ overlapping();
+ else switch (type) {
+ case TYCHAR:
+ { int this_char;
+
+ if (k == ch_ar_dim) {
+ nice_printf(outfile, "\" \"");
+ k = 0;
+ }
+ this_char = (int) ((chainp) values->datap)->
+ nextp->nextp->datap;
+ if ((int)((chainp)values->datap)->nextp->datap == TYBLANK) {
+ main_index += this_char;
+ k += this_char;
+ while(--this_char >= 0)
+ nice_printf(outfile, " ");
+ values = values -> nextp;
+ continue;
+ }
+ nice_printf(outfile, str_fmt[this_char], this_char);
+ k++;
+ } /* case TYCHAR */
+ break;
+
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYREAL:
+ case TYDREAL:
+ case TYLOGICAL:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ make_one_const(type, &Const.Const, values);
+ Const.vtype = type;
+ Const.vstg = ONEOF(type, MSKREAL|MSKCOMPLEX) != 0;
+ out_const(outfile, &Const);
+ break;
+ default:
+ erri("wr_array_init: bad type '%d'", type);
+ break;
+ } /* switch */
+ values = values->nextp;
+
+ main_index++;
+ if (values && type != TYCHAR)
+ nice_printf (outfile, ",");
+ } /* while values */
+
+ if (type == TYCHAR) {
+ nice_printf(outfile, "\"");
+ }
+ else
+ nice_printf (outfile, " }");
+} /* wr_array_init */
+
+
+ static void
+#ifdef KR_headers
+make_one_const(type, storage, values)
+ int type;
+ union Constant *storage;
+ chainp values;
+#else
+make_one_const(int type, union Constant *storage, chainp values)
+#endif
+{
+ union Constant *Const;
+ register char **L;
+
+ if (type == TYCHAR) {
+ char *str, *str_ptr;
+ chainp v, prev;
+ int b = 0, k, main_index = 0;
+
+/* Find the max length of init string, by finding the highest offset
+ value stored in the list of initial values */
+
+ for(k = 1, prev = CHNULL, v = values; v; prev = v, v = v->nextp)
+ ;
+ if (prev != CHNULL)
+ k = ((int) (((chainp) prev->datap)->datap)) + 2;
+ /* + 2 above for null char at end */
+ str = Alloc (k);
+ for (str_ptr = str; values; str_ptr++) {
+ int index = (int) (((chainp) values->datap)->datap);
+
+ if (index < main_index)
+ overlapping();
+ while (index > main_index++)
+ *str_ptr++ = ' ';
+
+ k = (int) (((chainp) values->datap)->nextp->nextp->datap);
+ if ((int)((chainp)values->datap)->nextp->datap == TYBLANK) {
+ b = k;
+ break;
+ }
+ *str_ptr = k;
+ values = values -> nextp;
+ } /* for str_ptr */
+ *str_ptr = '\0';
+ Const = storage;
+ Const -> ccp = str;
+ Const -> ccp1.blanks = b;
+ charlen = str_ptr - str;
+ } else {
+ int i = 0;
+ chainp vals;
+
+ vals = ((chainp)values->datap)->nextp->nextp;
+ if (vals) {
+ L = (char **)storage;
+ do L[i++] = vals->datap;
+ while(vals = vals->nextp);
+ }
+
+ } /* else */
+
+} /* make_one_const */
+
+
+ int
+#ifdef KR_headers
+rdname(infile, vargroupp, name)
+ FILE *infile;
+ int *vargroupp;
+ char *name;
+#else
+rdname(FILE *infile, int *vargroupp, char *name)
+#endif
+{
+ register int i, c;
+
+ c = getc (infile);
+
+ if (feof (infile))
+ return NO;
+
+ *vargroupp = c - '0';
+ for (i = 1;; i++) {
+ if (i >= NAME_MAX)
+ Fatal("rdname: oversize name");
+ c = getc (infile);
+ if (feof (infile))
+ return NO;
+ if (c == '\t')
+ break;
+ *name++ = c;
+ }
+ *name = 0;
+ return YES;
+} /* rdname */
+
+ int
+#ifdef KR_headers
+rdlong(infile, n)
+ FILE *infile;
+ ftnint *n;
+#else
+rdlong(FILE *infile, ftnint *n)
+#endif
+{
+ register int c;
+
+ for (c = getc (infile); !feof (infile) && isspace (c); c = getc (infile))
+ ;
+
+ if (feof (infile))
+ return NO;
+
+ for (*n = 0; isdigit (c); c = getc (infile))
+ *n = 10 * (*n) + c - '0';
+ return YES;
+} /* rdlong */
+
+
+ static int
+#ifdef KR_headers
+memno2info(memno, info)
+ int memno;
+ Namep *info;
+#else
+memno2info(int memno, Namep *info)
+#endif
+{
+ chainp this_var;
+ extern chainp new_vars;
+ extern struct Hashentry *hashtab, *lasthash;
+ struct Hashentry *entry;
+
+ for (this_var = new_vars; this_var; this_var = this_var -> nextp) {
+ Addrp var = (Addrp) this_var->datap;
+
+ if (var == (Addrp) NULL)
+ Fatal("memno2info: null variable");
+ else if (var -> tag != TADDR)
+ Fatal("memno2info: bad tag");
+ if (memno == var -> memno) {
+ *info = (Namep) var;
+ return 1;
+ } /* if memno == var -> memno */
+ } /* for this_var = new_vars */
+
+ for (entry = hashtab; entry < lasthash; ++entry) {
+ Namep var = entry -> varp;
+
+ if (var && var -> vardesc.varno == memno && var -> vstg == STGINIT) {
+ *info = (Namep) var;
+ return 0;
+ } /* if entry -> vardesc.varno == memno */
+ } /* for entry = hashtab */
+
+ Fatal("memno2info: couldn't find memno");
+ return 0;
+} /* memno2info */
+
+ static chainp
+#ifdef KR_headers
+do_string(outfile, v, nloc)
+ FILE *outfile;
+ register chainp v;
+ ftnint *nloc;
+#else
+do_string(FILE *outfile, register chainp v, ftnint *nloc)
+#endif
+{
+ register chainp cp, v0;
+ ftnint dloc, k, loc;
+ unsigned long uk;
+ char buf[8], *comma;
+
+ nice_printf(outfile, "{");
+ cp = (chainp)v->datap;
+ loc = (ftnint)cp->datap;
+ comma = "";
+ for(v0 = v;;) {
+ switch((int)cp->nextp->datap) {
+ case TYBLANK:
+ k = (ftnint)cp->nextp->nextp->datap;
+ loc += k;
+ while(--k >= 0) {
+ nice_printf(outfile, "%s' '", comma);
+ comma = ", ";
+ }
+ break;
+ case TYCHAR:
+ uk = (ftnint)cp->nextp->nextp->datap;
+ sprintf(buf, chr_fmt[uk], uk);
+ nice_printf(outfile, "%s'%s'", comma, buf);
+ comma = ", ";
+ loc++;
+ break;
+ default:
+ goto done;
+ }
+ v0 = v;
+ if (!(v = v->nextp) || !(cp = (chainp)v->datap))
+ break;
+ dloc = (ftnint)cp->datap;
+ if (loc != dloc)
+ break;
+ }
+ done:
+ nice_printf(outfile, "}");
+ *nloc = loc;
+ return v0;
+ }
+
+ static chainp
+#ifdef KR_headers
+Ado_string(outfile, v, nloc)
+ FILE *outfile;
+ register chainp v;
+ ftnint *nloc;
+#else
+Ado_string(FILE *outfile, register chainp v, ftnint *nloc)
+#endif
+{
+ register chainp cp, v0;
+ ftnint dloc, k, loc;
+
+ nice_printf(outfile, "\"");
+ cp = (chainp)v->datap;
+ loc = (ftnint)cp->datap;
+ for(v0 = v;;) {
+ switch((int)cp->nextp->datap) {
+ case TYBLANK:
+ k = (ftnint)cp->nextp->nextp->datap;
+ loc += k;
+ while(--k >= 0)
+ nice_printf(outfile, " ");
+ break;
+ case TYCHAR:
+ k = (ftnint)cp->nextp->nextp->datap;
+ nice_printf(outfile, str_fmt[k], k);
+ loc++;
+ break;
+ default:
+ goto done;
+ }
+ v0 = v;
+ if (!(v = v->nextp) || !(cp = (chainp)v->datap))
+ break;
+ dloc = (ftnint)cp->datap;
+ if (loc != dloc)
+ break;
+ }
+ done:
+ nice_printf(outfile, "\"");
+ *nloc = loc;
+ return v0;
+ }
+
+ static char *
+#ifdef KR_headers
+Len(L, type)
+ long L;
+ int type;
+#else
+Len(long L, int type)
+#endif
+{
+ static char buf[24];
+ if (L == 1 && type != TYCHAR)
+ return "";
+ sprintf(buf, "[%ld]", L);
+ return buf;
+ }
+
+ void
+#ifdef KR_headers
+wr_equiv_init(outfile, memno, Values, iscomm)
+ FILE *outfile;
+ int memno;
+ chainp *Values;
+ int iscomm;
+#else
+wr_equiv_init(FILE *outfile, int memno, chainp *Values, int iscomm)
+#endif
+{
+ struct Equivblock *eqv;
+ int btype, curtype, dtype, filltype, filltype1, j, k, wasblank, xtype;
+ static char Blank[] = "";
+ register char *comma = Blank;
+ register chainp cp, v;
+ chainp sentinel, values, v1, vlast;
+ ftnint L, L1, dL, dloc, loc, loc0;
+ union Constant Const;
+ char imag_buf[50], real_buf[50];
+ int szshort = typesize[TYSHORT];
+ static char typepref[] = {0, 0, TYINT1, TYSHORT, TYLONG,
+#ifdef TYQUAD
+ TYQUAD,
+#endif
+ TYREAL, TYDREAL, TYREAL, TYDREAL,
+ TYLOGICAL1, TYLOGICAL2,
+ TYLOGICAL, TYCHAR};
+ static char basetype[] = {0, 0, TYCHAR, TYSHORT, TYLONG,
+#ifdef TYQUAD
+ TYDREAL,
+#endif
+ TYLONG, TYDREAL, TYLONG, TYDREAL,
+ TYCHAR, TYSHORT,
+ TYLONG, TYCHAR, 0 /* for TYBLANK */ };
+ extern int htype;
+ char *z;
+
+ /* add sentinel */
+ if (iscomm) {
+ L = extsymtab[memno].maxleng;
+ xtype = extsymtab[memno].extype;
+ }
+ else {
+ eqv = &eqvclass[memno];
+ L = eqv->eqvtop - eqv->eqvbottom;
+ xtype = eqv->eqvtype;
+ }
+
+ if (halign && typealign[typepref[xtype]] < typealign[htype])
+ xtype = htype;
+ *Values = values = revchain(vlast = *Values);
+
+ if (xtype != TYCHAR) {
+
+ /* unless the data include a value of the appropriate
+ * type, we add an extra element in an attempt
+ * to force correct alignment */
+
+ btype = basetype[xtype];
+ loc = 0;
+ for(v = *Values;;v = v->nextp) {
+ if (!v) {
+ dtype = typepref[xtype];
+ z = ISREAL(dtype) ? cpstring("0.") : (char *)0;
+ k = typesize[dtype];
+ if (j = L % k)
+ L += k - j;
+ v = mkchain((char *)L,
+ mkchain((char *)LONG_CAST dtype,
+ mkchain(z, CHNULL)));
+ vlast = vlast->nextp =
+ mkchain((char *)v, CHNULL);
+ L += k;
+ break;
+ }
+ cp = (chainp)v->datap;
+ if (basetype[(int)cp->nextp->datap] == btype)
+ break;
+ dloc = (ftnint)cp->datap;
+ L1 = dloc - loc;
+ if (L1 > 0
+ && !(L1 % szshort)
+ && !(loc % szshort)
+ && btype <= type_choice[L1/szshort % 4]
+ && btype <= type_choice[loc/szshort % 4])
+ break;
+ dtype = (int)cp->nextp->datap;
+ loc = dloc + dtype == TYBLANK
+ ? (ftnint)cp->nextp->nextp->datap
+ : typesize[dtype];
+ }
+ }
+ sentinel = mkchain((char *)L, mkchain((char *)TYERROR,CHNULL));
+ vlast->nextp = mkchain((char *)sentinel, CHNULL);
+
+ /* use doublereal fillers only if there are doublereal values */
+
+ k = TYLONG;
+ for(v = values; v; v = v->nextp)
+ if (ONEOF((int)((chainp)v->datap)->nextp->datap,
+ M(TYDREAL)|M(TYDCOMPLEX))) {
+ k = TYDREAL;
+ break;
+ }
+ type_choice[0] = k;
+
+ nice_printf(outfile, "%sstruct {\n", iscomm ? "" : "static ");
+ next_tab(outfile);
+ loc = loc0 = k = 0;
+ curtype = -1;
+ for(v = values; v; v = v->nextp) {
+ cp = (chainp)v->datap;
+ dloc = (ftnint)cp->datap;
+ L = dloc - loc;
+ if (L < 0) {
+ overlapping();
+ if ((int)cp->nextp->datap != TYERROR) {
+ v1 = cp;
+ frchain(&v1);
+ v->datap = 0;
+ }
+ continue;
+ }
+ dtype = (int)cp->nextp->datap;
+ if (dtype == TYBLANK) {
+ dtype = TYCHAR;
+ wasblank = 1;
+ }
+ else
+ wasblank = 0;
+ if (curtype != dtype || L > 0) {
+ if (curtype != -1) {
+ L1 = (loc - loc0)/dL;
+ nice_printf(outfile, "%s e_%d%s;\n",
+ typename[curtype], ++k,
+ Len(L1,curtype));
+ }
+ curtype = dtype;
+ loc0 = dloc;
+ }
+ if (L > 0) {
+ if (xtype == TYCHAR)
+ filltype = TYCHAR;
+ else {
+ filltype = L % szshort ? TYCHAR
+ : type_choice[L/szshort % 4];
+ filltype1 = loc % szshort ? TYCHAR
+ : type_choice[loc/szshort % 4];
+ if (typesize[filltype] > typesize[filltype1])
+ filltype = filltype1;
+ }
+ L1 = L / typesize[filltype];
+ nice_printf(outfile, "%s fill_%d[%ld];\n",
+ typename[filltype], ++k, L1);
+ loc = dloc;
+ }
+ if (wasblank) {
+ loc += (ftnint)cp->nextp->nextp->datap;
+ dL = 1;
+ }
+ else {
+ dL = typesize[dtype];
+ loc += dL;
+ }
+ }
+ nice_printf(outfile, "} %s = { ", iscomm
+ ? extsymtab[memno].cextname
+ : equiv_name(eqvmemno, CNULL));
+ loc = 0;
+ for(v = values; ; v = v->nextp) {
+ cp = (chainp)v->datap;
+ if (!cp)
+ continue;
+ dtype = (int)cp->nextp->datap;
+ if (dtype == TYERROR)
+ break;
+ dloc = (ftnint)cp->datap;
+ if (dloc > loc) {
+ nice_printf(outfile, "%s{0}", comma);
+ comma = ", ";
+ loc = dloc;
+ }
+ if (comma != Blank)
+ nice_printf(outfile, ", ");
+ comma = ", ";
+ if (dtype == TYCHAR || dtype == TYBLANK) {
+ v = Ansi == 1 ? Ado_string(outfile, v, &loc)
+ : do_string(outfile, v, &loc);
+ continue;
+ }
+ make_one_const(dtype, &Const, v);
+ switch(dtype) {
+ case TYLOGICAL:
+ case TYLOGICAL2:
+ case TYLOGICAL1:
+ if (Const.ci < 0 || Const.ci > 1)
+ errl(
+ "wr_equiv_init: unexpected logical value %ld",
+ Const.ci);
+ nice_printf(outfile,
+ Const.ci ? "TRUE_" : "FALSE_");
+ break;
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ nice_printf(outfile, "%ld", Const.ci);
+ break;
+ case TYREAL:
+ nice_printf(outfile, "%s",
+ flconst(real_buf, Const.cds[0]));
+ break;
+ case TYDREAL:
+ nice_printf(outfile, "%s", Const.cds[0]);
+ break;
+ case TYCOMPLEX:
+ nice_printf(outfile, "%s, %s",
+ flconst(real_buf, Const.cds[0]),
+ flconst(imag_buf, Const.cds[1]));
+ break;
+ case TYDCOMPLEX:
+ nice_printf(outfile, "%s, %s",
+ Const.cds[0], Const.cds[1]);
+ break;
+ default:
+ erri("unexpected type %d in wr_equiv_init",
+ dtype);
+ }
+ loc += typesize[dtype];
+ }
+ nice_printf(outfile, " };\n\n");
+ prev_tab(outfile);
+ frchain(&sentinel);
+ }
diff --git a/usr.bin/f2c/ftypes.h b/usr.bin/f2c/ftypes.h
new file mode 100644
index 0000000..80d2deb
--- /dev/null
+++ b/usr.bin/f2c/ftypes.h
@@ -0,0 +1,51 @@
+
+/* variable types (stored in the vtype field of expptr)
+ * numeric assumptions:
+ * int < reals < complexes
+ * TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX
+ */
+
+#ifdef NO_TYQUAD
+#undef TYQUAD
+#define TYQUAD_inc 0
+#else
+#define TYQUAD 5
+#define TYQUAD_inc 1
+#endif
+
+#define TYUNKNOWN 0
+#define TYADDR 1
+#define TYINT1 2
+#define TYSHORT 3
+#define TYLONG 4
+/* #define TYQUAD 5 */
+#define TYREAL (5+TYQUAD_inc)
+#define TYDREAL (6+TYQUAD_inc)
+#define TYCOMPLEX (7+TYQUAD_inc)
+#define TYDCOMPLEX (8+TYQUAD_inc)
+#define TYLOGICAL1 (9+TYQUAD_inc)
+#define TYLOGICAL2 (10+TYQUAD_inc)
+#define TYLOGICAL (11+TYQUAD_inc)
+#define TYCHAR (12+TYQUAD_inc)
+#define TYSUBR (13+TYQUAD_inc)
+#define TYERROR (14+TYQUAD_inc)
+#define TYCILIST (15+TYQUAD_inc)
+#define TYICILIST (16+TYQUAD_inc)
+#define TYOLIST (17+TYQUAD_inc)
+#define TYCLLIST (18+TYQUAD_inc)
+#define TYALIST (19+TYQUAD_inc)
+#define TYINLIST (20+TYQUAD_inc)
+#define TYVOID (21+TYQUAD_inc)
+#define TYLABEL (22+TYQUAD_inc)
+#define TYFTNLEN (23+TYQUAD_inc)
+/* TYVOID is not in any tables. */
+
+/* NTYPES, NTYPES0 -- Total number of types, used to allocate tables indexed by
+ type. Such tables can include the size (in bytes) of objects of a given
+ type, or labels for returning objects of different types from procedures
+ (see array rtvlabels) */
+
+#define NTYPES TYVOID
+#define NTYPES0 TYCILIST
+#define TYBLANK TYSUBR /* Huh? */
+
diff --git a/usr.bin/f2c/gram.dcl b/usr.bin/f2c/gram.dcl
new file mode 100644
index 0000000..b30a45c
--- /dev/null
+++ b/usr.bin/f2c/gram.dcl
@@ -0,0 +1,416 @@
+spec: dcl
+ | common
+ | external
+ | intrinsic
+ | equivalence
+ | data
+ | implicit
+ | namelist
+ | SSAVE
+ { NO66("SAVE statement");
+ saveall = YES; }
+ | SSAVE savelist
+ { NO66("SAVE statement"); }
+ | SFORMAT
+ { fmtstmt(thislabel); setfmt(thislabel); }
+ | SPARAM in_dcl SLPAR paramlist SRPAR
+ { NO66("PARAMETER statement"); }
+ ;
+
+dcl: type opt_comma name in_dcl new_dcl dims lengspec
+ { settype($3, $1, $7);
+ if(ndim>0) setbound($3,ndim,dims);
+ }
+ | dcl SCOMMA name dims lengspec
+ { settype($3, $1, $5);
+ if(ndim>0) setbound($3,ndim,dims);
+ }
+ | dcl SSLASHD datainit vallist SSLASHD
+ { if (new_dcl == 2) {
+ err("attempt to give DATA in type-declaration");
+ new_dcl = 1;
+ }
+ }
+ ;
+
+new_dcl: { new_dcl = 2; } ;
+
+type: typespec lengspec
+ { varleng = $2; }
+ ;
+
+typespec: typename
+ { varleng = ($1<0 || ONEOF($1,M(TYLOGICAL)|M(TYLONG))
+ ? 0 : typesize[$1]);
+ vartype = $1; }
+ ;
+
+typename: SINTEGER { $$ = TYLONG; }
+ | SREAL { $$ = tyreal; }
+ | SCOMPLEX { ++complex_seen; $$ = tycomplex; }
+ | SDOUBLE { $$ = TYDREAL; }
+ | SDCOMPLEX { ++dcomplex_seen; NOEXT("DOUBLE COMPLEX statement"); $$ = TYDCOMPLEX; }
+ | SLOGICAL { $$ = TYLOGICAL; }
+ | SCHARACTER { NO66("CHARACTER statement"); $$ = TYCHAR; }
+ | SUNDEFINED { $$ = TYUNKNOWN; }
+ | SDIMENSION { $$ = TYUNKNOWN; }
+ | SAUTOMATIC { NOEXT("AUTOMATIC statement"); $$ = - STGAUTO; }
+ | SSTATIC { NOEXT("STATIC statement"); $$ = - STGBSS; }
+ | SBYTE { $$ = TYINT1; }
+ ;
+
+lengspec:
+ { $$ = varleng; }
+ | SSTAR intonlyon expr intonlyoff
+ {
+ expptr p;
+ p = $3;
+ NO66("length specification *n");
+ if( ! ISICON(p) || p->constblock.Const.ci <= 0 )
+ {
+ $$ = 0;
+ dclerr("length must be a positive integer constant",
+ NPNULL);
+ }
+ else {
+ if (vartype == TYCHAR)
+ $$ = p->constblock.Const.ci;
+ else switch((int)p->constblock.Const.ci) {
+ case 1: $$ = 1; break;
+ case 2: $$ = typesize[TYSHORT]; break;
+ case 4: $$ = typesize[TYLONG]; break;
+ case 8: $$ = typesize[TYDREAL]; break;
+ case 16: $$ = typesize[TYDCOMPLEX]; break;
+ default:
+ dclerr("invalid length",NPNULL);
+ $$ = varleng;
+ }
+ }
+ }
+ | SSTAR intonlyon SLPAR SSTAR SRPAR intonlyoff
+ { NO66("length specification *(*)"); $$ = -1; }
+ ;
+
+common: SCOMMON in_dcl var
+ { incomm( $$ = comblock("") , $3 ); }
+ | SCOMMON in_dcl comblock var
+ { $$ = $3; incomm($3, $4); }
+ | common opt_comma comblock opt_comma var
+ { $$ = $3; incomm($3, $5); }
+ | common SCOMMA var
+ { incomm($1, $3); }
+ ;
+
+comblock: SCONCAT
+ { $$ = comblock(""); }
+ | SSLASH SNAME SSLASH
+ { $$ = comblock(token); }
+ ;
+
+external: SEXTERNAL in_dcl name
+ { setext($3); }
+ | external SCOMMA name
+ { setext($3); }
+ ;
+
+intrinsic: SINTRINSIC in_dcl name
+ { NO66("INTRINSIC statement"); setintr($3); }
+ | intrinsic SCOMMA name
+ { setintr($3); }
+ ;
+
+equivalence: SEQUIV in_dcl equivset
+ | equivalence SCOMMA equivset
+ ;
+
+equivset: SLPAR equivlist SRPAR
+ {
+ struct Equivblock *p;
+ if(nequiv >= maxequiv)
+ many("equivalences", 'q', maxequiv);
+ p = & eqvclass[nequiv++];
+ p->eqvinit = NO;
+ p->eqvbottom = 0;
+ p->eqvtop = 0;
+ p->equivs = $2;
+ }
+ ;
+
+equivlist: lhs
+ { $$=ALLOC(Eqvchain);
+ $$->eqvitem.eqvlhs = primchk($1);
+ }
+ | equivlist SCOMMA lhs
+ { $$=ALLOC(Eqvchain);
+ $$->eqvitem.eqvlhs = primchk($3);
+ $$->eqvnextp = $1;
+ }
+ ;
+
+data: SDATA in_data datalist
+ | data opt_comma datalist
+ ;
+
+in_data:
+ { if(parstate == OUTSIDE)
+ {
+ newproc();
+ startproc(ESNULL, CLMAIN);
+ }
+ if(parstate < INDATA)
+ {
+ enddcl();
+ parstate = INDATA;
+ datagripe = 1;
+ }
+ }
+ ;
+
+datalist: datainit datavarlist SSLASH datapop vallist SSLASH
+ { ftnint junk;
+ if(nextdata(&junk) != NULL)
+ err("too few initializers");
+ frdata($2);
+ frrpl();
+ }
+ ;
+
+datainit: /* nothing */ { frchain(&datastack); curdtp = 0; } ;
+
+datapop: /* nothing */ { pop_datastack(); } ;
+
+vallist: { toomanyinit = NO; } val
+ | vallist SCOMMA val
+ ;
+
+val: value
+ { dataval(ENULL, $1); }
+ | simple SSTAR value
+ { dataval($1, $3); }
+ ;
+
+value: simple
+ | addop simple
+ { if( $1==OPMINUS && ISCONST($2) )
+ consnegop((Constp)$2);
+ $$ = $2;
+ }
+ | complex_const
+ ;
+
+savelist: saveitem
+ | savelist SCOMMA saveitem
+ ;
+
+saveitem: name
+ { int k;
+ $1->vsave = YES;
+ k = $1->vstg;
+ if( ! ONEOF(k, M(STGUNKNOWN)|M(STGBSS)|M(STGINIT)) )
+ dclerr("can only save static variables", $1);
+ }
+ | comblock
+ ;
+
+paramlist: paramitem
+ | paramlist SCOMMA paramitem
+ ;
+
+paramitem: name SEQUALS expr
+ { if($1->vclass == CLUNKNOWN)
+ make_param((struct Paramblock *)$1, $3);
+ else dclerr("cannot make into parameter", $1);
+ }
+ ;
+
+var: name dims
+ { if(ndim>0) setbound($1, ndim, dims); }
+ ;
+
+datavar: lhs
+ { Namep np;
+ struct Primblock *pp = (struct Primblock *)$1;
+ int tt = $1->tag;
+ if (tt != TPRIM) {
+ if (tt == TCONST)
+ err("parameter in data statement");
+ else
+ erri("tag %d in data statement",tt);
+ $$ = 0;
+ err_lineno = lineno;
+ break;
+ }
+ np = pp -> namep;
+ vardcl(np);
+ if ((pp->fcharp || pp->lcharp)
+ && (np->vtype != TYCHAR || np->vdim))
+ sserr(np);
+ if(np->vstg == STGCOMMON)
+ extsymtab[np->vardesc.varno].extinit = YES;
+ else if(np->vstg==STGEQUIV)
+ eqvclass[np->vardesc.varno].eqvinit = YES;
+ else if(np->vstg!=STGINIT && np->vstg!=STGBSS) {
+ errstr(np->vstg == STGARG
+ ? "Dummy argument \"%.60s\" in data statement."
+ : "Cannot give data to \"%.75s\"",
+ np->fvarname);
+ $$ = 0;
+ err_lineno = lineno;
+ break;
+ }
+ $$ = mkchain((char *)$1, CHNULL);
+ }
+ | SLPAR datavarlist SCOMMA dospec SRPAR
+ { chainp p; struct Impldoblock *q;
+ pop_datastack();
+ q = ALLOC(Impldoblock);
+ q->tag = TIMPLDO;
+ (q->varnp = (Namep) ($4->datap))->vimpldovar = 1;
+ p = $4->nextp;
+ if(p) { q->implb = (expptr)(p->datap); p = p->nextp; }
+ if(p) { q->impub = (expptr)(p->datap); p = p->nextp; }
+ if(p) { q->impstep = (expptr)(p->datap); }
+ frchain( & ($4) );
+ $$ = mkchain((char *)q, CHNULL);
+ q->datalist = hookup($2, $$);
+ }
+ ;
+
+datavarlist: datavar
+ { if (!datastack)
+ curdtp = 0;
+ datastack = mkchain((char *)curdtp, datastack);
+ curdtp = $1; curdtelt = 0;
+ }
+ | datavarlist SCOMMA datavar
+ { $$ = hookup($1, $3); }
+ ;
+
+dims:
+ { ndim = 0; }
+ | SLPAR dimlist SRPAR
+ ;
+
+dimlist: { ndim = 0; } dim
+ | dimlist SCOMMA dim
+ ;
+
+dim: ubound
+ {
+ if(ndim == maxdim)
+ err("too many dimensions");
+ else if(ndim < maxdim)
+ { dims[ndim].lb = 0;
+ dims[ndim].ub = $1;
+ }
+ ++ndim;
+ }
+ | expr SCOLON ubound
+ {
+ if(ndim == maxdim)
+ err("too many dimensions");
+ else if(ndim < maxdim)
+ { dims[ndim].lb = $1;
+ dims[ndim].ub = $3;
+ }
+ ++ndim;
+ }
+ ;
+
+ubound: SSTAR
+ { $$ = 0; }
+ | expr
+ ;
+
+labellist: label
+ { nstars = 1; labarray[0] = $1; }
+ | labellist SCOMMA label
+ { if(nstars < maxlablist) labarray[nstars++] = $3; }
+ ;
+
+label: SICON
+ { $$ = execlab( convci(toklen, token) ); }
+ ;
+
+implicit: SIMPLICIT in_dcl implist
+ { NO66("IMPLICIT statement"); }
+ | implicit SCOMMA implist
+ ;
+
+implist: imptype SLPAR letgroups SRPAR
+ | imptype
+ { if (vartype != TYUNKNOWN)
+ dclerr("-- expected letter range",NPNULL);
+ setimpl(vartype, varleng, 'a', 'z'); }
+ ;
+
+imptype: { needkwd = 1; } type
+ /* { vartype = $2; } */
+ ;
+
+letgroups: letgroup
+ | letgroups SCOMMA letgroup
+ ;
+
+letgroup: letter
+ { setimpl(vartype, varleng, $1, $1); }
+ | letter SMINUS letter
+ { setimpl(vartype, varleng, $1, $3); }
+ ;
+
+letter: SNAME
+ { if(toklen!=1 || token[0]<'a' || token[0]>'z')
+ {
+ dclerr("implicit item must be single letter", NPNULL);
+ $$ = 0;
+ }
+ else $$ = token[0];
+ }
+ ;
+
+namelist: SNAMELIST
+ | namelist namelistentry
+ ;
+
+namelistentry: SSLASH name SSLASH namelistlist
+ {
+ if($2->vclass == CLUNKNOWN)
+ {
+ $2->vclass = CLNAMELIST;
+ $2->vtype = TYINT;
+ $2->vstg = STGBSS;
+ $2->varxptr.namelist = $4;
+ $2->vardesc.varno = ++lastvarno;
+ }
+ else dclerr("cannot be a namelist name", $2);
+ }
+ ;
+
+namelistlist: name
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | namelistlist SCOMMA name
+ { $$ = hookup($1, mkchain((char *)$3, CHNULL)); }
+ ;
+
+in_dcl:
+ { switch(parstate)
+ {
+ case OUTSIDE: newproc();
+ startproc(ESNULL, CLMAIN);
+ case INSIDE: parstate = INDCL;
+ case INDCL: break;
+
+ case INDATA:
+ if (datagripe) {
+ errstr(
+ "Statement order error: declaration after DATA",
+ CNULL);
+ datagripe = 0;
+ }
+ break;
+
+ default:
+ dclerr("declaration among executables", NPNULL);
+ }
+ }
+ ;
diff --git a/usr.bin/f2c/gram.exec b/usr.bin/f2c/gram.exec
new file mode 100644
index 0000000..39d7e42
--- /dev/null
+++ b/usr.bin/f2c/gram.exec
@@ -0,0 +1,143 @@
+exec: iffable
+ | SDO end_spec label opt_comma dospecw
+ {
+ if($3->labdefined)
+ execerr("no backward DO loops", CNULL);
+ $3->blklevel = blklevel+1;
+ exdo($3->labelno, NPNULL, $5);
+ }
+ | SDO end_spec opt_comma dospecw
+ {
+ exdo((int)(ctls - ctlstack - 2), NPNULL, $4);
+ NOEXT("DO without label");
+ }
+ | SENDDO
+ { exenddo(NPNULL); }
+ | logif iffable
+ { exendif(); thiswasbranch = NO; }
+ | logif STHEN
+ | SELSEIF end_spec SLPAR expr SRPAR STHEN
+ { exelif($4); lastwasbranch = NO; }
+ | SELSE end_spec
+ { exelse(); lastwasbranch = NO; }
+ | SENDIF end_spec
+ { exendif(); lastwasbranch = NO; }
+ ;
+
+logif: SLOGIF end_spec SLPAR expr SRPAR
+ { exif($4); }
+ ;
+
+dospec: name SEQUALS exprlist
+ { $$ = mkchain((char *)$1, $3); }
+ ;
+
+dospecw: dospec
+ | SWHILE SLPAR expr SRPAR
+ { $$ = mkchain(CNULL, (chainp)$3); }
+ ;
+
+iffable: let lhs SEQUALS expr
+ { exequals((struct Primblock *)$2, $4); }
+ | SASSIGN end_spec assignlabel STO name
+ { exassign($5, $3); }
+ | SCONTINUE end_spec
+ | goto
+ | io
+ { inioctl = NO; }
+ | SARITHIF end_spec SLPAR expr SRPAR label SCOMMA label SCOMMA label
+ { exarif($4, $6, $8, $10); thiswasbranch = YES; }
+ | call
+ { excall($1, LBNULL, 0, labarray); }
+ | call SLPAR SRPAR
+ { excall($1, LBNULL, 0, labarray); }
+ | call SLPAR callarglist SRPAR
+ { if(nstars < maxlablist)
+ excall($1, mklist(revchain($3)), nstars, labarray);
+ else
+ many("alternate returns", 'l', maxlablist);
+ }
+ | SRETURN end_spec opt_expr
+ { exreturn($3); thiswasbranch = YES; }
+ | stop end_spec opt_expr
+ { exstop($1, $3); thiswasbranch = $1; }
+ ;
+
+assignlabel: SICON
+ { $$ = mklabel( convci(toklen, token) ); }
+ ;
+
+let: SLET
+ { if(parstate == OUTSIDE)
+ {
+ newproc();
+ startproc(ESNULL, CLMAIN);
+ }
+ }
+ ;
+
+goto: SGOTO end_spec label
+ { exgoto($3); thiswasbranch = YES; }
+ | SASGOTO end_spec name
+ { exasgoto($3); thiswasbranch = YES; }
+ | SASGOTO end_spec name opt_comma SLPAR labellist SRPAR
+ { exasgoto($3); thiswasbranch = YES; }
+ | SCOMPGOTO end_spec SLPAR labellist SRPAR opt_comma expr
+ { if(nstars < maxlablist)
+ putcmgo(putx(fixtype($7)), nstars, labarray);
+ else
+ many("labels in computed GOTO list", 'l', maxlablist);
+ }
+ ;
+
+opt_comma:
+ | SCOMMA
+ ;
+
+call: SCALL end_spec name
+ { nstars = 0; $$ = $3; }
+ ;
+
+callarglist: callarg
+ { $$ = $1 ? mkchain((char *)$1,CHNULL) : CHNULL; }
+ | callarglist SCOMMA callarg
+ { $$ = $3 ? mkchain((char *)$3, $1) : $1; }
+ ;
+
+callarg: expr
+ | SSTAR label
+ { if(nstars < maxlablist) labarray[nstars++] = $2; $$ = 0; }
+ ;
+
+stop: SPAUSE
+ { $$ = 0; }
+ | SSTOP
+ { $$ = 2; }
+ ;
+
+exprlist: expr
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | exprlist SCOMMA expr
+ { $$ = hookup($1, mkchain((char *)$3,CHNULL) ); }
+ ;
+
+end_spec:
+ { if(parstate == OUTSIDE)
+ {
+ newproc();
+ startproc(ESNULL, CLMAIN);
+ }
+
+/* This next statement depends on the ordering of the state table encoding */
+
+ if(parstate < INDATA) enddcl();
+ }
+ ;
+
+intonlyon:
+ { intonly = YES; }
+ ;
+
+intonlyoff:
+ { intonly = NO; }
+ ;
diff --git a/usr.bin/f2c/gram.expr b/usr.bin/f2c/gram.expr
new file mode 100644
index 0000000..1ef18e5
--- /dev/null
+++ b/usr.bin/f2c/gram.expr
@@ -0,0 +1,142 @@
+funarglist:
+ { $$ = 0; }
+ | funargs
+ { $$ = revchain($1); }
+ ;
+
+funargs: expr
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | funargs SCOMMA expr
+ { $$ = mkchain((char *)$3, $1); }
+ ;
+
+
+expr: uexpr
+ | SLPAR expr SRPAR { $$ = $2; if ($$->tag == TPRIM)
+ $$->primblock.parenused = 1; }
+ | complex_const
+ ;
+
+uexpr: lhs
+ | simple_const
+ | expr addop expr %prec SPLUS
+ { $$ = mkexpr($2, $1, $3); }
+ | expr SSTAR expr
+ { $$ = mkexpr(OPSTAR, $1, $3); }
+ | expr SSLASH expr
+ { $$ = mkexpr(OPSLASH, $1, $3); }
+ | expr SPOWER expr
+ { $$ = mkexpr(OPPOWER, $1, $3); }
+ | addop expr %prec SSTAR
+ { if($1 == OPMINUS)
+ $$ = mkexpr(OPNEG, $2, ENULL);
+ else $$ = $2;
+ }
+ | expr relop expr %prec SEQ
+ { $$ = mkexpr($2, $1, $3); }
+ | expr SEQV expr
+ { NO66(".EQV. operator");
+ $$ = mkexpr(OPEQV, $1,$3); }
+ | expr SNEQV expr
+ { NO66(".NEQV. operator");
+ $$ = mkexpr(OPNEQV, $1, $3); }
+ | expr SOR expr
+ { $$ = mkexpr(OPOR, $1, $3); }
+ | expr SAND expr
+ { $$ = mkexpr(OPAND, $1, $3); }
+ | SNOT expr
+ { $$ = mkexpr(OPNOT, $2, ENULL); }
+ | expr SCONCAT expr
+ { NO66("concatenation operator //");
+ $$ = mkexpr(OPCONCAT, $1, $3); }
+ ;
+
+addop: SPLUS { $$ = OPPLUS; }
+ | SMINUS { $$ = OPMINUS; }
+ ;
+
+relop: SEQ { $$ = OPEQ; }
+ | SGT { $$ = OPGT; }
+ | SLT { $$ = OPLT; }
+ | SGE { $$ = OPGE; }
+ | SLE { $$ = OPLE; }
+ | SNE { $$ = OPNE; }
+ ;
+
+lhs: name
+ { $$ = mkprim($1, LBNULL, CHNULL); }
+ | name substring
+ { NO66("substring operator :");
+ $$ = mkprim($1, LBNULL, $2); }
+ | name SLPAR funarglist SRPAR
+ { $$ = mkprim($1, mklist($3), CHNULL); }
+ | name SLPAR funarglist SRPAR substring
+ { NO66("substring operator :");
+ $$ = mkprim($1, mklist($3), $5); }
+ ;
+
+substring: SLPAR opt_expr SCOLON opt_expr SRPAR
+ { $$ = mkchain((char *)$2, mkchain((char *)$4,CHNULL)); }
+ ;
+
+opt_expr:
+ { $$ = 0; }
+ | expr
+ ;
+
+simple: name
+ { if($1->vclass == CLPARAM)
+ $$ = (expptr) cpexpr(
+ ( (struct Paramblock *) ($1) ) -> paramval);
+ }
+ | simple_const
+ ;
+
+simple_const: STRUE { $$ = mklogcon(1); }
+ | SFALSE { $$ = mklogcon(0); }
+ | SHOLLERITH { $$ = mkstrcon(toklen, token); }
+ | SICON = { $$ = mkintcon( convci(toklen, token) ); }
+ | SRCON = { $$ = mkrealcon(tyreal, token); }
+ | SDCON = { $$ = mkrealcon(TYDREAL, token); }
+ | bit_const
+ ;
+
+complex_const: SLPAR uexpr SCOMMA uexpr SRPAR
+ { $$ = mkcxcon($2,$4); }
+ ;
+
+bit_const: SHEXCON
+ { NOEXT("hex constant");
+ $$ = mkbitcon(4, toklen, token); }
+ | SOCTCON
+ { NOEXT("octal constant");
+ $$ = mkbitcon(3, toklen, token); }
+ | SBITCON
+ { NOEXT("binary constant");
+ $$ = mkbitcon(1, toklen, token); }
+ ;
+
+fexpr: unpar_fexpr
+ | SLPAR fexpr SRPAR
+ { $$ = $2; }
+ ;
+
+unpar_fexpr: lhs
+ | simple_const
+ | fexpr addop fexpr %prec SPLUS
+ { $$ = mkexpr($2, $1, $3); }
+ | fexpr SSTAR fexpr
+ { $$ = mkexpr(OPSTAR, $1, $3); }
+ | fexpr SSLASH fexpr
+ { $$ = mkexpr(OPSLASH, $1, $3); }
+ | fexpr SPOWER fexpr
+ { $$ = mkexpr(OPPOWER, $1, $3); }
+ | addop fexpr %prec SSTAR
+ { if($1 == OPMINUS)
+ $$ = mkexpr(OPNEG, $2, ENULL);
+ else $$ = $2;
+ }
+ | fexpr SCONCAT fexpr
+ { NO66("concatenation operator //");
+ $$ = mkexpr(OPCONCAT, $1, $3); }
+ ;
diff --git a/usr.bin/f2c/gram.head b/usr.bin/f2c/gram.head
new file mode 100644
index 0000000..183dfeb
--- /dev/null
+++ b/usr.bin/f2c/gram.head
@@ -0,0 +1,291 @@
+/****************************************************************
+Copyright 1990, 1993 by AT&T Bell Laboratories, Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T Bell Laboratories or
+Bellcore or any of their entities not be used in advertising or
+publicity pertaining to distribution of the software without
+specific, written prior permission.
+
+AT&T and Bellcore disclaim all warranties with regard to this
+software, including all implied warranties of merchantability
+and fitness. In no event shall AT&T or Bellcore be liable for
+any special, indirect or consequential damages or any damages
+whatsoever resulting from loss of use, data or profits, whether
+in an action of contract, negligence or other tortious action,
+arising out of or in connection with the use or performance of
+this software.
+****************************************************************/
+
+%{
+#include "defs.h"
+#include "p1defs.h"
+
+static int nstars; /* Number of labels in an
+ alternate return CALL */
+static int datagripe;
+static int ndim;
+static int vartype;
+int new_dcl;
+static ftnint varleng;
+static struct Dims dims[MAXDIM+1];
+extern struct Labelblock **labarray; /* Labels in an alternate
+ return CALL */
+extern int maxlablist;
+
+/* The next two variables are used to verify that each statement might be reached
+ during runtime. lastwasbranch is tested only in the defintion of the
+ stat: nonterminal. */
+
+int lastwasbranch = NO;
+static int thiswasbranch = NO;
+extern ftnint yystno;
+extern flag intonly;
+static chainp datastack;
+extern long laststfcn, thisstno;
+extern int can_include; /* for netlib */
+extern struct Primblock *primchk Argdcl((expptr));
+
+#define ESNULL (Extsym *)0
+#define NPNULL (Namep)0
+#define LBNULL (struct Listblock *)0
+
+ static void
+pop_datastack(Void) {
+ chainp d0 = datastack;
+ if (d0->datap)
+ curdtp = (chainp)d0->datap;
+ datastack = d0->nextp;
+ d0->nextp = 0;
+ frchain(&d0);
+ }
+
+%}
+
+/* Specify precedences and associativities. */
+
+%union {
+ int ival;
+ ftnint lval;
+ char *charpval;
+ chainp chval;
+ tagptr tagval;
+ expptr expval;
+ struct Labelblock *labval;
+ struct Nameblock *namval;
+ struct Eqvchain *eqvval;
+ Extsym *extval;
+ }
+
+%left SCOMMA
+%nonassoc SCOLON
+%right SEQUALS
+%left SEQV SNEQV
+%left SOR
+%left SAND
+%left SNOT
+%nonassoc SLT SGT SLE SGE SEQ SNE
+%left SCONCAT
+%left SPLUS SMINUS
+%left SSTAR SSLASH
+%right SPOWER
+
+%start program
+%type <labval> thislabel label assignlabel
+%type <tagval> other inelt
+%type <ival> type typespec typename dcl letter addop relop stop nameeq
+%type <lval> lengspec
+%type <charpval> filename
+%type <chval> datavar datavarlist namelistlist funarglist funargs
+%type <chval> dospec dospecw
+%type <chval> callarglist arglist args exprlist inlist outlist out2 substring
+%type <namval> name arg call var
+%type <expval> lhs expr uexpr opt_expr fexpr unpar_fexpr
+%type <expval> ubound simple value callarg complex_const simple_const bit_const
+%type <extval> common comblock entryname progname
+%type <eqvval> equivlist
+
+%%
+
+program:
+ | program stat SEOS
+ ;
+
+stat: thislabel entry
+ {
+/* stat: is the nonterminal for Fortran statements */
+
+ lastwasbranch = NO; }
+ | thislabel spec
+ | thislabel exec
+ { /* forbid further statement function definitions... */
+ if (parstate == INDATA && laststfcn != thisstno)
+ parstate = INEXEC;
+ thisstno++;
+ if($1 && ($1->labelno==dorange))
+ enddo($1->labelno);
+ if(lastwasbranch && thislabel==NULL)
+ warn("statement cannot be reached");
+ lastwasbranch = thiswasbranch;
+ thiswasbranch = NO;
+ if($1)
+ {
+ if($1->labtype == LABFORMAT)
+ err("label already that of a format");
+ else
+ $1->labtype = LABEXEC;
+ }
+ freetemps();
+ }
+ | thislabel SINCLUDE filename
+ { if (can_include)
+ doinclude( $3 );
+ else {
+ fprintf(diagfile, "Cannot open file %s\n", $3);
+ done(1);
+ }
+ }
+ | thislabel SEND end_spec
+ { if ($1)
+ lastwasbranch = NO;
+ endproc(); /* lastwasbranch = NO; -- set in endproc() */
+ }
+ | thislabel SUNKNOWN
+ { unclassifiable();
+
+/* flline flushes the current line, ignoring the rest of the text there */
+
+ flline(); }
+ | error
+ { flline(); needkwd = NO; inioctl = NO;
+ yyerrok; yyclearin; }
+ ;
+
+thislabel: SLABEL
+ {
+ if(yystno != 0)
+ {
+ $$ = thislabel = mklabel(yystno);
+ if( ! headerdone ) {
+ if (procclass == CLUNKNOWN)
+ procclass = CLMAIN;
+ puthead(CNULL, procclass);
+ }
+ if(thislabel->labdefined)
+ execerr("label %s already defined",
+ convic(thislabel->stateno) );
+ else {
+ if(thislabel->blklevel!=0 && thislabel->blklevel<blklevel
+ && thislabel->labtype!=LABFORMAT)
+ warn1("there is a branch to label %s from outside block",
+ convic( (ftnint) (thislabel->stateno) ) );
+ thislabel->blklevel = blklevel;
+ thislabel->labdefined = YES;
+ if(thislabel->labtype != LABFORMAT)
+ p1_label((long)(thislabel - labeltab));
+ }
+ }
+ else $$ = thislabel = NULL;
+ }
+ ;
+
+entry: SPROGRAM new_proc progname
+ {startproc($3, CLMAIN); }
+ | SPROGRAM new_proc progname progarglist
+ { warn("ignoring arguments to main program");
+ /* hashclear(); */
+ startproc($3, CLMAIN); }
+ | SBLOCK new_proc progname
+ { if($3) NO66("named BLOCKDATA");
+ startproc($3, CLBLOCK); }
+ | SSUBROUTINE new_proc entryname arglist
+ { entrypt(CLPROC, TYSUBR, (ftnint) 0, $3, $4); }
+ | SFUNCTION new_proc entryname arglist
+ { entrypt(CLPROC, TYUNKNOWN, (ftnint) 0, $3, $4); }
+ | type SFUNCTION new_proc entryname arglist
+ { entrypt(CLPROC, $1, varleng, $4, $5); }
+ | SENTRY entryname arglist
+ { if(parstate==OUTSIDE || procclass==CLMAIN
+ || procclass==CLBLOCK)
+ execerr("misplaced entry statement", CNULL);
+ entrypt(CLENTRY, 0, (ftnint) 0, $2, $3);
+ }
+ ;
+
+new_proc:
+ { newproc(); }
+ ;
+
+entryname: name
+ { $$ = newentry($1, 1); }
+ ;
+
+name: SNAME
+ { $$ = mkname(token); }
+ ;
+
+progname: { $$ = NULL; }
+ | entryname
+ ;
+
+progarglist:
+ SLPAR SRPAR
+ | SLPAR progargs SRPAR
+ ;
+
+progargs: progarg
+ | progargs SCOMMA progarg
+ ;
+
+progarg: SNAME
+ | SNAME SEQUALS SNAME
+ ;
+
+arglist:
+ { $$ = 0; }
+ | SLPAR SRPAR
+ { NO66(" () argument list");
+ $$ = 0; }
+ | SLPAR args SRPAR
+ {$$ = $2; }
+ ;
+
+args: arg
+ { $$ = ($1 ? mkchain((char *)$1,CHNULL) : CHNULL ); }
+ | args SCOMMA arg
+ { if($3) $1 = $$ = mkchain((char *)$3, $1); }
+ ;
+
+arg: name
+ { if($1->vstg!=STGUNKNOWN && $1->vstg!=STGARG)
+ dclerr("name declared as argument after use", $1);
+ $1->vstg = STGARG;
+ }
+ | SSTAR
+ { NO66("altenate return argument");
+
+/* substars means that '*'ed formal parameters should be replaced.
+ This is used to specify alternate return labels; in theory, only
+ parameter slots which have '*' should accept the statement labels.
+ This compiler chooses to ignore the '*'s in the formal declaration, and
+ always return the proper value anyway.
+
+ This variable is only referred to in proc.c */
+
+ $$ = 0; substars = YES; }
+ ;
+
+
+
+filename: SHOLLERITH
+ {
+ char *s;
+ s = copyn(toklen+1, token);
+ s[toklen] = '\0';
+ $$ = s;
+ }
+ ;
diff --git a/usr.bin/f2c/gram.io b/usr.bin/f2c/gram.io
new file mode 100644
index 0000000..f1a6649
--- /dev/null
+++ b/usr.bin/f2c/gram.io
@@ -0,0 +1,173 @@
+ /* Input/Output Statements */
+
+io: io1
+ { endio(); }
+ ;
+
+io1: iofmove ioctl
+ | iofmove unpar_fexpr
+ { ioclause(IOSUNIT, $2); endioctl(); }
+ | iofmove SSTAR
+ { ioclause(IOSUNIT, ENULL); endioctl(); }
+ | iofmove SPOWER
+ { ioclause(IOSUNIT, IOSTDERR); endioctl(); }
+ | iofctl ioctl
+ | read ioctl
+ { doio(CHNULL); }
+ | read infmt
+ { doio(CHNULL); }
+ | read ioctl inlist
+ { doio(revchain($3)); }
+ | read infmt SCOMMA inlist
+ { doio(revchain($4)); }
+ | read ioctl SCOMMA inlist
+ { doio(revchain($4)); }
+ | write ioctl
+ { doio(CHNULL); }
+ | write ioctl outlist
+ { doio(revchain($3)); }
+ | print
+ { doio(CHNULL); }
+ | print SCOMMA outlist
+ { doio(revchain($3)); }
+ ;
+
+iofmove: fmkwd end_spec in_ioctl
+ ;
+
+fmkwd: SBACKSPACE
+ { iostmt = IOBACKSPACE; }
+ | SREWIND
+ { iostmt = IOREWIND; }
+ | SENDFILE
+ { iostmt = IOENDFILE; }
+ ;
+
+iofctl: ctlkwd end_spec in_ioctl
+ ;
+
+ctlkwd: SINQUIRE
+ { iostmt = IOINQUIRE; }
+ | SOPEN
+ { iostmt = IOOPEN; }
+ | SCLOSE
+ { iostmt = IOCLOSE; }
+ ;
+
+infmt: unpar_fexpr
+ {
+ ioclause(IOSUNIT, ENULL);
+ ioclause(IOSFMT, $1);
+ endioctl();
+ }
+ | SSTAR
+ {
+ ioclause(IOSUNIT, ENULL);
+ ioclause(IOSFMT, ENULL);
+ endioctl();
+ }
+ ;
+
+ioctl: SLPAR fexpr SRPAR
+ {
+ ioclause(IOSUNIT, $2);
+ endioctl();
+ }
+ | SLPAR ctllist SRPAR
+ { endioctl(); }
+ ;
+
+ctllist: ioclause
+ | ctllist SCOMMA ioclause
+ ;
+
+ioclause: fexpr
+ { ioclause(IOSPOSITIONAL, $1); }
+ | SSTAR
+ { ioclause(IOSPOSITIONAL, ENULL); }
+ | SPOWER
+ { ioclause(IOSPOSITIONAL, IOSTDERR); }
+ | nameeq expr
+ { ioclause($1, $2); }
+ | nameeq SSTAR
+ { ioclause($1, ENULL); }
+ | nameeq SPOWER
+ { ioclause($1, IOSTDERR); }
+ ;
+
+nameeq: SNAMEEQ
+ { $$ = iocname(); }
+ ;
+
+read: SREAD end_spec in_ioctl
+ { iostmt = IOREAD; }
+ ;
+
+write: SWRITE end_spec in_ioctl
+ { iostmt = IOWRITE; }
+ ;
+
+print: SPRINT end_spec fexpr in_ioctl
+ {
+ iostmt = IOWRITE;
+ ioclause(IOSUNIT, ENULL);
+ ioclause(IOSFMT, $3);
+ endioctl();
+ }
+ | SPRINT end_spec SSTAR in_ioctl
+ {
+ iostmt = IOWRITE;
+ ioclause(IOSUNIT, ENULL);
+ ioclause(IOSFMT, ENULL);
+ endioctl();
+ }
+ ;
+
+inlist: inelt
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | inlist SCOMMA inelt
+ { $$ = mkchain((char *)$3, $1); }
+ ;
+
+inelt: lhs
+ { $$ = (tagptr) $1; }
+ | SLPAR inlist SCOMMA dospec SRPAR
+ { $$ = (tagptr) mkiodo($4,revchain($2)); }
+ ;
+
+outlist: uexpr
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | other
+ { $$ = mkchain((char *)$1, CHNULL); }
+ | out2
+ ;
+
+out2: uexpr SCOMMA uexpr
+ { $$ = mkchain((char *)$3, mkchain((char *)$1, CHNULL) ); }
+ | uexpr SCOMMA other
+ { $$ = mkchain((char *)$3, mkchain((char *)$1, CHNULL) ); }
+ | other SCOMMA uexpr
+ { $$ = mkchain((char *)$3, mkchain((char *)$1, CHNULL) ); }
+ | other SCOMMA other
+ { $$ = mkchain((char *)$3, mkchain((char *)$1, CHNULL) ); }
+ | out2 SCOMMA uexpr
+ { $$ = mkchain((char *)$3, $1); }
+ | out2 SCOMMA other
+ { $$ = mkchain((char *)$3, $1); }
+ ;
+
+other: complex_const
+ { $$ = (tagptr) $1; }
+ | SLPAR expr SRPAR
+ { $$ = (tagptr) $2; }
+ | SLPAR uexpr SCOMMA dospec SRPAR
+ { $$ = (tagptr) mkiodo($4, mkchain((char *)$2, CHNULL) ); }
+ | SLPAR other SCOMMA dospec SRPAR
+ { $$ = (tagptr) mkiodo($4, mkchain((char *)$2, CHNULL) ); }
+ | SLPAR out2 SCOMMA dospec SRPAR
+ { $$ = (tagptr) mkiodo($4, revchain($2)); }
+ ;
+
+in_ioctl:
+ { startioctl(); }
+ ;
diff --git a/usr.bin/f2c/init.c b/usr.bin/f2c/init.c
new file mode 100644
index 0000000..bc0dff4
--- /dev/null
+++ b/usr.bin/f2c/init.c
@@ -0,0 +1,517 @@
+/****************************************************************
+Copyright 1990, 1992 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "output.h"
+#include "iob.h"
+
+/* State required for the C output */
+char *fl_fmt_string; /* Float format string */
+char *db_fmt_string; /* Double format string */
+char *cm_fmt_string; /* Complex format string */
+char *dcm_fmt_string; /* Double complex format string */
+
+chainp new_vars = CHNULL; /* List of newly created locals in this
+ function. These may have identifiers
+ which have underscores and more than VL
+ characters */
+chainp used_builtins = CHNULL; /* List of builtins used by this function.
+ These are all Addrps with UNAM_EXTERN
+ */
+chainp assigned_fmts = CHNULL; /* assigned formats */
+chainp allargs; /* union of args in all entry points */
+chainp earlylabs; /* labels seen before enddcl() */
+char main_alias[52]; /* PROGRAM name, if any is given */
+int tab_size = 4;
+
+
+FILEP infile;
+FILEP diagfile;
+
+FILEP c_file;
+FILEP pass1_file;
+FILEP initfile;
+FILEP blkdfile;
+
+
+char *token;
+int maxtoklen, toklen;
+long err_lineno;
+long lineno; /* Current line in the input file, NOT the
+ Fortran statement label number */
+char *infname;
+int needkwd;
+struct Labelblock *thislabel = NULL;
+int nerr;
+int nwarn;
+
+flag saveall;
+flag substars;
+int parstate = OUTSIDE;
+flag headerdone = NO;
+int blklevel;
+int doin_setbound;
+int impltype[26];
+ftnint implleng[26];
+int implstg[26];
+
+int tyint = TYLONG ;
+int tylogical = TYLONG;
+int tylog = TYLOGICAL;
+int typesize[NTYPES] = {
+ 1, SZADDR, 1, SZSHORT, SZLONG,
+#ifdef TYQUAD
+ 2*SZLONG,
+#endif
+ SZLONG, 2*SZLONG,
+ 2*SZLONG, 4*SZLONG, 1, SZSHORT, SZLONG, 1, 1, 0,
+ 4*SZLONG + SZADDR, /* sizeof(cilist) */
+ 4*SZLONG + 2*SZADDR, /* sizeof(icilist) */
+ 4*SZLONG + 5*SZADDR, /* sizeof(olist) */
+ 2*SZLONG + SZADDR, /* sizeof(cllist) */
+ 2*SZLONG, /* sizeof(alist) */
+ 11*SZLONG + 15*SZADDR /* sizeof(inlist) */
+ };
+
+int typealign[NTYPES] = {
+ 1, ALIADDR, 1, ALISHORT, ALILONG,
+#ifdef TYQUAD
+ ALIDOUBLE,
+#endif
+ ALILONG, ALIDOUBLE,
+ ALILONG, ALIDOUBLE, 1, ALISHORT, ALILONG, 1, 1, 1,
+ ALILONG, ALILONG, ALILONG, ALILONG, ALILONG, ALILONG};
+
+int type_choice[4] = { TYDREAL, TYSHORT, TYLONG, TYSHORT };
+
+char *typename[] = {
+ "<<unknown>>",
+ "address",
+ "integer1",
+ "shortint",
+ "integer",
+#ifdef TYQUAD
+ "longint",
+#endif
+ "real",
+ "doublereal",
+ "complex",
+ "doublecomplex",
+ "logical1",
+ "shortlogical",
+ "logical",
+ "char" /* character */
+ };
+
+int type_pref[NTYPES] = { 0, 0, 3, 5, 7,
+#ifdef TYQUAD
+ 10,
+#endif
+ 8, 11, 9, 12, 1, 4, 6, 2 };
+
+char *protorettypes[] = {
+ "?", "??", "integer1", "shortint", "integer",
+#ifdef TYQUAD
+ "longint",
+#endif
+ "real", "doublereal",
+ "C_f", "Z_f", "logical1", "shortlogical", "logical", "H_f", "int"
+ };
+
+char *casttypes[TYSUBR+1] = {
+ "U_fp", "??bug??", "I1_fp",
+ "J_fp", "I_fp",
+#ifdef TYQUAD
+ "Q_fp",
+#endif
+ "R_fp", "D_fp", "C_fp", "Z_fp",
+ "L1_fp", "L2_fp", "L_fp", "H_fp", "S_fp"
+ };
+char *usedcasts[TYSUBR+1];
+
+char *dfltarg[] = {
+ 0, 0, "(integer1 *)0",
+ "(shortint *)0", "(integer *)0",
+#ifdef TYQUAD
+ "(longint *)0",
+#endif
+ "(real *)0",
+ "(doublereal *)0", "(complex *)0", "(doublecomplex *)0",
+ "(logical1 *)0","(shortlogical *)0", "(logical *)0", "(char *)0"
+ };
+
+static char *dflt0proc[] = {
+ 0, 0, "(integer1 (*)())0",
+ "(shortint (*)())0", "(integer (*)())0",
+#ifdef TYQUAD
+ "(longint (*)())0",
+#endif
+ "(real (*)())0",
+ "(doublereal (*)())0", "(complex (*)())0", "(doublecomplex (*)())0",
+ "(logical1 (*)())0", "(shortlogical (*)())0",
+ "(logical (*)())0", "(char (*)())0", "(int (*)())0"
+ };
+
+char *dflt1proc[] = { "(U_fp)0", "(??bug??)0", "(I1_fp)0",
+ "(J_fp)0", "(I_fp)0",
+#ifdef TYQUAD
+ "(Q_fp)0",
+#endif
+ "(R_fp)0", "(D_fp)0", "(C_fp)0", "(Z_fp)0",
+ "(L1_fp)0","(L2_fp)0",
+ "(L_fp)0", "(H_fp)0", "(S_fp)0"
+ };
+
+char **dfltproc = dflt0proc;
+
+static char Bug[] = "bug";
+
+char *ftn_types[] = { "external", "??", "integer*1",
+ "integer*2", "integer",
+#ifdef TYQUAD
+ "integer*8",
+#endif
+ "real",
+ "double precision", "complex", "double complex",
+ "logical*1", "logical*2",
+ "logical", "character", "subroutine",
+ Bug,Bug,Bug,Bug,Bug,Bug,Bug,Bug,Bug, "ftnlen"
+ };
+
+int init_ac[TYSUBR+1] = { 0,0,0,0,0,0,0,
+#ifdef TYQUAD
+ 0,
+#endif
+ 1, 1, 0, 0, 0, 2};
+
+int proctype = TYUNKNOWN;
+char *procname;
+int rtvlabel[NTYPES0];
+Addrp retslot; /* Holds automatic variable which was
+ allocated the function return value
+ */
+Addrp xretslot[NTYPES0]; /* for multiple entry points */
+int cxslot = -1;
+int chslot = -1;
+int chlgslot = -1;
+int procclass = CLUNKNOWN;
+int nentry;
+int nallargs;
+int nallchargs;
+flag multitype;
+ftnint procleng;
+long lastiolabno;
+long lastlabno;
+int lastvarno;
+int lastargslot;
+int autonum[TYVOID];
+char *av_pfix[TYVOID] = {"??TYUNKNOWN??", "a","i1","s","i",
+#ifdef TYQUAD
+ "i8",
+#endif
+ "r","d","q","z","L1","L2","L","ch",
+ "??TYSUBR??", "??TYERROR??","ci", "ici",
+ "o", "cl", "al", "ioin" };
+
+extern int maxctl;
+struct Ctlframe *ctls;
+struct Ctlframe *ctlstack;
+struct Ctlframe *lastctl;
+
+Namep regnamep[MAXREGVAR];
+int highregvar;
+int nregvar;
+
+extern int maxext;
+Extsym *extsymtab;
+Extsym *nextext;
+Extsym *lastext;
+
+extern int maxequiv;
+struct Equivblock *eqvclass;
+
+extern int maxhash;
+struct Hashentry *hashtab;
+struct Hashentry *lasthash;
+
+extern int maxstno; /* Maximum number of statement labels */
+struct Labelblock *labeltab;
+struct Labelblock *labtabend;
+struct Labelblock *highlabtab;
+
+int maxdim = MAXDIM;
+struct Rplblock *rpllist = NULL;
+struct Chain *curdtp = NULL;
+flag toomanyinit;
+ftnint curdtelt;
+chainp templist[TYVOID];
+chainp holdtemps;
+int dorange = 0;
+struct Entrypoint *entries = NULL;
+
+chainp chains = NULL;
+
+flag inioctl;
+int iostmt;
+int nioctl;
+int nequiv = 0;
+int eqvstart = 0;
+int nintnames = 0;
+extern int maxlablist;
+struct Labelblock **labarray;
+
+struct Literal *litpool;
+int nliterals;
+
+char dflttype[26];
+char hextoi_tab[Table_size], Letters[Table_size];
+char *ei_first, *ei_next, *ei_last;
+char *wh_first, *wh_next, *wh_last;
+
+#define ALLOCN(n,x) (struct x *) ckalloc((n)*sizeof(struct x))
+
+ void
+fileinit(Void)
+{
+ register char *s;
+ register int i, j;
+
+ lastiolabno = 100000;
+ lastlabno = 0;
+ lastvarno = 0;
+ nliterals = 0;
+ nerr = 0;
+
+ infile = stdin;
+
+ maxtoklen = 502;
+ token = (char *)ckalloc(maxtoklen+2);
+ memset(dflttype, tyreal, 26);
+ memset(dflttype + 'i' - 'a', tyint, 6);
+ memset(hextoi_tab, 16, sizeof(hextoi_tab));
+ for(i = 0, s = "0123456789abcdef"; *s; i++, s++)
+ hextoi(*s) = i;
+ for(i = 10, s = "ABCDEF"; *s; i++, s++)
+ hextoi(*s) = i;
+ for(j = 0, s = "abcdefghijklmnopqrstuvwxyz"; i = *s++; j++)
+ Letters[i] = Letters[i+'A'-'a'] = j;
+
+ ctls = ALLOCN(maxctl+1, Ctlframe);
+ extsymtab = ALLOCN(maxext, Extsym);
+ eqvclass = ALLOCN(maxequiv, Equivblock);
+ hashtab = ALLOCN(maxhash, Hashentry);
+ labeltab = ALLOCN(maxstno, Labelblock);
+ litpool = ALLOCN(maxliterals, Literal);
+ labarray = (struct Labelblock **)ckalloc(maxlablist*
+ sizeof(struct Labelblock *));
+ fmt_init();
+ mem_init();
+ np_init();
+
+ ctlstack = ctls++;
+ lastctl = ctls + maxctl;
+ nextext = extsymtab;
+ lastext = extsymtab + maxext;
+ lasthash = hashtab + maxhash;
+ labtabend = labeltab + maxstno;
+ highlabtab = labeltab;
+ main_alias[0] = '\0';
+ if (forcedouble)
+ dfltproc[TYREAL] = dfltproc[TYDREAL];
+
+/* Initialize the routines for providing C output */
+
+ out_init ();
+}
+
+ void
+hashclear(Void) /* clear hash table */
+{
+ register struct Hashentry *hp;
+ register Namep p;
+ register struct Dimblock *q;
+ register int i;
+
+ for(hp = hashtab ; hp < lasthash ; ++hp)
+ if(p = hp->varp)
+ {
+ frexpr(p->vleng);
+ if(q = p->vdim)
+ {
+ for(i = 0 ; i < q->ndim ; ++i)
+ {
+ frexpr(q->dims[i].dimsize);
+ frexpr(q->dims[i].dimexpr);
+ }
+ frexpr(q->nelt);
+ frexpr(q->baseoffset);
+ frexpr(q->basexpr);
+ free( (charptr) q);
+ }
+ if(p->vclass == CLNAMELIST)
+ frchain( &(p->varxptr.namelist) );
+ free( (charptr) p);
+ hp->varp = NULL;
+ }
+ }
+
+ void
+procinit(Void)
+{
+ register struct Labelblock *lp;
+ struct Chain *cp;
+ int i;
+ struct memblock;
+ extern struct memblock *curmemblock, *firstmemblock;
+ extern char *mem_first, *mem_next, *mem_last, *mem0_last;
+
+ curmemblock = firstmemblock;
+ mem_next = mem_first;
+ mem_last = mem0_last;
+ ei_next = ei_first = ei_last = 0;
+ wh_next = wh_first = wh_last = 0;
+ iob_list = 0;
+ for(i = 0; i < 9; i++)
+ io_structs[i] = 0;
+
+ parstate = OUTSIDE;
+ headerdone = NO;
+ blklevel = 1;
+ saveall = NO;
+ substars = NO;
+ nwarn = 0;
+ thislabel = NULL;
+ needkwd = 0;
+
+ proctype = TYUNKNOWN;
+ procname = "MAIN_";
+ procclass = CLUNKNOWN;
+ nentry = 0;
+ nallargs = nallchargs = 0;
+ multitype = NO;
+ retslot = NULL;
+ for(i = 0; i < NTYPES0; i++) {
+ frexpr((expptr)xretslot[i]);
+ xretslot[i] = 0;
+ }
+ cxslot = -1;
+ chslot = -1;
+ chlgslot = -1;
+ procleng = 0;
+ blklevel = 1;
+ lastargslot = 0;
+
+ for(lp = labeltab ; lp < labtabend ; ++lp)
+ lp->stateno = 0;
+
+ hashclear();
+
+/* Clear the list of newly generated identifiers from the previous
+ function */
+
+ frexchain(&new_vars);
+ frexchain(&used_builtins);
+ frchain(&assigned_fmts);
+ frchain(&allargs);
+ frchain(&earlylabs);
+
+ nintnames = 0;
+ highlabtab = labeltab;
+
+ ctlstack = ctls - 1;
+ for(i = TYADDR; i < TYVOID; i++) {
+ for(cp = templist[i]; cp ; cp = cp->nextp)
+ free( (charptr) (cp->datap) );
+ frchain(templist + i);
+ autonum[i] = 0;
+ }
+ holdtemps = NULL;
+ dorange = 0;
+ nregvar = 0;
+ highregvar = 0;
+ entries = NULL;
+ rpllist = NULL;
+ inioctl = NO;
+ eqvstart += nequiv;
+ nequiv = 0;
+ dcomplex_seen = 0;
+
+ for(i = 0 ; i<NTYPES0 ; ++i)
+ rtvlabel[i] = 0;
+
+ if(undeftype)
+ setimpl(TYUNKNOWN, (ftnint) 0, 'a', 'z');
+ else
+ {
+ setimpl(tyreal, (ftnint) 0, 'a', 'z');
+ setimpl(tyint, (ftnint) 0, 'i', 'n');
+ }
+ setimpl(-STGBSS, (ftnint) 0, 'a', 'z'); /* set class */
+}
+
+
+
+ void
+#ifdef KR_headers
+setimpl(type, length, c1, c2)
+ int type;
+ ftnint length;
+ int c1;
+ int c2;
+#else
+setimpl(int type, ftnint length, int c1, int c2)
+#endif
+{
+ int i;
+ char buff[100];
+
+ if(c1==0 || c2==0)
+ return;
+
+ if(c1 > c2) {
+ sprintf(buff, "characters out of order in implicit:%c-%c", c1, c2);
+ err(buff);
+ }
+ else {
+ c1 = letter(c1);
+ c2 = letter(c2);
+ if(type < 0)
+ for(i = c1 ; i<=c2 ; ++i)
+ implstg[i] = - type;
+ else {
+ type = lengtype(type, length);
+ if(type == TYCHAR) {
+ if (length < 0) {
+ err("length (*) in implicit");
+ length = 1;
+ }
+ }
+ else if (type != TYLONG)
+ length = 0;
+ for(i = c1 ; i<=c2 ; ++i) {
+ impltype[i] = type;
+ implleng[i] = length;
+ }
+ }
+ }
+ }
diff --git a/usr.bin/f2c/intr.c b/usr.bin/f2c/intr.c
new file mode 100644
index 0000000..c83325f
--- /dev/null
+++ b/usr.bin/f2c/intr.c
@@ -0,0 +1,977 @@
+/****************************************************************
+Copyright 1990, 1992, 1994-6 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "names.h"
+
+union
+ {
+ int ijunk;
+ struct Intrpacked bits;
+ } packed;
+
+struct Intrbits
+ {
+ char intrgroup /* :3 */;
+ char intrstuff /* result type or number of generics */;
+ char intrno /* :7 */;
+ char dblcmplx;
+ char dblintrno; /* for -r8 */
+ char extflag; /* for -cd, -i90 */
+ };
+
+/* List of all intrinsic functions. */
+
+LOCAL struct Intrblock
+ {
+ char intrfname[8];
+ struct Intrbits intrval;
+ } intrtab[ ] =
+{
+"int", { INTRCONV, TYLONG },
+"real", { INTRCONV, TYREAL, 1 },
+ /* 1 ==> real(TYDCOMPLEX) yields TYDREAL */
+"dble", { INTRCONV, TYDREAL },
+"cmplx", { INTRCONV, TYCOMPLEX },
+"dcmplx", { INTRCONV, TYDCOMPLEX, 0, 1 },
+"ifix", { INTRCONV, TYLONG },
+"idint", { INTRCONV, TYLONG },
+"float", { INTRCONV, TYREAL },
+"dfloat", { INTRCONV, TYDREAL },
+"sngl", { INTRCONV, TYREAL },
+"ichar", { INTRCONV, TYLONG },
+"iachar", { INTRCONV, TYLONG },
+"char", { INTRCONV, TYCHAR },
+"achar", { INTRCONV, TYCHAR },
+
+/* any MAX or MIN can be used with any types; the compiler will cast them
+ correctly. So rules against bad syntax in these expressions are not
+ enforced */
+
+"max", { INTRMAX, TYUNKNOWN },
+"max0", { INTRMAX, TYLONG },
+"amax0", { INTRMAX, TYREAL },
+"max1", { INTRMAX, TYLONG },
+"amax1", { INTRMAX, TYREAL },
+"dmax1", { INTRMAX, TYDREAL },
+
+"and", { INTRBOOL, TYUNKNOWN, OPBITAND },
+"or", { INTRBOOL, TYUNKNOWN, OPBITOR },
+"xor", { INTRBOOL, TYUNKNOWN, OPBITXOR },
+"not", { INTRBOOL, TYUNKNOWN, OPBITNOT },
+"lshift", { INTRBOOL, TYUNKNOWN, OPLSHIFT },
+"rshift", { INTRBOOL, TYUNKNOWN, OPRSHIFT },
+
+"min", { INTRMIN, TYUNKNOWN },
+"min0", { INTRMIN, TYLONG },
+"amin0", { INTRMIN, TYREAL },
+"min1", { INTRMIN, TYLONG },
+"amin1", { INTRMIN, TYREAL },
+"dmin1", { INTRMIN, TYDREAL },
+
+"aint", { INTRGEN, 2, 0 },
+"dint", { INTRSPEC, TYDREAL, 1 },
+
+"anint", { INTRGEN, 2, 2 },
+"dnint", { INTRSPEC, TYDREAL, 3 },
+
+"nint", { INTRGEN, 4, 4 },
+"idnint", { INTRGEN, 2, 6 },
+
+"abs", { INTRGEN, 6, 8 },
+"iabs", { INTRGEN, 2, 9 },
+"dabs", { INTRSPEC, TYDREAL, 11 },
+"cabs", { INTRSPEC, TYREAL, 12, 0, 13 },
+"zabs", { INTRSPEC, TYDREAL, 13, 1 },
+
+"mod", { INTRGEN, 4, 14 },
+"amod", { INTRSPEC, TYREAL, 16, 0, 17 },
+"dmod", { INTRSPEC, TYDREAL, 17 },
+
+"sign", { INTRGEN, 4, 18 },
+"isign", { INTRGEN, 2, 19 },
+"dsign", { INTRSPEC, TYDREAL, 21 },
+
+"dim", { INTRGEN, 4, 22 },
+"idim", { INTRGEN, 2, 23 },
+"ddim", { INTRSPEC, TYDREAL, 25 },
+
+"dprod", { INTRSPEC, TYDREAL, 26 },
+
+"len", { INTRSPEC, TYLONG, 27 },
+"index", { INTRSPEC, TYLONG, 29 },
+
+"imag", { INTRGEN, 2, 31 },
+"aimag", { INTRSPEC, TYREAL, 31, 0, 32 },
+"dimag", { INTRSPEC, TYDREAL, 32 },
+
+"conjg", { INTRGEN, 2, 33 },
+"dconjg", { INTRSPEC, TYDCOMPLEX, 34, 1 },
+
+"sqrt", { INTRGEN, 4, 35 },
+"dsqrt", { INTRSPEC, TYDREAL, 36 },
+"csqrt", { INTRSPEC, TYCOMPLEX, 37, 0, 38 },
+"zsqrt", { INTRSPEC, TYDCOMPLEX, 38, 1 },
+
+"exp", { INTRGEN, 4, 39 },
+"dexp", { INTRSPEC, TYDREAL, 40 },
+"cexp", { INTRSPEC, TYCOMPLEX, 41, 0, 42 },
+"zexp", { INTRSPEC, TYDCOMPLEX, 42, 1 },
+
+"log", { INTRGEN, 4, 43 },
+"alog", { INTRSPEC, TYREAL, 43, 0, 44 },
+"dlog", { INTRSPEC, TYDREAL, 44 },
+"clog", { INTRSPEC, TYCOMPLEX, 45, 0, 46 },
+"zlog", { INTRSPEC, TYDCOMPLEX, 46, 1 },
+
+"log10", { INTRGEN, 2, 47 },
+"alog10", { INTRSPEC, TYREAL, 47, 0, 48 },
+"dlog10", { INTRSPEC, TYDREAL, 48 },
+
+"sin", { INTRGEN, 4, 49 },
+"dsin", { INTRSPEC, TYDREAL, 50 },
+"csin", { INTRSPEC, TYCOMPLEX, 51, 0, 52 },
+"zsin", { INTRSPEC, TYDCOMPLEX, 52, 1 },
+
+"cos", { INTRGEN, 4, 53 },
+"dcos", { INTRSPEC, TYDREAL, 54 },
+"ccos", { INTRSPEC, TYCOMPLEX, 55, 0, 56 },
+"zcos", { INTRSPEC, TYDCOMPLEX, 56, 1 },
+
+"tan", { INTRGEN, 2, 57 },
+"dtan", { INTRSPEC, TYDREAL, 58 },
+
+"asin", { INTRGEN, 2, 59 },
+"dasin", { INTRSPEC, TYDREAL, 60 },
+
+"acos", { INTRGEN, 2, 61 },
+"dacos", { INTRSPEC, TYDREAL, 62 },
+
+"atan", { INTRGEN, 2, 63 },
+"datan", { INTRSPEC, TYDREAL, 64 },
+
+"atan2", { INTRGEN, 2, 65 },
+"datan2", { INTRSPEC, TYDREAL, 66 },
+
+"sinh", { INTRGEN, 2, 67 },
+"dsinh", { INTRSPEC, TYDREAL, 68 },
+
+"cosh", { INTRGEN, 2, 69 },
+"dcosh", { INTRSPEC, TYDREAL, 70 },
+
+"tanh", { INTRGEN, 2, 71 },
+"dtanh", { INTRSPEC, TYDREAL, 72 },
+
+"lge", { INTRSPEC, TYLOGICAL, 73},
+"lgt", { INTRSPEC, TYLOGICAL, 75},
+"lle", { INTRSPEC, TYLOGICAL, 77},
+"llt", { INTRSPEC, TYLOGICAL, 79},
+
+#if 0
+"epbase", { INTRCNST, 4, 0 },
+"epprec", { INTRCNST, 4, 4 },
+"epemin", { INTRCNST, 2, 8 },
+"epemax", { INTRCNST, 2, 10 },
+"eptiny", { INTRCNST, 2, 12 },
+"ephuge", { INTRCNST, 4, 14 },
+"epmrsp", { INTRCNST, 2, 18 },
+#endif
+
+"fpexpn", { INTRGEN, 4, 81 },
+"fpabsp", { INTRGEN, 2, 85 },
+"fprrsp", { INTRGEN, 2, 87 },
+"fpfrac", { INTRGEN, 2, 89 },
+"fpmake", { INTRGEN, 2, 91 },
+"fpscal", { INTRGEN, 2, 93 },
+
+"cdabs", { INTRSPEC, TYDREAL, 13, 1, 0, 1 },
+"cdsqrt", { INTRSPEC, TYDCOMPLEX, 38, 1, 0, 1 },
+"cdexp", { INTRSPEC, TYDCOMPLEX, 42, 1, 0, 1 },
+"cdlog", { INTRSPEC, TYDCOMPLEX, 46, 1, 0, 1 },
+"cdsin", { INTRSPEC, TYDCOMPLEX, 52, 1, 0, 1 },
+"cdcos", { INTRSPEC, TYDCOMPLEX, 56, 1, 0, 1 },
+
+"iand", { INTRBOOL, TYUNKNOWN, OPBITAND, 0, 0, 2 },
+"ior", { INTRBOOL, TYUNKNOWN, OPBITOR, 0, 0, 2 },
+"ieor", { INTRBOOL, TYUNKNOWN, OPBITXOR, 0, 0, 2 },
+
+"btest", { INTRBGEN, TYLOGICAL, OPBITTEST,0, 0, 2 },
+"ibclr", { INTRBGEN, TYUNKNOWN, OPBITCLR, 0, 0, 2 },
+"ibset", { INTRBGEN, TYUNKNOWN, OPBITSET, 0, 0, 2 },
+"ibits", { INTRBGEN, TYUNKNOWN, OPBITBITS,0, 0, 2 },
+"ishft", { INTRBGEN, TYUNKNOWN, OPBITSH, 0, 0, 2 },
+"ishftc", { INTRBGEN, TYUNKNOWN, OPBITSHC, 0, 0, 2 },
+
+"" };
+
+
+LOCAL struct Specblock
+ {
+ char atype; /* Argument type; every arg must have
+ this type */
+ char rtype; /* Result type */
+ char nargs; /* Number of arguments */
+ char spxname[8]; /* Name of the function in Fortran */
+ char othername; /* index into callbyvalue table */
+ } spectab[ ] =
+{
+ { TYREAL,TYREAL,1,"r_int" },
+ { TYDREAL,TYDREAL,1,"d_int" },
+
+ { TYREAL,TYREAL,1,"r_nint" },
+ { TYDREAL,TYDREAL,1,"d_nint" },
+
+ { TYREAL,TYSHORT,1,"h_nint" },
+ { TYREAL,TYLONG,1,"i_nint" },
+
+ { TYDREAL,TYSHORT,1,"h_dnnt" },
+ { TYDREAL,TYLONG,1,"i_dnnt" },
+
+ { TYREAL,TYREAL,1,"r_abs" },
+ { TYSHORT,TYSHORT,1,"h_abs" },
+ { TYLONG,TYLONG,1,"i_abs" },
+ { TYDREAL,TYDREAL,1,"d_abs" },
+ { TYCOMPLEX,TYREAL,1,"c_abs" },
+ { TYDCOMPLEX,TYDREAL,1,"z_abs" },
+
+ { TYSHORT,TYSHORT,2,"h_mod" },
+ { TYLONG,TYLONG,2,"i_mod" },
+ { TYREAL,TYREAL,2,"r_mod" },
+ { TYDREAL,TYDREAL,2,"d_mod" },
+
+ { TYREAL,TYREAL,2,"r_sign" },
+ { TYSHORT,TYSHORT,2,"h_sign" },
+ { TYLONG,TYLONG,2,"i_sign" },
+ { TYDREAL,TYDREAL,2,"d_sign" },
+
+ { TYREAL,TYREAL,2,"r_dim" },
+ { TYSHORT,TYSHORT,2,"h_dim" },
+ { TYLONG,TYLONG,2,"i_dim" },
+ { TYDREAL,TYDREAL,2,"d_dim" },
+
+ { TYREAL,TYDREAL,2,"d_prod" },
+
+ { TYCHAR,TYSHORT,1,"h_len" },
+ { TYCHAR,TYLONG,1,"i_len" },
+
+ { TYCHAR,TYSHORT,2,"h_indx" },
+ { TYCHAR,TYLONG,2,"i_indx" },
+
+ { TYCOMPLEX,TYREAL,1,"r_imag" },
+ { TYDCOMPLEX,TYDREAL,1,"d_imag" },
+ { TYCOMPLEX,TYCOMPLEX,1,"r_cnjg" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"d_cnjg" },
+
+ { TYREAL,TYREAL,1,"r_sqrt", 1 },
+ { TYDREAL,TYDREAL,1,"d_sqrt", 1 },
+ { TYCOMPLEX,TYCOMPLEX,1,"c_sqrt" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"z_sqrt" },
+
+ { TYREAL,TYREAL,1,"r_exp", 2 },
+ { TYDREAL,TYDREAL,1,"d_exp", 2 },
+ { TYCOMPLEX,TYCOMPLEX,1,"c_exp" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"z_exp" },
+
+ { TYREAL,TYREAL,1,"r_log", 3 },
+ { TYDREAL,TYDREAL,1,"d_log", 3 },
+ { TYCOMPLEX,TYCOMPLEX,1,"c_log" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"z_log" },
+
+ { TYREAL,TYREAL,1,"r_lg10" },
+ { TYDREAL,TYDREAL,1,"d_lg10" },
+
+ { TYREAL,TYREAL,1,"r_sin", 4 },
+ { TYDREAL,TYDREAL,1,"d_sin", 4 },
+ { TYCOMPLEX,TYCOMPLEX,1,"c_sin" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"z_sin" },
+
+ { TYREAL,TYREAL,1,"r_cos", 5 },
+ { TYDREAL,TYDREAL,1,"d_cos", 5 },
+ { TYCOMPLEX,TYCOMPLEX,1,"c_cos" },
+ { TYDCOMPLEX,TYDCOMPLEX,1,"z_cos" },
+
+ { TYREAL,TYREAL,1,"r_tan", 6 },
+ { TYDREAL,TYDREAL,1,"d_tan", 6 },
+
+ { TYREAL,TYREAL,1,"r_asin", 7 },
+ { TYDREAL,TYDREAL,1,"d_asin", 7 },
+
+ { TYREAL,TYREAL,1,"r_acos", 8 },
+ { TYDREAL,TYDREAL,1,"d_acos", 8 },
+
+ { TYREAL,TYREAL,1,"r_atan", 9 },
+ { TYDREAL,TYDREAL,1,"d_atan", 9 },
+
+ { TYREAL,TYREAL,2,"r_atn2", 10 },
+ { TYDREAL,TYDREAL,2,"d_atn2", 10 },
+
+ { TYREAL,TYREAL,1,"r_sinh", 11 },
+ { TYDREAL,TYDREAL,1,"d_sinh", 11 },
+
+ { TYREAL,TYREAL,1,"r_cosh", 12 },
+ { TYDREAL,TYDREAL,1,"d_cosh", 12 },
+
+ { TYREAL,TYREAL,1,"r_tanh", 13 },
+ { TYDREAL,TYDREAL,1,"d_tanh", 13 },
+
+ { TYCHAR,TYLOGICAL,2,"hl_ge" },
+ { TYCHAR,TYLOGICAL,2,"l_ge" },
+
+ { TYCHAR,TYLOGICAL,2,"hl_gt" },
+ { TYCHAR,TYLOGICAL,2,"l_gt" },
+
+ { TYCHAR,TYLOGICAL,2,"hl_le" },
+ { TYCHAR,TYLOGICAL,2,"l_le" },
+
+ { TYCHAR,TYLOGICAL,2,"hl_lt" },
+ { TYCHAR,TYLOGICAL,2,"l_lt" },
+
+ { TYREAL,TYSHORT,1,"hr_expn" },
+ { TYREAL,TYLONG,1,"ir_expn" },
+ { TYDREAL,TYSHORT,1,"hd_expn" },
+ { TYDREAL,TYLONG,1,"id_expn" },
+
+ { TYREAL,TYREAL,1,"r_absp" },
+ { TYDREAL,TYDREAL,1,"d_absp" },
+
+ { TYREAL,TYDREAL,1,"r_rrsp" },
+ { TYDREAL,TYDREAL,1,"d_rrsp" },
+
+ { TYREAL,TYREAL,1,"r_frac" },
+ { TYDREAL,TYDREAL,1,"d_frac" },
+
+ { TYREAL,TYREAL,2,"r_make" },
+ { TYDREAL,TYDREAL,2,"d_make" },
+
+ { TYREAL,TYREAL,2,"r_scal" },
+ { TYDREAL,TYDREAL,2,"d_scal" },
+
+ { 0 }
+} ;
+
+#if 0
+LOCAL struct Incstblock
+ {
+ char atype;
+ char rtype;
+ char constno;
+ } consttab[ ] =
+{
+ { TYSHORT, TYLONG, 0 },
+ { TYLONG, TYLONG, 1 },
+ { TYREAL, TYLONG, 2 },
+ { TYDREAL, TYLONG, 3 },
+
+ { TYSHORT, TYLONG, 4 },
+ { TYLONG, TYLONG, 5 },
+ { TYREAL, TYLONG, 6 },
+ { TYDREAL, TYLONG, 7 },
+
+ { TYREAL, TYLONG, 8 },
+ { TYDREAL, TYLONG, 9 },
+
+ { TYREAL, TYLONG, 10 },
+ { TYDREAL, TYLONG, 11 },
+
+ { TYREAL, TYREAL, 0 },
+ { TYDREAL, TYDREAL, 1 },
+
+ { TYSHORT, TYLONG, 12 },
+ { TYLONG, TYLONG, 13 },
+ { TYREAL, TYREAL, 2 },
+ { TYDREAL, TYDREAL, 3 },
+
+ { TYREAL, TYREAL, 4 },
+ { TYDREAL, TYDREAL, 5 }
+};
+#endif
+
+char *callbyvalue[ ] =
+ {0,
+ "sqrt",
+ "exp",
+ "log",
+ "sin",
+ "cos",
+ "tan",
+ "asin",
+ "acos",
+ "atan",
+ "atan2",
+ "sinh",
+ "cosh",
+ "tanh"
+ };
+
+ void
+r8fix(Void) /* adjust tables for -r8 */
+{
+ register struct Intrblock *I;
+ register struct Specblock *S;
+
+ for(I = intrtab; I->intrfname[0]; I++)
+ if (I->intrval.intrgroup != INTRGEN)
+ switch(I->intrval.intrstuff) {
+ case TYREAL:
+ I->intrval.intrstuff = TYDREAL;
+ I->intrval.intrno = I->intrval.dblintrno;
+ break;
+ case TYCOMPLEX:
+ I->intrval.intrstuff = TYDCOMPLEX;
+ I->intrval.intrno = I->intrval.dblintrno;
+ I->intrval.dblcmplx = 1;
+ }
+
+ for(S = spectab; S->atype; S++)
+ switch(S->atype) {
+ case TYCOMPLEX:
+ S->atype = TYDCOMPLEX;
+ if (S->rtype == TYREAL)
+ S->rtype = TYDREAL;
+ else if (S->rtype == TYCOMPLEX)
+ S->rtype = TYDCOMPLEX;
+ switch(S->spxname[0]) {
+ case 'r':
+ S->spxname[0] = 'd';
+ break;
+ case 'c':
+ S->spxname[0] = 'z';
+ break;
+ default:
+ Fatal("r8fix bug");
+ }
+ break;
+ case TYREAL:
+ S->atype = TYDREAL;
+ switch(S->rtype) {
+ case TYREAL:
+ S->rtype = TYDREAL;
+ if (S->spxname[0] != 'r')
+ Fatal("r8fix bug");
+ S->spxname[0] = 'd';
+ case TYDREAL: /* d_prod */
+ break;
+
+ case TYSHORT:
+ if (!strcmp(S->spxname, "hr_expn"))
+ S->spxname[1] = 'd';
+ else if (!strcmp(S->spxname, "h_nint"))
+ strcpy(S->spxname, "h_dnnt");
+ else Fatal("r8fix bug");
+ break;
+
+ case TYLONG:
+ if (!strcmp(S->spxname, "ir_expn"))
+ S->spxname[1] = 'd';
+ else if (!strcmp(S->spxname, "i_nint"))
+ strcpy(S->spxname, "i_dnnt");
+ else Fatal("r8fix bug");
+ break;
+
+ default:
+ Fatal("r8fix bug");
+ }
+ }
+ }
+
+
+ expptr
+#ifdef KR_headers
+intrcall(np, argsp, nargs)
+ Namep np;
+ struct Listblock *argsp;
+ int nargs;
+#else
+intrcall(Namep np, struct Listblock *argsp, int nargs)
+#endif
+{
+ int i, rettype;
+ Addrp ap;
+ register struct Specblock *sp;
+ register struct Chain *cp;
+ expptr q, ep;
+ int mtype;
+ int op;
+ int f1field, f2field, f3field;
+ char *s;
+ static char bit_bits[] = "?bit_bits",
+ bit_shift[] = "?bit_shift",
+ bit_cshift[] = "?bit_cshift";
+ static char *bitop[3] = { bit_bits, bit_shift, bit_cshift };
+ static int t_pref[2] = { 'l', 'q' };
+
+ packed.ijunk = np->vardesc.varno;
+ f1field = packed.bits.f1;
+ f2field = packed.bits.f2;
+ f3field = packed.bits.f3;
+ if(nargs == 0)
+ goto badnargs;
+
+ mtype = 0;
+ for(cp = argsp->listp ; cp ; cp = cp->nextp)
+ {
+ ep = (expptr)cp->datap;
+ if( ISCONST(ep) && ep->headblock.vtype==TYSHORT )
+ cp->datap = (char *) mkconv(tyint, ep);
+ mtype = maxtype(mtype, ep->headblock.vtype);
+ }
+
+ switch(f1field)
+ {
+ case INTRBGEN:
+ op = f3field;
+ if( ! ONEOF(mtype, MSKINT) )
+ goto badtype;
+ if (op < OPBITBITS) {
+ if(nargs != 2)
+ goto badnargs;
+ if (op != OPBITTEST) {
+#ifdef TYQUAD
+ if (mtype == TYQUAD)
+ op += 2;
+#endif
+ goto intrbool2;
+ }
+ q = mkexpr(op, (expptr)argsp->listp->datap,
+ (expptr)argsp->listp->nextp->datap);
+ q->exprblock.vtype = TYLOGICAL;
+ goto intrbool2a;
+ }
+ if (nargs != 2 && (nargs != 3 || op == OPBITSH))
+ goto badnargs;
+ cp = argsp->listp;
+ ep = (expptr)cp->datap;
+ if (ep->headblock.vtype < TYLONG)
+ cp->datap = (char *)mkconv(TYLONG, ep);
+ while(cp->nextp) {
+ cp = cp->nextp;
+ ep = (expptr)cp->datap;
+ if (ep->headblock.vtype != TYLONG)
+ cp->datap = (char *)mkconv(TYLONG, ep);
+ }
+ if (op == OPBITSH) {
+ ep = (expptr)argsp->listp->nextp->datap;
+ if (ISCONST(ep)) {
+ if ((i = ep->constblock.Const.ci) < 0) {
+ q = (expptr)argsp->listp->datap;
+ if (ISCONST(q)) {
+ ep->constblock.Const.ci = -i;
+ op = OPRSHIFT;
+ goto intrbool2;
+ }
+ }
+ else {
+ op = OPLSHIFT;
+ goto intrbool2;
+ }
+ }
+ }
+ else if (nargs == 2) {
+ if (op == OPBITBITS)
+ goto badnargs;
+ cp->nextp = mkchain((char*)ICON(-1), 0);
+ }
+ ep = (expptr)argsp->listp->datap;
+ i = ep->headblock.vtype;
+ s = bitop[op - OPBITBITS];
+ *s = t_pref[i - TYLONG];
+ ap = builtin(i, s, 1);
+ return fixexpr((Exprp)
+ mkexpr(OPCCALL, (expptr)ap, (expptr)argsp) );
+
+ case INTRBOOL:
+ op = f3field;
+ if( ! ONEOF(mtype, MSKINT|MSKLOGICAL) )
+ goto badtype;
+ if(op == OPBITNOT)
+ {
+ if(nargs != 1)
+ goto badnargs;
+ q = mkexpr(OPBITNOT, (expptr)argsp->listp->datap, ENULL);
+ }
+ else
+ {
+ if(nargs != 2)
+ goto badnargs;
+ intrbool2:
+ q = mkexpr(op, (expptr)argsp->listp->datap,
+ (expptr)argsp->listp->nextp->datap);
+ }
+ intrbool2a:
+ frchain( &(argsp->listp) );
+ free( (charptr) argsp);
+ return(q);
+
+ case INTRCONV:
+ rettype = f2field;
+ switch(rettype) {
+ case TYLONG:
+ rettype = tyint;
+ break;
+ case TYLOGICAL:
+ rettype = tylog;
+ }
+ if( ISCOMPLEX(rettype) && nargs==2)
+ {
+ expptr qr, qi;
+ qr = (expptr) argsp->listp->datap;
+ qi = (expptr) argsp->listp->nextp->datap;
+ if (qr->headblock.vtype == TYDREAL
+ || qi->headblock.vtype == TYDREAL)
+ rettype = TYDCOMPLEX;
+ if(ISCONST(qr) && ISCONST(qi))
+ q = mkcxcon(qr,qi);
+ else q = mkexpr(OPCONV,mkconv(rettype-2,qr),
+ mkconv(rettype-2,qi));
+ }
+ else if(nargs == 1) {
+ if (f3field && ((Exprp)argsp->listp->datap)->vtype
+ == TYDCOMPLEX)
+ rettype = TYDREAL;
+ q = mkconv(rettype+100, (expptr)argsp->listp->datap);
+ if (q->tag == TADDR)
+ q->addrblock.parenused = 1;
+ }
+ else goto badnargs;
+
+ q->headblock.vtype = rettype;
+ frchain(&(argsp->listp));
+ free( (charptr) argsp);
+ return(q);
+
+
+#if 0
+ case INTRCNST:
+
+/* Machine-dependent f77 stuff that f2c omits:
+
+intcon contains
+ radix for short int
+ radix for long int
+ radix for single precision
+ radix for double precision
+ precision for short int
+ precision for long int
+ precision for single precision
+ precision for double precision
+ emin for single precision
+ emin for double precision
+ emax for single precision
+ emax for double prcision
+ largest short int
+ largest long int
+
+realcon contains
+ tiny for single precision
+ tiny for double precision
+ huge for single precision
+ huge for double precision
+ mrsp (epsilon) for single precision
+ mrsp (epsilon) for double precision
+*/
+ { register struct Incstblock *cstp;
+ extern ftnint intcon[14];
+ extern double realcon[6];
+
+ cstp = consttab + f3field;
+ for(i=0 ; i<f2field ; ++i)
+ if(cstp->atype == mtype)
+ goto foundconst;
+ else
+ ++cstp;
+ goto badtype;
+
+foundconst:
+ switch(cstp->rtype)
+ {
+ case TYLONG:
+ return(mkintcon(intcon[cstp->constno]));
+
+ case TYREAL:
+ case TYDREAL:
+ return(mkrealcon(cstp->rtype,
+ realcon[cstp->constno]) );
+
+ default:
+ Fatal("impossible intrinsic constant");
+ }
+ }
+#endif
+
+ case INTRGEN:
+ sp = spectab + f3field;
+ if(no66flag)
+ if(sp->atype == mtype)
+ goto specfunct;
+ else err66("generic function");
+
+ for(i=0; i<f2field ; ++i)
+ if(sp->atype == mtype)
+ goto specfunct;
+ else
+ ++sp;
+ warn1 ("bad argument type to intrinsic %s", np->fvarname);
+
+/* Made this a warning rather than an error so things like "log (5) ==>
+ log (5.0)" can be accommodated. When none of these cases matches, the
+ argument is cast up to the first type in the spectab list; this first
+ type is assumed to be the "smallest" type, e.g. REAL before DREAL
+ before COMPLEX, before DCOMPLEX */
+
+ sp = spectab + f3field;
+ mtype = sp -> atype;
+ goto specfunct;
+
+ case INTRSPEC:
+ sp = spectab + f3field;
+specfunct:
+ if(tyint==TYLONG && ONEOF(sp->rtype,M(TYSHORT)|M(TYLOGICAL))
+ && (sp+1)->atype==sp->atype)
+ ++sp;
+
+ if(nargs != sp->nargs)
+ goto badnargs;
+ if(mtype != sp->atype)
+ goto badtype;
+
+/* NOTE!! I moved fixargs (YES) into the ELSE branch so that constants in
+ the inline expression wouldn't get put into the constant table */
+
+ fixargs (NO, argsp);
+ cast_args (mtype, argsp -> listp);
+
+ if(q = Inline((int)(sp-spectab), mtype, argsp->listp))
+ {
+ frchain( &(argsp->listp) );
+ free( (charptr) argsp);
+ } else {
+
+ if(sp->othername) {
+ /* C library routines that return double... */
+ /* sp->rtype might be TYREAL */
+ ap = builtin(sp->rtype,
+ callbyvalue[sp->othername], 1);
+ q = fixexpr((Exprp)
+ mkexpr(OPCCALL, (expptr)ap, (expptr)argsp) );
+ } else {
+ fixargs(YES, argsp);
+ ap = builtin(sp->rtype, sp->spxname, 0);
+ q = fixexpr((Exprp)
+ mkexpr(OPCALL, (expptr)ap, (expptr)argsp) );
+ } /* else */
+ } /* else */
+ return(q);
+
+ case INTRMIN:
+ case INTRMAX:
+ if(nargs < 2)
+ goto badnargs;
+ if( ! ONEOF(mtype, MSKINT|MSKREAL) )
+ goto badtype;
+ argsp->vtype = mtype;
+ q = mkexpr( (f1field==INTRMIN ? OPMIN : OPMAX), (expptr)argsp, ENULL);
+
+ q->headblock.vtype = mtype;
+ rettype = f2field;
+ if(rettype == TYLONG)
+ rettype = tyint;
+ else if(rettype == TYUNKNOWN)
+ rettype = mtype;
+ return( mkconv(rettype, q) );
+
+ default:
+ fatali("intrcall: bad intrgroup %d", f1field);
+ }
+badnargs:
+ errstr("bad number of arguments to intrinsic %s", np->fvarname);
+ goto bad;
+
+badtype:
+ errstr("bad argument type to intrinsic %s", np->fvarname);
+
+bad:
+ return( errnode() );
+}
+
+
+
+ int
+#ifdef KR_headers
+intrfunct(s)
+ char *s;
+#else
+intrfunct(char *s)
+#endif
+{
+ register struct Intrblock *p;
+ int i;
+ extern int intr_omit;
+
+ for(p = intrtab; p->intrval.intrgroup!=INTREND ; ++p)
+ {
+ if( !strcmp(s, p->intrfname) )
+ {
+ if (i = p->intrval.extflag) {
+ if (i & intr_omit)
+ return 0;
+ if (noextflag)
+ errext(s);
+ }
+ packed.bits.f1 = p->intrval.intrgroup;
+ packed.bits.f2 = p->intrval.intrstuff;
+ packed.bits.f3 = p->intrval.intrno;
+ packed.bits.f4 = p->intrval.dblcmplx;
+ return(packed.ijunk);
+ }
+ }
+
+ return(0);
+}
+
+
+
+
+
+ Addrp
+#ifdef KR_headers
+intraddr(np)
+ Namep np;
+#else
+intraddr(Namep np)
+#endif
+{
+ Addrp q;
+ register struct Specblock *sp;
+ int f3field;
+
+ if(np->vclass!=CLPROC || np->vprocclass!=PINTRINSIC)
+ fatalstr("intraddr: %s is not intrinsic", np->fvarname);
+ packed.ijunk = np->vardesc.varno;
+ f3field = packed.bits.f3;
+
+ switch(packed.bits.f1)
+ {
+ case INTRGEN:
+ /* imag, log, and log10 arent specific functions */
+ if(f3field==31 || f3field==43 || f3field==47)
+ goto bad;
+
+ case INTRSPEC:
+ sp = spectab + f3field;
+ if (tyint == TYLONG
+ && (sp->rtype == TYSHORT || sp->rtype == TYLOGICAL))
+ ++sp;
+ q = builtin(sp->rtype, sp->spxname,
+ sp->othername ? 1 : 0);
+ return(q);
+
+ case INTRCONV:
+ case INTRMIN:
+ case INTRMAX:
+ case INTRBOOL:
+ case INTRCNST:
+ case INTRBGEN:
+bad:
+ errstr("cannot pass %s as actual", np->fvarname);
+ return((Addrp)errnode());
+ }
+ fatali("intraddr: impossible f1=%d\n", (int) packed.bits.f1);
+ /* NOT REACHED */ return 0;
+}
+
+
+
+ void
+#ifdef KR_headers
+cast_args(maxtype, args)
+ int maxtype;
+ chainp args;
+#else
+cast_args(int maxtype, chainp args)
+#endif
+{
+ for (; args; args = args -> nextp) {
+ expptr e = (expptr) args->datap;
+ if (e -> headblock.vtype != maxtype)
+ if (e -> tag == TCONST)
+ args->datap = (char *) mkconv(maxtype, e);
+ else {
+ Addrp temp = mktmp(maxtype, ENULL);
+
+ puteq(cpexpr((expptr)temp), e);
+ args->datap = (char *)temp;
+ } /* else */
+ } /* for */
+} /* cast_args */
+
+
+
+ expptr
+#ifdef KR_headers
+Inline(fno, type, args)
+ int fno;
+ int type;
+ struct Chain *args;
+#else
+Inline(int fno, int type, struct Chain *args)
+#endif
+{
+ register expptr q, t, t1;
+
+ switch(fno)
+ {
+ case 8: /* real abs */
+ case 9: /* short int abs */
+ case 10: /* long int abs */
+ case 11: /* double precision abs */
+ if( addressable(q = (expptr) args->datap) )
+ {
+ t = q;
+ q = NULL;
+ }
+ else
+ t = (expptr) mktmp(type,ENULL);
+ t1 = mkexpr(type == TYREAL && forcedouble ? OPDABS : OPABS,
+ cpexpr(t), ENULL);
+ if(q)
+ t1 = mkexpr(OPCOMMA, mkexpr(OPASSIGN, cpexpr(t),q), t1);
+ frexpr(t);
+ return(t1);
+
+ case 26: /* dprod */
+ q = mkexpr(OPSTAR, mkconv(TYDREAL,(expptr)args->datap),
+ (expptr)args->nextp->datap);
+ return(q);
+
+ case 27: /* len of character string */
+ q = (expptr) cpexpr(((tagptr)args->datap)->headblock.vleng);
+ frexpr((expptr)args->datap);
+ return mkconv(tyioint, q);
+
+ case 14: /* half-integer mod */
+ case 15: /* mod */
+ return mkexpr(OPMOD, (expptr) args->datap,
+ (expptr) args->nextp->datap);
+ }
+ return(NULL);
+}
diff --git a/usr.bin/f2c/io.c b/usr.bin/f2c/io.c
new file mode 100644
index 0000000..12ecedd
--- /dev/null
+++ b/usr.bin/f2c/io.c
@@ -0,0 +1,1508 @@
+/****************************************************************
+Copyright 1990, 1991, 1993, 1994, 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* Routines to generate code for I/O statements.
+ Some corrections and improvements due to David Wasley, U. C. Berkeley
+*/
+
+/* TEMPORARY */
+#define TYIOINT TYLONG
+#define SZIOINT SZLONG
+
+#include "defs.h"
+#include "names.h"
+#include "iob.h"
+
+extern int byterev, inqmask;
+
+static void dofclose Argdcl((void));
+static void dofinquire Argdcl((void));
+static void dofmove Argdcl((char*));
+static void dofopen Argdcl((void));
+static void doiolist Argdcl((chainp));
+static void ioset Argdcl((int, int, expptr));
+static void ioseta Argdcl((int, Addrp));
+static void iosetc Argdcl((int, expptr));
+static void iosetip Argdcl((int, int));
+static void iosetlc Argdcl((int, int, int));
+static void putio Argdcl((expptr, expptr));
+static void putiocall Argdcl((expptr));
+
+iob_data *iob_list;
+Addrp io_structs[9];
+
+LOCAL char ioroutine[12];
+
+LOCAL long ioendlab;
+LOCAL long ioerrlab;
+LOCAL int endbit;
+LOCAL int errbit;
+LOCAL long jumplab;
+LOCAL long skiplab;
+LOCAL int ioformatted;
+LOCAL int statstruct = NO;
+LOCAL struct Labelblock *skiplabel;
+Addrp ioblkp;
+
+#define UNFORMATTED 0
+#define FORMATTED 1
+#define LISTDIRECTED 2
+#define NAMEDIRECTED 3
+
+#define V(z) ioc[z].iocval
+
+#define IOALL 07777
+
+LOCAL struct Ioclist
+{
+ char *iocname;
+ int iotype;
+ expptr iocval;
+}
+ioc[ ] =
+{
+ { "", 0 },
+ { "unit", IOALL },
+ { "fmt", M(IOREAD) | M(IOWRITE) },
+ { "err", IOALL },
+ { "end", M(IOREAD) },
+ { "iostat", IOALL },
+ { "rec", M(IOREAD) | M(IOWRITE) },
+ { "recl", M(IOOPEN) | M(IOINQUIRE) },
+ { "file", M(IOOPEN) | M(IOINQUIRE) },
+ { "status", M(IOOPEN) | M(IOCLOSE) },
+ { "access", M(IOOPEN) | M(IOINQUIRE) },
+ { "form", M(IOOPEN) | M(IOINQUIRE) },
+ { "blank", M(IOOPEN) | M(IOINQUIRE) },
+ { "exist", M(IOINQUIRE) },
+ { "opened", M(IOINQUIRE) },
+ { "number", M(IOINQUIRE) },
+ { "named", M(IOINQUIRE) },
+ { "name", M(IOINQUIRE) },
+ { "sequential", M(IOINQUIRE) },
+ { "direct", M(IOINQUIRE) },
+ { "formatted", M(IOINQUIRE) },
+ { "unformatted", M(IOINQUIRE) },
+ { "nextrec", M(IOINQUIRE) },
+ { "nml", M(IOREAD) | M(IOWRITE) }
+};
+
+#define NIOS (sizeof(ioc)/sizeof(struct Ioclist) - 1)
+
+/* #define IOSUNIT 1 */
+/* #define IOSFMT 2 */
+#define IOSERR 3
+#define IOSEND 4
+#define IOSIOSTAT 5
+#define IOSREC 6
+#define IOSRECL 7
+#define IOSFILE 8
+#define IOSSTATUS 9
+#define IOSACCESS 10
+#define IOSFORM 11
+#define IOSBLANK 12
+#define IOSEXISTS 13
+#define IOSOPENED 14
+#define IOSNUMBER 15
+#define IOSNAMED 16
+#define IOSNAME 17
+#define IOSSEQUENTIAL 18
+#define IOSDIRECT 19
+#define IOSFORMATTED 20
+#define IOSUNFORMATTED 21
+#define IOSNEXTREC 22
+#define IOSNML 23
+
+#define IOSTP V(IOSIOSTAT)
+
+
+/* offsets in generated structures */
+
+#define SZFLAG SZIOINT
+
+/* offsets for external READ and WRITE statements */
+
+#define XERR 0
+#define XUNIT SZFLAG
+#define XEND SZFLAG + SZIOINT
+#define XFMT 2*SZFLAG + SZIOINT
+#define XREC 2*SZFLAG + SZIOINT + SZADDR
+
+/* offsets for internal READ and WRITE statements */
+
+#define XIUNIT SZFLAG
+#define XIEND SZFLAG + SZADDR
+#define XIFMT 2*SZFLAG + SZADDR
+#define XIRLEN 2*SZFLAG + 2*SZADDR
+#define XIRNUM 2*SZFLAG + 2*SZADDR + SZIOINT
+#define XIREC 2*SZFLAG + 2*SZADDR + 2*SZIOINT
+
+/* offsets for OPEN statements */
+
+#define XFNAME SZFLAG + SZIOINT
+#define XFNAMELEN SZFLAG + SZIOINT + SZADDR
+#define XSTATUS SZFLAG + 2*SZIOINT + SZADDR
+#define XACCESS SZFLAG + 2*SZIOINT + 2*SZADDR
+#define XFORMATTED SZFLAG + 2*SZIOINT + 3*SZADDR
+#define XRECLEN SZFLAG + 2*SZIOINT + 4*SZADDR
+#define XBLANK SZFLAG + 3*SZIOINT + 4*SZADDR
+
+/* offset for CLOSE statement */
+
+#define XCLSTATUS SZFLAG + SZIOINT
+
+/* offsets for INQUIRE statement */
+
+#define XFILE SZFLAG + SZIOINT
+#define XFILELEN SZFLAG + SZIOINT + SZADDR
+#define XEXISTS SZFLAG + 2*SZIOINT + SZADDR
+#define XOPEN SZFLAG + 2*SZIOINT + 2*SZADDR
+#define XNUMBER SZFLAG + 2*SZIOINT + 3*SZADDR
+#define XNAMED SZFLAG + 2*SZIOINT + 4*SZADDR
+#define XNAME SZFLAG + 2*SZIOINT + 5*SZADDR
+#define XNAMELEN SZFLAG + 2*SZIOINT + 6*SZADDR
+#define XQACCESS SZFLAG + 3*SZIOINT + 6*SZADDR
+#define XQACCLEN SZFLAG + 3*SZIOINT + 7*SZADDR
+#define XSEQ SZFLAG + 4*SZIOINT + 7*SZADDR
+#define XSEQLEN SZFLAG + 4*SZIOINT + 8*SZADDR
+#define XDIRECT SZFLAG + 5*SZIOINT + 8*SZADDR
+#define XDIRLEN SZFLAG + 5*SZIOINT + 9*SZADDR
+#define XFORM SZFLAG + 6*SZIOINT + 9*SZADDR
+#define XFORMLEN SZFLAG + 6*SZIOINT + 10*SZADDR
+#define XFMTED SZFLAG + 7*SZIOINT + 10*SZADDR
+#define XFMTEDLEN SZFLAG + 7*SZIOINT + 11*SZADDR
+#define XUNFMT SZFLAG + 8*SZIOINT + 11*SZADDR
+#define XUNFMTLEN SZFLAG + 8*SZIOINT + 12*SZADDR
+#define XQRECL SZFLAG + 9*SZIOINT + 12*SZADDR
+#define XNEXTREC SZFLAG + 9*SZIOINT + 13*SZADDR
+#define XQBLANK SZFLAG + 9*SZIOINT + 14*SZADDR
+#define XQBLANKLEN SZFLAG + 9*SZIOINT + 15*SZADDR
+
+LOCAL char *cilist_names[] = {
+ "cilist",
+ "cierr",
+ "ciunit",
+ "ciend",
+ "cifmt",
+ "cirec"
+ };
+LOCAL char *icilist_names[] = {
+ "icilist",
+ "icierr",
+ "iciunit",
+ "iciend",
+ "icifmt",
+ "icirlen",
+ "icirnum"
+ };
+LOCAL char *olist_names[] = {
+ "olist",
+ "oerr",
+ "ounit",
+ "ofnm",
+ "ofnmlen",
+ "osta",
+ "oacc",
+ "ofm",
+ "orl",
+ "oblnk"
+ };
+LOCAL char *cllist_names[] = {
+ "cllist",
+ "cerr",
+ "cunit",
+ "csta"
+ };
+LOCAL char *alist_names[] = {
+ "alist",
+ "aerr",
+ "aunit"
+ };
+LOCAL char *inlist_names[] = {
+ "inlist",
+ "inerr",
+ "inunit",
+ "infile",
+ "infilen",
+ "inex",
+ "inopen",
+ "innum",
+ "innamed",
+ "inname",
+ "innamlen",
+ "inacc",
+ "inacclen",
+ "inseq",
+ "inseqlen",
+ "indir",
+ "indirlen",
+ "infmt",
+ "infmtlen",
+ "inform",
+ "informlen",
+ "inunf",
+ "inunflen",
+ "inrecl",
+ "innrec",
+ "inblank",
+ "inblanklen"
+ };
+
+LOCAL char **io_fields;
+
+#define zork(n,t) n, sizeof(n)/sizeof(char *) - 1, t
+
+LOCAL io_setup io_stuff[] = {
+ zork(cilist_names, TYCILIST), /* external read/write */
+ zork(inlist_names, TYINLIST), /* inquire */
+ zork(olist_names, TYOLIST), /* open */
+ zork(cllist_names, TYCLLIST), /* close */
+ zork(alist_names, TYALIST), /* rewind */
+ zork(alist_names, TYALIST), /* backspace */
+ zork(alist_names, TYALIST), /* endfile */
+ zork(icilist_names,TYICILIST), /* internal read */
+ zork(icilist_names,TYICILIST) /* internal write */
+ };
+
+#undef zork
+
+ int
+#ifdef KR_headers
+fmtstmt(lp)
+ register struct Labelblock *lp;
+#else
+fmtstmt(register struct Labelblock *lp)
+#endif
+{
+ if(lp == NULL)
+ {
+ execerr("unlabeled format statement" , CNULL);
+ return(-1);
+ }
+ if(lp->labtype == LABUNKNOWN)
+ {
+ lp->labtype = LABFORMAT;
+ lp->labelno = (int)newlabel();
+ }
+ else if(lp->labtype != LABFORMAT)
+ {
+ execerr("bad format number", CNULL);
+ return(-1);
+ }
+ return(lp->labelno);
+}
+
+
+ void
+#ifdef KR_headers
+setfmt(lp)
+ struct Labelblock *lp;
+#else
+setfmt(struct Labelblock *lp)
+#endif
+{
+ int n, parity;
+ char *s0;
+ register char *s, *se, *t;
+ register k;
+
+ s0 = s = lexline(&n);
+ se = t = s + n;
+
+ /* warn of trivial errors, e.g. " 11 CONTINUE" (one too few spaces) */
+ /* following FORMAT... */
+
+ if (n <= 0)
+ warn("No (...) after FORMAT");
+ else if (*s != '(')
+ warni("%c rather than ( after FORMAT", *s);
+ else if (se[-1] != ')') {
+ *se = 0;
+ while(--t > s && *t != ')') ;
+ if (t <= s)
+ warn("No ) at end of FORMAT statement");
+ else if (se - t > 30)
+ warn1("Extraneous text at end of FORMAT: ...%s", se-12);
+ else
+ warn1("Extraneous text at end of FORMAT: %s", t+1);
+ t = se;
+ }
+
+ /* fix MYQUOTES (\002's) and \\'s */
+
+ parity = 1;
+ while(s < se)
+ switch(*s++) {
+ case 2:
+ if ((parity ^= 1) && *s == 2) {
+ t -= 2;
+ ++s;
+ }
+ else
+ t += 3;
+ break;
+ case '"':
+ case '\\':
+ t++; break;
+ }
+ s = s0;
+ parity = 1;
+ if (lp) {
+ lp->fmtstring = t = mem((int)(t - s + 1), 0);
+ while(s < se)
+ switch(k = *s++) {
+ case 2:
+ if ((parity ^= 1) && *s == 2)
+ s++;
+ else {
+ t[0] = '\\';
+ t[1] = '0';
+ t[2] = '0';
+ t[3] = '2';
+ t += 4;
+ }
+ break;
+ case '"':
+ case '\\':
+ *t++ = '\\';
+ /* no break */
+ default:
+ *t++ = k;
+ }
+ *t = 0;
+ }
+ flline();
+}
+
+
+ void
+#ifdef KR_headers
+startioctl()
+#else
+startioctl()
+#endif
+{
+ register int i;
+
+ inioctl = YES;
+ nioctl = 0;
+ ioformatted = UNFORMATTED;
+ for(i = 1 ; i<=NIOS ; ++i)
+ V(i) = NULL;
+}
+
+ static long
+newiolabel(Void) {
+ long rv;
+ rv = ++lastiolabno;
+ skiplabel = mklabel(rv);
+ skiplabel->labdefined = 1;
+ return rv;
+ }
+
+ void
+endioctl(Void)
+{
+ int i;
+ expptr p;
+ struct io_setup *ios;
+
+ inioctl = NO;
+
+ /* set up for error recovery */
+
+ ioerrlab = ioendlab = skiplab = jumplab = 0;
+
+ if(p = V(IOSEND))
+ if(ISICON(p))
+ execlab(ioendlab = p->constblock.Const.ci);
+ else
+ err("bad end= clause");
+
+ if(p = V(IOSERR))
+ if(ISICON(p))
+ execlab(ioerrlab = p->constblock.Const.ci);
+ else
+ err("bad err= clause");
+
+ if(IOSTP)
+ if(IOSTP->tag!=TADDR || ! ISINT(IOSTP->addrblock.vtype) )
+ {
+ err("iostat must be an integer variable");
+ frexpr(IOSTP);
+ IOSTP = NULL;
+ }
+
+ if(iostmt == IOREAD)
+ {
+ if(IOSTP)
+ {
+ if(ioerrlab && ioendlab && ioerrlab==ioendlab)
+ jumplab = ioerrlab;
+ else
+ skiplab = jumplab = newiolabel();
+ }
+ else {
+ if(ioerrlab && ioendlab && ioerrlab!=ioendlab)
+ {
+ IOSTP = (expptr) mktmp(TYINT, ENULL);
+ skiplab = jumplab = newiolabel();
+ }
+ else
+ jumplab = (ioerrlab ? ioerrlab : ioendlab);
+ }
+ }
+ else if(iostmt == IOWRITE)
+ {
+ if(IOSTP && !ioerrlab)
+ skiplab = jumplab = newiolabel();
+ else
+ jumplab = ioerrlab;
+ }
+ else
+ jumplab = ioerrlab;
+
+ endbit = IOSTP!=NULL || ioendlab!=0; /* for use in startrw() */
+ errbit = IOSTP!=NULL || ioerrlab!=0;
+ if (jumplab && !IOSTP)
+ IOSTP = (expptr) mktmp(TYINT, ENULL);
+
+ if(iostmt!=IOREAD && iostmt!=IOWRITE)
+ {
+ ios = io_stuff + iostmt;
+ io_fields = ios->fields;
+ ioblkp = io_structs[iostmt];
+ if(ioblkp == NULL)
+ io_structs[iostmt] = ioblkp =
+ autovar(1, ios->type, ENULL, "");
+ ioset(TYIOINT, XERR, ICON(errbit));
+ }
+
+ switch(iostmt)
+ {
+ case IOOPEN:
+ dofopen();
+ break;
+
+ case IOCLOSE:
+ dofclose();
+ break;
+
+ case IOINQUIRE:
+ dofinquire();
+ break;
+
+ case IOBACKSPACE:
+ dofmove("f_back");
+ break;
+
+ case IOREWIND:
+ dofmove("f_rew");
+ break;
+
+ case IOENDFILE:
+ dofmove("f_end");
+ break;
+
+ case IOREAD:
+ case IOWRITE:
+ startrw();
+ break;
+
+ default:
+ fatali("impossible iostmt %d", iostmt);
+ }
+ for(i = 1 ; i<=NIOS ; ++i)
+ if(i!=IOSIOSTAT && V(i)!=NULL)
+ frexpr(V(i));
+}
+
+
+ int
+iocname(Void)
+{
+ register int i;
+ int found, mask;
+
+ found = 0;
+ mask = M(iostmt);
+ for(i = 1 ; i <= NIOS ; ++i)
+ if(!strcmp(ioc[i].iocname, token))
+ if(ioc[i].iotype & mask)
+ return(i);
+ else {
+ found = i;
+ break;
+ }
+ if(found) {
+ if (iostmt == IOOPEN && !strcmp(ioc[i].iocname, "name")) {
+ NOEXT("open with \"name=\" treated as \"file=\"");
+ for(i = 1; strcmp(ioc[i].iocname, "file"); i++);
+ return i;
+ }
+ errstr("invalid control %s for statement", ioc[found].iocname);
+ }
+ else
+ errstr("unknown iocontrol %s", token);
+ return(IOSBAD);
+}
+
+
+ void
+#ifdef KR_headers
+ioclause(n, p)
+ register int n;
+ register expptr p;
+#else
+ioclause(register int n, register expptr p)
+#endif
+{
+ struct Ioclist *iocp;
+
+ ++nioctl;
+ if(n == IOSBAD)
+ return;
+ if(n == IOSPOSITIONAL)
+ {
+ n = nioctl;
+ if (n == IOSFMT) {
+ if (iostmt == IOOPEN) {
+ n = IOSFILE;
+ NOEXT("file= specifier omitted from open");
+ }
+ else if (iostmt < IOREAD)
+ goto illegal;
+ }
+ else if(n > IOSFMT)
+ {
+ illegal:
+ err("illegal positional iocontrol");
+ return;
+ }
+ }
+ else if (n == IOSNML)
+ n = IOSFMT;
+
+ if(p == NULL)
+ {
+ if(n == IOSUNIT)
+ p = (expptr) (iostmt==IOREAD ? IOSTDIN : IOSTDOUT);
+ else if(n != IOSFMT)
+ {
+ err("illegal * iocontrol");
+ return;
+ }
+ }
+ if(n == IOSFMT)
+ ioformatted = (p==NULL ? LISTDIRECTED : FORMATTED);
+
+ iocp = & ioc[n];
+ if(iocp->iocval == NULL)
+ {
+ if(n!=IOSFMT && ( n!=IOSUNIT || (p && p->headblock.vtype!=TYCHAR) ) )
+ p = fixtype(p);
+ else if (p && p->tag == TPRIM
+ && p->primblock.namep->vclass == CLUNKNOWN) {
+ /* kludge made necessary by attempt to infer types
+ * for untyped external parameters: given an error
+ * in calling sequences, an integer argument might
+ * tentatively be assumed TYCHAR; this would otherwise
+ * be corrected too late in startrw after startrw
+ * had decided this to be an internal file.
+ */
+ vardcl(p->primblock.namep);
+ p->primblock.vtype = p->primblock.namep->vtype;
+ }
+ iocp->iocval = p;
+ }
+ else
+ errstr("iocontrol %s repeated", iocp->iocname);
+}
+
+/* io list item */
+
+ void
+#ifdef KR_headers
+doio(list)
+ chainp list;
+#else
+doio(chainp list)
+#endif
+{
+ if(ioformatted == NAMEDIRECTED)
+ {
+ if(list)
+ err("no I/O list allowed in NAMELIST read/write");
+ }
+ else
+ {
+ doiolist(list);
+ ioroutine[0] = 'e';
+ if (skiplab)
+ jumplab = 0;
+ putiocall( call0(TYINT, ioroutine) );
+ }
+}
+
+
+
+
+
+ LOCAL void
+#ifdef KR_headers
+doiolist(p0)
+ chainp p0;
+#else
+doiolist(chainp p0)
+#endif
+{
+ chainp p;
+ register tagptr q;
+ register expptr qe;
+ register Namep qn;
+ Addrp tp;
+ int range;
+ extern char *ohalign;
+
+ for (p = p0 ; p ; p = p->nextp)
+ {
+ q = (tagptr)p->datap;
+ if(q->tag == TIMPLDO)
+ {
+ exdo(range = (int)newlabel(), (Namep)0,
+ q->impldoblock.impdospec);
+ doiolist(q->impldoblock.datalist);
+ enddo(range);
+ free( (charptr) q);
+ }
+ else {
+ if(q->tag==TPRIM && q->primblock.argsp==NULL
+ && q->primblock.namep->vdim!=NULL)
+ {
+ vardcl(qn = q->primblock.namep);
+ if(qn->vdim->nelt) {
+ putio( fixtype(cpexpr(qn->vdim->nelt)),
+ (expptr)mkscalar(qn) );
+ qn->vlastdim = 0;
+ }
+ else
+ err("attempt to i/o array of unknown size");
+ }
+ else if(q->tag==TPRIM && q->primblock.argsp==NULL &&
+ (qe = (expptr) memversion(q->primblock.namep)) )
+ putio(ICON(1),qe);
+ else if (ISCONST(q) && q->constblock.vtype == TYCHAR) {
+ halign = 0;
+ putio(ICON(1), qe = fixtype(cpexpr(q)));
+ halign = ohalign;
+ }
+ else if(((qe = fixtype(cpexpr(q)))->tag==TADDR &&
+ (qe->addrblock.uname_tag != UNAM_CONST ||
+ !ISCOMPLEX(qe -> addrblock.vtype))) ||
+ (qe -> tag == TCONST && !ISCOMPLEX(qe ->
+ headblock.vtype))) {
+ if (qe -> tag == TCONST)
+ qe = (expptr) putconst((Constp)qe);
+ putio(ICON(1), qe);
+ }
+ else if(qe->headblock.vtype != TYERROR)
+ {
+ if(iostmt == IOWRITE)
+ {
+ expptr qvl;
+ qvl = NULL;
+ if( ISCHAR(qe) )
+ {
+ qvl = (expptr)
+ cpexpr(qe->headblock.vleng);
+ tp = mktmp(qe->headblock.vtype,
+ ICON(lencat(qe)));
+ }
+ else
+ tp = mktmp(qe->headblock.vtype,
+ qe->headblock.vleng);
+ puteq( cpexpr((expptr)tp), qe);
+ if(qvl) /* put right length on block */
+ {
+ frexpr(tp->vleng);
+ tp->vleng = qvl;
+ }
+ putio(ICON(1), (expptr)tp);
+ }
+ else
+ err("non-left side in READ list");
+ }
+ frexpr(q);
+ }
+ }
+ frchain( &p0 );
+}
+
+ int iocalladdr = TYADDR; /* for fixing TYADDR in saveargtypes */
+ int typeconv[TYERROR+1] = {
+#ifdef TYQUAD
+ 0, 1, 11, 2, 3, 14, 4, 5, 6, 7, 12, 13, 8, 9, 10, 15
+#else
+ 0, 1, 11, 2, 3, 4, 5, 6, 7, 12, 13, 8, 9, 10, 14
+#endif
+ };
+
+ LOCAL void
+#ifdef KR_headers
+putio(nelt, addr)
+ expptr nelt;
+ register expptr addr;
+#else
+putio(expptr nelt, register expptr addr)
+#endif
+{
+ int type;
+ register expptr q;
+ register Addrp c = 0;
+
+ type = addr->headblock.vtype;
+ if(ioformatted!=LISTDIRECTED && ISCOMPLEX(type) )
+ {
+ nelt = mkexpr(OPSTAR, ICON(2), nelt);
+ type -= (TYCOMPLEX-TYREAL);
+ }
+
+ /* pass a length with every item. for noncharacter data, fake one */
+ if(type != TYCHAR)
+ {
+
+ if( ISCONST(addr) )
+ addr = (expptr) putconst((Constp)addr);
+ c = ALLOC(Addrblock);
+ c->tag = TADDR;
+ c->vtype = TYLENG;
+ c->vstg = STGAUTO;
+ c->ntempelt = 1;
+ c->isarray = 1;
+ c->memoffset = ICON(0);
+ c->uname_tag = UNAM_IDENT;
+ c->charleng = 1;
+ sprintf(c->user.ident, "(ftnlen)sizeof(%s)", typename[type]);
+ addr = mkexpr(OPCHARCAST, addr, ENULL);
+ }
+
+ nelt = fixtype( mkconv(tyioint,nelt) );
+ if(ioformatted == LISTDIRECTED) {
+ expptr mc = mkconv(tyioint, ICON(typeconv[type]));
+ q = c ? call4(TYINT, "do_lio", mc, nelt, addr, (expptr)c)
+ : call3(TYINT, "do_lio", mc, nelt, addr);
+ }
+ else {
+ char *s = ioformatted==FORMATTED ? "do_fio"
+ : !byterev ? "do_uio"
+ : ONEOF(type, M(TYCHAR)|M(TYINT1)|M(TYLOGICAL1))
+ ? "do_ucio" : "do_unio";
+ q = c ? call3(TYINT, s, nelt, addr, (expptr)c)
+ : call2(TYINT, s, nelt, addr);
+ }
+ iocalladdr = TYCHAR;
+ putiocall(q);
+ iocalladdr = TYADDR;
+}
+
+
+
+ void
+endio(Void)
+{
+ if(skiplab)
+ {
+ if (ioformatted != NAMEDIRECTED)
+ p1_label((long)(skiplabel - labeltab));
+ if(ioendlab) {
+ exif( mkexpr(OPLT, cpexpr(IOSTP), ICON(0)));
+ exgoto(execlab(ioendlab));
+ exendif();
+ }
+ if(ioerrlab) {
+ exif( mkexpr(iostmt==IOREAD||iostmt==IOWRITE
+ ? OPGT : OPNE,
+ cpexpr(IOSTP), ICON(0)));
+ exgoto(execlab(ioerrlab));
+ exendif();
+ }
+ }
+
+ if(IOSTP)
+ frexpr(IOSTP);
+}
+
+
+
+ LOCAL void
+#ifdef KR_headers
+putiocall(q)
+ register expptr q;
+#else
+putiocall(register expptr q)
+#endif
+{
+ int tyintsave;
+
+ tyintsave = tyint;
+ tyint = tyioint; /* for -I2 and -i2 */
+
+ if(IOSTP)
+ {
+ q->headblock.vtype = TYINT;
+ q = fixexpr((Exprp)mkexpr(OPASSIGN, cpexpr(IOSTP), q));
+ }
+ putexpr(q);
+ if(jumplab) {
+ exif(mkexpr(OPNE, cpexpr(IOSTP), ICON(0)));
+ exgoto(execlab(jumplab));
+ exendif();
+ }
+ tyint = tyintsave;
+}
+
+ void
+#ifdef KR_headers
+fmtname(np, q)
+ Namep np;
+ register Addrp q;
+#else
+fmtname(Namep np, register Addrp q)
+#endif
+{
+ register int k;
+ register char *s, *t;
+ extern chainp assigned_fmts;
+
+ if (!np->vfmt_asg) {
+ np->vfmt_asg = 1;
+ assigned_fmts = mkchain((char *)np, assigned_fmts);
+ }
+ k = strlen(s = np->fvarname);
+ if (k < IDENT_LEN - 4) {
+ q->uname_tag = UNAM_IDENT;
+ t = q->user.ident;
+ }
+ else {
+ q->uname_tag = UNAM_CHARP;
+ q->user.Charp = t = mem(k + 5,0);
+ }
+ sprintf(t, "%s_fmt", s);
+ }
+
+ LOCAL Addrp
+#ifdef KR_headers
+asg_addr(p)
+ union Expression *p;
+#else
+asg_addr(union Expression *p)
+#endif
+{
+ register Addrp q;
+
+ if (p->tag != TPRIM)
+ badtag("asg_addr", p->tag);
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ q->vtype = TYCHAR;
+ q->vstg = STGAUTO;
+ q->ntempelt = 1;
+ q->isarray = 0;
+ q->memoffset = ICON(0);
+ fmtname(p->primblock.namep, q);
+ return q;
+ }
+
+ void
+startrw(Void)
+{
+ register expptr p;
+ register Namep np;
+ register Addrp unitp, fmtp, recp;
+ register expptr nump;
+ int iostmt1;
+ flag intfile, sequential, ok, varfmt;
+ struct io_setup *ios;
+
+ /* First look at all the parameters and determine what is to be done */
+
+ ok = YES;
+ statstruct = YES;
+
+ intfile = NO;
+ if(p = V(IOSUNIT))
+ {
+ if( ISINT(p->headblock.vtype) ) {
+ int_unit:
+ unitp = (Addrp) cpexpr(p);
+ }
+ else if(p->headblock.vtype == TYCHAR)
+ {
+ if (nioctl == 1 && iostmt == IOREAD) {
+ /* kludge to recognize READ(format expr) */
+ V(IOSFMT) = p;
+ V(IOSUNIT) = p = (expptr) IOSTDIN;
+ ioformatted = FORMATTED;
+ goto int_unit;
+ }
+ intfile = YES;
+ if(p->tag==TPRIM && p->primblock.argsp==NULL &&
+ (np = p->primblock.namep)->vdim!=NULL)
+ {
+ vardcl(np);
+ if(nump = np->vdim->nelt)
+ {
+ nump = fixtype(cpexpr(nump));
+ if( ! ISCONST(nump) ) {
+ statstruct = NO;
+ np->vlastdim = 0;
+ }
+ }
+ else
+ {
+ err("attempt to use internal unit array of unknown size");
+ ok = NO;
+ nump = ICON(1);
+ }
+ unitp = mkscalar(np);
+ }
+ else {
+ nump = ICON(1);
+ unitp = (Addrp /*pjw */) fixtype(cpexpr(p));
+ }
+ if(! isstatic((expptr)unitp) )
+ statstruct = NO;
+ }
+ else {
+ err("unit specifier not of type integer or character");
+ ok = NO;
+ }
+ }
+ else
+ {
+ err("bad unit specifier");
+ ok = NO;
+ }
+
+ sequential = YES;
+ if(p = V(IOSREC))
+ if( ISINT(p->headblock.vtype) )
+ {
+ recp = (Addrp) cpexpr(p);
+ sequential = NO;
+ }
+ else {
+ err("bad REC= clause");
+ ok = NO;
+ }
+ else
+ recp = NULL;
+
+
+ varfmt = YES;
+ fmtp = NULL;
+ if(p = V(IOSFMT))
+ {
+ if(p->tag==TPRIM && p->primblock.argsp==NULL)
+ {
+ np = p->primblock.namep;
+ if(np->vclass == CLNAMELIST)
+ {
+ ioformatted = NAMEDIRECTED;
+ fmtp = (Addrp) fixtype(p);
+ V(IOSFMT) = (expptr)fmtp;
+ if (skiplab)
+ jumplab = 0;
+ goto endfmt;
+ }
+ vardcl(np);
+ if(np->vdim)
+ {
+ if( ! ONEOF(np->vstg, MSKSTATIC) )
+ statstruct = NO;
+ fmtp = mkscalar(np);
+ goto endfmt;
+ }
+ if( ISINT(np->vtype) ) /* ASSIGNed label */
+ {
+ statstruct = NO;
+ varfmt = YES;
+ fmtp = asg_addr(p);
+ goto endfmt;
+ }
+ }
+ p = V(IOSFMT) = fixtype(p);
+ if(p->headblock.vtype == TYCHAR
+ /* Since we allow write(6,n) */
+ /* we may as well allow write(6,n(2)) */
+ || p->tag == TADDR && ISINT(p->addrblock.vtype))
+ {
+ if( ! isstatic(p) )
+ statstruct = NO;
+ fmtp = (Addrp) cpexpr(p);
+ }
+ else if( ISICON(p) )
+ {
+ struct Labelblock *lp;
+ lp = mklabel(p->constblock.Const.ci);
+ if (fmtstmt(lp) > 0)
+ {
+ fmtp = (Addrp)mkaddcon(lp->stateno);
+ /* lp->stateno for names fmt_nnn */
+ lp->fmtlabused = 1;
+ varfmt = NO;
+ }
+ else
+ ioformatted = UNFORMATTED;
+ }
+ else {
+ err("bad format descriptor");
+ ioformatted = UNFORMATTED;
+ ok = NO;
+ }
+ }
+ else
+ fmtp = NULL;
+
+endfmt:
+ if(intfile) {
+ if (ioformatted==UNFORMATTED) {
+ err("unformatted internal I/O not allowed");
+ ok = NO;
+ }
+ if (recp) {
+ err("direct internal I/O not allowed");
+ ok = NO;
+ }
+ }
+ if(!sequential && ioformatted==LISTDIRECTED)
+ {
+ err("direct list-directed I/O not allowed");
+ ok = NO;
+ }
+ if(!sequential && ioformatted==NAMEDIRECTED)
+ {
+ err("direct namelist I/O not allowed");
+ ok = NO;
+ }
+
+ if( ! ok ) {
+ statstruct = NO;
+ return;
+ }
+
+ /*
+ Now put out the I/O structure, statically if all the clauses
+ are constants, dynamically otherwise
+*/
+
+ if (intfile) {
+ ios = io_stuff + iostmt;
+ iostmt1 = IOREAD;
+ }
+ else {
+ ios = io_stuff;
+ iostmt1 = 0;
+ }
+ io_fields = ios->fields;
+ if(statstruct)
+ {
+ ioblkp = ALLOC(Addrblock);
+ ioblkp->tag = TADDR;
+ ioblkp->vtype = ios->type;
+ ioblkp->vclass = CLVAR;
+ ioblkp->vstg = STGINIT;
+ ioblkp->memno = ++lastvarno;
+ ioblkp->memoffset = ICON(0);
+ ioblkp -> uname_tag = UNAM_IDENT;
+ new_iob_data(ios,
+ temp_name("io_", lastvarno, ioblkp->user.ident)); }
+ else if(!(ioblkp = io_structs[iostmt1]))
+ io_structs[iostmt1] = ioblkp =
+ autovar(1, ios->type, ENULL, "");
+
+ ioset(TYIOINT, XERR, ICON(errbit));
+ if(iostmt == IOREAD)
+ ioset(TYIOINT, (intfile ? XIEND : XEND), ICON(endbit) );
+
+ if(intfile)
+ {
+ ioset(TYIOINT, XIRNUM, nump);
+ ioset(TYIOINT, XIRLEN, cpexpr(unitp->vleng) );
+ ioseta(XIUNIT, unitp);
+ }
+ else
+ ioset(TYIOINT, XUNIT, (expptr) unitp);
+
+ if(recp)
+ ioset(TYIOINT, /* intfile ? XIREC : */ XREC, (expptr) recp);
+
+ if(varfmt)
+ ioseta( intfile ? XIFMT : XFMT , fmtp);
+ else
+ ioset(TYADDR, intfile ? XIFMT : XFMT, (expptr) fmtp);
+
+ ioroutine[0] = 's';
+ ioroutine[1] = '_';
+ ioroutine[2] = iostmt==IOREAD ? 'r' : 'w';
+ ioroutine[3] = "ds"[sequential];
+ ioroutine[4] = "ufln"[ioformatted];
+ ioroutine[5] = "ei"[intfile];
+ ioroutine[6] = '\0';
+
+ putiocall( call1(TYINT, ioroutine, cpexpr((expptr)ioblkp) ));
+
+ if(statstruct)
+ {
+ frexpr((expptr)ioblkp);
+ statstruct = NO;
+ ioblkp = 0; /* unnecessary */
+ }
+}
+
+
+
+ LOCAL void
+dofopen(Void)
+{
+ register expptr p;
+
+ if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) )
+ ioset(TYIOINT, XUNIT, cpexpr(p) );
+ else
+ err("bad unit in open");
+ if( (p = V(IOSFILE)) )
+ if(p->headblock.vtype == TYCHAR)
+ ioset(TYIOINT, XFNAMELEN, cpexpr(p->headblock.vleng) );
+ else
+ err("bad file in open");
+
+ iosetc(XFNAME, p);
+
+ if(p = V(IOSRECL))
+ if( ISINT(p->headblock.vtype) )
+ ioset(TYIOINT, XRECLEN, cpexpr(p) );
+ else
+ err("bad recl");
+ else
+ ioset(TYIOINT, XRECLEN, ICON(0) );
+
+ iosetc(XSTATUS, V(IOSSTATUS));
+ iosetc(XACCESS, V(IOSACCESS));
+ iosetc(XFORMATTED, V(IOSFORM));
+ iosetc(XBLANK, V(IOSBLANK));
+
+ putiocall( call1(TYINT, "f_open", cpexpr((expptr)ioblkp) ));
+}
+
+
+ LOCAL void
+dofclose(Void)
+{
+ register expptr p;
+
+ if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) )
+ {
+ ioset(TYIOINT, XUNIT, cpexpr(p) );
+ iosetc(XCLSTATUS, V(IOSSTATUS));
+ putiocall( call1(TYINT, "f_clos", cpexpr((expptr)ioblkp)) );
+ }
+ else
+ err("bad unit in close statement");
+}
+
+
+ LOCAL void
+dofinquire(Void)
+{
+ register expptr p;
+ if(p = V(IOSUNIT))
+ {
+ if( V(IOSFILE) )
+ err("inquire by unit or by file, not both");
+ ioset(TYIOINT, XUNIT, cpexpr(p) );
+ }
+ else if( ! V(IOSFILE) )
+ err("must inquire by unit or by file");
+ iosetlc(IOSFILE, XFILE, XFILELEN);
+ iosetip(IOSEXISTS, XEXISTS);
+ iosetip(IOSOPENED, XOPEN);
+ iosetip(IOSNUMBER, XNUMBER);
+ iosetip(IOSNAMED, XNAMED);
+ iosetlc(IOSNAME, XNAME, XNAMELEN);
+ iosetlc(IOSACCESS, XQACCESS, XQACCLEN);
+ iosetlc(IOSSEQUENTIAL, XSEQ, XSEQLEN);
+ iosetlc(IOSDIRECT, XDIRECT, XDIRLEN);
+ iosetlc(IOSFORM, XFORM, XFORMLEN);
+ iosetlc(IOSFORMATTED, XFMTED, XFMTEDLEN);
+ iosetlc(IOSUNFORMATTED, XUNFMT, XUNFMTLEN);
+ iosetip(IOSRECL, XQRECL);
+ iosetip(IOSNEXTREC, XNEXTREC);
+ iosetlc(IOSBLANK, XQBLANK, XQBLANKLEN);
+
+ putiocall( call1(TYINT, "f_inqu", cpexpr((expptr)ioblkp) ));
+}
+
+
+
+ LOCAL void
+#ifdef KR_headers
+dofmove(subname)
+ char *subname;
+#else
+dofmove(char *subname)
+#endif
+{
+ register expptr p;
+
+ if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) )
+ {
+ ioset(TYIOINT, XUNIT, cpexpr(p) );
+ putiocall( call1(TYINT, subname, cpexpr((expptr)ioblkp) ));
+ }
+ else
+ err("bad unit in I/O motion statement");
+}
+
+static int ioset_assign = OPASSIGN;
+
+ LOCAL void
+#ifdef KR_headers
+ioset(type, offset, p)
+ int type;
+ int offset;
+ register expptr p;
+#else
+ioset(int type, int offset, register expptr p)
+#endif
+{
+ offset /= SZLONG;
+ if(statstruct && ISCONST(p)) {
+ register char *s;
+ switch(type) {
+ case TYADDR: /* stmt label */
+ s = "fmt_";
+ break;
+ case TYIOINT:
+ s = "";
+ break;
+ default:
+ badtype("ioset", type);
+ }
+ iob_list->fields[offset] =
+ string_num(s, p->constblock.Const.ci);
+ frexpr(p);
+ }
+ else {
+ register Addrp q;
+
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ q->vtype = type;
+ q->vstg = STGAUTO;
+ q->ntempelt = 1;
+ q->isarray = 0;
+ q->memoffset = ICON(0);
+ q->uname_tag = UNAM_IDENT;
+ sprintf(q->user.ident, "%s.%s",
+ statstruct ? iob_list->name : ioblkp->user.ident,
+ io_fields[offset + 1]);
+ if (type == TYADDR && p->tag == TCONST
+ && p->constblock.vtype == TYADDR) {
+ /* kludge */
+ register Addrp p1;
+ p1 = ALLOC(Addrblock);
+ p1->tag = TADDR;
+ p1->vtype = type;
+ p1->vstg = STGAUTO; /* wrong, but who cares? */
+ p1->ntempelt = 1;
+ p1->isarray = 0;
+ p1->memoffset = ICON(0);
+ p1->uname_tag = UNAM_IDENT;
+ sprintf(p1->user.ident, "fmt_%ld",
+ p->constblock.Const.ci);
+ frexpr(p);
+ p = (expptr)p1;
+ }
+ if (type == TYADDR && p->headblock.vtype == TYCHAR)
+ q->vtype = TYCHAR;
+ putexpr(mkexpr(ioset_assign, (expptr)q, p));
+ }
+}
+
+
+
+
+ LOCAL void
+#ifdef KR_headers
+iosetc(offset, p)
+ int offset;
+ register expptr p;
+#else
+iosetc(int offset, register expptr p)
+#endif
+{
+ if(p == NULL)
+ ioset(TYADDR, offset, ICON(0) );
+ else if(p->headblock.vtype == TYCHAR) {
+ p = putx(fixtype((expptr)putchop(cpexpr(p))));
+ ioset(TYADDR, offset, addrof(p));
+ }
+ else
+ err("non-character control clause");
+}
+
+
+
+ LOCAL void
+#ifdef KR_headers
+ioseta(offset, p)
+ int offset;
+ register Addrp p;
+#else
+ioseta(int offset, register Addrp p)
+#endif
+{
+ char *s, *s1;
+ static char who[] = "ioseta";
+ expptr e, mo;
+ Namep np;
+ ftnint ci;
+ int k;
+ char buf[24], buf1[24];
+ Extsym *comm;
+ extern int usedefsforcommon;
+
+ if(statstruct)
+ {
+ if (!p)
+ return;
+ if (p->tag != TADDR)
+ badtag(who, p->tag);
+ offset /= SZLONG;
+ switch(p->uname_tag) {
+ case UNAM_NAME:
+ mo = p->memoffset;
+ if (mo->tag != TCONST)
+ badtag("ioseta/memoffset", mo->tag);
+ np = p->user.name;
+ np->visused = 1;
+ ci = mo->constblock.Const.ci - np->voffset;
+ if (np->vstg == STGCOMMON
+ && !np->vcommequiv
+ && !usedefsforcommon) {
+ comm = &extsymtab[np->vardesc.varno];
+ sprintf(buf, "%d.", comm->curno);
+ k = strlen(buf) + strlen(comm->cextname)
+ + strlen(np->cvarname);
+ if (ci) {
+ sprintf(buf1, "+%ld", ci);
+ k += strlen(buf1);
+ }
+ else
+ buf1[0] = 0;
+ s = mem(k + 1, 0);
+ sprintf(s, "%s%s%s%s", comm->cextname, buf,
+ np->cvarname, buf1);
+ }
+ else if (ci) {
+ sprintf(buf,"%ld", ci);
+ s1 = p->user.name->cvarname;
+ k = strlen(buf) + strlen(s1);
+ sprintf(s = mem(k+2,0), "%s+%s", s1, buf);
+ }
+ else
+ s = cpstring(np->cvarname);
+ break;
+ case UNAM_CONST:
+ s = tostring(p->user.Const.ccp1.ccp0,
+ (int)p->vleng->constblock.Const.ci);
+ break;
+ default:
+ badthing("uname_tag", who, p->uname_tag);
+ }
+ /* kludge for Hollerith */
+ if (p->vtype != TYCHAR) {
+ s1 = mem(strlen(s)+10,0);
+ sprintf(s1, "(char *)%s%s", p->isarray ? "" : "&", s);
+ s = s1;
+ }
+ iob_list->fields[offset] = s;
+ }
+ else {
+ if (!p)
+ e = ICON(0);
+ else if (p->vtype != TYCHAR) {
+ NOEXT("non-character variable as format or internal unit");
+ e = mkexpr(OPCHARCAST, (expptr)p, ENULL);
+ }
+ else
+ e = addrof((expptr)p);
+ ioset(TYADDR, offset, e);
+ }
+}
+
+
+
+
+ LOCAL void
+#ifdef KR_headers
+iosetip(i, offset)
+ int i;
+ int offset;
+#else
+iosetip(int i, int offset)
+#endif
+{
+ register expptr p;
+
+ if(p = V(i))
+ if(p->tag==TADDR &&
+ ONEOF(p->addrblock.vtype, inqmask) ) {
+ ioset_assign = OPASSIGNI;
+ ioset(TYADDR, offset, addrof(cpexpr(p)) );
+ ioset_assign = OPASSIGN;
+ }
+ else
+ errstr("impossible inquire parameter %s", ioc[i].iocname);
+ else
+ ioset(TYADDR, offset, ICON(0) );
+}
+
+
+
+ LOCAL void
+#ifdef KR_headers
+iosetlc(i, offp, offl)
+ int i;
+ int offp;
+ int offl;
+#else
+iosetlc(int i, int offp, int offl)
+#endif
+{
+ register expptr p;
+ if( (p = V(i)) && p->headblock.vtype==TYCHAR)
+ ioset(TYIOINT, offl, cpexpr(p->headblock.vleng) );
+ iosetc(offp, p);
+}
diff --git a/usr.bin/f2c/iob.h b/usr.bin/f2c/iob.h
new file mode 100644
index 0000000..065d813
--- /dev/null
+++ b/usr.bin/f2c/iob.h
@@ -0,0 +1,26 @@
+struct iob_data {
+ struct iob_data *next;
+ char *type;
+ char *name;
+ char *fields[1];
+ };
+struct io_setup {
+ char **fields;
+ int nelt, type;
+ };
+
+struct defines {
+ struct defines *next;
+ char defname[1];
+ };
+
+typedef struct iob_data iob_data;
+typedef struct io_setup io_setup;
+typedef struct defines defines;
+
+extern iob_data *iob_list;
+extern struct Addrblock *io_structs[9];
+void def_start Argdcl((FILEP, char*, char*, char*));
+void new_iob_data Argdcl((io_setup*, char*));
+void other_undefs Argdcl((FILEP));
+char* tostring Argdcl((char*, int));
diff --git a/usr.bin/f2c/lex.c b/usr.bin/f2c/lex.c
new file mode 100644
index 0000000..6e779e1
--- /dev/null
+++ b/usr.bin/f2c/lex.c
@@ -0,0 +1,1707 @@
+/****************************************************************
+Copyright 1990, 1992 - 1997 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "tokdefs.h"
+#include "p1defs.h"
+
+#ifdef NO_EOF_CHAR_CHECK
+#undef EOF_CHAR
+#else
+#ifndef EOF_CHAR
+#define EOF_CHAR 26 /* ASCII control-Z */
+#endif
+#endif
+
+#define BLANK ' '
+#define MYQUOTE (2)
+#define SEOF 0
+
+/* card types */
+
+#define STEOF 1
+#define STINITIAL 2
+#define STCONTINUE 3
+
+/* lex states */
+
+#define NEWSTMT 1
+#define FIRSTTOKEN 2
+#define OTHERTOKEN 3
+#define RETEOS 4
+
+
+LOCAL int stkey; /* Type of the current statement (DO, END, IF, etc) */
+static int needwkey;
+ftnint yystno;
+flag intonly;
+extern int new_dcl;
+LOCAL long int stno;
+LOCAL long int nxtstno; /* Statement label */
+LOCAL int parlev; /* Parentheses level */
+LOCAL int parseen;
+LOCAL int expcom;
+LOCAL int expeql;
+LOCAL char *nextch;
+LOCAL char *lastch;
+LOCAL char *nextcd = NULL;
+LOCAL char *endcd;
+LOCAL long prevlin;
+LOCAL long thislin;
+LOCAL int code; /* Card type; INITIAL, CONTINUE or EOF */
+LOCAL int lexstate = NEWSTMT;
+LOCAL char *sbuf; /* Main buffer for Fortran source input. */
+LOCAL char *send; /* Was = sbuf+20*66 with sbuf[1390]. */
+LOCAL int maxcont;
+LOCAL int nincl = 0; /* Current number of include files */
+LOCAL long firstline;
+LOCAL char *laststb, *stb0;
+extern int addftnsrc;
+static char **linestart;
+LOCAL int ncont;
+LOCAL char comstart[Table_size];
+#define USC (unsigned char *)
+
+static char anum_buf[Table_size];
+#define isalnum_(x) anum_buf[x]
+#define isalpha_(x) (anum_buf[x] == 1)
+
+#define COMMENT_BUF_STORE 4088
+
+typedef struct comment_buf {
+ struct comment_buf *next;
+ char *last;
+ char buf[COMMENT_BUF_STORE];
+ } comment_buf;
+static comment_buf *cbfirst, *cbcur;
+static char *cbinit, *cbnext, *cblast;
+static void flush_comments Argdcl((void));
+extern flag use_bs;
+static char *lastfile = "??", *lastfile0 = "?";
+static char fbuf[P1_FILENAME_MAX];
+static long lastline;
+static void putlineno(Void);
+
+
+/* Comment buffering data
+
+ Comments are kept in a list until the statement before them has
+ been parsed. This list is implemented with the above comment_buf
+ structure and the pointers cbnext and cblast.
+
+ The comments are stored with terminating NULL, and no other
+ intervening space. The last few bytes of each block are likely to
+ remain unused.
+*/
+
+/* struct Inclfile holds the state information for each include file */
+struct Inclfile
+{
+ struct Inclfile *inclnext;
+ FILEP inclfp;
+ char *inclname;
+ int incllno;
+ char *incllinp;
+ int incllen;
+ int inclcode;
+ ftnint inclstno;
+};
+
+LOCAL struct Inclfile *inclp = NULL;
+struct Keylist {
+ char *keyname;
+ int keyval;
+ char notinf66;
+};
+struct Punctlist {
+ char punchar;
+ int punval;
+};
+struct Fmtlist {
+ char fmtchar;
+ int fmtval;
+};
+struct Dotlist {
+ char *dotname;
+ int dotval;
+ };
+LOCAL struct Keylist *keystart[26], *keyend[26];
+
+/* KEYWORD AND SPECIAL CHARACTER TABLES
+*/
+
+static struct Punctlist puncts[ ] =
+{
+ '(', SLPAR,
+ ')', SRPAR,
+ '=', SEQUALS,
+ ',', SCOMMA,
+ '+', SPLUS,
+ '-', SMINUS,
+ '*', SSTAR,
+ '/', SSLASH,
+ '$', SCURRENCY,
+ ':', SCOLON,
+ '<', SLT,
+ '>', SGT,
+ 0, 0 };
+
+LOCAL struct Dotlist dots[ ] =
+{
+ "and.", SAND,
+ "or.", SOR,
+ "not.", SNOT,
+ "true.", STRUE,
+ "false.", SFALSE,
+ "eq.", SEQ,
+ "ne.", SNE,
+ "lt.", SLT,
+ "le.", SLE,
+ "gt.", SGT,
+ "ge.", SGE,
+ "neqv.", SNEQV,
+ "eqv.", SEQV,
+ 0, 0 };
+
+LOCAL struct Keylist keys[ ] =
+{
+ { "assign", SASSIGN },
+ { "automatic", SAUTOMATIC, YES },
+ { "backspace", SBACKSPACE },
+ { "blockdata", SBLOCK },
+ { "byte", SBYTE },
+ { "call", SCALL },
+ { "character", SCHARACTER, YES },
+ { "close", SCLOSE, YES },
+ { "common", SCOMMON },
+ { "complex", SCOMPLEX },
+ { "continue", SCONTINUE },
+ { "data", SDATA },
+ { "dimension", SDIMENSION },
+ { "doubleprecision", SDOUBLE },
+ { "doublecomplex", SDCOMPLEX, YES },
+ { "elseif", SELSEIF, YES },
+ { "else", SELSE, YES },
+ { "endfile", SENDFILE },
+ { "endif", SENDIF, YES },
+ { "enddo", SENDDO, YES },
+ { "end", SEND },
+ { "entry", SENTRY, YES },
+ { "equivalence", SEQUIV },
+ { "external", SEXTERNAL },
+ { "format", SFORMAT },
+ { "function", SFUNCTION },
+ { "goto", SGOTO },
+ { "implicit", SIMPLICIT, YES },
+ { "include", SINCLUDE, YES },
+ { "inquire", SINQUIRE, YES },
+ { "intrinsic", SINTRINSIC, YES },
+ { "integer", SINTEGER },
+ { "logical", SLOGICAL },
+ { "namelist", SNAMELIST, YES },
+ { "none", SUNDEFINED, YES },
+ { "open", SOPEN, YES },
+ { "parameter", SPARAM, YES },
+ { "pause", SPAUSE },
+ { "print", SPRINT },
+ { "program", SPROGRAM, YES },
+ { "punch", SPUNCH, YES },
+ { "read", SREAD },
+ { "real", SREAL },
+ { "return", SRETURN },
+ { "rewind", SREWIND },
+ { "save", SSAVE, YES },
+ { "static", SSTATIC, YES },
+ { "stop", SSTOP },
+ { "subroutine", SSUBROUTINE },
+ { "then", STHEN, YES },
+ { "undefined", SUNDEFINED, YES },
+ { "while", SWHILE, YES },
+ { "write", SWRITE },
+ { 0, 0 }
+};
+
+static void analyz Argdcl((void));
+static void crunch Argdcl((void));
+static int getcd Argdcl((char*, int));
+static int getcds Argdcl((void));
+static int getkwd Argdcl((void));
+static int gettok Argdcl((void));
+static void store_comment Argdcl((char*));
+LOCAL char *stbuf[3];
+
+ int
+#ifdef KR_headers
+inilex(name)
+ char *name;
+#else
+inilex(char *name)
+#endif
+{
+ stbuf[0] = Alloc(3*P1_STMTBUFSIZE);
+ stbuf[1] = stbuf[0] + P1_STMTBUFSIZE;
+ stbuf[2] = stbuf[1] + P1_STMTBUFSIZE;
+ nincl = 0;
+ inclp = NULL;
+ doinclude(name);
+ lexstate = NEWSTMT;
+ return(NO);
+}
+
+
+
+/* throw away the rest of the current line */
+ void
+flline(Void)
+{
+ lexstate = RETEOS;
+}
+
+
+
+ char *
+#ifdef KR_headers
+lexline(n)
+ int *n;
+#else
+lexline(int *n)
+#endif
+{
+ *n = (lastch - nextch) + 1;
+ return(nextch);
+}
+
+
+
+
+ void
+#ifdef KR_headers
+doinclude(name)
+ char *name;
+#else
+doinclude(char *name)
+#endif
+{
+ FILEP fp;
+ struct Inclfile *t;
+ char *name0, *lastslash, *s, *s0, *temp;
+ int j, k;
+ chainp I;
+ extern chainp Iargs;
+
+ err_lineno = -1;
+ if(inclp)
+ {
+ inclp->incllno = thislin;
+ inclp->inclcode = code;
+ inclp->inclstno = nxtstno;
+ if(nextcd && (j = endcd - nextcd) > 0)
+ inclp->incllinp = copyn(inclp->incllen = j, nextcd);
+ else
+ inclp->incllinp = 0;
+ }
+ nextcd = NULL;
+
+ if(++nincl >= MAXINCLUDES)
+ Fatal("includes nested too deep");
+ if(name[0] == '\0')
+ fp = stdin;
+ else if(name[0] == '/' || inclp == NULL
+#ifdef MSDOS
+ || name[0] == '\\'
+ || name[1] == ':'
+#endif
+ )
+ fp = fopen(name, textread);
+ else {
+ lastslash = NULL;
+ s = s0 = inclp->inclname;
+#ifdef MSDOS
+ if (s[1] == ':')
+ lastslash = s + 1;
+#endif
+ for(; *s ; ++s)
+ if(*s == '/'
+#ifdef MSDOS
+ || *s == '\\'
+#endif
+ )
+ lastslash = s;
+ name0 = name;
+ if(lastslash) {
+ k = lastslash - s0 + 1;
+ temp = Alloc(k + strlen(name) + 1);
+ strncpy(temp, s0, k);
+ strcpy(temp+k, name);
+ name = temp;
+ }
+ fp = fopen(name, textread);
+ if (!fp && (I = Iargs)) {
+ k = strlen(name0) + 2;
+ for(; I; I = I->nextp) {
+ j = strlen(s = I->datap);
+ name = Alloc(j + k);
+ strcpy(name, s);
+ switch(s[j-1]) {
+ case '/':
+#ifdef MSDOS
+ case ':':
+ case '\\':
+#endif
+ break;
+ default:
+ name[j++] = '/';
+ }
+ strcpy(name+j, name0);
+ if (fp = fopen(name, textread)) {
+ free(name0);
+ goto havefp;
+ }
+ free(name);
+ name = name0;
+ }
+ }
+ }
+ if (fp)
+ {
+ havefp:
+ t = inclp;
+ inclp = ALLOC(Inclfile);
+ inclp->inclnext = t;
+ prevlin = thislin = 0;
+ infname = inclp->inclname = name;
+ infile = inclp->inclfp = fp;
+ lastline = 0;
+ putlineno();
+ lastline = 0;
+ }
+ else
+ {
+ fprintf(diagfile, "Cannot open file %s\n", name);
+ done(1);
+ }
+}
+
+
+
+
+ LOCAL int
+popinclude(Void)
+{
+ struct Inclfile *t;
+ register char *p;
+ register int k;
+
+ if(infile != stdin)
+ clf(&infile, infname, 1); /* Close the input file */
+ free(infname);
+
+ --nincl;
+ err_lineno = -1;
+ t = inclp->inclnext;
+ free( (charptr) inclp);
+ inclp = t;
+ if(inclp == NULL) {
+ infname = 0;
+ return(NO);
+ }
+
+ infile = inclp->inclfp;
+ infname = inclp->inclname;
+ lineno = prevlin = thislin = inclp->incllno;
+ code = inclp->inclcode;
+ stno = nxtstno = inclp->inclstno;
+ if(inclp->incllinp)
+ {
+ lastline = 0;
+ putlineno();
+ lastline = lineno;
+ endcd = nextcd = sbuf;
+ k = inclp->incllen;
+ p = inclp->incllinp;
+ while(--k >= 0)
+ *endcd++ = *p++;
+ free( (charptr) (inclp->incllinp) );
+ }
+ else
+ nextcd = NULL;
+ return(YES);
+}
+
+
+ void
+#ifdef KR_headers
+p1_line_number(line_number)
+ long line_number;
+#else
+p1_line_number(long line_number)
+#endif
+{
+ if (lastfile != lastfile0) {
+ p1puts(P1_FILENAME, fbuf);
+ lastfile0 = lastfile;
+ }
+ fprintf(pass1_file, "%d: %ld\n", P1_SET_LINE, line_number);
+ }
+
+ static void
+putlineno(Void)
+{
+ extern int gflag;
+ register char *s0, *s1;
+
+ if (gflag) {
+ if (lastline)
+ p1_line_number(lastline);
+ lastline = firstline;
+ if (lastfile != infname)
+ if (lastfile = infname) {
+ strncpy(fbuf, lastfile, sizeof(fbuf));
+ fbuf[sizeof(fbuf)-1] = 0;
+ }
+ else
+ fbuf[0] = 0;
+ }
+ if (addftnsrc) {
+ if (laststb && *laststb) {
+ for(s1 = laststb; *s1; s1++) {
+ for(s0 = s1; *s1 != '\n'; s1++)
+ if (*s1 == '*' && s1[1] == '/')
+ *s1 = '+';
+ *s1 = 0;
+ p1puts(P1_FORTRAN, s0);
+ }
+ *laststb = 0; /* prevent trouble after EOF */
+ }
+ laststb = stb0;
+ }
+ }
+
+ int
+yylex(Void)
+{
+ static int tokno;
+ int retval;
+
+ switch(lexstate)
+ {
+ case NEWSTMT : /* need a new statement */
+ retval = getcds();
+ putlineno();
+ if(retval == STEOF) {
+ retval = SEOF;
+ break;
+ } /* if getcds() == STEOF */
+ crunch();
+ tokno = 0;
+ lexstate = FIRSTTOKEN;
+ yystno = stno;
+ stno = nxtstno;
+ toklen = 0;
+ retval = SLABEL;
+ break;
+
+first:
+ case FIRSTTOKEN : /* first step on a statement */
+ analyz();
+ lexstate = OTHERTOKEN;
+ tokno = 1;
+ retval = stkey;
+ break;
+
+ case OTHERTOKEN : /* return next token */
+ if(nextch > lastch)
+ goto reteos;
+ ++tokno;
+ if( (stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3)
+ goto first;
+
+ if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
+ nextch[0]=='t' && nextch[1]=='o')
+ {
+ nextch+=2;
+ retval = STO;
+ break;
+ }
+ if (tokno == 2 && stkey == SDO) {
+ intonly = 1;
+ retval = gettok();
+ intonly = 0;
+ }
+ else
+ retval = gettok();
+ break;
+
+reteos:
+ case RETEOS:
+ lexstate = NEWSTMT;
+ retval = SEOS;
+ break;
+ default:
+ fatali("impossible lexstate %d", lexstate);
+ break;
+ }
+
+ if (retval == SEOF)
+ flush_comments ();
+
+ return retval;
+}
+
+ LOCAL void
+contmax(Void)
+{
+ lineno = thislin;
+ many("continuation lines", 'C', maxcontin);
+ }
+
+/* Get Cards.
+
+ Returns STEOF or STINITIAL, never STCONTINUE. Any continuation cards get
+merged into one long card (hence the size of the buffer named sbuf) */
+
+ LOCAL int
+getcds(Void)
+{
+ register char *p, *q;
+
+ flush_comments ();
+top:
+ if(nextcd == NULL)
+ {
+ code = getcd( nextcd = sbuf, 1 );
+ stno = nxtstno;
+ prevlin = thislin;
+ }
+ if(code == STEOF)
+ if( popinclude() )
+ goto top;
+ else
+ return(STEOF);
+
+ if(code == STCONTINUE)
+ {
+ lineno = thislin;
+ nextcd = NULL;
+ goto top;
+ }
+
+/* Get rid of unused space at the head of the buffer */
+
+ if(nextcd > sbuf)
+ {
+ q = nextcd;
+ p = sbuf;
+ while(q < endcd)
+ *p++ = *q++;
+ endcd = p;
+ }
+
+/* Be aware that the input (i.e. the string at the address nextcd) is NOT
+ NULL-terminated */
+
+/* This loop merges all continuations into one long statement, AND puts the next
+ card to be read at the end of the buffer (i.e. it stores the look-ahead card
+ when there's room) */
+
+ ncont = 0;
+ for(;;) {
+ nextcd = endcd;
+ if (ncont >= maxcont || nextcd+66 > send)
+ contmax();
+ linestart[ncont++] = nextcd;
+ if ((code = getcd(nextcd,0)) != STCONTINUE)
+ break;
+ if (ncont == 20 && noextflag) {
+ lineno = thislin;
+ errext("more than 19 continuation lines");
+ }
+ }
+ nextch = sbuf;
+ lastch = nextcd - 1;
+
+ lineno = prevlin;
+ prevlin = thislin;
+ return(STINITIAL);
+}
+
+ static void
+#ifdef KR_headers
+bang(a, b, c, d, e)
+ char *a;
+ char *b;
+ char *c;
+ register char *d;
+ register char *e;
+#else
+bang(char *a, char *b, char *c, register char *d, register char *e)
+#endif
+ /* save ! comments */
+{
+ char buf[COMMENT_BUFFER_SIZE + 1];
+ register char *p, *pe;
+
+ p = buf;
+ pe = buf + COMMENT_BUFFER_SIZE;
+ *pe = 0;
+ while(a < b)
+ if (!(*p++ = *a++))
+ p[-1] = 0;
+ if (b < c)
+ *p++ = '\t';
+ while(d < e) {
+ if (!(*p++ = *d++))
+ p[-1] = ' ';
+ if (p == pe) {
+ store_comment(buf);
+ p = buf;
+ }
+ }
+ if (p > buf) {
+ while(--p >= buf && *p == ' ');
+ p[1] = 0;
+ store_comment(buf);
+ }
+ }
+
+
+/* getcd - Get next input card
+
+ This function reads the next input card from global file pointer infile.
+It assumes that b points to currently empty storage somewhere in sbuf */
+
+ LOCAL int
+#ifdef KR_headers
+getcd(b, nocont)
+ register char *b;
+ int nocont;
+#else
+getcd(register char *b, int nocont)
+#endif
+{
+ register int c;
+ register char *p, *bend;
+ int speclin; /* Special line - true when the line is allowed
+ to have more than 66 characters (e.g. the
+ "&" shorthand for continuation, use of a "\t"
+ to skip part of the label columns) */
+ static char a[6]; /* Statement label buffer */
+ static char *aend = a+6;
+ static char *stb, *stbend;
+ static int nst;
+ char *atend, *endcd0;
+ extern int warn72;
+ char buf72[24];
+ int amp, i;
+ char storage[COMMENT_BUFFER_SIZE + 1];
+ char *pointer;
+ long L;
+
+top:
+ endcd = b;
+ bend = b+66;
+ amp = speclin = NO;
+ atend = aend;
+
+/* Handle the continuation shorthand of "&" in the first column, which stands
+ for " x" */
+
+ if( (c = getc(infile)) == '&')
+ {
+ a[0] = c;
+ a[1] = 0;
+ a[5] = 'x';
+ amp = speclin = YES;
+ bend = send;
+ p = aend;
+ }
+
+/* Handle the Comment cards (a 'C', 'c', '*', or '!' in the first column). */
+
+ else if(comstart[c & (Table_size-1)])
+ {
+ if (feof (infile)
+#ifdef EOF_CHAR
+ || c == EOF_CHAR
+#endif
+ )
+ return STEOF;
+
+ if (c == '#') {
+ *endcd++ = c;
+ while((c = getc(infile)) != '\n')
+ if (c == EOF)
+ return STEOF;
+ else if (endcd < bend)
+ *endcd++ = c;
+ ++thislin;
+ *endcd = 0;
+ if (b[1] == ' ')
+ p = b + 2;
+ else if (!strncmp(b,"#line ",6))
+ p = b + 6;
+ else {
+ bad_cpp:
+ errstr("Bad # line: \"%s\"", b);
+ goto top;
+ }
+ if (*p < '1' || *p > '9')
+ goto bad_cpp;
+ L = *p - '0';
+ while((c = *++p) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (c != ' ' || *++p != '"')
+ goto bad_cpp;
+ bend = p;
+ while(*++p != '"')
+ if (!*p)
+ goto bad_cpp;
+ *p = 0;
+ i = p - bend++;
+ thislin = L - 1;
+ if (!infname || strcmp(infname, bend)) {
+ if (infname)
+ free(infname);
+ lastfile = 0;
+ infname = Alloc(i);
+ strcpy(infname, bend);
+ if (inclp)
+ inclp->inclname = infname;
+ }
+ goto top;
+ }
+
+ storage[COMMENT_BUFFER_SIZE] = c = '\0';
+ pointer = storage;
+ while( !feof (infile) && (*pointer++ = c = getc(infile)) != '\n') {
+
+/* Handle obscure end of file conditions on many machines */
+
+ if (feof (infile) && (c == '\377' || c == EOF)) {
+ pointer--;
+ break;
+ } /* if (feof (infile)) */
+
+ if (c == '\0')
+ *(pointer - 1) = ' ';
+
+ if (pointer == &storage[COMMENT_BUFFER_SIZE]) {
+ store_comment (storage);
+ pointer = storage;
+ } /* if (pointer == BUFFER_SIZE) */
+ } /* while */
+
+ if (pointer > storage) {
+ if (c == '\n')
+
+/* Get rid of the newline */
+
+ pointer[-1] = 0;
+ else
+ *pointer = 0;
+
+ store_comment (storage);
+ } /* if */
+
+ if (feof (infile))
+ if (c != '\n') /* To allow the line index to
+ increment correctly */
+ return STEOF;
+
+ ++thislin;
+ goto top;
+ }
+
+ else if(c != EOF)
+ {
+
+/* Load buffer a with the statement label */
+
+ /* a tab in columns 1-6 skips to column 7 */
+ ungetc(c, infile);
+ for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
+ if(c == '\t')
+
+/* The tab character translates into blank characters in the statement label */
+
+ {
+ atend = p;
+ while(p < aend)
+ *p++ = BLANK;
+ speclin = YES;
+ bend = send;
+ }
+ else
+ *p++ = c;
+ }
+
+/* By now we've read either a continuation character or the statement label
+ field */
+
+ if(c == EOF)
+ return(STEOF);
+
+/* The next 'if' block handles lines that have fewer than 7 characters */
+
+ if(c == '\n')
+ {
+ while(p < aend)
+ *p++ = BLANK;
+
+/* Blank out the buffer on lines which are not longer than 66 characters */
+
+ endcd0 = endcd;
+ if( ! speclin )
+ while(endcd < bend)
+ *endcd++ = BLANK;
+ }
+ else { /* read body of line */
+ if (warn72 & 2) {
+ speclin = YES;
+ bend = send;
+ }
+ while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
+ *endcd++ = c;
+ if(c == EOF)
+ return(STEOF);
+
+/* Drop any extra characters on the input card; this usually means those after
+ column 72 */
+
+ if(c != '\n')
+ {
+ i = 0;
+ while( (c=getc(infile)) != '\n' && c != EOF)
+ if (i < 23)
+ buf72[i++] = c;
+ if (warn72 && i && !speclin) {
+ buf72[i] = 0;
+ if (i >= 23)
+ strcpy(buf72+20, "...");
+ lineno = thislin + 1;
+ errstr("text after column 72: %s", buf72);
+ }
+ if(c == EOF)
+ return(STEOF);
+ }
+
+ endcd0 = endcd;
+ if( ! speclin )
+ while(endcd < bend)
+ *endcd++ = BLANK;
+ }
+
+/* The flow of control usually gets to this line (unless an earlier RETURN has
+ been taken) */
+
+ ++thislin;
+
+ /* Fortran 77 specifies that a 0 in column 6 */
+ /* does not signify continuation */
+
+ if( !isspace(a[5]) && a[5]!='0') {
+ if (!amp)
+ for(p = a; p < aend;)
+ if (*p++ == '!' && p != aend)
+ goto initcheck;
+ if (addftnsrc && stb) {
+ if (stbend > stb + 7) { /* otherwise forget col 1-6 */
+ /* kludge around funny p1gets behavior */
+ *stb++ = '$';
+ if (amp)
+ *stb++ = '&';
+ else
+ for(p = a; p < atend;)
+ *stb++ = *p++;
+ }
+ if (endcd0 - b > stbend - stb) {
+ if (stb > stbend)
+ stb = stbend;
+ endcd0 = b + (stbend - stb);
+ }
+ for(p = b; p < endcd0;)
+ *stb++ = *p++;
+ *stb++ = '\n';
+ *stb = 0;
+ }
+ if (nocont) {
+ lineno = thislin;
+ errstr("illegal continuation card (starts \"%.6s\")",a);
+ }
+ else if (!amp && strncmp(a," ",5)) {
+ lineno = thislin;
+ errstr("labeled continuation line (starts \"%.6s\")",a);
+ }
+ return(STCONTINUE);
+ }
+initcheck:
+ for(p=a; p<atend; ++p)
+ if( !isspace(*p) ) {
+ if (*p++ != '!')
+ goto initline;
+ bang(p, atend, aend, b, endcd);
+ goto top;
+ }
+ for(p = b ; p<endcd ; ++p)
+ if( !isspace(*p) ) {
+ if (*p++ != '!')
+ goto initline;
+ bang(a, a, a, p, endcd);
+ goto top;
+ }
+
+/* Skip over blank cards by reading the next one right away */
+
+ goto top;
+
+initline:
+ if (!lastline)
+ lastline = thislin;
+ if (addftnsrc) {
+ nst = (nst+1)%3;
+ if (!laststb && stb0)
+ laststb = stb0;
+ stb0 = stb = stbuf[nst];
+ *stb++ = '$'; /* kludge around funny p1gets behavior */
+ stbend = stb + sizeof(stbuf[0])-2;
+ for(p = a; p < atend;)
+ *stb++ = *p++;
+ if (atend < aend)
+ *stb++ = '\t';
+ for(p = b; p < endcd0;)
+ *stb++ = *p++;
+ *stb++ = '\n';
+ *stb = 0;
+ }
+
+/* Set nxtstno equal to the integer value of the statement label */
+
+ nxtstno = 0;
+ bend = a + 5;
+ for(p = a ; p < bend ; ++p)
+ if( !isspace(*p) )
+ if(isdigit(*p))
+ nxtstno = 10*nxtstno + (*p - '0');
+ else if (*p == '!') {
+ if (!addftnsrc)
+ bang(p+1,atend,aend,b,endcd);
+ endcd = b;
+ break;
+ }
+ else {
+ lineno = thislin;
+ errstr(
+ "nondigit in statement label field \"%.5s\"", a);
+ nxtstno = 0;
+ break;
+ }
+ firstline = thislin;
+ return(STINITIAL);
+}
+
+ LOCAL void
+#ifdef KR_headers
+adjtoklen(newlen)
+ int newlen;
+#else
+adjtoklen(int newlen)
+#endif
+{
+ while(maxtoklen < newlen)
+ maxtoklen = 2*maxtoklen + 2;
+ if (token = (char *)realloc(token, maxtoklen))
+ return;
+ fprintf(stderr, "adjtoklen: realloc(%d) failure!\n", maxtoklen);
+ exit(2);
+ }
+
+/* crunch -- deletes all space characters, folds the backslash chars and
+ Hollerith strings, quotes the Fortran strings */
+
+ LOCAL void
+crunch(Void)
+{
+ register char *i, *j, *j0, *j1, *prvstr;
+ int k, ten, nh, nh0, quote;
+
+ /* i is the next input character to be looked at
+ j is the next output character */
+
+ new_dcl = needwkey = parlev = parseen = 0;
+ expcom = 0; /* exposed ','s */
+ expeql = 0; /* exposed equal signs */
+ j = sbuf;
+ prvstr = sbuf;
+ k = 0;
+ for(i=sbuf ; i<=lastch ; ++i)
+ {
+ if(isspace(*i) )
+ continue;
+ if (*i == '!') {
+ while(i >= linestart[k])
+ if (++k >= maxcont)
+ contmax();
+ j0 = linestart[k];
+ if (!addftnsrc)
+ bang(sbuf,sbuf,sbuf,i+1,j0);
+ i = j0-1;
+ continue;
+ }
+
+/* Keep everything in a quoted string */
+
+ if(*i=='\'' || *i=='"')
+ {
+ int len = 0;
+
+ quote = *i;
+ *j = MYQUOTE; /* special marker */
+ for(;;)
+ {
+ if(++i > lastch)
+ {
+ err("unbalanced quotes; closing quote supplied");
+ if (j >= lastch)
+ j = lastch - 1;
+ break;
+ }
+ if(*i == quote)
+ if(i<lastch && i[1]==quote) ++i;
+ else break;
+ else if(*i=='\\' && i<lastch && use_bs) {
+ ++i;
+ *i = escapes[*(unsigned char *)i];
+ }
+ *++j = *i;
+ len++;
+ } /* for (;;) */
+
+ if ((len = j - sbuf) > maxtoklen)
+ adjtoklen(len);
+ j[1] = MYQUOTE;
+ j += 2;
+ prvstr = j;
+ }
+ else if( (*i=='h' || *i=='H') && j>prvstr) /* test for Hollerith strings */
+ {
+ j0 = j - 1;
+ if( ! isdigit(*j0)) goto copychar;
+ nh = *j0 - '0';
+ ten = 10;
+ j1 = prvstr;
+ if (j1 > sbuf && j1[-1] == MYQUOTE)
+ --j1;
+ if (j1+4 < j)
+ j1 = j-4;
+ for(;;) {
+ if (j0-- <= j1)
+ goto copychar;
+ if( ! isdigit(*j0 ) ) break;
+ nh += ten * (*j0-'0');
+ ten*=10;
+ }
+/* A Hollerith string must be preceded by a punctuation mark.
+ '*' is possible only as repetition factor in a data statement
+ not, in particular, in character*2h .
+ To avoid some confusion with missing commas in FORMAT statements,
+ treat a preceding string as a punctuation mark.
+ */
+
+ if( !(*j0=='*'&&sbuf[0]=='d') && *j0!='/'
+ && *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.'
+ && *j0 != MYQUOTE)
+ goto copychar;
+ nh0 = nh;
+ if(i+nh > lastch)
+ {
+ erri("%dH too big", nh);
+ nh = lastch - i;
+ nh0 = -1;
+ }
+ if (nh > maxtoklen)
+ adjtoklen(nh);
+ j0[1] = MYQUOTE; /* special marker */
+ j = j0 + 1;
+ while(nh-- > 0)
+ {
+ if (++i > lastch) {
+ hol_overflow:
+ if (nh0 >= 0)
+ erri("escapes make %dH too big",
+ nh0);
+ break;
+ }
+ if(*i == '\\' && use_bs) {
+ if (++i > lastch)
+ goto hol_overflow;
+ *i = escapes[*(unsigned char *)i];
+ }
+ *++j = *i;
+ }
+ j[1] = MYQUOTE;
+ j+=2;
+ prvstr = j;
+ }
+ else {
+ if(*i == '(') parseen = ++parlev;
+ else if(*i == ')') --parlev;
+ else if(parlev == 0)
+ if(*i == '=') expeql = 1;
+ else if(*i == ',') expcom = 1;
+copychar: /*not a string or space -- copy, shifting case if necessary */
+ if(shiftcase && isupper(*i))
+ *j++ = tolower(*i);
+ else *j++ = *i;
+ }
+ }
+ lastch = j - 1;
+ nextch = sbuf;
+}
+
+ LOCAL void
+analyz(Void)
+{
+ register char *i;
+
+ if(parlev != 0)
+ {
+ err("unbalanced parentheses, statement skipped");
+ stkey = SUNKNOWN;
+ lastch = sbuf - 1; /* prevent double error msg */
+ return;
+ }
+ if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
+ {
+ /* assignment or if statement -- look at character after balancing paren */
+ parlev = 1;
+ for(i=nextch+3 ; i<=lastch; ++i)
+ if(*i == (MYQUOTE))
+ {
+ while(*++i != MYQUOTE)
+ ;
+ }
+ else if(*i == '(')
+ ++parlev;
+ else if(*i == ')')
+ {
+ if(--parlev == 0)
+ break;
+ }
+ if(i >= lastch)
+ stkey = SLOGIF;
+ else if(i[1] == '=')
+ stkey = SLET;
+ else if( isdigit(i[1]) )
+ stkey = SARITHIF;
+ else stkey = SLOGIF;
+ if(stkey != SLET)
+ nextch += 2;
+ }
+ else if(expeql) /* may be an assignment */
+ {
+ if(expcom && nextch<lastch &&
+ nextch[0]=='d' && nextch[1]=='o')
+ {
+ stkey = SDO;
+ nextch += 2;
+ }
+ else stkey = SLET;
+ }
+ else if (parseen && nextch + 7 < lastch
+ && nextch[2] != 'u' /* screen out "double..." early */
+ && nextch[0] == 'd' && nextch[1] == 'o'
+ && ((nextch[2] >= '0' && nextch[2] <= '9')
+ || nextch[2] == ','
+ || nextch[2] == 'w'))
+ {
+ stkey = SDO;
+ nextch += 2;
+ needwkey = 1;
+ }
+ /* otherwise search for keyword */
+ else {
+ stkey = getkwd();
+ if(stkey==SGOTO && lastch>=nextch)
+ if(nextch[0]=='(')
+ stkey = SCOMPGOTO;
+ else if(isalpha_(* USC nextch))
+ stkey = SASGOTO;
+ }
+ parlev = 0;
+}
+
+
+
+ LOCAL int
+getkwd(Void)
+{
+ register char *i, *j;
+ register struct Keylist *pk, *pend;
+ int k;
+
+ if(! isalpha_(* USC nextch) )
+ return(SUNKNOWN);
+ k = letter(nextch[0]);
+ if(pk = keystart[k])
+ for(pend = keyend[k] ; pk<=pend ; ++pk )
+ {
+ i = pk->keyname;
+ j = nextch;
+ while(*++i==*++j && *i!='\0')
+ ;
+ if(*i=='\0' && j<=lastch+1)
+ {
+ nextch = j;
+ if(no66flag && pk->notinf66)
+ errstr("Not a Fortran 66 keyword: %s",
+ pk->keyname);
+ return(pk->keyval);
+ }
+ }
+ return(SUNKNOWN);
+}
+
+ void
+initkey(Void)
+{
+ register struct Keylist *p;
+ register int i,j;
+ register char *s;
+
+ for(i = 0 ; i<26 ; ++i)
+ keystart[i] = NULL;
+
+ for(p = keys ; p->keyname ; ++p) {
+ j = letter(p->keyname[0]);
+ if(keystart[j] == NULL)
+ keystart[j] = p;
+ keyend[j] = p;
+ }
+ i = (maxcontin + 2) * 66;
+ sbuf = (char *)ckalloc(i + 70);
+ send = sbuf + i;
+ maxcont = maxcontin + 1;
+ linestart = (char **)ckalloc(maxcont*sizeof(char*));
+ comstart['c'] = comstart['C'] = comstart['*'] = comstart['!'] =
+ comstart['#'] = 1;
+#ifdef EOF_CHAR
+ comstart[EOF_CHAR] = 1;
+#endif
+ s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
+ while(i = *s++)
+ anum_buf[i] = 1;
+ s = "0123456789";
+ while(i = *s++)
+ anum_buf[i] = 2;
+ }
+
+ LOCAL int
+#ifdef KR_headers
+hexcheck(key)
+ int key;
+#else
+hexcheck(int key)
+#endif
+{
+ register int radix;
+ register char *p;
+ char *kind;
+
+ switch(key) {
+ case 'z':
+ case 'Z':
+ case 'x':
+ case 'X':
+ radix = 16;
+ key = SHEXCON;
+ kind = "hexadecimal";
+ break;
+ case 'o':
+ case 'O':
+ radix = 8;
+ key = SOCTCON;
+ kind = "octal";
+ break;
+ case 'b':
+ case 'B':
+ radix = 2;
+ key = SBITCON;
+ kind = "binary";
+ break;
+ default:
+ err("bad bit identifier");
+ return(SNAME);
+ }
+ for(p = token; *p; p++)
+ if (hextoi(*p) >= radix) {
+ errstr("invalid %s character", kind);
+ break;
+ }
+ return key;
+ }
+
+/* gettok -- moves the right amount of text from nextch into the token
+ buffer. token initially contains garbage (leftovers from the prev token) */
+
+ LOCAL int
+gettok(Void)
+{
+ int havdot, havexp, havdbl;
+ int radix, val;
+ struct Punctlist *pp;
+ struct Dotlist *pd;
+ register int ch;
+ static char Exp_mi[] = "X**-Y treated as X**(-Y)",
+ Exp_pl[] = "X**+Y treated as X**(+Y)";
+
+ char *i, *j, *n1, *p;
+
+ ch = * USC nextch;
+ if(ch == (MYQUOTE))
+ {
+ ++nextch;
+ p = token;
+ while(*nextch != MYQUOTE)
+ *p++ = *nextch++;
+ toklen = p - token;
+ *p = 0;
+ /* allow octal, binary, hex constants of the form 'abc'x (etc.) */
+ if (++nextch <= lastch && isalpha_(val = * USC nextch)) {
+ ++nextch;
+ return hexcheck(val);
+ }
+ return (SHOLLERITH);
+ }
+
+ if(needkwd)
+ {
+ needkwd = 0;
+ return( getkwd() );
+ }
+
+ for(pp=puncts; pp->punchar; ++pp)
+ if(ch == pp->punchar) {
+ val = pp->punval;
+ if (++nextch <= lastch)
+ switch(ch) {
+ case '/':
+ switch(*nextch) {
+ case '/':
+ nextch++;
+ val = SCONCAT;
+ break;
+ case '=':
+ goto sne;
+ default:
+ if (new_dcl && parlev == 0)
+ val = SSLASHD;
+ }
+ return val;
+ case '*':
+ if (*nextch == '*') {
+ nextch++;
+ if (noextflag
+ && nextch <= lastch)
+ switch(*nextch) {
+ case '-':
+ errext(Exp_mi);
+ break;
+ case '+':
+ errext(Exp_pl);
+ }
+ return SPOWER;
+ }
+ break;
+ case '<':
+ switch(*nextch) {
+ case '=':
+ nextch++;
+ val = SLE;
+ break;
+ case '>':
+ sne:
+ nextch++;
+ val = SNE;
+ }
+ goto extchk;
+ case '=':
+ if (*nextch == '=') {
+ nextch++;
+ val = SEQ;
+ goto extchk;
+ }
+ break;
+ case '>':
+ if (*nextch == '=') {
+ nextch++;
+ val = SGE;
+ }
+ extchk:
+ NOEXT("Fortran 8x comparison operator");
+ return val;
+ }
+ else if (ch == '/' && new_dcl && parlev == 0)
+ return SSLASHD;
+ switch(val) {
+ case SLPAR:
+ ++parlev;
+ break;
+ case SRPAR:
+ --parlev;
+ }
+ return(val);
+ }
+ if(ch == '.')
+ if(nextch >= lastch) goto badchar;
+ else if(isdigit(nextch[1])) goto numconst;
+ else {
+ for(pd=dots ; (j=pd->dotname) ; ++pd)
+ {
+ for(i=nextch+1 ; i<=lastch ; ++i)
+ if(*i != *j) break;
+ else if(*i != '.') ++j;
+ else {
+ nextch = i+1;
+ return(pd->dotval);
+ }
+ }
+ goto badchar;
+ }
+ if( isalpha_(ch) )
+ {
+ p = token;
+ *p++ = *nextch++;
+ while(nextch<=lastch)
+ if( isalnum_(* USC nextch) )
+ *p++ = *nextch++;
+ else break;
+ toklen = p - token;
+ *p = 0;
+ if (needwkey) {
+ needwkey = 0;
+ if (toklen == 5
+ && nextch <= lastch && *nextch == '(' /*)*/
+ && !strcmp(token,"while"))
+ return(SWHILE);
+ }
+ if(inioctl && nextch<=lastch && *nextch=='=')
+ {
+ ++nextch;
+ return(SNAMEEQ);
+ }
+ if(toklen>8 && eqn(8,token,"function")
+ && isalpha_(* USC (token+8)) &&
+ nextch<lastch && nextch[0]=='(' &&
+ (nextch[1]==')' || isalpha_(* USC (nextch+1))) )
+ {
+ nextch -= (toklen - 8);
+ return(SFUNCTION);
+ }
+
+ if(toklen > MAXNAMELEN)
+ {
+ char buff[MAXNAMELEN+50];
+ sprintf(buff, toklen >= MAXNAMELEN+10
+ ? "name %.*s... too long, truncated to %.*s"
+ : "name %s too long, truncated to %.*s",
+ MAXNAMELEN+6, token, MAXNAMELEN, token);
+ err(buff);
+ toklen = MAXNAMELEN;
+ token[MAXNAMELEN] = '\0';
+ }
+ if(toklen==1 && *nextch==MYQUOTE) {
+ val = token[0];
+ ++nextch;
+ for(p = token ; *nextch!=MYQUOTE ; )
+ *p++ = *nextch++;
+ ++nextch;
+ toklen = p - token;
+ *p = 0;
+ return hexcheck(val);
+ }
+ return(SNAME);
+ }
+
+ if (isdigit(ch)) {
+
+ /* Check for NAG's special hex constant */
+
+ if (nextch[1] == '#' && nextch < lastch
+ || nextch[2] == '#' && isdigit(nextch[1])
+ && lastch - nextch >= 2) {
+
+ radix = atoi (nextch);
+ if (*++nextch != '#')
+ nextch++;
+ if (radix != 2 && radix != 8 && radix != 16) {
+ erri("invalid base %d for constant, defaulting to hex",
+ radix);
+ radix = 16;
+ } /* if */
+ if (++nextch > lastch)
+ goto badchar;
+ for (p = token; hextoi(*nextch) < radix;) {
+ *p++ = *nextch++;
+ if (nextch > lastch)
+ break;
+ }
+ toklen = p - token;
+ *p = 0;
+ return (radix == 16) ? SHEXCON : ((radix == 8) ? SOCTCON :
+ SBITCON);
+ }
+ }
+ else
+ goto badchar;
+numconst:
+ havdot = NO;
+ havexp = NO;
+ havdbl = NO;
+ for(n1 = nextch ; nextch<=lastch ; ++nextch)
+ {
+ if(*nextch == '.')
+ if(havdot) break;
+ else if(nextch+2<=lastch && isalpha_(* USC (nextch+1))
+ && isalpha_(* USC (nextch+2)))
+ break;
+ else havdot = YES;
+ else if( !intonly && (*nextch=='d' || *nextch=='e') )
+ {
+ p = nextch;
+ havexp = YES;
+ if(*nextch == 'd')
+ havdbl = YES;
+ if(nextch<lastch)
+ if(nextch[1]=='+' || nextch[1]=='-')
+ ++nextch;
+ if( ! isdigit(*++nextch) )
+ {
+ nextch = p;
+ havdbl = havexp = NO;
+ break;
+ }
+ for(++nextch ;
+ nextch<=lastch && isdigit(* USC nextch);
+ ++nextch);
+ break;
+ }
+ else if( ! isdigit(* USC nextch) )
+ break;
+ }
+ p = token;
+ i = n1;
+ while(i < nextch)
+ *p++ = *i++;
+ toklen = p - token;
+ *p = 0;
+ if(havdbl) return(SDCON);
+ if(havdot || havexp) return(SRCON);
+ return(SICON);
+badchar:
+ sbuf[0] = *nextch++;
+ return(SUNKNOWN);
+}
+
+/* Comment buffering code */
+
+ static void
+#ifdef KR_headers
+store_comment(str)
+ char *str;
+#else
+store_comment(char *str)
+#endif
+{
+ int len;
+ comment_buf *ncb;
+
+ if (nextcd == sbuf) {
+ flush_comments();
+ p1_comment(str);
+ return;
+ }
+ len = strlen(str) + 1;
+ if (cbnext + len > cblast) {
+ if (!cbcur || !(ncb = cbcur->next)) {
+ ncb = (comment_buf *) Alloc(sizeof(comment_buf));
+ if (cbcur) {
+ cbcur->last = cbnext;
+ cbcur->next = ncb;
+ }
+ else {
+ cbfirst = ncb;
+ cbinit = ncb->buf;
+ }
+ ncb->next = 0;
+ }
+ cbcur = ncb;
+ cbnext = ncb->buf;
+ cblast = cbnext + COMMENT_BUF_STORE;
+ }
+ strcpy(cbnext, str);
+ cbnext += len;
+ }
+
+ static void
+flush_comments(Void)
+{
+ register char *s, *s1;
+ register comment_buf *cb;
+ if (cbnext == cbinit)
+ return;
+ cbcur->last = cbnext;
+ for(cb = cbfirst;; cb = cb->next) {
+ for(s = cb->buf; s < cb->last; s = s1) {
+ /* compute s1 = new s value first, since */
+ /* p1_comment may insert nulls into s */
+ s1 = s + strlen(s) + 1;
+ p1_comment(s);
+ }
+ if (cb == cbcur)
+ break;
+ }
+ cbcur = cbfirst;
+ cbnext = cbinit;
+ cblast = cbnext + COMMENT_BUF_STORE;
+ }
+
+ void
+unclassifiable(Void)
+{
+ register char *s, *se;
+
+ s = sbuf;
+ se = lastch;
+ if (se < sbuf)
+ return;
+ lastch = s - 1;
+ if (++se - s > 10)
+ se = s + 10;
+ for(; s < se; s++)
+ if (*s == MYQUOTE) {
+ se = s;
+ break;
+ }
+ *se = 0;
+ errstr("unclassifiable statement (starts \"%s\")", sbuf);
+ }
diff --git a/usr.bin/f2c/machdefs.h b/usr.bin/f2c/machdefs.h
new file mode 100644
index 0000000..3ab8961
--- /dev/null
+++ b/usr.bin/f2c/machdefs.h
@@ -0,0 +1,31 @@
+#define TYLENG TYLONG /* char string length field */
+
+#define TYINT TYLONG
+#define SZADDR 4
+#define SZSHORT 2
+#define SZINT 4
+
+#define SZLONG 4
+#define SZLENG SZLONG
+
+#define SZDREAL 8
+
+/* Alignment restrictions */
+
+#define ALIADDR SZADDR
+#define ALISHORT SZSHORT
+#define ALILONG 4
+#define ALIDOUBLE 8
+#define ALIINT ALILONG
+#define ALILENG ALILONG
+
+#define BLANKCOMMON "_BLNK__" /* Name for the unnamed
+ common block; this is unique
+ because of underscores */
+
+#define LABELFMT "%s:\n"
+
+#define MAXREGVAR 4
+#define TYIREG TYLONG
+#define MSKIREG (M(TYSHORT)|M(TYLONG)) /* allowed types of DO indicies
+ which can be put in registers */
diff --git a/usr.bin/f2c/main.c b/usr.bin/f2c/main.c
new file mode 100644
index 0000000..4183855
--- /dev/null
+++ b/usr.bin/f2c/main.c
@@ -0,0 +1,708 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+extern char F2C_version[];
+
+#include "defs.h"
+#include "parse.h"
+
+int complex_seen, dcomplex_seen;
+
+LOCAL int Max_ftn_files;
+
+int badargs;
+char **ftn_files;
+int current_ftn_file = 0;
+
+flag ftn66flag = NO;
+flag nowarnflag = NO;
+flag noextflag = NO;
+flag no66flag = NO; /* Must also set noextflag to this
+ same value */
+flag zflag = YES; /* recognize double complex intrinsics */
+flag debugflag = NO;
+flag onetripflag = NO;
+flag shiftcase = YES;
+flag undeftype = NO;
+flag checksubs = NO;
+flag r8flag = NO;
+flag use_bs = YES;
+flag keepsubs = NO;
+flag byterev = NO;
+int intr_omit;
+static int no_cd, no_i90;
+#ifdef TYQUAD
+flag use_tyquad = YES;
+#endif
+int tyreal = TYREAL;
+int tycomplex = TYCOMPLEX;
+
+int maxregvar = MAXREGVAR; /* if maxregvar > MAXREGVAR, error */
+int maxequiv = MAXEQUIV;
+int maxext = MAXEXT;
+int maxstno = MAXSTNO;
+int maxctl = MAXCTL;
+int maxhash = MAXHASH;
+int maxliterals = MAXLITERALS;
+int maxcontin = MAXCONTIN;
+int maxlablist = MAXLABLIST;
+int extcomm, ext1comm, useauto;
+int can_include = YES; /* so we can disable includes for netlib */
+
+static char *def_i2 = "";
+
+static int useshortints = NO; /* YES => tyint = TYSHORT */
+static int uselongints = NO; /* YES => tyint = TYLONG */
+int addftnsrc = NO; /* Include ftn source in output */
+int usedefsforcommon = NO; /* Use #defines for common reference */
+int forcedouble = YES; /* force real functions to double */
+int dneg = NO; /* f77 treatment of unary minus */
+int Ansi = NO;
+int def_equivs = YES;
+int tyioint = TYLONG;
+int szleng = SZLENG;
+int inqmask = M(TYLONG)|M(TYLOGICAL);
+int wordalign = NO;
+int forcereal = NO;
+int warn72 = NO;
+static int skipC, skipversion;
+char *file_name, *filename0, *parens;
+int Castargs = 1;
+static int Castargs1;
+static int typedefs = 0;
+int chars_per_wd, gflag, protostatus;
+int infertypes = 1;
+char used_rets[TYSUBR+1];
+extern char *tmpdir;
+static int h0align = 0;
+char *halign, *ohalign;
+int krparens = NO;
+int hsize; /* for padding under -h */
+int htype; /* for wr_equiv_init under -h */
+chainp Iargs;
+char *o_coutput = 0;
+
+#define f2c_entry(swit,count,type,store,size) \
+ p_entry ("-", swit, 0, count, type, store, size)
+
+static arg_info table[] = {
+ f2c_entry ("o", P_ONE_ARG, P_STRING, &o_coutput, YES),
+ f2c_entry ("w66", P_NO_ARGS, P_INT, &ftn66flag, YES),
+ f2c_entry ("w", P_NO_ARGS, P_INT, &nowarnflag, YES),
+ f2c_entry ("66", P_NO_ARGS, P_INT, &no66flag, YES),
+ f2c_entry ("1", P_NO_ARGS, P_INT, &onetripflag, YES),
+ f2c_entry ("onetrip", P_NO_ARGS, P_INT, &onetripflag, YES),
+ f2c_entry ("I2", P_NO_ARGS, P_INT, &useshortints, YES),
+ f2c_entry ("I4", P_NO_ARGS, P_INT, &uselongints, YES),
+ f2c_entry ("U", P_NO_ARGS, P_INT, &shiftcase, NO),
+ f2c_entry ("u", P_NO_ARGS, P_INT, &undeftype, YES),
+ f2c_entry ("O", P_ONE_ARG, P_INT, &maxregvar, 0),
+ f2c_entry ("C", P_NO_ARGS, P_INT, &checksubs, YES),
+ f2c_entry ("Nq", P_ONE_ARG, P_INT, &maxequiv, 0),
+ f2c_entry ("Nx", P_ONE_ARG, P_INT, &maxext, 0),
+ f2c_entry ("Ns", P_ONE_ARG, P_INT, &maxstno, 0),
+ f2c_entry ("Nc", P_ONE_ARG, P_INT, &maxctl, 0),
+ f2c_entry ("Nn", P_ONE_ARG, P_INT, &maxhash, 0),
+ f2c_entry ("NL", P_ONE_ARG, P_INT, &maxliterals, 0),
+ f2c_entry ("NC", P_ONE_ARG, P_INT, &maxcontin, 0),
+ f2c_entry ("Nl", P_ONE_ARG, P_INT, &maxlablist, 0),
+ f2c_entry ("c", P_NO_ARGS, P_INT, &addftnsrc, YES),
+ f2c_entry ("p", P_NO_ARGS, P_INT, &usedefsforcommon, YES),
+ f2c_entry ("R", P_NO_ARGS, P_INT, &forcedouble, NO),
+ f2c_entry ("!R", P_NO_ARGS, P_INT, &forcedouble, YES),
+ f2c_entry ("A", P_NO_ARGS, P_INT, &Ansi, YES),
+ f2c_entry ("ext", P_NO_ARGS, P_INT, &noextflag, YES),
+ f2c_entry ("z", P_NO_ARGS, P_INT, &zflag, NO),
+ f2c_entry ("a", P_NO_ARGS, P_INT, &useauto, YES),
+ f2c_entry ("r8", P_NO_ARGS, P_INT, &r8flag, YES),
+ f2c_entry ("i2", P_NO_ARGS, P_INT, &tyioint, NO),
+ f2c_entry ("w8", P_NO_ARGS, P_INT, &wordalign, YES),
+ f2c_entry ("!I", P_NO_ARGS, P_INT, &can_include, NO),
+ f2c_entry ("W", P_ONE_ARG, P_INT, &chars_per_wd, 0),
+ f2c_entry ("g", P_NO_ARGS, P_INT, &gflag, YES),
+ f2c_entry ("T", P_ONE_ARG, P_STRING, &tmpdir, 0),
+ f2c_entry ("E", P_NO_ARGS, P_INT, &extcomm, 1),
+ f2c_entry ("e1c", P_NO_ARGS, P_INT, &ext1comm, 1),
+ f2c_entry ("ec", P_NO_ARGS, P_INT, &ext1comm, 2),
+ f2c_entry ("C++", P_NO_ARGS, P_INT, &Ansi, 2),
+ f2c_entry ("P", P_NO_ARGS, P_INT, &Castargs, 3),
+ f2c_entry ("Ps", P_NO_ARGS, P_INT, &protostatus, 1),
+ f2c_entry ("!P", P_NO_ARGS, P_INT, &Castargs, 0),
+ f2c_entry ("!c", P_NO_ARGS, P_INT, &skipC, 1),
+ f2c_entry ("!it", P_NO_ARGS, P_INT, &infertypes, 0),
+ f2c_entry ("h", P_NO_ARGS, P_INT, &h0align, 1),
+ f2c_entry ("hd", P_NO_ARGS, P_INT, &h0align, 2),
+ f2c_entry ("kr", P_NO_ARGS, P_INT, &krparens, 1),
+ f2c_entry ("krd", P_NO_ARGS, P_INT, &krparens, 2),
+ f2c_entry ("!bs", P_NO_ARGS, P_INT, &use_bs, NO),
+ f2c_entry ("r", P_NO_ARGS, P_INT, &forcereal, YES),
+ f2c_entry ("72", P_NO_ARGS, P_INT, &warn72, 1),
+ f2c_entry ("f", P_NO_ARGS, P_INT, &warn72, 2),
+ f2c_entry ("s", P_NO_ARGS, P_INT, &keepsubs, 1),
+ f2c_entry ("d", P_ONE_ARG, P_STRING, &outbuf, 0),
+ f2c_entry ("cd", P_NO_ARGS, P_INT, &no_cd, 1),
+ f2c_entry ("i90", P_NO_ARGS, P_INT, &no_i90, 2),
+#ifdef TYQUAD
+ f2c_entry ("!i8", P_NO_ARGS, P_INT, &use_tyquad, NO),
+#endif
+
+ /* options omitted from man pages */
+
+ /* -b ==> for unformatted I/O, call do_unio (for noncharacter */
+ /* data of length > 1 byte) and do_ucio (for the rest) rather */
+ /* than do_uio. This permits modifying libI77 to byte-reverse */
+ /* numeric data. */
+
+ f2c_entry ("b", P_NO_ARGS, P_INT, &byterev, YES),
+
+ /* -ev ==> implement equivalence with initialized pointers */
+ f2c_entry ("ev", P_NO_ARGS, P_INT, &def_equivs, NO),
+
+ /* -!it used to be the default when -it was more agressive */
+
+ f2c_entry ("it", P_NO_ARGS, P_INT, &infertypes, 1),
+
+ /* -Pd is similar to -P, but omits :ref: lines */
+ f2c_entry ("Pd", P_NO_ARGS, P_INT, &Castargs, 2),
+
+ /* -t ==> emit typedefs (under -A or -C++) for procedure
+ argument types used. This is meant for netlib's
+ f2c service, so -A and -C++ will work with older
+ versions of f2c.h
+ */
+ f2c_entry ("t", P_NO_ARGS, P_INT, &typedefs, 1),
+
+ /* -!V ==> omit version msg (to facilitate using diff in
+ regression testing)
+ */
+ f2c_entry ("!V", P_NO_ARGS, P_INT, &skipversion, 1),
+
+ /* -Dnnn = debug level nnn */
+
+ f2c_entry ("D", P_ONE_ARG, P_INT, &debugflag, YES),
+
+ /* -dneg ==> under (default) -!R, imitate f77's bizarre */
+ /* treatment of unary minus of REAL expressions by */
+ /* promoting them to DOUBLE PRECISION . */
+
+ f2c_entry ("dneg", P_NO_ARGS, P_INT, &dneg, YES)
+}; /* table */
+
+extern char *c_functions; /* "c_functions" */
+extern char *coutput; /* "c_output" */
+extern char *initfname; /* "raw_data" */
+extern char *blkdfname; /* "block_data" */
+extern char *p1_file; /* "p1_file" */
+extern char *p1_bakfile; /* "p1_file.BAK" */
+extern char *sortfname; /* "init_file" */
+extern char *proto_fname; /* "proto_file" */
+FILE *protofile;
+
+ void
+set_externs(Void)
+{
+ static char *hset[3] = { 0, "integer", "doublereal" };
+
+/* Adjust the global flags according to the command line parameters */
+
+ if (chars_per_wd > 0) {
+ typesize[TYADDR] = typesize[TYLONG] = typesize[TYREAL] =
+ typesize[TYLOGICAL] = chars_per_wd;
+ typesize[TYINT1] = typesize[TYLOGICAL1] = 1;
+ typesize[TYDREAL] = typesize[TYCOMPLEX] = chars_per_wd << 1;
+ typesize[TYDCOMPLEX] = chars_per_wd << 2;
+ typesize[TYSHORT] = typesize[TYLOGICAL2] = chars_per_wd >> 1;
+ typesize[TYCILIST] = 5*chars_per_wd;
+ typesize[TYICILIST] = 6*chars_per_wd;
+ typesize[TYOLIST] = 9*chars_per_wd;
+ typesize[TYCLLIST] = 3*chars_per_wd;
+ typesize[TYALIST] = 2*chars_per_wd;
+ typesize[TYINLIST] = 26*chars_per_wd;
+ }
+
+ if (wordalign)
+ typealign[TYDREAL] = typealign[TYDCOMPLEX] = typealign[TYREAL];
+ if (!tyioint) {
+ tyioint = TYSHORT;
+ szleng = typesize[TYSHORT];
+ def_i2 = "#define f2c_i2 1\n";
+ inqmask = M(TYSHORT)|M(TYLOGICAL2);
+ goto checklong;
+ }
+ else
+ szleng = typesize[TYLONG];
+ if (useshortints) {
+ /* inqmask = M(TYLONG); */
+ /* used to disallow LOGICAL in INQUIRE under -I2 */
+ checklong:
+ protorettypes[TYLOGICAL] = "shortlogical";
+ casttypes[TYLOGICAL] = "K_fp";
+ if (uselongints)
+ err ("Can't use both long and short ints");
+ else {
+ tyint = tylogical = TYSHORT;
+ tylog = TYLOGICAL2;
+ }
+ }
+ else if (uselongints)
+ tyint = TYLONG;
+
+ if (h0align) {
+ if (tyint == TYLONG && wordalign)
+ h0align = 1;
+ ohalign = halign = hset[h0align];
+ htype = h0align == 1 ? tyint : TYDREAL;
+ hsize = typesize[htype];
+ }
+
+ if (no66flag)
+ noextflag = no66flag;
+ if (noextflag)
+ zflag = 0;
+
+ if (r8flag) {
+ tyreal = TYDREAL;
+ tycomplex = TYDCOMPLEX;
+ r8fix();
+ }
+ if (forcedouble) {
+ protorettypes[TYREAL] = "E_f";
+ casttypes[TYREAL] = "E_fp";
+ }
+ else
+ dneg = 0;
+
+ if (maxregvar > MAXREGVAR) {
+ warni("-O%d: too many register variables", maxregvar);
+ maxregvar = MAXREGVAR;
+ } /* if maxregvar > MAXREGVAR */
+
+/* Check the list of input files */
+
+ {
+ int bad, i, cur_max = Max_ftn_files;
+
+ for (i = bad = 0; i < cur_max && ftn_files[i]; i++)
+ if (ftn_files[i][0] == '-') {
+ errstr ("Invalid flag '%s'", ftn_files[i]);
+ bad++;
+ }
+ if (bad)
+ exit(1);
+
+ } /* block */
+} /* set_externs */
+
+
+ static int
+comm2dcl(Void)
+{
+ Extsym *ext;
+ if (ext1comm)
+ for(ext = extsymtab; ext < nextext; ext++)
+ if (ext->extstg == STGCOMMON && !ext->extinit)
+ return ext1comm;
+ return 0;
+ }
+
+ static void
+#ifdef KR_headers
+write_typedefs(outfile)
+ FILE *outfile;
+#else
+write_typedefs(FILE *outfile)
+#endif
+{
+ register int i;
+ register char *s, *p = 0;
+ static char st[4] = { TYREAL, TYCOMPLEX, TYDCOMPLEX, TYCHAR };
+ static char stl[4] = { 'E', 'C', 'Z', 'H' };
+
+ for(i = 0; i <= TYSUBR; i++)
+ if (s = usedcasts[i]) {
+ if (!p) {
+ p = Ansi == 1 ? "()" : "(...)";
+ nice_printf(outfile,
+ "/* Types for casting procedure arguments: */\
+\n\n#ifndef F2C_proc_par_types\n");
+ if (i == 0) {
+ nice_printf(outfile,
+ "typedef int /* Unknown procedure type */ (*%s)%s;\n",
+ s, p);
+ continue;
+ }
+ }
+ nice_printf(outfile, "typedef %s (*%s)%s;\n",
+ c_type_decl(i,1), s, p);
+ }
+ for(i = !forcedouble; i < 4; i++)
+ if (used_rets[st[i]])
+ nice_printf(outfile,
+ "typedef %s %c_f; /* %s function */\n",
+ p = i ? "VOID" : "doublereal",
+ stl[i], ftn_types[st[i]]);
+ if (p)
+ nice_printf(outfile, "#endif\n\n");
+ }
+
+ static void
+#ifdef KR_headers
+commonprotos(outfile)
+ register FILE *outfile;
+#else
+commonprotos(register FILE *outfile)
+#endif
+{
+ register Extsym *e, *ee;
+ register Argtypes *at;
+ Atype *a, *ae;
+ int k;
+ extern int proc_protochanges;
+
+ if (!outfile)
+ return;
+ for (e = extsymtab, ee = nextext; e < ee; e++)
+ if (e->extstg == STGCOMMON && e->allextp)
+ nice_printf(outfile, "/* comlen %s %ld */\n",
+ e->cextname, e->maxleng);
+ if (Castargs1 < 3)
+ return;
+
+ /* -Pr: special comments conveying current knowledge
+ of external references */
+
+ k = proc_protochanges;
+ for (e = extsymtab, ee = nextext; e < ee; e++)
+ if (e->extstg == STGEXT
+ && e->cextname != e->fextname) /* not a library function */
+ if (at = e->arginfo) {
+ if ((!e->extinit || at->changes & 1)
+ /* not defined here or
+ changed since definition */
+ && at->nargs >= 0) {
+ nice_printf(outfile, "/*:ref: %s %d %d",
+ e->cextname, e->extype, at->nargs);
+ a = at->atypes;
+ for(ae = a + at->nargs; a < ae; a++)
+ nice_printf(outfile, " %d", a->type);
+ nice_printf(outfile, " */\n");
+ if (at->changes & 1)
+ k++;
+ }
+ }
+ else if (e->extype)
+ /* typed external, never invoked */
+ nice_printf(outfile, "/*:ref: %s %d :*/\n",
+ e->cextname, e->extype);
+ if (k) {
+ nice_printf(outfile,
+ "/* Rerunning f2c -P may change prototypes or declarations. */\n");
+ if (nerr)
+ return;
+ if (protostatus)
+ done(4);
+ if (protofile != stdout) {
+ fprintf(diagfile,
+ "Rerunning \"f2c -P ... %s %s\" may change prototypes or declarations.\n",
+ filename0, proto_fname);
+ fflush(diagfile);
+ }
+ }
+ }
+
+ static int
+#ifdef KR_headers
+I_args(argc, a)
+ int argc;
+ char **a;
+#else
+I_args(int argc, char **a)
+#endif
+{
+ char **a0, **a1, **ae, *s;
+
+ ae = a + argc;
+ a0 = a;
+ for(a1 = ++a; a < ae; a++) {
+ if (!(s = *a))
+ break;
+ if (*s == '-' && s[1] == 'I' && s[2]
+ && (s[3] || s[2] != '2' && s[2] != '4'))
+ Iargs = mkchain(s+2, Iargs);
+ else
+ *a1++ = s;
+ }
+ Iargs = revchain(Iargs);
+ *a1 = 0;
+ return a1 - a0;
+ }
+
+ int retcode = 0;
+
+ int
+#ifdef KR_headers
+main(argc, argv)
+ int argc;
+ char **argv;
+#else
+main(int argc, char **argv)
+#endif
+{
+ int c2d, k;
+ FILE *c_output;
+ char *cdfilename;
+ static char stderrbuf[BUFSIZ];
+ extern char **dfltproc, *dflt1proc[];
+ extern char link_msg[];
+
+ diagfile = stderr;
+ setbuf(stderr, stderrbuf); /* arrange for fast error msgs */
+
+ argc = I_args(argc, argv); /* extract -I args */
+ Max_ftn_files = argc - 1;
+ ftn_files = (char **)ckalloc((argc+1)*sizeof(char *));
+
+ parse_args (argc, argv, table, sizeof(table)/sizeof(arg_info),
+ ftn_files, Max_ftn_files);
+ if (badargs)
+ return 1;
+ intr_omit = no_cd | no_i90;
+ if (keepsubs && checksubs) {
+ warn("-C suppresses -s\n");
+ keepsubs = 0;
+ }
+ if (!can_include && ext1comm == 2)
+ ext1comm = 1;
+ if (ext1comm && !extcomm)
+ extcomm = 2;
+ if (protostatus)
+ Castargs = 3;
+ Castargs1 = Castargs;
+ if (!Ansi) {
+ Castargs = 0;
+ parens = "()";
+ }
+ else if (!Castargs)
+ parens = Ansi == 1 ? "()" : "(...)";
+ else
+ dfltproc = dflt1proc;
+
+ outbuf_adjust();
+ set_externs();
+ fileinit();
+ read_Pfiles(ftn_files);
+
+ for(k = 1; ftn_files[k]; k++)
+ if (dofork())
+ break;
+ filename0 = file_name = ftn_files[current_ftn_file = k - 1];
+
+ set_tmp_names();
+ sigcatch(0);
+
+ c_file = opf(c_functions, textwrite);
+ pass1_file=opf(p1_file, binwrite);
+ initkey();
+ if (file_name && *file_name) {
+ if (debugflag != 1) {
+ if (!o_coutput)
+ coutput = c_name(file_name,'c');
+ else
+ coutput = o_coutput;
+ if (Castargs1 >= 2)
+ proto_fname = c_name(file_name,'P');
+ }
+ cdfilename = coutput;
+ if (skipC)
+ coutput = 0;
+ if (coutput[0] == '-'){
+ c_output = stdout;
+ coutput = 0;
+ }
+ else if (!(c_output = fopen(coutput, textwrite))) {
+ file_name = coutput;
+ coutput = 0; /* don't delete read-only .c file */
+ fatalstr("can't open %.86s", file_name);
+ }
+
+ if (Castargs1 >= 2
+ && !(protofile = fopen(proto_fname, textwrite)))
+ fatalstr("Can't open %.84s\n", proto_fname);
+ }
+ else {
+ file_name = "";
+ cdfilename = "f2c_out.c";
+ c_output = stdout;
+ coutput = 0;
+ if (Castargs1 >= 2) {
+ protofile = stdout;
+ if (!skipC)
+ printf("#ifdef P_R_O_T_O_T_Y_P_E_S\n");
+ }
+ }
+
+ if(inilex( copys(file_name) ))
+ done(1);
+ if (filename0) {
+ fprintf(diagfile, "%s:\n", file_name);
+ fflush(diagfile);
+ }
+
+ procinit();
+ if(k = yyparse())
+ {
+ fprintf(diagfile, "Bad parse, return code %d\n", k);
+ done(1);
+ }
+
+ commonprotos(protofile);
+ if (protofile == stdout && !skipC)
+ printf("#endif\n\n");
+
+ if (nerr || skipC)
+ goto C_skipped;
+
+
+/* Write out the declarations which are global to this file */
+
+ if ((c2d = comm2dcl()) == 1)
+ nice_printf(c_output, "/*>>>'/dev/null'<<<*/\n\n\
+/* Split this into several files by piping it through\n\n\
+sed \"s/^\\/\\*>>>'\\(.*\\)'<<<\\*\\/\\$/cat >'\\1' <<'\\/*<<<\\1>>>*\\/'/\" | /bin/sh\n\
+ */\n\
+/*<<</dev/null>>>*/\n\
+/*>>>'%s'<<<*/\n", cdfilename);
+ if (gflag)
+ nice_printf (c_output, "#line 1 \"%s\"\n", file_name);
+ if (!skipversion) {
+ nice_printf (c_output, "/* %s -- translated by f2c ", file_name);
+ nice_printf (c_output, "(version %s).\n", F2C_version);
+ nice_printf (c_output,
+ " You must link the resulting object file with the libraries:\n\
+ %s (in that order)\n*/\n\n", link_msg);
+ }
+ if (Ansi == 2)
+ nice_printf(c_output,
+ "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
+ nice_printf (c_output, "%s#include \"f2c.h\"\n\n", def_i2);
+ if (gflag)
+ nice_printf (c_output, "#line 1 \"%s\"\n", file_name);
+ if (Castargs && typedefs)
+ write_typedefs(c_output);
+ nice_printf (c_file, "\n");
+ fclose (c_file);
+ c_file = c_output; /* HACK to get the next indenting
+ to work */
+ wr_common_decls (c_output);
+ if (blkdfile)
+ list_init_data(&blkdfile, blkdfname, c_output);
+ wr_globals (c_output);
+ if ((c_file = fopen (c_functions, textread)) == (FILE *) NULL)
+ Fatal("main - couldn't reopen c_functions");
+ ffilecopy (c_file, c_output);
+ if (*main_alias) {
+ nice_printf (c_output, "/* Main program alias */ ");
+ nice_printf (c_output, "int %s () { MAIN__ ();%s }\n",
+ main_alias, Ansi ? " return 0;" : "");
+ }
+ if (Ansi == 2)
+ nice_printf(c_output,
+ "#ifdef __cplusplus\n\t}\n#endif\n");
+ if (c2d) {
+ if (c2d == 1)
+ fprintf(c_output, "/*<<<%s>>>*/\n", cdfilename);
+ else
+ fclose(c_output);
+ def_commons(c_output);
+ }
+ if (c2d != 2)
+ fclose (c_output);
+
+ C_skipped:
+ if(parstate != OUTSIDE)
+ {
+ warn("missing final end statement");
+ endproc();
+ nerr = 1;
+ }
+ done(nerr ? 1 : 0);
+ /* NOT REACHED */ return 0;
+}
+
+
+ FILEP
+#ifdef KR_headers
+opf(fn, mode)
+ char *fn;
+ char *mode;
+#else
+opf(char *fn, char *mode)
+#endif
+{
+ FILEP fp;
+ if( fp = fopen(fn, mode) )
+ return(fp);
+
+ fatalstr("cannot open intermediate file %s", fn);
+ /* NOT REACHED */ return 0;
+}
+
+
+ void
+#ifdef KR_headers
+clf(p, what, quit)
+ FILEP *p;
+ char *what;
+ int quit;
+#else
+clf(FILEP *p, char *what, int quit)
+#endif
+{
+ if(p!=NULL && *p!=NULL && *p!=stdout)
+ {
+ if(ferror(*p)) {
+ fprintf(stderr, "I/O error on %s\n", what);
+ if (quit)
+ done(3);
+ retcode = 3;
+ }
+ fclose(*p);
+ }
+ *p = NULL;
+}
+
+
+ void
+#ifdef KR_headers
+done(k)
+ int k;
+#else
+done(int k)
+#endif
+{
+ clf(&initfile, "initfile", 0);
+ clf(&c_file, "c_file", 0);
+ clf(&pass1_file, "pass1_file", 0);
+ Un_link_all(k);
+ exit(k|retcode);
+}
diff --git a/usr.bin/f2c/malloc.c b/usr.bin/f2c/malloc.c
new file mode 100644
index 0000000..3f5cb2a
--- /dev/null
+++ b/usr.bin/f2c/malloc.c
@@ -0,0 +1,165 @@
+/****************************************************************
+Copyright 1990, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#ifndef CRAY
+#define STACKMIN 512
+#define MINBLK (2*sizeof(struct mem) + 16)
+#define F _malloc_free_
+#define SBGULP 8192
+#include "string.h" /* for memcpy */
+
+#ifdef KR_headers
+#define Char char
+#define Unsigned unsigned
+#define Int /*int*/
+#else
+#define Char void
+#define Unsigned size_t
+#define Int int
+#endif
+
+typedef struct mem {
+ struct mem *next;
+ Unsigned len;
+ } mem;
+
+mem *F;
+
+ Char *
+#ifdef KR_headers
+malloc(size)
+ register Unsigned size;
+#else
+malloc(register Unsigned size)
+#endif
+{
+ register mem *p, *q, *r, *s;
+ unsigned register k, m;
+ extern Char *sbrk(Int);
+ char *top, *top1;
+
+ size = (size+7) & ~7;
+ r = (mem *) &F;
+ for (p = F, q = 0; p; r = p, p = p->next) {
+ if ((k = p->len) >= size && (!q || m > k)) {
+ m = k;
+ q = p;
+ s = r;
+ }
+ }
+ if (q) {
+ if (q->len - size >= MINBLK) { /* split block */
+ p = (mem *) (((char *) (q+1)) + size);
+ p->next = q->next;
+ p->len = q->len - size - sizeof(mem);
+ s->next = p;
+ q->len = size;
+ }
+ else
+ s->next = q->next;
+ }
+ else {
+ top = (Char *)(((long)sbrk(0) + 7) & ~7);
+ if (F && (char *)(F+1) + F->len == top) {
+ q = F;
+ F = F->next;
+ }
+ else
+ q = (mem *) top;
+ top1 = (char *)(q+1) + size;
+ if (sbrk((int)(top1-top+SBGULP)) == (Char *) -1)
+ return 0;
+ r = (mem *)top1;
+ r->len = SBGULP - sizeof(mem);
+ r->next = F;
+ F = r;
+ q->len = size;
+ }
+ return (Char *) (q+1);
+ }
+
+ void
+#ifdef KR_headers
+free(f)
+ Char *f;
+#else
+free(Char *f)
+#endif
+{
+ mem *p, *q, *r;
+ char *pn, *qn;
+
+ if (!f) return;
+ q = (mem *) ((char *)f - sizeof(mem));
+ qn = (char *)f + q->len;
+ for (p = F, r = (mem *) &F; ; r = p, p = p->next) {
+ if (qn == (Char *) p) {
+ q->len += p->len + sizeof(mem);
+ p = p->next;
+ }
+ pn = p ? ((char *) (p+1)) + p->len : 0;
+ if (pn == (Char *) q) {
+ p->len += sizeof(mem) + q->len;
+ q->len = 0;
+ q->next = p;
+ r->next = p;
+ break;
+ }
+ if (pn < (char *) q) {
+ r->next = q;
+ q->next = p;
+ break;
+ }
+ }
+ }
+
+ Char *
+#ifdef KR_headers
+realloc(f, size)
+ Char *f;
+ Unsigned size;
+#else
+realloc(Char *f, Unsigned size)
+#endif
+{
+ mem *p;
+ Char *q, *f1;
+ Unsigned s1;
+
+ if (!f) return malloc(size);
+ p = (mem *) ((char *)f - sizeof(mem));
+ s1 = p->len;
+ free(f);
+ if (s1 > size)
+ s1 = size + 7 & ~7;
+ if (!p->len) {
+ f1 = (Char *)(p->next + 1);
+ memcpy(f1, f, s1);
+ f = f1;
+ }
+ q = malloc(size);
+ if (q && q != f)
+ memcpy(q, f, s1);
+ return q;
+ }
+#endif
diff --git a/usr.bin/f2c/mem.c b/usr.bin/f2c/mem.c
new file mode 100644
index 0000000..4e3d777
--- /dev/null
+++ b/usr.bin/f2c/mem.c
@@ -0,0 +1,268 @@
+/****************************************************************
+Copyright 1990, 1991, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "iob.h"
+
+#define MEMBSIZE 32000
+#define GMEMBSIZE 16000
+
+ char *
+#ifdef KR_headers
+gmem(n, round)
+ int n;
+ int round;
+#else
+gmem(int n, int round)
+#endif
+{
+ static char *last, *next;
+ char *rv;
+ if (round)
+#ifdef CRAY
+ if ((long)next & 0xe000000000000000)
+ next = (char *)(((long)next & 0x1fffffffffffffff) + 1);
+#else
+#ifdef MSDOS
+ if ((int)next & 1)
+ next++;
+#else
+ next = (char *)(((long)next + sizeof(char *)-1)
+ & ~((long)sizeof(char *)-1));
+#endif
+#endif
+ rv = next;
+ if ((next += n) > last) {
+ rv = Alloc(n + GMEMBSIZE);
+
+ next = rv + n;
+ last = next + GMEMBSIZE;
+ }
+ return rv;
+ }
+
+ struct memblock {
+ struct memblock *next;
+ char buf[MEMBSIZE];
+ };
+ typedef struct memblock memblock;
+
+ static memblock *mem0;
+ memblock *curmemblock, *firstmemblock;
+
+ char *mem_first, *mem_next, *mem_last, *mem0_last;
+
+ void
+mem_init(Void)
+{
+ curmemblock = firstmemblock = mem0
+ = (memblock *)Alloc(sizeof(memblock));
+ mem_first = mem0->buf;
+ mem_next = mem0->buf;
+ mem_last = mem0->buf + MEMBSIZE;
+ mem0_last = mem0->buf + MEMBSIZE;
+ mem0->next = 0;
+ }
+
+ char *
+#ifdef KR_headers
+mem(n, round)
+ int n;
+ int round;
+#else
+mem(int n, int round)
+#endif
+{
+ memblock *b;
+ register char *rv, *s;
+
+ if (round)
+#ifdef CRAY
+ if ((long)mem_next & 0xe000000000000000)
+ mem_next = (char *)(((long)mem_next & 0x1fffffffffffffff) + 1);
+#else
+#ifdef MSDOS
+ if ((int)mem_next & 1)
+ mem_next++;
+#else
+ mem_next = (char *)(((long)mem_next + sizeof(char *)-1)
+ & ~((long)sizeof(char *)-1));
+#endif
+#endif
+ rv = mem_next;
+ s = rv + n;
+ if (s >= mem_last) {
+ if (n > MEMBSIZE) {
+ fprintf(stderr, "mem(%d) failure!\n", n);
+ exit(1);
+ }
+ if (!(b = curmemblock->next)) {
+ b = (memblock *)Alloc(sizeof(memblock));
+ curmemblock->next = b;
+ b->next = 0;
+ }
+ curmemblock = b;
+ rv = b->buf;
+ mem_last = rv + sizeof(b->buf);
+ s = rv + n;
+ }
+ mem_next = s;
+ return rv;
+ }
+
+ char *
+#ifdef KR_headers
+tostring(s, n)
+ register char *s;
+ int n;
+#else
+tostring(register char *s, int n)
+#endif
+{
+ register char *s1, *se, **sf;
+ char *rv, *s0;
+ register int k = n + 2, t;
+
+ sf = str_fmt;
+ sf['%'] = "%";
+ s0 = s;
+ se = s + n;
+ for(; s < se; s++) {
+ t = *(unsigned char *)s;
+ s1 = sf[t];
+ while(*++s1)
+ k++;
+ }
+ sf['%'] = "%%";
+ rv = s1 = mem(k,0);
+ *s1++ = '"';
+ for(s = s0; s < se; s++) {
+ t = *(unsigned char *)s;
+ sprintf(s1, sf[t], t);
+ s1 += strlen(s1);
+ }
+ *s1 = 0;
+ return rv;
+ }
+
+ char *
+#ifdef KR_headers
+cpstring(s)
+ register char *s;
+#else
+cpstring(register char *s)
+#endif
+{
+ return strcpy(mem(strlen(s)+1,0), s);
+ }
+
+ void
+#ifdef KR_headers
+new_iob_data(ios, name)
+ register io_setup *ios;
+ char *name;
+#else
+new_iob_data(register io_setup *ios, char *name)
+#endif
+{
+ register iob_data *iod;
+ register char **s, **se;
+
+ iod = (iob_data *)
+ mem(sizeof(iob_data) + ios->nelt*sizeof(char *), 1);
+ iod->next = iob_list;
+ iob_list = iod;
+ iod->type = ios->fields[0];
+ iod->name = cpstring(name);
+ s = iod->fields;
+ se = s + ios->nelt;
+ while(s < se)
+ *s++ = "0";
+ *s = 0;
+ }
+
+ char *
+#ifdef KR_headers
+string_num(pfx, n)
+ char *pfx;
+ long n;
+#else
+string_num(char *pfx, long n)
+#endif
+{
+ char buf[32];
+ sprintf(buf, "%s%ld", pfx, n);
+ /* can't trust return type of sprintf -- BSD gets it wrong */
+ return strcpy(mem(strlen(buf)+1,0), buf);
+ }
+
+static defines *define_list;
+
+ void
+#ifdef KR_headers
+def_start(outfile, s1, s2, post)
+ FILE *outfile;
+ char *s1;
+ char *s2;
+ char *post;
+#else
+def_start(FILE *outfile, char *s1, char *s2, char *post)
+#endif
+{
+ defines *d;
+ int n, n1;
+ extern int in_define;
+
+ n = n1 = strlen(s1);
+ if (s2)
+ n += strlen(s2);
+ d = (defines *)mem(sizeof(defines)+n, 1);
+ d->next = define_list;
+ define_list = d;
+ strcpy(d->defname, s1);
+ if (s2)
+ strcpy(d->defname + n1, s2);
+ in_define = 1;
+ nice_printf(outfile, "#define %s", d->defname);
+ if (post)
+ nice_printf(outfile, " %s", post);
+ }
+
+ void
+#ifdef KR_headers
+other_undefs(outfile)
+ FILE *outfile;
+#else
+other_undefs(FILE *outfile)
+#endif
+{
+ defines *d;
+ if (d = define_list) {
+ define_list = 0;
+ nice_printf(outfile, "\n");
+ do
+ nice_printf(outfile, "#undef %s\n", d->defname);
+ while(d = d->next);
+ nice_printf(outfile, "\n");
+ }
+ }
diff --git a/usr.bin/f2c/memset.c b/usr.bin/f2c/memset.c
new file mode 100644
index 0000000..4d6ab47
--- /dev/null
+++ b/usr.bin/f2c/memset.c
@@ -0,0 +1,66 @@
+/****************************************************************
+Copyright 1990 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* This is for the benefit of people whose systems don't provide
+ * memset, memcpy, and memcmp. If yours is such a system, adjust
+ * the makefile by adding memset.o to the "OBJECTS =" assignment.
+ * WARNING: the memcpy below is adequate for f2c, but is not a
+ * general memcpy routine (which must correctly handle overlapping
+ * fields).
+ */
+
+ int
+memcmp(s1, s2, n)
+ register char *s1, *s2;
+ int n;
+{
+ register char *se;
+
+ for(se = s1 + n; s1 < se; s1++, s2++)
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ return 0;
+ }
+
+ char *
+memcpy(s1, s2, n)
+ register char *s1, *s2;
+ int n;
+{
+ register char *s0 = s1, *se = s1 + n;
+
+ while(s1 < se)
+ *s1++ = *s2++;
+ return s0;
+ }
+
+memset(s, c, n)
+ register char *s;
+ register int c;
+ int n;
+{
+ register char *se = s + n;
+
+ while(s < se)
+ *s++ = c;
+ }
diff --git a/usr.bin/f2c/misc.c b/usr.bin/f2c/misc.c
new file mode 100644
index 0000000..f5cca53
--- /dev/null
+++ b/usr.bin/f2c/misc.c
@@ -0,0 +1,1329 @@
+/****************************************************************
+Copyright 1990, 1992 - 1995 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "limits.h"
+
+ int
+#ifdef KR_headers
+oneof_stg(name, stg, mask)
+ Namep name;
+ int stg;
+ int mask;
+#else
+oneof_stg(Namep name, int stg, int mask)
+#endif
+{
+ if (stg == STGCOMMON && name) {
+ if ((mask & M(STGEQUIV)))
+ return name->vcommequiv;
+ if ((mask & M(STGCOMMON)))
+ return !name->vcommequiv;
+ }
+ return ONEOF(stg, mask);
+ }
+
+
+/* op_assign -- given a binary opcode, return the associated assignment
+ operator */
+
+ int
+#ifdef KR_headers
+op_assign(opcode)
+ int opcode;
+#else
+op_assign(int opcode)
+#endif
+{
+ int retval = -1;
+
+ switch (opcode) {
+ case OPPLUS: retval = OPPLUSEQ; break;
+ case OPMINUS: retval = OPMINUSEQ; break;
+ case OPSTAR: retval = OPSTAREQ; break;
+ case OPSLASH: retval = OPSLASHEQ; break;
+ case OPMOD: retval = OPMODEQ; break;
+ case OPLSHIFT: retval = OPLSHIFTEQ; break;
+ case OPRSHIFT: retval = OPRSHIFTEQ; break;
+ case OPBITAND: retval = OPBITANDEQ; break;
+ case OPBITXOR: retval = OPBITXOREQ; break;
+ case OPBITOR: retval = OPBITOREQ; break;
+ default:
+ erri ("op_assign: bad opcode '%d'", opcode);
+ break;
+ } /* switch */
+
+ return retval;
+} /* op_assign */
+
+
+ char *
+#ifdef KR_headers
+Alloc(n)
+ int n;
+#else
+Alloc(int n)
+#endif
+ /* error-checking version of malloc */
+ /* ckalloc initializes memory to 0; Alloc does not */
+{
+ char errbuf[32];
+ register char *rv;
+
+ rv = malloc(n);
+ if (!rv) {
+ sprintf(errbuf, "malloc(%d) failure!", n);
+ Fatal(errbuf);
+ }
+ return rv;
+ }
+
+ void
+#ifdef KR_headers
+cpn(n, a, b)
+ register int n;
+ register char *a;
+ register char *b;
+#else
+cpn(register int n, register char *a, register char *b)
+#endif
+{
+ while(--n >= 0)
+ *b++ = *a++;
+}
+
+
+ int
+#ifdef KR_headers
+eqn(n, a, b)
+ register int n;
+ register char *a;
+ register char *b;
+#else
+eqn(register int n, register char *a, register char *b)
+#endif
+{
+ while(--n >= 0)
+ if(*a++ != *b++)
+ return(NO);
+ return(YES);
+}
+
+
+
+
+
+
+ int
+#ifdef KR_headers
+cmpstr(a, b, la, lb)
+ register char *a;
+ register char *b;
+ ftnint la;
+ ftnint lb;
+#else
+cmpstr(register char *a, register char *b, ftnint la, ftnint lb)
+#endif
+ /* compare two strings */
+{
+ register char *aend, *bend;
+ aend = a + la;
+ bend = b + lb;
+
+
+ if(la <= lb)
+ {
+ while(a < aend)
+ if(*a != *b)
+ return( *a - *b );
+ else
+ {
+ ++a;
+ ++b;
+ }
+
+ while(b < bend)
+ if(*b != ' ')
+ return(' ' - *b);
+ else
+ ++b;
+ }
+
+ else
+ {
+ while(b < bend)
+ if(*a != *b)
+ return( *a - *b );
+ else
+ {
+ ++a;
+ ++b;
+ }
+ while(a < aend)
+ if(*a != ' ')
+ return(*a - ' ');
+ else
+ ++a;
+ }
+ return(0);
+}
+
+
+/* hookup -- Same as LISP NCONC, that is a destructive append of two lists */
+
+ chainp
+#ifdef KR_headers
+hookup(x, y)
+ register chainp x;
+ register chainp y;
+#else
+hookup(register chainp x, register chainp y)
+#endif
+{
+ register chainp p;
+
+ if(x == NULL)
+ return(y);
+
+ for(p = x ; p->nextp ; p = p->nextp)
+ ;
+ p->nextp = y;
+ return(x);
+}
+
+
+
+ struct Listblock *
+#ifdef KR_headers
+mklist(p)
+ chainp p;
+#else
+mklist(chainp p)
+#endif
+{
+ register struct Listblock *q;
+
+ q = ALLOC(Listblock);
+ q->tag = TLIST;
+ q->listp = p;
+ return(q);
+}
+
+
+ chainp
+#ifdef KR_headers
+mkchain(p, q)
+ register char * p;
+ register chainp q;
+#else
+mkchain(register char * p, register chainp q)
+#endif
+{
+ register chainp r;
+
+ if(chains)
+ {
+ r = chains;
+ chains = chains->nextp;
+ }
+ else
+ r = ALLOC(Chain);
+
+ r->datap = p;
+ r->nextp = q;
+ return(r);
+}
+
+ chainp
+#ifdef KR_headers
+revchain(next)
+ register chainp next;
+#else
+revchain(register chainp next)
+#endif
+{
+ register chainp p, prev = 0;
+
+ while(p = next) {
+ next = p->nextp;
+ p->nextp = prev;
+ prev = p;
+ }
+ return prev;
+ }
+
+
+/* addunder -- turn a cvarname into an external name */
+/* The cvarname may already end in _ (to avoid C keywords); */
+/* if not, it has room for appending an _. */
+
+ char *
+#ifdef KR_headers
+addunder(s)
+ register char *s;
+#else
+addunder(register char *s)
+#endif
+{
+ register int c, i, j;
+ char *s0 = s;
+
+ i = j = 0;
+ while(c = *s++)
+ if (c == '_')
+ i++, j++;
+ else
+ i = 0;
+ if (!i) {
+ *s-- = 0;
+ *s = '_';
+ }
+ else if (j == 2)
+ s[-2] = 0;
+ return( s0 );
+ }
+
+
+/* copyn -- return a new copy of the input Fortran-string */
+
+ char *
+#ifdef KR_headers
+copyn(n, s)
+ register int n;
+ register char *s;
+#else
+copyn(register int n, register char *s)
+#endif
+{
+ register char *p, *q;
+
+ p = q = (char *) Alloc(n);
+ while(--n >= 0)
+ *q++ = *s++;
+ return(p);
+}
+
+
+
+/* copys -- return a new copy of the input C-string */
+
+ char *
+#ifdef KR_headers
+copys(s)
+ char *s;
+#else
+copys(char *s)
+#endif
+{
+ return( copyn( strlen(s)+1 , s) );
+}
+
+
+
+/* convci -- Convert Fortran-string to integer; assumes that input is a
+ legal number, with no trailing blanks */
+
+ ftnint
+#ifdef KR_headers
+convci(n, s)
+ register int n;
+ register char *s;
+#else
+convci(register int n, register char *s)
+#endif
+{
+ ftnint sum, t;
+ char buff[100], *s0;
+ int n0;
+
+ s0 = s;
+ n0 = n;
+ sum = 0;
+ while(n-- > 0) {
+ /* sum = 10*sum + (*s++ - '0'); */
+ t = *s++ - '0';
+ if (sum > LONG_MAX/10) {
+ ovfl:
+ if (n0 > 60)
+ n0 = 60;
+ sprintf(buff, "integer constant %.*s truncated.",
+ n0, s0);
+ err(buff);
+ return LONG_MAX;
+ }
+ sum *= 10;
+ if (sum > LONG_MAX - t)
+ goto ovfl;
+ sum += t;
+ }
+ return(sum);
+ }
+
+/* convic - Convert Integer constant to string */
+
+ char *
+#ifdef KR_headers
+convic(n)
+ ftnint n;
+#else
+convic(ftnint n)
+#endif
+{
+ static char s[20];
+ register char *t;
+
+ s[19] = '\0';
+ t = s+19;
+
+ do {
+ *--t = '0' + n%10;
+ n /= 10;
+ } while(n > 0);
+
+ return(t);
+}
+
+
+
+/* mkname -- add a new identifier to the environment, including the closed
+ hash table. */
+
+ Namep
+#ifdef KR_headers
+mkname(s)
+ register char *s;
+#else
+mkname(register char *s)
+#endif
+{
+ struct Hashentry *hp;
+ register Namep q;
+ register int c, hash, i;
+ register char *t;
+ char *s0;
+ char errbuf[64];
+
+ hash = i = 0;
+ s0 = s;
+ while(c = *s++) {
+ hash += c;
+ if (c == '_')
+ i = 2;
+ }
+ if (!i && in_vector(s0,c_keywords,n_keywords) >= 0)
+ i = 2;
+ hash %= maxhash;
+
+/* Add the name to the closed hash table */
+
+ hp = hashtab + hash;
+
+ while(q = hp->varp)
+ if( hash == hp->hashval && !strcmp(s0,q->fvarname) )
+ return(q);
+ else if(++hp >= lasthash)
+ hp = hashtab;
+
+ if(++nintnames >= maxhash-1)
+ many("names", 'n', maxhash); /* Fatal error */
+ hp->varp = q = ALLOC(Nameblock);
+ hp->hashval = hash;
+ q->tag = TNAME; /* TNAME means the tag type is NAME */
+ c = s - s0;
+ if (c > 7 && noextflag) {
+ sprintf(errbuf, "\"%.35s%s\" over 6 characters long", s0,
+ c > 36 ? "..." : "");
+ errext(errbuf);
+ }
+ q->fvarname = strcpy(mem(c,0), s0);
+ t = q->cvarname = mem(c + i + 1, 0);
+ s = s0;
+ /* add __ to the end of any name containing _ and to any C keyword */
+ while(*t = *s++)
+ t++;
+ if (i) {
+ do *t++ = '_';
+ while(--i > 0);
+ *t = 0;
+ }
+ return(q);
+}
+
+
+ struct Labelblock *
+#ifdef KR_headers
+mklabel(l)
+ ftnint l;
+#else
+mklabel(ftnint l)
+#endif
+{
+ register struct Labelblock *lp;
+
+ if(l <= 0)
+ return(NULL);
+
+ for(lp = labeltab ; lp < highlabtab ; ++lp)
+ if(lp->stateno == l)
+ return(lp);
+
+ if(++highlabtab > labtabend)
+ many("statement labels", 's', maxstno);
+
+ lp->stateno = l;
+ lp->labelno = (int)newlabel();
+ lp->blklevel = 0;
+ lp->labused = NO;
+ lp->fmtlabused = NO;
+ lp->labdefined = NO;
+ lp->labinacc = NO;
+ lp->labtype = LABUNKNOWN;
+ lp->fmtstring = 0;
+ return(lp);
+}
+
+ long
+newlabel(Void)
+{
+ return ++lastlabno;
+}
+
+
+/* this label appears in a branch context */
+
+ struct Labelblock *
+#ifdef KR_headers
+execlab(stateno)
+ ftnint stateno;
+#else
+execlab(ftnint stateno)
+#endif
+{
+ register struct Labelblock *lp;
+
+ if(lp = mklabel(stateno))
+ {
+ if(lp->labinacc)
+ warn1("illegal branch to inner block, statement label %s",
+ convic(stateno) );
+ else if(lp->labdefined == NO)
+ lp->blklevel = blklevel;
+ if(lp->labtype == LABFORMAT)
+ err("may not branch to a format");
+ else
+ lp->labtype = LABEXEC;
+ }
+ else
+ execerr("illegal label %s", convic(stateno));
+
+ return(lp);
+}
+
+
+/* find or put a name in the external symbol table */
+
+ Extsym *
+#ifdef KR_headers
+mkext1(f, s)
+ char *f;
+ char *s;
+#else
+mkext1(char *f, char *s)
+#endif
+{
+ Extsym *p;
+
+ for(p = extsymtab ; p<nextext ; ++p)
+ if(!strcmp(s,p->cextname))
+ return( p );
+
+ if(nextext >= lastext)
+ many("external symbols", 'x', maxext);
+
+ nextext->fextname = strcpy(gmem(strlen(f)+1,0), f);
+ nextext->cextname = f == s
+ ? nextext->fextname
+ : strcpy(gmem(strlen(s)+1,0), s);
+ nextext->extstg = STGUNKNOWN;
+ nextext->extp = 0;
+ nextext->allextp = 0;
+ nextext->extleng = 0;
+ nextext->maxleng = 0;
+ nextext->extinit = 0;
+ nextext->curno = nextext->maxno = 0;
+ return( nextext++ );
+}
+
+
+ Extsym *
+#ifdef KR_headers
+mkext(f, s)
+ char *f;
+ char *s;
+#else
+mkext(char *f, char *s)
+#endif
+{
+ Extsym *e = mkext1(f, s);
+ if (e->extstg == STGCOMMON)
+ errstr("%.52s cannot be a subprogram: it is a common block.",f);
+ return e;
+ }
+
+ Addrp
+#ifdef KR_headers
+builtin(t, s, dbi)
+ int t;
+ char *s;
+ int dbi;
+#else
+builtin(int t, char *s, int dbi)
+#endif
+{
+ register Extsym *p;
+ register Addrp q;
+ extern chainp used_builtins;
+
+ p = mkext(s,s);
+ if(p->extstg == STGUNKNOWN)
+ p->extstg = STGEXT;
+ else if(p->extstg != STGEXT)
+ {
+ errstr("improper use of builtin %s", s);
+ return(0);
+ }
+
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ q->vtype = t;
+ q->vclass = CLPROC;
+ q->vstg = STGEXT;
+ q->memno = p - extsymtab;
+ q->dbl_builtin = dbi;
+
+/* A NULL pointer here tells you to use memno to check the external
+ symbol table */
+
+ q -> uname_tag = UNAM_EXTERN;
+
+/* Add to the list of used builtins */
+
+ if (dbi >= 0)
+ add_extern_to_list (q, &used_builtins);
+ return(q);
+}
+
+
+ void
+#ifdef KR_headers
+add_extern_to_list(addr, list_store)
+ Addrp addr;
+ chainp *list_store;
+#else
+add_extern_to_list(Addrp addr, chainp *list_store)
+#endif
+{
+ chainp last = CHNULL;
+ chainp list;
+ int memno;
+
+ if (list_store == (chainp *) NULL || addr == (Addrp) NULL)
+ return;
+
+ list = *list_store;
+ memno = addr -> memno;
+
+ for (;list; last = list, list = list -> nextp) {
+ Addrp this = (Addrp) (list -> datap);
+
+ if (this -> tag == TADDR && this -> uname_tag == UNAM_EXTERN &&
+ this -> memno == memno)
+ return;
+ } /* for */
+
+ if (*list_store == CHNULL)
+ *list_store = mkchain((char *)cpexpr((expptr)addr), CHNULL);
+ else
+ last->nextp = mkchain((char *)cpexpr((expptr)addr), CHNULL);
+
+} /* add_extern_to_list */
+
+
+ void
+#ifdef KR_headers
+frchain(p)
+ register chainp *p;
+#else
+frchain(register chainp *p)
+#endif
+{
+ register chainp q;
+
+ if(p==0 || *p==0)
+ return;
+
+ for(q = *p; q->nextp ; q = q->nextp)
+ ;
+ q->nextp = chains;
+ chains = *p;
+ *p = 0;
+}
+
+ void
+#ifdef KR_headers
+frexchain(p)
+ register chainp *p;
+#else
+frexchain(register chainp *p)
+#endif
+{
+ register chainp q, r;
+
+ if (q = *p) {
+ for(;;q = r) {
+ frexpr((expptr)q->datap);
+ if (!(r = q->nextp))
+ break;
+ }
+ q->nextp = chains;
+ chains = *p;
+ *p = 0;
+ }
+ }
+
+
+ tagptr
+#ifdef KR_headers
+cpblock(n, p)
+ register int n;
+ register char *p;
+#else
+cpblock(register int n, register char *p)
+#endif
+{
+ register ptr q;
+
+ memcpy((char *)(q = ckalloc(n)), (char *)p, n);
+ return( (tagptr) q);
+}
+
+
+
+ ftnint
+#ifdef KR_headers
+lmax(a, b)
+ ftnint a;
+ ftnint b;
+#else
+lmax(ftnint a, ftnint b)
+#endif
+{
+ return( a>b ? a : b);
+}
+
+ ftnint
+#ifdef KR_headers
+lmin(a, b)
+ ftnint a;
+ ftnint b;
+#else
+lmin(ftnint a, ftnint b)
+#endif
+{
+ return(a < b ? a : b);
+}
+
+
+
+
+#ifdef KR_headers
+maxtype(t1, t2)
+ int t1;
+ int t2;
+#else
+maxtype(int t1, int t2)
+#endif
+{
+ int t;
+
+ t = t1 >= t2 ? t1 : t2;
+ if(t==TYCOMPLEX && (t1==TYDREAL || t2==TYDREAL) )
+ t = TYDCOMPLEX;
+ return(t);
+}
+
+
+
+/* return log base 2 of n if n a power of 2; otherwise -1 */
+ int
+#ifdef KR_headers
+log_2(n)
+ ftnint n;
+#else
+log_2(ftnint n)
+#endif
+{
+ int k;
+
+ /* trick based on binary representation */
+
+ if(n<=0 || (n & (n-1))!=0)
+ return(-1);
+
+ for(k = 0 ; n >>= 1 ; ++k)
+ ;
+ return(k);
+}
+
+
+ void
+frrpl(Void)
+{
+ struct Rplblock *rp;
+
+ while(rpllist)
+ {
+ rp = rpllist->rplnextp;
+ free( (charptr) rpllist);
+ rpllist = rp;
+ }
+}
+
+
+
+/* Call a Fortran function with an arbitrary list of arguments */
+
+int callk_kludge;
+
+ expptr
+#ifdef KR_headers
+callk(type, name, args)
+ int type;
+ char *name;
+ chainp args;
+#else
+callk(int type, char *name, chainp args)
+#endif
+{
+ register expptr p;
+
+ p = mkexpr(OPCALL,
+ (expptr)builtin(callk_kludge ? callk_kludge : type, name, 0),
+ (expptr)args);
+ p->exprblock.vtype = type;
+ return(p);
+}
+
+
+
+ expptr
+#ifdef KR_headers
+call4(type, name, arg1, arg2, arg3, arg4)
+ int type;
+ char *name;
+ expptr arg1;
+ expptr arg2;
+ expptr arg3;
+ expptr arg4;
+#else
+call4(int type, char *name, expptr arg1, expptr arg2, expptr arg3, expptr arg4)
+#endif
+{
+ struct Listblock *args;
+ args = mklist( mkchain((char *)arg1,
+ mkchain((char *)arg2,
+ mkchain((char *)arg3,
+ mkchain((char *)arg4, CHNULL)) ) ) );
+ return( callk(type, name, (chainp)args) );
+}
+
+
+
+
+ expptr
+#ifdef KR_headers
+call3(type, name, arg1, arg2, arg3)
+ int type;
+ char *name;
+ expptr arg1;
+ expptr arg2;
+ expptr arg3;
+#else
+call3(int type, char *name, expptr arg1, expptr arg2, expptr arg3)
+#endif
+{
+ struct Listblock *args;
+ args = mklist( mkchain((char *)arg1,
+ mkchain((char *)arg2,
+ mkchain((char *)arg3, CHNULL) ) ) );
+ return( callk(type, name, (chainp)args) );
+}
+
+
+
+
+
+ expptr
+#ifdef KR_headers
+call2(type, name, arg1, arg2)
+ int type;
+ char *name;
+ expptr arg1;
+ expptr arg2;
+#else
+call2(int type, char *name, expptr arg1, expptr arg2)
+#endif
+{
+ struct Listblock *args;
+
+ args = mklist( mkchain((char *)arg1, mkchain((char *)arg2, CHNULL) ) );
+ return( callk(type,name, (chainp)args) );
+}
+
+
+
+
+ expptr
+#ifdef KR_headers
+call1(type, name, arg)
+ int type;
+ char *name;
+ expptr arg;
+#else
+call1(int type, char *name, expptr arg)
+#endif
+{
+ return( callk(type,name, (chainp)mklist(mkchain((char *)arg,CHNULL)) ));
+}
+
+
+ expptr
+#ifdef KR_headers
+call0(type, name)
+ int type;
+ char *name;
+#else
+call0(int type, char *name)
+#endif
+{
+ return( callk(type, name, CHNULL) );
+}
+
+
+
+ struct Impldoblock *
+#ifdef KR_headers
+mkiodo(dospec, list)
+ chainp dospec;
+ chainp list;
+#else
+mkiodo(chainp dospec, chainp list)
+#endif
+{
+ register struct Impldoblock *q;
+
+ q = ALLOC(Impldoblock);
+ q->tag = TIMPLDO;
+ q->impdospec = dospec;
+ q->datalist = list;
+ return(q);
+}
+
+
+
+
+/* ckalloc -- Allocate 1 memory unit of size n, checking for out of
+ memory error */
+
+ ptr
+#ifdef KR_headers
+ckalloc(n)
+ register int n;
+#else
+ckalloc(register int n)
+#endif
+{
+ register ptr p;
+ p = (ptr)calloc(1, (unsigned) n);
+ if (p || !n)
+ return(p);
+ fprintf(stderr, "failing to get %d bytes\n",n);
+ Fatal("out of memory");
+ /* NOT REACHED */ return 0;
+}
+
+
+ int
+#ifdef KR_headers
+isaddr(p)
+ register expptr p;
+#else
+isaddr(register expptr p)
+#endif
+{
+ if(p->tag == TADDR)
+ return(YES);
+ if(p->tag == TEXPR)
+ switch(p->exprblock.opcode)
+ {
+ case OPCOMMA:
+ return( isaddr(p->exprblock.rightp) );
+
+ case OPASSIGN:
+ case OPASSIGNI:
+ case OPPLUSEQ:
+ case OPMINUSEQ:
+ case OPSLASHEQ:
+ case OPMODEQ:
+ case OPLSHIFTEQ:
+ case OPRSHIFTEQ:
+ case OPBITANDEQ:
+ case OPBITXOREQ:
+ case OPBITOREQ:
+ return( isaddr(p->exprblock.leftp) );
+ }
+ return(NO);
+}
+
+
+
+ int
+#ifdef KR_headers
+isstatic(p)
+ register expptr p;
+#else
+isstatic(register expptr p)
+#endif
+{
+ extern int useauto;
+ if(p->headblock.vleng && !ISCONST(p->headblock.vleng))
+ return(NO);
+
+ switch(p->tag)
+ {
+ case TCONST:
+ return(YES);
+
+ case TADDR:
+ if(ONEOF(p->addrblock.vstg,MSKSTATIC) &&
+ ISCONST(p->addrblock.memoffset) && !useauto)
+ return(YES);
+
+ default:
+ return(NO);
+ }
+}
+
+
+
+/* addressable -- return True iff it is a constant value, or can be
+ referenced by constant values */
+
+ int
+#ifdef KR_headers
+addressable(p)
+ register expptr p;
+#else
+addressable(register expptr p)
+#endif
+{
+ switch(p->tag)
+ {
+ case TCONST:
+ return(YES);
+
+ case TADDR:
+ return( addressable(p->addrblock.memoffset) );
+
+ default:
+ return(NO);
+ }
+}
+
+
+/* isnegative_const -- returns true if the constant is negative. Returns
+ false for imaginary and nonnumeric constants */
+
+ int
+#ifdef KR_headers
+isnegative_const(cp)
+ struct Constblock *cp;
+#else
+isnegative_const(struct Constblock *cp)
+#endif
+{
+ int retval;
+
+ if (cp == NULL)
+ return 0;
+
+ switch (cp -> vtype) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ retval = cp -> Const.ci < 0;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ retval = cp->vstg ? *cp->Const.cds[0] == '-'
+ : cp->Const.cd[0] < 0.0;
+ break;
+ default:
+
+ retval = 0;
+ break;
+ } /* switch */
+
+ return retval;
+} /* isnegative_const */
+
+ void
+#ifdef KR_headers
+negate_const(cp)
+ Constp cp;
+#else
+negate_const(Constp cp)
+#endif
+{
+ if (cp == (struct Constblock *) NULL)
+ return;
+
+ switch (cp -> vtype) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ cp -> Const.ci = - cp -> Const.ci;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if (cp->vstg)
+ switch(*cp->Const.cds[1]) {
+ case '-':
+ ++cp->Const.cds[1];
+ break;
+ case '0':
+ break;
+ default:
+ --cp->Const.cds[1];
+ }
+ else
+ cp->Const.cd[1] = -cp->Const.cd[1];
+ /* no break */
+ case TYREAL:
+ case TYDREAL:
+ if (cp->vstg)
+ switch(*cp->Const.cds[0]) {
+ case '-':
+ ++cp->Const.cds[0];
+ break;
+ case '0':
+ break;
+ default:
+ --cp->Const.cds[0];
+ }
+ else
+ cp->Const.cd[0] = -cp->Const.cd[0];
+ break;
+ case TYCHAR:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+ erri ("negate_const: can't negate type '%d'", cp -> vtype);
+ break;
+ default:
+ erri ("negate_const: bad type '%d'",
+ cp -> vtype);
+ break;
+ } /* switch */
+} /* negate_const */
+
+ void
+#ifdef KR_headers
+ffilecopy(infp, outfp)
+ FILE *infp;
+ FILE *outfp;
+#else
+ffilecopy(FILE *infp, FILE *outfp)
+#endif
+{
+ while (!feof (infp)) {
+ register c = getc (infp);
+ if (!feof (infp))
+ putc (c, outfp);
+ } /* while */
+} /* ffilecopy */
+
+
+/* in_vector -- verifies whether str is in c_keywords.
+ If so, the index is returned else -1 is returned.
+ c_keywords must be in alphabetical order (as defined by strcmp).
+*/
+
+ int
+#ifdef KR_headers
+in_vector(str, keywds, n)
+ char *str;
+ char **keywds;
+ register int n;
+#else
+in_vector(char *str, char **keywds, register int n)
+#endif
+{
+ register char **K = keywds;
+ register int n1, t;
+
+ do {
+ n1 = n >> 1;
+ if (!(t = strcmp(str, K[n1])))
+ return K - keywds + n1;
+ if (t < 0)
+ n = n1;
+ else {
+ n -= ++n1;
+ K += n1;
+ }
+ }
+ while(n > 0);
+
+ return -1;
+ } /* in_vector */
+
+
+ int
+#ifdef KR_headers
+is_negatable(Const)
+ Constp Const;
+#else
+is_negatable(Constp Const)
+#endif
+{
+ int retval = 0;
+ if (Const != (Constp) NULL)
+ switch (Const -> vtype) {
+ case TYINT1:
+ retval = Const -> Const.ci >= -BIGGEST_CHAR;
+ break;
+ case TYSHORT:
+ retval = Const -> Const.ci >= -BIGGEST_SHORT;
+ break;
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ retval = Const -> Const.ci >= -BIGGEST_LONG;
+ break;
+ case TYREAL:
+ case TYDREAL:
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ retval = 1;
+ break;
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+ case TYCHAR:
+ case TYSUBR:
+ default:
+ retval = 0;
+ break;
+ } /* switch */
+
+ return retval;
+} /* is_negatable */
+
+ void
+#ifdef KR_headers
+backup(fname, bname)
+ char *fname;
+ char *bname;
+#else
+backup(char *fname, char *bname)
+#endif
+{
+ FILE *b, *f;
+ static char couldnt[] = "Couldn't open %.80s";
+
+ if (!(f = fopen(fname, binread))) {
+ warn1(couldnt, fname);
+ return;
+ }
+ if (!(b = fopen(bname, binwrite))) {
+ warn1(couldnt, bname);
+ return;
+ }
+ ffilecopy(f, b);
+ fclose(f);
+ fclose(b);
+ }
+
+
+/* struct_eq -- returns YES if structures have the same field names and
+ types, NO otherwise */
+
+ int
+#ifdef KR_headers
+struct_eq(s1, s2)
+ chainp s1;
+ chainp s2;
+#else
+struct_eq(chainp s1, chainp s2)
+#endif
+{
+ struct Dimblock *d1, *d2;
+ Constp cp1, cp2;
+
+ if (s1 == CHNULL && s2 == CHNULL)
+ return YES;
+ for(; s1 && s2; s1 = s1->nextp, s2 = s2->nextp) {
+ register Namep v1 = (Namep) s1 -> datap;
+ register Namep v2 = (Namep) s2 -> datap;
+
+ if (v1 == (Namep) NULL || v1 -> tag != TNAME ||
+ v2 == (Namep) NULL || v2 -> tag != TNAME)
+ return NO;
+
+ if (v1->vtype != v2->vtype || v1->vclass != v2->vclass
+ || strcmp(v1->fvarname, v2->fvarname))
+ return NO;
+
+ /* compare dimensions (needed for comparing COMMON blocks) */
+
+ if (d1 = v1->vdim) {
+ if (!(cp1 = (Constp)d1->nelt) || cp1->tag != TCONST
+ || !(d2 = v2->vdim)
+ || !(cp2 = (Constp)d2->nelt) || cp2->tag != TCONST
+ || cp1->Const.ci != cp2->Const.ci)
+ return NO;
+ }
+ else if (v2->vdim)
+ return NO;
+ } /* while s1 != CHNULL && s2 != CHNULL */
+
+ return s1 == CHNULL && s2 == CHNULL;
+} /* struct_eq */
diff --git a/usr.bin/f2c/names.c b/usr.bin/f2c/names.c
new file mode 100644
index 0000000..b0e1058
--- /dev/null
+++ b/usr.bin/f2c/names.c
@@ -0,0 +1,835 @@
+/****************************************************************
+Copyright 1990, 1992 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "output.h"
+#include "names.h"
+#include "iob.h"
+
+
+/* Names generated by the translator are guaranteed to be unique from the
+ Fortan names because Fortran does not allow underscores in identifiers,
+ and all of the system generated names do have underscores. The various
+ naming conventions are outlined below:
+
+ FORMAT APPLICATION
+ ----------------------------------------------------------------------
+ io_# temporaries generated by IO calls; these will
+ contain the device number (e.g. 5, 6, 0)
+ ret_val function return value, required for complex and
+ character functions.
+ ret_val_len length of the return value in character functions
+
+ ssss_len length of character argument "ssss"
+
+ c_# member of the literal pool, where # is an
+ arbitrary label assigned by the system
+ cs_# short integer constant in the literal pool
+ t_# expression temporary, # is the depth of arguments
+ on the stack.
+ L# label "#", given by user in the Fortran program.
+ This is unique because Fortran labels are numeric
+ pad_# label on an init field required for alignment
+ xxx_init label on a common block union, if a block data
+ requires a separate declaration
+*/
+
+/* generate variable references */
+
+ char *
+#ifdef KR_headers
+c_type_decl(type, is_extern)
+ int type;
+ int is_extern;
+#else
+c_type_decl(int type, int is_extern)
+#endif
+{
+ static char buff[100];
+
+ switch (type) {
+ case TYREAL: if (!is_extern || !forcedouble)
+ { strcpy (buff, "real");break; }
+ case TYDREAL: strcpy (buff, "doublereal"); break;
+ case TYCOMPLEX: if (is_extern)
+ strcpy (buff, "/* Complex */ VOID");
+ else
+ strcpy (buff, "complex");
+ break;
+ case TYDCOMPLEX:if (is_extern)
+ strcpy (buff, "/* Double Complex */ VOID");
+ else
+ strcpy (buff, "doublecomplex");
+ break;
+ case TYADDR:
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL: strcpy(buff, typename[type]);
+ break;
+ case TYCHAR: if (is_extern)
+ strcpy (buff, "/* Character */ VOID");
+ else
+ strcpy (buff, "char");
+ break;
+
+ case TYUNKNOWN: strcpy (buff, "UNKNOWN");
+
+/* If a procedure's type is unknown, assume it's a subroutine */
+
+ if (!is_extern)
+ break;
+
+/* Subroutines must return an INT, because they might return a label
+ value. Even if one doesn't, the caller will EXPECT it to. */
+
+ case TYSUBR: strcpy (buff, "/* Subroutine */ int");
+ break;
+ case TYERROR: strcpy (buff, "ERROR"); break;
+ case TYVOID: strcpy (buff, "void"); break;
+ case TYCILIST: strcpy (buff, "cilist"); break;
+ case TYICILIST: strcpy (buff, "icilist"); break;
+ case TYOLIST: strcpy (buff, "olist"); break;
+ case TYCLLIST: strcpy (buff, "cllist"); break;
+ case TYALIST: strcpy (buff, "alist"); break;
+ case TYINLIST: strcpy (buff, "inlist"); break;
+ case TYFTNLEN: strcpy (buff, "ftnlen"); break;
+ default: sprintf (buff, "BAD DECL '%d'", type);
+ break;
+ } /* switch */
+
+ return buff;
+} /* c_type_decl */
+
+
+ char *
+new_func_length(Void)
+{ return "ret_val_len"; }
+
+ char *
+#ifdef KR_headers
+new_arg_length(arg)
+ Namep arg;
+#else
+new_arg_length(Namep arg)
+#endif
+{
+ static char buf[64];
+ char *fmt = "%s_len", *s = arg->fvarname;
+ switch(*s) {
+ case 'r':
+ if (!strcmp(s+1, "et_val"))
+ goto adjust_fmt;
+ break;
+ case 'h':
+ case 'i':
+ if (!s[1]) {
+ adjust_fmt:
+ fmt = "%s_length"; /* avoid conflict with libF77 */
+ }
+ }
+ sprintf (buf, fmt, s);
+ return buf;
+} /* new_arg_length */
+
+
+/* declare_new_addr -- Add a new local variable to the function, given a
+ pointer to an Addrblock structure (which must have the uname_tag set)
+ This list of idents will be printed in reverse (i.e., chronological)
+ order */
+
+ void
+#ifdef KR_headers
+declare_new_addr(addrp)
+ struct Addrblock *addrp;
+#else
+declare_new_addr(struct Addrblock *addrp)
+#endif
+{
+ extern chainp new_vars;
+
+ new_vars = mkchain((char *)cpexpr((expptr)addrp), new_vars);
+} /* declare_new_addr */
+
+
+ void
+#ifdef KR_headers
+wr_nv_ident_help(outfile, addrp)
+ FILE *outfile;
+ struct Addrblock *addrp;
+#else
+wr_nv_ident_help(FILE *outfile, struct Addrblock *addrp)
+#endif
+{
+ int eltcount = 0;
+
+ if (addrp == (struct Addrblock *) NULL)
+ return;
+
+ if (addrp -> isarray) {
+ frexpr (addrp -> memoffset);
+ addrp -> memoffset = ICON(0);
+ eltcount = addrp -> ntempelt;
+ addrp -> ntempelt = 0;
+ addrp -> isarray = 0;
+ } /* if */
+ out_addr (outfile, addrp);
+ if (eltcount)
+ nice_printf (outfile, "[%d]", eltcount);
+} /* wr_nv_ident_help */
+
+ int
+#ifdef KR_headers
+nv_type_help(addrp)
+ struct Addrblock *addrp;
+#else
+nv_type_help(struct Addrblock *addrp)
+#endif
+{
+ if (addrp == (struct Addrblock *) NULL)
+ return -1;
+
+ return addrp -> vtype;
+} /* nv_type_help */
+
+
+/* lit_name -- returns a unique identifier for the given literal. Make
+ the label useful, when possible. For example:
+
+ 1 -> c_1 (constant 1)
+ 2 -> c_2 (constant 2)
+ 1000 -> c_1000 (constant 1000)
+ 1000000 -> c_b<memno> (big constant number)
+ 1.2 -> c_1_2 (constant 1.2)
+ 1.234345 -> c_b<memno> (big constant number)
+ -1 -> c_n1 (constant -1)
+ -1.0 -> c_n1_0 (constant -1.0)
+ .true. -> c_true (constant true)
+ .false. -> c_false (constant false)
+ default -> c_b<memno> (default label)
+*/
+
+ char *
+#ifdef KR_headers
+lit_name(litp)
+ struct Literal *litp;
+#else
+lit_name(struct Literal *litp)
+#endif
+{
+ static char buf[CONST_IDENT_MAX];
+ ftnint val;
+ char *fmt;
+
+ if (litp == (struct Literal *) NULL)
+ return NULL;
+
+ switch (litp -> littype) {
+ case TYINT1:
+ val = litp -> litval.litival;
+ if (val >= 256 || val < -255)
+ sprintf (buf, "ci1_b%ld", litp -> litnum);
+ else if (val < 0)
+ sprintf (buf, "ci1_n%ld", -val);
+ else
+ sprintf(buf, "ci1__%ld", val);
+ break;
+ case TYSHORT:
+ val = litp -> litval.litival;
+ if (val >= 32768 || val <= -32769)
+ sprintf (buf, "cs_b%ld", litp -> litnum);
+ else if (val < 0)
+ sprintf (buf, "cs_n%ld", -val);
+ else
+ sprintf (buf, "cs__%ld", val);
+ break;
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ val = litp -> litval.litival;
+ if (val >= 100000 || val <= -10000)
+ sprintf (buf, "c_b%ld", litp -> litnum);
+ else if (val < 0)
+ sprintf (buf, "c_n%ld", -val);
+ else
+ sprintf (buf, "c__%ld", val);
+ break;
+ case TYLOGICAL1:
+ fmt = "cl1_%s";
+ goto spr_logical;
+ case TYLOGICAL2:
+ fmt = "cl2_%s";
+ goto spr_logical;
+ case TYLOGICAL:
+ fmt = "c_%s";
+ spr_logical:
+ sprintf (buf, fmt, (litp -> litval.litival
+ ? "true" : "false"));
+ break;
+ case TYREAL:
+ case TYDREAL:
+ /* Given a limit of 6 or 8 character on external names, */
+ /* few f.p. values can be meaningfully encoded in the */
+ /* constant name. Just going with the default cb_# */
+ /* seems to be the best course for floating-point */
+ /* constants. */
+ case TYCHAR:
+ /* Shouldn't be any of these */
+ case TYADDR:
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ case TYSUBR:
+ default:
+ sprintf (buf, "c_b%ld", litp -> litnum);
+ } /* switch */
+ return buf;
+} /* lit_name */
+
+
+
+ char *
+#ifdef KR_headers
+comm_union_name(count)
+ int count;
+#else
+comm_union_name(int count)
+#endif
+{
+ static char buf[12];
+
+ sprintf(buf, "%d", count);
+ return buf;
+ }
+
+
+
+
+/* wr_globals -- after every function has been translated, we need to
+ output the global declarations, such as the static table of constant
+ values */
+
+ void
+#ifdef KR_headers
+wr_globals(outfile)
+ FILE *outfile;
+#else
+wr_globals(FILE *outfile)
+#endif
+{
+ struct Literal *litp, *lastlit;
+ extern int hsize;
+ char *litname;
+ int did_one, t;
+ struct Constblock cb;
+ ftnint x, y;
+
+ if (nliterals == 0)
+ return;
+
+ lastlit = litpool + nliterals;
+ did_one = 0;
+ for (litp = litpool; litp < lastlit; litp++) {
+ if (!litp->lituse)
+ continue;
+ litname = lit_name(litp);
+ if (!did_one) {
+ margin_printf(outfile, "/* Table of constant values */\n\n");
+ did_one = 1;
+ }
+ cb.vtype = litp->littype;
+ if (litp->littype == TYCHAR) {
+ x = litp->litval.litival2[0] + litp->litval.litival2[1];
+ if (y = x % hsize)
+ x += y = hsize - y;
+ nice_printf(outfile,
+ "static struct { %s fill; char val[%ld+1];", halign, x);
+ nice_printf(outfile, " char fill2[%ld];", hsize - 1);
+ nice_printf(outfile, " } %s_st = { 0,", litname);
+ cb.vleng = ICON(litp->litval.litival2[0]);
+ cb.Const.ccp = litp->cds[0];
+ cb.Const.ccp1.blanks = litp->litval.litival2[1] + y;
+ cb.vtype = TYCHAR;
+ out_const(outfile, &cb);
+ frexpr(cb.vleng);
+ nice_printf(outfile, " };\n");
+ nice_printf(outfile, "#define %s %s_st.val\n", litname, litname);
+ continue;
+ }
+ nice_printf(outfile, "static %s %s = ",
+ c_type_decl(litp->littype,0), litname);
+
+ t = litp->littype;
+ if (ONEOF(t, MSKREAL|MSKCOMPLEX)) {
+ cb.vstg = 1;
+ cb.Const.cds[0] = litp->cds[0];
+ cb.Const.cds[1] = litp->cds[1];
+ }
+ else {
+ memcpy((char *)&cb.Const, (char *)&litp->litval,
+ sizeof(cb.Const));
+ cb.vstg = 0;
+ }
+ out_const(outfile, &cb);
+
+ nice_printf (outfile, ";\n");
+ } /* for */
+ if (did_one)
+ nice_printf (outfile, "\n");
+} /* wr_globals */
+
+ ftnint
+#ifdef KR_headers
+commlen(vl)
+ register chainp vl;
+#else
+commlen(register chainp vl)
+#endif
+{
+ ftnint size;
+ int type;
+ struct Dimblock *t;
+ Namep v;
+
+ while(vl->nextp)
+ vl = vl->nextp;
+ v = (Namep)vl->datap;
+ type = v->vtype;
+ if (type == TYCHAR)
+ size = v->vleng->constblock.Const.ci;
+ else
+ size = typesize[type];
+ if ((t = v->vdim) && ISCONST(t->nelt))
+ size *= t->nelt->constblock.Const.ci;
+ return size + v->voffset;
+ }
+
+ static void /* Pad common block if an EQUIVALENCE extended it. */
+#ifdef KR_headers
+pad_common(c)
+ Extsym *c;
+#else
+pad_common(Extsym *c)
+#endif
+{
+ register chainp cvl;
+ register Namep v;
+ long L = c->maxleng;
+ int type;
+ struct Dimblock *t;
+ int szshort = typesize[TYSHORT];
+
+ for(cvl = c->allextp; cvl; cvl = cvl->nextp)
+ if (commlen((chainp)cvl->datap) >= L)
+ return;
+ v = ALLOC(Nameblock);
+ v->vtype = type = L % szshort ? TYCHAR
+ : type_choice[L/szshort % 4];
+ v->vstg = STGCOMMON;
+ v->vclass = CLVAR;
+ v->tag = TNAME;
+ v->vdim = t = ALLOC(Dimblock);
+ t->ndim = 1;
+ t->dims[0].dimsize = ICON(L / typesize[type]);
+ v->fvarname = v->cvarname = "eqv_pad";
+ if (type == TYCHAR)
+ v->vleng = ICON(1);
+ c->allextp = mkchain((char *)mkchain((char *)v, CHNULL), c->allextp);
+ }
+
+
+/* wr_common_decls -- outputs the common declarations in one of three
+ formats. If all references to a common block look the same (field
+ names and types agree), only one actual declaration will appear.
+ Otherwise, the same block will require many structs. If there is no
+ block data, these structs will be union'ed together (so the linker
+ knows the size of the largest one). If there IS a block data, only
+ that version will be associated with the variable, others will only be
+ defined as types, so the pointer can be cast to it. e.g.
+
+ FORTRAN C
+----------------------------------------------------------------------
+ common /com1/ a, b, c struct { real a, b, c; } com1_;
+
+ common /com1/ a, b, c union {
+ common /com1/ i, j, k struct { real a, b, c; } _1;
+ struct { integer i, j, k; } _2;
+ } com1_;
+
+ common /com1/ a, b, c struct com1_1_ { real a, b, c; };
+ block data struct { integer i, j, k; } com1_ =
+ common /com1/ i, j, k { 1, 2, 3 };
+ data i/1/, j/2/, k/3/
+
+
+ All of these versions will be followed by #defines, since the code in
+ the function bodies can't know ahead of time which of these options
+ will be taken */
+
+/* Macros for deciding the output type */
+
+#define ONE_STRUCT 1
+#define UNION_STRUCT 2
+#define INIT_STRUCT 3
+
+ void
+#ifdef KR_headers
+wr_common_decls(outfile)
+ FILE *outfile;
+#else
+wr_common_decls(FILE *outfile)
+#endif
+{
+ Extsym *ext;
+ extern int extcomm;
+ static char *Extern[4] = {"", "Extern ", "extern "};
+ char *E, *E0 = Extern[extcomm];
+ int did_one = 0;
+
+ for (ext = extsymtab; ext < nextext; ext++) {
+ if (ext -> extstg == STGCOMMON && ext->allextp) {
+ chainp comm;
+ int count = 1;
+ int which; /* which display to use;
+ ONE_STRUCT, UNION or INIT */
+
+ if (!did_one)
+ nice_printf (outfile, "/* Common Block Declarations */\n\n");
+
+ pad_common(ext);
+
+/* Construct the proper, condensed list of structs; eliminate duplicates
+ from the initial list ext -> allextp */
+
+ comm = ext->allextp = revchain(ext->allextp);
+
+ if (ext -> extinit)
+ which = INIT_STRUCT;
+ else if (comm->nextp) {
+ which = UNION_STRUCT;
+ nice_printf (outfile, "%sunion {\n", E0);
+ next_tab (outfile);
+ E = "";
+ }
+ else {
+ which = ONE_STRUCT;
+ E = E0;
+ }
+
+ for (; comm; comm = comm -> nextp, count++) {
+
+ if (which == INIT_STRUCT)
+ nice_printf (outfile, "struct %s%d_ {\n",
+ ext->cextname, count);
+ else
+ nice_printf (outfile, "%sstruct {\n", E);
+
+ next_tab (c_file);
+
+ wr_struct (outfile, (chainp) comm -> datap);
+
+ prev_tab (c_file);
+ if (which == UNION_STRUCT)
+ nice_printf (outfile, "} _%d;\n", count);
+ else if (which == ONE_STRUCT)
+ nice_printf (outfile, "} %s;\n", ext->cextname);
+ else
+ nice_printf (outfile, "};\n");
+ } /* for */
+
+ if (which == UNION_STRUCT) {
+ prev_tab (c_file);
+ nice_printf (outfile, "} %s;\n", ext->cextname);
+ } /* if */
+ did_one = 1;
+ nice_printf (outfile, "\n");
+
+ for (count = 1, comm = ext -> allextp; comm;
+ comm = comm -> nextp, count++) {
+ def_start(outfile, ext->cextname,
+ comm_union_name(count), "");
+ switch (which) {
+ case ONE_STRUCT:
+ extern_out (outfile, ext);
+ break;
+ case UNION_STRUCT:
+ nice_printf (outfile, "(");
+ extern_out (outfile, ext);
+ nice_printf(outfile, "._%d)", count);
+ break;
+ case INIT_STRUCT:
+ nice_printf (outfile, "(*(struct ");
+ extern_out (outfile, ext);
+ nice_printf (outfile, "%d_ *) &", count);
+ extern_out (outfile, ext);
+ nice_printf (outfile, ")");
+ break;
+ } /* switch */
+ nice_printf (outfile, "\n");
+ } /* for count = 1, comm = ext -> allextp */
+ nice_printf (outfile, "\n");
+ } /* if ext -> extstg == STGCOMMON */
+ } /* for ext = extsymtab */
+} /* wr_common_decls */
+
+ void
+#ifdef KR_headers
+wr_struct(outfile, var_list)
+ FILE *outfile;
+ chainp var_list;
+#else
+wr_struct(FILE *outfile, chainp var_list)
+#endif
+{
+ int last_type = -1;
+ int did_one = 0;
+ chainp this_var;
+
+ for (this_var = var_list; this_var; this_var = this_var -> nextp) {
+ Namep var = (Namep) this_var -> datap;
+ int type;
+ char *comment = NULL;
+
+ if (var == (Namep) NULL)
+ err ("wr_struct: null variable");
+ else if (var -> tag != TNAME)
+ erri ("wr_struct: bad tag on variable '%d'",
+ var -> tag);
+
+ type = var -> vtype;
+
+ if (last_type == type && did_one)
+ nice_printf (outfile, ", ");
+ else {
+ if (did_one)
+ nice_printf (outfile, ";\n");
+ nice_printf (outfile, "%s ",
+ c_type_decl (type, var -> vclass == CLPROC));
+ } /* else */
+
+/* Character type is really a string type. Put out a '*' for parameters
+ with unknown length and functions returning character */
+
+ if (var -> vtype == TYCHAR && (!ISICON ((var -> vleng))
+ || var -> vclass == CLPROC))
+ nice_printf (outfile, "*");
+
+ var -> vstg = STGAUTO;
+ out_name (outfile, var);
+ if (var -> vclass == CLPROC)
+ nice_printf (outfile, "()");
+ else if (var -> vdim)
+ comment = wr_ardecls(outfile, var->vdim,
+ var->vtype == TYCHAR && ISICON(var->vleng)
+ ? var->vleng->constblock.Const.ci : 1L);
+ else if (var -> vtype == TYCHAR && var -> vclass != CLPROC &&
+ ISICON ((var -> vleng)))
+ nice_printf (outfile, "[%ld]",
+ var -> vleng -> constblock.Const.ci);
+
+ if (comment)
+ nice_printf (outfile, "%s", comment);
+ did_one = 1;
+ last_type = type;
+ } /* for this_var */
+
+ if (did_one)
+ nice_printf (outfile, ";\n");
+} /* wr_struct */
+
+
+ char *
+#ifdef KR_headers
+user_label(stateno)
+ ftnint stateno;
+#else
+user_label(ftnint stateno)
+#endif
+{
+ static char buf[USER_LABEL_MAX + 1];
+ static char *Lfmt[2] = { "L_%ld", "L%ld" };
+
+ if (stateno >= 0)
+ sprintf(buf, Lfmt[shiftcase], stateno);
+ else
+ sprintf(buf, "L_%s", extsymtab[-1-stateno].fextname);
+ return buf;
+} /* user_label */
+
+
+ char *
+#ifdef KR_headers
+temp_name(starter, num, storage)
+ char *starter;
+ int num;
+ char *storage;
+#else
+temp_name(char *starter, int num, char *storage)
+#endif
+{
+ static char buf[IDENT_LEN];
+ char *pointer = buf;
+ char *prefix = "t";
+
+ if (storage)
+ pointer = storage;
+
+ if (starter && *starter)
+ prefix = starter;
+
+ sprintf (pointer, "%s__%d", prefix, num);
+ return pointer;
+} /* temp_name */
+
+
+ char *
+#ifdef KR_headers
+equiv_name(memno, store)
+ int memno;
+ char *store;
+#else
+equiv_name(int memno, char *store)
+#endif
+{
+ static char buf[IDENT_LEN];
+ char *pointer = buf;
+
+ if (store)
+ pointer = store;
+
+ sprintf (pointer, "%s_%d", EQUIV_INIT_NAME, memno);
+ return pointer;
+} /* equiv_name */
+
+ void
+#ifdef KR_headers
+def_commons(of)
+ FILE *of;
+#else
+def_commons(FILE *of)
+#endif
+{
+ Extsym *ext;
+ int c, onefile, Union;
+ chainp comm;
+ extern int ext1comm;
+ FILE *c_filesave = c_file;
+
+ if (ext1comm == 1) {
+ onefile = 1;
+ c_file = of;
+ fprintf(of, "/*>>>'/dev/null'<<<*/\n\
+#ifdef Define_COMMONs\n\
+/*<<</dev/null>>>*/\n");
+ }
+ else
+ onefile = 0;
+ for(ext = extsymtab; ext < nextext; ext++)
+ if (ext->extstg == STGCOMMON
+ && !ext->extinit && (comm = ext->allextp)) {
+ sprintf(outbtail, "%scom.c", ext->cextname);
+ if (onefile)
+ fprintf(of, "/*>>>'%s'<<<*/\n",
+ outbtail);
+ else {
+ c_file = of = fopen(outbuf,textwrite);
+ if (!of)
+ fatalstr("can't open %s", outbuf);
+ }
+ fprintf(of, "#include \"f2c.h\"\n");
+ if (Ansi == 2)
+ fprintf(of,
+ "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n");
+ if (comm->nextp) {
+ Union = 1;
+ nice_printf(of, "union {\n");
+ next_tab(of);
+ }
+ else
+ Union = 0;
+ for(c = 1; comm; comm = comm->nextp) {
+ nice_printf(of, "struct {\n");
+ next_tab(of);
+ wr_struct(of, (chainp)comm->datap);
+ prev_tab(of);
+ if (Union)
+ nice_printf(of, "} _%d;\n", c++);
+ }
+ if (Union)
+ prev_tab(of);
+ nice_printf(of, "} %s;\n", ext->cextname);
+ if (Ansi == 2)
+ fprintf(of,
+ "\n#ifdef __cplusplus\n}\n#endif\n");
+ if (onefile)
+ fprintf(of, "/*<<<%s>>>*/\n", outbtail);
+ else
+ fclose(of);
+ }
+ if (onefile)
+ fprintf(of, "/*>>>'/dev/null'<<<*/\n#endif\n\
+/*<<</dev/null>>>*/\n");
+ c_file = c_filesave;
+ }
+
+/* C Language keywords. Needed to filter unwanted fortran identifiers like
+ * "int", etc. Source: Kernighan & Ritchie, eds. 1 and 2; Stroustrup.
+ * Also includes C++ keywords and types used for I/O in f2c.h .
+ * These keywords must be in alphabetical order (as defined by strcmp()).
+ */
+
+char *c_keywords[] = {
+ "Long", "Multitype", "Namelist", "Vardesc", "abs", "acos",
+ "addr", "address", "aerr", "alist", "asin", "asm", "atan",
+ "atan2", "aunit", "auto", "break", "c", "case", "catch", "cerr",
+ "char", "ciend", "cierr", "cifmt", "cilist", "cirec", "ciunit",
+ "class", "cllist", "complex", "const", "continue", "cos",
+ "cosh", "csta", "cunit", "d", "dabs", "default", "defined",
+ "delete", "dims", "dmax", "dmin", "do", "double",
+ "doublecomplex", "doublereal", "else", "entry", "enum", "exp",
+ "extern", "far", "flag", "float", "for", "friend", "ftnint",
+ "ftnlen", "goto", "h", "huge", "i", "iciend", "icierr",
+ "icifmt", "icilist", "icirlen", "icirnum", "iciunit", "if",
+ "inacc", "inacclen", "inblank", "inblanklen", "include",
+ "indir", "indirlen", "inerr", "inex", "infile", "infilen",
+ "infmt", "infmtlen", "inform", "informlen", "inline", "inlist",
+ "inname", "innamed", "innamlen", "innrec", "innum", "inopen",
+ "inrecl", "inseq", "inseqlen", "int", "integer", "integer1",
+ "inunf", "inunflen", "inunit", "log", "logical", "logical1",
+ "long", "longint", "max", "min", "name", "near", "new", "nvars",
+ "oacc", "oblnk", "oerr", "ofm", "ofnm", "ofnmlen", "olist",
+ "operator", "orl", "osta", "ounit", "overload", "private",
+ "protected", "public", "r", "real", "register", "return",
+ "short", "shortint", "shortlogical", "signed", "sin", "sinh",
+ "sizeof", "sqrt", "static", "struct", "switch", "tan", "tanh",
+ "template", "this", "try", "type", "typedef", "uinteger",
+ "ulongint", "union", "unsigned", "vars", "virtual", "void",
+ "volatile", "while", "z"
+ }; /* c_keywords */
+
+int n_keywords = sizeof(c_keywords)/sizeof(char *);
diff --git a/usr.bin/f2c/names.h b/usr.bin/f2c/names.h
new file mode 100644
index 0000000..16bcc0b
--- /dev/null
+++ b/usr.bin/f2c/names.h
@@ -0,0 +1,19 @@
+#define CONST_IDENT_MAX 30
+#define IO_IDENT_MAX 30
+#define ARGUMENT_MAX 30
+#define USER_LABEL_MAX 30
+
+#define EQUIV_INIT_NAME "equiv"
+
+#define write_nv_ident(fp,a) wr_nv_ident_help ((fp), (struct Addrblock *) (a))
+#define nv_type(x) nv_type_help ((struct Addrblock *) x)
+
+extern char *c_keywords[];
+
+char* c_type_decl Argdcl((int, int));
+void declare_new_addr Argdcl((Addrp));
+char* new_arg_length Argdcl((Namep));
+char* new_func_length Argdcl((void));
+int nv_type_help Argdcl((Addrp));
+char* temp_name Argdcl((char*, int, char*));
+char* user_label Argdcl((long int));
diff --git a/usr.bin/f2c/niceprintf.c b/usr.bin/f2c/niceprintf.c
new file mode 100644
index 0000000..0d5f5cc
--- /dev/null
+++ b/usr.bin/f2c/niceprintf.c
@@ -0,0 +1,441 @@
+/****************************************************************
+Copyright 1990, 1991, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "names.h"
+#include "output.h"
+#ifndef KR_headers
+#include "stdarg.h"
+#endif
+
+#define TOO_LONG_INDENT (2 * tab_size)
+#define MAX_INDENT 44
+#define MIN_INDENT 22
+static int last_was_newline = 0;
+int sharp_line = 0;
+int indent = 0;
+int in_comment = 0;
+int in_define = 0;
+ extern int gflag1;
+ extern char filename[];
+
+ static void ind_printf Argdcl((int, FILE*, char*, va_list));
+
+ static void
+#ifdef KR_headers
+write_indent(fp, use_indent, extra_indent, start, end)
+ FILE *fp;
+ int use_indent;
+ int extra_indent;
+ char *start;
+ char *end;
+#else
+write_indent(FILE *fp, int use_indent, int extra_indent, char *start, char *end)
+#endif
+{
+ int ind, tab;
+
+ if (sharp_line) {
+ fprintf(fp, "#line %ld \"%s\"\n", lineno, filename);
+ sharp_line = 0;
+ }
+ if (in_define == 1) {
+ in_define = 2;
+ use_indent = 0;
+ }
+ if (last_was_newline && use_indent) {
+ if (*start == '\n') do {
+ putc('\n', fp);
+ if (++start > end)
+ return;
+ }
+ while(*start == '\n');
+
+ ind = indent <= MAX_INDENT
+ ? indent
+ : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
+
+ tab = ind + extra_indent;
+
+ while (tab > 7) {
+ putc ('\t', fp);
+ tab -= 8;
+ } /* while */
+
+ while (tab-- > 0)
+ putc (' ', fp);
+ } /* if last_was_newline */
+
+ while (start <= end)
+ putc (*start++, fp);
+} /* write_indent */
+
+#ifdef KR_headers
+/*VARARGS2*/
+ void
+ margin_printf (fp, a, b, c, d, e, f, g)
+ FILE *fp;
+ char *a;
+ long b, c, d, e, f, g;
+{
+ ind_printf (0, fp, a, b, c, d, e, f, g);
+} /* margin_printf */
+
+/*VARARGS2*/
+ void
+ nice_printf (fp, a, b, c, d, e, f, g)
+ FILE *fp;
+ char *a;
+ long b, c, d, e, f, g;
+{
+ ind_printf (1, fp, a, b, c, d, e, f, g);
+} /* nice_printf */
+#define SPRINTF(x,a,b,c,d,e,f,g) sprintf(x,a,b,c,d,e,f,g)
+
+#else /* if (!defined(KR_HEADERS)) */
+
+#define SPRINTF(x,a,b,c,d,e,f,g) vsprintf(x,a,ap)
+
+ void
+ margin_printf(FILE *fp, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ ind_printf(0, fp, fmt, ap);
+ va_end(ap);
+ }
+
+ void
+ nice_printf(FILE *fp, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ ind_printf(1, fp, fmt, ap);
+ va_end(ap);
+ }
+#endif
+
+#define max_line_len c_output_line_length
+ /* 74Number of characters allowed on an output
+ line. This assumes newlines are handled
+ nicely, i.e. a newline after a full text
+ line on a terminal is ignored */
+
+/* output_buf holds the text of the next line to be printed. It gets
+ flushed when a newline is printed. next_slot points to the next
+ available location in the output buffer, i.e. where the next call to
+ nice_printf will have its output stored */
+
+static char *output_buf;
+static char *next_slot;
+static char *string_start;
+
+static char *word_start = NULL;
+static int cursor_pos = 0;
+static int In_string = 0;
+
+ void
+np_init(Void)
+{
+ next_slot = output_buf = Alloc(MAX_OUTPUT_SIZE);
+ memset(output_buf, 0, MAX_OUTPUT_SIZE);
+ }
+
+ static char *
+#ifdef KR_headers
+adjust_pointer_in_string(pointer)
+ register char *pointer;
+#else
+adjust_pointer_in_string(register char *pointer)
+#endif
+{
+ register char *s, *s1, *se, *s0;
+
+ /* arrange not to break \002 */
+ s1 = string_start ? string_start : output_buf;
+ for(s = s1; s < pointer; s++) {
+ s0 = s1;
+ s1 = s;
+ if (*s == '\\') {
+ se = s++ + 4;
+ if (se > pointer)
+ break;
+ if (*s < '0' || *s > '7')
+ continue;
+ while(++s < se)
+ if (*s < '0' || *s > '7')
+ break;
+ --s;
+ }
+ }
+ return s0 - 1;
+ }
+
+/* ANSI says strcpy's behavior is undefined for overlapping args,
+ * so we roll our own fwd_strcpy: */
+
+ static void
+#ifdef KR_headers
+fwd_strcpy(t, s)
+ register char *t;
+ register char *s;
+#else
+fwd_strcpy(register char *t, register char *s)
+#endif
+{ while(*t++ = *s++); }
+
+/* isident -- true iff character could belong to a unit. C allows
+ letters, numbers and underscores in identifiers. This also doubles as
+ a check for numeric constants, since we include the decimal point and
+ minus sign. The minus has to be here, since the constant "10e-2"
+ cannot be broken up. The '.' also prevents structure references from
+ being broken, which is a quite acceptable side effect */
+
+#define isident(x) (Tr[x] & 1)
+#define isntident(x) (!Tr[x])
+
+ static void
+#ifdef KR_headers
+ ind_printf (use_indent, fp, a, b, c, d, e, f, g)
+ int use_indent;
+ FILE *fp;
+ char *a;
+ long b, c, d, e, f, g;
+#else
+ ind_printf (int use_indent, FILE *fp, char *a, va_list ap)
+#endif
+{
+ extern int max_line_len;
+ extern FILEP c_file;
+ extern char tr_tab[]; /* in output.c */
+ register char *Tr = tr_tab;
+ int ch, inc, ind;
+ static int extra_indent, last_indent, set_cursor = 1;
+
+ cursor_pos += indent - last_indent;
+ last_indent = indent;
+ SPRINTF (next_slot, a, b, c, d, e, f, g);
+
+ if (fp != c_file) {
+ fprintf (fp,"%s", next_slot);
+ return;
+ } /* if fp != c_file */
+
+ do {
+ char *pointer;
+
+/* The for loop will parse one output line */
+
+ if (set_cursor) {
+ ind = indent <= MAX_INDENT
+ ? indent
+ : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
+ cursor_pos = ind + extra_indent;
+ set_cursor = 0;
+ }
+ if (in_comment)
+ for (pointer = next_slot; *pointer && *pointer != '\n' &&
+ cursor_pos <= max_line_len; pointer++)
+ cursor_pos++;
+ else
+ for (pointer = next_slot; *pointer && *pointer != '\n' &&
+ cursor_pos <= max_line_len; pointer++) {
+
+ /* Update state variables here */
+
+ if (In_string) {
+ switch(*pointer) {
+ case '\\':
+ if (++cursor_pos > max_line_len) {
+ cursor_pos -= 2;
+ --pointer;
+ goto overflow;
+ }
+ ++pointer;
+ break;
+ case '"':
+ In_string = 0;
+ word_start = 0;
+ }
+ }
+ else switch (*pointer) {
+ case '"':
+ if (cursor_pos + 5 > max_line_len) {
+ word_start = 0;
+ --pointer;
+ goto overflow;
+ }
+ In_string = 1;
+ string_start = word_start = pointer;
+ break;
+ case '\'':
+ if (pointer[1] == '\\')
+ if ((ch = pointer[2]) >= '0' && ch <= '7')
+ for(inc = 3; pointer[inc] != '\''
+ && ++inc < 5;);
+ else
+ inc = 3;
+ else
+ inc = 2;
+ /*debug*/ if (pointer[inc] != '\'')
+ /*debug*/ fatalstr("Bad character constant %.10s",
+ pointer);
+ if ((cursor_pos += inc) > max_line_len) {
+ cursor_pos -= inc;
+ word_start = 0;
+ --pointer;
+ goto overflow;
+ }
+ word_start = pointer;
+ pointer += inc;
+ break;
+ case '\t':
+ cursor_pos = 8 * ((cursor_pos + 8) / 8) - 1;
+ break;
+ default: {
+
+/* HACK Assumes that all characters in an atomic C token will be written
+ at the same time. Must check for tokens first, since '-' is considered
+ part of an identifier; checking isident first would mean breaking up "->" */
+
+ if (word_start) {
+ if (isntident(*(unsigned char *)pointer))
+ word_start = NULL;
+ }
+ else if (isident(*(unsigned char *)pointer))
+ word_start = pointer;
+ break;
+ } /* default */
+ } /* switch */
+ cursor_pos++;
+ } /* for pointer = next_slot */
+ overflow:
+ if (*pointer == '\0') {
+
+/* The output line is not complete, so break out and don't output
+ anything. The current line fragment will be stored in the buffer */
+
+ next_slot = pointer;
+ break;
+ } else {
+ char last_char;
+ int in_string0 = In_string;
+
+/* If the line was too long, move pointer back to the character before
+ the current word. This allows line breaking on word boundaries. Make
+ sure that 80 character comment lines get broken up somehow. We assume
+ that any non-string 80 character identifier must be in a comment.
+*/
+
+ if (*pointer == '\n')
+ in_define = 0;
+ else if (word_start && word_start > output_buf)
+ if (In_string)
+ if (string_start && pointer - string_start < 5)
+ pointer = string_start - 1;
+ else {
+ pointer = adjust_pointer_in_string(pointer);
+ string_start = 0;
+ }
+ else if (word_start == string_start
+ && pointer - string_start >= 5) {
+ pointer = adjust_pointer_in_string(next_slot);
+ In_string = 1;
+ string_start = 0;
+ }
+ else
+ pointer = word_start - 1;
+ else if (cursor_pos > max_line_len) {
+#ifndef ANSI_Libraries
+ extern char *strchr();
+#endif
+ if (In_string) {
+ pointer = adjust_pointer_in_string(pointer);
+ if (string_start && pointer > string_start)
+ string_start = 0;
+ }
+ else if (strchr("&*+-/<=>|", *pointer)
+ && strchr("!%&*+-/<=>^|", pointer[-1])) {
+ pointer -= 2;
+ if (strchr("<>", *pointer)) /* <<=, >>= */
+ pointer--;
+ }
+ else {
+ if (word_start)
+ while(isident(*(unsigned char *)pointer))
+ pointer++;
+ pointer--;
+ }
+ }
+ last_char = *pointer;
+ write_indent(fp, use_indent, extra_indent, output_buf, pointer);
+ next_slot = output_buf;
+ if (In_string && !string_start && Ansi == 1 && last_char != '\n')
+ *next_slot++ = '"';
+ fwd_strcpy(next_slot, pointer + 1);
+
+/* insert a line break */
+
+ if (last_char == '\n') {
+ if (In_string)
+ last_was_newline = 0;
+ else {
+ last_was_newline = 1;
+ extra_indent = 0;
+ sharp_line = gflag1;
+ }
+ }
+ else {
+ extra_indent = TOO_LONG_INDENT;
+ if (In_string && !string_start) {
+ if (Ansi == 1) {
+ fprintf(fp, gflag1 ? "\"\\\n" : "\"\n");
+ use_indent = 1;
+ last_was_newline = 1;
+ }
+ else {
+ fprintf(fp, "\\\n");
+ last_was_newline = 0;
+ }
+ In_string = in_string0;
+ }
+ else {
+ if (in_define/* | gflag1*/)
+ putc('\\', fp);
+ putc ('\n', fp);
+ last_was_newline = 1;
+ }
+ } /* if *pointer != '\n' */
+
+ if (In_string && Ansi != 1 && !string_start)
+ cursor_pos = 0;
+ else
+ set_cursor = 1;
+
+ string_start = word_start = NULL;
+
+ } /* else */
+
+ } while (*next_slot);
+
+} /* ind_printf */
diff --git a/usr.bin/f2c/niceprintf.h b/usr.bin/f2c/niceprintf.h
new file mode 100644
index 0000000..24c65d4
--- /dev/null
+++ b/usr.bin/f2c/niceprintf.h
@@ -0,0 +1,16 @@
+/* niceprintf.h -- contains constants and macros from the output filter
+ for the generated C code. We use macros for increased speed, less
+ function overhead. */
+
+#define MAX_OUTPUT_SIZE 6000 /* Number of chars on one output line PLUS
+ the length of the longest string
+ printed using nice_printf */
+
+
+
+#define next_tab(fp) (indent += tab_size)
+
+#define prev_tab(fp) (indent -= tab_size)
+
+
+
diff --git a/usr.bin/f2c/output.c b/usr.bin/f2c/output.c
new file mode 100644
index 0000000..03d0ed0
--- /dev/null
+++ b/usr.bin/f2c/output.c
@@ -0,0 +1,1709 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "names.h"
+#include "output.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+char _assoc_table[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
+
+/* Opcode table -- This array is indexed by the OP_____ macros defined in
+ defines.h; these macros are expected to be adjacent integers, so that
+ this table is as small as possible. */
+
+table_entry opcode_table[] = {
+ { 0, 0, NULL },
+ /* OPPLUS 1 */ { BINARY_OP, 12, "%l + %r" },
+ /* OPMINUS 2 */ { BINARY_OP, 12, "%l - %r" },
+ /* OPSTAR 3 */ { BINARY_OP, 13, "%l * %r" },
+ /* OPSLASH 4 */ { BINARY_OP, 13, "%l / %r" },
+ /* OPPOWER 5 */ { BINARY_OP, 0, "power (%l, %r)" },
+ /* OPNEG 6 */ { UNARY_OP, 14, "-%l" },
+ /* OPOR 7 */ { BINARY_OP, 4, "%l || %r" },
+ /* OPAND 8 */ { BINARY_OP, 5, "%l && %r" },
+ /* OPEQV 9 */ { BINARY_OP, 9, "%l == %r" },
+ /* OPNEQV 10 */ { BINARY_OP, 9, "%l != %r" },
+ /* OPNOT 11 */ { UNARY_OP, 14, "! %l" },
+ /* OPCONCAT 12 */ { BINARY_OP, 0, "concat (%l, %r)" },
+ /* OPLT 13 */ { BINARY_OP, 10, "%l < %r" },
+ /* OPEQ 14 */ { BINARY_OP, 9, "%l == %r" },
+ /* OPGT 15 */ { BINARY_OP, 10, "%l > %r" },
+ /* OPLE 16 */ { BINARY_OP, 10, "%l <= %r" },
+ /* OPNE 17 */ { BINARY_OP, 9, "%l != %r" },
+ /* OPGE 18 */ { BINARY_OP, 10, "%l >= %r" },
+ /* OPCALL 19 */ { BINARY_OP, 15, SPECIAL_FMT },
+ /* OPCCALL 20 */ { BINARY_OP, 15, SPECIAL_FMT },
+
+/* Left hand side of an assignment cannot have outermost parens */
+
+ /* OPASSIGN 21 */ { BINARY_OP, 2, "%l = %r" },
+ /* OPPLUSEQ 22 */ { BINARY_OP, 2, "%l += %r" },
+ /* OPSTAREQ 23 */ { BINARY_OP, 2, "%l *= %r" },
+ /* OPCONV 24 */ { BINARY_OP, 14, "%l" },
+ /* OPLSHIFT 25 */ { BINARY_OP, 11, "%l << %r" },
+ /* OPMOD 26 */ { BINARY_OP, 13, "%l %% %r" },
+ /* OPCOMMA 27 */ { BINARY_OP, 1, "%l, %r" },
+
+/* Don't want to nest the colon operator in parens */
+
+ /* OPQUEST 28 */ { BINARY_OP, 3, "%l ? %r" },
+ /* OPCOLON 29 */ { BINARY_OP, 3, "%l : %r" },
+ /* OPABS 30 */ { UNARY_OP, 0, "abs(%l)" },
+ /* OPMIN 31 */ { BINARY_OP, 0, SPECIAL_FMT },
+ /* OPMAX 32 */ { BINARY_OP, 0, SPECIAL_FMT },
+ /* OPADDR 33 */ { UNARY_OP, 14, "&%l" },
+
+ /* OPCOMMA_ARG 34 */ { BINARY_OP, 15, SPECIAL_FMT },
+ /* OPBITOR 35 */ { BINARY_OP, 6, "%l | %r" },
+ /* OPBITAND 36 */ { BINARY_OP, 8, "%l & %r" },
+ /* OPBITXOR 37 */ { BINARY_OP, 7, "%l ^ %r" },
+ /* OPBITNOT 38 */ { UNARY_OP, 14, "~ %l" },
+ /* OPRSHIFT 39 */ { BINARY_OP, 11, "%l >> %r" },
+
+/* This isn't quite right -- it doesn't handle arrays, for instance */
+
+ /* OPWHATSIN 40 */ { UNARY_OP, 14, "*%l" },
+ /* OPMINUSEQ 41 */ { BINARY_OP, 2, "%l -= %r" },
+ /* OPSLASHEQ 42 */ { BINARY_OP, 2, "%l /= %r" },
+ /* OPMODEQ 43 */ { BINARY_OP, 2, "%l %%= %r" },
+ /* OPLSHIFTEQ 44 */ { BINARY_OP, 2, "%l <<= %r" },
+ /* OPRSHIFTEQ 45 */ { BINARY_OP, 2, "%l >>= %r" },
+ /* OPBITANDEQ 46 */ { BINARY_OP, 2, "%l &= %r" },
+ /* OPBITXOREQ 47 */ { BINARY_OP, 2, "%l ^= %r" },
+ /* OPBITOREQ 48 */ { BINARY_OP, 2, "%l |= %r" },
+ /* OPPREINC 49 */ { UNARY_OP, 14, "++%l" },
+ /* OPPREDEC 50 */ { UNARY_OP, 14, "--%l" },
+ /* OPDOT 51 */ { BINARY_OP, 15, "%l.%r" },
+ /* OPARROW 52 */ { BINARY_OP, 15, "%l -> %r"},
+ /* OPNEG1 53 */ { UNARY_OP, 14, "-%l" },
+ /* OPDMIN 54 */ { BINARY_OP, 0, "dmin(%l,%r)" },
+ /* OPDMAX 55 */ { BINARY_OP, 0, "dmax(%l,%r)" },
+ /* OPASSIGNI 56 */ { BINARY_OP, 2, "%l = &%r" },
+ /* OPIDENTITY 57 */ { UNARY_OP, 15, "%l" },
+ /* OPCHARCAST 58 */ { UNARY_OP, 14, "(char *)&%l" },
+ /* OPDABS 59 */ { UNARY_OP, 0, "dabs(%l)" },
+ /* OPMIN2 60 */ { BINARY_OP, 0, "min(%l,%r)" },
+ /* OPMAX2 61 */ { BINARY_OP, 0, "max(%l,%r)" },
+ /* OPBITTEST 62 */ { BINARY_OP, 0, "bit_test(%l,%r)" },
+ /* OPBITCLR 63 */ { BINARY_OP, 0, "bit_clear(%l,%r)" },
+ /* OPBITSET 64 */ { BINARY_OP, 0, "bit_set(%l,%r)" },
+#ifdef TYQUAD
+ /* OPQBITCLR 65 */ { BINARY_OP, 0, "qbit_clear(%l,%r)" },
+ /* OPQBITSET 66 */ { BINARY_OP, 0, "qbit_set(%l,%r)" },
+#endif
+
+/* kludge to imitate (under forcedouble) f77's bizarre treatement of OPNEG... */
+
+ /* OPNEG KLUDGE */ { UNARY_OP, 14, "-(doublereal)%l" }
+}; /* opcode_table */
+
+#define OPNEG_KLUDGE (sizeof(opcode_table)/sizeof(table_entry) - 1)
+
+extern int dneg;
+static char opeqable[sizeof(opcode_table)/sizeof(table_entry)];
+
+
+static void output_arg_list Argdcl((FILEP, struct Listblock*));
+static void output_binary Argdcl((FILEP, Exprp));
+static void output_list Argdcl((FILEP, struct Listblock*));
+static void output_literal Argdcl((FILEP, long, Constp));
+static void output_prim Argdcl((FILEP, struct Primblock*));
+static void output_unary Argdcl((FILEP, Exprp));
+
+
+ void
+#ifdef KR_headers
+expr_out(fp, e)
+ FILE *fp;
+ expptr e;
+#else
+expr_out(FILE *fp, expptr e)
+#endif
+{
+ if (e == (expptr) NULL)
+ return;
+
+ switch (e -> tag) {
+ case TNAME: out_name (fp, (struct Nameblock *) e);
+ return;
+
+ case TCONST: out_const(fp, &e->constblock);
+ goto end_out;
+ case TEXPR:
+ break;
+
+ case TADDR: out_addr (fp, &(e -> addrblock));
+ goto end_out;
+
+ case TPRIM: if (!nerr)
+ warn ("expr_out: got TPRIM");
+ output_prim (fp, &(e -> primblock));
+ return;
+
+ case TLIST: output_list (fp, &(e -> listblock));
+ end_out: frexpr(e);
+ return;
+
+ case TIMPLDO: err ("expr_out: got TIMPLDO");
+ return;
+
+ case TERROR:
+ default:
+ erri ("expr_out: bad tag '%d'", e -> tag);
+ } /* switch */
+
+/* Now we know that the tag is TEXPR */
+
+/* Optimize on simple expressions, such as "a = a + b" ==> "a += b" */
+
+ if (e -> exprblock.opcode == OPASSIGN && e -> exprblock.rightp &&
+ e -> exprblock.rightp -> tag == TEXPR) {
+ int opcode;
+
+ opcode = e -> exprblock.rightp -> exprblock.opcode;
+
+ if (opeqable[opcode]) {
+ expptr leftp, rightp;
+
+ if ((leftp = e -> exprblock.leftp) &&
+ (rightp = e -> exprblock.rightp -> exprblock.leftp)) {
+
+ if (same_ident (leftp, rightp)) {
+ expptr temp = e -> exprblock.rightp;
+
+ e -> exprblock.opcode = op_assign(opcode);
+
+ e -> exprblock.rightp = temp -> exprblock.rightp;
+ temp->exprblock.rightp = 0;
+ frexpr(temp);
+ } /* if same_ident (leftp, rightp) */
+ } /* if leftp && rightp */
+ } /* if opcode == OPPLUS || */
+ } /* if e -> exprblock.opcode == OPASSIGN */
+
+
+/* Optimize on increment or decrement by 1 */
+
+ {
+ int opcode = e -> exprblock.opcode;
+ expptr leftp = e -> exprblock.leftp;
+ expptr rightp = e -> exprblock.rightp;
+
+ if (leftp && rightp && (leftp -> headblock.vstg == STGARG ||
+ ISINT (leftp -> headblock.vtype)) &&
+ (opcode == OPPLUSEQ || opcode == OPMINUSEQ) &&
+ ISINT (rightp -> headblock.vtype) &&
+ ISICON (e -> exprblock.rightp) &&
+ (ISONE (e -> exprblock.rightp) ||
+ e -> exprblock.rightp -> constblock.Const.ci == -1)) {
+
+/* Allow for the '-1' constant value */
+
+ if (!ISONE (e -> exprblock.rightp))
+ opcode = (opcode == OPPLUSEQ) ? OPMINUSEQ : OPPLUSEQ;
+
+/* replace the existing opcode */
+
+ if (opcode == OPPLUSEQ)
+ e -> exprblock.opcode = OPPREINC;
+ else
+ e -> exprblock.opcode = OPPREDEC;
+
+/* Free up storage used by the right hand side */
+
+ frexpr (e -> exprblock.rightp);
+ e->exprblock.rightp = 0;
+ } /* if opcode == OPPLUS */
+ } /* block */
+
+
+ if (is_unary_op (e -> exprblock.opcode))
+ output_unary (fp, &(e -> exprblock));
+ else if (is_binary_op (e -> exprblock.opcode))
+ output_binary (fp, &(e -> exprblock));
+ else
+ erri ("expr_out: bad opcode '%d'", (int) e -> exprblock.opcode);
+
+ free((char *)e);
+
+} /* expr_out */
+
+
+ void
+#ifdef KR_headers
+out_and_free_statement(outfile, expr)
+ FILE *outfile;
+ expptr expr;
+#else
+out_and_free_statement(FILE *outfile, expptr expr)
+#endif
+{
+ if (expr)
+ expr_out (outfile, expr);
+
+ nice_printf (outfile, ";\n");
+} /* out_and_free_statement */
+
+
+
+ int
+#ifdef KR_headers
+same_ident(left, right)
+ expptr left;
+ expptr right;
+#else
+same_ident(expptr left, expptr right)
+#endif
+{
+ if (!left || !right)
+ return 0;
+
+ if (left -> tag == TNAME && right -> tag == TNAME && left == right)
+ return 1;
+
+ if (left -> tag == TADDR && right -> tag == TADDR &&
+ left -> addrblock.uname_tag == right -> addrblock.uname_tag)
+ switch (left -> addrblock.uname_tag) {
+ case UNAM_REF:
+ case UNAM_NAME:
+
+/* Check for array subscripts */
+
+ if (left -> addrblock.user.name -> vdim ||
+ right -> addrblock.user.name -> vdim)
+ if (left -> addrblock.user.name !=
+ right -> addrblock.user.name ||
+ !same_expr (left -> addrblock.memoffset,
+ right -> addrblock.memoffset))
+ return 0;
+
+ return same_ident ((expptr) (left -> addrblock.user.name),
+ (expptr) right -> addrblock.user.name);
+ case UNAM_IDENT:
+ return strcmp(left->addrblock.user.ident,
+ right->addrblock.user.ident) == 0;
+ case UNAM_CHARP:
+ return strcmp(left->addrblock.user.Charp,
+ right->addrblock.user.Charp) == 0;
+ default:
+ return 0;
+ } /* switch */
+
+ if (left->tag == TEXPR && left->exprblock.opcode == OPWHATSIN
+ && right->tag == TEXPR && right->exprblock.opcode == OPWHATSIN)
+ return same_ident(left->exprblock.leftp,
+ right->exprblock.leftp);
+
+ return 0;
+} /* same_ident */
+
+ static int
+#ifdef KR_headers
+samefpconst(c1, c2, n)
+ register Constp c1;
+ register Constp c2;
+ register int n;
+#else
+samefpconst(register Constp c1, register Constp c2, register int n)
+#endif
+{
+ char *s1, *s2;
+ if (!c1->vstg && !c2->vstg)
+ return c1->Const.cd[n] == c2->Const.cd[n];
+ s1 = c1->vstg ? c1->Const.cds[n] : dtos(c1->Const.cd[n]);
+ s2 = c2->vstg ? c2->Const.cds[n] : dtos(c2->Const.cd[n]);
+ return !strcmp(s1, s2);
+ }
+
+ static int
+#ifdef KR_headers
+sameconst(c1, c2)
+ register Constp c1;
+ register Constp c2;
+#else
+sameconst(register Constp c1, register Constp c2)
+#endif
+{
+ switch(c1->vtype) {
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if (!samefpconst(c1,c2,1))
+ return 0;
+ case TYREAL:
+ case TYDREAL:
+ return samefpconst(c1,c2,0);
+ case TYCHAR:
+ return c1->Const.ccp1.blanks == c2->Const.ccp1.blanks
+ && c1->vleng->constblock.Const.ci
+ == c2->vleng->constblock.Const.ci
+ && !memcmp(c1->Const.ccp, c2->Const.ccp,
+ (int)c1->vleng->constblock.Const.ci);
+ case TYSHORT:
+ case TYINT:
+ case TYLOGICAL:
+ return c1->Const.ci == c2->Const.ci;
+ }
+ err("unexpected type in sameconst");
+ return 0;
+ }
+
+/* same_expr -- Returns true only if e1 and e2 match. This is
+ somewhat pessimistic, but can afford to be because it's just used to
+ optimize on the assignment operators (+=, -=, etc). */
+
+ int
+#ifdef KR_headers
+same_expr(e1, e2)
+ expptr e1;
+ expptr e2;
+#else
+same_expr(expptr e1, expptr e2)
+#endif
+{
+ if (!e1 || !e2)
+ return !e1 && !e2;
+
+ if (e1 -> tag != e2 -> tag || e1 -> headblock.vtype != e2 -> headblock.vtype)
+ return 0;
+
+ switch (e1 -> tag) {
+ case TEXPR:
+ if (e1 -> exprblock.opcode != e2 -> exprblock.opcode)
+ return 0;
+
+ return same_expr (e1 -> exprblock.leftp, e2 -> exprblock.leftp) &&
+ same_expr (e1 -> exprblock.rightp, e2 -> exprblock.rightp);
+ case TNAME:
+ case TADDR:
+ return same_ident (e1, e2);
+ case TCONST:
+ return sameconst(&e1->constblock, &e2->constblock);
+ default:
+ return 0;
+ } /* switch */
+} /* same_expr */
+
+
+
+ void
+#ifdef KR_headers
+out_name(fp, namep)
+ FILE *fp;
+ Namep namep;
+#else
+out_name(FILE *fp, Namep namep)
+#endif
+{
+ extern int usedefsforcommon;
+ Extsym *comm;
+
+ if (namep == NULL)
+ return;
+
+/* DON'T want to use oneof_stg() here; need to find the right common name
+ */
+
+ if (namep->vstg == STGCOMMON && !namep->vcommequiv && !usedefsforcommon) {
+ comm = &extsymtab[namep->vardesc.varno];
+ extern_out(fp, comm);
+ nice_printf(fp, "%d.", comm->curno);
+ } /* if namep -> vstg == STGCOMMON */
+
+ if (namep->vprocclass == PTHISPROC && namep->vtype != TYSUBR)
+ nice_printf(fp, xretslot[namep->vtype]->user.ident);
+ else
+ nice_printf (fp, "%s", namep->cvarname);
+} /* out_name */
+
+
+static char *Longfmt = "%ld";
+
+#define cpd(n) cp->vstg ? cp->Const.cds[n] : dtos(cp->Const.cd[n])
+
+ void
+#ifdef KR_headers
+out_const(fp, cp)
+ FILE *fp;
+ register Constp cp;
+#else
+out_const(FILE *fp, register Constp cp)
+#endif
+{
+ static char real_buf[50], imag_buf[50];
+ unsigned int k;
+ int type = cp->vtype;
+
+ switch (type) {
+ case TYINT1:
+ case TYSHORT:
+ nice_printf (fp, "%ld", cp->Const.ci); /* don't cast ci! */
+ break;
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ nice_printf (fp, Longfmt, cp->Const.ci); /* don't cast ci! */
+ break;
+ case TYREAL:
+ nice_printf(fp, "%s", flconst(real_buf, cpd(0)));
+ break;
+ case TYDREAL:
+ nice_printf(fp, "%s", cpd(0));
+ break;
+ case TYCOMPLEX:
+ nice_printf(fp, cm_fmt_string, flconst(real_buf, cpd(0)),
+ flconst(imag_buf, cpd(1)));
+ break;
+ case TYDCOMPLEX:
+ nice_printf(fp, dcm_fmt_string, cpd(0), cpd(1));
+ break;
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+ nice_printf (fp, "%s", cp->Const.ci ? "TRUE_" : "FALSE_");
+ break;
+ case TYCHAR: {
+ char *c = cp->Const.ccp, *ce;
+
+ if (c == NULL) {
+ nice_printf (fp, "\"\"");
+ break;
+ } /* if c == NULL */
+
+ nice_printf (fp, "\"");
+ ce = c + cp->vleng->constblock.Const.ci;
+ while(c < ce) {
+ k = *(unsigned char *)c++;
+ nice_printf(fp, str_fmt[k], k);
+ }
+ for(k = cp->Const.ccp1.blanks; k > 0; k--)
+ nice_printf(fp, " ");
+ nice_printf (fp, "\"");
+ break;
+ } /* case TYCHAR */
+ default:
+ erri ("out_const: bad type '%d'", (int) type);
+ break;
+ } /* switch */
+
+} /* out_const */
+#undef cpd
+
+ static void
+#ifdef KR_headers
+out_args(fp, ep)
+ FILE *fp;
+ expptr ep;
+#else
+out_args(FILE *fp, expptr ep)
+#endif
+{
+ chainp arglist;
+
+ if(ep->tag != TLIST)
+ badtag("out_args", ep->tag);
+ for(arglist = ep->listblock.listp;;) {
+ expr_out(fp, (expptr)arglist->datap);
+ arglist->datap = 0;
+ if (!(arglist = arglist->nextp))
+ break;
+ nice_printf(fp, ", ");
+ }
+ }
+
+
+/* out_addr -- this routine isn't local because it is called by the
+ system-generated identifier printing routines */
+
+ void
+#ifdef KR_headers
+out_addr(fp, addrp)
+ FILE *fp;
+ struct Addrblock *addrp;
+#else
+out_addr(FILE *fp, struct Addrblock *addrp)
+#endif
+{
+ extern Extsym *extsymtab;
+ int was_array = 0;
+ char *s;
+
+
+ if (addrp == NULL)
+ return;
+ if (doin_setbound
+ && addrp->vstg == STGARG
+ && addrp->vtype != TYCHAR
+ && ISICON(addrp->memoffset)
+ && !addrp->memoffset->constblock.Const.ci)
+ nice_printf(fp, "*");
+
+ switch (addrp -> uname_tag) {
+ case UNAM_REF:
+ nice_printf(fp, "%s_%s(", addrp->user.name->cvarname,
+ addrp->cmplx_sub ? "subscr" : "ref");
+ out_args(fp, addrp->memoffset);
+ nice_printf(fp, ")");
+ return;
+ case UNAM_NAME:
+ out_name (fp, addrp -> user.name);
+ break;
+ case UNAM_IDENT:
+ if (*(s = addrp->user.ident) == ' ') {
+ if (multitype)
+ nice_printf(fp, "%s",
+ xretslot[addrp->vtype]->user.ident);
+ else
+ nice_printf(fp, "%s", s+1);
+ }
+ else {
+ nice_printf(fp, "%s", s);
+ }
+ break;
+ case UNAM_CHARP:
+ nice_printf(fp, "%s", addrp->user.Charp);
+ break;
+ case UNAM_EXTERN:
+ extern_out (fp, &extsymtab[addrp -> memno]);
+ break;
+ case UNAM_CONST:
+ switch(addrp->vstg) {
+ case STGCONST:
+ out_const(fp, (Constp)addrp);
+ break;
+ case STGMEMNO:
+ output_literal (fp, addrp->memno,
+ (Constp)addrp);
+ break;
+ default:
+ Fatal("unexpected vstg in out_addr");
+ }
+ break;
+ case UNAM_UNKNOWN:
+ default:
+ nice_printf (fp, "Unknown Addrp");
+ break;
+ } /* switch */
+
+/* It's okay to just throw in the brackets here because they have a
+ precedence level of 15, the highest value. */
+
+ if ((addrp->uname_tag == UNAM_NAME && addrp->user.name->vdim
+ || addrp->ntempelt > 1 || addrp->isarray)
+ && addrp->vtype != TYCHAR) {
+ expptr offset;
+
+ was_array = 1;
+
+ offset = addrp -> memoffset;
+ addrp->memoffset = 0;
+ if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
+ && addrp -> uname_tag == UNAM_NAME
+ && !addrp->skip_offset)
+ offset = mkexpr (OPMINUS, offset, mkintcon (
+ addrp -> user.name -> voffset));
+
+ nice_printf (fp, "[");
+
+ offset = mkexpr (OPSLASH, offset,
+ ICON (typesize[addrp -> vtype] * (addrp -> Field ? 2 : 1)));
+ expr_out (fp, offset);
+ nice_printf (fp, "]");
+ }
+
+/* Check for structure field reference */
+
+ if (addrp -> Field && addrp -> uname_tag != UNAM_CONST &&
+ addrp -> uname_tag != UNAM_UNKNOWN) {
+ if (oneof_stg((addrp -> uname_tag == UNAM_NAME ? addrp -> user.name :
+ (Namep) NULL), addrp -> vstg, M(STGARG)|M(STGEQUIV))
+ && !was_array && (addrp->vclass != CLPROC || !multitype))
+ nice_printf (fp, "->%s", addrp -> Field);
+ else
+ nice_printf (fp, ".%s", addrp -> Field);
+ } /* if */
+
+/* Check for character subscripting */
+
+ if (addrp->vtype == TYCHAR &&
+ (addrp->vclass != CLPROC || addrp->uname_tag == UNAM_NAME
+ && addrp->user.name->vprocclass == PTHISPROC) &&
+ addrp -> memoffset &&
+ (addrp -> uname_tag != UNAM_NAME ||
+ addrp -> user.name -> vtype == TYCHAR) &&
+ (!ISICON (addrp -> memoffset) ||
+ (addrp -> memoffset -> constblock.Const.ci))) {
+
+ int use_paren = 0;
+ expptr e = addrp -> memoffset;
+
+ if (!e)
+ return;
+ addrp->memoffset = 0;
+
+ if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
+ && addrp -> uname_tag == UNAM_NAME) {
+ e = mkexpr (OPMINUS, e, mkintcon (addrp -> user.name -> voffset));
+
+/* mkexpr will simplify it to zero if possible */
+ if (e->tag == TCONST && e->constblock.Const.ci == 0)
+ return;
+ } /* if addrp -> vstg == STGCOMMON */
+
+/* In the worst case, parentheses might be needed OUTSIDE the expression,
+ too. But since I think this subscripting can only appear as a
+ parameter in a procedure call, I don't think outside parens will ever
+ be needed. INSIDE parens are handled below */
+
+ nice_printf (fp, " + ");
+ if (e -> tag == TEXPR) {
+ int arg_prec = op_precedence (e -> exprblock.opcode);
+ int prec = op_precedence (OPPLUS);
+ use_paren = arg_prec && (arg_prec < prec || (arg_prec == prec &&
+ is_left_assoc (OPPLUS)));
+ } /* if e -> tag == TEXPR */
+ if (use_paren) nice_printf (fp, "(");
+ expr_out (fp, e);
+ if (use_paren) nice_printf (fp, ")");
+ } /* if */
+} /* out_addr */
+
+
+ static void
+#ifdef KR_headers
+output_literal(fp, memno, cp)
+ FILE *fp;
+ long memno;
+ Constp cp;
+#else
+output_literal(FILE *fp, long memno, Constp cp)
+#endif
+{
+ struct Literal *litp, *lastlit;
+
+ lastlit = litpool + nliterals;
+
+ for (litp = litpool; litp < lastlit; litp++) {
+ if (litp -> litnum == memno)
+ break;
+ } /* for litp */
+
+ if (litp >= lastlit)
+ out_const (fp, cp);
+ else {
+ nice_printf (fp, "%s", lit_name (litp));
+ litp->lituse++;
+ }
+} /* output_literal */
+
+
+ static void
+#ifdef KR_headers
+output_prim(fp, primp)
+ FILE *fp;
+ struct Primblock *primp;
+#else
+output_prim(FILE *fp, struct Primblock *primp)
+#endif
+{
+ if (primp == NULL)
+ return;
+
+ out_name (fp, primp -> namep);
+ if (primp -> argsp)
+ output_arg_list (fp, primp -> argsp);
+
+ if (primp -> fcharp != (expptr) NULL || primp -> lcharp != (expptr) NULL)
+ nice_printf (fp, "Sorry, no substrings yet");
+}
+
+
+
+ static void
+#ifdef KR_headers
+output_arg_list(fp, listp)
+ FILE *fp;
+ struct Listblock *listp;
+#else
+output_arg_list(FILE *fp, struct Listblock *listp)
+#endif
+{
+ chainp arg_list;
+
+ if (listp == (struct Listblock *) NULL || listp -> listp == (chainp) NULL)
+ return;
+
+ nice_printf (fp, "(");
+
+ for (arg_list = listp -> listp; arg_list; arg_list = arg_list -> nextp) {
+ expr_out (fp, (expptr) arg_list -> datap);
+ if (arg_list -> nextp != (chainp) NULL)
+
+/* Might want to add a hook in here to accomodate the style setting which
+ wants spaces after commas */
+
+ nice_printf (fp, ",");
+ } /* for arg_list */
+
+ nice_printf (fp, ")");
+} /* output_arg_list */
+
+
+
+ static void
+#ifdef KR_headers
+output_unary(fp, e)
+ FILE *fp;
+ struct Exprblock *e;
+#else
+output_unary(FILE *fp, struct Exprblock *e)
+#endif
+{
+ if (e == NULL)
+ return;
+
+ switch (e -> opcode) {
+ case OPNEG:
+ if (e->vtype == TYREAL && dneg) {
+ e->opcode = OPNEG_KLUDGE;
+ output_binary(fp,e);
+ e->opcode = OPNEG;
+ break;
+ }
+ case OPNEG1:
+ case OPNOT:
+ case OPABS:
+ case OPBITNOT:
+ case OPWHATSIN:
+ case OPPREINC:
+ case OPPREDEC:
+ case OPADDR:
+ case OPIDENTITY:
+ case OPCHARCAST:
+ case OPDABS:
+ output_binary (fp, e);
+ break;
+ case OPCALL:
+ case OPCCALL:
+ nice_printf (fp, "Sorry, no OPCALL yet");
+ break;
+ default:
+ erri ("output_unary: bad opcode", (int) e -> opcode);
+ break;
+ } /* switch */
+} /* output_unary */
+
+
+ static char *
+#ifdef KR_headers
+findconst(m)
+ register long m;
+#else
+findconst(register long m)
+#endif
+{
+ register struct Literal *litp, *litpe;
+
+ litp = litpool;
+ for(litpe = litp + nliterals; litp < litpe; litp++)
+ if (litp->litnum == m)
+ return litp->cds[0];
+ Fatal("findconst failure!");
+ return 0;
+ }
+
+ static int
+#ifdef KR_headers
+opconv_fudge(fp, e)
+ FILE *fp;
+ struct Exprblock *e;
+#else
+opconv_fudge(FILE *fp, struct Exprblock *e)
+#endif
+{
+ /* special handling for conversions, ichar and character*1 */
+ register expptr lp;
+ register union Expression *Offset;
+ register char *cp;
+ int lt;
+ char buf[8], *s;
+ unsigned int k;
+ Namep np;
+ Addrp ap;
+
+ if (!(lp = e->leftp)) /* possible with erroneous Fortran */
+ return 1;
+ lt = lp->headblock.vtype;
+ if (lt == TYCHAR) {
+ switch(lp->tag) {
+ case TNAME:
+ nice_printf(fp, "*(unsigned char *)");
+ out_name(fp, (Namep)lp);
+ return 1;
+ case TCONST:
+ tconst:
+ cp = lp->constblock.Const.ccp;
+ tconst1:
+ k = *(unsigned char *)cp;
+ if (k < 128) { /* ASCII character */
+ sprintf(buf, chr_fmt[k], k);
+ nice_printf(fp, "'%s'", buf);
+ }
+ else
+ nice_printf(fp, "%d", k);
+ return 1;
+ case TADDR:
+ switch(lp->addrblock.vstg) {
+ case STGMEMNO:
+ if (halign && e->vtype != TYCHAR) {
+ nice_printf(fp, "*(%s *)",
+ c_type_decl(e->vtype,0));
+ expr_out(fp, lp);
+ return 1;
+ }
+ cp = findconst(lp->addrblock.memno);
+ goto tconst1;
+ case STGCONST:
+ goto tconst;
+ }
+ lp->addrblock.vtype = tyint;
+ Offset = lp->addrblock.memoffset;
+ switch(lp->addrblock.uname_tag) {
+ case UNAM_REF:
+ nice_printf(fp, "*(unsigned char *)");
+ return 0;
+ case UNAM_NAME:
+ np = lp->addrblock.user.name;
+ if (ONEOF(np->vstg,
+ M(STGCOMMON)|M(STGEQUIV)))
+ Offset = mkexpr(OPMINUS, Offset,
+ ICON(np->voffset));
+ }
+ lp->addrblock.memoffset = Offset ?
+ mkexpr(OPSTAR, Offset,
+ ICON(typesize[tyint]))
+ : ICON(0);
+ lp->addrblock.isarray = 1;
+ /* STGCOMMON or STGEQUIV would cause */
+ /* voffset to be added in a second time */
+ lp->addrblock.vstg = STGUNKNOWN;
+ nice_printf(fp, "*(unsigned char *)&");
+ return 0;
+ default:
+ badtag("opconv_fudge", lp->tag);
+ }
+ }
+ if (lt != e->vtype) {
+ s = c_type_decl(e->vtype, 0);
+ if (ISCOMPLEX(lt)) {
+ tryagain:
+ np = (Namep)e->leftp;
+ switch(np->tag) {
+ case TNAME:
+ nice_printf(fp, "(%s) %s%sr", s,
+ np->cvarname,
+ np->vstg == STGARG ? "->" : ".");
+ return 1;
+ case TADDR:
+ ap = (Addrp)np;
+ switch(ap->uname_tag) {
+ case UNAM_IDENT:
+ nice_printf(fp, "(%s) %s.r", s,
+ ap->user.ident);
+ return 1;
+ case UNAM_NAME:
+ nice_printf(fp, "(%s) ", s);
+ out_addr(fp, ap);
+ nice_printf(fp, ".r");
+ return 1;
+ }
+ case TEXPR:
+ e = (Exprp)np;
+ if (e->opcode == OPWHATSIN)
+ goto tryagain;
+ default:
+ fatali("Unexpected tag %d in opconv_fudge",
+ np->tag);
+ }
+ }
+ nice_printf(fp, "(%s) ", s);
+ }
+ return 0;
+ }
+
+
+ static void
+#ifdef KR_headers
+output_binary(fp, e)
+ FILE *fp;
+ struct Exprblock *e;
+#else
+output_binary(FILE *fp, struct Exprblock *e)
+#endif
+{
+ char *format;
+ extern table_entry opcode_table[];
+ int prec;
+
+ if (e == NULL || e -> tag != TEXPR)
+ return;
+
+/* Instead of writing a huge switch, I've incorporated the output format
+ into a table. Things like "%l" and "%r" stand for the left and
+ right subexpressions. This should allow both prefix and infix
+ functions to be specified (e.g. "(%l * %r", "z_div (%l, %r"). Of
+ course, I should REALLY think out the ramifications of writing out
+ straight text, as opposed to some intermediate format, which could
+ figure out and optimize on the the number of required blanks (we don't
+ want "x - (-y)" to become "x --y", for example). Special cases (such as
+ incomplete implementations) could still be implemented as part of the
+ switch, they will just have some dummy value instead of the string
+ pattern. Another difficulty is the fact that the complex functions
+ will differ from the integer and real ones */
+
+/* Handle a special case. We don't want to output "x + - 4", or "y - - 3"
+*/
+ if ((e -> opcode == OPPLUS || e -> opcode == OPMINUS) &&
+ e -> rightp && e -> rightp -> tag == TCONST &&
+ isnegative_const (&(e -> rightp -> constblock)) &&
+ is_negatable (&(e -> rightp -> constblock))) {
+
+ e -> opcode = (e -> opcode == OPPLUS) ? OPMINUS : OPPLUS;
+ negate_const (&(e -> rightp -> constblock));
+ } /* if e -> opcode == PLUS or MINUS */
+
+ prec = op_precedence (e -> opcode);
+ format = op_format (e -> opcode);
+
+ if (format != SPECIAL_FMT) {
+ while (*format) {
+ if (*format == '%') {
+ int arg_prec, use_paren = 0;
+ expptr lp, rp;
+
+ switch (*(format + 1)) {
+ case 'l':
+ lp = e->leftp;
+ if (lp && lp->tag == TEXPR) {
+ arg_prec = op_precedence(lp->exprblock.opcode);
+
+ use_paren = arg_prec &&
+ (arg_prec < prec || (arg_prec == prec &&
+ is_right_assoc (prec)));
+ } /* if e -> leftp */
+ if (e->opcode == OPCONV && opconv_fudge(fp,e))
+ break;
+ if (use_paren)
+ nice_printf (fp, "(");
+ expr_out(fp, lp);
+ if (use_paren)
+ nice_printf (fp, ")");
+ break;
+ case 'r':
+ rp = e->rightp;
+ if (rp && rp->tag == TEXPR) {
+ arg_prec = op_precedence(rp->exprblock.opcode);
+
+ use_paren = arg_prec &&
+ (arg_prec < prec || (arg_prec == prec &&
+ is_left_assoc (prec)));
+ use_paren = use_paren ||
+ (rp->exprblock.opcode == OPNEG
+ && prec >= op_precedence(OPMINUS));
+ } /* if e -> rightp */
+ if (use_paren)
+ nice_printf (fp, "(");
+ expr_out(fp, rp);
+ if (use_paren)
+ nice_printf (fp, ")");
+ break;
+ case '\0':
+ case '%':
+ nice_printf (fp, "%%");
+ break;
+ default:
+ erri ("output_binary: format err: '%%%c' illegal",
+ (int) *(format + 1));
+ break;
+ } /* switch */
+ format += 2;
+ } else
+ nice_printf (fp, "%c", *format++);
+ } /* while *format */
+ } else {
+
+/* Handle Special cases of formatting */
+
+ switch (e -> opcode) {
+ case OPCCALL:
+ case OPCALL:
+ out_call (fp, (int) e -> opcode, e -> vtype,
+ e -> vleng, e -> leftp, e -> rightp);
+ break;
+
+ case OPCOMMA_ARG:
+ doin_setbound = 1;
+ nice_printf(fp, "(");
+ expr_out(fp, e->leftp);
+ nice_printf(fp, ", &");
+ doin_setbound = 0;
+ expr_out(fp, e->rightp);
+ nice_printf(fp, ")");
+ break;
+
+ case OPADDR:
+ default:
+ nice_printf (fp, "Sorry, can't format OPCODE '%d'",
+ e -> opcode);
+ break;
+ }
+
+ } /* else */
+} /* output_binary */
+
+ void
+#ifdef KR_headers
+out_call(outfile, op, ftype, len, name, args)
+ FILE *outfile;
+ int op;
+ int ftype;
+ expptr len;
+ expptr name;
+ expptr args;
+#else
+out_call(FILE *outfile, int op, int ftype, expptr len, expptr name, expptr args)
+#endif
+{
+ chainp arglist; /* Pointer to any actual arguments */
+ chainp cp; /* Iterator over argument lists */
+ Addrp ret_val = (Addrp) NULL;
+ /* Function return value buffer, if any is
+ required */
+ int byvalue; /* True iff we're calling a C library
+ routine */
+ int done_once; /* Used for writing commas to outfile */
+ int narg, t;
+ register expptr q;
+ long L;
+ Argtypes *at;
+ Atype *A, *Ac;
+ Namep np;
+ extern int forcereal;
+
+/* Don't use addresses if we're calling a C function */
+
+ byvalue = op == OPCCALL;
+
+ if (args)
+ arglist = args -> listblock.listp;
+ else
+ arglist = CHNULL;
+
+/* If this is a CHARACTER function, the first argument is the result */
+
+ if (ftype == TYCHAR)
+ if (ISICON (len)) {
+ ret_val = (Addrp) (arglist -> datap);
+ arglist = arglist -> nextp;
+ } else {
+ err ("adjustable character function");
+ return;
+ } /* else */
+
+/* If this is a COMPLEX function, the first argument is the result */
+
+ else if (ISCOMPLEX (ftype)) {
+ ret_val = (Addrp) (arglist -> datap);
+ arglist = arglist -> nextp;
+ } /* if ISCOMPLEX */
+
+ /* prepare to cast procedure parameters -- set A if we know how */
+ np = name->tag == TEXPR && name->exprblock.opcode == OPWHATSIN
+ ? (Namep)name->exprblock.leftp : (Namep)name;
+
+ A = Ac = 0;
+ if (np->tag == TNAME && (at = np->arginfo)) {
+ if (at->nargs > 0)
+ A = at->atypes;
+ if (Ansi && (at->defined || at->nargs > 0))
+ Ac = at->atypes;
+ }
+
+/* Now we can actually start to write out the function invocation */
+
+ if (ftype == TYREAL && forcereal)
+ nice_printf(outfile, "(real)");
+ if (name -> tag == TEXPR && name -> exprblock.opcode == OPWHATSIN) {
+ nice_printf (outfile, "(");
+ expr_out (outfile, name);
+ nice_printf (outfile, ")");
+ }
+ else
+ expr_out(outfile, name);
+
+ nice_printf(outfile, "(");
+
+ if (ret_val) {
+ if (ISCOMPLEX (ftype))
+ nice_printf (outfile, "&");
+ expr_out (outfile, (expptr) ret_val);
+ if (Ac)
+ Ac++;
+
+/* The length of the result of a character function is the second argument */
+/* It should be in place from putcall(), so we won't touch it explicitly */
+
+ } /* if ret_val */
+ done_once = ret_val ? TRUE : FALSE;
+
+/* Now run through the named arguments */
+
+ narg = -1;
+ for (cp = arglist; cp; cp = cp -> nextp, done_once = TRUE) {
+
+ if (done_once)
+ nice_printf (outfile, ", ");
+ narg++;
+
+ if (!( q = (expptr)cp->datap) )
+ continue;
+
+ if (q->tag == TADDR) {
+ if (q->addrblock.vtype > TYERROR) {
+ /* I/O block */
+ nice_printf(outfile, "&%s", q->addrblock.user.ident);
+ continue;
+ }
+ if (!byvalue && q->addrblock.isarray
+ && q->addrblock.vtype != TYCHAR
+ && q->addrblock.memoffset->tag == TCONST) {
+
+ /* check for 0 offset -- after */
+ /* correcting for equivalence. */
+ L = q->addrblock.memoffset->constblock.Const.ci;
+ if (ONEOF(q->addrblock.vstg, M(STGCOMMON)|M(STGEQUIV))
+ && q->addrblock.uname_tag == UNAM_NAME)
+ L -= q->addrblock.user.name->voffset;
+ if (L)
+ goto skip_deref;
+
+ if (Ac && narg < at->dnargs
+ && q->headblock.vtype != (t = Ac[narg].type)
+ && t > TYADDR && t < TYSUBR)
+ nice_printf(outfile, "(%s*)", typename[t]);
+
+ /* &x[0] == x */
+ /* This also prevents &sizeof(doublereal)[0] */
+
+ switch(q->addrblock.uname_tag) {
+ case UNAM_NAME:
+ out_name(outfile, q->addrblock.user.name);
+ continue;
+ case UNAM_IDENT:
+ nice_printf(outfile, "%s",
+ q->addrblock.user.ident);
+ continue;
+ case UNAM_CHARP:
+ nice_printf(outfile, "%s",
+ q->addrblock.user.Charp);
+ continue;
+ case UNAM_EXTERN:
+ extern_out(outfile,
+ &extsymtab[q->addrblock.memno]);
+ continue;
+ }
+ }
+ }
+
+/* Skip over the dereferencing operator generated only for the
+ intermediate file */
+ skip_deref:
+ if (q -> tag == TEXPR && q -> exprblock.opcode == OPWHATSIN)
+ q = q -> exprblock.leftp;
+
+ if (q->headblock.vclass == CLPROC) {
+ if (Castargs && (q->tag != TNAME
+ || q->nameblock.vprocclass != PTHISPROC)
+ && (q->tag != TADDR
+ || q->addrblock.uname_tag != UNAM_NAME
+ || q->addrblock.user.name->vprocclass
+ != PTHISPROC))
+ {
+ if (A && (t = A[narg].type) >= 200)
+ t %= 100;
+ else {
+ t = q->headblock.vtype;
+ if (q->tag == TNAME && q->nameblock.vimpltype)
+ t = TYUNKNOWN;
+ }
+ nice_printf(outfile, "(%s)", usedcasts[t] = casttypes[t]);
+ }
+ }
+ else if (Ac && narg < at->dnargs
+ && q->headblock.vtype != (t = Ac[narg].type)
+ && t > TYADDR && t < TYSUBR)
+ nice_printf(outfile, "(%s*)", typename[t]);
+
+ if ((q -> tag == TADDR || q-> tag == TNAME) &&
+ (byvalue || q -> headblock.vstg != STGREG)) {
+ if (q -> headblock.vtype != TYCHAR)
+ if (byvalue) {
+
+ if (q -> tag == TADDR &&
+ q -> addrblock.uname_tag == UNAM_NAME &&
+ ! q -> addrblock.user.name -> vdim &&
+ oneof_stg(q -> addrblock.user.name, q -> addrblock.vstg,
+ M(STGARG)|M(STGEQUIV)) &&
+ ! ISCOMPLEX(q->addrblock.user.name->vtype))
+ nice_printf (outfile, "*");
+ else if (q -> tag == TNAME
+ && oneof_stg(&q->nameblock, q -> nameblock.vstg,
+ M(STGARG)|M(STGEQUIV))
+ && !(q -> nameblock.vdim))
+ nice_printf (outfile, "*");
+
+ } else {
+ expptr memoffset;
+
+ if (q->tag == TADDR && (
+ !ONEOF (q -> addrblock.vstg, M(STGEXT)|M(STGLENG))
+ && (ONEOF(q->addrblock.vstg,
+ M(STGCOMMON)|M(STGEQUIV)|M(STGMEMNO))
+ || ((memoffset = q->addrblock.memoffset)
+ && (!ISICON(memoffset)
+ || memoffset->constblock.Const.ci)))
+ || ONEOF(q->addrblock.vstg,
+ M(STGINIT)|M(STGAUTO)|M(STGBSS))
+ && !q->addrblock.isarray))
+ nice_printf (outfile, "&");
+ else if (q -> tag == TNAME
+ && !oneof_stg(&q->nameblock, q -> nameblock.vstg,
+ M(STGARG)|M(STGEXT)|M(STGEQUIV)))
+ nice_printf (outfile, "&");
+ } /* else */
+
+ expr_out (outfile, q);
+ } /* if q -> tag == TADDR || q -> tag == TNAME */
+
+/* Might be a Constant expression, e.g. string length, character constants */
+
+ else if (q -> tag == TCONST) {
+ if (tyioint == TYLONG)
+ Longfmt = "%ldL";
+ out_const(outfile, &q->constblock);
+ Longfmt = "%ld";
+ }
+
+/* Must be some other kind of expression, or register var, or constant.
+ In particular, this is likely to be a temporary variable assignment
+ which was generated in p1put_call */
+
+ else if (!ISCOMPLEX (q -> headblock.vtype) && !ISCHAR (q)){
+ int use_paren = q -> tag == TEXPR &&
+ op_precedence (q -> exprblock.opcode) <=
+ op_precedence (OPCOMMA);
+
+ if (use_paren) nice_printf (outfile, "(");
+ expr_out (outfile, q);
+ if (use_paren) nice_printf (outfile, ")");
+ } /* if !ISCOMPLEX */
+ else
+ err ("out_call: unknown parameter");
+
+ } /* for (cp = arglist */
+
+ if (arglist)
+ frchain (&arglist);
+
+ nice_printf (outfile, ")");
+
+} /* out_call */
+
+
+ char *
+#ifdef KR_headers
+flconst(buf, x)
+ char *buf;
+ char *x;
+#else
+flconst(char *buf, char *x)
+#endif
+{
+ sprintf(buf, fl_fmt_string, x);
+ return buf;
+ }
+
+ char *
+#ifdef KR_headers
+dtos(x)
+ double x;
+#else
+dtos(double x)
+#endif
+{
+ static char buf[64];
+#ifdef USE_DTOA
+ g_fmt(buf, x);
+#else
+ sprintf(buf, db_fmt_string, x);
+#endif
+ return strcpy(mem(strlen(buf)+1,0), buf);
+ }
+
+char tr_tab[Table_size];
+
+/* out_init -- Initialize the data structures used by the routines in
+ output.c. These structures include the output format to be used for
+ Float, Double, Complex, and Double Complex constants. */
+
+ void
+out_init(Void)
+{
+ extern int tab_size;
+ register char *s;
+
+ s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-.";
+ while(*s)
+ tr_tab[*s++] = 3;
+ tr_tab['>'] = 1;
+
+ opeqable[OPPLUS] = 1;
+ opeqable[OPMINUS] = 1;
+ opeqable[OPSTAR] = 1;
+ opeqable[OPSLASH] = 1;
+ opeqable[OPMOD] = 1;
+ opeqable[OPLSHIFT] = 1;
+ opeqable[OPBITAND] = 1;
+ opeqable[OPBITXOR] = 1;
+ opeqable[OPBITOR ] = 1;
+
+
+/* Set the output format for both types of floating point constants */
+
+ if (fl_fmt_string == NULL || *fl_fmt_string == '\0')
+ fl_fmt_string = Ansi == 1 ? "%sf" : "(float)%s";
+
+ if (db_fmt_string == NULL || *db_fmt_string == '\0')
+ db_fmt_string = "%.17g";
+
+/* Set the output format for both types of complex constants. They will
+ have string parameters rather than float or double so that the decimal
+ point may be added to the strings generated by the {db,fl}_fmt_string
+ formats above */
+
+ if (cm_fmt_string == NULL || *cm_fmt_string == '\0') {
+ cm_fmt_string = "{%s,%s}";
+ } /* if cm_fmt_string == NULL */
+
+ if (dcm_fmt_string == NULL || *dcm_fmt_string == '\0') {
+ dcm_fmt_string = "{%s,%s}";
+ } /* if dcm_fmt_string == NULL */
+
+ tab_size = 4;
+} /* out_init */
+
+
+ void
+#ifdef KR_headers
+extern_out(fp, extsym)
+ FILE *fp;
+ Extsym *extsym;
+#else
+extern_out(FILE *fp, Extsym *extsym)
+#endif
+{
+ if (extsym == (Extsym *) NULL)
+ return;
+
+ nice_printf (fp, "%s", extsym->cextname);
+
+} /* extern_out */
+
+
+
+ static void
+#ifdef KR_headers
+output_list(fp, listp)
+ FILE *fp;
+ struct Listblock *listp;
+#else
+output_list(FILE *fp, struct Listblock *listp)
+#endif
+{
+ int did_one = 0;
+ chainp elts;
+
+ nice_printf (fp, "(");
+ if (listp)
+ for (elts = listp -> listp; elts; elts = elts -> nextp) {
+ if (elts -> datap) {
+ if (did_one)
+ nice_printf (fp, ", ");
+ expr_out (fp, (expptr) elts -> datap);
+ did_one = 1;
+ } /* if elts -> datap */
+ } /* for elts */
+ nice_printf (fp, ")");
+} /* output_list */
+
+
+ void
+#ifdef KR_headers
+out_asgoto(outfile, expr)
+ FILE *outfile;
+ expptr expr;
+#else
+out_asgoto(FILE *outfile, expptr expr)
+#endif
+{
+ chainp value;
+ Namep namep;
+ int k;
+
+ if (expr == (expptr) NULL) {
+ err ("out_asgoto: NULL variable expr");
+ return;
+ } /* if expr */
+
+ nice_printf (outfile, Ansi ? "switch (" : "switch ((int)"); /*)*/
+ expr_out (outfile, expr);
+ nice_printf (outfile, ") {\n");
+ next_tab (outfile);
+
+/* The initial addrp value will be stored as a namep pointer */
+
+ switch(expr->tag) {
+ case TNAME:
+ /* local variable */
+ namep = &expr->nameblock;
+ break;
+ case TEXPR:
+ if (expr->exprblock.opcode == OPWHATSIN
+ && expr->exprblock.leftp->tag == TNAME)
+ /* argument */
+ namep = &expr->exprblock.leftp->nameblock;
+ else
+ goto bad;
+ break;
+ case TADDR:
+ if (expr->addrblock.uname_tag == UNAM_NAME) {
+ /* initialized local variable */
+ namep = expr->addrblock.user.name;
+ break;
+ }
+ default:
+ bad:
+ err("out_asgoto: bad expr");
+ return;
+ }
+
+ for(k = 0, value = namep -> varxptr.assigned_values; value;
+ value = value->nextp, k++) {
+ nice_printf (outfile, "case %d: goto %s;\n", k,
+ user_label((long)value->datap));
+ } /* for value */
+ prev_tab (outfile);
+
+ nice_printf (outfile, "}\n");
+} /* out_asgoto */
+
+ void
+#ifdef KR_headers
+out_if(outfile, expr)
+ FILE *outfile;
+ expptr expr;
+#else
+out_if(FILE *outfile, expptr expr)
+#endif
+{
+ nice_printf (outfile, "if (");
+ expr_out (outfile, expr);
+ nice_printf (outfile, ") {\n");
+ next_tab (outfile);
+} /* out_if */
+
+ static void
+#ifdef KR_headers
+output_rbrace(outfile, s)
+ FILE *outfile;
+ char *s;
+#else
+output_rbrace(FILE *outfile, char *s)
+#endif
+{
+ extern int last_was_label;
+ register char *fmt;
+
+ if (last_was_label) {
+ last_was_label = 0;
+ fmt = ";%s";
+ }
+ else
+ fmt = "%s";
+ nice_printf(outfile, fmt, s);
+ }
+
+ void
+#ifdef KR_headers
+out_else(outfile)
+ FILE *outfile;
+#else
+out_else(FILE *outfile)
+#endif
+{
+ prev_tab (outfile);
+ output_rbrace(outfile, "} else {\n");
+ next_tab (outfile);
+} /* out_else */
+
+ void
+#ifdef KR_headers
+elif_out(outfile, expr)
+ FILE *outfile;
+ expptr expr;
+#else
+elif_out(FILE *outfile, expptr expr)
+#endif
+{
+ prev_tab (outfile);
+ output_rbrace(outfile, "} else ");
+ out_if (outfile, expr);
+} /* elif_out */
+
+ void
+#ifdef KR_headers
+endif_out(outfile)
+ FILE *outfile;
+#else
+endif_out(FILE *outfile)
+#endif
+{
+ prev_tab (outfile);
+ output_rbrace(outfile, "}\n");
+} /* endif_out */
+
+ void
+#ifdef KR_headers
+end_else_out(outfile)
+ FILE *outfile;
+#else
+end_else_out(FILE *outfile)
+#endif
+{
+ prev_tab (outfile);
+ output_rbrace(outfile, "}\n");
+} /* end_else_out */
+
+
+
+ void
+#ifdef KR_headers
+compgoto_out(outfile, index, labels)
+ FILE *outfile;
+ expptr index;
+ expptr labels;
+#else
+compgoto_out(FILE *outfile, expptr index, expptr labels)
+#endif
+{
+ char *s1, *s2;
+
+ if (index == ENULL)
+ err ("compgoto_out: null index for computed goto");
+ else if (labels && labels -> tag != TLIST)
+ erri ("compgoto_out: expected label list, got tag '%d'",
+ labels -> tag);
+ else {
+ chainp elts;
+ int i = 1;
+
+ s2 = /*(*/ ") {\n"; /*}*/
+ if (Ansi)
+ s1 = "switch ("; /*)*/
+ else if (index->tag == TNAME || index->tag == TEXPR
+ && index->exprblock.opcode == OPWHATSIN)
+ s1 = "switch ((int)"; /*)*/
+ else {
+ s1 = "switch ((int)(";
+ s2 = ")) {\n"; /*}*/
+ }
+ nice_printf(outfile, s1);
+ expr_out (outfile, index);
+ nice_printf (outfile, s2);
+ next_tab (outfile);
+
+ for (elts = labels -> listblock.listp; elts; elts = elts -> nextp, i++) {
+ if (elts -> datap) {
+ if (ISICON(((expptr) (elts -> datap))))
+ nice_printf (outfile, "case %d: goto %s;\n", i,
+ user_label(((expptr)(elts->datap))->constblock.Const.ci));
+ else
+ err ("compgoto_out: bad label in label list");
+ } /* if (elts -> datap) */
+ } /* for elts */
+ prev_tab (outfile);
+ nice_printf (outfile, /*{*/ "}\n");
+ } /* else */
+} /* compgoto_out */
+
+
+ void
+#ifdef KR_headers
+out_for(outfile, init, test, inc)
+ FILE *outfile;
+ expptr init;
+ expptr test;
+ expptr inc;
+#else
+out_for(FILE *outfile, expptr init, expptr test, expptr inc)
+#endif
+{
+ nice_printf (outfile, "for (");
+ expr_out (outfile, init);
+ nice_printf (outfile, "; ");
+ expr_out (outfile, test);
+ nice_printf (outfile, "; ");
+ expr_out (outfile, inc);
+ nice_printf (outfile, ") {\n");
+ next_tab (outfile);
+} /* out_for */
+
+
+ void
+#ifdef KR_headers
+out_end_for(outfile)
+ FILE *outfile;
+#else
+out_end_for(FILE *outfile)
+#endif
+{
+ prev_tab (outfile);
+ nice_printf (outfile, "}\n");
+} /* out_end_for */
diff --git a/usr.bin/f2c/output.h b/usr.bin/f2c/output.h
new file mode 100644
index 0000000..97e3a0a
--- /dev/null
+++ b/usr.bin/f2c/output.h
@@ -0,0 +1,64 @@
+/* nice_printf -- same arguments as fprintf.
+
+ All output which is to become C code must be directed through this
+ function. For now, no buffering is done. Later on, every line of
+ output will be filtered to accomodate the style definitions (e.g. one
+ statement per line, spaces between function names and argument lists,
+ etc.)
+*/
+#include "niceprintf.h"
+
+
+/* Definitions for the opcode table. The table is indexed by the macros
+ which are #defined in defines.h */
+
+#define UNARY_OP 01
+#define BINARY_OP 02
+
+#define SPECIAL_FMT NULL
+
+#define is_unary_op(x) (opcode_table[x].type == UNARY_OP)
+#define is_binary_op(x) (opcode_table[x].type == BINARY_OP)
+#define op_precedence(x) (opcode_table[x].prec)
+#define op_format(x) (opcode_table[x].format)
+
+/* _assoc_table -- encodes left-associativity and right-associativity
+ information; indexed by precedence level. Only 2, 3, 14 are
+ right-associative. Source: Kernighan & Ritchie, p. 49 */
+
+extern char _assoc_table[];
+
+#define is_right_assoc(x) (_assoc_table [x])
+#define is_left_assoc(x) (! _assoc_table [x])
+
+
+typedef struct {
+ int type; /* UNARY_OP or BINARY_OP */
+ int prec; /* Precedence level, useful for adjusting
+ number of parens to insert. Zero is a
+ special level, and 2, 3, 14 are
+ right-associative */
+ char *format;
+} table_entry;
+
+
+extern char *fl_fmt_string; /* Float constant format string */
+extern char *db_fmt_string; /* Double constant format string */
+extern char *cm_fmt_string; /* Complex constant format string */
+extern char *dcm_fmt_string; /* Double Complex constant format string */
+
+extern int indent; /* Number of spaces to indent; this is a
+ temporary fix */
+extern int tab_size; /* Number of spaces in each tab */
+extern int in_string;
+
+extern table_entry opcode_table[];
+
+
+void compgoto_out Argdcl((FILEP, tagptr, tagptr));
+void endif_out Argdcl((FILEP));
+void expr_out Argdcl((FILEP, tagptr));
+void out_and_free_statement Argdcl((FILEP, tagptr));
+void out_end_for Argdcl((FILEP));
+void out_if Argdcl((FILEP, tagptr));
+void out_name Argdcl((FILEP, Namep));
diff --git a/usr.bin/f2c/p1defs.h b/usr.bin/f2c/p1defs.h
new file mode 100644
index 0000000..c76af22
--- /dev/null
+++ b/usr.bin/f2c/p1defs.h
@@ -0,0 +1,158 @@
+#define P1_UNKNOWN 0
+#define P1_COMMENT 1 /* Fortan comment string */
+#define P1_EOF 2 /* End of file dummy token */
+#define P1_SET_LINE 3 /* Reset the line counter */
+#define P1_FILENAME 4 /* Name of current input file */
+#define P1_NAME_POINTER 5 /* Pointer to hash table entry */
+#define P1_CONST 6 /* Some constant value */
+#define P1_EXPR 7 /* Followed by opcode */
+
+/* The next two tokens could be grouped together, since they always come
+ from an Addr structure */
+
+#define P1_IDENT 8 /* Char string identifier in addrp->user
+ field */
+#define P1_EXTERN 9 /* Pointer to external symbol entry */
+
+#define P1_HEAD 10 /* Function header info */
+#define P1_LIST 11 /* A list of data (e.g. arguments) will
+ follow the tag, type, and count */
+#define P1_LITERAL 12 /* Hold the index into the literal pool */
+#define P1_LABEL 13 /* label value */
+#define P1_ASGOTO 14 /* Store the hash table pointer of
+ variable used in assigned goto */
+#define P1_GOTO 15 /* Store the statement number */
+#define P1_IF 16 /* store the condition as an expression */
+#define P1_ELSE 17 /* No data */
+#define P1_ELIF 18 /* store the condition as an expression */
+#define P1_ENDIF 19 /* Marks the end of a block IF */
+#define P1_ENDELSE 20 /* Marks the end of a block ELSE */
+#define P1_ADDR 21 /* Addr data; used for arrays, common and
+ equiv addressing, NOT for names, idents
+ or externs */
+#define P1_SUBR_RET 22 /* Subroutine return; the return expression
+ follows */
+#define P1_COMP_GOTO 23 /* Computed goto; has expr, label list */
+#define P1_FOR 24 /* C FOR loop; three expressions follow */
+#define P1_ENDFOR 25 /* End of C FOR loop */
+#define P1_FORTRAN 26 /* original Fortran source */
+#define P1_CHARP 27 /* user.Charp field -- for long names */
+#define P1_WHILE1START 28 /* start of DO WHILE */
+#define P1_WHILE2START 29 /* rest of DO WHILE */
+#define P1_PROCODE 30 /* invoke procode() -- to adjust params */
+#define P1_ELSEIFSTART 31 /* handle extra code for abs, min, max
+ in else if() */
+
+#define P1_FILENAME_MAX 256 /* max filename length to retain (for -g) */
+#define P1_STMTBUFSIZE 1400
+
+
+
+#define COMMENT_BUFFER_SIZE 255 /* max number of chars in each comment */
+#define CONSTANT_STR_MAX 1000 /* max number of chars in string constant */
+
+void p1_asgoto Argdcl((Addrp));
+void p1_comment Argdcl((char*));
+void p1_elif Argdcl((tagptr));
+void p1_else Argdcl((void));
+void p1_endif Argdcl((void));
+void p1_expr Argdcl((tagptr));
+void p1_for Argdcl((tagptr, tagptr, tagptr));
+void p1_goto Argdcl((long int));
+void p1_head Argdcl((int, char*));
+void p1_if Argdcl((tagptr));
+void p1_label Argdcl((long int));
+void p1_line_number Argdcl((long int));
+void p1_subr_ret Argdcl((tagptr));
+void p1comp_goto Argdcl((tagptr, int, struct Labelblock**));
+void p1else_end Argdcl((void));
+void p1for_end Argdcl((void));
+void p1put Argdcl((int));
+void p1puts Argdcl((int, char*));
+
+/* The pass 1 intermediate file has the following format:
+
+ <ascii-integer-rep> [ : [ <sp> [ <data> ]]] \n
+
+ e.g. 1: This is a comment
+
+ This format is destined to change in the future, but for now a readable
+ form is more desirable than a compact form.
+
+ NOTES ABOUT THE P1 FORMAT
+ ----------------------------------------------------------------------
+
+ P1_COMMENT: The comment string (in <data>) may be at most
+ COMMENT_BUFFER_SIZE bytes long. It must contain no newlines
+ or null characters. A side effect of the way comments are
+ read in lex.c is that no '\377' chars may be in a
+ comment either.
+
+ P1_SET_LINE: <data> holds the line number in the current source file.
+
+ P1_INC_LINE: Increment the source line number; <data> is empty.
+
+ P1_NAME_POINTER: <data> holds the integer representation of a
+ pointer into a hash table entry.
+
+ P1_CONST: the first field in <data> is a type tag (one of the
+ TYxxxx macros), the next field holds the constant
+ value
+
+ P1_EXPR: <data> holds the opcode number of the expression,
+ followed by the type of the expression (required for
+ OPCONV). Next is the value of vleng.
+ The type of operation represented by the
+ opcode determines how many of the following data items
+ are part of this expression.
+
+ P1_IDENT: <data> holds the type, then storage, then the
+ char string identifier in the addrp->user field.
+
+ P1_EXTERN: <data> holds an offset into the external symbol
+ table entry
+
+ P1_HEAD: the first field in <data> is the procedure class, the
+ second is the name of the procedure
+
+ P1_LIST: the first field in <data> is the tag, the second the
+ type of the list, the third the number of elements in
+ the list
+
+ P1_LITERAL: <data> holds the litnum of a value in the
+ literal pool.
+
+ P1_LABEL: <data> holds the statement number of the current
+ line
+
+ P1_ASGOTO: <data> holds the hash table pointer of the variable
+
+ P1_GOTO: <data> holds the statement number to jump to
+
+ P1_IF: <data> is empty, the following expression is the IF
+ condition.
+
+ P1_ELSE: <data> is empty.
+
+ P1_ELIF: <data> is empty, the following expression is the IF
+ condition.
+
+ P1_ENDIF: <data> is empty.
+
+ P1_ENDELSE: <data> is empty.
+
+ P1_ADDR: <data> holds a direct copy of the structure. The
+ next expression is a copy of vleng, and the next a
+ copy of memoffset.
+
+ P1_SUBR_RET: The next token is an expression for the return value.
+
+ P1_COMP_GOTO: The next token is an integer expression, the
+ following one a list of labels.
+
+ P1_FOR: The next three expressions are the Init, Test, and
+ Increment expressions of a C FOR loop.
+
+ P1_ENDFOR: Marks the end of the body of a FOR loop
+
+*/
diff --git a/usr.bin/f2c/p1output.c b/usr.bin/f2c/p1output.c
new file mode 100644
index 0000000..93204ab
--- /dev/null
+++ b/usr.bin/f2c/p1output.c
@@ -0,0 +1,723 @@
+/****************************************************************
+Copyright 1990, 1991, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "p1defs.h"
+#include "output.h"
+#include "names.h"
+
+
+static void p1_addr Argdcl((Addrp));
+static void p1_big_addr Argdcl((Addrp));
+static void p1_binary Argdcl((Exprp));
+static void p1_const Argdcl((Constp));
+static void p1_list Argdcl((struct Listblock*));
+static void p1_literal Argdcl((long int));
+static void p1_name Argdcl((Namep));
+static void p1_unary Argdcl((Exprp));
+static void p1putd Argdcl((int, long int));
+static void p1putdd Argdcl((int, int, int));
+static void p1putddd Argdcl((int, int, int, int));
+static void p1putdds Argdcl((int, int, int, char*));
+static void p1putds Argdcl((int, int, char*));
+static void p1putn Argdcl((int, int, char*));
+
+
+/* p1_comment -- save the text of a Fortran comment in the intermediate
+ file. Make sure that there are no spurious "/ *" or "* /" characters by
+ mapping them onto "/+" and "+/". str is assumed to hold no newlines and be
+ null terminated; it may be modified by this function. */
+
+ void
+#ifdef KR_headers
+p1_comment(str)
+ char *str;
+#else
+p1_comment(char *str)
+#endif
+{
+ register unsigned char *pointer, *ustr;
+
+ if (!str)
+ return;
+
+/* Get rid of any open or close comment combinations that may be in the
+ Fortran input */
+
+ ustr = (unsigned char *)str;
+ for(pointer = ustr; *pointer; pointer++)
+ if (*pointer == '*' && (pointer[1] == '/'
+ || pointer > ustr && pointer[-1] == '/'))
+ *pointer = '+';
+ /* trim trailing white space */
+#ifdef isascii
+ while(--pointer >= ustr && (!isascii(*pointer) || isspace(*pointer)));
+#else
+ while(--pointer >= ustr && isspace(*pointer));
+#endif
+ pointer[1] = 0;
+ p1puts (P1_COMMENT, str);
+} /* p1_comment */
+
+/* p1_name -- Writes the address of a hash table entry into the
+ intermediate file */
+
+ static void
+#ifdef KR_headers
+p1_name(namep)
+ Namep namep;
+#else
+p1_name(Namep namep)
+#endif
+{
+ p1putd (P1_NAME_POINTER, (long) namep);
+ namep->visused = 1;
+} /* p1_name */
+
+
+
+ void
+#ifdef KR_headers
+p1_expr(expr)
+ expptr expr;
+#else
+p1_expr(expptr expr)
+#endif
+{
+/* An opcode of 0 means a null entry */
+
+ if (expr == ENULL) {
+ p1putdd (P1_EXPR, 0, TYUNKNOWN); /* Should this be TYERROR? */
+ return;
+ } /* if (expr == ENULL) */
+
+ switch (expr -> tag) {
+ case TNAME:
+ p1_name ((Namep) expr);
+ return;
+ case TCONST:
+ p1_const(&expr->constblock);
+ return;
+ case TEXPR:
+ /* Fall through the switch */
+ break;
+ case TADDR:
+ p1_addr (&(expr -> addrblock));
+ goto freeup;
+ case TPRIM:
+ warn ("p1_expr: got TPRIM");
+ return;
+ case TLIST:
+ p1_list (&(expr->listblock));
+ frchain( &(expr->listblock.listp) );
+ return;
+ case TERROR:
+ return;
+ default:
+ erri ("p1_expr: bad tag '%d'", (int) (expr -> tag));
+ return;
+ }
+
+/* Now we know that the tag is TEXPR */
+
+ if (is_unary_op (expr -> exprblock.opcode))
+ p1_unary (&(expr -> exprblock));
+ else if (is_binary_op (expr -> exprblock.opcode))
+ p1_binary (&(expr -> exprblock));
+ else
+ erri ("p1_expr: bad opcode '%d'", (int) expr -> exprblock.opcode);
+ freeup:
+ free((char *)expr);
+
+} /* p1_expr */
+
+
+
+ static void
+#ifdef KR_headers
+p1_const(cp)
+ register Constp cp;
+#else
+p1_const(register Constp cp)
+#endif
+{
+ int type = cp->vtype;
+ expptr vleng = cp->vleng;
+ union Constant *c = &cp->Const;
+ char cdsbuf0[64], cdsbuf1[64];
+ char *cds0, *cds1;
+
+ switch (type) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYLOGICAL:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ fprintf(pass1_file, "%d: %d %ld\n", P1_CONST, type, c->ci);
+ break;
+ case TYREAL:
+ case TYDREAL:
+ fprintf(pass1_file, "%d: %d %s\n", P1_CONST, type,
+ cp->vstg ? c->cds[0] : cds(dtos(c->cd[0]), cdsbuf0));
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ if (cp->vstg) {
+ cds0 = c->cds[0];
+ cds1 = c->cds[1];
+ }
+ else {
+ cds0 = cds(dtos(c->cd[0]), cdsbuf0);
+ cds1 = cds(dtos(c->cd[1]), cdsbuf1);
+ }
+ fprintf(pass1_file, "%d: %d %s %s\n", P1_CONST, type,
+ cds0, cds1);
+ break;
+ case TYCHAR:
+ if (vleng && !ISICON (vleng))
+ erri("p1_const: bad vleng '%d'\n", (int) vleng);
+ else
+ fprintf(pass1_file, "%d: %d %lx\n", P1_CONST, type,
+ cpexpr((expptr)cp));
+ break;
+ default:
+ erri ("p1_const: bad constant type '%d'", type);
+ break;
+ } /* switch */
+} /* p1_const */
+
+
+ void
+#ifdef KR_headers
+p1_asgoto(addrp)
+ Addrp addrp;
+#else
+p1_asgoto(Addrp addrp)
+#endif
+{
+ p1put (P1_ASGOTO);
+ p1_addr (addrp);
+} /* p1_asgoto */
+
+
+ void
+#ifdef KR_headers
+p1_goto(stateno)
+ ftnint stateno;
+#else
+p1_goto(ftnint stateno)
+#endif
+{
+ p1putd (P1_GOTO, stateno);
+} /* p1_goto */
+
+
+ static void
+#ifdef KR_headers
+p1_addr(addrp)
+ register struct Addrblock *addrp;
+#else
+p1_addr(register struct Addrblock *addrp)
+#endif
+{
+ int stg;
+
+ if (addrp == (struct Addrblock *) NULL)
+ return;
+
+ stg = addrp -> vstg;
+
+ if (ONEOF(stg, M(STGINIT)|M(STGREG))
+ || ONEOF(stg, M(STGCOMMON)|M(STGEQUIV)) &&
+ (!ISICON(addrp->memoffset)
+ || (addrp->uname_tag == UNAM_NAME
+ ? addrp->memoffset->constblock.Const.ci
+ != addrp->user.name->voffset
+ : addrp->memoffset->constblock.Const.ci))
+ || ONEOF(stg, M(STGBSS)|M(STGINIT)|M(STGAUTO)|M(STGARG)) &&
+ (!ISICON(addrp->memoffset)
+ || addrp->memoffset->constblock.Const.ci)
+ || addrp->Field || addrp->isarray || addrp->vstg == STGLENG)
+ {
+ p1_big_addr (addrp);
+ return;
+ }
+
+/* Write out a level of indirection for non-array arguments, which have
+ addrp -> memoffset set and are handled by p1_big_addr().
+ Lengths are passed by value, so don't check STGLENG
+ 28-Jun-89 (dmg) Added the check for != TYCHAR
+ */
+
+ if (oneof_stg ( addrp -> uname_tag == UNAM_NAME ? addrp -> user.name : NULL,
+ stg, M(STGARG)|M(STGEQUIV)) && addrp->vtype != TYCHAR) {
+ p1putdd (P1_EXPR, OPWHATSIN, addrp -> vtype);
+ p1_expr (ENULL); /* Put dummy vleng */
+ } /* if stg == STGARG */
+
+ switch (addrp -> uname_tag) {
+ case UNAM_NAME:
+ p1_name (addrp -> user.name);
+ break;
+ case UNAM_IDENT:
+ p1putdds(P1_IDENT, addrp->vtype, addrp->vstg,
+ addrp->user.ident);
+ break;
+ case UNAM_CHARP:
+ p1putdds(P1_CHARP, addrp->vtype, addrp->vstg,
+ addrp->user.Charp);
+ break;
+ case UNAM_EXTERN:
+ p1putd (P1_EXTERN, (long) addrp -> memno);
+ if (addrp->vclass == CLPROC)
+ extsymtab[addrp->memno].extype = addrp->vtype;
+ break;
+ case UNAM_CONST:
+ if (addrp -> memno != BAD_MEMNO)
+ p1_literal (addrp -> memno);
+ else
+ p1_const((struct Constblock *)addrp);
+ break;
+ case UNAM_UNKNOWN:
+ default:
+ erri ("p1_addr: unknown uname_tag '%d'", addrp -> uname_tag);
+ break;
+ } /* switch */
+} /* p1_addr */
+
+
+ static void
+#ifdef KR_headers
+p1_list(listp)
+ struct Listblock *listp;
+#else
+p1_list(struct Listblock *listp)
+#endif
+{
+ chainp lis;
+ int count = 0;
+
+ if (listp == (struct Listblock *) NULL)
+ return;
+
+/* Count the number of parameters in the list */
+
+ for (lis = listp -> listp; lis; lis = lis -> nextp)
+ count++;
+
+ p1putddd (P1_LIST, listp -> tag, listp -> vtype, count);
+
+ for (lis = listp -> listp; lis; lis = lis -> nextp)
+ p1_expr ((expptr) lis -> datap);
+
+} /* p1_list */
+
+
+ void
+#ifdef KR_headers
+p1_label(lab)
+ long lab;
+#else
+p1_label(long lab)
+#endif
+{
+ if (parstate < INDATA)
+ earlylabs = mkchain((char *)lab, earlylabs);
+ else
+ p1putd (P1_LABEL, lab);
+ }
+
+
+
+ static void
+#ifdef KR_headers
+p1_literal(memno)
+ long memno;
+#else
+p1_literal(long memno)
+#endif
+{
+ p1putd (P1_LITERAL, memno);
+} /* p1_literal */
+
+
+ void
+#ifdef KR_headers
+p1_if(expr)
+ expptr expr;
+#else
+p1_if(expptr expr)
+#endif
+{
+ p1put (P1_IF);
+ p1_expr (expr);
+} /* p1_if */
+
+
+
+
+ void
+#ifdef KR_headers
+p1_elif(expr)
+ expptr expr;
+#else
+p1_elif(expptr expr)
+#endif
+{
+ p1put (P1_ELIF);
+ p1_expr (expr);
+} /* p1_elif */
+
+
+
+
+ void
+p1_else(Void)
+{
+ p1put (P1_ELSE);
+} /* p1_else */
+
+
+
+
+ void
+p1_endif(Void)
+{
+ p1put (P1_ENDIF);
+} /* p1_endif */
+
+
+
+
+ void
+p1else_end(Void)
+{
+ p1put (P1_ENDELSE);
+} /* p1else_end */
+
+
+ static void
+#ifdef KR_headers
+p1_big_addr(addrp)
+ Addrp addrp;
+#else
+p1_big_addr(Addrp addrp)
+#endif
+{
+ if (addrp == (Addrp) NULL)
+ return;
+
+ p1putn (P1_ADDR, (int)sizeof(struct Addrblock), (char *) addrp);
+ p1_expr (addrp -> vleng);
+ p1_expr (addrp -> memoffset);
+ if (addrp->uname_tag == UNAM_NAME)
+ addrp->user.name->visused = 1;
+} /* p1_big_addr */
+
+
+
+ static void
+#ifdef KR_headers
+p1_unary(e)
+ struct Exprblock *e;
+#else
+p1_unary(struct Exprblock *e)
+#endif
+{
+ if (e == (struct Exprblock *) NULL)
+ return;
+
+ p1putdd (P1_EXPR, (int) e -> opcode, e -> vtype);
+ p1_expr (e -> vleng);
+
+ switch (e -> opcode) {
+ case OPNEG:
+ case OPNEG1:
+ case OPNOT:
+ case OPABS:
+ case OPBITNOT:
+ case OPPREINC:
+ case OPPREDEC:
+ case OPADDR:
+ case OPIDENTITY:
+ case OPCHARCAST:
+ case OPDABS:
+ p1_expr(e -> leftp);
+ break;
+ default:
+ erri ("p1_unary: bad opcode '%d'", (int) e -> opcode);
+ break;
+ } /* switch */
+
+} /* p1_unary */
+
+
+ static void
+#ifdef KR_headers
+p1_binary(e)
+ struct Exprblock *e;
+#else
+p1_binary(struct Exprblock *e)
+#endif
+{
+ if (e == (struct Exprblock *) NULL)
+ return;
+
+ p1putdd (P1_EXPR, e -> opcode, e -> vtype);
+ p1_expr (e -> vleng);
+ p1_expr (e -> leftp);
+ p1_expr (e -> rightp);
+} /* p1_binary */
+
+
+ void
+#ifdef KR_headers
+p1_head(class, name)
+ int class;
+ char *name;
+#else
+p1_head(int class, char *name)
+#endif
+{
+ p1putds (P1_HEAD, class, name ? name : "");
+} /* p1_head */
+
+
+ void
+#ifdef KR_headers
+p1_subr_ret(retexp)
+ expptr retexp;
+#else
+p1_subr_ret(expptr retexp)
+#endif
+{
+
+ p1put (P1_SUBR_RET);
+ p1_expr (cpexpr(retexp));
+} /* p1_subr_ret */
+
+
+
+ void
+#ifdef KR_headers
+p1comp_goto(index, count, labels)
+ expptr index;
+ int count;
+ struct Labelblock **labels;
+#else
+p1comp_goto(expptr index, int count, struct Labelblock **labels)
+#endif
+{
+ struct Constblock c;
+ int i;
+ register struct Labelblock *L;
+
+ p1put (P1_COMP_GOTO);
+ p1_expr (index);
+
+/* Write out a P1_LIST directly, to avoid the overhead of allocating a
+ list before it's needed HACK HACK HACK */
+
+ p1putddd (P1_LIST, TLIST, TYUNKNOWN, count);
+ c.vtype = TYLONG;
+ c.vleng = 0;
+
+ for (i = 0; i < count; i++) {
+ L = labels[i];
+ L->labused = 1;
+ c.Const.ci = L->stateno;
+ p1_const(&c);
+ } /* for i = 0 */
+} /* p1comp_goto */
+
+
+
+ void
+#ifdef KR_headers
+p1_for(init, test, inc)
+ expptr init;
+ expptr test;
+ expptr inc;
+#else
+p1_for(expptr init, expptr test, expptr inc)
+#endif
+{
+ p1put (P1_FOR);
+ p1_expr (init);
+ p1_expr (test);
+ p1_expr (inc);
+} /* p1_for */
+
+
+ void
+p1for_end(Void)
+{
+ p1put (P1_ENDFOR);
+} /* p1for_end */
+
+
+
+
+/* ----------------------------------------------------------------------
+ The intermediate file actually gets written ONLY by the routines below.
+ To change the format of the file, you need only change these routines.
+ ----------------------------------------------------------------------
+*/
+
+
+/* p1puts -- Put a typed string into the Pass 1 intermediate file. Assumes that
+ str contains no newlines and is null-terminated. */
+
+ void
+#ifdef KR_headers
+p1puts(type, str)
+ int type;
+ char *str;
+#else
+p1puts(int type, char *str)
+#endif
+{
+ fprintf (pass1_file, "%d: %s\n", type, str);
+} /* p1puts */
+
+
+/* p1putd -- Put a typed integer into the Pass 1 intermediate file. */
+
+ static void
+#ifdef KR_headers
+p1putd(type, value)
+ int type;
+ long value;
+#else
+p1putd(int type, long value)
+#endif
+{
+ fprintf (pass1_file, "%d: %ld\n", type, value);
+} /* p1_putd */
+
+
+/* p1putdd -- Put a typed pair of integers into the intermediate file. */
+
+ static void
+#ifdef KR_headers
+p1putdd(type, v1, v2)
+ int type;
+ int v1;
+ int v2;
+#else
+p1putdd(int type, int v1, int v2)
+#endif
+{
+ fprintf (pass1_file, "%d: %d %d\n", type, v1, v2);
+} /* p1putdd */
+
+
+/* p1putddd -- Put a typed triple of integers into the intermediate file. */
+
+ static void
+#ifdef KR_headers
+p1putddd(type, v1, v2, v3)
+ int type;
+ int v1;
+ int v2;
+ int v3;
+#else
+p1putddd(int type, int v1, int v2, int v3)
+#endif
+{
+ fprintf (pass1_file, "%d: %d %d %d\n", type, v1, v2, v3);
+} /* p1putddd */
+
+ union dL {
+ double d;
+ long L[2];
+ };
+
+ static void
+#ifdef KR_headers
+p1putn(type, count, str)
+ int type;
+ int count;
+ char *str;
+#else
+p1putn(int type, int count, char *str)
+#endif
+{
+ int i;
+
+ fprintf (pass1_file, "%d: ", type);
+
+ for (i = 0; i < count; i++)
+ putc (str[i], pass1_file);
+
+ putc ('\n', pass1_file);
+} /* p1putn */
+
+
+
+/* p1put -- Put a type marker into the intermediate file. */
+
+ void
+#ifdef KR_headers
+p1put(type)
+ int type;
+#else
+p1put(int type)
+#endif
+{
+ fprintf (pass1_file, "%d:\n", type);
+} /* p1put */
+
+
+
+ static void
+#ifdef KR_headers
+p1putds(type, i, str)
+ int type;
+ int i;
+ char *str;
+#else
+p1putds(int type, int i, char *str)
+#endif
+{
+ fprintf (pass1_file, "%d: %d %s\n", type, i, str);
+} /* p1putds */
+
+
+ static void
+#ifdef KR_headers
+p1putdds(token, type, stg, str)
+ int token;
+ int type;
+ int stg;
+ char *str;
+#else
+p1putdds(int token, int type, int stg, char *str)
+#endif
+{
+ fprintf (pass1_file, "%d: %d %d %s\n", token, type, stg, str);
+} /* p1putdds */
diff --git a/usr.bin/f2c/parse.h b/usr.bin/f2c/parse.h
new file mode 100644
index 0000000..6de2399
--- /dev/null
+++ b/usr.bin/f2c/parse.h
@@ -0,0 +1,47 @@
+#ifndef PARSE_INCLUDE
+#define PARSE_INCLUDE
+
+/* macros for the parse_args routine */
+
+#define P_STRING 1 /* Macros for the result_type attribute */
+#define P_CHAR 2
+#define P_SHORT 3
+#define P_INT 4
+#define P_LONG 5
+#define P_FILE 6
+#define P_OLD_FILE 7
+#define P_NEW_FILE 8
+#define P_FLOAT 9
+#define P_DOUBLE 10
+
+#define P_CASE_INSENSITIVE 01 /* Macros for the flags attribute */
+#define P_REQUIRED_PREFIX 02
+
+#define P_NO_ARGS 0 /* Macros for the arg_count attribute */
+#define P_ONE_ARG 1
+#define P_INFINITE_ARGS 2
+
+#define p_entry(pref,swit,flag,count,type,store,size) \
+ { (pref), (swit), (flag), (count), (type), (int *) (store), (size) }
+
+typedef struct {
+ char *prefix;
+ char *string;
+ int flags;
+ int count;
+ int result_type;
+ int *result_ptr;
+ int table_size;
+} arg_info;
+
+#ifdef KR_headers
+#define Argdcl(x) ()
+#else
+#define Argdcl(x) x
+#endif
+int arg_verify Argdcl((char**, arg_info*, int));
+void init_store Argdcl((arg_info*, int));
+int match_table Argdcl((char*, arg_info*, int, int, int*));
+int parse_args Argdcl((int, char**, arg_info*, int, char**, int));
+
+#endif
diff --git a/usr.bin/f2c/parse_args.c b/usr.bin/f2c/parse_args.c
new file mode 100644
index 0000000..b6dc75d
--- /dev/null
+++ b/usr.bin/f2c/parse_args.c
@@ -0,0 +1,557 @@
+/****************************************************************
+Copyright 1990, 1994-5 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* parse_args
+
+ This function will parse command line input into appropriate data
+ structures, output error messages when appropriate and provide some
+ minimal type conversion.
+
+ Input to the function consists of the standard argc,argv
+ values, and a table which directs the parser. Each table entry has the
+ following components:
+
+ prefix -- the (optional) switch character string, e.g. "-" "/" "="
+ switch -- the command string, e.g. "o" "data" "file" "F"
+ flags -- control flags, e.g. CASE_INSENSITIVE, REQUIRED_PREFIX
+ arg_count -- number of arguments this command requires, e.g. 0 for
+ booleans, 1 for filenames, INFINITY for input files
+ result_type -- how to interpret the switch arguments, e.g. STRING,
+ CHAR, FILE, OLD_FILE, NEW_FILE
+ result_ptr -- pointer to storage for the result, be it a table or
+ a string or whatever
+ table_size -- if the arguments fill a table, the maximum number of
+ entries; if there are no arguments, the value to
+ load into the result storage
+
+ Although the table can be used to hold a list of filenames, only
+ scalar values (e.g. pointers) can be stored in the table. No vector
+ processing will be done, only pointers to string storage will be moved.
+
+ An example entry, which could be used to parse input filenames, is:
+
+ "-", "o", 0, oo, OLD_FILE, infilenames, INFILE_TABLE_SIZE
+
+*/
+
+#include <stdio.h>
+#ifndef NULL
+/* ANSI C */
+#include <stddef.h>
+#endif
+#ifdef KR_headers
+extern double atof();
+#else
+#include "stdlib.h"
+#include "string.h"
+#endif
+#include "parse.h"
+#include <math.h> /* For atof */
+#include <ctype.h>
+
+#define MAX_INPUT_SIZE 1000
+
+#define arg_prefix(x) ((x).prefix)
+#define arg_string(x) ((x).string)
+#define arg_flags(x) ((x).flags)
+#define arg_count(x) ((x).count)
+#define arg_result_type(x) ((x).result_type)
+#define arg_result_ptr(x) ((x).result_ptr)
+#define arg_table_size(x) ((x).table_size)
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+typedef int boolean;
+
+
+static char *this_program = "";
+
+static int arg_parse Argdcl((char*, arg_info*));
+static char *lower_string Argdcl((char*, char*));
+static int match Argdcl((char*, char*, arg_info*, boolean));
+static int put_one_arg Argdcl((int, char*, char**, char*, char*));
+extern int badargs;
+
+
+ boolean
+#ifdef KR_headers
+parse_args(argc, argv, table, entries, others, other_count)
+ int argc;
+ char **argv;
+ arg_info *table;
+ int entries;
+ char **others;
+ int other_count;
+#else
+parse_args(int argc, char **argv, arg_info *table, int entries, char **others, int other_count)
+#endif
+{
+ boolean result;
+
+ if (argv)
+ this_program = argv[0];
+
+/* Check the validity of the table and its parameters */
+
+ result = arg_verify (argv, table, entries);
+
+/* Initialize the storage values */
+
+ init_store (table, entries);
+
+ if (result) {
+ boolean use_prefix = TRUE;
+ char *argv0;
+
+ argc--;
+ argv0 = *++argv;
+ while (argc) {
+ int index, length;
+
+ index = match_table (*argv, table, entries, use_prefix, &length);
+ if (index < 0) {
+
+/* The argument doesn't match anything in the table */
+
+ if (others) {
+
+ if (*argv > argv0)
+ *--*argv = '-'; /* complain at invalid flag */
+
+ if (other_count > 0) {
+ *others++ = *argv;
+ other_count--;
+ } else {
+ fprintf (stderr, "%s: too many parameters: ",
+ this_program);
+ fprintf (stderr, "'%s' ignored\n", *argv);
+ badargs++;
+ } /* else */
+ } /* if (others) */
+ argv0 = *++argv;
+ argc--;
+ } else {
+
+/* A match was found */
+
+ if (length >= strlen (*argv)) {
+ argc--;
+ argv0 = *++argv;
+ use_prefix = TRUE;
+ } else {
+ (*argv) += length;
+ use_prefix = FALSE;
+ } /* else */
+
+/* Parse any necessary arguments */
+
+ if (arg_count (table[index]) != P_NO_ARGS) {
+
+/* Now length will be used to store the number of parsed characters */
+
+ length = arg_parse(*argv, &table[index]);
+ if (*argv == NULL)
+ argc = 0;
+ else if (length >= strlen (*argv)) {
+ argc--;
+ argv0 = *++argv;
+ use_prefix = TRUE;
+ } else {
+ (*argv) += length;
+ use_prefix = FALSE;
+ } /* else */
+ } /* if (argv_count != P_NO_ARGS) */
+ else
+ *arg_result_ptr(table[index]) =
+ arg_table_size(table[index]);
+ } /* else */
+ } /* while (argc) */
+ } /* if (result) */
+
+ return result;
+} /* parse_args */
+
+
+ boolean
+#ifdef KR_headers
+arg_verify(argv, table, entries)
+ char **argv;
+ arg_info *table;
+ int entries;
+#else
+arg_verify(char **argv, arg_info *table, int entries)
+#endif
+{
+ int i;
+ char *this_program = "";
+
+ if (argv)
+ this_program = argv[0];
+
+ for (i = 0; i < entries; i++) {
+ arg_info *arg = &table[i];
+
+/* Check the argument flags */
+
+ if (arg_flags (*arg) & ~(P_CASE_INSENSITIVE | P_REQUIRED_PREFIX)) {
+ fprintf (stderr, "%s [arg_verify]: too many ", this_program);
+ fprintf (stderr, "flags in entry %d: '%x' (hex)\n", i,
+ arg_flags (*arg));
+ badargs++;
+ } /* if */
+
+/* Check the argument count */
+
+ { int count = arg_count (*arg);
+
+ if (count != P_NO_ARGS && count != P_ONE_ARG && count !=
+ P_INFINITE_ARGS) {
+ fprintf (stderr, "%s [arg_verify]: invalid ", this_program);
+ fprintf (stderr, "argument count in entry %d: '%d'\n", i,
+ count);
+ badargs++;
+ } /* if count != P_NO_ARGS ... */
+
+/* Check the result field; want to be able to store results */
+
+ else
+ if (arg_result_ptr (*arg) == (int *) NULL) {
+ fprintf (stderr, "%s [arg_verify]: ", this_program);
+ fprintf (stderr, "no argument storage given for ");
+ fprintf (stderr, "entry %d\n", i);
+ badargs++;
+ } /* if arg_result_ptr */
+ }
+
+/* Check the argument type */
+
+ { int type = arg_result_type (*arg);
+
+ if (type < P_STRING || type > P_DOUBLE) {
+ fprintf(stderr,
+ "%s [arg_verify]: bad arg type in entry %d: '%d'\n",
+ this_program, i, type);
+ badargs++;
+ }
+ }
+
+/* Check table size */
+
+ { int size = arg_table_size (*arg);
+
+ if (arg_count (*arg) == P_INFINITE_ARGS && size < 1) {
+ fprintf (stderr, "%s [arg_verify]: bad ", this_program);
+ fprintf (stderr, "table size in entry %d: '%d'\n", i,
+ size);
+ badargs++;
+ } /* if (arg_count == P_INFINITE_ARGS && size < 1) */
+ }
+
+ } /* for i = 0 */
+
+ return TRUE;
+} /* arg_verify */
+
+
+/* match_table -- returns the index of the best entry matching the input,
+ -1 if no match. The best match is the one of longest length which
+ appears lowest in the table. The length of the match will be returned
+ in length ONLY IF a match was found. */
+
+ int
+#ifdef KR_headers
+match_table(norm_input, table, entries, use_prefix, length)
+ register char *norm_input;
+ arg_info *table;
+ int entries;
+ boolean use_prefix;
+ int *length;
+#else
+match_table(register char *norm_input, arg_info *table, int entries, boolean use_prefix, int *length)
+#endif
+{
+ char low_input[MAX_INPUT_SIZE];
+ register int i;
+ int best_index = -1, best_length = 0;
+
+/* FUNCTION BODY */
+
+ (void) lower_string (low_input, norm_input);
+
+ for (i = 0; i < entries; i++) {
+ int this_length = match(norm_input, low_input, &table[i], use_prefix);
+
+ if (this_length > best_length) {
+ best_index = i;
+ best_length = this_length;
+ } /* if (this_length > best_length) */
+ } /* for (i = 0) */
+
+ if (best_index > -1 && length != (int *) NULL)
+ *length = best_length;
+
+ return best_index;
+} /* match_table */
+
+
+/* match -- takes an input string and table entry, and returns the length
+ of the longer match.
+
+ 0 ==> input doesn't match
+
+ For example:
+
+ INPUT PREFIX STRING RESULT
+----------------------------------------------------------------------
+ "abcd" "-" "d" 0
+ "-d" "-" "d" 2 (i.e. "-d")
+ "dout" "-" "d" 1 (i.e. "d")
+ "-d" "" "-d" 2 (i.e. "-d")
+ "dd" "d" "d" 2 <= here's the weird one
+*/
+
+ static int
+#ifdef KR_headers
+match(norm_input, low_input, entry, use_prefix)
+ char *norm_input;
+ char *low_input;
+ arg_info *entry;
+ boolean use_prefix;
+#else
+match(char *norm_input, char *low_input, arg_info *entry, boolean use_prefix)
+#endif
+{
+ char *norm_prefix = arg_prefix (*entry);
+ char *norm_string = arg_string (*entry);
+ boolean prefix_match = FALSE, string_match = FALSE;
+ int result = 0;
+
+/* Buffers for the lowercased versions of the strings being compared.
+ These are used when the switch is to be case insensitive */
+
+ static char low_prefix[MAX_INPUT_SIZE];
+ static char low_string[MAX_INPUT_SIZE];
+ int prefix_length = strlen (norm_prefix);
+ int string_length = strlen (norm_string);
+
+/* Pointers for the required strings (lowered or nonlowered) */
+
+ register char *input, *prefix, *string;
+
+/* FUNCTION BODY */
+
+/* Use the appropriate strings to handle case sensitivity */
+
+ if (arg_flags (*entry) & P_CASE_INSENSITIVE) {
+ input = low_input;
+ prefix = lower_string (low_prefix, norm_prefix);
+ string = lower_string (low_string, norm_string);
+ } else {
+ input = norm_input;
+ prefix = norm_prefix;
+ string = norm_string;
+ } /* else */
+
+/* First, check the string formed by concatenating the prefix onto the
+ switch string, but only when the prefix is not being ignored */
+
+ if (use_prefix && prefix != NULL && *prefix != '\0')
+ prefix_match = (strncmp (input, prefix, prefix_length) == 0) &&
+ (strncmp (input + prefix_length, string, string_length) == 0);
+
+/* Next, check just the switch string, if that's allowed */
+
+ if (!use_prefix && (arg_flags (*entry) & P_REQUIRED_PREFIX) == 0)
+ string_match = strncmp (input, string, string_length) == 0;
+
+ if (prefix_match)
+ result = prefix_length + string_length;
+ else if (string_match)
+ result = string_length;
+
+ return result;
+} /* match */
+
+
+ static char *
+#ifdef KR_headers
+lower_string(dest, src)
+ char *dest;
+ char *src;
+#else
+lower_string(char *dest, char *src)
+#endif
+{
+ char *result = dest;
+ register int c;
+
+ if (dest == NULL || src == NULL)
+ result = NULL;
+ else
+ while (*dest++ = (c = *src++) >= 'A' && c <= 'Z' ? tolower(c) : c);
+
+ return result;
+} /* lower_string */
+
+
+/* arg_parse -- returns the number of characters parsed for this entry */
+
+ static int
+#ifdef KR_headers
+arg_parse(str, entry)
+ char *str;
+ arg_info *entry;
+#else
+arg_parse(char *str, arg_info *entry)
+#endif
+{
+ int length = 0;
+
+ if (arg_count (*entry) == P_ONE_ARG) {
+ char **store = (char **) arg_result_ptr (*entry);
+
+ length = put_one_arg (arg_result_type (*entry), str, store,
+ arg_prefix (*entry), arg_string (*entry));
+
+ } /* if (arg_count == P_ONE_ARG) */
+ else { /* Must be a table of arguments */
+ char **store = (char **) arg_result_ptr (*entry);
+
+ if (store) {
+ while (*store)
+ store++;
+
+ length = put_one_arg(arg_result_type (*entry), str, store++,
+ arg_prefix (*entry), arg_string (*entry));
+
+ *store = (char *) NULL;
+ } /* if (store) */
+ } /* else */
+
+ return length;
+} /* arg_parse */
+
+
+ static int
+#ifdef KR_headers
+put_one_arg(type, str, store, prefix, string)
+ int type;
+ char *str;
+ char **store;
+ char *prefix;
+ char *string;
+#else
+put_one_arg(int type, char *str, char **store, char *prefix, char *string)
+#endif
+{
+ int length = 0;
+ long L;
+
+ if (store) {
+ switch (type) {
+ case P_STRING:
+ case P_FILE:
+ case P_OLD_FILE:
+ case P_NEW_FILE:
+ if (str == NULL) {
+ fprintf(stderr, "%s: Missing argument after '%s%s'\n",
+ this_program, prefix, string);
+ length = 0;
+ badargs++;
+ }
+ else
+ length = strlen(*store = str);
+ break;
+ case P_CHAR:
+ *((char *) store) = *str;
+ length = 1;
+ break;
+ case P_SHORT:
+ L = atol(str);
+ *(short *)store = (short) L;
+ if (L != *(short *)store) {
+ fprintf(stderr,
+ "%s%s parameter '%ld' is not a SHORT INT (truncating to %d)\n",
+ prefix, string, L, *(short *)store);
+ badargs++;
+ }
+ length = strlen (str);
+ break;
+ case P_INT:
+ L = atol(str);
+ *(int *)store = (int)L;
+ if (L != *(int *)store) {
+ fprintf(stderr,
+ "%s%s parameter '%ld' is not an INT (truncating to %d)\n",
+ prefix, string, L, *(int *)store);
+ badargs++;
+ }
+ length = strlen (str);
+ break;
+ case P_LONG:
+ *(long *)store = atol(str);
+ length = strlen (str);
+ break;
+ case P_FLOAT:
+ *((float *) store) = (float) atof(str);
+ length = strlen (str);
+ break;
+ case P_DOUBLE:
+ *((double *) store) = (double) atof(str);
+ length = strlen (str);
+ break;
+ default:
+ fprintf (stderr, "put_one_arg: bad type '%d'\n", type);
+ badargs++;
+ break;
+ } /* switch */
+ } /* if (store) */
+
+ return length;
+} /* put_one_arg */
+
+
+ void
+#ifdef KR_headers
+init_store(table, entries)
+ arg_info *table;
+ int entries;
+#else
+init_store(arg_info *table, int entries)
+#endif
+{
+ int index;
+
+ for (index = 0; index < entries; index++)
+ if (arg_count (table[index]) == P_INFINITE_ARGS) {
+ char **place = (char **) arg_result_ptr (table[index]);
+
+ if (place)
+ *place = (char *) NULL;
+ } /* if arg_count == P_INFINITE_ARGS */
+
+} /* init_store */
diff --git a/usr.bin/f2c/pccdefs.h b/usr.bin/f2c/pccdefs.h
new file mode 100644
index 0000000..bde8117
--- /dev/null
+++ b/usr.bin/f2c/pccdefs.h
@@ -0,0 +1,64 @@
+/* The following numbers are strange, and implementation-dependent */
+
+#define P2BAD -1
+#define P2NAME 2
+#define P2ICON 4 /* Integer constant */
+#define P2PLUS 6
+#define P2PLUSEQ 7
+#define P2MINUS 8
+#define P2NEG 10
+#define P2STAR 11
+#define P2STAREQ 12
+#define P2INDIRECT 13
+#define P2BITAND 14
+#define P2BITOR 17
+#define P2BITXOR 19
+#define P2QUEST 21
+#define P2COLON 22
+#define P2ANDAND 23
+#define P2OROR 24
+#define P2GOTO 37
+#define P2LISTOP 56
+#define P2ASSIGN 58
+#define P2COMOP 59
+#define P2SLASH 60
+#define P2MOD 62
+#define P2LSHIFT 64
+#define P2RSHIFT 66
+#define P2CALL 70
+#define P2CALL0 72
+
+#define P2NOT 76
+#define P2BITNOT 77
+#define P2EQ 80
+#define P2NE 81
+#define P2LE 82
+#define P2LT 83
+#define P2GE 84
+#define P2GT 85
+#define P2REG 94
+#define P2OREG 95
+#define P2CONV 104
+#define P2FORCE 108
+#define P2CBRANCH 109
+
+/* special operators included only for fortran's use */
+
+#define P2PASS 200
+#define P2STMT 201
+#define P2SWITCH 202
+#define P2LBRACKET 203
+#define P2RBRACKET 204
+#define P2EOF 205
+#define P2ARIF 206
+#define P2LABEL 207
+
+#define P2SHORT 3
+#define P2INT 4
+#define P2LONG 4
+
+#define P2CHAR 2
+#define P2REAL 6
+#define P2DREAL 7
+#define P2PTR 020
+#define P2FUNCT 040
diff --git a/usr.bin/f2c/pread.c b/usr.bin/f2c/pread.c
new file mode 100644
index 0000000..eb1576a
--- /dev/null
+++ b/usr.bin/f2c/pread.c
@@ -0,0 +1,990 @@
+/****************************************************************
+Copyright 1990, 1992, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+
+ static char Ptok[128], Pct[Table_size];
+ static char *Pfname;
+ static long Plineno;
+ static int Pbad;
+ static int *tfirst, *tlast, *tnext, tmax;
+
+#define P_space 1
+#define P_anum 2
+#define P_delim 3
+#define P_slash 4
+
+#define TGULP 100
+
+ static void
+trealloc(Void)
+{
+ int k = tmax;
+ tfirst = (int *)realloc((char *)tfirst,
+ (tmax += TGULP)*sizeof(int));
+ if (!tfirst) {
+ fprintf(stderr,
+ "Pfile: realloc failure!\n");
+ exit(2);
+ }
+ tlast = tfirst + tmax;
+ tnext = tfirst + k;
+ }
+
+ static void
+#ifdef KR_headers
+badchar(c)
+ int c;
+#else
+badchar(int c)
+#endif
+{
+ fprintf(stderr,
+ "unexpected character 0x%.2x = '%c' on line %ld of %s\n",
+ c, c, Plineno, Pfname);
+ exit(2);
+ }
+
+ static void
+bad_type(Void)
+{
+ fprintf(stderr,
+ "unexpected type \"%s\" on line %ld of %s\n",
+ Ptok, Plineno, Pfname);
+ exit(2);
+ }
+
+ static void
+#ifdef KR_headers
+badflag(tname, option)
+ char *tname;
+ char *option;
+#else
+badflag(char *tname, char *option)
+#endif
+{
+ fprintf(stderr, "%s type from `f2c -%s` on line %ld of %s\n",
+ tname, option, Plineno, Pfname);
+ Pbad++;
+ }
+
+ static void
+#ifdef KR_headers
+detected(msg)
+ char *msg;
+#else
+detected(char *msg)
+#endif
+{
+ fprintf(stderr,
+ "%sdetected on line %ld of %s\n", msg, Plineno, Pfname);
+ Pbad++;
+ }
+
+#if 0
+ static void
+#ifdef KR_headers
+checklogical(k)
+ int k;
+#else
+checklogical(int k)
+#endif
+{
+ static int lastmsg = 0;
+ static int seen[2] = {0,0};
+
+ seen[k] = 1;
+ if (seen[1-k]) {
+ if (lastmsg < 3) {
+ lastmsg = 3;
+ detected(
+ "Illegal combination of LOGICAL types -- mixing -I4 with -I2 or -i2\n\t");
+ }
+ return;
+ }
+ if (k) {
+ if (tylogical == TYLONG || lastmsg >= 2)
+ return;
+ if (!lastmsg) {
+ lastmsg = 2;
+ badflag("LOGICAL", "I4");
+ }
+ }
+ else {
+ if (tylogical == TYSHORT || lastmsg & 1)
+ return;
+ if (!lastmsg) {
+ lastmsg = 1;
+ badflag("LOGICAL", "i2` or `f2c -I2");
+ }
+ }
+ }
+#else
+#define checklogical(n) /* */
+#endif
+
+ static void
+#ifdef KR_headers
+checkreal(k)
+ int k;
+#else
+checkreal(int k)
+#endif
+{
+ static int warned = 0;
+ static int seen[2] = {0,0};
+
+ seen[k] = 1;
+ if (seen[1-k]) {
+ if (warned < 2)
+ detected("Illegal mixture of -R and -!R ");
+ warned = 2;
+ return;
+ }
+ if (k == forcedouble || warned)
+ return;
+ warned = 1;
+ badflag("REAL return", k ? "!R" : "R");
+ }
+
+ static void
+#ifdef KR_headers
+Pnotboth(e)
+ Extsym *e;
+#else
+Pnotboth(Extsym *e)
+#endif
+{
+ if (e->curno)
+ return;
+ Pbad++;
+ e->curno = 1;
+ fprintf(stderr,
+ "%s cannot be both a procedure and a common block (line %ld of %s)\n",
+ e->fextname, Plineno, Pfname);
+ }
+
+ static int
+#ifdef KR_headers
+numread(pf, n)
+ register FILE *pf;
+ int *n;
+#else
+numread(register FILE *pf, int *n)
+#endif
+{
+ register int c, k;
+
+ if ((c = getc(pf)) < '0' || c > '9')
+ return c;
+ k = c - '0';
+ for(;;) {
+ if ((c = getc(pf)) == ' ') {
+ *n = k;
+ return c;
+ }
+ if (c < '0' || c > '9')
+ break;
+ k = 10*k + c - '0';
+ }
+ return c;
+ }
+
+ static void argverify Argdcl((int, Extsym*));
+ static void Pbadret Argdcl((int ftype, Extsym *p));
+
+ static int
+#ifdef KR_headers
+readref(pf, e, ftype)
+ register FILE *pf;
+ Extsym *e;
+ int ftype;
+#else
+readref(register FILE *pf, Extsym *e, int ftype)
+#endif
+{
+ register int c, *t;
+ int i, nargs, type;
+ Argtypes *at;
+ Atype *a, *ae;
+
+ if (ftype > TYSUBR)
+ return 0;
+ if ((c = numread(pf, &nargs)) != ' ') {
+ if (c != ':')
+ return c == EOF;
+ /* just a typed external */
+ if (e->extstg == STGUNKNOWN) {
+ at = 0;
+ goto justsym;
+ }
+ if (e->extstg == STGEXT) {
+ if (e->extype != ftype)
+ Pbadret(ftype, e);
+ }
+ else
+ Pnotboth(e);
+ return 0;
+ }
+
+ tnext = tfirst;
+ for(i = 0; i < nargs; i++) {
+ if ((c = numread(pf, &type)) != ' '
+ || type >= 500
+ || type != TYFTNLEN + 100 && type % 100 > TYSUBR)
+ return c == EOF;
+ if (tnext >= tlast)
+ trealloc();
+ *tnext++ = type;
+ }
+
+ if (e->extstg == STGUNKNOWN) {
+ save_at:
+ at = (Argtypes *)
+ gmem(sizeof(Argtypes) + (nargs-1)*sizeof(Atype), 1);
+ at->dnargs = at->nargs = nargs;
+ at->changes = 0;
+ t = tfirst;
+ a = at->atypes;
+ for(ae = a + nargs; a < ae; a++) {
+ a->type = *t++;
+ a->cp = 0;
+ }
+ justsym:
+ e->extstg = STGEXT;
+ e->extype = ftype;
+ e->arginfo = at;
+ }
+ else if (e->extstg != STGEXT) {
+ Pnotboth(e);
+ }
+ else if (!e->arginfo) {
+ if (e->extype != ftype)
+ Pbadret(ftype, e);
+ else
+ goto save_at;
+ }
+ else
+ argverify(ftype, e);
+ return 0;
+ }
+
+ static int
+#ifdef KR_headers
+comlen(pf)
+ register FILE *pf;
+#else
+comlen(register FILE *pf)
+#endif
+{
+ register int c;
+ register char *s, *se;
+ char buf[128], cbuf[128];
+ int refread;
+ long L;
+ Extsym *e;
+
+ if ((c = getc(pf)) == EOF)
+ return 1;
+ if (c == ' ') {
+ refread = 0;
+ s = "comlen ";
+ }
+ else if (c == ':') {
+ refread = 1;
+ s = "ref: ";
+ }
+ else {
+ ret0:
+ if (c == '*')
+ ungetc(c,pf);
+ return 0;
+ }
+ while(*s) {
+ if ((c = getc(pf)) == EOF)
+ return 1;
+ if (c != *s++)
+ goto ret0;
+ }
+ s = buf;
+ se = buf + sizeof(buf) - 1;
+ for(;;) {
+ if ((c = getc(pf)) == EOF)
+ return 1;
+ if (c == ' ')
+ break;
+ if (s >= se || Pct[c] != P_anum)
+ goto ret0;
+ *s++ = c;
+ }
+ *s-- = 0;
+ if (s <= buf || *s != '_')
+ return 0;
+ strcpy(cbuf,buf);
+ *s-- = 0;
+ if (*s == '_') {
+ *s-- = 0;
+ if (s <= buf)
+ return 0;
+ }
+ for(L = 0;;) {
+ if ((c = getc(pf)) == EOF)
+ return 1;
+ if (c == ' ')
+ break;
+ if (c < '0' && c > '9')
+ goto ret0;
+ L = 10*L + c - '0';
+ }
+ if (!L && !refread)
+ return 0;
+ e = mkext1(buf, cbuf);
+ if (refread)
+ return readref(pf, e, (int)L);
+ if (e->extstg == STGUNKNOWN) {
+ e->extstg = STGCOMMON;
+ e->maxleng = L;
+ }
+ else if (e->extstg != STGCOMMON)
+ Pnotboth(e);
+ else if (e->maxleng != L) {
+ fprintf(stderr,
+ "incompatible lengths for common block %s (line %ld of %s)\n",
+ buf, Plineno, Pfname);
+ if (e->maxleng < L)
+ e->maxleng = L;
+ }
+ return 0;
+ }
+
+ static int
+#ifdef KR_headers
+Ptoken(pf, canend)
+ FILE *pf;
+ int canend;
+#else
+Ptoken(FILE *pf, int canend)
+#endif
+{
+ register int c;
+ register char *s, *se;
+
+ top:
+ for(;;) {
+ c = getc(pf);
+ if (c == EOF) {
+ if (canend)
+ return 0;
+ goto badeof;
+ }
+ if (Pct[c] != P_space)
+ break;
+ if (c == '\n')
+ Plineno++;
+ }
+ switch(Pct[c]) {
+ case P_anum:
+ if (c == '_')
+ badchar(c);
+ s = Ptok;
+ se = s + sizeof(Ptok) - 1;
+ do {
+ if (s < se)
+ *s++ = c;
+ if ((c = getc(pf)) == EOF) {
+ badeof:
+ fprintf(stderr,
+ "unexpected end of file in %s\n",
+ Pfname);
+ exit(2);
+ }
+ }
+ while(Pct[c] == P_anum);
+ ungetc(c,pf);
+ *s = 0;
+ return P_anum;
+
+ case P_delim:
+ return c;
+
+ case P_slash:
+ if ((c = getc(pf)) != '*') {
+ if (c == EOF)
+ goto badeof;
+ badchar('/');
+ }
+ if (canend && comlen(pf))
+ goto badeof;
+ for(;;) {
+ while((c = getc(pf)) != '*') {
+ if (c == EOF)
+ goto badeof;
+ if (c == '\n')
+ Plineno++;
+ }
+ slashseek:
+ switch(getc(pf)) {
+ case '/':
+ goto top;
+ case EOF:
+ goto badeof;
+ case '*':
+ goto slashseek;
+ }
+ }
+ default:
+ badchar(c);
+ }
+ /* NOT REACHED */
+ return 0;
+ }
+
+ static int
+Pftype(Void)
+{
+ switch(Ptok[0]) {
+ case 'C':
+ if (!strcmp(Ptok+1, "_f"))
+ return TYCOMPLEX;
+ break;
+ case 'E':
+ if (!strcmp(Ptok+1, "_f")) {
+ /* TYREAL under forcedouble */
+ checkreal(1);
+ return TYREAL;
+ }
+ break;
+ case 'H':
+ if (!strcmp(Ptok+1, "_f"))
+ return TYCHAR;
+ break;
+ case 'Z':
+ if (!strcmp(Ptok+1, "_f"))
+ return TYDCOMPLEX;
+ break;
+ case 'd':
+ if (!strcmp(Ptok+1, "oublereal"))
+ return TYDREAL;
+ break;
+ case 'i':
+ if (!strcmp(Ptok+1, "nt"))
+ return TYSUBR;
+ if (!strcmp(Ptok+1, "nteger"))
+ return TYLONG;
+ if (!strcmp(Ptok+1, "nteger1"))
+ return TYINT1;
+ break;
+ case 'l':
+ if (!strcmp(Ptok+1, "ogical")) {
+ checklogical(1);
+ return TYLOGICAL;
+ }
+ if (!strcmp(Ptok+1, "ogical1"))
+ return TYLOGICAL1;
+#ifdef TYQUAD
+ if (!strcmp(Ptok+1, "ongint"))
+ return TYQUAD;
+#endif
+ break;
+ case 'r':
+ if (!strcmp(Ptok+1, "eal")) {
+ checkreal(0);
+ return TYREAL;
+ }
+ break;
+ case 's':
+ if (!strcmp(Ptok+1, "hortint"))
+ return TYSHORT;
+ if (!strcmp(Ptok+1, "hortlogical")) {
+ checklogical(0);
+ return TYLOGICAL2;
+ }
+ break;
+ }
+ bad_type();
+ /* NOT REACHED */
+ return 0;
+ }
+
+ static void
+#ifdef KR_headers
+wanted(i, what)
+ int i;
+ char *what;
+#else
+wanted(int i, char *what)
+#endif
+{
+ if (i != P_anum) {
+ Ptok[0] = i;
+ Ptok[1] = 0;
+ }
+ fprintf(stderr,"Error: expected %s, not \"%s\" (line %ld of %s)\n",
+ what, Ptok, Plineno, Pfname);
+ exit(2);
+ }
+
+ static int
+#ifdef KR_headers
+Ptype(pf)
+ FILE *pf;
+#else
+Ptype(FILE *pf)
+#endif
+{
+ int i, rv;
+
+ i = Ptoken(pf,0);
+ if (i == ')')
+ return 0;
+ if (i != P_anum)
+ badchar(i);
+
+ rv = 0;
+ switch(Ptok[0]) {
+ case 'C':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYCOMPLEX+200;
+ break;
+ case 'D':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYDREAL+200;
+ break;
+ case 'E':
+ case 'R':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYREAL+200;
+ break;
+ case 'H':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYCHAR+200;
+ break;
+ case 'I':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYLONG+200;
+ else if (!strcmp(Ptok+1, "1_fp"))
+ rv = TYINT1+200;
+#ifdef TYQUAD
+ else if (!strcmp(Ptok+1, "8_fp"))
+ rv = TYQUAD+200;
+#endif
+ break;
+ case 'J':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYSHORT+200;
+ break;
+ case 'K':
+ checklogical(0);
+ goto Logical;
+ case 'L':
+ checklogical(1);
+ Logical:
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYLOGICAL+200;
+ else if (!strcmp(Ptok+1, "1_fp"))
+ rv = TYLOGICAL1+200;
+ else if (!strcmp(Ptok+1, "2_fp"))
+ rv = TYLOGICAL2+200;
+ break;
+ case 'S':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYSUBR+200;
+ break;
+ case 'U':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYUNKNOWN+300;
+ break;
+ case 'Z':
+ if (!strcmp(Ptok+1, "_fp"))
+ rv = TYDCOMPLEX+200;
+ break;
+ case 'c':
+ if (!strcmp(Ptok+1, "har"))
+ rv = TYCHAR;
+ else if (!strcmp(Ptok+1, "omplex"))
+ rv = TYCOMPLEX;
+ break;
+ case 'd':
+ if (!strcmp(Ptok+1, "oublereal"))
+ rv = TYDREAL;
+ else if (!strcmp(Ptok+1, "oublecomplex"))
+ rv = TYDCOMPLEX;
+ break;
+ case 'f':
+ if (!strcmp(Ptok+1, "tnlen"))
+ rv = TYFTNLEN+100;
+ break;
+ case 'i':
+ if (!strncmp(Ptok+1, "nteger", 6)) {
+ if (!Ptok[7])
+ rv = TYLONG;
+ else if (Ptok[7] == '1' && !Ptok[8])
+ rv = TYINT1;
+ }
+ break;
+ case 'l':
+ if (!strncmp(Ptok+1, "ogical", 6)) {
+ if (!Ptok[7]) {
+ checklogical(1);
+ rv = TYLOGICAL;
+ }
+ else if (Ptok[7] == '1' && !Ptok[8])
+ rv = TYLOGICAL1;
+ }
+#ifdef TYQUAD
+ else if (!strcmp(Ptok+1,"ongint"))
+ rv = TYQUAD;
+#endif
+ break;
+ case 'r':
+ if (!strcmp(Ptok+1, "eal"))
+ rv = TYREAL;
+ break;
+ case 's':
+ if (!strcmp(Ptok+1, "hortint"))
+ rv = TYSHORT;
+ else if (!strcmp(Ptok+1, "hortlogical")) {
+ checklogical(0);
+ rv = TYLOGICAL2;
+ }
+ break;
+ case 'v':
+ if (tnext == tfirst && !strcmp(Ptok+1, "oid")) {
+ if ((i = Ptoken(pf,0)) != /*(*/ ')')
+ wanted(i, /*(*/ "\")\"");
+ return 0;
+ }
+ }
+ if (!rv)
+ bad_type();
+ if (rv < 100 && (i = Ptoken(pf,0)) != '*')
+ wanted(i, "\"*\"");
+ if ((i = Ptoken(pf,0)) == P_anum)
+ i = Ptoken(pf,0); /* skip variable name */
+ switch(i) {
+ case ')':
+ ungetc(i,pf);
+ break;
+ case ',':
+ break;
+ default:
+ wanted(i, "\",\" or \")\"");
+ }
+ return rv;
+ }
+
+ static char *
+trimunder(Void)
+{
+ register char *s;
+ register int n;
+ static char buf[128];
+
+ s = Ptok + strlen(Ptok) - 1;
+ if (*s != '_') {
+ fprintf(stderr,
+ "warning: %s does not end in _ (line %ld of %s)\n",
+ Ptok, Plineno, Pfname);
+ return Ptok;
+ }
+ if (s[-1] == '_')
+ s--;
+ strncpy(buf, Ptok, n = s - Ptok);
+ buf[n] = 0;
+ return buf;
+ }
+
+ static void
+#ifdef KR_headers
+Pbadmsg(msg, p)
+ char *msg;
+ Extsym *p;
+#else
+Pbadmsg(char *msg, Extsym *p)
+#endif
+{
+ Pbad++;
+ fprintf(stderr, "%s for %s (line %ld of %s):\n\t", msg,
+ p->fextname, Plineno, Pfname);
+ p->arginfo->nargs = -1;
+ }
+
+ static void
+#ifdef KR_headers
+Pbadret(ftype, p)
+ int ftype;
+ Extsym *p;
+#else
+Pbadret(int ftype, Extsym *p)
+#endif
+{
+ char buf1[32], buf2[32];
+
+ Pbadmsg("inconsistent types",p);
+ fprintf(stderr, "here %s, previously %s\n",
+ Argtype(ftype+200,buf1),
+ Argtype(p->extype+200,buf2));
+ }
+
+ static void
+#ifdef KR_headers
+argverify(ftype, p)
+ int ftype;
+ Extsym *p;
+#else
+argverify(int ftype, Extsym *p)
+#endif
+{
+ Argtypes *at;
+ register Atype *aty;
+ int i, j, k;
+ register int *t, *te;
+ char buf1[32], buf2[32];
+
+ at = p->arginfo;
+ if (at->nargs < 0)
+ return;
+ if (p->extype != ftype) {
+ Pbadret(ftype, p);
+ return;
+ }
+ t = tfirst;
+ te = tnext;
+ i = te - t;
+ if (at->nargs != i) {
+ j = at->nargs;
+ Pbadmsg("differing numbers of arguments",p);
+ fprintf(stderr, "here %d, previously %d\n",
+ i, j);
+ return;
+ }
+ for(aty = at->atypes; t < te; t++, aty++) {
+ if (*t == aty->type)
+ continue;
+ j = aty->type;
+ k = *t;
+ if (k >= 300 || k == j)
+ continue;
+ if (j >= 300) {
+ if (k >= 200) {
+ if (k == TYUNKNOWN + 200)
+ continue;
+ if (j % 100 != k - 200
+ && k != TYSUBR + 200
+ && j != TYUNKNOWN + 300
+ && !type_fixup(at,aty,k))
+ goto badtypes;
+ }
+ else if (j % 100 % TYSUBR != k % TYSUBR
+ && !type_fixup(at,aty,k))
+ goto badtypes;
+ }
+ else if (k < 200 || j < 200)
+ goto badtypes;
+ else if (k == TYUNKNOWN+200)
+ continue;
+ else if (j != TYUNKNOWN+200)
+ {
+ badtypes:
+ Pbadmsg("differing calling sequences",p);
+ i = t - tfirst + 1;
+ fprintf(stderr,
+ "arg %d: here %s, prevously %s\n",
+ i, Argtype(k,buf1), Argtype(j,buf2));
+ return;
+ }
+ /* We've subsequently learned the right type,
+ as in the call on zoo below...
+
+ subroutine foo(x, zap)
+ external zap
+ call goo(zap)
+ x = zap(3)
+ call zoo(zap)
+ end
+ */
+ aty->type = k;
+ at->changes = 1;
+ }
+ }
+
+ static void
+#ifdef KR_headers
+newarg(ftype, p)
+ int ftype;
+ Extsym *p;
+#else
+newarg(int ftype, Extsym *p)
+#endif
+{
+ Argtypes *at;
+ register Atype *aty;
+ register int *t, *te;
+ int i, k;
+
+ if (p->extstg == STGCOMMON) {
+ Pnotboth(p);
+ return;
+ }
+ p->extstg = STGEXT;
+ p->extype = ftype;
+ p->exproto = 1;
+ t = tfirst;
+ te = tnext;
+ i = te - t;
+ k = sizeof(Argtypes) + (i-1)*sizeof(Atype);
+ at = p->arginfo = (Argtypes *)gmem(k,1);
+ at->dnargs = at->nargs = i;
+ at->defined = at->changes = 0;
+ for(aty = at->atypes; t < te; aty++) {
+ aty->type = *t++;
+ aty->cp = 0;
+ }
+ }
+
+ static int
+#ifdef KR_headers
+Pfile(fname)
+ char *fname;
+#else
+Pfile(char *fname)
+#endif
+{
+ char *s;
+ int ftype, i;
+ FILE *pf;
+ Extsym *p;
+
+ for(s = fname; *s; s++);
+ if (s - fname < 2
+ || s[-2] != '.'
+ || (s[-1] != 'P' && s[-1] != 'p'))
+ return 0;
+
+ if (!(pf = fopen(fname, textread))) {
+ fprintf(stderr, "can't open %s\n", fname);
+ exit(2);
+ }
+ Pfname = fname;
+ Plineno = 1;
+ if (!Pct[' ']) {
+ for(s = " \t\n\r\v\f"; *s; s++)
+ Pct[*s] = P_space;
+ for(s = "*,();"; *s; s++)
+ Pct[*s] = P_delim;
+ for(i = '0'; i <= '9'; i++)
+ Pct[i] = P_anum;
+ for(s = "abcdefghijklmnopqrstuvwxyz"; i = *s; s++)
+ Pct[i] = Pct[i+'A'-'a'] = P_anum;
+ Pct['_'] = P_anum;
+ Pct['/'] = P_slash;
+ }
+
+ for(;;) {
+ if (!(i = Ptoken(pf,1)))
+ break;
+ if (i != P_anum
+ || !strcmp(Ptok, "extern") && (i = Ptoken(pf,0)) != P_anum)
+ badchar(i);
+ ftype = Pftype();
+ getname:
+ if ((i = Ptoken(pf,0)) != P_anum)
+ badchar(i);
+ p = mkext1(trimunder(), Ptok);
+
+ if ((i = Ptoken(pf,0)) != '(')
+ badchar(i);
+ tnext = tfirst;
+ while(i = Ptype(pf)) {
+ if (tnext >= tlast)
+ trealloc();
+ *tnext++ = i;
+ }
+ if (p->arginfo) {
+ argverify(ftype, p);
+ if (p->arginfo->nargs < 0)
+ newarg(ftype, p);
+ }
+ else
+ newarg(ftype, p);
+ p->arginfo->defined = 1;
+ i = Ptoken(pf,0);
+ switch(i) {
+ case ';':
+ break;
+ case ',':
+ goto getname;
+ default:
+ wanted(i, "\";\" or \",\"");
+ }
+ }
+ fclose(pf);
+ return 1;
+ }
+
+ void
+#ifdef KR_headers
+read_Pfiles(ffiles)
+ char **ffiles;
+#else
+read_Pfiles(char **ffiles)
+#endif
+{
+ char **f1files, **f1files0, *s;
+ int k;
+ register Extsym *e, *ee;
+ register Argtypes *at;
+ extern int retcode;
+
+ f1files0 = f1files = ffiles;
+ while(s = *ffiles++)
+ if (!Pfile(s))
+ *f1files++ = s;
+ if (Pbad)
+ retcode = 8;
+ if (tfirst) {
+ free((char *)tfirst);
+ /* following should be unnecessary, as we won't be back here */
+ tfirst = tnext = tlast = 0;
+ tmax = 0;
+ }
+ *f1files = 0;
+ if (f1files == f1files0)
+ f1files[1] = 0;
+
+ k = 0;
+ ee = nextext;
+ for (e = extsymtab; e < ee; e++)
+ if (e->extstg == STGEXT
+ && (at = e->arginfo)) {
+ if (at->nargs < 0 || at->changes)
+ k++;
+ at->changes = 2;
+ }
+ if (k) {
+ fprintf(diagfile,
+ "%d prototype%s updated while reading prototypes.\n", k,
+ k > 1 ? "s" : "");
+ }
+ fflush(diagfile);
+ }
diff --git a/usr.bin/f2c/proc.c b/usr.bin/f2c/proc.c
new file mode 100644
index 0000000..6796d52
--- /dev/null
+++ b/usr.bin/f2c/proc.c
@@ -0,0 +1,1821 @@
+/****************************************************************
+Copyright 1990, 1994-6 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "names.h"
+#include "output.h"
+#include "p1defs.h"
+
+/* round a up to the nearest multiple of b:
+
+ a = b * floor ( (a + (b - 1)) / b )*/
+
+#undef roundup
+#define roundup(a,b) ( b * ( (a+b-1)/b) )
+
+#define EXNULL (union Expression *)0
+
+static void dobss Argdcl((void));
+static void docomleng Argdcl((void));
+static void docommon Argdcl((void));
+static void doentry Argdcl((struct Entrypoint*));
+static void epicode Argdcl((void));
+static int nextarg Argdcl((int));
+static void retval Argdcl((int));
+
+static char Blank[] = BLANKCOMMON;
+
+ static char *postfix[] = { "g", "h", "i",
+#ifdef TYQUAD
+ "j",
+#endif
+ "r", "d", "c", "z", "g", "h", "i" };
+
+ chainp new_procs;
+ int prev_proc, proc_argchanges, proc_protochanges;
+
+ void
+#ifdef KR_headers
+changedtype(q)
+ Namep q;
+#else
+changedtype(Namep q)
+#endif
+{
+ char buf[200];
+ int qtype, type1;
+ register Extsym *e;
+ Argtypes *at;
+
+ if (q->vtypewarned)
+ return;
+ q->vtypewarned = 1;
+ qtype = q->vtype;
+ e = &extsymtab[q->vardesc.varno];
+ if (!(at = e->arginfo)) {
+ if (!e->exused)
+ return;
+ }
+ else if (at->changes & 2 && qtype != TYUNKNOWN && !at->defined)
+ proc_protochanges++;
+ type1 = e->extype;
+ if (type1 == TYUNKNOWN)
+ return;
+ if (qtype == TYUNKNOWN)
+ /* e.g.,
+ subroutine foo
+ end
+ external foo
+ call goo(foo)
+ end
+ */
+ return;
+ sprintf(buf, "%.90s: inconsistent declarations:\n\
+ here %s%s, previously %s%s.", q->fvarname, ftn_types[qtype],
+ qtype == TYSUBR ? "" : " function",
+ ftn_types[type1], type1 == TYSUBR ? "" : " function");
+ warn(buf);
+ }
+
+ void
+#ifdef KR_headers
+unamstring(q, s)
+ register Addrp q;
+ register char *s;
+#else
+unamstring(register Addrp q, register char *s)
+#endif
+{
+ register int k;
+ register char *t;
+
+ k = strlen(s);
+ if (k < IDENT_LEN) {
+ q->uname_tag = UNAM_IDENT;
+ t = q->user.ident;
+ }
+ else {
+ q->uname_tag = UNAM_CHARP;
+ q->user.Charp = t = mem(k+1, 0);
+ }
+ strcpy(t, s);
+ }
+
+ static void
+fix_entry_returns(Void) /* for multiple entry points */
+{
+ Addrp a;
+ int i;
+ struct Entrypoint *e;
+ Namep np;
+
+ e = entries = (struct Entrypoint *)revchain((chainp)entries);
+ allargs = revchain(allargs);
+ if (!multitype)
+ return;
+
+ /* TYLOGICAL should have been turned into TYLONG or TYSHORT by now */
+
+ for(i = TYINT1; i <= TYLOGICAL; i++)
+ if (a = xretslot[i])
+ sprintf(a->user.ident, "(*ret_val).%s",
+ postfix[i-TYINT1]);
+
+ do {
+ np = e->enamep;
+ switch(np->vtype) {
+ case TYINT1:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYREAL:
+ case TYDREAL:
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+ np->vstg = STGARG;
+ }
+ }
+ while(e = e->entnextp);
+ }
+
+ static void
+#ifdef KR_headers
+putentries(outfile)
+ FILE *outfile;
+#else
+putentries(FILE *outfile)
+#endif
+ /* put out wrappers for multiple entries */
+{
+ char base[MAXNAMELEN+4];
+ struct Entrypoint *e;
+ Namep *A, *Ae, *Ae1, **Alp, *a, **a1, np;
+ chainp args, lengths;
+ int i, k, mt, nL, t, type;
+ extern char *dfltarg[], **dfltproc;
+
+ e = entries;
+ if (!e->enamep) /* only possible with erroneous input */
+ return;
+ nL = (nallargs + nallchargs) * sizeof(Namep *);
+ A = (Namep *)ckalloc(nL + nallargs*sizeof(Namep **));
+ Ae = A + nallargs;
+ Alp = (Namep **)(Ae1 = Ae + nallchargs);
+ i = k = 0;
+ for(a1 = Alp, args = allargs; args; a1++, args = args->nextp) {
+ np = (Namep)args->datap;
+ if (np->vtype == TYCHAR && np->vclass != CLPROC)
+ *a1 = &Ae[i++];
+ }
+
+ mt = multitype;
+ multitype = 0;
+ sprintf(base, "%s0_", e->enamep->cvarname);
+ do {
+ np = e->enamep;
+ lengths = length_comp(e, 0);
+ proctype = type = np->vtype;
+ if (protofile)
+ protowrite(protofile, type, np->cvarname, e, lengths);
+ nice_printf(outfile, "\n%s ", c_type_decl(type, 1));
+ nice_printf(outfile, "%s", np->cvarname);
+ if (!Ansi) {
+ listargs(outfile, e, 0, lengths);
+ nice_printf(outfile, "\n");
+ }
+ list_arg_types(outfile, e, lengths, 0, "\n");
+ nice_printf(outfile, "{\n");
+ frchain(&lengths);
+ next_tab(outfile);
+ if (mt)
+ nice_printf(outfile,
+ "Multitype ret_val;\n%s(%d, &ret_val",
+ base, k); /*)*/
+ else if (ISCOMPLEX(type))
+ nice_printf(outfile, "%s(%d,%s", base, k,
+ xretslot[type]->user.ident); /*)*/
+ else if (type == TYCHAR)
+ nice_printf(outfile,
+ "%s(%d, ret_val, ret_val_len", base, k); /*)*/
+ else
+ nice_printf(outfile, "return %s(%d", base, k); /*)*/
+ k++;
+ memset((char *)A, 0, nL);
+ for(args = e->arglist; args; args = args->nextp) {
+ np = (Namep)args->datap;
+ A[np->argno] = np;
+ if (np->vtype == TYCHAR && np->vclass != CLPROC)
+ *Alp[np->argno] = np;
+ }
+ args = allargs;
+ for(a = A; a < Ae; a++, args = args->nextp) {
+ t = ((Namep)args->datap)->vtype;
+ nice_printf(outfile, ", %s", (np = *a)
+ ? np->cvarname
+ : ((Namep)args->datap)->vclass == CLPROC
+ ? dfltproc[((Namep)args->datap)->vimpltype
+ ? (Castargs ? TYUNKNOWN : TYSUBR)
+ : t == TYREAL && forcedouble && !Castargs
+ ? TYDREAL : t]
+ : dfltarg[((Namep)args->datap)->vtype]);
+ }
+ for(; a < Ae1; a++)
+ if (np = *a)
+ nice_printf(outfile, ", %s",
+ new_arg_length(np));
+ else
+ nice_printf(outfile, ", (ftnint)0");
+ nice_printf(outfile, /*(*/ ");\n");
+ if (mt) {
+ if (type == TYCOMPLEX)
+ nice_printf(outfile,
+ "r_v->r = ret_val.c.r; r_v->i = ret_val.c.i;\n");
+ else if (type == TYDCOMPLEX)
+ nice_printf(outfile,
+ "r_v->r = ret_val.z.r; r_v->i = ret_val.z.i;\n");
+ else if (type <= TYLOGICAL)
+ nice_printf(outfile, "return ret_val.%s;\n",
+ postfix[type-TYINT1]);
+ }
+ nice_printf(outfile, "}\n");
+ prev_tab(outfile);
+ }
+ while(e = e->entnextp);
+ free((char *)A);
+ }
+
+ static void
+#ifdef KR_headers
+entry_goto(outfile)
+ FILE *outfile;
+#else
+entry_goto(FILE *outfile)
+#endif
+{
+ struct Entrypoint *e = entries;
+ int k = 0;
+
+ nice_printf(outfile, "switch(n__) {\n");
+ next_tab(outfile);
+ while(e = e->entnextp)
+ nice_printf(outfile, "case %d: goto %s;\n", ++k,
+ user_label((long)(extsymtab - e->entryname - 1)));
+ nice_printf(outfile, "}\n\n");
+ prev_tab(outfile);
+ }
+
+/* start a new procedure */
+
+ void
+newproc(Void)
+{
+ if(parstate != OUTSIDE)
+ {
+ execerr("missing end statement", CNULL);
+ endproc();
+ }
+
+ parstate = INSIDE;
+ procclass = CLMAIN; /* default */
+}
+
+ static void
+zap_changes(Void)
+{
+ register chainp cp;
+ register Argtypes *at;
+
+ /* arrange to get correct count of prototypes that would
+ change by running f2c again */
+
+ if (prev_proc && proc_argchanges)
+ proc_protochanges++;
+ prev_proc = proc_argchanges = 0;
+ for(cp = new_procs; cp; cp = cp->nextp)
+ if (at = ((Namep)cp->datap)->arginfo)
+ at->changes &= ~1;
+ frchain(&new_procs);
+ }
+
+/* end of procedure. generate variables, epilogs, and prologs */
+
+ void
+endproc(Void)
+{
+ struct Labelblock *lp;
+ Extsym *ext;
+
+ if(parstate < INDATA)
+ enddcl();
+ if(ctlstack >= ctls)
+ err("DO loop or BLOCK IF not closed");
+ for(lp = labeltab ; lp < labtabend ; ++lp)
+ if(lp->stateno!=0 && lp->labdefined==NO)
+ errstr("missing statement label %s",
+ convic(lp->stateno) );
+
+/* Save copies of the common variables in extptr -> allextp */
+
+ for (ext = extsymtab; ext < nextext; ext++)
+ if (ext -> extstg == STGCOMMON && ext -> extp) {
+ extern int usedefsforcommon;
+
+/* Write out the abbreviations for common block reference */
+
+ copy_data (ext -> extp);
+ if (usedefsforcommon) {
+ wr_abbrevs (c_file, 1, ext -> extp);
+ ext -> used_here = 1;
+ }
+ else
+ ext -> extp = CHNULL;
+
+ }
+
+ if (nentry > 1)
+ fix_entry_returns();
+ epicode();
+ donmlist();
+ dobss();
+ start_formatting ();
+ if (nentry > 1)
+ putentries(c_file);
+
+ zap_changes();
+ procinit(); /* clean up for next procedure */
+}
+
+
+
+/* End of declaration section of procedure. Allocate storage. */
+
+ void
+enddcl(Void)
+{
+ register struct Entrypoint *ep;
+ struct Entrypoint *ep0;
+ chainp cp;
+ extern char *err_proc;
+ static char comblks[] = "common blocks";
+
+ err_proc = comblks;
+ docommon();
+
+/* Now the hash table entries for fields of common blocks have STGCOMMON,
+ vdcldone, voffset, and varno. And the common blocks themselves have
+ their full sizes in extleng. */
+
+ err_proc = "equivalences";
+ doequiv();
+
+ err_proc = comblks;
+ docomleng();
+
+/* This implies that entry points in the declarations are buffered in
+ entries but not written out */
+
+ err_proc = "entries";
+ if (ep = ep0 = (struct Entrypoint *)revchain((chainp)entries)) {
+ /* entries could be 0 in case of an error */
+ do doentry(ep);
+ while(ep = ep->entnextp);
+ entries = (struct Entrypoint *)revchain((chainp)ep0);
+ }
+
+ err_proc = 0;
+ parstate = INEXEC;
+ p1put(P1_PROCODE);
+ freetemps();
+ if (earlylabs) {
+ for(cp = earlylabs = revchain(earlylabs); cp; cp = cp->nextp)
+ p1_label((long)cp->datap);
+ frchain(&earlylabs);
+ }
+ p1_line_number(lineno); /* for files that start with a MAIN program */
+ /* that starts with an executable statement */
+}
+
+/* ROUTINES CALLED WHEN ENCOUNTERING ENTRY POINTS */
+
+/* Main program or Block data */
+
+ void
+#ifdef KR_headers
+startproc(progname, class)
+ Extsym *progname;
+ int class;
+#else
+startproc(Extsym *progname, int class)
+#endif
+{
+ register struct Entrypoint *p;
+
+ p = ALLOC(Entrypoint);
+ if(class == CLMAIN) {
+ puthead(CNULL, CLMAIN);
+ if (progname)
+ strcpy (main_alias, progname->cextname);
+ } else {
+ if (progname) {
+ /* Construct an empty subroutine with this name */
+ /* in case the name is needed to force loading */
+ /* of this block-data subprogram: the name can */
+ /* appear elsewhere in an external statement. */
+ entrypt(CLPROC, TYSUBR, (ftnint)0, progname, (chainp)0);
+ endproc();
+ newproc();
+ }
+ puthead(CNULL, CLBLOCK);
+ }
+ if(class == CLMAIN)
+ newentry( mkname(" MAIN"), 0 )->extinit = 1;
+ p->entryname = progname;
+ entries = p;
+
+ procclass = class;
+ fprintf(diagfile, " %s", (class==CLMAIN ? "MAIN" : "BLOCK DATA") );
+ if(progname) {
+ fprintf(diagfile, " %s", progname->fextname);
+ procname = progname->cextname;
+ }
+ fprintf(diagfile, ":\n");
+ fflush(diagfile);
+}
+
+/* subroutine or function statement */
+
+ Extsym *
+#ifdef KR_headers
+newentry(v, substmsg)
+ register Namep v;
+ int substmsg;
+#else
+newentry(register Namep v, int substmsg)
+#endif
+{
+ register Extsym *p;
+ char buf[128], badname[64];
+ static int nbad = 0;
+ static char already[] = "external name already used";
+
+ p = mkext(v->fvarname, addunder(v->cvarname));
+
+ if(p->extinit || ! ONEOF(p->extstg, M(STGUNKNOWN)|M(STGEXT)) )
+ {
+ sprintf(badname, "%s_bad%d", v->fvarname, ++nbad);
+ if (substmsg) {
+ sprintf(buf,"%s\n\tsubstituting \"%s\"",
+ already, badname);
+ dclerr(buf, v);
+ }
+ else
+ dclerr(already, v);
+ p = mkext(v->fvarname, badname);
+ }
+ v->vstg = STGAUTO;
+ v->vprocclass = PTHISPROC;
+ v->vclass = CLPROC;
+ if (p->extstg == STGEXT)
+ prev_proc = 1;
+ else
+ p->extstg = STGEXT;
+ p->extinit = YES;
+ v->vardesc.varno = p - extsymtab;
+ return(p);
+}
+
+ void
+#ifdef KR_headers
+entrypt(class, type, length, entry, args)
+ int class;
+ int type;
+ ftnint length;
+ Extsym *entry;
+ chainp args;
+#else
+entrypt(int class, int type, ftnint length, Extsym *entry, chainp args)
+#endif
+{
+ register Namep q;
+ register struct Entrypoint *p;
+
+ if(class != CLENTRY)
+ puthead( procname = entry->cextname, class);
+ else
+ fprintf(diagfile, " entry ");
+ fprintf(diagfile, " %s:\n", entry->fextname);
+ fflush(diagfile);
+ q = mkname(entry->fextname);
+ if (type == TYSUBR)
+ q->vstg = STGEXT;
+
+ type = lengtype(type, length);
+ if(class == CLPROC)
+ {
+ procclass = CLPROC;
+ proctype = type;
+ procleng = type == TYCHAR ? length : 0;
+ }
+
+ p = ALLOC(Entrypoint);
+
+ p->entnextp = entries;
+ entries = p;
+
+ p->entryname = entry;
+ p->arglist = revchain(args);
+ p->enamep = q;
+
+ if(class == CLENTRY)
+ {
+ class = CLPROC;
+ if(proctype == TYSUBR)
+ type = TYSUBR;
+ }
+
+ q->vclass = class;
+ q->vprocclass = 0;
+ settype(q, type, length);
+ q->vprocclass = PTHISPROC;
+ /* hold all initial entry points till end of declarations */
+ if(parstate >= INDATA)
+ doentry(p);
+}
+
+/* generate epilogs */
+
+/* epicode -- write out the proper function return mechanism at the end of
+ the procedure declaration. Handles multiple return value types, as
+ well as cooercion into the proper value */
+
+ LOCAL void
+epicode(Void)
+{
+ extern int lastwasbranch;
+
+ if(procclass==CLPROC)
+ {
+ if(proctype==TYSUBR)
+ {
+
+/* Return a zero only when the alternate return mechanism has been
+ specified in the function header */
+
+ if ((substars || Ansi) && lastwasbranch != YES)
+ p1_subr_ret (ICON(0));
+ }
+ else if (!multitype && lastwasbranch != YES)
+ retval(proctype);
+ }
+ else if (procclass == CLMAIN && Ansi && lastwasbranch != YES)
+ p1_subr_ret (ICON(0));
+ lastwasbranch = NO;
+}
+
+
+/* generate code to return value of type t */
+
+ LOCAL void
+#ifdef KR_headers
+retval(t)
+ register int t;
+#else
+retval(register int t)
+#endif
+{
+ register Addrp p;
+
+ switch(t)
+ {
+ case TYCHAR:
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ break;
+
+ case TYLOGICAL:
+ t = tylogical;
+ case TYINT1:
+ case TYADDR:
+ case TYSHORT:
+ case TYLONG:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYREAL:
+ case TYDREAL:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ p = (Addrp) cpexpr((expptr)retslot);
+ p->vtype = t;
+ p1_subr_ret (mkconv (t, fixtype((expptr)p)));
+ break;
+
+ default:
+ badtype("retval", t);
+ }
+}
+
+
+/* Do parameter adjustments */
+
+ void
+#ifdef KR_headers
+procode(outfile)
+ FILE *outfile;
+#else
+procode(FILE *outfile)
+#endif
+{
+ prolog(outfile, allargs);
+
+ if (nentry > 1)
+ entry_goto(outfile);
+ }
+
+ static void
+#ifdef KR_headers
+bad_dimtype(q) Namep q;
+#else
+bad_dimtype(Namep q)
+#endif
+{
+ errstr("bad dimension type for %.70s", q->fvarname);
+ }
+
+/* Finish bound computations now that all variables are declared.
+ * This used to be in setbound(), but under -u the following incurred
+ * an erroneous error message:
+ * subroutine foo(x,n)
+ * real x(n)
+ * integer n
+ */
+
+ static void
+#ifdef KR_headers
+dim_finish(v)
+ Namep v;
+#else
+dim_finish(Namep v)
+#endif
+{
+ register struct Dimblock *p;
+ register expptr q;
+ register int i, nd;
+
+ p = v->vdim;
+ v->vdimfinish = 0;
+ nd = p->ndim;
+ doin_setbound = 1;
+ for(i = 0; i < nd; i++)
+ if (q = p->dims[i].dimexpr) {
+ q = p->dims[i].dimexpr = make_int_expr(putx(fixtype(q)));
+ if (!ONEOF(q->headblock.vtype, MSKINT|MSKREAL))
+ bad_dimtype(v);
+ }
+ if (q = p->basexpr)
+ p->basexpr = make_int_expr(putx(fixtype(q)));
+ doin_setbound = 0;
+ }
+
+ static void
+#ifdef KR_headers
+duparg(q)
+ Namep q;
+#else
+duparg(Namep q)
+#endif
+{ errstr("duplicate argument %.80s", q->fvarname); }
+
+/*
+ manipulate argument lists (allocate argument slot positions)
+ * keep track of return types and labels
+ */
+
+ LOCAL void
+#ifdef KR_headers
+doentry(ep)
+ struct Entrypoint *ep;
+#else
+doentry(struct Entrypoint *ep)
+#endif
+{
+ register int type;
+ register Namep np;
+ chainp p, p1;
+ register Namep q;
+ Addrp rs;
+ int it, k;
+ extern char dflttype[26];
+ Extsym *entryname = ep->entryname;
+
+ if (++nentry > 1)
+ p1_label((long)(extsymtab - entryname - 1));
+
+/* The main program isn't allowed to have parameters, so any given
+ parameters are ignored */
+
+ if(procclass == CLMAIN || procclass == CLBLOCK)
+ return;
+
+/* So now we're working with something other than CLMAIN or CLBLOCK.
+ Determine the type of its return value. */
+
+ impldcl( np = mkname(entryname->fextname) );
+ type = np->vtype;
+ proc_argchanges = prev_proc && type != entryname->extype;
+ entryname->extseen = 1;
+ if(proctype == TYUNKNOWN)
+ if( (proctype = type) == TYCHAR)
+ procleng = np->vleng ? np->vleng->constblock.Const.ci
+ : (ftnint) (-1);
+
+ if(proctype == TYCHAR)
+ {
+ if(type != TYCHAR)
+ err("noncharacter entry of character function");
+
+/* Functions returning type char can only have multiple entries if all
+ entries return the same length */
+
+ else if( (np->vleng ? np->vleng->constblock.Const.ci :
+ (ftnint) (-1)) != procleng)
+ err("mismatched character entry lengths");
+ }
+ else if(type == TYCHAR)
+ err("character entry of noncharacter function");
+ else if(type != proctype)
+ multitype = YES;
+ if(rtvlabel[type] == 0)
+ rtvlabel[type] = (int)newlabel();
+ ep->typelabel = rtvlabel[type];
+
+ if(type == TYCHAR)
+ {
+ if(chslot < 0)
+ {
+ chslot = nextarg(TYADDR);
+ chlgslot = nextarg(TYLENG);
+ }
+ np->vstg = STGARG;
+
+/* Put a new argument in the function, one which will hold the result of
+ a character function. This will have to be named sometime, probably in
+ mkarg(). */
+
+ if(procleng < 0) {
+ np->vleng = (expptr) mkarg(TYLENG, chlgslot);
+ np->vleng->addrblock.uname_tag = UNAM_IDENT;
+ strcpy (np -> vleng -> addrblock.user.ident,
+ new_func_length());
+ }
+ if (!xretslot[TYCHAR]) {
+ xretslot[TYCHAR] = rs =
+ autovar(0, type, ISCONST(np->vleng)
+ ? np->vleng : ICON(0), "");
+ strcpy(rs->user.ident, "ret_val");
+ }
+ }
+
+/* Handle a complex return type -- declare a new parameter (pointer to
+ a complex value) */
+
+ else if( ISCOMPLEX(type) ) {
+ if (!xretslot[type])
+ xretslot[type] =
+ autovar(0, type, EXNULL, " ret_val");
+ /* the blank is for use in out_addr */
+ np->vstg = STGARG;
+ if(cxslot < 0)
+ cxslot = nextarg(TYADDR);
+ }
+ else if (type != TYSUBR) {
+ if (type == TYUNKNOWN) {
+ dclerr("untyped function", np);
+ proctype = type = np->vtype =
+ dflttype[letter(np->fvarname[0])];
+ }
+ if (!xretslot[type])
+ xretslot[type] = retslot =
+ autovar(1, type, EXNULL, " ret_val");
+ /* the blank is for use in out_addr */
+ np->vstg = STGAUTO;
+ }
+
+ for(p = ep->arglist ; p ; p = p->nextp)
+ if(! (( q = (Namep) (p->datap) )->vknownarg) ) {
+ q->vknownarg = 1;
+ q->vardesc.varno = nextarg(TYADDR);
+ allargs = mkchain((char *)q, allargs);
+ q->argno = nallargs++;
+ }
+ else if (nentry == 1)
+ duparg(q);
+ else for(p1 = ep->arglist ; p1 != p; p1 = p1->nextp)
+ if ((Namep)p1->datap == q)
+ duparg(q);
+
+ k = 0;
+ for(p = ep->arglist ; p ; p = p->nextp) {
+ if(! (( q = (Namep) (p->datap) )->vdcldone) )
+ {
+ impldcl(q);
+ q->vdcldone = YES;
+ if(q->vtype == TYCHAR)
+ {
+
+/* If we don't know the length of a char*(*) (i.e. a string), we must add
+ in this additional length argument. */
+
+ ++nallchargs;
+ if (q->vclass == CLPROC)
+ nallchargs--;
+ else if (q->vleng == NULL) {
+ /* character*(*) */
+ q->vleng = (expptr)
+ mkarg(TYLENG, nextarg(TYLENG) );
+ unamstring((Addrp)q->vleng,
+ new_arg_length(q));
+ }
+ }
+ }
+ if (q->vdimfinish)
+ dim_finish(q);
+ if (q->vtype == TYCHAR && q->vclass != CLPROC)
+ k++;
+ }
+
+ if (entryname->extype != type)
+ changedtype(np);
+
+ /* save information for checking consistency of arg lists */
+
+ it = infertypes;
+ if (entryname->exproto)
+ infertypes = 1;
+ save_argtypes(ep->arglist, &entryname->arginfo, &np->arginfo,
+ 0, np->fvarname, STGEXT, k, np->vtype, 2);
+ infertypes = it;
+}
+
+
+
+ LOCAL int
+#ifdef KR_headers
+nextarg(type)
+ int type;
+#else
+nextarg(int type)
+#endif
+{
+ type = type; /* shut up warning */
+ return(lastargslot++);
+ }
+
+ LOCAL void
+#ifdef KR_headers
+dim_check(q)
+ Namep q;
+#else
+dim_check(Namep q)
+#endif
+{
+ register struct Dimblock *vdim = q->vdim;
+ register expptr nelt;
+
+ if(!(nelt = vdim->nelt) || !ISCONST(nelt))
+ dclerr("adjustable dimension on non-argument", q);
+ else if (!ONEOF(nelt->headblock.vtype, MSKINT|MSKREAL))
+ bad_dimtype(q);
+ else if (ISINT(nelt->headblock.vtype)
+ && nelt->constblock.Const.ci <= 0
+ || nelt->constblock.Const.cd[0] <= 0)
+ dclerr("nonpositive dimension", q);
+ }
+
+ LOCAL void
+dobss(Void)
+{
+ register struct Hashentry *p;
+ register Namep q;
+ int qstg, qclass, qtype;
+ Extsym *e;
+
+ for(p = hashtab ; p<lasthash ; ++p)
+ if(q = p->varp)
+ {
+ qstg = q->vstg;
+ qtype = q->vtype;
+ qclass = q->vclass;
+
+ if( (qclass==CLUNKNOWN && qstg!=STGARG) ||
+ (qclass==CLVAR && qstg==STGUNKNOWN) ) {
+ if (!(q->vis_assigned | q->vimpldovar))
+ warn1("local variable %s never used",
+ q->fvarname);
+ }
+ else if(qclass==CLVAR && qstg==STGBSS)
+ { ; }
+
+/* Give external procedures the proper storage class */
+
+ else if(qclass==CLPROC && q->vprocclass==PEXTERNAL
+ && qstg!=STGARG) {
+ e = mkext(q->fvarname,addunder(q->cvarname));
+ e->extstg = STGEXT;
+ q->vardesc.varno = e - extsymtab;
+ if (e->extype != qtype)
+ changedtype(q);
+ }
+ if(qclass==CLVAR) {
+ if (qstg != STGARG && q->vdim)
+ dim_check(q);
+ } /* if qclass == CLVAR */
+ }
+
+}
+
+
+ void
+donmlist(Void)
+{
+ register struct Hashentry *p;
+ register Namep q;
+
+ for(p=hashtab; p<lasthash; ++p)
+ if( (q = p->varp) && q->vclass==CLNAMELIST)
+ namelist(q);
+}
+
+
+/* iarrlen -- Returns the size of the array in bytes, or -1 */
+
+ ftnint
+#ifdef KR_headers
+iarrlen(q)
+ register Namep q;
+#else
+iarrlen(register Namep q)
+#endif
+{
+ ftnint leng;
+
+ leng = typesize[q->vtype];
+ if(leng <= 0)
+ return(-1);
+ if(q->vdim)
+ if( ISICON(q->vdim->nelt) )
+ leng *= q->vdim->nelt->constblock.Const.ci;
+ else return(-1);
+ if(q->vleng)
+ if( ISICON(q->vleng) )
+ leng *= q->vleng->constblock.Const.ci;
+ else return(-1);
+ return(leng);
+}
+
+ void
+#ifdef KR_headers
+namelist(np)
+ Namep np;
+#else
+namelist(Namep np)
+#endif
+{
+ register chainp q;
+ register Namep v;
+ int y;
+
+ if (!np->visused)
+ return;
+ y = 0;
+
+ for(q = np->varxptr.namelist ; q ; q = q->nextp)
+ {
+ vardcl( v = (Namep) (q->datap) );
+ if( !ONEOF(v->vstg, MSKSTATIC) )
+ dclerr("may not appear in namelist", v);
+ else {
+ v->vnamelist = 1;
+ v->visused = 1;
+ v->vsave = 1;
+ y = 1;
+ }
+ np->visused = y;
+ }
+}
+
+/* docommon -- called at the end of procedure declarations, before
+ equivalences and the procedure body */
+
+ LOCAL void
+docommon(Void)
+{
+ register Extsym *extptr;
+ register chainp q, q1;
+ struct Dimblock *t;
+ expptr neltp;
+ register Namep comvar;
+ ftnint size;
+ int i, k, pref, type;
+ extern int type_pref[];
+
+ for(extptr = extsymtab ; extptr<nextext ; ++extptr)
+ if (extptr->extstg == STGCOMMON && (q = extptr->extp)) {
+
+/* If a common declaration also had a list of variables ... */
+
+ q = extptr->extp = revchain(q);
+ pref = 1;
+ for(k = TYCHAR; q ; q = q->nextp)
+ {
+ comvar = (Namep) (q->datap);
+
+ if(comvar->vdcldone == NO)
+ vardcl(comvar);
+ type = comvar->vtype;
+ if (pref < type_pref[type])
+ pref = type_pref[k = type];
+ if(extptr->extleng % typealign[type] != 0) {
+ dclerr("common alignment", comvar);
+ --nerr; /* don't give bad return code for this */
+#if 0
+ extptr->extleng = roundup(extptr->extleng, typealign[type]);
+#endif
+ } /* if extptr -> extleng % */
+
+/* Set the offset into the common block */
+
+ comvar->voffset = extptr->extleng;
+ comvar->vardesc.varno = extptr - extsymtab;
+ if(type == TYCHAR)
+ if (comvar->vleng)
+ size = comvar->vleng->constblock.Const.ci;
+ else {
+ dclerr("character*(*) in common", comvar);
+ size = 1;
+ }
+ else
+ size = typesize[type];
+ if(t = comvar->vdim)
+ if( (neltp = t->nelt) && ISCONST(neltp) )
+ size *= neltp->constblock.Const.ci;
+ else
+ dclerr("adjustable array in common", comvar);
+
+/* Adjust the length of the common block so far */
+
+ extptr->extleng += size;
+ } /* for */
+
+ extptr->extype = k;
+
+/* Determine curno and, if new, save this identifier chain */
+
+ q1 = extptr->extp;
+ for (q = extptr->allextp, i = 0; q; i++, q = q->nextp)
+ if (struct_eq((chainp)q->datap, q1))
+ break;
+ if (q)
+ extptr->curno = extptr->maxno - i;
+ else {
+ extptr->curno = ++extptr->maxno;
+ extptr->allextp = mkchain((char *)extptr->extp,
+ extptr->allextp);
+ }
+ } /* if extptr -> extstg == STGCOMMON */
+
+/* Now the hash table entries have STGCOMMON, vdcldone, voffset, and
+ varno. And the common block itself has its full size in extleng. */
+
+} /* docommon */
+
+
+/* copy_data -- copy the Namep entries so they are available even after
+ the hash table is empty */
+
+ void
+#ifdef KR_headers
+copy_data(list)
+ chainp list;
+#else
+copy_data(chainp list)
+#endif
+{
+ for (; list; list = list -> nextp) {
+ Namep namep = ALLOC (Nameblock);
+ int size, nd, i;
+ struct Dimblock *dp;
+
+ cpn(sizeof(struct Nameblock), list->datap, (char *)namep);
+ namep->fvarname = strcpy(gmem(strlen(namep->fvarname)+1,0),
+ namep->fvarname);
+ namep->cvarname = strcmp(namep->fvarname, namep->cvarname)
+ ? strcpy(gmem(strlen(namep->cvarname)+1,0), namep->cvarname)
+ : namep->fvarname;
+ if (namep -> vleng)
+ namep -> vleng = (expptr) cpexpr (namep -> vleng);
+ if (namep -> vdim) {
+ nd = namep -> vdim -> ndim;
+ size = sizeof(int) + (3 + 2 * nd) * sizeof (expptr);
+ dp = (struct Dimblock *) ckalloc (size);
+ cpn(size, (char *)namep->vdim, (char *)dp);
+ namep -> vdim = dp;
+ dp->nelt = (expptr)cpexpr(dp->nelt);
+ for (i = 0; i < nd; i++) {
+ dp -> dims[i].dimsize = (expptr) cpexpr (dp -> dims[i].dimsize);
+ } /* for */
+ } /* if */
+ list -> datap = (char *) namep;
+ } /* for */
+} /* copy_data */
+
+
+
+ LOCAL void
+docomleng(Void)
+{
+ register Extsym *p;
+
+ for(p = extsymtab ; p < nextext ; ++p)
+ if(p->extstg == STGCOMMON)
+ {
+ if(p->maxleng!=0 && p->extleng!=0 && p->maxleng!=p->extleng
+ && strcmp(Blank, p->cextname) )
+ warn1("incompatible lengths for common block %.60s",
+ p->fextname);
+ if(p->maxleng < p->extleng)
+ p->maxleng = p->extleng;
+ p->extleng = 0;
+ }
+}
+
+
+/* ROUTINES DEALING WITH AUTOMATIC AND TEMPORARY STORAGE */
+
+ void
+#ifdef KR_headers
+frtemp(p)
+ Addrp p;
+#else
+frtemp(Addrp p)
+#endif
+{
+ /* put block on chain of temps to be reclaimed */
+ holdtemps = mkchain((char *)p, holdtemps);
+}
+
+ void
+freetemps(Void)
+{
+ register chainp p, p1;
+ register Addrp q;
+ register int t;
+
+ p1 = holdtemps;
+ while(p = p1) {
+ q = (Addrp)p->datap;
+ t = q->vtype;
+ if (t == TYCHAR && q->varleng != 0) {
+ /* restore clobbered character string lengths */
+ frexpr(q->vleng);
+ q->vleng = ICON(q->varleng);
+ }
+ p1 = p->nextp;
+ p->nextp = templist[t];
+ templist[t] = p;
+ }
+ holdtemps = 0;
+ }
+
+/* allocate an automatic variable slot for each of nelt variables */
+
+ Addrp
+#ifdef KR_headers
+autovar(nelt0, t, lengp, name)
+ register int nelt0;
+ register int t;
+ expptr lengp;
+ char *name;
+#else
+autovar(register int nelt0, register int t, expptr lengp, char *name)
+#endif
+{
+ ftnint leng;
+ register Addrp q;
+ register int nelt = nelt0 > 0 ? nelt0 : 1;
+ extern char *av_pfix[];
+
+ if(t == TYCHAR)
+ if( ISICON(lengp) )
+ leng = lengp->constblock.Const.ci;
+ else {
+ Fatal("automatic variable of nonconstant length");
+ }
+ else
+ leng = typesize[t];
+
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ q->vtype = t;
+ if(t == TYCHAR)
+ {
+ q->vleng = ICON(leng);
+ q->varleng = leng;
+ }
+ q->vstg = STGAUTO;
+ q->ntempelt = nelt;
+ q->isarray = (nelt > 1);
+ q->memoffset = ICON(0);
+
+ /* kludge for nls so we can have ret_val rather than ret_val_4 */
+ if (*name == ' ')
+ unamstring(q, name);
+ else {
+ q->uname_tag = UNAM_IDENT;
+ temp_name(av_pfix[t], ++autonum[t], q->user.ident);
+ }
+ if (nelt0 > 0)
+ declare_new_addr (q);
+ return(q);
+}
+
+
+/* Returns a temporary of the appropriate type. Will reuse existing
+ temporaries when possible */
+
+ Addrp
+#ifdef KR_headers
+mktmpn(nelt, type, lengp)
+ int nelt;
+ register int type;
+ expptr lengp;
+#else
+mktmpn(int nelt, register int type, expptr lengp)
+#endif
+{
+ ftnint leng;
+ chainp p, oldp;
+ register Addrp q;
+ extern int krparens;
+
+ if(type==TYUNKNOWN || type==TYERROR)
+ badtype("mktmpn", type);
+
+ if(type==TYCHAR)
+ if(lengp && ISICON(lengp) )
+ leng = lengp->constblock.Const.ci;
+ else {
+ err("adjustable length");
+ return( (Addrp) errnode() );
+ }
+ else if (type > TYCHAR || type < TYADDR) {
+ erri("mktmpn: unexpected type %d", type);
+ exit(1);
+ }
+/*
+ * if a temporary of appropriate shape is on the templist,
+ * remove it from the list and return it
+ */
+ if (krparens == 2 && ONEOF(type,M(TYREAL)|M(TYCOMPLEX)))
+ type++;
+ for(oldp=CHNULL, p=templist[type]; p ; oldp=p, p=p->nextp)
+ {
+ q = (Addrp) (p->datap);
+ if(q->ntempelt==nelt &&
+ (type!=TYCHAR || q->vleng->constblock.Const.ci==leng) )
+ {
+ if(oldp)
+ oldp->nextp = p->nextp;
+ else
+ templist[type] = p->nextp;
+ free( (charptr) p);
+ return(q);
+ }
+ }
+ q = autovar(nelt, type, lengp, "");
+ return(q);
+}
+
+
+
+
+/* mktmp -- create new local variable; call it something like name
+ lengp is taken directly, not copied */
+
+ Addrp
+#ifdef KR_headers
+mktmp(type, lengp)
+ int type;
+ expptr lengp;
+#else
+mktmp(int type, expptr lengp)
+#endif
+{
+ Addrp rv;
+ /* arrange for temporaries to be recycled */
+ /* at the end of this statement... */
+ rv = mktmpn(1,type,lengp);
+ frtemp((Addrp)cpexpr((expptr)rv));
+ return rv;
+}
+
+/* mktmp0 omits frtemp() */
+ Addrp
+#ifdef KR_headers
+mktmp0(type, lengp)
+ int type;
+ expptr lengp;
+#else
+mktmp0(int type, expptr lengp)
+#endif
+{
+ Addrp rv;
+ /* arrange for temporaries to be recycled */
+ /* when this Addrp is freed */
+ rv = mktmpn(1,type,lengp);
+ rv->istemp = YES;
+ return rv;
+}
+
+/* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */
+
+/* comblock -- Declare a new common block. Input parameters name the block;
+ s will be NULL if the block is unnamed */
+
+ Extsym *
+#ifdef KR_headers
+comblock(s)
+ register char *s;
+#else
+comblock(register char *s)
+#endif
+{
+ Extsym *p;
+ register char *t;
+ register int c, i;
+ char cbuf[256], *s0;
+
+/* Give the unnamed common block a unique name */
+
+ if(*s == 0)
+ p = mkext1(s0 = Blank, Blank);
+ else {
+ s0 = s;
+ t = cbuf;
+ for(i = 0; c = *t = *s++; t++)
+ if (c == '_')
+ i = 1;
+ if (i)
+ *t++ = '_';
+ t[0] = '_';
+ t[1] = 0;
+ p = mkext1(s0,cbuf);
+ }
+ if(p->extstg == STGUNKNOWN)
+ p->extstg = STGCOMMON;
+ else if(p->extstg != STGCOMMON)
+ {
+ errstr("%.52s cannot be a common block: it is a subprogram.",
+ s0);
+ return(0);
+ }
+
+ return( p );
+}
+
+
+/* incomm -- add a new variable to a common declaration */
+
+ void
+#ifdef KR_headers
+incomm(c, v)
+ Extsym *c;
+ Namep v;
+#else
+incomm(Extsym *c, Namep v)
+#endif
+{
+ if (!c)
+ return;
+ if(v->vstg != STGUNKNOWN && !v->vimplstg)
+ dclerr(v->vstg == STGARG
+ ? "dummy arguments cannot be in common"
+ : "incompatible common declaration", v);
+ else
+ {
+ v->vstg = STGCOMMON;
+ c->extp = mkchain((char *)v, c->extp);
+ }
+}
+
+
+
+
+/* settype -- set the type or storage class of a Namep object. If
+ v -> vstg == STGUNKNOWN && type < 0, attempt to reset vstg to be
+ -type. This function will not change any earlier definitions in v,
+ in will only attempt to fill out more information give the other params */
+
+ void
+#ifdef KR_headers
+settype(v, type, length)
+ register Namep v;
+ register int type;
+ register ftnint length;
+#else
+settype(register Namep v, register int type, register ftnint length)
+#endif
+{
+ int type1;
+
+ if(type == TYUNKNOWN)
+ return;
+
+ if(type==TYSUBR && v->vtype!=TYUNKNOWN && v->vstg==STGARG)
+ {
+ v->vtype = TYSUBR;
+ frexpr(v->vleng);
+ v->vleng = 0;
+ v->vimpltype = 0;
+ }
+ else if(type < 0) /* storage class set */
+ {
+ if(v->vstg == STGUNKNOWN)
+ v->vstg = - type;
+ else if(v->vstg != -type)
+ dclerr("incompatible storage declarations", v);
+ }
+ else if(v->vtype == TYUNKNOWN
+ || v->vtype != type
+ && (v->vimpltype || v->vinftype || v->vinfproc))
+ {
+ if( (v->vtype = lengtype(type, length))==TYCHAR )
+ if (length>=0)
+ v->vleng = ICON(length);
+ else if (parstate >= INDATA)
+ v->vleng = ICON(1); /* avoid a memory fault */
+ v->vimpltype = 0;
+ v->vinftype = 0; /* 19960709 */
+ v->vinfproc = 0; /* 19960709 */
+
+ if (v->vclass == CLPROC) {
+ if (v->vstg == STGEXT
+ && (type1 = extsymtab[v->vardesc.varno].extype)
+ && type1 != v->vtype)
+ changedtype(v);
+ else if (v->vprocclass == PTHISPROC
+ && (parstate >= INDATA
+ || procclass == CLMAIN)
+ && !xretslot[type]) {
+ xretslot[type] = autovar(ONEOF(type,
+ MSKCOMPLEX|MSKCHAR) ? 0 : 1, type,
+ v->vleng, " ret_val");
+ if (procclass == CLMAIN)
+ errstr(
+ "illegal use of %.60s (main program name)",
+ v->fvarname);
+ /* not completely right, but enough to */
+ /* avoid memory faults; we won't */
+ /* emit any C as we have illegal Fortran */
+ }
+ }
+ }
+ else if(v->vtype != type && v->vtype != lengtype(type, length)) {
+ incompat:
+ dclerr("incompatible type declarations", v);
+ }
+ else if (type==TYCHAR)
+ if (v->vleng && v->vleng->constblock.Const.ci != length)
+ goto incompat;
+ else if (parstate >= INDATA)
+ v->vleng = ICON(1); /* avoid a memory fault */
+}
+
+
+
+
+
+/* lengtype -- returns the proper compiler type, given input of Fortran
+ type and length specifier */
+
+ int
+#ifdef KR_headers
+lengtype(type, len)
+ register int type;
+ ftnint len;
+#else
+lengtype(register int type, ftnint len)
+#endif
+{
+ register int length = (int)len;
+ switch(type)
+ {
+ case TYREAL:
+ if(length == typesize[TYDREAL])
+ return(TYDREAL);
+ if(length == typesize[TYREAL])
+ goto ret;
+ break;
+
+ case TYCOMPLEX:
+ if(length == typesize[TYDCOMPLEX])
+ return(TYDCOMPLEX);
+ if(length == typesize[TYCOMPLEX])
+ goto ret;
+ break;
+
+ case TYINT1:
+ case TYSHORT:
+ case TYDREAL:
+ case TYDCOMPLEX:
+ case TYCHAR:
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYUNKNOWN:
+ case TYSUBR:
+ case TYERROR:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ goto ret;
+
+ case TYLOGICAL:
+ switch(length) {
+ case 0: return tylog;
+ case 1: return TYLOGICAL1;
+ case 2: return TYLOGICAL2;
+ case 4: goto ret;
+ }
+ break;
+
+ case TYLONG:
+ if(length == 0)
+ return(tyint);
+ if (length == 1)
+ return TYINT1;
+ if(length == typesize[TYSHORT])
+ return(TYSHORT);
+#ifdef TYQUAD
+ if(length == typesize[TYQUAD] && use_tyquad)
+ return(TYQUAD);
+#endif
+ if(length == typesize[TYLONG])
+ goto ret;
+ break;
+ default:
+ badtype("lengtype", type);
+ }
+
+ if(len != 0)
+ err("incompatible type-length combination");
+
+ret:
+ return(type);
+}
+
+
+
+
+
+/* setintr -- Set Intrinsic function */
+
+ void
+#ifdef KR_headers
+setintr(v)
+ register Namep v;
+#else
+setintr(register Namep v)
+#endif
+{
+ int k;
+
+ if(k = intrfunct(v->fvarname)) {
+ if ((*(struct Intrpacked *)&k).f4)
+ if (noextflag)
+ goto unknown;
+ else
+ dcomplex_seen++;
+ v->vardesc.varno = k;
+ }
+ else {
+ unknown:
+ dclerr("unknown intrinsic function", v);
+ return;
+ }
+ if(v->vstg == STGUNKNOWN)
+ v->vstg = STGINTR;
+ else if(v->vstg!=STGINTR)
+ dclerr("incompatible use of intrinsic function", v);
+ if(v->vclass==CLUNKNOWN)
+ v->vclass = CLPROC;
+ if(v->vprocclass == PUNKNOWN)
+ v->vprocclass = PINTRINSIC;
+ else if(v->vprocclass != PINTRINSIC)
+ dclerr("invalid intrinsic declaration", v);
+}
+
+
+
+/* setext -- Set External declaration -- assume that unknowns will become
+ procedures */
+
+ void
+#ifdef KR_headers
+setext(v)
+ register Namep v;
+#else
+setext(register Namep v)
+#endif
+{
+ if(v->vclass == CLUNKNOWN)
+ v->vclass = CLPROC;
+ else if(v->vclass != CLPROC)
+ dclerr("invalid external declaration", v);
+
+ if(v->vprocclass == PUNKNOWN)
+ v->vprocclass = PEXTERNAL;
+ else if(v->vprocclass != PEXTERNAL)
+ dclerr("invalid external declaration", v);
+} /* setext */
+
+
+
+
+/* create dimensions block for array variable */
+
+ void
+#ifdef KR_headers
+setbound(v, nd, dims)
+ register Namep v;
+ int nd;
+ struct Dims *dims;
+#else
+setbound(register Namep v, int nd, struct Dims *dims)
+#endif
+{
+ register expptr q, t;
+ register struct Dimblock *p;
+ int i;
+ extern chainp new_vars;
+ char buf[256];
+
+ if(v->vclass == CLUNKNOWN)
+ v->vclass = CLVAR;
+ else if(v->vclass != CLVAR)
+ {
+ dclerr("only variables may be arrays", v);
+ return;
+ }
+
+ v->vdim = p = (struct Dimblock *)
+ ckalloc( sizeof(int) + (3+2*nd)*sizeof(expptr) );
+ p->ndim = nd--;
+ p->nelt = ICON(1);
+ doin_setbound = 1;
+
+ if (noextflag)
+ for(i = 0; i <= nd; i++)
+ if (((q = dims[i].lb) && !ISINT(q->headblock.vtype))
+ || ((q = dims[i].ub) && !ISINT(q->headblock.vtype))) {
+ sprintf(buf, "dimension %d of %s is not an integer.",
+ i+1, v->fvarname);
+ errext(buf);
+ break;
+ }
+
+ for(i = 0; i <= nd; i++) {
+ if (((q = dims[i].lb) && !ISINT(q->headblock.vtype)))
+ dims[i].lb = mkconv(TYINT, q);
+ if (((q = dims[i].ub) && !ISINT(q->headblock.vtype)))
+ dims[i].ub = mkconv(TYINT, q);
+ }
+
+ for(i = 0; i <= nd; ++i)
+ {
+ if( (q = dims[i].ub) == NULL)
+ {
+ if(i == nd)
+ {
+ frexpr(p->nelt);
+ p->nelt = NULL;
+ }
+ else
+ err("only last bound may be asterisk");
+ p->dims[i].dimsize = ICON(1);
+ p->dims[i].dimexpr = NULL;
+ }
+ else
+ {
+
+ if(dims[i].lb)
+ {
+ q = mkexpr(OPMINUS, q, cpexpr(dims[i].lb));
+ q = mkexpr(OPPLUS, q, ICON(1) );
+ }
+ if( ISCONST(q) )
+ {
+ p->dims[i].dimsize = q;
+ p->dims[i].dimexpr = (expptr) PNULL;
+ }
+ else {
+ sprintf(buf, " %s_dim%d", v->fvarname, i+1);
+ p->dims[i].dimsize = (expptr)
+ autovar(1, tyint, EXNULL, buf);
+ p->dims[i].dimexpr = q;
+ if (i == nd)
+ v->vlastdim = new_vars;
+ v->vdimfinish = 1;
+ }
+ if(p->nelt)
+ p->nelt = mkexpr(OPSTAR, p->nelt,
+ cpexpr(p->dims[i].dimsize) );
+ }
+ }
+
+ q = dims[nd].lb;
+ if(q == NULL)
+ q = ICON(1);
+
+ for(i = nd-1 ; i>=0 ; --i)
+ {
+ t = dims[i].lb;
+ if(t == NULL)
+ t = ICON(1);
+ if(p->dims[i].dimsize)
+ q = mkexpr(OPPLUS, t,
+ mkexpr(OPSTAR, cpexpr(p->dims[i].dimsize), q));
+ }
+
+ if( ISCONST(q) )
+ {
+ p->baseoffset = q;
+ p->basexpr = NULL;
+ }
+ else
+ {
+ sprintf(buf, " %s_offset", v->fvarname);
+ p->baseoffset = (expptr) autovar(1, tyint, EXNULL, buf);
+ p->basexpr = q;
+ v->vdimfinish = 1;
+ }
+ doin_setbound = 0;
+}
+
+
+ void
+#ifdef KR_headers
+wr_abbrevs(outfile, function_head, vars)
+ FILE *outfile;
+ int function_head;
+ chainp vars;
+#else
+wr_abbrevs(FILE *outfile, int function_head, chainp vars)
+#endif
+{
+ for (; vars; vars = vars -> nextp) {
+ Namep name = (Namep) vars -> datap;
+ if (!name->visused)
+ continue;
+
+ if (function_head)
+ nice_printf (outfile, "#define ");
+ else
+ nice_printf (outfile, "#undef ");
+ out_name (outfile, name);
+
+ if (function_head) {
+ Extsym *comm = &extsymtab[name -> vardesc.varno];
+
+ nice_printf (outfile, " (");
+ extern_out (outfile, comm);
+ nice_printf (outfile, "%d.", comm->curno);
+ nice_printf (outfile, "%s)", name->cvarname);
+ } /* if function_head */
+ nice_printf (outfile, "\n");
+ } /* for */
+} /* wr_abbrevs */
diff --git a/usr.bin/f2c/put.c b/usr.bin/f2c/put.c
new file mode 100644
index 0000000..25425c5
--- /dev/null
+++ b/usr.bin/f2c/put.c
@@ -0,0 +1,441 @@
+/****************************************************************
+Copyright 1990, 1991, 1993, 1994, 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/*
+ * INTERMEDIATE CODE GENERATION PROCEDURES COMMON TO BOTH
+ * JOHNSON (PORTABLE) AND RITCHIE FAMILIES OF SECOND PASSES
+*/
+
+#include "defs.h"
+#include "names.h" /* For LOCAL_CONST_NAME */
+#include "pccdefs.h"
+#include "p1defs.h"
+
+/* Definitions for putconst() */
+
+#define LIT_CHAR 1
+#define LIT_FLOAT 2
+#define LIT_INT 3
+
+
+/*
+char *ops [ ] =
+ {
+ "??", "+", "-", "*", "/", "**", "-",
+ "OR", "AND", "EQV", "NEQV", "NOT",
+ "CONCAT",
+ "<", "==", ">", "<=", "!=", ">=",
+ " of ", " ofC ", " = ", " += ", " *= ", " CONV ", " << ", " % ",
+ " , ", " ? ", " : "
+ " abs ", " min ", " max ", " addr ", " indirect ",
+ " bitor ", " bitand ", " bitxor ", " bitnot ", " >> ",
+ };
+*/
+
+/* Each of these values is defined in pccdefs */
+
+int ops2 [ ] =
+{
+ P2BAD, P2PLUS, P2MINUS, P2STAR, P2SLASH, P2BAD, P2NEG,
+ P2OROR, P2ANDAND, P2EQ, P2NE, P2NOT,
+ P2BAD,
+ P2LT, P2EQ, P2GT, P2LE, P2NE, P2GE,
+ P2CALL, P2CALL, P2ASSIGN, P2PLUSEQ, P2STAREQ, P2CONV, P2LSHIFT, P2MOD,
+ P2COMOP, P2QUEST, P2COLON,
+ 1, P2BAD, P2BAD, P2BAD, P2BAD,
+ P2BITOR, P2BITAND, P2BITXOR, P2BITNOT, P2RSHIFT,
+ P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD, P2BAD,
+ P2BAD, P2BAD, P2BAD, P2BAD,
+ 1,1,1,1,1, /* OPNEG1, OPDMIN, OPDMAX, OPASSIGNI, OPIDENTITY */
+ 1,1,1,1, /* OPCHARCAST, OPDABS, OPMIN2, OPMAX2 */
+ 1,1,1,1,1 /* OPBITTEST, OPBITCLR, OPBITSET, OPQBIT{CLR,SET} */
+};
+
+
+ void
+#ifdef KR_headers
+putexpr(p)
+ expptr p;
+#else
+putexpr(expptr p)
+#endif
+{
+/* Write the expression to the p1 file */
+
+ p = (expptr) putx (fixtype (p));
+ p1_expr (p);
+}
+
+
+
+
+
+ expptr
+#ifdef KR_headers
+putassign(lp, rp)
+ expptr lp;
+ expptr rp;
+#else
+putassign(expptr lp, expptr rp)
+#endif
+{
+ return putx(fixexpr((Exprp)mkexpr(OPASSIGN, lp, rp)));
+}
+
+
+
+
+ void
+#ifdef KR_headers
+puteq(lp, rp)
+ expptr lp;
+ expptr rp;
+#else
+puteq(expptr lp, expptr rp)
+#endif
+{
+ putexpr(mkexpr(OPASSIGN, lp, rp) );
+}
+
+
+
+
+/* put code for a *= b */
+
+ expptr
+#ifdef KR_headers
+putsteq(a, b)
+ Addrp a;
+ Addrp b;
+#else
+putsteq(Addrp a, Addrp b)
+#endif
+{
+ return putx( fixexpr((Exprp)
+ mkexpr(OPSTAREQ, cpexpr((expptr)a), cpexpr((expptr)b))));
+}
+
+
+
+
+ Addrp
+#ifdef KR_headers
+mkfield(res, f, ty)
+ register Addrp res;
+ char *f;
+ int ty;
+#else
+mkfield(register Addrp res, char *f, int ty)
+#endif
+{
+ res -> vtype = ty;
+ res -> Field = f;
+ return res;
+} /* mkfield */
+
+
+ Addrp
+#ifdef KR_headers
+realpart(p)
+ register Addrp p;
+#else
+realpart(register Addrp p)
+#endif
+{
+ register Addrp q;
+
+ if (p->tag == TADDR
+ && p->uname_tag == UNAM_CONST
+ && ISCOMPLEX (p->vtype))
+ return (Addrp)mkrealcon (p -> vtype + TYREAL - TYCOMPLEX,
+ p->user.kludge.vstg1 ? p->user.Const.cds[0]
+ : cds(dtos(p->user.Const.cd[0]),CNULL));
+
+ q = (Addrp) cpexpr((expptr) p);
+ if( ISCOMPLEX(p->vtype) )
+ q = mkfield (q, "r", p -> vtype + TYREAL - TYCOMPLEX);
+
+ return(q);
+}
+
+
+
+
+ expptr
+#ifdef KR_headers
+imagpart(p)
+ register Addrp p;
+#else
+imagpart(register Addrp p)
+#endif
+{
+ register Addrp q;
+
+ if( ISCOMPLEX(p->vtype) )
+ {
+ if (p->tag == TADDR && p->uname_tag == UNAM_CONST)
+ return mkrealcon (p -> vtype + TYREAL - TYCOMPLEX,
+ p->user.kludge.vstg1 ? p->user.Const.cds[1]
+ : cds(dtos(p->user.Const.cd[1]),CNULL));
+ q = (Addrp) cpexpr((expptr) p);
+ q = mkfield (q, "i", p -> vtype + TYREAL - TYCOMPLEX);
+ return( (expptr) q );
+ }
+ else
+
+/* Cast an integer type onto a Double Real type */
+
+ return( mkrealcon( ISINT(p->vtype) ? TYDREAL : p->vtype , "0"));
+}
+
+
+
+
+
+/* ncat -- computes the number of adjacent concatenation operations */
+
+ int
+#ifdef KR_headers
+ncat(p)
+ register expptr p;
+#else
+ncat(register expptr p)
+#endif
+{
+ if(p->tag==TEXPR && p->exprblock.opcode==OPCONCAT)
+ return( ncat(p->exprblock.leftp) + ncat(p->exprblock.rightp) );
+ else return(1);
+}
+
+
+
+
+/* lencat -- returns the length of the concatenated string. Each
+ substring must have a static (i.e. compile-time) fixed length */
+
+ ftnint
+#ifdef KR_headers
+lencat(p)
+ register expptr p;
+#else
+lencat(register expptr p)
+#endif
+{
+ if(p->tag==TEXPR && p->exprblock.opcode==OPCONCAT)
+ return( lencat(p->exprblock.leftp) + lencat(p->exprblock.rightp) );
+ else if( p->headblock.vleng!=NULL && ISICON(p->headblock.vleng) )
+ return(p->headblock.vleng->constblock.Const.ci);
+ else if(p->tag==TADDR && p->addrblock.varleng!=0)
+ return(p->addrblock.varleng);
+ else
+ {
+ err("impossible element in concatenation");
+ return(0);
+ }
+}
+
+/* putconst -- Creates a new Addrp value which maps onto the input
+ constant value. The Addrp doesn't retain the value of the constant,
+ instead that value is copied into a table of constants (called
+ litpool, for pool of literal values). The only way to retrieve the
+ actual value of the constant is to look at the memno field of the
+ Addrp result. You know that the associated literal is the one referred
+ to by q when (q -> memno == litp -> litnum).
+*/
+
+ Addrp
+#ifdef KR_headers
+putconst(p)
+ register Constp p;
+#else
+putconst(register Constp p)
+#endif
+{
+ register Addrp q;
+ struct Literal *litp, *lastlit;
+ int k, len, type;
+ int litflavor;
+ double cd[2];
+ ftnint nblanks;
+ char *strp;
+ char cdsbuf0[64], cdsbuf1[64], *ds[2];
+
+ if (p->tag != TCONST)
+ badtag("putconst", p->tag);
+
+ q = ALLOC(Addrblock);
+ q->tag = TADDR;
+ type = p->vtype;
+ q->vtype = ( type==TYADDR ? tyint : type );
+ q->vleng = (expptr) cpexpr(p->vleng);
+ q->vstg = STGCONST;
+
+/* Create the new label for the constant. This is wasteful of labels
+ because when the constant value already exists in the literal pool,
+ this label gets thrown away and is never reclaimed. It might be
+ cleaner to move this down past the first switch() statement below */
+
+ q->memno = newlabel();
+ q->memoffset = ICON(0);
+ q -> uname_tag = UNAM_CONST;
+
+/* Copy the constant info into the Addrblock; do this by copying the
+ largest storage elts */
+
+ q -> user.Const = p -> Const;
+ q->user.kludge.vstg1 = p->vstg; /* distinguish string from binary fp */
+
+ /* check for value in literal pool, and update pool if necessary */
+
+ k = 1;
+ switch(type)
+ {
+ case TYCHAR:
+ if (halign) {
+ strp = p->Const.ccp;
+ nblanks = p->Const.ccp1.blanks;
+ len = p->vleng->constblock.Const.ci;
+ litflavor = LIT_CHAR;
+ goto loop;
+ }
+ else
+ q->memno = BAD_MEMNO;
+ break;
+ case TYCOMPLEX:
+ case TYDCOMPLEX:
+ k = 2;
+ if (p->vstg)
+ cd[1] = atof(ds[1] = p->Const.cds[1]);
+ else
+ ds[1] = cds(dtos(cd[1] = p->Const.cd[1]), cdsbuf1);
+ case TYREAL:
+ case TYDREAL:
+ litflavor = LIT_FLOAT;
+ if (p->vstg)
+ cd[0] = atof(ds[0] = p->Const.cds[0]);
+ else
+ ds[0] = cds(dtos(cd[0] = p->Const.cd[0]), cdsbuf0);
+ goto loop;
+
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+ case TYLONG:
+ case TYSHORT:
+ case TYINT1:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ lit_int_flavor:
+ litflavor = LIT_INT;
+
+/* Scan the literal pool for this constant value. If this same constant
+ has been assigned before, use the same label. Note that this routine
+ does NOT consider two differently-typed constants with the same bit
+ pattern to be the same constant */
+
+ loop:
+ lastlit = litpool + nliterals;
+ for(litp = litpool ; litp<lastlit ; ++litp)
+
+/* Remove this type checking to ensure that all bit patterns are reused */
+
+ if(type == litp->littype) switch(litflavor)
+ {
+ case LIT_CHAR:
+ if (len == (int)litp->litval.litival2[0]
+ && nblanks == litp->litval.litival2[1]
+ && !memcmp(strp, litp->cds[0], len)) {
+ q->memno = litp->litnum;
+ frexpr((expptr)p);
+ q->user.Const.ccp1.ccp0 = litp->cds[0];
+ return(q);
+ }
+ break;
+ case LIT_FLOAT:
+ if(cd[0] == litp->litval.litdval[0]
+ && !strcmp(ds[0], litp->cds[0])
+ && (k == 1 ||
+ cd[1] == litp->litval.litdval[1]
+ && !strcmp(ds[1], litp->cds[1]))) {
+ret:
+ q->memno = litp->litnum;
+ frexpr((expptr)p);
+ return(q);
+ }
+ break;
+
+ case LIT_INT:
+ if(p->Const.ci == litp->litval.litival)
+ goto ret;
+ break;
+ }
+
+/* If there's room in the literal pool, add this new value to the pool */
+
+ if(nliterals < maxliterals)
+ {
+ ++nliterals;
+
+ /* litp now points to the next free elt */
+
+ litp->littype = type;
+ litp->litnum = q->memno;
+ switch(litflavor)
+ {
+ case LIT_CHAR:
+ litp->litval.litival2[0] = len;
+ litp->litval.litival2[1] = nblanks;
+ q->user.Const.ccp = litp->cds[0] =
+ memcpy(gmem(len,0), strp, len);
+ break;
+
+ case LIT_FLOAT:
+ litp->litval.litdval[0] = cd[0];
+ litp->cds[0] = copys(ds[0]);
+ if (k == 2) {
+ litp->litval.litdval[1] = cd[1];
+ litp->cds[1] = copys(ds[1]);
+ }
+ break;
+
+ case LIT_INT:
+ litp->litval.litival = p->Const.ci;
+ break;
+ } /* switch (litflavor) */
+ }
+ else
+ many("literal constants", 'L', maxliterals);
+
+ break;
+ case TYADDR:
+ break;
+ default:
+ badtype ("putconst", p -> vtype);
+ break;
+ } /* switch */
+
+ if (type != TYCHAR || halign)
+ frexpr((expptr)p);
+ return( q );
+}
diff --git a/usr.bin/f2c/putpcc.c b/usr.bin/f2c/putpcc.c
new file mode 100644
index 0000000..c104098
--- /dev/null
+++ b/usr.bin/f2c/putpcc.c
@@ -0,0 +1,2075 @@
+/****************************************************************
+Copyright 1990 - 1996 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* INTERMEDIATE CODE GENERATION FOR S. C. JOHNSON C COMPILERS */
+/* NEW VERSION USING BINARY POLISH POSTFIX INTERMEDIATE */
+
+#include "defs.h"
+#include "pccdefs.h"
+#include "output.h" /* for nice_printf */
+#include "names.h"
+#include "p1defs.h"
+
+static Addrp intdouble Argdcl((Addrp));
+static Addrp putcx1 Argdcl((tagptr));
+static tagptr putaddr Argdcl((tagptr));
+static tagptr putcall Argdcl((tagptr, Addrp*));
+static tagptr putcat Argdcl((tagptr, tagptr));
+static Addrp putch1 Argdcl((tagptr));
+static tagptr putchcmp Argdcl((tagptr));
+static tagptr putcheq Argdcl((tagptr));
+static void putct1 Argdcl((tagptr, Addrp, Addrp, ptr));
+static tagptr putcxcmp Argdcl((tagptr));
+static Addrp putcxeq Argdcl((tagptr));
+static tagptr putmnmx Argdcl((tagptr));
+static tagptr putop Argdcl((tagptr));
+static tagptr putpower Argdcl((tagptr));
+
+extern int init_ac[TYSUBR+1];
+extern int ops2[];
+extern int proc_argchanges, proc_protochanges;
+extern int krparens;
+
+#define P2BUFFMAX 128
+
+/* Puthead -- output the header information about subroutines, functions
+ and entry points */
+
+ void
+#ifdef KR_headers
+puthead(s, class)
+ char *s;
+ int class;
+#else
+puthead(char *s, int class)
+#endif
+{
+ if (headerdone == NO) {
+ if (class == CLMAIN)
+ s = "MAIN__";
+ p1_head (class, s);
+ headerdone = YES;
+ }
+}
+
+ void
+#ifdef KR_headers
+putif(p, else_if_p)
+ register expptr p;
+ int else_if_p;
+#else
+putif(register expptr p, int else_if_p)
+#endif
+{
+ register int k;
+ int n;
+ long where;
+
+ if (else_if_p) {
+ p1put(P1_ELSEIFSTART);
+ where = ftell(pass1_file);
+ }
+ if( !ISLOGICAL((k = (p = fixtype(p))->headblock.vtype )) )
+ {
+ if(k != TYERROR)
+ err("non-logical expression in IF statement");
+ }
+ else {
+ if (else_if_p) {
+ if (ei_next >= ei_last)
+ {
+ k = ei_last - ei_first;
+ n = k + 100;
+ ei_next = mem(n,0);
+ ei_last = ei_first + n;
+ if (k)
+ memcpy(ei_next, ei_first, k);
+ ei_first = ei_next;
+ ei_next += k;
+ ei_last = ei_first + n;
+ }
+ p = putx(p);
+ if (*ei_next++ = ftell(pass1_file) > where) {
+ p1_if(p);
+ new_endif();
+ }
+ else
+ p1_elif(p);
+ }
+ else {
+ p = putx(p);
+ p1_if(p);
+ }
+ }
+ }
+
+ void
+#ifdef KR_headers
+putout(p)
+ expptr p;
+#else
+putout(expptr p)
+#endif
+{
+ p1_expr (p);
+
+/* Used to make temporaries in holdtemps available here, but they */
+/* may be reused too soon (e.g. when multiple **'s are involved). */
+}
+
+
+ void
+#ifdef KR_headers
+putcmgo(index, nlab, labs)
+ expptr index;
+ int nlab;
+ struct Labelblock **labs;
+#else
+putcmgo(expptr index, int nlab, struct Labelblock **labs)
+#endif
+{
+ if(! ISINT(index->headblock.vtype) )
+ {
+ execerr("computed goto index must be integer", CNULL);
+ return;
+ }
+
+ p1comp_goto (index, nlab, labs);
+}
+
+ static expptr
+#ifdef KR_headers
+krput(p)
+ register expptr p;
+#else
+krput(register expptr p)
+#endif
+{
+ register expptr e, e1;
+ register unsigned op;
+ int t = krparens == 2 ? TYDREAL : p->exprblock.vtype;
+
+ op = p->exprblock.opcode;
+ e = p->exprblock.leftp;
+ if (e->tag == TEXPR && e->exprblock.opcode == op) {
+ e1 = (expptr)mktmp(t, ENULL);
+ putout(putassign(cpexpr(e1), e));
+ p->exprblock.leftp = e1;
+ }
+ else
+ p->exprblock.leftp = putx(e);
+
+ e = p->exprblock.rightp;
+ if (e->tag == TEXPR && e->exprblock.opcode == op) {
+ e1 = (expptr)mktmp(t, ENULL);
+ putout(putassign(cpexpr(e1), e));
+ p->exprblock.rightp = e1;
+ }
+ else
+ p->exprblock.rightp = putx(e);
+ return p;
+ }
+
+ expptr
+#ifdef KR_headers
+putx(p)
+ register expptr p;
+#else
+putx(register expptr p)
+#endif
+{
+ int opc;
+ int k;
+
+ if (p)
+ switch(p->tag)
+ {
+ case TERROR:
+ break;
+
+ case TCONST:
+ switch(p->constblock.vtype)
+ {
+ case TYLOGICAL1:
+ case TYLOGICAL2:
+ case TYLOGICAL:
+#ifdef TYQUAD
+ case TYQUAD:
+#endif
+ case TYLONG:
+ case TYSHORT:
+ case TYINT1:
+ break;
+
+ case TYADDR:
+ break;
+ case TYREAL:
+ case TYDREAL:
+
+/* Don't write it out to the p2 file, since you'd need to call putconst,
+ which is just what we need to avoid in the translator */
+
+ break;
+ default:
+ p = putx( (expptr)putconst((Constp)p) );
+ break;
+ }
+ break;
+
+ case TEXPR:
+ switch(opc = p->exprblock.opcode)
+ {
+ case OPCALL:
+ case OPCCALL:
+ if( ISCOMPLEX(p->exprblock.vtype) )
+ p = putcxop(p);
+ else p = putcall(p, (Addrp *)NULL);
+ break;
+
+ case OPMIN:
+ case OPMAX:
+ p = putmnmx(p);
+ break;
+
+
+ case OPASSIGN:
+ if(ISCOMPLEX(p->exprblock.leftp->headblock.vtype)
+ || ISCOMPLEX(p->exprblock.rightp->headblock.vtype)) {
+ (void) putcxeq(p);
+ p = ENULL;
+ } else if( ISCHAR(p) )
+ p = putcheq(p);
+ else
+ goto putopp;
+ break;
+
+ case OPEQ:
+ case OPNE:
+ if( ISCOMPLEX(p->exprblock.leftp->headblock.vtype) ||
+ ISCOMPLEX(p->exprblock.rightp->headblock.vtype) )
+ {
+ p = putcxcmp(p);
+ break;
+ }
+ case OPLT:
+ case OPLE:
+ case OPGT:
+ case OPGE:
+ if(ISCHAR(p->exprblock.leftp))
+ {
+ p = putchcmp(p);
+ break;
+ }
+ goto putopp;
+
+ case OPPOWER:
+ p = putpower(p);
+ break;
+
+ case OPSTAR:
+ /* m * (2**k) -> m<<k */
+ if(INT(p->exprblock.leftp->headblock.vtype) &&
+ ISICON(p->exprblock.rightp) &&
+ ( (k = log_2(p->exprblock.rightp->constblock.Const.ci))>0) )
+ {
+ p->exprblock.opcode = OPLSHIFT;
+ frexpr(p->exprblock.rightp);
+ p->exprblock.rightp = ICON(k);
+ goto putopp;
+ }
+ if (krparens && ISREAL(p->exprblock.vtype))
+ return krput(p);
+
+ case OPMOD:
+ goto putopp;
+ case OPPLUS:
+ if (krparens && ISREAL(p->exprblock.vtype))
+ return krput(p);
+ case OPMINUS:
+ case OPSLASH:
+ case OPNEG:
+ case OPNEG1:
+ case OPABS:
+ case OPDABS:
+ if( ISCOMPLEX(p->exprblock.vtype) )
+ p = putcxop(p);
+ else goto putopp;
+ break;
+
+ case OPCONV:
+ if( ISCOMPLEX(p->exprblock.vtype) )
+ p = putcxop(p);
+ else if( ISCOMPLEX(p->exprblock.leftp->headblock.vtype) )
+ {
+ p = putx( mkconv(p->exprblock.vtype,
+ (expptr)realpart(putcx1(p->exprblock.leftp))));
+ }
+ else goto putopp;
+ break;
+
+ case OPNOT:
+ case OPOR:
+ case OPAND:
+ case OPEQV:
+ case OPNEQV:
+ case OPADDR:
+ case OPPLUSEQ:
+ case OPSTAREQ:
+ case OPCOMMA:
+ case OPQUEST:
+ case OPCOLON:
+ case OPBITOR:
+ case OPBITAND:
+ case OPBITXOR:
+ case OPBITNOT:
+ case OPLSHIFT:
+ case OPRSHIFT:
+ case OPASSIGNI:
+ case OPIDENTITY:
+ case OPCHARCAST:
+ case OPMIN2:
+ case OPMAX2:
+ case OPDMIN:
+ case OPDMAX:
+ case OPBITTEST:
+ case OPBITCLR:
+ case OPBITSET:
+#ifdef TYQUAD
+ case OPQBITSET:
+ case OPQBITCLR:
+#endif
+putopp:
+ p = putop(p);
+ break;
+
+ case OPCONCAT:
+ /* weird things like ichar(a//a) */
+ p = (expptr)putch1(p);
+ break;
+
+ default:
+ badop("putx", opc);
+ p = errnode ();
+ }
+ break;
+
+ case TADDR:
+ p = putaddr(p);
+ break;
+
+ default:
+ badtag("putx", p->tag);
+ p = errnode ();
+ }
+
+ return p;
+}
+
+
+
+ LOCAL expptr
+#ifdef KR_headers
+putop(p)
+ expptr p;
+#else
+putop(expptr p)
+#endif
+{
+ expptr lp, tp;
+ int pt, lt, lt1;
+ int comma;
+ char *hsave;
+
+ switch(p->exprblock.opcode) /* check for special cases and rewrite */
+ {
+ case OPCONV:
+ pt = p->exprblock.vtype;
+ lp = p->exprblock.leftp;
+ lt = lp->headblock.vtype;
+
+/* Simplify nested type casts */
+
+ while(p->tag==TEXPR && p->exprblock.opcode==OPCONV &&
+ ( (ISREAL(pt)&&ONEOF(lt,MSKREAL|MSKCOMPLEX)) ||
+ (INT(pt)&&(ONEOF(lt,MSKINT|MSKADDR|MSKCHAR|M(TYSUBR)))) ))
+ {
+ if(pt==TYDREAL && lt==TYREAL)
+ {
+ if(lp->tag==TEXPR
+ && lp->exprblock.opcode == OPCONV) {
+ lt1 = lp->exprblock.leftp->headblock.vtype;
+ if (lt1 == TYDREAL) {
+ lp->exprblock.leftp =
+ putx(lp->exprblock.leftp);
+ return p;
+ }
+ if (lt1 == TYDCOMPLEX) {
+ lp->exprblock.leftp = putx(
+ (expptr)realpart(
+ putcx1(lp->exprblock.leftp)));
+ return p;
+ }
+ }
+ break;
+ }
+ else if (ISREAL(pt) && ISCOMPLEX(lt)) {
+ p->exprblock.leftp = putx(mkconv(pt,
+ (expptr)realpart(
+ putcx1(p->exprblock.leftp))));
+ break;
+ }
+ if(lt==TYCHAR && lp->tag==TEXPR &&
+ lp->exprblock.opcode==OPCALL)
+ {
+
+/* May want to make a comma expression here instead. I had one, but took
+ it out for my convenience, not for the convenience of the end user */
+
+ putout (putcall (lp, (Addrp *) &(p ->
+ exprblock.leftp)));
+ return putop (p);
+ }
+ if (lt == TYCHAR) {
+ if (ISCONST(p->exprblock.leftp)
+ && ISNUMERIC(p->exprblock.vtype)) {
+ hsave = halign;
+ halign = 0;
+ p->exprblock.leftp = putx((expptr)
+ putconst((Constp)
+ p->exprblock.leftp));
+ halign = hsave;
+ }
+ else
+ p->exprblock.leftp =
+ putx(p->exprblock.leftp);
+ return p;
+ }
+ if (pt < lt && ONEOF(lt,MSKINT|MSKREAL))
+ break;
+ frexpr(p->exprblock.vleng);
+ free( (charptr) p );
+ p = lp;
+ if (p->tag != TEXPR)
+ goto retputx;
+ pt = lt;
+ lp = p->exprblock.leftp;
+ lt = lp->headblock.vtype;
+ } /* while */
+ if(p->tag==TEXPR && p->exprblock.opcode==OPCONV)
+ break;
+ retputx:
+ return putx(p);
+
+ case OPADDR:
+ comma = NO;
+ lp = p->exprblock.leftp;
+ free( (charptr) p );
+ if(lp->tag != TADDR)
+ {
+ tp = (expptr)
+ mktmp(lp->headblock.vtype,lp->headblock.vleng);
+ p = putx( mkexpr(OPASSIGN, cpexpr(tp), lp) );
+ lp = tp;
+ comma = YES;
+ }
+ if(comma)
+ p = mkexpr(OPCOMMA, p, putaddr(lp));
+ else
+ p = (expptr)putaddr(lp);
+ return p;
+
+ case OPASSIGN:
+ case OPASSIGNI:
+ case OPLT:
+ case OPLE:
+ case OPGT:
+ case OPGE:
+ case OPEQ:
+ case OPNE:
+ ;
+ }
+
+ if( ops2[p->exprblock.opcode] <= 0)
+ badop("putop", p->exprblock.opcode);
+ lp = p->exprblock.leftp = putx(p->exprblock.leftp);
+ if (p -> exprblock.rightp) {
+ tp = p->exprblock.rightp = putx(p->exprblock.rightp);
+ if (ISCONST(tp) && ISCONST(lp))
+ p = fold(p);
+ }
+ return p;
+}
+
+ LOCAL expptr
+#ifdef KR_headers
+putpower(p)
+ expptr p;
+#else
+putpower(expptr p)
+#endif
+{
+ expptr base;
+ Addrp t1, t2;
+ ftnint k;
+ int type;
+ char buf[80]; /* buffer for text of comment */
+
+ if(!ISICON(p->exprblock.rightp) ||
+ (k = p->exprblock.rightp->constblock.Const.ci)<2)
+ Fatal("putpower: bad call");
+ base = p->exprblock.leftp;
+ type = base->headblock.vtype;
+ t1 = mktmp(type, ENULL);
+ t2 = NULL;
+
+ free ((charptr) p);
+ p = putassign (cpexpr((expptr) t1), base);
+
+ sprintf (buf, "Computing %ld%s power", k,
+ k == 2 ? "nd" : k == 3 ? "rd" : "th");
+ p1_comment (buf);
+
+ for( ; (k&1)==0 && k>2 ; k>>=1 )
+ {
+ p = mkexpr (OPCOMMA, p, putsteq(t1, t1));
+ }
+
+ if(k == 2) {
+
+/* Write the power computation out immediately */
+ putout (p);
+ p = putx( mkexpr(OPSTAR, cpexpr((expptr)t1), cpexpr((expptr)t1)));
+ } else {
+ t2 = mktmp(type, ENULL);
+ p = mkexpr (OPCOMMA, p, putassign(cpexpr((expptr)t2),
+ cpexpr((expptr)t1)));
+
+ for(k>>=1 ; k>1 ; k>>=1)
+ {
+ p = mkexpr (OPCOMMA, p, putsteq(t1, t1));
+ if(k & 1)
+ {
+ p = mkexpr (OPCOMMA, p, putsteq(t2, t1));
+ }
+ }
+/* Write the power computation out immediately */
+ putout (p);
+ p = putx( mkexpr(OPSTAR, cpexpr((expptr)t2),
+ mkexpr(OPSTAR, cpexpr((expptr)t1), cpexpr((expptr)t1))));
+ }
+ frexpr((expptr)t1);
+ if(t2)
+ frexpr((expptr)t2);
+ return p;
+}
+
+
+
+
+ LOCAL Addrp
+#ifdef KR_headers
+intdouble(p)
+ Addrp p;
+#else
+intdouble(Addrp p)
+#endif
+{
+ register Addrp t;
+
+ t = mktmp(TYDREAL, ENULL);
+ putout (putassign(cpexpr((expptr)t), (expptr)p));
+ return(t);
+}
+
+
+
+
+
+/* Complex-type variable assignment */
+
+ LOCAL Addrp
+#ifdef KR_headers
+putcxeq(p)
+ register expptr p;
+#else
+putcxeq(register expptr p)
+#endif
+{
+ register Addrp lp, rp;
+ expptr code;
+
+ if(p->tag != TEXPR)
+ badtag("putcxeq", p->tag);
+
+ lp = putcx1(p->exprblock.leftp);
+ rp = putcx1(p->exprblock.rightp);
+ code = putassign ( (expptr)realpart(lp), (expptr)realpart(rp));
+
+ if( ISCOMPLEX(p->exprblock.vtype) )
+ {
+ code = mkexpr (OPCOMMA, code, putassign
+ (imagpart(lp), imagpart(rp)));
+ }
+ putout (code);
+ frexpr((expptr)rp);
+ free ((charptr) p);
+ return lp;
+}
+
+
+
+/* putcxop -- used to write out embedded calls to complex functions, and
+ complex arguments to procedures */
+
+ expptr
+#ifdef KR_headers
+putcxop(p)
+ expptr p;
+#else
+putcxop(expptr p)
+#endif
+{
+ return (expptr)putaddr((expptr)putcx1(p));
+}
+
+#define PAIR(x,y) mkexpr (OPCOMMA, (x), (y))
+
+ LOCAL Addrp
+#ifdef KR_headers
+putcx1(p)
+ register expptr p;
+#else
+putcx1(register expptr p)
+#endif
+{
+ expptr q;
+ Addrp lp, rp;
+ register Addrp resp;
+ int opcode;
+ int ltype, rtype;
+ long ts, tskludge;
+
+ if(p == NULL)
+ return(NULL);
+
+ switch(p->tag)
+ {
+ case TCONST:
+ if( ISCOMPLEX(p->constblock.vtype) )
+ p = (expptr) putconst((Constp)p);
+ return( (Addrp) p );
+
+ case TADDR:
+ resp = &p->addrblock;
+ if (addressable(p))
+ return (Addrp) p;
+ ts = tskludge = 0;
+ if (q = resp->memoffset) {
+ if (resp->uname_tag == UNAM_REF) {
+ q = cpexpr((tagptr)resp);
+ q->addrblock.vtype = tyint;
+ q->addrblock.cmplx_sub = 1;
+ p->addrblock.skip_offset = 1;
+ resp->user.name->vsubscrused = 1;
+ resp->uname_tag = UNAM_NAME;
+ tskludge = typesize[resp->vtype]
+ * (resp->Field ? 2 : 1);
+ }
+ else if (resp->isarray
+ && resp->vtype != TYCHAR) {
+ if (ONEOF(resp->vstg, M(STGCOMMON)|M(STGEQUIV))
+ && resp->uname_tag == UNAM_NAME)
+ q = mkexpr(OPMINUS, q,
+ mkintcon(resp->user.name->voffset));
+ ts = typesize[resp->vtype]
+ * (resp->Field ? 2 : 1);
+ q = resp->memoffset = mkexpr(OPSLASH, q,
+ ICON(ts));
+ }
+ }
+ resp = mktmp(tyint, ENULL);
+ putout(putassign(cpexpr((expptr)resp), q));
+ p->addrblock.memoffset = tskludge
+ ? mkexpr(OPSTAR, (expptr)resp, ICON(tskludge))
+ : (expptr)resp;
+ if (ts) {
+ resp = &p->addrblock;
+ q = mkexpr(OPSTAR, resp->memoffset, ICON(ts));
+ if (ONEOF(resp->vstg, M(STGCOMMON)|M(STGEQUIV))
+ && resp->uname_tag == UNAM_NAME)
+ q = mkexpr(OPPLUS, q,
+ mkintcon(resp->user.name->voffset));
+ resp->memoffset = q;
+ }
+ return (Addrp) p;
+
+ case TEXPR:
+ if( ISCOMPLEX(p->exprblock.vtype) )
+ break;
+ resp = mktmp(p->exprblock.vtype, ENULL);
+ /*first arg of above mktmp call was TYDREAL before 19950102 */
+ putout (putassign( cpexpr((expptr)resp), p));
+ return(resp);
+
+ case TERROR:
+ return NULL;
+
+ default:
+ badtag("putcx1", p->tag);
+ }
+
+ opcode = p->exprblock.opcode;
+ if(opcode==OPCALL || opcode==OPCCALL)
+ {
+ Addrp t;
+ p = putcall(p, &t);
+ putout(p);
+ return t;
+ }
+ else if(opcode == OPASSIGN)
+ {
+ return putcxeq (p);
+ }
+
+/* BUG (inefficient) Generates too many temporary variables */
+
+ resp = mktmp(p->exprblock.vtype, ENULL);
+ if(lp = putcx1(p->exprblock.leftp) )
+ ltype = lp->vtype;
+ if(rp = putcx1(p->exprblock.rightp) )
+ rtype = rp->vtype;
+
+ switch(opcode)
+ {
+ case OPCOMMA:
+ frexpr((expptr)resp);
+ resp = rp;
+ rp = NULL;
+ break;
+
+ case OPNEG:
+ case OPNEG1:
+ putout (PAIR (
+ putassign( (expptr)realpart(resp),
+ mkexpr(OPNEG, (expptr)realpart(lp), ENULL)),
+ putassign( imagpart(resp),
+ mkexpr(OPNEG, imagpart(lp), ENULL))));
+ break;
+
+ case OPPLUS:
+ case OPMINUS: { expptr r;
+ r = putassign( (expptr)realpart(resp),
+ mkexpr(opcode, (expptr)realpart(lp), (expptr)realpart(rp) ));
+ if(rtype < TYCOMPLEX)
+ q = putassign( imagpart(resp), imagpart(lp) );
+ else if(ltype < TYCOMPLEX)
+ {
+ if(opcode == OPPLUS)
+ q = putassign( imagpart(resp), imagpart(rp) );
+ else
+ q = putassign( imagpart(resp),
+ mkexpr(OPNEG, imagpart(rp), ENULL) );
+ }
+ else
+ q = putassign( imagpart(resp),
+ mkexpr(opcode, imagpart(lp), imagpart(rp) ));
+ r = PAIR (r, q);
+ putout (r);
+ break;
+ } /* case OPPLUS, OPMINUS: */
+ case OPSTAR:
+ if(ltype < TYCOMPLEX)
+ {
+ if( ISINT(ltype) )
+ lp = intdouble(lp);
+ putout (PAIR (
+ putassign( (expptr)realpart(resp),
+ mkexpr(OPSTAR, cpexpr((expptr)lp),
+ (expptr)realpart(rp))),
+ putassign( imagpart(resp),
+ mkexpr(OPSTAR, cpexpr((expptr)lp), imagpart(rp)))));
+ }
+ else if(rtype < TYCOMPLEX)
+ {
+ if( ISINT(rtype) )
+ rp = intdouble(rp);
+ putout (PAIR (
+ putassign( (expptr)realpart(resp),
+ mkexpr(OPSTAR, cpexpr((expptr)rp),
+ (expptr)realpart(lp))),
+ putassign( imagpart(resp),
+ mkexpr(OPSTAR, cpexpr((expptr)rp), imagpart(lp)))));
+ }
+ else {
+ putout (PAIR (
+ putassign( (expptr)realpart(resp), mkexpr(OPMINUS,
+ mkexpr(OPSTAR, (expptr)realpart(lp),
+ (expptr)realpart(rp)),
+ mkexpr(OPSTAR, imagpart(lp), imagpart(rp)))),
+ putassign( imagpart(resp), mkexpr(OPPLUS,
+ mkexpr(OPSTAR, (expptr)realpart(lp), imagpart(rp)),
+ mkexpr(OPSTAR, imagpart(lp),
+ (expptr)realpart(rp))))));
+ }
+ break;
+
+ case OPSLASH:
+ /* fixexpr has already replaced all divisions
+ * by a complex by a function call
+ */
+ if( ISINT(rtype) )
+ rp = intdouble(rp);
+ putout (PAIR (
+ putassign( (expptr)realpart(resp),
+ mkexpr(OPSLASH, (expptr)realpart(lp), cpexpr((expptr)rp))),
+ putassign( imagpart(resp),
+ mkexpr(OPSLASH, imagpart(lp), cpexpr((expptr)rp)))));
+ break;
+
+ case OPCONV:
+ if (!lp)
+ break;
+ if(ISCOMPLEX(lp->vtype) )
+ q = imagpart(lp);
+ else if(rp != NULL)
+ q = (expptr) realpart(rp);
+ else
+ q = mkrealcon(TYDREAL, "0");
+ putout (PAIR (
+ putassign( (expptr)realpart(resp), (expptr)realpart(lp)),
+ putassign( imagpart(resp), q)));
+ break;
+
+ default:
+ badop("putcx1", opcode);
+ }
+
+ frexpr((expptr)lp);
+ frexpr((expptr)rp);
+ free( (charptr) p );
+ return(resp);
+}
+
+
+
+
+/* Only .EQ. and .NE. may be performed on COMPLEX data, other relations
+ are not defined */
+
+ LOCAL expptr
+#ifdef KR_headers
+putcxcmp(p)
+ register expptr p;
+#else
+putcxcmp(register expptr p)
+#endif
+{
+ int opcode;
+ register Addrp lp, rp;
+ expptr q;
+
+ if(p->tag != TEXPR)
+ badtag("putcxcmp", p->tag);
+
+ opcode = p->exprblock.opcode;
+ lp = putcx1(p->exprblock.leftp);
+ rp = putcx1(p->exprblock.rightp);
+
+ q = mkexpr( opcode==OPEQ ? OPAND : OPOR ,
+ mkexpr(opcode, (expptr)realpart(lp), (expptr)realpart(rp)),
+ mkexpr(opcode, imagpart(lp), imagpart(rp)) );
+
+ free( (charptr) lp);
+ free( (charptr) rp);
+ free( (charptr) p );
+ if (ISCONST(q))
+ return q;
+ return putx( fixexpr((Exprp)q) );
+}
+
+/* putch1 -- Forces constants into the literal pool, among other things */
+
+ LOCAL Addrp
+#ifdef KR_headers
+putch1(p)
+ register expptr p;
+#else
+putch1(register expptr p)
+#endif
+{
+ Addrp t;
+ expptr e;
+
+ switch(p->tag)
+ {
+ case TCONST:
+ return( putconst((Constp)p) );
+
+ case TADDR:
+ return( (Addrp) p );
+
+ case TEXPR:
+ switch(p->exprblock.opcode)
+ {
+ expptr q;
+
+ case OPCALL:
+ case OPCCALL:
+
+ p = putcall(p, &t);
+ putout (p);
+ break;
+
+ case OPCONCAT:
+ t = mktmp(TYCHAR, ICON(lencat(p)));
+ q = (expptr) cpexpr(p->headblock.vleng);
+ p = putcat( cpexpr((expptr)t), p );
+ /* put the correct length on the block */
+ frexpr(t->vleng);
+ t->vleng = q;
+ putout (p);
+ break;
+
+ case OPCONV:
+ if(!ISICON(p->exprblock.vleng)
+ || p->exprblock.vleng->constblock.Const.ci!=1
+ || ! INT(p->exprblock.leftp->headblock.vtype) )
+ Fatal("putch1: bad character conversion");
+ t = mktmp(TYCHAR, ICON(1));
+ e = mkexpr(OPCONV, (expptr)t, ENULL);
+ e->headblock.vtype = TYCHAR;
+ p = putop( mkexpr(OPASSIGN, cpexpr(e), p));
+ putout (p);
+ break;
+ default:
+ badop("putch1", p->exprblock.opcode);
+ }
+ return(t);
+
+ default:
+ badtag("putch1", p->tag);
+ }
+ /* NOT REACHED */ return 0;
+}
+
+
+/* putchop -- Write out a character actual parameter; that is, this is
+ part of a procedure invocation */
+
+ Addrp
+#ifdef KR_headers
+putchop(p)
+ expptr p;
+#else
+putchop(expptr p)
+#endif
+{
+ p = putaddr((expptr)putch1(p));
+ return (Addrp)p;
+}
+
+
+
+
+ LOCAL expptr
+#ifdef KR_headers
+putcheq(p)
+ register expptr p;
+#else
+putcheq(register expptr p)
+#endif
+{
+ expptr lp, rp;
+ int nbad;
+
+ if(p->tag != TEXPR)
+ badtag("putcheq", p->tag);
+
+ lp = p->exprblock.leftp;
+ rp = p->exprblock.rightp;
+ frexpr(p->exprblock.vleng);
+ free( (charptr) p );
+
+/* If s = t // u, don't bother copying the result, write it directly into
+ this buffer */
+
+ nbad = badchleng(lp) + badchleng(rp);
+ if( rp->tag==TEXPR && rp->exprblock.opcode==OPCONCAT )
+ p = putcat(lp, rp);
+ else if( !nbad
+ && ISONE(lp->headblock.vleng)
+ && ISONE(rp->headblock.vleng) ) {
+ lp = mkexpr(OPCONV, lp, ENULL);
+ rp = mkexpr(OPCONV, rp, ENULL);
+ lp->headblock.vtype = rp->headblock.vtype = TYCHAR;
+ p = putop(mkexpr(OPASSIGN, lp, rp));
+ }
+ else
+ p = putx( call2(TYSUBR, "s_copy", lp, rp) );
+ return p;
+}
+
+
+
+
+ LOCAL expptr
+#ifdef KR_headers
+putchcmp(p)
+ register expptr p;
+#else
+putchcmp(register expptr p)
+#endif
+{
+ expptr lp, rp;
+
+ if(p->tag != TEXPR)
+ badtag("putchcmp", p->tag);
+
+ lp = p->exprblock.leftp;
+ rp = p->exprblock.rightp;
+
+ if(ISONE(lp->headblock.vleng) && ISONE(rp->headblock.vleng) ) {
+ lp = mkexpr(OPCONV, lp, ENULL);
+ rp = mkexpr(OPCONV, rp, ENULL);
+ lp->headblock.vtype = rp->headblock.vtype = TYCHAR;
+ }
+ else {
+ lp = call2(TYINT,"s_cmp", lp, rp);
+ rp = ICON(0);
+ }
+ p->exprblock.leftp = lp;
+ p->exprblock.rightp = rp;
+ p = putop(p);
+ return p;
+}
+
+
+
+
+
+/* putcat -- Writes out a concatenation operation. Two temporary arrays
+ are allocated, putct1() is called to initialize them, and then a
+ call to runtime library routine s_cat() is inserted.
+
+ This routine generates code which will perform an (nconc lhs rhs)
+ at runtime. The runtime funciton does not return a value, the routine
+ that calls this putcat must remember the name of lhs.
+*/
+
+
+ LOCAL expptr
+#ifdef KR_headers
+putcat(lhs0, rhs)
+ expptr lhs0;
+ register expptr rhs;
+#else
+putcat(expptr lhs0, register expptr rhs)
+#endif
+{
+ register Addrp lhs = (Addrp)lhs0;
+ int n, tyi;
+ Addrp length_var, string_var;
+ expptr p;
+ static char Writing_concatenation[] = "Writing concatenation";
+
+/* Create the temporary arrays */
+
+ n = ncat(rhs);
+ length_var = mktmpn(n, tyioint, ENULL);
+ string_var = mktmpn(n, TYADDR, ENULL);
+ frtemp((Addrp)cpexpr((expptr)length_var));
+ frtemp((Addrp)cpexpr((expptr)string_var));
+
+/* Initialize the arrays */
+
+ n = 0;
+ /* p1_comment scribbles on its argument, so we
+ * cannot safely pass a string literal here. */
+ p1_comment(Writing_concatenation);
+ putct1(rhs, length_var, string_var, &n);
+
+/* Create the invocation */
+
+ tyi = tyint;
+ tyint = tyioint; /* for -I2 */
+ p = putx (call4 (TYSUBR, "s_cat",
+ (expptr)lhs,
+ (expptr)string_var,
+ (expptr)length_var,
+ (expptr)putconst((Constp)ICON(n))));
+ tyint = tyi;
+
+ return p;
+}
+
+
+
+
+
+ LOCAL void
+#ifdef KR_headers
+putct1(q, length_var, string_var, ip)
+ register expptr q;
+ register Addrp length_var;
+ register Addrp string_var;
+ int *ip;
+#else
+putct1(register expptr q, register Addrp length_var, register Addrp string_var, int *ip)
+#endif
+{
+ int i;
+ Addrp length_copy, string_copy;
+ expptr e;
+ extern int szleng;
+
+ if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT)
+ {
+ putct1(q->exprblock.leftp, length_var, string_var,
+ ip);
+ putct1(q->exprblock.rightp, length_var, string_var,
+ ip);
+ frexpr (q -> exprblock.vleng);
+ free ((charptr) q);
+ }
+ else
+ {
+ i = (*ip)++;
+ e = cpexpr(q->headblock.vleng);
+ if (!e)
+ return; /* error -- character*(*) */
+ length_copy = (Addrp) cpexpr((expptr)length_var);
+ length_copy->memoffset =
+ mkexpr(OPPLUS,length_copy->memoffset, ICON(i*szleng));
+ string_copy = (Addrp) cpexpr((expptr)string_var);
+ string_copy->memoffset =
+ mkexpr(OPPLUS, string_copy->memoffset,
+ ICON(i*typesize[TYADDR]));
+ putout (PAIR (putassign((expptr)length_copy, e),
+ putassign((expptr)string_copy, addrof((expptr)putch1(q)))));
+ }
+}
+
+/* putaddr -- seems to write out function invocation actual parameters */
+
+ LOCAL expptr
+#ifdef KR_headers
+putaddr(p0)
+ expptr p0;
+#else
+putaddr(expptr p0)
+#endif
+{
+ register Addrp p;
+ chainp cp;
+
+ if (!(p = (Addrp)p0))
+ return ENULL;
+
+ if( p->tag==TERROR || (p->memoffset!=NULL && ISERROR(p->memoffset)) )
+ {
+ frexpr((expptr)p);
+ return ENULL;
+ }
+ if (p->isarray && p->memoffset)
+ if (p->uname_tag == UNAM_REF) {
+ cp = p->memoffset->listblock.listp;
+ for(; cp; cp = cp->nextp)
+ cp->datap = (char *)fixtype((tagptr)cp->datap);
+ }
+ else
+ p->memoffset = putx(p->memoffset);
+ return (expptr) p;
+}
+
+ LOCAL expptr
+#ifdef KR_headers
+addrfix(e)
+ expptr e;
+#else
+addrfix(expptr e)
+#endif
+ /* fudge character string length if it's a TADDR */
+{
+ return e->tag == TADDR ? mkexpr(OPIDENTITY, e, ENULL) : e;
+ }
+
+ LOCAL int
+#ifdef KR_headers
+typekludge(ccall, q, at, j)
+ int ccall;
+ register expptr q;
+ Atype *at;
+ int j;
+#else
+typekludge(int ccall, register expptr q, Atype *at, int j)
+#endif
+ /* j = alternate type */
+{
+ register int i, k;
+ extern int iocalladdr;
+ register Namep np;
+
+ /* Return value classes:
+ * < 100 ==> Fortran arg (pointer to type)
+ * < 200 ==> C arg
+ * < 300 ==> procedure arg
+ * < 400 ==> external, no explicit type
+ * < 500 ==> arg that may turn out to be
+ * either a variable or a procedure
+ */
+
+ k = q->headblock.vtype;
+ if (ccall) {
+ if (k == TYREAL)
+ k = TYDREAL; /* force double for library routines */
+ return k + 100;
+ }
+ if (k == TYADDR)
+ return iocalladdr;
+ i = q->tag;
+ if ((i == TEXPR && q->exprblock.opcode != OPCOMMA_ARG)
+ || (i == TADDR && q->addrblock.charleng)
+ || i == TCONST)
+ k = TYFTNLEN + 100;
+ else if (i == TADDR)
+ switch(q->addrblock.vclass) {
+ case CLPROC:
+ if (q->addrblock.uname_tag != UNAM_NAME)
+ k += 200;
+ else if ((np = q->addrblock.user.name)->vprocclass
+ != PTHISPROC) {
+ if (k && !np->vimpltype)
+ k += 200;
+ else {
+ if (j > 200 && infertypes && j < 300) {
+ k = j;
+ inferdcl(np, j-200);
+ }
+ else k = (np->vstg == STGEXT
+ ? extsymtab[np->vardesc.varno].extype
+ : 0) + 200;
+ at->cp = mkchain((char *)np, at->cp);
+ }
+ }
+ else if (k == TYSUBR)
+ k += 200;
+ break;
+
+ case CLUNKNOWN:
+ if (q->addrblock.vstg == STGARG
+ && q->addrblock.uname_tag == UNAM_NAME) {
+ k += 400;
+ at->cp = mkchain((char *)q->addrblock.user.name,
+ at->cp);
+ }
+ }
+ else if (i == TNAME && q->nameblock.vstg == STGARG) {
+ np = &q->nameblock;
+ switch(np->vclass) {
+ case CLPROC:
+ if (!np->vimpltype)
+ k += 200;
+ else if (j <= 200 || !infertypes || j >= 300)
+ k += 300;
+ else {
+ k = j;
+ inferdcl(np, j-200);
+ }
+ goto add2chain;
+
+ case CLUNKNOWN:
+ /* argument may be a scalar variable or a function */
+ if (np->vimpltype && j && infertypes
+ && j < 300) {
+ inferdcl(np, j % 100);
+ k = j;
+ }
+ else
+ k += 400;
+
+ /* to handle procedure args only so far known to be
+ * external, save a pointer to the symbol table entry...
+ */
+ add2chain:
+ at->cp = mkchain((char *)np, at->cp);
+ }
+ }
+ return k;
+ }
+
+ char *
+#ifdef KR_headers
+Argtype(k, buf)
+ int k;
+ char *buf;
+#else
+Argtype(int k, char *buf)
+#endif
+{
+ if (k < 100) {
+ sprintf(buf, "%s variable", ftn_types[k]);
+ return buf;
+ }
+ if (k < 200) {
+ k -= 100;
+ return ftn_types[k];
+ }
+ if (k < 300) {
+ k -= 200;
+ if (k == TYSUBR)
+ return ftn_types[TYSUBR];
+ sprintf(buf, "%s function", ftn_types[k]);
+ return buf;
+ }
+ if (k < 400)
+ return "external argument";
+ k -= 400;
+ sprintf(buf, "%s argument", ftn_types[k]);
+ return buf;
+ }
+
+ static void
+#ifdef KR_headers
+atype_squawk(at, msg)
+ Argtypes *at;
+ char *msg;
+#else
+atype_squawk(Argtypes *at, char *msg)
+#endif
+{
+ register Atype *a, *ae;
+ warn(msg);
+ for(a = at->atypes, ae = a + at->nargs; a < ae; a++)
+ frchain(&a->cp);
+ at->nargs = -1;
+ if (at->changes & 2 && !at->defined)
+ proc_protochanges++;
+ }
+
+ static char inconsist[] = "inconsistent calling sequences for ";
+
+ void
+#ifdef KR_headers
+bad_atypes(at, fname, i, j, k, here, prev)
+ Argtypes *at;
+ char *fname;
+ int i;
+ int j;
+ int k;
+ char *here;
+ char *prev;
+#else
+bad_atypes(Argtypes *at, char *fname, int i, int j, int k, char *here, char *prev)
+#endif
+{
+ char buf[208], buf1[32], buf2[32];
+
+ sprintf(buf, "%s%.90s,\n\targ %d: %s%s%s %s.",
+ inconsist, fname, i, here, Argtype(k, buf1),
+ prev, Argtype(j, buf2));
+ atype_squawk(at, buf);
+ }
+
+ int
+#ifdef KR_headers
+type_fixup(at, a, k)
+ Argtypes *at;
+ Atype *a;
+ int k;
+#else
+type_fixup(Argtypes *at, Atype *a, int k)
+#endif
+{
+ register struct Entrypoint *ep;
+ if (!infertypes)
+ return 0;
+ for(ep = entries; ep; ep = ep->entnextp)
+ if (ep->entryname && at == ep->entryname->arginfo) {
+ a->type = k % 100;
+ return proc_argchanges = 1;
+ }
+ return 0;
+ }
+
+
+ void
+#ifdef KR_headers
+save_argtypes(arglist, at0, at1, ccall, fname, stg, nchargs, type, zap)
+ chainp arglist;
+ Argtypes **at0;
+ Argtypes **at1;
+ int ccall;
+ char *fname;
+ int stg;
+ int nchargs;
+ int type;
+ int zap;
+#else
+save_argtypes(chainp arglist, Argtypes **at0, Argtypes **at1, int ccall, char *fname, int stg, int nchargs, int type, int zap)
+#endif
+{
+ Argtypes *at;
+ chainp cp;
+ int i, i0, j, k, nargs, nbad, *t, *te;
+ Atype *atypes;
+ expptr q;
+ char buf[208], buf1[32], buf2[32];
+ static int initargs[4] = {TYCOMPLEX, TYDCOMPLEX, TYCHAR, TYFTNLEN+100};
+ static int *init_ap[TYSUBR+1] = {0,0,0,0,0,0,0,
+#ifdef TYQUAD
+ 0,
+#endif
+ initargs, initargs+1,0,0,0,initargs+2};
+
+ i0 = init_ac[type];
+ t = init_ap[type];
+ te = t + i0;
+ if (at = *at0) {
+ *at1 = at;
+ nargs = at->nargs;
+ if (nargs < 0 && type && at->changes & 2 && !at->defined)
+ --proc_protochanges;
+ if (at->dnargs >= 0 && zap != 2)
+ type = 0;
+ if (nargs < 0) { /* inconsistent usage seen */
+ if (type)
+ goto newlist;
+ return;
+ }
+ atypes = at->atypes;
+ i = nchargs;
+ for(nbad = 0; t < te; atypes++) {
+ if (++i > nargs) {
+ toomany:
+ i = nchargs + i0;
+ for(cp = arglist; cp; cp = cp->nextp)
+ i++;
+ toofew:
+ switch(zap) {
+ case 2: zap = 6; break;
+ case 1: if (at->defined & 4)
+ return;
+ }
+ sprintf(buf,
+ "%s%.90s:\n\there %d, previously %d args and string lengths.",
+ inconsist, fname, i, nargs);
+ atype_squawk(at, buf);
+ if (type) {
+ t = init_ap[type];
+ goto newlist;
+ }
+ return;
+ }
+ j = atypes->type;
+ k = *t++;
+ if (j != k && j-400 != k) {
+ cp = 0;
+ goto badtypes;
+ }
+ }
+ for(cp = arglist; cp; atypes++, cp = cp->nextp) {
+ if (++i > nargs)
+ goto toomany;
+ j = atypes->type;
+ if (!(q = (expptr)cp->datap))
+ continue;
+ k = typekludge(ccall, q, atypes, j);
+ if (k >= 300 || k == j)
+ continue;
+ if (j >= 300) {
+ if (k >= 200) {
+ if (k == TYUNKNOWN + 200)
+ continue;
+ if (j % 100 != k - 200
+ && k != TYSUBR + 200
+ && j != TYUNKNOWN + 300
+ && !type_fixup(at,atypes,k))
+ goto badtypes;
+ }
+ else if (j % 100 % TYSUBR != k % TYSUBR
+ && !type_fixup(at,atypes,k))
+ goto badtypes;
+ }
+ else if (k < 200 || j < 200)
+ if (j) {
+ if (k == TYUNKNOWN
+ && q->tag == TNAME
+ && q->nameblock.vinfproc) {
+ q->nameblock.vdcldone = 0;
+ impldcl((Namep)q);
+ }
+ goto badtypes;
+ }
+ else ; /* fall through to update */
+ else if (k == TYUNKNOWN+200)
+ continue;
+ else if (j != TYUNKNOWN+200)
+ {
+ badtypes:
+ if (++nbad == 1)
+ bad_atypes(at, fname, i - nchargs,
+ j, k, "here ", ", previously");
+ else
+ fprintf(stderr,
+ "\targ %d: here %s, previously %s.\n",
+ i - nchargs, Argtype(k,buf1),
+ Argtype(j,buf2));
+ if (!cp)
+ break;
+ continue;
+ }
+ /* We've subsequently learned the right type,
+ as in the call on zoo below...
+
+ subroutine foo(x, zap)
+ external zap
+ call goo(zap)
+ x = zap(3)
+ call zoo(zap)
+ end
+ */
+ if (!nbad) {
+ atypes->type = k;
+ at->changes |= 1;
+ }
+ }
+ if (i < nargs)
+ goto toofew;
+ if (nbad) {
+ if (type) {
+ /* we're defining the procedure */
+ t = init_ap[type];
+ te = t + i0;
+ proc_argchanges = 1;
+ goto newlist;
+ }
+ return;
+ }
+ if (zap == 1 && (at->changes & 5) != 5)
+ at->changes = 0;
+ return;
+ }
+ newlist:
+ i = i0 + nchargs;
+ for(cp = arglist; cp; cp = cp->nextp)
+ i++;
+ k = sizeof(Argtypes) + (i-1)*sizeof(Atype);
+ *at0 = *at1 = at = stg == STGEXT ? (Argtypes *)gmem(k,1)
+ : (Argtypes *) mem(k,1);
+ at->dnargs = at->nargs = i;
+ at->defined = zap & 6;
+ at->changes = type ? 0 : 4;
+ atypes = at->atypes;
+ for(; t < te; atypes++) {
+ atypes->type = *t++;
+ atypes->cp = 0;
+ }
+ for(cp = arglist; cp; atypes++, cp = cp->nextp) {
+ atypes->cp = 0;
+ atypes->type = (q = (expptr)cp->datap)
+ ? typekludge(ccall, q, atypes, 0)
+ : 0;
+ }
+ for(; --nchargs >= 0; atypes++) {
+ atypes->type = TYFTNLEN + 100;
+ atypes->cp = 0;
+ }
+ }
+
+ static char*
+#ifdef KR_headers
+get_argtypes(p, pat0, pat1) Exprp p; Argtypes ***pat0, ***pat1;
+#else
+get_argtypes(Exprp p, Argtypes ***pat0, Argtypes ***pat1)
+#endif
+{
+ Addrp a;
+ Argtypes **at0, **at1;
+ Namep np;
+ expptr rp;
+ Extsym *e;
+ char *fname;
+
+ a = (Addrp)p->leftp;
+ switch(a->vstg) {
+ case STGEXT:
+ switch(a->uname_tag) {
+ case UNAM_EXTERN: /* e.g., sqrt() */
+ e = extsymtab + a->memno;
+ at0 = at1 = &e->arginfo;
+ fname = e->fextname;
+ break;
+ case UNAM_NAME:
+ np = a->user.name;
+ at0 = &extsymtab[np->vardesc.varno].arginfo;
+ at1 = &np->arginfo;
+ fname = np->fvarname;
+ break;
+ default:
+ goto bug;
+ }
+ break;
+ case STGARG:
+ if (a->uname_tag != UNAM_NAME)
+ goto bug;
+ np = a->user.name;
+ at0 = at1 = &np->arginfo;
+ fname = np->fvarname;
+ break;
+ default:
+ bug:
+ Fatal("Confusion in saveargtypes");
+ }
+ *pat0 = at0;
+ *pat1 = at1;
+ return fname;
+ }
+
+ void
+#ifdef KR_headers
+saveargtypes(p)
+ register Exprp p;
+#else
+saveargtypes(register Exprp p)
+#endif
+ /* for writing prototypes */
+{
+ Argtypes **at0, **at1;
+ chainp arglist;
+ expptr rp;
+ char *fname;
+
+ fname = get_argtypes(p, &at0, &at1);
+ rp = p->rightp;
+ arglist = rp && rp->tag == TLIST ? rp->listblock.listp : 0;
+ save_argtypes(arglist, at0, at1, p->opcode == OPCCALL,
+ fname, p->leftp->addrblock.vstg, 0, 0, 0);
+ }
+
+/* putcall - fix up the argument list, and write out the invocation. p
+ is expected to be initialized and point to an OPCALL or OPCCALL
+ expression. The return value is a pointer to a temporary holding the
+ result of a COMPLEX or CHARACTER operation, or NULL. */
+
+ LOCAL expptr
+#ifdef KR_headers
+putcall(p0, temp)
+ expptr p0;
+ Addrp *temp;
+#else
+putcall(expptr p0, Addrp *temp)
+#endif
+{
+ register Exprp p = (Exprp)p0;
+ chainp arglist; /* Pointer to actual arguments, if any */
+ chainp charsp; /* List of copies of the variables which
+ hold the lengths of character
+ parameters (other than procedure
+ parameters) */
+ chainp cp; /* Iterator over argument lists */
+ register expptr q; /* Pointer to the current argument */
+ Addrp fval; /* Function return value */
+ int type; /* type of the call - presumably this was
+ set elsewhere */
+ int byvalue; /* True iff we don't want to massage the
+ parameter list, since we're calling a C
+ library routine */
+ char *s;
+ Argtypes *at, **at0, **at1;
+ Atype *At, *Ate;
+
+ type = p -> vtype;
+ charsp = NULL;
+ byvalue = (p->opcode == OPCCALL);
+
+/* Verify the actual parameters */
+
+ if (p == (Exprp) NULL)
+ err ("putcall: NULL call expression");
+ else if (p -> tag != TEXPR)
+ erri ("putcall: expected TEXPR, got '%d'", p -> tag);
+
+/* Find the argument list */
+
+ if(p->rightp && p -> rightp -> tag == TLIST)
+ arglist = p->rightp->listblock.listp;
+ else
+ arglist = NULL;
+
+/* Count the number of explicit arguments, including lengths of character
+ variables */
+
+ if (!byvalue) {
+ get_argtypes(p, &at0, &at1);
+ At = Ate = 0;
+ if ((at = *at0) && at->nargs >= 0) {
+ At = at->atypes;
+ Ate = At + at->nargs;
+ At += init_ac[type];
+ }
+ for(cp = arglist ; cp ; cp = cp->nextp) {
+ q = (expptr) cp->datap;
+ if( ISCONST(q) ) {
+
+/* Even constants are passed by reference, so we need to put them in the
+ literal table */
+
+ q = (expptr) putconst((Constp)q);
+ cp->datap = (char *) q;
+ }
+
+/* Save the length expression of character variables (NOT character
+ procedures) for the end of the argument list */
+
+ if( ISCHAR(q) &&
+ (q->headblock.vclass != CLPROC
+ || q->headblock.vstg == STGARG
+ && q->tag == TADDR
+ && q->addrblock.uname_tag == UNAM_NAME
+ && q->addrblock.user.name->vprocclass == PTHISPROC)
+ && (!At || At->type % 100 % TYSUBR == TYCHAR))
+ {
+ p0 = cpexpr(q->headblock.vleng);
+ charsp = mkchain((char *)p0, charsp);
+ if (q->headblock.vclass == CLUNKNOWN
+ && q->headblock.vstg == STGARG)
+ q->addrblock.user.name->vpassed = 1;
+ else if (q->tag == TADDR
+ && q->addrblock.uname_tag == UNAM_CONST)
+ p0->constblock.Const.ci
+ += q->addrblock.user.Const.ccp1.blanks;
+ }
+ if (At && ++At == Ate)
+ At = 0;
+ }
+ }
+ charsp = revchain(charsp);
+
+/* If the routine is a CHARACTER function ... */
+
+ if(type == TYCHAR)
+ {
+ if( ISICON(p->vleng) )
+ {
+
+/* Allocate a temporary to hold the return value of the function */
+
+ fval = mktmp(TYCHAR, p->vleng);
+ }
+ else {
+ err("adjustable character function");
+ if (temp)
+ *temp = 0;
+ return 0;
+ }
+ }
+
+/* If the routine is a COMPLEX function ... */
+
+ else if( ISCOMPLEX(type) )
+ fval = mktmp(type, ENULL);
+ else
+ fval = NULL;
+
+/* Write the function name, without taking its address */
+
+ p -> leftp = putx(fixtype(putaddr(p->leftp)));
+
+ if(fval)
+ {
+ chainp prepend;
+
+/* Prepend a copy of the function return value buffer out as the first
+ argument. */
+
+ prepend = mkchain((char *)putx(putaddr(cpexpr((expptr)fval))), arglist);
+
+/* If it's a character function, also prepend the length of the result */
+
+ if(type==TYCHAR)
+ {
+
+ prepend->nextp = mkchain((char *)putx(mkconv(TYLENG,
+ p->vleng)), arglist);
+ }
+ if (!(q = p->rightp))
+ p->rightp = q = (expptr)mklist(CHNULL);
+ q->listblock.listp = prepend;
+ }
+
+/* Scan through the fortran argument list */
+
+ for(cp = arglist ; cp ; cp = cp->nextp)
+ {
+ q = (expptr) (cp->datap);
+ if (q == ENULL)
+ err ("putcall: NULL argument");
+
+/* call putaddr only when we've got a parameter for a C routine or a
+ memory resident parameter */
+
+ if (q -> tag == TCONST && !byvalue)
+ q = (expptr) putconst ((Constp)q);
+
+ if(q->tag==TADDR && (byvalue || q->addrblock.vstg!=STGREG) ) {
+ if (q->addrblock.parenused
+ && !byvalue && q->headblock.vtype != TYCHAR)
+ goto make_copy;
+ cp->datap = (char *)putaddr(q);
+ }
+ else if( ISCOMPLEX(q->headblock.vtype) )
+ cp -> datap = (char *) putx (fixtype(putcxop(q)));
+ else if (ISCHAR(q) )
+ cp -> datap = (char *) putx (fixtype((expptr)putchop(q)));
+ else if( ! ISERROR(q) )
+ {
+ if(byvalue) {
+ if (q->tag == TEXPR && q->exprblock.opcode == OPCONV) {
+ if (ISCOMPLEX(q->exprblock.leftp->headblock.vtype)
+ && q->exprblock.leftp->tag == TEXPR)
+ q->exprblock.leftp = putcxop(q->exprblock.leftp);
+ else
+ q->exprblock.leftp = putx(q->exprblock.leftp);
+ }
+ else
+ cp -> datap = (char *) putx(q);
+ }
+ else if (q->tag == TEXPR && q->exprblock.opcode == OPCHARCAST)
+ cp -> datap = (char *) putx(q);
+ else {
+ expptr t, t1;
+
+/* If we've got a register parameter, or (maybe?) a constant, save it in a
+ temporary first */
+ make_copy:
+ t = (expptr) mktmp(q->headblock.vtype, q->headblock.vleng);
+
+/* Assign to temporary variables before invoking the subroutine or
+ function */
+
+ t1 = putassign( cpexpr(t), q );
+ if (doin_setbound)
+ t = mkexpr(OPCOMMA_ARG, t1, t);
+ else
+ putout(t1);
+ cp -> datap = (char *) t;
+ } /* else */
+ } /* if !ISERROR(q) */
+ }
+
+/* Now adjust the lengths of the CHARACTER parameters */
+
+ for(cp = charsp ; cp ; cp = cp->nextp)
+ cp->datap = (char *)addrfix(putx(
+ /* in case MAIN has a character*(*)... */
+ (s = cp->datap) ? mkconv(TYLENG,(expptr)s)
+ : ICON(0)));
+
+/* ... and add them to the end of the argument list */
+
+ hookup (arglist, charsp);
+
+/* Return the name of the temporary used to hold the results, if any was
+ necessary. */
+
+ if (temp) *temp = fval;
+ else frexpr ((expptr)fval);
+
+ saveargtypes(p);
+
+ return (expptr) p;
+}
+
+
+
+/* putmnmx -- Put min or max. p must point to an EXPR, not just a
+ CONST */
+
+ LOCAL expptr
+#ifdef KR_headers
+putmnmx(p)
+ register expptr p;
+#else
+putmnmx(register expptr p)
+#endif
+{
+ int op, op2, type;
+ expptr arg, qp, temp;
+ chainp p0, p1;
+ Addrp sp, tp;
+ char comment_buf[80];
+ char *what;
+
+ if(p->tag != TEXPR)
+ badtag("putmnmx", p->tag);
+
+ type = p->exprblock.vtype;
+ op = p->exprblock.opcode;
+ op2 = op == OPMIN ? OPMIN2 : OPMAX2;
+ p0 = p->exprblock.leftp->listblock.listp;
+ free( (charptr) (p->exprblock.leftp) );
+ free( (charptr) p );
+
+ /* special case for two addressable operands */
+
+ if (addressable((expptr)p0->datap)
+ && (p1 = p0->nextp)
+ && addressable((expptr)p1->datap)
+ && !p1->nextp) {
+ if (type == TYREAL && forcedouble)
+ op2 = op == OPMIN ? OPDMIN : OPDMAX;
+ p = mkexpr(op2, mkconv(type, cpexpr((expptr)p0->datap)),
+ mkconv(type, cpexpr((expptr)p1->datap)));
+ frchain(&p0);
+ return p;
+ }
+
+ /* general case */
+
+ sp = mktmp(type, ENULL);
+
+/* We only need a second temporary if the arg list has an unaddressable
+ value */
+
+ tp = (Addrp) NULL;
+ qp = ENULL;
+ for (p1 = p0 -> nextp; p1; p1 = p1 -> nextp)
+ if (!addressable ((expptr) p1 -> datap)) {
+ tp = mktmp(type, ENULL);
+ qp = mkexpr(op2, cpexpr((expptr)sp), cpexpr((expptr)tp));
+ qp = fixexpr((Exprp)qp);
+ break;
+ } /* if */
+
+/* Now output the appropriate number of assignments and comparisons. Min
+ and max are implemented by the simple O(n) algorithm:
+
+ min (a, b, c, d) ==>
+ { <type> t1, t2;
+
+ t1 = a;
+ t2 = b; t1 = (t1 < t2) ? t1 : t2;
+ t2 = c; t1 = (t1 < t2) ? t1 : t2;
+ t2 = d; t1 = (t1 < t2) ? t1 : t2;
+ }
+*/
+
+ if (!doin_setbound) {
+ switch(op) {
+ case OPLT:
+ case OPMIN:
+ case OPDMIN:
+ case OPMIN2:
+ what = "IN";
+ break;
+ default:
+ what = "AX";
+ }
+ sprintf (comment_buf, "Computing M%s", what);
+ p1_comment (comment_buf);
+ }
+
+ p1 = p0->nextp;
+ temp = (expptr)p0->datap;
+ if (addressable(temp) && addressable((expptr)p1->datap)) {
+ p = mkconv(type, cpexpr(temp));
+ arg = mkconv(type, cpexpr((expptr)p1->datap));
+ temp = mkexpr(op2, p, arg);
+ if (!ISCONST(temp))
+ temp = fixexpr((Exprp)temp);
+ p1 = p1->nextp;
+ }
+ p = putassign (cpexpr((expptr)sp), temp);
+
+ for(; p1 ; p1 = p1->nextp)
+ {
+ if (addressable ((expptr) p1 -> datap)) {
+ arg = mkconv(type, cpexpr((expptr)p1->datap));
+ temp = mkexpr(op2, cpexpr((expptr)sp), arg);
+ temp = fixexpr((Exprp)temp);
+ } else {
+ temp = (expptr) cpexpr (qp);
+ p = mkexpr(OPCOMMA, p,
+ putassign(cpexpr((expptr)tp), (expptr)p1->datap));
+ } /* else */
+
+ if(p1->nextp)
+ p = mkexpr(OPCOMMA, p,
+ putassign(cpexpr((expptr)sp), temp));
+ else {
+ if (type == TYREAL && forcedouble)
+ temp->exprblock.opcode =
+ op == OPMIN ? OPDMIN : OPDMAX;
+ if (doin_setbound)
+ p = mkexpr(OPCOMMA, p, temp);
+ else {
+ putout (p);
+ p = putx(temp);
+ }
+ if (qp)
+ frexpr (qp);
+ } /* else */
+ } /* for */
+
+ frchain( &p0 );
+ return p;
+}
+
+
+ void
+#ifdef KR_headers
+putwhile(p)
+ expptr p;
+#else
+putwhile(expptr p)
+#endif
+{
+ long where;
+ int k, n;
+
+ if (wh_next >= wh_last)
+ {
+ k = wh_last - wh_first;
+ n = k + 100;
+ wh_next = mem(n,0);
+ wh_last = wh_first + n;
+ if (k)
+ memcpy(wh_next, wh_first, k);
+ wh_first = wh_next;
+ wh_next += k;
+ wh_last = wh_first + n;
+ }
+ p1put(P1_WHILE1START);
+ where = ftell(pass1_file);
+ if( !ISLOGICAL((k = (p = fixtype(p))->headblock.vtype)))
+ {
+ if(k != TYERROR)
+ err("non-logical expression in DO WHILE statement");
+ }
+ else {
+ p = putx(p);
+ *wh_next++ = ftell(pass1_file) > where;
+ p1put(P1_WHILE2START);
+ p1_expr(p);
+ }
+ }
diff --git a/usr.bin/f2c/sysdep.c b/usr.bin/f2c/sysdep.c
new file mode 100644
index 0000000..5469034
--- /dev/null
+++ b/usr.bin/f2c/sysdep.c
@@ -0,0 +1,519 @@
+/****************************************************************
+Copyright 1990 - 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+#include "defs.h"
+#include "usignal.h"
+
+char binread[] = "rb", textread[] = "r";
+char binwrite[] = "wb", textwrite[] = "w";
+char *c_functions = "c_functions";
+char *coutput = "c_output";
+char *initfname = "raw_data";
+char *initbname = "raw_data.b";
+char *blkdfname = "block_data";
+char *p1_file = "p1_file";
+char *p1_bakfile = "p1_file.BAK";
+char *sortfname = "init_file";
+char *proto_fname = "proto_file";
+
+char link_msg[] = "-lf2c -lm"; /* was "-lF77 -lI77 -lm -lc"; */
+
+char *outbuf = "", *outbtail;
+
+#ifndef TMPDIR
+#ifdef MSDOS
+#define TMPDIR ""
+#else
+#define TMPDIR "/tmp"
+#endif
+#endif
+
+char *tmpdir = TMPDIR;
+#ifndef MSDOS
+#ifndef KR_headers
+extern int getpid(void);
+#endif
+#endif
+
+ void
+#ifdef KR_headers
+Un_link_all(cdelete)
+ int cdelete;
+#else
+Un_link_all(int cdelete)
+#endif
+{
+#ifndef KR_headers
+ extern int unlink(const char *);
+#endif
+ if (!debugflag) {
+ unlink(c_functions);
+ unlink(initfname);
+ unlink(p1_file);
+ unlink(sortfname);
+ unlink(blkdfname);
+ if (cdelete && coutput)
+ unlink(coutput);
+ }
+ }
+
+ void
+set_tmp_names(Void)
+{
+ int k;
+ if (debugflag == 1)
+ return;
+ k = strlen(tmpdir) + 24;
+ c_functions = (char *)ckalloc(7*k);
+ initfname = c_functions + k;
+ initbname = initfname + k;
+ blkdfname = initbname + k;
+ p1_file = blkdfname + k;
+ p1_bakfile = p1_file + k;
+ sortfname = p1_bakfile + k;
+ {
+#ifdef MSDOS
+ char buf[64], *s, *t;
+ if (!*tmpdir || *tmpdir == '.' && !tmpdir[1])
+ t = "";
+ else {
+ /* substitute \ for / to avoid confusion with a
+ * switch indicator in the system("sort ...")
+ * call in formatdata.c
+ */
+ for(s = tmpdir, t = buf; *s; s++, t++)
+ if ((*t = *s) == '/')
+ *t = '\\';
+ if (t[-1] != '\\')
+ *t++ = '\\';
+ *t = 0;
+ t = buf;
+ }
+ sprintf(c_functions, "%sf2c_func", t);
+ sprintf(initfname, "%sf2c_rd", t);
+ sprintf(blkdfname, "%sf2c_blkd", t);
+ sprintf(p1_file, "%sf2c_p1f", t);
+ sprintf(p1_bakfile, "%sf2c_p1fb", t);
+ sprintf(sortfname, "%sf2c_sort", t);
+#else
+ long pid = getpid();
+ sprintf(c_functions, "%s/f2c%ld_func", tmpdir, pid);
+ sprintf(initfname, "%s/f2c%ld_rd", tmpdir, pid);
+ sprintf(blkdfname, "%s/f2c%ld_blkd", tmpdir, pid);
+ sprintf(p1_file, "%s/f2c%ld_p1f", tmpdir, pid);
+ sprintf(p1_bakfile, "%s/f2c%ld_p1fb", tmpdir, pid);
+ sprintf(sortfname, "%s/f2c%ld_sort", tmpdir, pid);
+#endif
+ sprintf(initbname, "%s.b", initfname);
+ }
+ if (debugflag)
+ fprintf(diagfile, "%s %s %s %s %s %s\n", c_functions,
+ initfname, blkdfname, p1_file, p1_bakfile, sortfname);
+ }
+
+ char *
+#ifdef KR_headers
+c_name(s, ft)
+ char *s;
+ int ft;
+#else
+c_name(char *s, int ft)
+#endif
+{
+ char *b, *s0;
+ int c;
+
+ b = s0 = s;
+ while(c = *s++)
+ if (c == '/')
+ b = s;
+ if (--s < s0 + 3 || s[-2] != '.'
+ || ((c = *--s) != 'f' && c != 'F')) {
+ infname = s0;
+ Fatal("file name must end in .f or .F");
+ }
+ strcpy(outbtail, b);
+ outbtail[s-b] = ft;
+ b = copys(outbuf);
+ return b;
+ }
+
+ static void
+#ifdef KR_headers
+killed(sig)
+ int sig;
+#else
+killed(int sig)
+#endif
+{
+ sig = sig; /* shut up warning */
+ signal(SIGINT, SIG_IGN);
+#ifdef SIGQUIT
+ signal(SIGQUIT, SIG_IGN);
+#endif
+#ifdef SIGHUP
+ signal(SIGHUP, SIG_IGN);
+#endif
+ signal(SIGTERM, SIG_IGN);
+ Un_link_all(1);
+ exit(126);
+ }
+
+ static void
+#ifdef KR_headers
+sig1catch(sig)
+ int sig;
+#else
+sig1catch(int sig)
+#endif
+{
+ sig = sig; /* shut up warning */
+ if (signal(sig, SIG_IGN) != SIG_IGN)
+ signal(sig, killed);
+ }
+
+ static void
+#ifdef KR_headers
+flovflo(sig)
+ int sig;
+#else
+flovflo(int sig)
+#endif
+{
+ sig = sig; /* shut up warning */
+ Fatal("floating exception during constant evaluation; cannot recover");
+ /* vax returns a reserved operand that generates
+ an illegal operand fault on next instruction,
+ which if ignored causes an infinite loop.
+ */
+ signal(SIGFPE, flovflo);
+}
+
+ void
+#ifdef KR_headers
+sigcatch(sig)
+ int sig;
+#else
+sigcatch(int sig)
+#endif
+{
+ sig = sig; /* shut up warning */
+ sig1catch(SIGINT);
+#ifdef SIGQUIT
+ sig1catch(SIGQUIT);
+#endif
+#ifdef SIGHUP
+ sig1catch(SIGHUP);
+#endif
+ sig1catch(SIGTERM);
+ signal(SIGFPE, flovflo); /* catch overflows */
+ }
+
+
+dofork(Void)
+{
+#ifdef MSDOS
+ Fatal("Only one Fortran input file allowed under MS-DOS");
+#else
+#ifndef KR_headers
+ extern int fork(void), wait(int*);
+#endif
+ int pid, status, w;
+ extern int retcode;
+
+ if (!(pid = fork()))
+ return 1;
+ if (pid == -1)
+ Fatal("bad fork");
+ while((w = wait(&status)) != pid)
+ if (w == -1)
+ Fatal("bad wait code");
+ retcode |= status >> 8;
+#endif
+ return 0;
+ }
+
+/* Initialization of tables that change with the character set... */
+
+char escapes[Table_size];
+
+#ifdef non_ASCII
+char *str_fmt[Table_size];
+static char *str0fmt[127] = { /*}*/
+#else
+char *str_fmt[Table_size] = {
+#endif
+ "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007",
+ "\\b", "\\t", "\\n", "\\013", "\\f", "\\r", "\\016", "\\017",
+ "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027",
+ "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037",
+ " ", "!", "\\\"", "#", "$", "%%", "&", "'",
+ "(", ")", "*", "+", ",", "-", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "<", "=", ">", "?",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
+ "`", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "{", "|", "}", "~"
+ };
+
+#ifdef non_ASCII
+char *chr_fmt[Table_size];
+static char *chr0fmt[127] = { /*}*/
+#else
+char *chr_fmt[Table_size] = {
+#endif
+ "\\0", "\\1", "\\2", "\\3", "\\4", "\\5", "\\6", "\\7",
+ "\\b", "\\t", "\\n", "\\13", "\\f", "\\r", "\\16", "\\17",
+ "\\20", "\\21", "\\22", "\\23", "\\24", "\\25", "\\26", "\\27",
+ "\\30", "\\31", "\\32", "\\33", "\\34", "\\35", "\\36", "\\37",
+ " ", "!", "\"", "#", "$", "%%", "&", "\\'",
+ "(", ")", "*", "+", ",", "-", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "<", "=", ">", "?",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
+ "`", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "{", "|", "}", "~"
+ };
+
+ void
+fmt_init(Void)
+{
+ static char *str1fmt[6] =
+ { "\\b", "\\t", "\\n", "\\f", "\\r", "\\%03o" };
+ register int i, j;
+ register char *s;
+
+ /* str_fmt */
+
+#ifdef non_ASCII
+ i = 0;
+#else
+ i = 127;
+#endif
+ for(; i < Table_size; i++)
+ str_fmt[i] = "\\%03o";
+#ifdef non_ASCII
+ for(i = 32; i < 127; i++) {
+ s = str0fmt[i];
+ str_fmt[*(unsigned char *)s] = s;
+ }
+ str_fmt['"'] = "\\\"";
+#else
+ if (Ansi == 1)
+ str_fmt[7] = chr_fmt[7] = "\\a";
+#endif
+
+ /* chr_fmt */
+
+#ifdef non_ASCII
+ for(i = 0; i < 32; i++)
+ chr_fmt[i] = chr0fmt[i];
+#else
+ i = 127;
+#endif
+ for(; i < Table_size; i++)
+ chr_fmt[i] = "\\%o";
+#ifdef non_ASCII
+ for(i = 32; i < 127; i++) {
+ s = chr0fmt[i];
+ j = *(unsigned char *)s;
+ if (j == '\\')
+ j = *(unsigned char *)(s+1);
+ chr_fmt[j] = s;
+ }
+#endif
+
+ /* escapes (used in lex.c) */
+
+ for(i = 0; i < Table_size; i++)
+ escapes[i] = i;
+ for(s = "btnfr0", i = 0; i < 6; i++)
+ escapes[*(unsigned char *)s++] = "\b\t\n\f\r"[i];
+ /* finish str_fmt and chr_fmt */
+
+ if (Ansi)
+ str1fmt[5] = "\\v";
+ if ('\v' == 'v') { /* ancient C compiler */
+ str1fmt[5] = "v";
+#ifndef non_ASCII
+ escapes['v'] = 11;
+#endif
+ }
+ else
+ escapes['v'] = '\v';
+ for(s = "\b\t\n\f\r\v", i = 0; j = *(unsigned char *)s++;)
+ str_fmt[j] = chr_fmt[j] = str1fmt[i++];
+ /* '\v' = 11 for both EBCDIC and ASCII... */
+ chr_fmt[11] = Ansi ? "\\v" : "\\13";
+ }
+
+ void
+outbuf_adjust(Void)
+{
+ int n, n1;
+ char *s;
+
+ n = n1 = strlen(outbuf);
+ if (*outbuf && outbuf[n-1] != '/')
+ n1++;
+ s = Alloc(n+64);
+ outbtail = s + n1;
+ strcpy(s, outbuf);
+ if (n != n1)
+ strcpy(s+n, "/");
+ outbuf = s;
+ }
+
+
+/* Unless SYSTEM_SORT is defined, the following gives a simple
+ * in-core version of dsort(). On Fortran source with huge DATA
+ * statements, the in-core version may exhaust the available memory,
+ * in which case you might either recompile this source file with
+ * SYSTEM_SORT defined (if that's reasonable on your system), or
+ * replace the dsort below with a more elaborate version that
+ * does a merging sort with the help of auxiliary files.
+ */
+
+#ifdef SYSTEM_SORT
+
+ int
+#ifdef KR_headers
+dsort(from, to)
+ char *from;
+ char *to;
+#else
+dsort(char *from, char *to)
+#endif
+{
+ char buf[200];
+ sprintf(buf, "sort <%s >%s", from, to);
+ return system(buf) >> 8;
+ }
+#else
+
+ static int
+#ifdef KR_headers
+ compare(a,b)
+ char *a, *b;
+#else
+ compare(const void *a, const void *b)
+#endif
+{ return strcmp(*(char **)a, *(char **)b); }
+
+#ifdef KR_headers
+dsort(from, to)
+ char *from;
+ char *to;
+#else
+dsort(char *from, char *to)
+#endif
+{
+ struct Memb {
+ struct Memb *next;
+ int n;
+ char buf[32000];
+ };
+ typedef struct Memb memb;
+ memb *mb, *mb1;
+ register char *x, *x0, *xe;
+ register int c, n;
+ FILE *f;
+ char **z, **z0;
+ int nn = 0;
+
+ f = opf(from, textread);
+ mb = (memb *)Alloc(sizeof(memb));
+ mb->next = 0;
+ x0 = x = mb->buf;
+ xe = x + sizeof(mb->buf);
+ n = 0;
+ for(;;) {
+ c = getc(f);
+ if (x >= xe && (c != EOF || x != x0)) {
+ if (!n)
+ return 126;
+ nn += n;
+ mb->n = n;
+ mb1 = (memb *)Alloc(sizeof(memb));
+ mb1->next = mb;
+ mb = mb1;
+ memcpy(mb->buf, x0, n = x-x0);
+ x0 = mb->buf;
+ x = x0 + n;
+ xe = x0 + sizeof(mb->buf);
+ n = 0;
+ }
+ if (c == EOF)
+ break;
+ if (c == '\n') {
+ ++n;
+ *x++ = 0;
+ x0 = x;
+ }
+ else
+ *x++ = c;
+ }
+ clf(&f, from, 1);
+ f = opf(to, textwrite);
+ if (x > x0) { /* shouldn't happen */
+ *x = 0;
+ ++n;
+ }
+ mb->n = n;
+ nn += n;
+ if (!nn) /* shouldn't happen */
+ goto done;
+ z = z0 = (char **)Alloc(nn*sizeof(char *));
+ for(mb1 = mb; mb1; mb1 = mb1->next) {
+ x = mb1->buf;
+ n = mb1->n;
+ for(;;) {
+ *z++ = x;
+ if (--n <= 0)
+ break;
+ while(*x++);
+ }
+ }
+ qsort((char *)z0, nn, sizeof(char *), compare);
+ for(n = nn, z = z0; n > 0; n--)
+ fprintf(f, "%s\n", *z++);
+ free((char *)z0);
+ done:
+ clf(&f, to, 1);
+ do {
+ mb1 = mb->next;
+ free((char *)mb);
+ }
+ while(mb = mb1);
+ return 0;
+ }
+#endif
diff --git a/usr.bin/f2c/sysdep.h b/usr.bin/f2c/sysdep.h
new file mode 100644
index 0000000..e3a68ef
--- /dev/null
+++ b/usr.bin/f2c/sysdep.h
@@ -0,0 +1,98 @@
+/****************************************************************
+Copyright 1990, 1991, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+/* This file is included at the start of defs.h; this file
+ * is an initial attempt to gather in one place some declarations
+ * that may need to be tweaked on some systems.
+ */
+
+#ifdef __STDC__
+#undef KR_headers
+#endif
+
+#ifndef KR_headers
+#ifndef ANSI_Libraries
+#define ANSI_Libraries
+#endif
+#ifndef ANSI_Prototypes
+#define ANSI_Prototypes
+#endif
+#endif
+
+#ifdef __BORLANDC__
+#define MSDOS
+#endif
+
+#ifdef __ZTC__ /* Zortech */
+#define MSDOS
+#endif
+
+#ifdef MSDOS
+#define ANSI_Libraries
+#define ANSI_Prototypes
+#define LONG_CAST (long)
+#else
+#define LONG_CAST
+#endif
+
+#include <stdio.h>
+
+#ifdef ANSI_Libraries
+#include <stddef.h>
+#include <stdlib.h>
+#else
+char *calloc(), *malloc(), *memcpy(), *memset(), *realloc();
+typedef int size_t;
+#ifndef atol
+ long atol();
+#endif
+
+#ifdef ANSI_Prototypes
+extern double atof(const char *);
+extern double strtod(const char*, char**);
+#else
+extern double atof(), strtod();
+#endif
+#endif
+
+/* On systems like VMS where fopen might otherwise create
+ * multiple versions of intermediate files, you may wish to
+ * #define scrub(x) unlink(x)
+ */
+#ifndef scrub
+#define scrub(x) /* do nothing */
+#endif
+
+/* On systems that severely limit the total size of statically
+ * allocated arrays, you may need to change the following to
+ * extern char **chr_fmt, *escapes, **str_fmt;
+ * and to modify sysdep.c appropriately
+ */
+extern char *chr_fmt[], escapes[], *str_fmt[];
+
+#include <string.h>
+
+#include "ctype.h"
+
+#define Bits_per_Byte 8
+#define Table_size (1 << Bits_per_Byte)
diff --git a/usr.bin/f2c/tokens b/usr.bin/f2c/tokens
new file mode 100644
index 0000000..07b1881
--- /dev/null
+++ b/usr.bin/f2c/tokens
@@ -0,0 +1,100 @@
+SEOS
+SCOMMENT
+SLABEL
+SUNKNOWN
+SHOLLERITH
+SICON
+SRCON
+SDCON
+SBITCON
+SOCTCON
+SHEXCON
+STRUE
+SFALSE
+SNAME
+SNAMEEQ
+SFIELD
+SSCALE
+SINCLUDE
+SLET
+SASSIGN
+SAUTOMATIC
+SBACKSPACE
+SBLOCK
+SCALL
+SCHARACTER
+SCLOSE
+SCOMMON
+SCOMPLEX
+SCONTINUE
+SDATA
+SDCOMPLEX
+SDIMENSION
+SDO
+SDOUBLE
+SELSE
+SELSEIF
+SEND
+SENDFILE
+SENDIF
+SENTRY
+SEQUIV
+SEXTERNAL
+SFORMAT
+SFUNCTION
+SGOTO
+SASGOTO
+SCOMPGOTO
+SARITHIF
+SLOGIF
+SIMPLICIT
+SINQUIRE
+SINTEGER
+SINTRINSIC
+SLOGICAL
+SNAMELIST
+SOPEN
+SPARAM
+SPAUSE
+SPRINT
+SPROGRAM
+SPUNCH
+SREAD
+SREAL
+SRETURN
+SREWIND
+SSAVE
+SSTATIC
+SSTOP
+SSUBROUTINE
+STHEN
+STO
+SUNDEFINED
+SWRITE
+SLPAR
+SRPAR
+SEQUALS
+SCOLON
+SCOMMA
+SCURRENCY
+SPLUS
+SMINUS
+SSTAR
+SSLASH
+SPOWER
+SCONCAT
+SAND
+SOR
+SNEQV
+SEQV
+SNOT
+SEQ
+SLT
+SGT
+SLE
+SGE
+SNE
+SENDDO
+SWHILE
+SSLASHD
+SBYTE
diff --git a/usr.bin/f2c/usignal.h b/usr.bin/f2c/usignal.h
new file mode 100644
index 0000000..ba4ee6a
--- /dev/null
+++ b/usr.bin/f2c/usignal.h
@@ -0,0 +1,7 @@
+#include <signal.h>
+#ifndef SIGHUP
+#define SIGHUP 1 /* hangup */
+#endif
+#ifndef SIGQUIT
+#define SIGQUIT 3 /* quit */
+#endif
diff --git a/usr.bin/f2c/vax.c b/usr.bin/f2c/vax.c
new file mode 100644
index 0000000..fa78805
--- /dev/null
+++ b/usr.bin/f2c/vax.c
@@ -0,0 +1,570 @@
+/****************************************************************
+Copyright 1990, 1992, 1993, 1994 by AT&T, Lucent Technologies and Bellcore.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the names of AT&T, Bell Laboratories,
+Lucent or Bellcore or any of their entities not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+AT&T, Lucent and Bellcore disclaim all warranties with regard to
+this software, including all implied warranties of
+merchantability and fitness. In no event shall AT&T, Lucent or
+Bellcore be liable for any special, indirect or consequential
+damages or any damages whatsoever resulting from loss of use,
+data or profits, whether in an action of contract, negligence or
+other tortious action, arising out of or in connection with the
+use or performance of this software.
+****************************************************************/
+
+#include "defs.h"
+#include "pccdefs.h"
+#include "output.h"
+
+int regnum[] = {
+ 11, 10, 9, 8, 7, 6 };
+
+/* Put out a constant integer */
+
+ void
+#ifdef KR_headers
+prconi(fp, n)
+ FILEP fp;
+ ftnint n;
+#else
+prconi(FILEP fp, ftnint n)
+#endif
+{
+ fprintf(fp, "\t%ld\n", n);
+}
+
+
+
+/* Put out a constant address */
+
+ void
+#ifdef KR_headers
+prcona(fp, a)
+ FILEP fp;
+ ftnint a;
+#else
+prcona(FILEP fp, ftnint a)
+#endif
+{
+ fprintf(fp, "\tL%ld\n", a);
+}
+
+
+ void
+#ifdef KR_headers
+prconr(fp, x, k)
+ FILEP fp;
+ Constp x;
+ int k;
+#else
+prconr(FILEP fp, Constp x, int k)
+#endif
+{
+ char *x0, *x1;
+ char cdsbuf0[64], cdsbuf1[64];
+
+ if (k > 1) {
+ if (x->vstg) {
+ x0 = x->Const.cds[0];
+ x1 = x->Const.cds[1];
+ }
+ else {
+ x0 = cds(dtos(x->Const.cd[0]), cdsbuf0);
+ x1 = cds(dtos(x->Const.cd[1]), cdsbuf1);
+ }
+ fprintf(fp, "\t%s %s\n", x0, x1);
+ }
+ else
+ fprintf(fp, "\t%s\n", x->vstg ? x->Const.cds[0]
+ : cds(dtos(x->Const.cd[0]), cdsbuf0));
+}
+
+
+ char *
+#ifdef KR_headers
+memname(stg, mem)
+ int stg;
+ long mem;
+#else
+memname(int stg, long mem)
+#endif
+{
+ static char s[20];
+
+ switch(stg)
+ {
+ case STGCOMMON:
+ case STGEXT:
+ sprintf(s, "_%s", extsymtab[mem].cextname);
+ break;
+
+ case STGBSS:
+ case STGINIT:
+ sprintf(s, "v.%ld", mem);
+ break;
+
+ case STGCONST:
+ sprintf(s, "L%ld", mem);
+ break;
+
+ case STGEQUIV:
+ sprintf(s, "q.%ld", mem+eqvstart);
+ break;
+
+ default:
+ badstg("memname", stg);
+ }
+ return(s);
+}
+
+extern void addrlit Argdcl((Addrp));
+
+/* make_int_expr -- takes an arbitrary expression, and replaces all
+ occurrences of arguments with indirection */
+
+ expptr
+#ifdef KR_headers
+make_int_expr(e)
+ expptr e;
+#else
+make_int_expr(expptr e)
+#endif
+{
+ chainp listp;
+ Addrp ap;
+ expptr e1;
+
+ if (e != ENULL)
+ switch (e -> tag) {
+ case TADDR:
+ if (e->addrblock.isarray) {
+ if (e1 = e->addrblock.memoffset)
+ e->addrblock.memoffset = make_int_expr(e1);
+ }
+ else if (e->addrblock.vstg == STGARG)
+ e = mkexpr(OPWHATSIN, e, ENULL);
+ break;
+ case TEXPR:
+ e -> exprblock.leftp = make_int_expr (e -> exprblock.leftp);
+ e -> exprblock.rightp = make_int_expr (e -> exprblock.rightp);
+ break;
+ case TLIST:
+ for(listp = e->listblock.listp; listp; listp = listp->nextp)
+ if ((ap = (Addrp)listp->datap)
+ && ap->tag == TADDR
+ && ap->uname_tag == UNAM_CONST)
+ addrlit(ap);
+ break;
+ default:
+ break;
+ } /* switch */
+
+ return e;
+} /* make_int_expr */
+
+
+
+/* prune_left_conv -- used in prolog() to strip type cast away from
+ left-hand side of parameter adjustments. This is necessary to avoid
+ error messages from cktype() */
+
+ expptr
+#ifdef KR_headers
+prune_left_conv(e)
+ expptr e;
+#else
+prune_left_conv(expptr e)
+#endif
+{
+ struct Exprblock *leftp;
+
+ if (e && e -> tag == TEXPR && e -> exprblock.leftp &&
+ e -> exprblock.leftp -> tag == TEXPR) {
+ leftp = &(e -> exprblock.leftp -> exprblock);
+ if (leftp -> opcode == OPCONV) {
+ e -> exprblock.leftp = leftp -> leftp;
+ free ((charptr) leftp);
+ }
+ }
+
+ return e;
+} /* prune_left_conv */
+
+
+ static int wrote_comment;
+ static FILE *comment_file;
+
+ static void
+write_comment(Void)
+{
+ if (!wrote_comment) {
+ wrote_comment = 1;
+ nice_printf (comment_file, "/* Parameter adjustments */\n");
+ }
+ }
+
+ static int *
+count_args(Void)
+{
+ register int *ac;
+ register chainp cp;
+ register struct Entrypoint *ep;
+ register Namep q;
+
+ ac = (int *)ckalloc(nallargs*sizeof(int));
+
+ for(ep = entries; ep; ep = ep->entnextp)
+ for(cp = ep->arglist; cp; cp = cp->nextp)
+ if (q = (Namep)cp->datap)
+ ac[q->argno]++;
+ return ac;
+ }
+
+ static int nu, *refs, *used;
+ static void awalk Argdcl((expptr));
+
+ static void
+#ifdef KR_headers
+aawalk(P)
+ struct Primblock *P;
+#else
+aawalk(struct Primblock *P)
+#endif
+{
+ chainp p;
+ expptr q;
+
+ if (P->argsp)
+ for(p = P->argsp->listp; p; p = p->nextp) {
+ q = (expptr)p->datap;
+ if (q->tag != TCONST)
+ awalk(q);
+ }
+ if (P->namep->vtype == TYCHAR) {
+ if (q = P->fcharp)
+ awalk(q);
+ if (q = P->lcharp)
+ awalk(q);
+ }
+ }
+
+ static void
+#ifdef KR_headers
+afwalk(P)
+ struct Primblock *P;
+#else
+afwalk(struct Primblock *P)
+#endif
+{
+ chainp p;
+ expptr q;
+ Namep np;
+
+ for(p = P->argsp->listp; p; p = p->nextp) {
+ q = (expptr)p->datap;
+ switch(q->tag) {
+ case TPRIM:
+ np = q->primblock.namep;
+ if (np->vknownarg)
+ if (!refs[np->argno]++)
+ used[nu++] = np->argno;
+ if (q->primblock.argsp == 0) {
+ if (q->primblock.namep->vclass == CLPROC
+ && q->primblock.namep->vprocclass
+ != PTHISPROC
+ || q->primblock.namep->vdim != NULL)
+ continue;
+ }
+ default:
+ awalk(q);
+ /* no break */
+ case TCONST:
+ continue;
+ }
+ }
+ }
+
+ static void
+#ifdef KR_headers
+awalk(e)
+ expptr e;
+#else
+awalk(expptr e)
+#endif
+{
+ Namep np;
+ top:
+ if (!e)
+ return;
+ switch(e->tag) {
+ default:
+ badtag("awalk", e->tag);
+ case TCONST:
+ case TERROR:
+ case TLIST:
+ return;
+ case TADDR:
+ if (e->addrblock.uname_tag == UNAM_NAME) {
+ np = e->addrblock.user.name;
+ if (np->vknownarg && !refs[np->argno]++)
+ used[nu++] = np->argno;
+ }
+ e = e->addrblock.memoffset;
+ goto top;
+ case TPRIM:
+ np = e->primblock.namep;
+ if (np->vknownarg && !refs[np->argno]++)
+ used[nu++] = np->argno;
+ if (e->primblock.argsp && np->vclass != CLVAR)
+ afwalk((struct Primblock *)e);
+ else
+ aawalk((struct Primblock *)e);
+ return;
+ case TEXPR:
+ awalk(e->exprblock.rightp);
+ e = e->exprblock.leftp;
+ goto top;
+ }
+ }
+
+ static chainp
+#ifdef KR_headers
+argsort(p0)
+ chainp p0;
+#else
+argsort(chainp p0)
+#endif
+{
+ Namep *args, q, *stack;
+ int i, nargs, nout, nst;
+ chainp *d, *da, p, rv, *rvp;
+ struct Dimblock *dp;
+
+ if (!p0)
+ return p0;
+ for(nargs = 0, p = p0; p; p = p->nextp)
+ nargs++;
+ args = (Namep *)ckalloc(i = nargs*(sizeof(Namep) + 2*sizeof(chainp)
+ + 2*sizeof(int)));
+ memset((char *)args, 0, i);
+ stack = args + nargs;
+ d = (chainp *)(stack + nargs);
+ refs = (int *)(d + nargs);
+ used = refs + nargs;
+
+ for(p = p0; p; p = p->nextp) {
+ q = (Namep) p->datap;
+ args[q->argno] = q;
+ }
+ for(p = p0; p; p = p->nextp) {
+ q = (Namep) p->datap;
+ if (!(dp = q->vdim))
+ continue;
+ i = dp->ndim;
+ while(--i >= 0)
+ awalk(dp->dims[i].dimexpr);
+ awalk(dp->basexpr);
+ while(nu > 0) {
+ refs[i = used[--nu]] = 0;
+ d[i] = mkchain((char *)q, d[i]);
+ }
+ }
+ for(i = nst = 0; i < nargs; i++)
+ for(p = d[i]; p; p = p->nextp)
+ refs[((Namep)p->datap)->argno]++;
+ while(--i >= 0)
+ if (!refs[i])
+ stack[nst++] = args[i];
+ if (nst == nargs) {
+ rv = p0;
+ goto done;
+ }
+ nout = 0;
+ rv = 0;
+ rvp = &rv;
+ while(nst > 0) {
+ nout++;
+ q = stack[--nst];
+ *rvp = p = mkchain((char *)q, CHNULL);
+ rvp = &p->nextp;
+ da = d + q->argno;
+ for(p = *da; p; p = p->nextp)
+ if (!--refs[(q = (Namep)p->datap)->argno])
+ stack[nst++] = q;
+ frchain(da);
+ }
+ if (nout < nargs)
+ for(i = 0; i < nargs; i++)
+ if (refs[i]) {
+ q = args[i];
+ errstr("Can't adjust %.38s correctly\n\
+ due to dependencies among arguments.",
+ q->fvarname);
+ *rvp = p = mkchain((char *)q, CHNULL);
+ rvp = &p->nextp;
+ frchain(d+i);
+ }
+ done:
+ free((char *)args);
+ return rv;
+ }
+
+ void
+#ifdef KR_headers
+prolog(outfile, p)
+ FILE *outfile;
+ register chainp p;
+#else
+prolog(FILE *outfile, register chainp p)
+#endif
+{
+ int addif, addif0, i, nd, size;
+ int *ac;
+ register Namep q;
+ register struct Dimblock *dp;
+ chainp p0, p1;
+
+ if(procclass == CLBLOCK)
+ return;
+ p0 = p;
+ p1 = p = argsort(p);
+ wrote_comment = 0;
+ comment_file = outfile;
+ ac = 0;
+
+/* Compute the base addresses and offsets for the array parameters, and
+ assign these values to local variables */
+
+ addif = addif0 = nentry > 1;
+ for(; p ; p = p->nextp)
+ {
+ q = (Namep) p->datap;
+ if(dp = q->vdim) /* if this param is an array ... */
+ {
+ expptr Q, expr;
+
+ /* See whether to protect the following with an if. */
+ /* This only happens when there are multiple entries. */
+
+ nd = dp->ndim - 1;
+ if (addif0) {
+ if (!ac)
+ ac = count_args();
+ if (ac[q->argno] == nentry)
+ addif = 0;
+ else if (dp->basexpr
+ || dp->baseoffset->constblock.Const.ci)
+ addif = 1;
+ else for(addif = i = 0; i <= nd; i++)
+ if (dp->dims[i].dimexpr
+ && (i < nd || !q->vlastdim)) {
+ addif = 1;
+ break;
+ }
+ if (addif) {
+ write_comment();
+ nice_printf(outfile, "if (%s) {\n", /*}*/
+ q->cvarname);
+ next_tab(outfile);
+ }
+ }
+ for(i = 0 ; i <= nd; ++i)
+
+/* Store the variable length of each dimension (which is fixed upon
+ runtime procedure entry) into a local variable */
+
+ if ((Q = dp->dims[i].dimexpr)
+ && (i < nd || !q->vlastdim)) {
+ expr = (expptr)cpexpr(Q);
+ write_comment();
+ out_and_free_statement (outfile, mkexpr (OPASSIGN,
+ fixtype(cpexpr(dp->dims[i].dimsize)), expr));
+ } /* if dp -> dims[i].dimexpr */
+
+/* size will equal the size of a single element, or -1 if the type is
+ variable length character type */
+
+ size = typesize[ q->vtype ];
+ if(q->vtype == TYCHAR)
+ if( ISICON(q->vleng) )
+ size *= q->vleng->constblock.Const.ci;
+ else
+ size = -1;
+
+ /* Fudge the argument pointers for arrays so subscripts
+ * are 0-based. Not done if array bounds are being checked.
+ */
+ if(dp->basexpr) {
+
+/* Compute the base offset for this procedure */
+
+ write_comment();
+ out_and_free_statement (outfile, mkexpr (OPASSIGN,
+ cpexpr(fixtype(dp->baseoffset)),
+ cpexpr(fixtype(dp->basexpr))));
+ } /* if dp -> basexpr */
+
+ if(! checksubs) {
+ if(dp->basexpr) {
+ expptr tp;
+
+/* If the base of this array has a variable adjustment ... */
+
+ tp = (expptr) cpexpr (dp -> baseoffset);
+ if(size < 0 || q -> vtype == TYCHAR)
+ tp = mkexpr (OPSTAR, tp, cpexpr (q -> vleng));
+
+ write_comment();
+ tp = mkexpr (OPMINUSEQ,
+ mkconv (TYADDR, (expptr)p->datap),
+ mkconv(TYINT, fixtype
+ (fixtype (tp))));
+/* Avoid type clash by removing the type conversion */
+ tp = prune_left_conv (tp);
+ out_and_free_statement (outfile, tp);
+ } else if(dp->baseoffset->constblock.Const.ci != 0) {
+
+/* if the base of this array has a nonzero constant adjustment ... */
+
+ expptr tp;
+
+ write_comment();
+ if(size > 0 && q -> vtype != TYCHAR) {
+ tp = prune_left_conv (mkexpr (OPMINUSEQ,
+ mkconv (TYADDR, (expptr)p->datap),
+ mkconv (TYINT, fixtype
+ (cpexpr (dp->baseoffset)))));
+ out_and_free_statement (outfile, tp);
+ } else {
+ tp = prune_left_conv (mkexpr (OPMINUSEQ,
+ mkconv (TYADDR, (expptr)p->datap),
+ mkconv (TYINT, fixtype
+ (mkexpr (OPSTAR, cpexpr (dp -> baseoffset),
+ cpexpr (q -> vleng))))));
+ out_and_free_statement (outfile, tp);
+ } /* else */
+ } /* if dp -> baseoffset -> const */
+ } /* if !checksubs */
+
+ if (addif) {
+ nice_printf(outfile, /*{*/ "}\n");
+ prev_tab(outfile);
+ }
+ }
+ }
+ if (wrote_comment)
+ nice_printf (outfile, "\n/* Function Body */\n");
+ if (ac)
+ free((char *)ac);
+ if (p0 != p1)
+ frchain(&p1);
+} /* prolog */
diff --git a/usr.bin/f2c/version.c b/usr.bin/f2c/version.c
new file mode 100644
index 0000000..87a0922
--- /dev/null
+++ b/usr.bin/f2c/version.c
@@ -0,0 +1,2 @@
+char F2C_version[] = "19970219";
+char xxxvers[] = "\n@(#) FORTRAN 77 to C Translator, VERSION 19970219\n";
diff --git a/usr.bin/fetch/Makefile b/usr.bin/fetch/Makefile
new file mode 100644
index 0000000..31479bd
--- /dev/null
+++ b/usr.bin/fetch/Makefile
@@ -0,0 +1,9 @@
+PROG = fetch
+SRCS = file.c ftp.c http.c main.c util.c uri.c
+
+CFLAGS+= -Wall -Wwrite-strings -Wmissing-prototypes
+
+DPADD= ${LIBFTPIO} ${LIBMD}
+LDADD= -lftpio -lmd
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/fetch/fetch.1 b/usr.bin/fetch/fetch.1
new file mode 100644
index 0000000..924e867
--- /dev/null
+++ b/usr.bin/fetch/fetch.1
@@ -0,0 +1,303 @@
+.\" $Id: fetch.1,v 1.16 1997/02/22 23:43:32 wosch Exp $
+.Dd July 2, 1996
+.Dt FETCH 1
+.Os FreeBSD 2.2
+.Sh NAME
+.Nm fetch
+.Nd retrieve a file by Uniform Resource Locator
+.Sh SYNOPSIS
+.Nm fetch
+.Op Fl MPamnpqr
+.Op Fl o Ar file
+.Ar URL
+.Op Ar ...
+.Nm fetch
+.Op Fl MPRmnpqr
+.Op Fl o Ar file
+.Op Fl c Ar dir
+.Fl f Ar file
+.Fl h Ar host
+.Sh DESCRIPTION
+.Nm fetch
+allows a user to transfer files from a remote network site using
+either the
+.Tn FTP
+or the
+.Tn HTTP
+protocol. In the first form of the command, the
+.Ar URL
+may be of the form
+.Li http://site.domain/path/to/the/file
+or
+.Li ftp://site.domain/path/to/the/file.
+To denote a local filename to be copied or linked to (see the
+.Fl l
+flag below), the
+.Em file:/path/to/the/file
+URL form is used.
+.Pp
+The second form of the command can be used to get a file using the
+.Tn FTP
+protocol, specifying the file name and the remote host with the
+.Fl h
+and the
+.Fl f
+flags.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Fl a
+Automatically retry the transfer upon soft failures.
+.It Fl c Ar dir
+The file to retrieve is in directory
+.Ar dir
+on the remote host.
+.It Fl f Ar file
+The file to retrieve is named
+.Ar file
+on the remote host.
+.It Fl h Ar host
+The file to retrieve is located on the host
+.Ar host .
+.It Fl l
+If target is a
+.Ar file:/
+style of URL, make a link to the target rather than trying
+to copy it.
+.It Fl M
+.It Fl m
+Mirror mode: Set the modification time of the file so that it is
+identical to the modification time of the file at the remote host.
+If the file already exists on the local host and is identical (as
+gauged by size and modification time), no transfer is done.
+.It Fl n
+Don't preserve the modtime of the transfered file, use the current time.
+.It Fl o Ar file
+Set the output file name to
+.Ar file .
+By default, a ``pathname'' is extracted from the specified URI, and
+its basename is used as the name of the output file. A
+.Ar file
+argument of
+.Sq Li \&-
+indicates that results are to be directed to the standard output.
+.It Fl P
+.It Fl p
+Use the passive mode of the
+.Tn FTP
+protocol. This is useful for crossing certain sorts of firewalls.
+.It Fl q
+Quiet mode. Do not report transfer progress on the terminal.
+.It Fl R
+The filenames specified are ``precious'', and should not be deleted
+under any circumstances, even if the transfer failed or was incomplete.
+.It Fl r
+Restart a previously interrupted transfer.
+.It Fl T Ar seconds
+Set timeout value to
+.Ar seconds.
+Overrides the environment variables
+.Ev FTP_TIMEOUT
+for ftp transfers or
+.Ev HTTP_TIMEOUT
+for http transfers if set.
+.It Fl v
+Increase verbosity. More
+.Fl v Ns \&'s
+result in more information.
+.El
+.Pp
+Many options are also controlled solely by the environment (this is a
+bug).
+.Sh PROXY SERVERS
+Many sites use application gateways (``proxy servers'') in their
+firewalls in order to allow communication across the firewall using a
+trusted protocol. The
+.Nm fetch
+program can use both the
+.Tn FTP
+and the
+.Tn HTTP
+protocol with a proxy server.
+.Tn FTP
+proxy servers can only relay
+.Tn FTP
+requests;
+.Tn HTTP
+proxy servers can relay both
+.Tn FTP
+and
+.Tn HTTP
+requests.
+A proxy server can be configured by defining an environment variable
+named
+.Dq Va PROTO Ns Ev _PROXY ,
+where
+.Va PROTO
+is the name of the protocol in upper case. The value of the
+environment variable specifies a hostname, optionally followed by a
+colon and a port number.
+.Pp
+The
+.Tn FTP
+proxy client passes the remote username, host and port as the
+.Tn FTP
+session's username, in the form
+.Do Va remoteuser Ns Li \&@ Ns Va remotehost
+.Op Li \^@ Ns Va port
+.Dc .
+The
+.Tn HTTP
+proxy client simply passes the originally-requested URI to the remote
+server in an
+.Tn HTTP
+.Dq Li GET
+request. HTTP proxy authentication is not yet implemented.
+.Sh HTTP AUTHENTICATION
+The
+.Tn HTTP
+protocol includes support for various methods of authentication.
+Currently, the
+.Dq basic
+method, which provides no security from packet-sniffing or
+man-in-the-middle attacks, is the only method supported in
+.Nm fetch .
+Authentication is enabled by the
+.Ev HTTP_AUTH
+and
+.Ev HTTP_PROXY_AUTH
+environment variables. Both variables have the same format, which
+consists of space-separated list of parameter settings, where each
+setting consists of a colon-separated list of parameters. The first
+two parameters are always the (case-insensitive) authentication scheme
+name and the realm in which authentication is to be performed. If the
+realm is specified as
+.Sq Li \&* ,
+then it will match all realms not specified otherwise.
+.Pp
+For the
+.Li basic
+authentication scheme uses two additional optional parameters; the
+first is a user name, and the second is the password associated with
+it. If either the password or both parameters are not specified in
+the environment, and the standard input of
+.Nm
+is connected to a terminal, then
+.Nm
+will prompt the user to enter the missing parameters. Thus, if the
+user is known as
+.Dq Li jane
+in the
+.Dq Li WallyWorld
+realm, and has a password of
+.Dq Li QghiLx79
+there, then she might set her
+.Ev HTTP_AUTH
+variable to:
+.Bl -enum -offset indent
+.It
+.Dq Li basic:WallyWorld:jane:QghiLx79
+.It
+.Dq Li basic:WallyWorld:jane ,
+or
+.It
+.Dq Li basic:WallyWorld
+.El
+.Pp
+and
+.Nm
+will prompt for the missing information if it is required. She might
+also specify a realm of
+.Dq Li \&*
+instead of
+.Dq Li WallyWorld
+to indicate that the parameters can be applied to any realm. (This is
+most commonly used in a construction such as
+.Dq Li basic:* ,
+which indicates to
+.Nm
+that it may offer to do
+.Li basic
+authentication for any realm.
+.Sh ERRORS
+The
+.Nm
+command returns zero on success, or a non-zero value from
+.Aq Pa sysexits.h
+on failure. If multiple URIs are given for retrieval,
+.Nm
+will attempt all of them and return zero only if all succeeded
+(otherwise it will return the error from the last failure).
+.Sh ENVIRONMENT
+.Bl -tag -width FTP_PASSIVE_MODE -offset indent
+.It Ev FTP_TIMEOUT
+maximum time, in seconds, to wait before aborting an
+.Tn FTP
+connection.
+.It Ev FTP_LOGIN
+the login name used for
+.Tn FTP
+transfers (default
+.Dq Li anonymous )
+.It Ev FTP_PASSIVE_MODE
+force the use of passive mode FTP
+.It Ev FTP_PASSWORD
+the password used for
+.Tn FTP
+transfers (default
+.Dq Va yourname Ns Li \&@ Ns Va yourhost )
+.It Ev FTP_PROXY
+the address (in the form
+.Do Va hostname Ns
+.Op Li : Ns Va port
+.Dc )
+of a proxy server which understands
+.Tn FTP
+.It Ev HTTP_AUTH
+defines authentication parameters for
+.Tn HTTP
+.It Ev HTTP_PROXY
+the address (in the form
+.Do Va hostname Ns
+.Op Li : Ns Va port
+.Dc )
+of a proxy server which understands
+.Tn HTTP
+.It Ev HTTP_PROXY_AUTH
+defines authentication parameters for
+.Tn HTTP
+proxy servers
+.It Ev HTTP_TIMEOUT
+maximum time, in seconds, to wait before aborting an
+.Tn HTTP
+connection.
+.Sh SEE ALSO
+.Xr ftp 1 ,
+.Xr tftp 1
+.Sh HISTORY
+The
+.Nm fetch
+command appeared in
+.Fx 2.1.5 .
+.Sh AUTHORS
+The original implementation of
+.Nm
+was done by Jean-Marc Zucconi. It was extensively re-worked for
+.Fx 2.2
+by Garrett Wollman.
+.Sh BUGS
+There are too many environment variables and command-line options.
+.Pp
+The
+.Fl a
+option is only implemented for certain kinds of
+.Tn HTTP
+failures, and no
+.Tn FTP
+failures.
+.Pp
+Only the
+.Dq basic
+authentication mode is implemented for
+.Tn HTTP .
+This should be replaced by digest authentication.
diff --git a/usr.bin/fetch/fetch.h b/usr.bin/fetch/fetch.h
new file mode 100644
index 0000000..321af11
--- /dev/null
+++ b/usr.bin/fetch/fetch.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: fetch.h,v 1.2 1997/01/31 19:55:49 wollman Exp $
+ */
+
+#ifndef fetch_h
+#define fetch_h 1
+
+
+#define BUFFER_SIZE 1024
+#define FETCH_VERSION "fetch/1.0"
+#define PATH_CP "/bin/cp"
+
+struct fetch_state {
+ const char *fs_status;
+ const char *fs_outputfile;
+ int fs_verbose; /* -q, -v option */
+ int fs_newtime; /* -n option */
+ int fs_mirror; /* -m option */
+ int fs_restart; /* -r option */
+ int fs_timeout; /* -T option */
+ int fs_passive_mode; /* -p option */
+ int fs_linkfile; /* -l option */
+ int fs_precious; /* -R option */
+ int fs_auto_retry; /* -a option */
+ time_t fs_modtime;
+ void *fs_proto;
+ int (*fs_retrieve)(struct fetch_state *);
+ int (*fs_close)(struct fetch_state *);
+};
+
+struct uri_scheme {
+ const char *sc_name; /* name of the scheme, <32 characters */
+ int (*sc_parse)(struct fetch_state *, const char *);
+ /* routine to parse a URI and build state */
+ int (*sc_proxy_parse)(struct fetch_state *, const char *);
+ /* same, but for proxy case */
+ const char *sc_proxy_envar; /* envar used to determine proxy */
+ const char *sc_proxy_by; /* list of protos which can proxy us */
+
+ /* The rest is filled in dynamically... */
+ int sc_can_proxy;
+ struct uri_scheme *sc_proxyproto;
+};
+
+extern struct uri_scheme file_scheme, ftp_scheme, http_scheme;
+
+void adjmodtime(struct fetch_state *fs);
+void catchsig(int signo);
+void display(struct fetch_state *fs, off_t total, ssize_t thisincr);
+void init_schemes(void);
+void rm(struct fetch_state *fs);
+void setup_sigalrm(void);
+void unsetup_sigalrm(void);
+void *safe_malloc(size_t len);
+char *percent_decode(const char *orig);
+char *safe_strdup(const char *orig);
+char *safe_strndup(const char *orig, size_t len);
+char *to_base64(const unsigned char *buf, size_t len);
+int from_base64(const char *orig, unsigned char *buf, size_t *lenp);
+int parse_host_port(const char *str, char **hostname, int *port);
+int parse_uri(struct fetch_state *fs, const char *uri);
+#endif /* ! fetch_h */
diff --git a/usr.bin/fetch/file.c b/usr.bin/fetch/file.c
new file mode 100644
index 0000000..091639c
--- /dev/null
+++ b/usr.bin/fetch/file.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+
+#include "fetch.h"
+
+static int file_retrieve(struct fetch_state *fs);
+static int file_close(struct fetch_state *fs);
+static int file_parse(struct fetch_state *fs, const char *uri);
+
+struct uri_scheme file_scheme =
+ { "file", file_parse, 0, 0, 0 };
+
+/*
+ * Again, we slightly misinterpret the slash after the hostname as
+ * being the start of the pathname rather than merely a separator.
+ */
+static int
+file_parse(struct fetch_state *fs, const char *uri)
+{
+ const char *p;
+
+ p = uri + 5; /* skip past `file:' */
+ if (p[0] == '/' && p[1] == '/') {
+ /* skip past `//localhost', if any */
+ p += 2;
+ while (*p && *p != '/')
+ p++;
+ }
+
+ if (p[0] != '/') {
+ warnx("`%s': expected absolute pathname in `file' URL", uri);
+ return EX_USAGE;
+ }
+
+ fs->fs_proto = percent_decode(p);
+ /* guaranteed to succeed because of above test */
+ p = strrchr(fs->fs_proto, '/');
+ if (fs->fs_outputfile == 0) /* only set if not overridden by user */
+ fs->fs_outputfile = p + 1;
+ fs->fs_retrieve = file_retrieve;
+ fs->fs_close = file_close;
+ return 0;
+}
+
+static int
+file_close(struct fetch_state *fs)
+{
+ free(fs->fs_proto);
+ fs->fs_proto = 0;
+ fs->fs_outputfile = 0;
+ fs->fs_status = "free";
+ return 0;
+}
+
+static int
+file_retrieve(struct fetch_state *fs)
+{
+ /* XXX - this seems bogus to me! */
+ if (access(fs->fs_outputfile, F_OK) == 0) {
+ errno = EEXIST;
+ warn("%s", fs->fs_outputfile);
+ return EX_USAGE;
+ }
+
+ if (fs->fs_linkfile) {
+ fs->fs_status = "symlink";
+ if (symlink(fs->fs_proto, fs->fs_outputfile) == -1) {
+ warn("symlink");
+ return EX_OSERR;
+ }
+ fs->fs_status = "done";
+ } else {
+ pid_t pid;
+ int status;
+
+ fflush(stderr);
+ pid = fork();
+ if (pid < 0) {
+ warn("fork");
+ return EX_TEMPFAIL;
+ } else if (pid == 0) {
+ execl(PATH_CP, "cp", "-p", fs->fs_proto,
+ fs->fs_outputfile, (char *)0);
+ warn("execl: " PATH_CP);
+ fflush(stderr);
+ _exit(EX_OSERR);
+ } else {
+ fs->fs_status = "copying";
+ if (waitpid(pid, &status, 0) < 0) {
+ warn("waitpid(%ld)", (long)pid);
+ return EX_OSERR;
+ }
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ if (WIFSIGNALED(status))
+ warn(PATH_CP " exited on signal: %s",
+ sys_signame[WTERMSIG(status)]);
+ return EX_OSERR;
+ }
+ }
+ return 0;
+}
+
diff --git a/usr.bin/fetch/ftp.c b/usr.bin/fetch/ftp.c
new file mode 100644
index 0000000..457e43d
--- /dev/null
+++ b/usr.bin/fetch/ftp.c
@@ -0,0 +1,427 @@
+/*-
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ftp.c,v 1.6 1997/03/11 15:13:28 jmg Exp $
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <ftpio.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "fetch.h"
+
+struct ftp_state {
+ char *ftp_hostname;
+ char *ftp_user;
+ char *ftp_password;
+ char *ftp_remote_file;
+ unsigned ftp_port;
+};
+
+static int ftp_close(struct fetch_state *fs);
+static int ftp_retrieve(struct fetch_state *fs);
+static int ftp_parse(struct fetch_state *fs, const char *uri);
+static int ftp_proxy_parse(struct fetch_state *fs, const char *uri);
+
+struct uri_scheme ftp_scheme =
+ { "ftp", ftp_parse, ftp_proxy_parse, "FTP_PROXY", "ftp,http" };
+
+static int
+ftp_parse(struct fetch_state *fs, const char *uri)
+{
+ const char *p, *slash, *q;
+ char *hostname, *atsign, *colon;
+ unsigned port;
+ struct ftp_state *ftps;
+
+ p = uri + 4;
+ port = 0;
+
+ if (p[0] != '/' || p[1] != '/') {
+ warnx("`%s': invalid `ftp' URL", uri);
+ return EX_USAGE;
+ }
+
+ p += 2;
+ slash = strchr(p, '/');
+ if (slash == 0) {
+ warnx("`%s': malformed `ftp' URL", uri);
+ return EX_USAGE;
+ }
+ hostname = alloca(slash - p + 1);
+ hostname[0] = '\0';
+ strncat(hostname, p, slash - p);
+
+ if ((atsign = strrchr(hostname, '@')) == 0)
+ q = hostname;
+ else
+ q = atsign + 1;
+
+ if ((colon = strchr(q, ':')) != 0)
+ *colon = '\0';
+
+ if (colon && *(colon + 1)) {
+ unsigned long ul;
+ char *ep;
+
+ errno = 0;
+ ul = strtoul(colon + 1, &ep, 10);
+ if (*ep || errno != 0 || ul < 1 || ul > 65534) {
+ if (errno)
+ warn("`%s': invalid port in URL", uri);
+ else
+ warnx("`%s': invalid port in URL", uri);
+ return EX_USAGE;
+ }
+
+ port = ul;
+ } else {
+ port = 21;
+ }
+
+ p = slash + 1;
+
+ ftps = safe_malloc(sizeof *ftps);
+ ftps->ftp_password = 0;
+ ftps->ftp_user = 0;
+
+ /*
+ * Now, we have a copy of the hostname in hostname, the specified port
+ * (or the default value) in port, and p points to the filename part
+ * of the URI. We just need to check for a user in the hostname,
+ * and then save all the bits in our state.
+ */
+ if (atsign) {
+ if (atsign[1] == '\0') {
+ warnx("`%s': malformed `ftp' hostname", hostname);
+ free(ftps);
+ return EX_USAGE;
+ }
+
+ *atsign = '\0';
+ if ((colon = strchr(hostname, ':')) != 0)
+ *colon = '\0';
+ if (hostname[0] == '\0') {
+ warnx("`%s': malformed `ftp' user", atsign + 1);
+ free(ftps);
+ return EX_USAGE;
+ }
+ if (colon != 0)
+ ftps->ftp_password = percent_decode(colon + 1);
+ ftps->ftp_user = percent_decode(hostname);
+ ftps->ftp_hostname = safe_strdup(atsign + 1);
+ } else
+ ftps->ftp_hostname = safe_strdup(hostname);
+ ftps->ftp_port = port;
+
+ p = ftps->ftp_remote_file = percent_decode(p);
+ /* now p is the decoded version */
+
+ if (fs->fs_outputfile == 0) {
+ slash = strrchr(p, '/');
+ fs->fs_outputfile = slash ? slash + 1 : p;
+ }
+
+ if (ftps->ftp_password == 0)
+ ftps->ftp_password = getenv("FTP_PASSWORD");
+ if (ftps->ftp_password != 0) {
+ ftps->ftp_password = safe_strdup(ftps->ftp_password);
+ } else {
+ char *pw;
+ const char *logname;
+ char localhost[MAXHOSTNAMELEN];
+
+ logname = getlogin();
+ if (logname == 0)
+ logname = "root";
+ gethostname(localhost, sizeof localhost);
+ pw = safe_malloc(strlen(logname) + 1 + strlen(localhost) + 1);
+ strcpy(pw, logname);
+ strcat(pw, "@");
+ strcat(pw, localhost);
+ ftps->ftp_password = pw;
+ setenv("FTP_PASSWORD", pw, 0); /* cache the result */
+ }
+
+ if (ftps->ftp_user == 0)
+ ftps->ftp_user = getenv("FTP_LOGIN");
+ if (ftps->ftp_user != 0)
+ ftps->ftp_user = safe_strdup(ftps->ftp_user);
+
+ fs->fs_proto = ftps;
+ fs->fs_close = ftp_close;
+ fs->fs_retrieve = ftp_retrieve;
+ return 0;
+}
+
+/*
+ * The only URIs we can handle in the FTP proxy are FTP URLs.
+ * This makes it possible to take a few short cuts.
+ */
+static int
+ftp_proxy_parse(struct fetch_state *fs, const char *uri)
+{
+ int rv;
+ char *hostname;
+ char *port;
+ const char *user;
+ char *newuser;
+ unsigned portno;
+ struct ftp_state *ftps;
+
+ hostname = getenv("FTP_PROXY");
+ port = strchr(hostname, ':');
+ if (port == 0) {
+ portno = 21;
+ } else {
+ unsigned long ul;
+ char *ep;
+
+ /* All this to avoid modifying the environment. */
+ ep = alloca(strlen(hostname) + 1);
+ strcpy(ep, hostname);
+ port = ep + (port - hostname);
+ hostname = ep;
+
+ *port++ = '\0';
+ errno = 0;
+ ul = strtoul(port, &ep, 0);
+ if (*ep || !*port || errno != 0 || ul < 1 || ul > 65534) {
+ warnx("`%s': invalid port specification for FTP proxy",
+ port);
+ return EX_USAGE;
+ }
+ portno = ul;
+ }
+
+ /* ftp_parse() does most of the work; we can just fix things up */
+ rv = ftp_parse(fs, uri);
+ if (rv)
+ return rv;
+ /* Oops.. it got turned into a file: */
+ if (fs->fs_retrieve != ftp_retrieve) {
+ return 0;
+ }
+
+ ftps = fs->fs_proto;
+
+ user = ftps->ftp_user ? ftps->ftp_user : "anonymous";
+ /* user @ hostname [ @port ] \0 */
+ newuser = safe_malloc(strlen(user) + 1 + strlen(ftps->ftp_hostname)
+ + ((ftps->ftp_port != 21) ? 6 : 0) + 1);
+
+ strcpy(newuser, user);
+ strcat(newuser, "@");
+ strcat(newuser, ftps->ftp_hostname);
+ if (ftps->ftp_port != 21) {
+ char numbuf[6];
+
+ snprintf(numbuf, sizeof(numbuf), "%d", ftps->ftp_port);
+ numbuf[sizeof(numbuf)-1] = '\0';
+ strcat(newuser, "@");
+ strcat(newuser, numbuf);
+ }
+
+ ftps->ftp_port = portno;
+ free(ftps->ftp_hostname);
+ ftps->ftp_hostname = safe_strdup(hostname);
+ free(ftps->ftp_user);
+ ftps->ftp_user = newuser;
+ return 0;
+}
+
+static int
+ftp_close(struct fetch_state *fs)
+{
+ struct ftp_state *ftps = fs->fs_proto;
+
+ if (ftps->ftp_user)
+ free(ftps->ftp_user);
+ free(ftps->ftp_hostname);
+ free(ftps->ftp_password);
+ free(ftps->ftp_remote_file);
+ free(ftps);
+ fs->fs_proto = 0;
+ fs->fs_outputfile = 0;
+ return 0;
+}
+
+static int
+ftp_retrieve(struct fetch_state *fs)
+{
+ struct ftp_state *ftps = fs->fs_proto;
+ FILE *ftp, *remote, *local;
+ int status;
+ off_t size;
+ off_t seekloc, wehave;
+ time_t modtime;
+ size_t readresult, writeresult;
+
+ ftp = ftpLogin(ftps->ftp_hostname,
+ (char *)(ftps->ftp_user ? ftps->ftp_user : "anonymous"),
+ /* XXX ^^^^ bad API */
+ ftps->ftp_password, ftps->ftp_port, fs->fs_verbose > 1,
+ &status);
+ if (ftp == 0) {
+ warnx("%s: %s", ftps->ftp_hostname,
+ status ? ftpErrString(status) : hstrerror(h_errno));
+ return EX_IOERR;
+ }
+ ftpBinary(ftp);
+ ftpPassive(ftp, fs->fs_passive_mode);
+ size = ftpGetSize(ftp, ftps->ftp_remote_file);
+ modtime = ftpGetModtime(ftp, ftps->ftp_remote_file);
+ if (modtime <= 0) { /* xxx */
+ warnx("%s: cannot get remote modification time",
+ ftps->ftp_remote_file);
+ modtime = -1;
+ }
+ fs->fs_modtime = modtime;
+ seekloc = wehave = 0;
+ if (fs->fs_restart || fs->fs_mirror) {
+ struct stat stab;
+
+ if (fs->fs_outputfile[0] == '-'
+ && fs->fs_outputfile[1] == '\0')
+ status = fstat(STDOUT_FILENO, &stab);
+ else
+ status = stat(fs->fs_outputfile, &stab);
+ if (status < 0) {
+ stab.st_mtime = -1;
+ stab.st_size = 0;
+ }
+ if (status == 0 && !S_ISREG(stab.st_mode)) {
+ fs->fs_restart = 0;
+ fs->fs_mirror = 0;
+ }
+ if (fs->fs_mirror && stab.st_size == size
+ && modtime <= stab.st_mtime) {
+ fclose(ftp);
+ return 0;
+ }
+ if (fs->fs_restart) {
+ if (stab.st_size != 0 && stab.st_size < size)
+ seekloc = wehave = stab.st_size;
+ }
+ }
+
+ remote = ftpGet(ftp, ftps->ftp_remote_file, &seekloc);
+ if (remote == 0) {
+ if (ftpErrno(ftp)) {
+ warnx("ftp://%s/%s: FTP error:",
+ ftps->ftp_hostname, ftps->ftp_remote_file);
+ warnx("%s", ftpErrString(ftpErrno(ftp)));
+ fclose(ftp);
+ return EX_IOERR;
+ } else {
+ warn("ftpGet");
+ return EX_OSERR;
+ }
+ }
+
+ if (fs->fs_outputfile[0] == '-' && fs->fs_outputfile[1] == '\0')
+ local = fopen("/dev/stdout", wehave ? "a" : "w");
+ else
+ local = fopen(fs->fs_outputfile, wehave ? "a" : "w");
+ if (local == 0) {
+ warn("%s", fs->fs_outputfile);
+ fclose(remote);
+ fclose(ftp);
+ return EX_OSERR;
+ }
+
+ if (fs->fs_timeout) {
+ char buf[sizeof("18446744073709551616")]; /* 2**64 */
+ snprintf(buf, sizeof buf, "%d", fs->fs_timeout);
+ setenv("FTP_TIMEOUT", buf, 1);
+ } else {
+ char *env = getenv("FTP_TIMEOUT");
+ char *ep;
+ unsigned long ul;
+
+ if (env) {
+ errno = 0;
+ ul = strtoul(env, &ep, 0);
+ if (*env && *ep == '\0' && errno == 0 && ul <= INT_MAX)
+ fs->fs_timeout = ul;
+ else
+ warnx("`%s': invalid FTP timeout", env);
+ }
+ }
+
+ display(fs, size, wehave);
+ setup_sigalrm();
+
+ do {
+ char buf[BUFFER_SIZE];
+
+ alarm(fs->fs_timeout);
+ readresult = fread(buf, 1, sizeof buf, remote);
+ alarm(0);
+ if (readresult == 0)
+ break;
+ display(fs, size, readresult);
+ writeresult = fwrite(buf, 1, readresult, local);
+ } while (writeresult == readresult);
+ unsetup_sigalrm();
+
+ if (ferror(remote)) {
+ warn("reading remote file from %s", ftps->ftp_hostname);
+ fclose(local);
+ fclose(remote);
+ fclose(ftp);
+ rm(fs);
+ return EX_IOERR;
+ } else if(ferror(local)) {
+ warn("%s", fs->fs_outputfile);
+ fclose(local);
+ fclose(remote);
+ fclose(ftp);
+ rm(fs);
+ return EX_IOERR;
+ }
+
+ fclose(local);
+ fclose(remote);
+ fclose(ftp);
+ display(fs, size, -1);
+ adjmodtime(fs);
+ return 0;
+}
diff --git a/usr.bin/fetch/http.c b/usr.bin/fetch/http.c
new file mode 100644
index 0000000..fa445e0
--- /dev/null
+++ b/usr.bin/fetch/http.c
@@ -0,0 +1,1605 @@
+/*-
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: http.c,v 1.5 1997/03/05 18:57:16 fenner Exp $
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <md5.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "fetch.h"
+
+struct http_state {
+ char *http_hostname;
+ char *http_remote_request;
+ char *http_decoded_file;
+ char *http_host_header;
+ char *http_authentication;
+ char *http_proxy_authentication;
+ unsigned http_port;
+ int http_redirected;
+};
+
+struct http_auth {
+ TAILQ_ENTRY(http_auth) ha_link;
+ char *ha_scheme;
+ char *ha_realm;
+ char *ha_params;
+ const struct http_auth_method *ha_ham;
+};
+TAILQ_HEAD(http_auth_head, http_auth);
+
+static int http_parse(struct fetch_state *fs, const char *uri);
+static int http_proxy_parse(struct fetch_state *fs, const char *uri);
+static int http_close(struct fetch_state *fs);
+static int http_retrieve(struct fetch_state *fs);
+static int basic_doauth(struct fetch_state *fs, struct http_auth *ha, int prx);
+
+struct uri_scheme http_scheme =
+ { "http", http_parse, http_proxy_parse, "HTTP_PROXY", "http" };
+
+struct http_auth_head http_auth, http_proxy_auth;
+
+struct http_auth_method {
+ const char *ham_scheme;
+ int (*ham_doauth)(struct fetch_state *, struct http_auth *, int);
+} http_auth_methods[] = {
+ { "basic", basic_doauth },
+ { 0, 0 }
+};
+
+/* We are only concerned with headers we might receive. */
+enum http_header {
+ ht_accept_ranges, ht_age, ht_allow, ht_cache_control, ht_connection,
+ ht_content_base, ht_content_encoding, ht_content_language,
+ ht_content_length, ht_content_location, ht_content_md5,
+ ht_content_range, ht_content_type, ht_date, ht_etag, ht_expires,
+ ht_last_modified, ht_location, ht_pragma, ht_proxy_authenticate,
+ ht_public, ht_retry_after, ht_server, ht_transfer_encoding,
+ ht_upgrade, ht_vary, ht_via, ht_www_authenticate, ht_warning,
+ /* unusual cases */
+ ht_syntax_error, ht_unknown, ht_end_of_header
+};
+
+static char *format_http_date(time_t when);
+static char *format_http_user_agent(void);
+static enum http_header http_parse_header(char *line, char **valuep);
+static int check_md5(FILE *fp, char *base64ofmd5);
+static int http_first_line(const char *line);
+static int parse_http_content_range(char *orig, off_t *first, off_t *total);
+static int process_http_auth(struct fetch_state *fs, char *hdr, int autherr);
+static struct http_auth *find_http_auth(struct http_auth_head *list,
+ const char *scheme, const char *realm);
+static time_t parse_http_date(char *datestring);
+static void setup_http_auth(void);
+
+static int
+http_parse(struct fetch_state *fs, const char *uri)
+{
+ const char *p, *colon, *slash, *ques, *q;
+ char *hostname, *hosthdr, *trimmed_name;
+ unsigned port;
+ struct http_state *https;
+
+ p = uri + 5;
+ port = 0;
+
+ if (p[0] != '/' || p[1] != '/') {
+ warnx("`%s': malformed `http' URL", uri);
+ return EX_USAGE;
+ }
+
+ p += 2;
+ colon = strchr(p, ':');
+ slash = strchr(p, '/');
+ if (colon && slash && colon < slash)
+ q = colon;
+ else
+ q = slash;
+ if (q == 0) {
+ warnx("`%s': malformed `http' URL", uri);
+ return EX_USAGE;
+ }
+ hostname = alloca(q - p + 1);
+ hostname[0] = '\0';
+ strncat(hostname, p, q - p);
+ p = slash;
+
+ if (colon && colon + 1 != slash) {
+ unsigned long ul;
+ char *ep;
+
+ errno = 0;
+ ul = strtoul(colon + 1, &ep, 10);
+ if (ep != slash || ep == colon + 1 || errno != 0
+ || ul < 1 || ul > 65534) {
+ warn("`%s': invalid port in URL", uri);
+ return EX_USAGE;
+ }
+
+ port = ul;
+ } else {
+ port = 80;
+ }
+
+ p = slash;
+
+ https = safe_malloc(sizeof *https);
+
+ /*
+ * Now, we have a copy of the hostname in hostname, the specified port
+ * (or the default value) in port, and p points to the filename part
+ * of the URI.
+ */
+ https->http_hostname = safe_strdup(hostname);
+ https->http_port = port;
+ hosthdr = alloca(sizeof("Host: :\r\n") + 5 + strlen(hostname));
+ sprintf(hosthdr, "Host: %s:%d\r\n", hostname, port);
+ https->http_host_header = safe_strdup(hosthdr);
+
+ /*
+ * NB: HTTP/1.1 servers MUST also accept a full URI.
+ * However, HTTP/1.0 servers will ONLY accept a trimmed URI.
+ */
+ https->http_remote_request = safe_strdup(p);
+ p++;
+ ques = strpbrk(p, "?#");
+ if (ques) {
+ trimmed_name = safe_strndup(p, ques - p);
+ } else {
+ trimmed_name = safe_strdup(p);
+ }
+ https->http_decoded_file = percent_decode(trimmed_name);
+ free(trimmed_name);
+ p = https->http_decoded_file;
+ /* now p is the decoded version, so we can extract the basename */
+
+ if (fs->fs_outputfile == 0) {
+ slash = strrchr(p, '/');
+ if (slash)
+ fs->fs_outputfile = slash + 1;
+ else
+ fs->fs_outputfile = p;
+ }
+ https->http_redirected = 0;
+ https->http_authentication = https->http_proxy_authentication = 0;
+
+ fs->fs_proto = https;
+ fs->fs_close = http_close;
+ fs->fs_retrieve = http_retrieve;
+ return 0;
+}
+
+/*
+ * An HTTP proxy works by accepting a complete URI in a GET request,
+ * retrieving that object, and then forwarding it back to us. Because
+ * it can conceivably handle any URI, we have to do a bit more work
+ * in the parsing of it.
+ */
+static int
+http_proxy_parse(struct fetch_state *fs, const char *uri)
+{
+ struct http_state *https;
+ const char *env, *slash, *ques;
+ char *file;
+ int rv;
+
+ https = safe_malloc(sizeof *https);
+ https->http_remote_request = safe_strdup(uri);
+
+ env = getenv("HTTP_PROXY");
+ rv = parse_host_port(env, &https->http_hostname, &https->http_port);
+ if (rv) {
+out:
+ free(https->http_remote_request);
+ free(https);
+ return rv;
+ }
+
+ if (strncmp(uri, "http://", 7) == 0) {
+ char *hosthdr;
+ slash = strchr(uri + 7, '/');
+ if (slash == 0) {
+ warnx("`%s': malformed `http' URL", uri);
+ rv = EX_USAGE;
+ free(https->http_hostname);
+ goto out;
+ }
+ ques = strpbrk(slash, "?#");
+ if (ques == 0)
+ file = safe_strdup(slash);
+ else
+ file = safe_strndup(slash, ques - slash);
+ hosthdr = alloca(sizeof("Host: \r\n") + slash - uri - 7);
+ strcpy(hosthdr, "Host: ");
+ strncat(hosthdr, uri + 7, slash - uri - 7);
+ strcat(hosthdr, "\r\n");
+ https->http_host_header = safe_strdup(hosthdr);
+ } else {
+ slash = uri;
+ while (*slash && *slash != ':')
+ slash++;
+ if (*slash)
+ slash++;
+ if (slash[0] == '/' && slash[1] == '/') {
+ slash += 2;
+ while (*slash && *slash != '/')
+ slash++;
+ }
+ file = safe_strdup(slash);
+ https->http_host_header = safe_strdup("");
+ }
+ https->http_decoded_file = percent_decode(file);
+ https->http_redirected = 0;
+ https->http_authentication = https->http_proxy_authentication = 0;
+ free(file);
+ if (fs->fs_outputfile == 0) {
+ slash = strrchr(https->http_decoded_file, '/');
+ /* NB: we are not guaranteed to find one... */
+ fs->fs_outputfile = slash ? slash + 1
+ : https->http_decoded_file;
+ }
+
+ fs->fs_proto = https;
+ fs->fs_close = http_close;
+ fs->fs_retrieve = http_retrieve;
+ return 0;
+}
+
+static int
+http_close(struct fetch_state *fs)
+{
+ struct http_state *https = fs->fs_proto;
+
+ free(https->http_hostname);
+ free(https->http_remote_request);
+ free(https->http_decoded_file);
+ free(https->http_host_header);
+ if (https->http_authentication)
+ free(https->http_authentication);
+ if (https->http_proxy_authentication)
+ free(https->http_proxy_authentication);
+ free(https);
+ fs->fs_outputfile = 0;
+ return 0;
+}
+
+static int
+nullclose(struct fetch_state *fs)
+{
+ return 0;
+}
+
+/*
+ * Process a redirection. This has a small memory leak.
+ */
+static int
+http_redirect(struct fetch_state *fs, char *new, int permanent)
+{
+ struct http_state *https = fs->fs_proto;
+ int num_redirects = https->http_redirected + 1;
+ char *out = safe_strdup(fs->fs_outputfile);
+ int rv;
+
+ if (num_redirects > 5) {
+ warnx("%s: HTTP redirection limit exceeded");
+ return EX_PROTOCOL;
+ }
+
+ free(https->http_hostname);
+ free(https->http_remote_request);
+ free(https->http_decoded_file);
+ free(https);
+ warnx("%s: resource has moved %s to `%s'", out,
+ permanent ? "permanently" : "temporarily", new);
+ rv = http_parse(fs, new);
+ if (rv != 0) {
+ fs->fs_close = nullclose; /* XXX rethink interface? */
+ return rv;
+ }
+ https = fs->fs_proto;
+ https->http_redirected = num_redirects;
+ /*
+ * This ensures that the output file name doesn't suddenly change
+ * under the user's feet. Unfortunately, this results in a small
+ * memory leak. I wish C had garbage collection...
+ */
+ fs->fs_outputfile = out;
+ rv = http_retrieve(fs);
+ return rv;
+}
+
+/*
+ * Read HTML-formatted data from remote and display it on stderr.
+ * This is extremely incomplete, as all it does is delete anything
+ * between angle brackets. However, this is usually good enough for
+ * error messages.
+ */
+static void
+html_display(FILE *remote)
+{
+ char *line;
+ int linelen;
+ int inbracket = 0;
+
+
+ while ((line = fgetln(remote, &linelen)) != 0) {
+ char *end = line + linelen;
+ char *p;
+ int content = 0;
+
+ for (p = line; p < end; p++) {
+ if (*p == '<' && !inbracket) {
+ fwrite(line, 1, (p - line),
+ stderr);
+ inbracket = 1;
+ }
+ if (!inbracket && !content &&
+ *p != '\n' && *p != '\r')
+ content = 1;
+ if (*p == '>' && inbracket) {
+ line = p + 1;
+ inbracket = 0;
+ }
+ }
+ if (content && line < end)
+ fwrite(line, 1, (end - line), stderr);
+ }
+}
+
+/*
+ * Get a file using HTTP. We will try to implement HTTP/1.1 eventually.
+ * This subroutine makes heavy use of the 4.4-Lite standard I/O library,
+ * in particular the `fgetln' which allows us to slurp an entire `line'
+ * (an arbitrary string of non-NUL characters ending in a newline) directly
+ * out of the stdio buffer. This makes interpreting the HTTP headers much
+ * easier, since they are all guaranteed to end in `\r\n' and we can just
+ * ignore the `\r'.
+ */
+static int
+http_retrieve(struct fetch_state *fs)
+{
+ struct http_state *https;
+ FILE *remote, *local;
+ int s;
+ struct sockaddr_in sin;
+ struct msghdr msg;
+#define NIOV 16 /* max is currently 14 */
+ struct iovec iov[NIOV];
+ int n, status;
+ const char *env;
+ int timo;
+ char *line, *new_location;
+ char *errstr = 0;
+ size_t linelen, readresult, writeresult;
+ off_t total_length, restart_from;
+ time_t last_modified, when_to_retry;
+ char *base64ofmd5;
+ static char buf[BUFFER_SIZE];
+ int to_stdout, restarting, redirection, retrying, autherror;
+ char rangebuf[sizeof("Range: bytes=18446744073709551616-\r\n")];
+
+ setup_http_auth();
+
+ https = fs->fs_proto;
+ to_stdout = (strcmp(fs->fs_outputfile, "-") == 0);
+ restarting = fs->fs_restart;
+ redirection = 0;
+ retrying = 0;
+ autherror = 0;
+
+ /*
+ * Figure out the timeout. Prefer the -T command-line value,
+ * otherwise the HTTP_TIMEOUT envar, or else don't time out at all.
+ */
+ if (fs->fs_timeout) {
+ timo = fs->fs_timeout;
+ } else if ((env = getenv("HTTP_TIMEOUT")) != 0) {
+ char *ep;
+ unsigned long ul;
+
+ errno = 0;
+ ul = strtoul(env, &ep, 0);
+ if (*ep != '\0' || *env == '\0' || errno != 0
+ || ul > INT_MAX) {
+ warnx("`%s': invalid timeout", env);
+ return EX_USAGE;
+ }
+ timo = ul;
+ } else {
+ timo = 0;
+ }
+
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_port = htons(https->http_port);
+
+ fs->fs_status = "looking up hostname";
+ if (inet_aton(https->http_hostname, &sin.sin_addr) == 0) {
+ struct hostent *hp;
+
+ /* XXX - do timeouts for name resolution? */
+ hp = gethostbyname2(https->http_hostname, AF_INET);
+ if (hp == 0) {
+ warnx("`%s': cannot resolve: %s", https->http_hostname,
+ hstrerror(h_errno));
+ return EX_NOHOST;
+ }
+ memcpy(&sin.sin_addr, hp->h_addr_list[0], sizeof sin.sin_addr);
+ }
+
+ fs->fs_status = "creating request message";
+ msg.msg_name = (caddr_t)&sin;
+ msg.msg_namelen = sizeof sin;
+ msg.msg_iov = iov;
+ n = 0;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_EOF;
+
+#define addstr(Iov, N, Str) \
+ do { \
+ Iov[N].iov_base = (void *)Str; \
+ Iov[N].iov_len = strlen(Iov[n].iov_base); \
+ N++; \
+ } while(0)
+
+retry:
+ addstr(iov, n, "GET ");
+ addstr(iov, n, https->http_remote_request);
+ addstr(iov, n, " HTTP/1.1\r\n");
+ /*
+ * The choice of HTTP/1.1 may be a bit controversial. The
+ * specification says that implementations which are not at
+ * least conditionally compliant MUST NOT call themselves
+ * HTTP/1.1. We choose not to comply with that requirement.
+ * (Eventually we will support the full HTTP/1.1, at which
+ * time this comment will not apply. But it's amusing how
+ * specifications attempt to define behavior for implementations
+ * which aren't obeying the spec in the first place...)
+ */
+ addstr(iov, n, format_http_user_agent());
+ /* do content negotiation here */
+ addstr(iov, n, "Accept: */*\r\n");
+ addstr(iov, n, https->http_host_header);
+ addstr(iov, n, "Connection: close\r\n");
+ if (https->http_proxy_authentication)
+ addstr(iov, n, https->http_proxy_authentication);
+ if (https->http_authentication)
+ addstr(iov, n, https->http_authentication);
+ if (fs->fs_mirror) {
+ struct stat stab;
+
+ errno = 0;
+ if (((!to_stdout && stat(fs->fs_outputfile, &stab) == 0)
+ || (to_stdout && fstat(STDOUT_FILENO, &stab) == 0))
+ && S_ISREG(stab.st_mode)) {
+ addstr(iov, n, "If-Modified-Since: ");
+ addstr(iov, n, format_http_date(stab.st_mtime));
+ addstr(iov, n, "\r\n");
+ } else if (errno != 0) {
+ warn("%s: cannot mirror; will retrieve anew",
+ fs->fs_outputfile);
+ }
+ }
+ if (restarting) {
+ struct stat stab;
+
+ errno = 0;
+ if (((!to_stdout && stat(fs->fs_outputfile, &stab) == 0)
+ || (to_stdout && fstat(STDOUT_FILENO, &stab) == 0))
+ && S_ISREG(stab.st_mode)) {
+ addstr(iov, n, "If-Range: ");
+ addstr(iov, n, format_http_date(stab.st_mtime));
+ addstr(iov, n, "\r\n");
+ sprintf(rangebuf, "Range: bytes=%qd-\r\n",
+ (quad_t)stab.st_size);
+ addstr(iov, n, rangebuf);
+ } else if (errno != 0) {
+ warn("%s: cannot restart; will retrieve anew",
+ fs->fs_outputfile);
+ restarting = 0;
+ } else {
+ warnx("%s: cannot restart; will retrieve anew",
+ fs->fs_outputfile);
+ restarting = 0;
+ }
+ }
+ addstr(iov, n, "\r\n");
+ msg.msg_iovlen = n;
+
+ if (n >= NIOV)
+ err(EX_SOFTWARE, "request vector length exceeded: %d", n);
+
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ warn("socket");
+ return EX_OSERR;
+ }
+
+ remote = fdopen(s, "r");
+ if (remote == 0) {
+ warn("fdopen");
+ close(s);
+ return EX_OSERR;
+ }
+
+ fs->fs_status = "sending request message";
+ setup_sigalrm();
+ alarm(timo);
+ if (sendmsg(s, &msg, MSG_EOF) < 0) {
+ warn("sendmsg: %s", https->http_hostname);
+ fclose(remote);
+ return EX_OSERR;
+ }
+
+got100reply:
+ fs->fs_status = "reading reply status";
+ alarm(timo);
+ line = fgetln(remote, &linelen);
+ alarm(0);
+ if (line == 0) {
+ if (ferror(remote)) {
+ warn("reading reply from %s", https->http_hostname);
+ fclose(remote);
+ unsetup_sigalrm();
+ return EX_OSERR;
+ } else {
+ warnx("empty reply from %s", https->http_hostname);
+ fclose(remote);
+ unsetup_sigalrm();
+ return EX_PROTOCOL;
+ }
+ }
+ /*
+ * If the other end is HTTP 0.9, then we just suck their
+ * response over; can't do anything fancy. We assume that
+ * the file is a text file, so it is safe to use fgetln()
+ * to suck the entire file. (It had better be, since
+ * we used it to grab the first line.)
+ */
+ if (linelen < 5 || strncasecmp(line, "http", 4) != 0) {
+ if (to_stdout)
+ local = fopen("/dev/stdout", "w");
+ else
+ local = fopen(fs->fs_outputfile, "w");
+ if (local == 0) {
+ warn("%s: fopen", fs->fs_outputfile);
+ fclose(remote);
+ unsetup_sigalrm();
+ return EX_OSERR;
+ }
+ fs->fs_status = "retrieving from HTTP/0.9 server";
+ display(fs, -1, 0);
+
+ do {
+ writeresult = fwrite(line, 1, linelen, local);
+ display(fs, -1, writeresult);
+ if (writeresult != linelen)
+ break;
+ alarm(timo);
+ line = fgetln(remote, &linelen);
+ alarm(0);
+ } while(line != 0);
+ unsetup_sigalrm();
+
+ if (ferror(local)) {
+ warn("%s", fs->fs_outputfile);
+ fclose(local);
+ fclose(remote);
+ rm(fs);
+ return EX_OSERR;
+ } else if(ferror(remote)) {
+ warn("%s", https->http_hostname);
+ fclose(local);
+ fclose(remote);
+ rm(fs);
+ return EX_OSERR;
+ }
+ fclose(local);
+ fclose(remote);
+ display(fs, -1, -1);
+ return 0;
+ }
+ /*
+ * OK. The other end is doing HTTP 1.0 at the very least.
+ * This means that some of the fancy stuff is at least possible.
+ */
+ line[linelen - 1] = '\0'; /* turn line into a string */
+ status = http_first_line(line);
+
+ /* In the future, we might handle redirection and other responses. */
+ switch(status) {
+ case 100: /* Continue */
+ goto got100reply;
+ case 200: /* Here come results */
+ case 203: /* Non-Authoritative Information */
+ restarting = 0;
+ break;
+ case 206: /* Here come partial results */
+ /* can only happen when restarting */
+ break;
+ case 301: /* Resource has moved permanently */
+ if (!fs->fs_auto_retry)
+ errstr = safe_strdup(line);
+ else
+ redirection = 301;
+ break;
+ case 302: /* Resource has moved temporarily */
+ /*
+ * We don't test fs->fs_auto_retry here so that this
+ * sort of redirection is transparent to the user.
+ */
+ redirection = 302;
+ break;
+ case 304: /* Object is unmodified */
+ if (fs->fs_mirror) {
+ fclose(remote);
+ unsetup_sigalrm();
+ return 0;
+ }
+ errstr = safe_strdup(line);
+ break;
+ case 401: /* Unauthorized */
+ if (https->http_authentication)
+ errstr = safe_strdup(line);
+ else
+ autherror = 401;
+ break;
+ case 407: /* Proxy Authentication Required */
+ if (https->http_proxy_authentication)
+ errstr = safe_strdup(line);
+ else
+ autherror = 407;
+ break;
+ case 503: /* Service Unavailable */
+ if (!fs->fs_auto_retry)
+ errstr = safe_strdup(line);
+ else
+ retrying = 503;
+ break;
+
+ default:
+ errstr = safe_strdup(line);
+ break;
+ }
+
+ total_length = -1; /* -1 means ``don't know'' */
+ last_modified = when_to_retry = -1;
+ base64ofmd5 = 0;
+ new_location = 0;
+ restart_from = 0;
+ fs->fs_status = "parsing reply headers";
+
+ while((line = fgetln(remote, &linelen)) != 0) {
+ char *value, *ep;
+ enum http_header header;
+ unsigned long ul;
+
+ line[linelen - 1] = '\0';
+ header = http_parse_header(line, &value);
+
+ if (header == ht_end_of_header)
+ break;
+
+ switch(header) {
+ case ht_content_length:
+ errno = 0;
+ ul = strtoul(value, &ep, 10);
+ if (errno != 0 || *ep)
+ warnx("invalid Content-Length: `%s'", value);
+ if (!restarting)
+ total_length = ul;
+ break;
+
+ case ht_last_modified:
+ last_modified = parse_http_date(value);
+ if (last_modified == -1 && fs->fs_verbose > 0)
+ warnx("invalid Last-Modified: `%s'", value);
+ break;
+
+ case ht_content_md5:
+ base64ofmd5 = safe_strdup(value);
+ break;
+
+ case ht_content_range:
+ if (!restarting) /* XXX protocol error */
+ break;
+
+ /* NB: we might have to restart from farther back
+ than we asked. */
+ status = parse_http_content_range(value, &restart_from,
+ &total_length);
+ /* If we couldn't understand the reply, get the whole
+ thing. */
+ if (status) {
+ restarting = 0;
+doretry:
+ fclose(remote);
+ if (base64ofmd5)
+ free(base64ofmd5);
+ if (new_location)
+ free(new_location);
+ restart_from = 0;
+ n = 0;
+ goto retry;
+ }
+ break;
+
+ case ht_location:
+ if (redirection) {
+ char *s = value;
+ while (*s && !isspace(*s))
+ s++;
+ new_location = safe_strndup(value, s - value);
+ }
+ break;
+
+ case ht_transfer_encoding:
+ warnx("%s: %s specified a Transfer-Encoding: %s",
+ fs->fs_outputfile, https->http_hostname,
+ value);
+ warnx("%s: output file may be uninterpretable",
+ fs->fs_outputfile);
+ break;
+
+ case ht_retry_after:
+ if (!retrying)
+ break;
+
+ errno = 0;
+ ul = strtoul(value, &ep, 10);
+ if (errno != 0 || (*ep && !isspace(*ep))) {
+ time_t when;
+ when = parse_http_date(value);
+ if (when == -1)
+ break;
+ when_to_retry = when;
+ } else {
+ when_to_retry = time(0) + ul;
+ }
+ break;
+
+ case ht_www_authenticate:
+ if (autherror != 401)
+ break;
+
+ status = process_http_auth(fs, value, autherror);
+ if (status != 0)
+ goto cantauth;
+ break;
+
+ case ht_proxy_authenticate:
+ if (autherror != 407)
+ break;
+ status = process_http_auth(fs, value, autherror);
+ if (status != 0)
+ goto cantauth;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (autherror == 401 && https->http_authentication)
+ goto doretry;
+ if (autherror == 407 && https->http_proxy_authentication)
+ goto doretry;
+ if (autherror) {
+ goto spewerror;
+ }
+
+ if (retrying) {
+ int howlong;
+
+ if (when_to_retry == -1) {
+ errstr = safe_strdup("HTTP/1.1 503 Service Unavailable");
+ goto spewerror;
+ }
+ howlong = when_to_retry - time(0);
+ if (howlong < 30)
+ howlong = 30;
+
+ warnx("%s: service unavailable; retrying in %d seconds",
+ https->http_hostname, howlong);
+ fs->fs_status = "waiting to retry";
+ sleep(howlong);
+ goto doretry;
+ }
+
+ if (errstr != 0) {
+spewerror:
+ warnx("%s: %s: HTTP server returned error code %d",
+ fs->fs_outputfile, https->http_hostname, status);
+ if (fs->fs_verbose > 1) {
+ fputs(errstr, stderr);
+ fputc('\n', stderr);
+ html_display(remote);
+ }
+ free(errstr);
+ fclose(remote);
+ unsetup_sigalrm();
+ return EX_UNAVAILABLE;
+ }
+
+ if (redirection && new_location) {
+ fclose(remote);
+ if (base64ofmd5)
+ free(base64ofmd5);
+ fs->fs_status = "processing redirection";
+ status = http_redirect(fs, new_location, redirection == 301);
+ free(new_location);
+ return status;
+ } else if (redirection) {
+ warnx("%s: redirection but no new location",
+ fs->fs_outputfile);
+ fclose(remote);
+ if (base64ofmd5)
+ free(base64ofmd5);
+ return EX_PROTOCOL;
+ }
+
+ fs->fs_status = "retrieving file from HTTP/1.x server";
+
+ /*
+ * OK, if we got here, then we have finished parsing the header
+ * and have read the `\r\n' line which denotes the end of same.
+ * We may or may not have a good idea of the length of the file
+ * or its modtime. At this point we will have to deal with
+ * any special byte-range, content-negotiation, redirection,
+ * or authentication, and probably jump back up to the top,
+ * once we implement those features. So, all we have left to
+ * do is open up the output file and copy data from input to
+ * output until EOF.
+ */
+ if (to_stdout)
+ local = fopen("/dev/stdout", restarting ? "a" : "w");
+ else
+ local = fopen(fs->fs_outputfile, restarting ? "a" : "w");
+ if (local == 0) {
+ warn("%s: fopen", fs->fs_outputfile);
+ fclose(remote);
+ unsetup_sigalrm();
+ return EX_OSERR;
+ }
+
+ fs->fs_modtime = last_modified;
+ fseek(local, restart_from, SEEK_SET); /* XXX truncation off_t->long */
+ display(fs, total_length, restart_from); /* XXX truncation */
+
+ /*
+ * Eventually this loop will be separated out as http_suck(), and
+ * there will be a separate http_suck_chunked() to deal with that
+ * Transfer-Encoding.
+ */
+ do {
+ alarm(timo);
+ readresult = fread(buf, 1, sizeof buf, remote);
+ alarm(0);
+
+ if (readresult == 0)
+ break;
+ display(fs, total_length, readresult);
+
+ writeresult = fwrite(buf, 1, readresult, local);
+ } while (writeresult == readresult);
+
+ status = errno; /* save errno for warn(), below, if needed */
+ display(fs, total_length, -1); /* do here in case we have to warn */
+ errno = status;
+
+ if (ferror(remote)) {
+ warn("reading remote file from %s", https->http_hostname);
+ status = EX_OSERR;
+ } else if(ferror(local)) {
+ warn("`%s': fwrite", fs->fs_outputfile);
+ status = EX_OSERR;
+ } else {
+ status = 0;
+ }
+ if (base64ofmd5) {
+ /*
+ * Ack. When restarting, the MD5 only covers the parts
+ * we are getting, not the whole thing.
+ */
+ fseek(local, restart_from, SEEK_SET);
+ fs->fs_status = "computing MD5 message digest";
+ status = check_md5(local, base64ofmd5);
+ free(base64ofmd5);
+ }
+
+ fclose(local);
+out:
+ unsetup_sigalrm();
+ fclose(remote);
+
+ if (status != 0)
+ rm(fs);
+ else
+ adjmodtime(fs);
+
+ return status;
+#undef addstr
+
+cantauth:
+ warnx("%s: cannot authenticate with %s %s",
+ fs->fs_outputfile,
+ (autherror == 401) ? "server" : "proxy",
+ https->http_hostname);
+ status = EX_NOPERM;
+ goto out;
+}
+
+/*
+ * The format of the response line for an HTTP request is:
+ * HTTP/V.vv{WS}999{WS}Explanatory text for humans to read\r\n
+ * Old pre-HTTP/1.0 servers can return
+ * HTTP{WS}999{WS}Explanatory text for humans to read\r\n
+ * Where {WS} represents whitespace (spaces and/or tabs) and 999
+ * is a machine-interprable result code. We return the integer value
+ * of that result code, or the impossible value `0' if we are unable to
+ * parse the result.
+ */
+static int
+http_first_line(const char *line)
+{
+ char *ep;
+ unsigned long ul;
+
+ if (strncasecmp(line, "http", 4) != 0)
+ return 0;
+
+ line += 4;
+ while (*line && !isspace(*line)) /* skip non-whitespace */
+ line++;
+ while (*line && isspace(*line)) /* skip first whitespace */
+ line++;
+
+ errno = 0;
+ ul = strtoul(line, &ep, 10);
+ if (errno != 0 || ul > 999 || ul < 100 || !isspace(*ep))
+ return 0;
+ return ul;
+}
+
+/*
+ * The format of a header line for an HTTP request is:
+ * Header-Name: header-value (with comments in parens)\r\n
+ * This would be a nice application for gperf(1), except that the
+ * names are case-insensitive and gperf can't handle that.
+ */
+static enum http_header
+http_parse_header(char *line, char **valuep)
+{
+ char *colon, *value;
+
+ if (*line == '\0' /* protocol error! */
+ || (line[0] == '\r' && line[1] == '\0'))
+ return ht_end_of_header;
+
+ colon = strchr(line, ':');
+ if (colon == 0)
+ return ht_syntax_error;
+ *colon = '\0';
+
+ for (value = colon + 1; *value && isspace(*value); value++)
+ ; /* do nothing */
+
+ /* Trim trailing whitespace (including \r). */
+ *valuep = value;
+ value += strlen(value) - 1;
+ while (value > *valuep && isspace(*value))
+ value--;
+ *++value = '\0';
+
+#define cmp(name, num) do { if (!strcasecmp(line, name)) return num; } while(0)
+ cmp("Accept-Ranges", ht_accept_ranges);
+ cmp("Age", ht_age);
+ cmp("Allow", ht_allow);
+ cmp("Cache-Control", ht_cache_control);
+ cmp("Connection", ht_connection);
+ cmp("Content-Base", ht_content_base);
+ cmp("Content-Encoding", ht_content_encoding);
+ cmp("Content-Language", ht_content_language);
+ cmp("Content-Length", ht_content_length);
+ cmp("Content-Location", ht_content_location);
+ cmp("Content-MD5", ht_content_md5);
+ cmp("Content-Range", ht_content_range);
+ cmp("Content-Type", ht_content_type);
+ cmp("Date", ht_date);
+ cmp("ETag", ht_etag);
+ cmp("Expires", ht_expires);
+ cmp("Last-Modified", ht_last_modified);
+ cmp("Location", ht_location);
+ cmp("Pragma", ht_pragma);
+ cmp("Proxy-Authenticate", ht_proxy_authenticate);
+ cmp("Public", ht_public);
+ cmp("Retry-After", ht_retry_after);
+ cmp("Server", ht_server);
+ cmp("Transfer-Encoding", ht_transfer_encoding);
+ cmp("Upgrade", ht_upgrade);
+ cmp("Vary", ht_vary);
+ cmp("Via", ht_via);
+ cmp("WWW-Authenticate", ht_www_authenticate);
+ cmp("Warning", ht_warning);
+#undef cmp
+ return ht_unknown;
+}
+
+/*
+ * Compute the RSA Data Security, Inc., MD5 Message Digest of the file
+ * given in `fp', see if it matches the one given in base64 encoding by
+ * `base64ofmd5'. Warn and return an error if it doesn't.
+ */
+static int
+check_md5(FILE *fp, char *base64ofmd5) {
+ MD5_CTX ctx;
+ unsigned char digest[16];
+ char buf[512];
+ size_t len;
+ char *ourval;
+
+ MD5Init(&ctx);
+ while ((len = fread(buf, 1, sizeof buf, fp)) != 0) {
+ MD5Update(&ctx, buf, len);
+ }
+ MD5Final(digest, &ctx);
+ ourval = to_base64(digest, 16);
+ if (strcmp(ourval, base64ofmd5) != 0) {
+ warnx("MD5 digest mismatch: %s, should be %s", ourval,
+ base64ofmd5);
+ free(ourval);
+ return EX_DATAERR;
+ }
+ free(ourval);
+ return 0;
+}
+
+static const char *wkdays[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+static const char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec"
+};
+
+/*
+ * Interpret one of the three possible formats for an HTTP date.
+ * All of them are really bogus; HTTP should use either ISO 8601
+ * or NTP timestamps. We make some attempt to accept a subset of 8601
+ * format. The three standard formats are all fixed-length subsets of their
+ * respective standards (except 8601, which puts all of the stuff we
+ * care about up front).
+ */
+static time_t
+parse_http_date(char *string)
+{
+ static struct tm tm; /* get good initialization */
+ time_t rv;
+ const char *tz;
+ int i;
+
+ /* 8601 has the shortest minimum length */
+ if (strlen(string) < 15)
+ return -1;
+
+ if (isdigit(*string)) {
+ /* ISO 8601: 19970127T134551stuffwedon'tcareabout */
+ for (i = 0; i < 15; i++) {
+ if (i != 8 && !isdigit(string[i]))
+ break;
+ }
+ if (i < 15)
+ return -1;
+#define digit(x) (string[x] - '0')
+ tm.tm_year = (digit(0) * 1000
+ + digit(1) * 100
+ + digit(2) * 10
+ + digit(3)) - 1900;
+ tm.tm_mon = digit(4) * 10 + digit(5) - 1;
+ tm.tm_mday = digit(6) * 10 + digit(7);
+ if (string[8] != 'T' && string[8] != 't' && string[8] != ' ')
+ return -1;
+ tm.tm_hour = digit(9) * 10 + digit(10);
+ tm.tm_min = digit(11) * 10 + digit(12);
+ tm.tm_sec = digit(13) * 10 + digit(14);
+ /* We don't care about the rest of the stuff after the secs. */
+ } else if (string[3] == ',') {
+ /* Mon, 27 Jan 1997 14:24:35 stuffwedon'tcareabout */
+ if (strlen(string) < 25)
+ return -1;
+ string += 5; /* skip over day-of-week */
+ if (!(isdigit(string[0]) && isdigit(string[1])))
+ return -1;
+ tm.tm_mday = digit(0) * 10 + digit(1);
+ for (i = 0; i < 12; i++) {
+ if (strncasecmp(months[i], &string[3], 3) == 0)
+ break;
+ }
+ if (i >= 12)
+ return -1;
+ tm.tm_mon = i;
+
+ if (sscanf(&string[7], "%d %d:%d:%d", &i, &tm.tm_hour,
+ &tm.tm_min, &tm.tm_sec) != 4)
+ return -1;
+ tm.tm_year = i - 1900;
+
+ } else if (string[3] == ' ') {
+ /* Mon Jan 27 14:25:20 1997 */
+ if (strlen(string) < 25)
+ return -1;
+ string += 4;
+ for (i = 0; i < 12; i++) {
+ if (strncasecmp(string, months[i], 3) == 0)
+ break;
+ }
+ if (i >= 12)
+ return -1;
+ tm.tm_mon = i;
+ if (sscanf(&string[4], "%d %d:%d:%d %u", &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &i)
+ != 5)
+ return -1;
+ tm.tm_year = i - 1900;
+ } else {
+ /* Monday, 27-Jan-97 14:31:09 stuffwedon'tcareabout */
+ char *comma = strchr(string, ',');
+ char mname[4];
+
+ if (comma == 0)
+ return -1;
+ string = comma + 1;
+ if (strlen(string) < 19)
+ return -1;
+ string++;
+ mname[4] = '\0';
+ if (sscanf(string, "%d-%c%c%c-%d %d:%d:%d", &tm.tm_mday,
+ mname, mname + 1, mname + 2, &tm.tm_year,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 8)
+ return -1;
+ for (i = 0; i < 12; i++) {
+ if (strcasecmp(months[i], mname))
+ break;
+ }
+ if (i >= 12)
+ return -1;
+ tm.tm_mon = i;
+ }
+#undef digit
+
+ if (tm.tm_sec > 60 || tm.tm_min > 59 || tm.tm_hour > 23
+ || tm.tm_mday > 31 || tm.tm_mon > 11)
+ return -1;
+ if (tm.tm_sec < 0 || tm.tm_min < 0 || tm.tm_hour < 0
+ || tm.tm_mday < 0 || tm.tm_mon < 0 || tm.tm_year < 0)
+ return -1;
+
+ tz = getenv("TZ");
+ setenv("TZ", "UTC0", 1);
+ tzset();
+ rv = mktime(&tm);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ return rv;
+}
+
+static char *
+format_http_date(time_t when)
+{
+ struct tm *tm;
+ static char buf[30];
+
+ tm = gmtime(&when);
+ if (tm == 0)
+ return 0;
+#ifndef HTTP_DATE_ISO_8601
+ sprintf(buf, "%s, %02d %s %04d %02d:%02d:%02d GMT",
+ wkdays[tm->tm_wday], tm->tm_mday, months[tm->tm_mon],
+ tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
+#else /* ISO 8601 */
+ sprintf(buf, "%04d%02d%02dT%02d%02d%02d+0000",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+#endif
+ return buf;
+}
+
+static char *
+format_http_user_agent(void)
+{
+ static char buf[128];
+ static int inited;
+
+ if (!inited) {
+ int mib[2];
+ char ostype[128], osrelease[128], machine[128];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSTYPE;
+ len = sizeof ostype;
+ if (sysctl(mib, 2, ostype, &len, 0, 0) < 0) {
+ warn("sysctl");
+ ostype[0] = '\0';
+ }
+ mib[1] = KERN_OSRELEASE;
+ len = sizeof osrelease;
+ if (sysctl(mib, 2, osrelease, &len, 0, 0) < 0) {
+ warn("sysctl");
+ osrelease[0] = '\0';
+ }
+ mib[0] = CTL_HW;
+ mib[1] = HW_MACHINE;
+ len = sizeof machine;
+ if (sysctl(mib, 2, machine, &len, 0, 0) < 0) {
+ warn("sysctl");
+ machine[0] = '\0';
+ }
+
+ snprintf(buf, sizeof buf,
+ "User-Agent: " FETCH_VERSION " %s/%s (%s)\r\n",
+ ostype, osrelease, machine);
+ }
+ return buf;
+}
+
+/*
+ * Parse a Content-Range return header from the server. RFC 2066 defines
+ * this header to have the format:
+ * Content-Range: bytes 12345-67890/123456
+ * Since we always ask for the whole rest of the file, we consider it an
+ * error if the reply doesn't claim to give it to us.
+ */
+static int
+parse_http_content_range(char *orig, off_t *restart_from, off_t *total_length)
+{
+ u_quad_t first, last, total;
+ char *ep;
+
+ if (strncasecmp(orig, "bytes", 5) != 0) {
+ warnx("unknown Content-Range unit: `%s'", orig);
+ return EX_PROTOCOL;
+ }
+
+ orig += 5;
+ while (*orig && isspace(*orig))
+ orig++;
+
+ errno = 0;
+ first = strtouq(orig, &ep, 10);
+ if (errno != 0 || *ep != '-') {
+ warnx("invalid Content-Range: `%s'", orig);
+ return EX_PROTOCOL;
+ }
+ last = strtouq(ep + 1, &ep, 10);
+ if (errno != 0 || *ep != '/' || last < first) {
+ warnx("invalid Content-Range: `%s'", orig);
+ return EX_PROTOCOL;
+ }
+ total = strtouq(ep + 1, &ep, 10);
+ if (errno != 0 || !(*ep == '\0' || isspace(*ep))) {
+ warnx("invalid Content-Range: `%s'", orig);
+ return EX_PROTOCOL;
+ }
+
+ if (last + 1 != total) {
+ warnx("HTTP server did not return requested Content-Range");
+ return EX_PROTOCOL;
+ }
+
+ *restart_from = first;
+ *total_length = last;
+ return 0;
+}
+
+/*
+ * Do HTTP authentication. We only do ``basic'' right now, but
+ * MD5 ought to be fairly easy. The hard part is actually teasing
+ * apart the header, which is fairly badly designed (so what else is
+ * new?).
+ */
+static char *
+getauthparam(char *params, const char *name)
+{
+ char *rv;
+ enum state { normal, quoted } state;
+ while (*params) {
+ if (strncasecmp(params, name, strlen(name)) == 0
+ && params[strlen(name)] == '=')
+ break;
+ state = normal;
+ while (*params) {
+ if (state == normal && *params == ',')
+ break;
+ if (*params == '\"')
+ state = (state == quoted) ? normal : quoted;
+ if (*params == '\\' && params[1] != '\0')
+ params++;
+ params++;
+ }
+ }
+
+ if (*params == '\0')
+ return 0;
+ params += strlen(name) + 1;
+ rv = params;
+ state = normal;
+ while (*params) {
+ if (state == normal && *params == ',')
+ break;
+ if (*params == '\"')
+ state = (state == quoted) ? normal : quoted;
+ if (*params == '\\' && params[1] != '\0')
+ params++;
+ params++;
+ }
+ if (params[-1] == '\"')
+ params[-1] = '\0';
+ else
+ params[0] = '\0';
+
+ if (*rv == '\"')
+ rv++;
+ return rv;
+}
+
+static int
+process_http_auth(struct fetch_state *fs, char *hdr, int autherr)
+{
+ enum state { normal, quoted } state;
+ char *scheme, *params, *nscheme, *realm;
+ struct http_auth *ha;
+
+ do {
+ scheme = params = hdr;
+ /* Look for end of scheme name. */
+ while (*params && !isspace(*params))
+ params++;
+
+ if (*params == '\0')
+ return EX_PROTOCOL;
+
+ /* Null-terminate scheme and skip whitespace. */
+ while (*params && isspace(*params))
+ *params++ = '\0';
+
+ /* Semi-parse parameters to find their end. */
+ nscheme = params;
+ state = normal;
+ while (*nscheme) {
+ if (state == normal && isspace(*nscheme))
+ break;
+ if (*nscheme == '\"')
+ state = (state == quoted) ? normal : quoted;
+ if (*nscheme == '\\' && nscheme[1] != '\0')
+ nscheme++;
+ nscheme++;
+ }
+
+ /* Null-terminate parameters and skip whitespace. */
+ while (*nscheme && isspace(*nscheme))
+ *nscheme++ = '\0';
+
+ realm = getauthparam(params, "realm");
+ if (realm == 0) {
+ scheme = nscheme;
+ continue;
+ }
+
+ if (autherr == 401)
+ ha = find_http_auth(&http_auth, scheme, realm);
+ else
+ ha = find_http_auth(&http_proxy_auth, scheme, realm);
+
+ if (ha)
+ return ha->ha_ham->ham_doauth(fs, ha, autherr == 407);
+ } while (*scheme);
+ return EX_NOPERM;
+}
+
+static void
+parse_http_auth_env(const char *env, struct http_auth_head *ha_tqh)
+{
+ char *nenv, *p, *scheme, *realm, *params;
+ struct http_auth *ha;
+ struct http_auth_method *ham;
+
+ nenv = alloca(strlen(env) + 1);
+ strcpy(nenv, env);
+
+ while ((p = strsep(&nenv, " \t")) != 0) {
+ scheme = strsep(&p, ":");
+ if (scheme == 0 || *scheme == '\0')
+ continue;
+ realm = strsep(&p, ":");
+ if (realm == 0 || *realm == '\0')
+ continue;
+ params = (p && *p) ? p : 0;
+ for (ham = http_auth_methods; ham->ham_scheme; ham++) {
+ if (strcasecmp(scheme, ham->ham_scheme) == 0)
+ break;
+ }
+ if (ham == 0)
+ continue;
+ ha = safe_malloc(sizeof *ha);
+ ha->ha_scheme = safe_strdup(scheme);
+ ha->ha_realm = safe_strdup(realm);
+ ha->ha_params = params ? safe_strdup(params) : 0;
+ ha->ha_ham = ham;
+ TAILQ_INSERT_TAIL(ha_tqh, ha, ha_link);
+ }
+}
+
+/*
+ * Look up an authentication method. Automatically clone wildcards
+ * into fully-specified entries.
+ */
+static struct http_auth *
+find_http_auth(struct http_auth_head *tqh, const char *scm, const char *realm)
+{
+ struct http_auth *ha;
+
+ for (ha = tqh->tqh_first; ha; ha = ha->ha_link.tqe_next) {
+ if (strcasecmp(ha->ha_scheme, scm) == 0
+ && strcasecmp(ha->ha_realm, realm) == 0)
+ return ha;
+ }
+
+ for (ha = tqh->tqh_first; ha; ha = ha->ha_link.tqe_next) {
+ if (strcasecmp(ha->ha_scheme, scm) == 0
+ && strcmp(ha->ha_realm, "*") == 0)
+ break;
+ }
+ if (ha != 0) {
+ struct http_auth *ha2;
+
+ ha2 = safe_malloc(sizeof *ha2);
+ ha2->ha_scheme = safe_strdup(scm);
+ ha2->ha_realm = safe_strdup(realm);
+ ha2->ha_params = ha->ha_params ? safe_strdup(ha->ha_params) :0;
+ ha2->ha_ham = ha->ha_ham;
+ TAILQ_INSERT_TAIL(tqh, ha2, ha_link);
+ ha = ha2;
+ }
+
+ return ha;
+}
+
+static void
+setup_http_auth(void)
+{
+ const char *envar;
+ static int once;
+
+ if (once)
+ return;
+ once = 1;
+
+ TAILQ_INIT(&http_auth);
+ TAILQ_INIT(&http_proxy_auth);
+ envar = getenv("HTTP_AUTH");
+ if (envar)
+ parse_http_auth_env(envar, &http_auth);
+
+ envar = getenv("HTTP_PROXY_AUTH");
+ if (envar)
+ parse_http_auth_env(envar, &http_proxy_auth);
+}
+
+static int
+basic_doauth(struct fetch_state *fs, struct http_auth *ha, int isproxy)
+{
+ struct http_state *https = fs->fs_proto;
+ char *user;
+ char *pass;
+ char *enc;
+ char **hdr;
+ size_t userlen;
+ FILE *fp;
+
+ if (!isatty(0) &&
+ (ha->ha_params == 0 || strchr(ha->ha_params, ':') == 0))
+ return EX_NOPERM;
+
+ fp = fopen("/dev/tty", "r+");
+ if (fp == 0) {
+ warn("opening /dev/tty");
+ return EX_OSERR;
+ }
+ if (ha->ha_params == 0) {
+ fprintf(fp, "Enter `basic' user name for realm `%s': ",
+ ha->ha_realm);
+ fflush(fp);
+ user = fgetln(stdin, &userlen);
+ if (user == 0 || userlen < 1) { /* longer name? */
+ fclose(fp);
+ return EX_NOPERM;
+ }
+ if (user[userlen - 1] == '\n')
+ user[userlen - 1] = '\0';
+ else
+ user[userlen] = '\0';
+ user = safe_strdup(user);
+ pass = 0;
+ } else if ((pass = strchr(ha->ha_params, ':')) == 0) {
+ user = safe_strdup(ha->ha_params);
+ free(ha->ha_params);
+ }
+
+ if (pass == 0) {
+ pass = getpass("Password: ");
+ ha->ha_params = safe_malloc(strlen(user) + 2 + strlen(pass));
+ strcpy(ha->ha_params, user);
+ strcat(ha->ha_params, ":");
+ strcat(ha->ha_params, pass);
+ }
+
+ enc = to_base64(ha->ha_params, strlen(ha->ha_params));
+
+ hdr = isproxy ? &https->http_proxy_authentication
+ : &https->http_authentication;
+ if (*hdr)
+ free(*hdr);
+ *hdr = safe_malloc(sizeof("Proxy-Authorization: basic \r\n")
+ + strlen(enc));
+ if (isproxy)
+ strcpy(*hdr, "Proxy-Authorization");
+ else
+ strcpy(*hdr, "Authorization");
+ strcat(*hdr, ": Basic ");
+ strcat(*hdr, enc);
+ strcat(*hdr, "\r\n");
+ free(enc);
+ return 0;
+}
diff --git a/usr.bin/fetch/main.c b/usr.bin/fetch/main.c
new file mode 100644
index 0000000..999aff6
--- /dev/null
+++ b/usr.bin/fetch/main.c
@@ -0,0 +1,353 @@
+/*-
+ * Copyright (c) 1996
+ * Jean-Marc Zucconi
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: main.c,v 1.39 1997/07/01 06:37:34 charnier Exp $ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h> /* needed for INT_MAX */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+#include <sys/time.h> /* for struct timeval, gettimeofday */
+
+#include "fetch.h"
+
+static struct fetch_state clean_fetch_state;
+static sigjmp_buf sigbuf;
+static int get(struct fetch_state *volatile fs);
+
+static void
+usage()
+{
+ fprintf(stderr, "%s\n%s\n",
+ "usage: fetch [-DHILMNPRTValmnpqrv] [-o outputfile]",
+ " [-f file -h host [-c dir] | URL]");
+ exit(EX_USAGE);
+}
+
+
+int
+main(int argc, char *const *argv)
+{
+ int c;
+ char *ep;
+ struct fetch_state fs;
+ const char *change_to_dir, *file_to_get, *hostname;
+ int error, rv;
+ unsigned long l;
+
+ init_schemes();
+ fs = clean_fetch_state;
+ fs.fs_verbose = 1;
+ change_to_dir = file_to_get = hostname = 0;
+
+ while ((c = getopt(argc, argv, "ac:D:f:h:HilLmMnNo:pPqRrT:vV:")) != -1) {
+ switch (c) {
+ case 'D': case 'H': case 'I': case 'N': case 'L': case 'V':
+ break; /* ncftp compatibility */
+
+ case 'a':
+ fs.fs_auto_retry = 1;
+ break;
+ case 'c':
+ change_to_dir = optarg;
+ break;
+
+ case 'f':
+ file_to_get = optarg;
+ break;
+
+ case 'h':
+ hostname = optarg;
+ break;
+
+ case 'l':
+ fs.fs_linkfile = 1;
+ break;
+
+ case 'm': case 'M':
+ fs.fs_mirror = 1;
+ break;
+
+ case 'n':
+ fs.fs_newtime = 1;
+ break;
+
+ case 'o':
+ fs.fs_outputfile = optarg;
+ break;
+
+ case 'p': case 'P':
+ fs.fs_passive_mode = 1;
+ break;
+
+ case 'q':
+ fs.fs_verbose = 0;
+ break;
+
+ case 'r':
+ fs.fs_restart = 1;
+ break;
+
+ case 'R':
+ fs.fs_precious = 1;
+ break;
+
+ case 'T':
+ /* strtol sets errno to ERANGE in the case of overflow */
+ errno = 0;
+ l = strtoul(optarg, &ep, 0);
+ if (!optarg[0] || *ep || errno != 0 || l > INT_MAX)
+ errx(EX_USAGE, "invalid timeout value: `%s'",
+ optarg);
+ fs.fs_timeout = l;
+ break;
+
+ case 'v':
+ if (fs.fs_verbose < 2)
+ fs.fs_verbose = 2;
+ else
+ fs.fs_verbose++;
+ break;
+
+ default:
+ case '?':
+ usage();
+ }
+ }
+
+ clean_fetch_state = fs; /* preserve option settings */
+
+ if (argv[optind] && (hostname || change_to_dir || file_to_get)) {
+ warnx("cannot use -h, -c, or -f with a URI argument");
+ usage();
+ }
+
+ if (fs.fs_mirror && fs.fs_restart)
+ errx(EX_USAGE, "-m and -r are mutually exclusive.");
+
+ if (argv[optind] == 0) {
+ char *uri;
+
+ if (hostname == 0) hostname = "localhost";
+ if (change_to_dir == 0) change_to_dir = "";
+ if (file_to_get == 0) {
+ usage();
+ }
+
+ uri = alloca(sizeof("ftp://") + strlen(hostname) +
+ strlen(change_to_dir) + 2 + strlen(file_to_get));
+ strcpy(uri, "ftp://");
+ strcat(uri, hostname);
+ /*
+ * XXX - we should %-map a leading `/' into `%2f', but for
+ * anonymous FTP it is unlikely to matter. Still, it would
+ * be better to follow the spec.
+ */
+ if (change_to_dir[0] != '/')
+ strcat(uri, "/");
+ strcat(uri, change_to_dir);
+ if (file_to_get[0] != '/' && uri[strlen(uri) - 1] != '/')
+ strcat(uri, "/");
+ strcat(uri, file_to_get);
+
+ error = parse_uri(&fs, uri);
+ if (error)
+ return error;
+ return get(&fs);
+ }
+
+ for (rv = 0; argv[optind] != 0; optind++) {
+ error = parse_uri(&fs, argv[optind]);
+ if (error) {
+ rv = error;
+ continue;
+ }
+
+ error = get(&fs);
+ if (error) {
+ rv = error;
+ }
+ fs = clean_fetch_state;
+ }
+ return rv;
+}
+
+/*
+ * The signal handling is probably more complex than it needs to be,
+ * but it doesn't cost a lot, so we'll be extra-careful. Using
+ * siglongjmp() to get out of the signal handler allows us to
+ * call rm() without having to store the state variable in some global
+ * spot where the signal handler can get at it. We also obviate the need
+ * for a separate timeout signal handler.
+ */
+static int
+get(struct fetch_state *volatile fs)
+{
+ volatile int error;
+ struct sigaction oldhup, oldint, oldquit, oldterm;
+ struct sigaction catch;
+ volatile sigset_t omask;
+
+ sigemptyset(&catch.sa_mask);
+ sigaddset(&catch.sa_mask, SIGHUP);
+ sigaddset(&catch.sa_mask, SIGINT);
+ sigaddset(&catch.sa_mask, SIGQUIT);
+ sigaddset(&catch.sa_mask, SIGTERM);
+ sigaddset(&catch.sa_mask, SIGALRM);
+ catch.sa_handler = catchsig;
+ catch.sa_flags = 0;
+
+ sigprocmask(SIG_BLOCK, &catch.sa_mask, (sigset_t *)&omask);
+ sigaction(SIGHUP, &catch, &oldhup);
+ sigaction(SIGINT, &catch, &oldint);
+ sigaction(SIGQUIT, &catch, &oldquit);
+ sigaction(SIGTERM, &catch, &oldterm);
+
+ error = sigsetjmp(sigbuf, 0);
+ if (error == SIGALRM) {
+ rm(fs);
+ unsetup_sigalrm();
+ fprintf(stderr, "\n"); /* just in case */
+ warnx("%s: %s: timed out", fs->fs_outputfile, fs->fs_status);
+ goto close;
+ } else if (error) {
+ rm(fs);
+ fprintf(stderr, "\n"); /* just in case */
+ warnx("%s: interrupted by signal: %s", fs->fs_status,
+ sys_signame[error]);
+ sigdelset(&omask, error);
+ signal(error, SIG_DFL);
+ sigprocmask(SIG_SETMASK, (sigset_t *)&omask, 0);
+ raise(error); /* so that it gets reported as such */
+ }
+
+ sigprocmask(SIG_SETMASK, (sigset_t *)&omask, 0);
+ error = fs->fs_retrieve(fs);
+
+close:
+ sigaction(SIGHUP, &oldhup, 0);
+ sigaction(SIGINT, &oldint, 0);
+ sigaction(SIGQUIT, &oldquit, 0);
+ sigaction(SIGTERM, &oldterm, 0);
+ fs->fs_close(fs);
+
+ return error;
+}
+
+
+/*
+ * Utility functions
+ */
+
+/*
+ * Handle all signals by jumping back into get().
+ */
+void
+catchsig(int sig)
+{
+ siglongjmp(sigbuf, sig);
+}
+
+/* Used to generate the progress display when not in quiet mode. */
+void
+display(struct fetch_state *fs, off_t size, ssize_t n)
+{
+ static off_t bytes;
+ static off_t bytestart;
+ static int pr, stdoutatty, init = 0;
+ static struct timeval t0, t_start;
+ static char *s;
+ struct timezone tz;
+ struct timeval t;
+ float d;
+
+ if (!fs->fs_verbose)
+ return;
+ if (init == 0) {
+ init = 1;
+ gettimeofday(&t0, &tz);
+ t_start = t0;
+ bytes = pr = 0;
+ stdoutatty = isatty(STDOUT_FILENO);
+ if (size > 0)
+ asprintf (&s, "Receiving %s (%qd bytes)%s", fs->fs_outputfile,
+ (quad_t)size,
+ size ? "" : " [appending]");
+ else
+ asprintf (&s, "Receiving %s", fs->fs_outputfile);
+ fprintf (stderr, "%s", s);
+ bytestart = bytes = n;
+ return;
+ }
+ gettimeofday(&t, &tz);
+ if (n == -1) {
+ if(stdoutatty) {
+ if (size > 0)
+ fprintf (stderr, "\r%s: 100%%", s);
+ else
+ fprintf (stderr, "\r%s: %qd Kbytes", s, (quad_t)bytes/1024);
+ }
+ bytes -= bytestart;
+ d = t.tv_sec + t.tv_usec/1.e6 - t_start.tv_sec - t_start.tv_usec/1.e6;
+ fprintf (stderr, "\n%qd bytes transfered in %.1f seconds",
+ (quad_t)bytes, d);
+ d = bytes/d;
+ if (d < 1000)
+ fprintf (stderr, " (%.0f bytes/s)\n", d);
+ else {
+ d /=1024;
+ fprintf (stderr, " (%.2f kB/s)\n", d);
+ }
+ free(s);
+ init = 0;
+ return;
+ }
+ bytes += n;
+ d = t.tv_sec + t.tv_usec/1.e6 - t0.tv_sec - t0.tv_usec/1.e6;
+ if (d < 5) /* display every 5 sec. */
+ return;
+ t0 = t;
+ pr++;
+ if(stdoutatty) {
+ if (size > 1000000)
+ fprintf (stderr, "\r%s: %2qd%%", s, (quad_t)bytes/(size/100));
+ else if (size > 0)
+ fprintf (stderr, "\r%s: %2qd%%", s, (quad_t)100*bytes/size);
+ else
+ fprintf (stderr, "\r%s: %qd kB", s, (quad_t)bytes/1024);
+ }
+}
+
diff --git a/usr.bin/fetch/uri.c b/usr.bin/fetch/uri.c
new file mode 100644
index 0000000..95d4c91
--- /dev/null
+++ b/usr.bin/fetch/uri.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "fetch.h"
+
+struct uri_scheme *schemes[] = {
+ &http_scheme, &ftp_scheme, &file_scheme, 0
+};
+
+static struct uri_scheme *
+find_scheme(const char *name)
+{
+ int i;
+
+ for (i = 0; schemes[i]; i++) {
+ if (strcasecmp(schemes[i]->sc_name, name) == 0)
+ return schemes[i];
+ }
+ return 0;
+}
+
+void
+init_schemes(void)
+{
+ int i;
+ char schemebuf[32];
+ const char *s, *t;
+ struct uri_scheme *scp;
+
+ for (i = 0; schemes[i]; i++) {
+ if (getenv(schemes[i]->sc_proxy_envar) != 0)
+ schemes[i]->sc_can_proxy = 1;
+ }
+
+ for (i = 0; schemes[i]; i++) {
+ s = schemes[i]->sc_proxy_by;
+ while (s && *s) {
+ t = strchr(s, ',');
+ if (t) {
+ schemebuf[0] = '\0';
+ strncat(schemebuf, s, t - s);
+ s = t + 1;
+ } else {
+ strcpy(schemebuf, s);
+ s = 0;
+ }
+ scp = find_scheme(schemebuf);
+ if (scp && scp->sc_can_proxy) {
+ schemes[i]->sc_proxyproto = scp;
+ break;
+ }
+ }
+ }
+}
+
+int
+parse_uri(struct fetch_state *fs, const char *uri)
+{
+ const char *colon, *slash;
+ char *scheme;
+ struct uri_scheme *scp;
+
+ fs->fs_status = "parsing URI";
+ colon = strchr(uri, ':');
+ slash = strchr(uri, '/');
+ if (!colon || !slash || slash < colon) {
+ warnx("%s: an absolute URI is required", uri);
+ return EX_USAGE;
+ }
+
+ scheme = alloca(colon - uri + 1);
+ scheme[0] = '\0';
+ strncat(scheme, uri, colon - uri);
+ scp = find_scheme(scheme);
+
+ if (scp == 0) {
+ warnx("%s: unknown URI scheme", scheme);
+ return EX_USAGE;
+ }
+ if (scp->sc_proxyproto)
+ return scp->sc_proxyproto->sc_proxy_parse(fs, uri);
+ else
+ return scp->sc_parse(fs, uri);
+}
+
diff --git a/usr.bin/fetch/util.c b/usr.bin/fetch/util.c
new file mode 100644
index 0000000..49c1108
--- /dev/null
+++ b/usr.bin/fetch/util.c
@@ -0,0 +1,332 @@
+/*-
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: util.c,v 1.4 1997/02/07 17:55:01 wollman Exp $
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <time.h> /* for time() */
+#include <unistd.h>
+
+#include <sys/time.h> /* for struct timeval */
+
+#include "fetch.h"
+
+
+/* Signal handling functions */
+
+/*
+ * If this were Scheme we could make this variable private to just these two
+ * functions...
+ */
+static struct sigaction oldalrm;
+
+void
+setup_sigalrm(void)
+{
+ struct sigaction catch;
+
+ sigemptyset(&catch.sa_mask);
+ sigaddset(&catch.sa_mask, SIGHUP);
+ sigaddset(&catch.sa_mask, SIGINT);
+ sigaddset(&catch.sa_mask, SIGQUIT);
+ sigaddset(&catch.sa_mask, SIGTERM);
+ sigaddset(&catch.sa_mask, SIGALRM);
+ catch.sa_handler = catchsig;
+ catch.sa_flags = 0;
+
+ sigaction(SIGALRM, &catch, &oldalrm);
+}
+
+void
+unsetup_sigalrm(void)
+{
+ sigaction(SIGALRM, &oldalrm, 0);
+}
+
+
+/* File-handling functions */
+
+/*
+ * Set the last-modified time of the output file to be that returned by
+ * the server.
+ */
+void
+adjmodtime(struct fetch_state *fs)
+{
+ struct timeval tv[2];
+
+ /* XXX - not strictly correct, since (time_t)-1 does not have to be
+ > 0. This also catches some of the other routines which erroneously
+ return 0 for invalid times rather than -1. */
+ if (!fs->fs_newtime && fs->fs_modtime > 0) {
+ tv[0].tv_usec = tv[1].tv_usec = 0;
+ time(&tv[0].tv_sec);
+ tv[1].tv_sec = fs->fs_modtime;
+ utimes(fs->fs_outputfile, tv);
+ }
+}
+
+/*
+ * Delete the file when exiting on error, if it is not `precious'.
+ */
+void
+rm(struct fetch_state *fs)
+{
+ if (!(fs->fs_outputfile[0] == '-' && fs->fs_outputfile[1] == '\0')) {
+ if (!fs->fs_restart && !fs->fs_mirror && !fs->fs_precious)
+ unlink(fs->fs_outputfile);
+ else
+ adjmodtime(fs);
+ }
+}
+
+
+/* String-handling and -parsing functions */
+
+/*
+ * Undo the standard %-sign encoding in URIs (e.g., `%2f' -> `/'). This
+ * must be done after the URI is parsed, since the principal purpose of
+ * the encoding is to hide characters which would otherwise be significant
+ * to the parser (like `/').
+ */
+char *
+percent_decode(const char *uri)
+{
+ char *rv, *s;
+
+ rv = s = safe_malloc(strlen(uri) + 1);
+
+ while (*uri) {
+ if (*uri == '%' && uri[1]
+ && isxdigit(uri[1]) && isxdigit(uri[2])) {
+ int c;
+ static char buf[] = "xx";
+
+ buf[0] = uri[1];
+ buf[1] = uri[2];
+ sscanf(buf, "%x", &c);
+ uri += 3;
+ *s++ = c;
+ } else {
+ *s++ = *uri++;
+ }
+ }
+ *s = '\0';
+ return rv;
+}
+
+/*
+ * Decode a standard host:port string into its constituents, allocating
+ * memory for a new copy of the host part.
+ */
+int
+parse_host_port(const char *s, char **hostname, int *port)
+{
+ const char *colon;
+ char *ep;
+ unsigned long ul;
+
+ colon = strchr(s, ':');
+ if (colon != 0) {
+ errno = 0;
+ ul = strtoul(colon + 1, &ep, 10);
+ if (*ep != '\0' || colon[1] == '\0' || errno != 0
+ || ul < 1 || ul > 65534) {
+ warnx("`%s': invalid port number", colon + 1);
+ return EX_USAGE;
+ }
+
+ *hostname = safe_strndup(s, colon - s);
+ *port = ul;
+ } else {
+ *hostname = safe_strdup(s);
+ }
+ return 0;
+}
+
+/*
+ * safe_malloc is like malloc, but aborts on error.
+ */
+void *
+safe_malloc(size_t len)
+{
+ void *rv;
+
+ rv = malloc(len);
+ if (rv == 0)
+ err(EX_OSERR, "malloc(%qu)", (u_quad_t)len);
+ return rv;
+}
+
+/*
+ * safe_strdup is like strdup, but aborts on error.
+ */
+char *
+safe_strdup(const char *orig)
+{
+ char *s;
+
+ s = safe_malloc(strlen(orig) + 1);
+ strcpy(s, orig);
+ return s;
+}
+
+/*
+ * safe_strndup is like safe_strdup, but copies at most `len'
+ * characters from `orig'.
+ */
+char *
+safe_strndup(const char *orig, size_t len)
+{
+ char *s;
+
+ s = safe_malloc(len + 1);
+ s[0] = '\0';
+ strncat(s, orig, len);
+ return s;
+}
+
+/*
+ * Implement the `base64' encoding as described in RFC 1521.
+ */
+static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char *
+to_base64(const unsigned char *buf, size_t len)
+{
+ char *s, *rv;
+ unsigned tmp;
+
+ s = safe_malloc((4 * (len + 1)) / 3 + 1);
+
+ rv = s;
+ while (len >= 3) {
+ tmp = buf[0] << 16 | buf[1] << 8 | buf[2];
+ s[0] = base64[tmp >> 18];
+ s[1] = base64[(tmp >> 12) & 077];
+ s[2] = base64[(tmp >> 6) & 077];
+ s[3] = base64[tmp & 077];
+ len -= 3;
+ buf += 3;
+ s += 4;
+ }
+
+ /* RFC 1521 enumerates these three possibilities... */
+ switch(len) {
+ case 2:
+ tmp = buf[0] << 16 | buf[1] << 8;
+ s[0] = base64[(tmp >> 18) & 077];
+ s[1] = base64[(tmp >> 12) & 077];
+ s[2] = base64[(tmp >> 6) & 077];
+ s[3] = '=';
+ s[4] = '\0';
+ break;
+ case 1:
+ tmp = buf[0] << 16;
+ s[0] = base64[(tmp >> 18) & 077];
+ s[1] = base64[(tmp >> 12) & 077];
+ s[2] = s[3] = '=';
+ s[4] = '\0';
+ break;
+ case 0:
+ s[0] = '\0';
+ break;
+ }
+
+ return rv;
+}
+
+int
+from_base64(const char *orig, unsigned char *buf, size_t *lenp)
+{
+ int len, len2;
+ const char *equals;
+ unsigned tmp;
+
+ len = strlen(orig);
+ while (isspace(orig[len - 1]))
+ len--;
+
+ if (len % 4)
+ return -1;
+
+ len2 = 3 * (len / 4);
+ equals = strchr(orig, '=');
+ if (equals != 0) {
+ if (equals[1] == '=')
+ len2 -= 2;
+ else
+ len2 -= 1;
+ }
+
+ /* Now the length is len2 is the actual length of the original. */
+ if (len2 > *lenp)
+ return -1;
+ *lenp = len2;
+
+ while (len > 0) {
+ int i;
+ const char *off;
+ int forget;
+
+ tmp = 0;
+ forget = 0;
+ for (i = 0; i < 4; i++) {
+ if (orig[i] == '=') {
+ off = base64;
+ forget++;
+ } else {
+ off = strchr(base64, orig[i]);
+ }
+ if (off == 0)
+ return -1;
+ tmp = (tmp << 6) | (off - base64);
+ }
+
+ buf[0] = (tmp >> 16) & 0xff;
+ if (forget < 2)
+ buf[1] = (tmp >> 8) & 0xff;
+ if (forget < 1)
+ buf[2] = (tmp >> 8) & 0xff;
+ len -= 4;
+ orig += 4;
+ buf += 3 - forget;
+ }
+ return 0;
+}
diff --git a/usr.bin/file/LEGAL.NOTICE b/usr.bin/file/LEGAL.NOTICE
new file mode 100644
index 0000000..122c5f6
--- /dev/null
+++ b/usr.bin/file/LEGAL.NOTICE
@@ -0,0 +1,31 @@
+Copyright (c) Ian F. Darwin 1986, 1987, 1989, 1990, 1991, 1992, 1994, 1995.
+Software written by Ian F. Darwin and others; maintained by Christos Zoulas.
+$Id$
+
+This software (or derivative software) may not be made subject to any
+license which denies anyone permission to alter it and redistribute it
+freely. Derivative software must also still fall under this license.
+
+This software is not subject to any export provision of the United States
+Department of Commerce, and may be exported to any country or planet.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it freely, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+ Derivative works must also be marked as such, and credits must appear
+ in the documentation.
+
+4. This notice may not be removed or altered.
+
+
diff --git a/usr.bin/file/MAINT b/usr.bin/file/MAINT
new file mode 100644
index 0000000..2b91576
--- /dev/null
+++ b/usr.bin/file/MAINT
@@ -0,0 +1,33 @@
+$Id$
+
+Maintenance notes:
+
+I am continuing to maintain the file command. I welcome your help,
+but to make my life easier I'd like to request the following:
+
+- Don't change the version numbers!
+
+If your changes are extensive, I will have to work hard to
+integrate them into my version. If you check it into SCCS locally,
+the version numbers will likely be kept. IF you check it into RCS
+or CVS locally, please use -k to keep the version numbers, and
+please use branch deltas (1.21.1, 1.21.2, ...). If you don't do
+this, I will likely be unable to use your changes; life's just too
+short.
+
+- Do not distribute changed versions.
+
+People trying to be helpful occasionally put up their hacked versions
+of the file command for FTP, then the "archie" server finds and publishes
+the hacked version, and people all over the world get copies of it.
+Within a day or two I am getting email from around the world
+asking me why "my" file command won't compile!!! Needless to say this
+detracts from the limited time I have available to work on the actual
+software. Therefore I ask you again to please NOT distribute
+your changed version.
+
+
+Thank you for your assistance and cooperation.
+
+Mark Moraes Christos Zoulas
+moraes@deshaw.com christos@deshaw.com
diff --git a/usr.bin/file/Magdir/Header b/usr.bin/file/Magdir/Header
new file mode 100644
index 0000000..0c97bae
--- /dev/null
+++ b/usr.bin/file/Magdir/Header
@@ -0,0 +1,5 @@
+#! file
+# Magic data for file(1) command.
+# Machine-genererated from src/cmd/file/magdir/*; edit there only!
+# Format is described in magic(files), where:
+# files is 4 on V7 and BSD, 4 on SV, and ?? in the SVID.
diff --git a/usr.bin/file/Magdir/Localstuff b/usr.bin/file/Magdir/Localstuff
new file mode 100644
index 0000000..0b6d955
--- /dev/null
+++ b/usr.bin/file/Magdir/Localstuff
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# Localstuff: file(1) magic for locally observed files
+#
+# $Id$
+# Add any locally observed files here. Remember:
+# text if readable, executable if runnable binary, data if unreadable.
diff --git a/usr.bin/file/Magdir/alliant b/usr.bin/file/Magdir/alliant
new file mode 100644
index 0000000..69cf4b4
--- /dev/null
+++ b/usr.bin/file/Magdir/alliant
@@ -0,0 +1,17 @@
+
+#------------------------------------------------------------------------------
+# alliant: file(1) magic for Alliant FX series a.out files
+#
+# If the FX series is the one that had a processor with a 68K-derived
+# instruction set, the "short" should probably become "beshort" and the
+# "long" should probably become "belong".
+# If it's the i860-based one, they should probably become either the
+# big-endian or little-endian versions, depending on the mode they ran
+# the 860 in....
+#
+0 short 0420 0420 Alliant virtual executable
+>2 short &0x0020 common library
+>16 long >0 not stripped
+0 short 0421 0421 Alliant compact executable
+>2 short &0x0020 common library
+>16 long >0 not stripped
diff --git a/usr.bin/file/Magdir/alpha b/usr.bin/file/Magdir/alpha
new file mode 100644
index 0000000..42e1917
--- /dev/null
+++ b/usr.bin/file/Magdir/alpha
@@ -0,0 +1,21 @@
+#------------------------------------------------------------------------------
+# alpha architecture description
+#
+
+0 leshort 0603 COFF format alpha
+>22 leshort&030000 !020000 executable
+>24 leshort 0410 pure
+>24 leshort 0413 paged
+>22 leshort&020000 !0 dynamically linked
+>16 lelong !0 not stripped
+>16 lelong 0 stripped
+>22 leshort&030000 020000 shared library
+>24 leshort 0407 object
+>27 byte x - version %d
+>26 byte x .%d
+>28 byte x -%d
+
+# Basic recognition of OSF/1 core dumps - Mike Bremford <mike@opac.bl.uk>
+#
+0 string Core\001 COFF format core dump (OSF/1)
+>24 string >\0 generated by '%s'
diff --git a/usr.bin/file/Magdir/amanda b/usr.bin/file/Magdir/amanda
new file mode 100644
index 0000000..57c4359
--- /dev/null
+++ b/usr.bin/file/Magdir/amanda
@@ -0,0 +1,7 @@
+#------------------------------------------------------------------------------
+# amanda: file(1) magic for amanda file format
+#
+0 string AMANDA:\ TAPESTART\ DATE AMANDA dump header file,
+>23 string X
+>>25 string >\ Unused %s
+>23 string >\ DATE %s
diff --git a/usr.bin/file/Magdir/amigaos b/usr.bin/file/Magdir/amigaos
new file mode 100644
index 0000000..6073936
--- /dev/null
+++ b/usr.bin/file/Magdir/amigaos
@@ -0,0 +1,10 @@
+#------------------------------------------------------------------------------
+# amigaos: file(1) magic for AmigaOS binary formats:
+
+#
+# From ignatios@cs.uni-bonn.de (Ignatios Souvatzis)
+# Some formats are still missing: AmigaOS special IFF's, e.g.: FORM....CTLG
+# (the others should be seperate, anyway)
+#
+0 belong 0x000003f3 AmigaOS loadseg()ble executable/binary
+0 belong 0x000003e7 AmigaOS object/library data
diff --git a/usr.bin/file/Magdir/animation b/usr.bin/file/Magdir/animation
new file mode 100644
index 0000000..18ae9da
--- /dev/null
+++ b/usr.bin/file/Magdir/animation
@@ -0,0 +1,58 @@
+
+#------------------------------------------------------------------------------
+# animation: file(1) magic for animation/movie formats
+#
+# animation formats
+# MPEG, FLI, DL originally from vax@ccwf.cc.utexas.edu (VaX#n8)
+# FLC, SGI, Apple originally from Daniel Quinlan (quinlan@yggdrasil.com)
+
+# MPEG animation format
+0 belong 0x000001b3 Mpeg video stream data
+#>4 beshort&0xfff0 x (%d x
+#>5 beshort&0x0fff x %d)
+0 belong 0x000001ba Mpeg system stream data
+0 beshort&0xfff0 0xfff0 Mpeg audio stream data
+
+# FLI animation format
+4 leshort 0xAF11 FLI file
+>6 leshort x - %d frames,
+>8 leshort x width=%d pixels,
+>10 leshort x height=%d pixels,
+>12 leshort x depth=%d,
+>16 leshort x ticks/frame=%d
+# FLC animation format
+4 leshort 0xAF12 FLC file
+>6 leshort x - %d frames
+>8 leshort x width=%d pixels,
+>10 leshort x height=%d pixels,
+>12 leshort x depth=%d,
+>16 leshort x ticks/frame=%d
+
+# DL animation format
+# XXX - collision with most `mips' magic
+#
+# I couldn't find a real magic number for these, however, this
+# -appears- to work. Note that it might catch other files, too, so be
+# careful!
+#
+# Note that title and author appear in the two 20-byte chunks
+# at decimal offsets 2 and 22, respectively, but they are XOR'ed with
+# 255 (hex FF)! The DL format is really bad.
+#
+#0 byte 1 DL version 1, medium format (160x100, 4 images/screen)
+#>42 byte x - %d screens,
+#>43 byte x %d commands
+#0 byte 2 DL version 2
+#>1 byte 1 - large format (320x200,1 image/screen),
+#>1 byte 2 - medium format (160x100,4 images/screen),
+#>1 byte >2 - unknown format,
+#>42 byte x %d screens,
+#>43 byte x %d commands
+# Based on empirical evidence, DL version 3 have several nulls following the
+# \003. Most of them start with non-null values at hex offset 0x34 or so.
+#0 string \3\0\0\0\0\0\0\0\0\0\0\0 DL version 3
+
+# SGI and Apple formats
+0 string MOVI Silicon Graphics movie file
+4 string moov Apple QuickTime movie file (moov)
+4 string mdat Apple QuickTime movie file (mdat)
diff --git a/usr.bin/file/Magdir/apl b/usr.bin/file/Magdir/apl
new file mode 100644
index 0000000..0400431
--- /dev/null
+++ b/usr.bin/file/Magdir/apl
@@ -0,0 +1,6 @@
+
+#------------------------------------------------------------------------------
+# apl: file(1) magic for APL (see also "pdp" and "vax" for other APL
+# workspaces)
+#
+0 long 0100554 APL workspace (Ken's original?)
diff --git a/usr.bin/file/Magdir/apple b/usr.bin/file/Magdir/apple
new file mode 100644
index 0000000..a6492b7
--- /dev/null
+++ b/usr.bin/file/Magdir/apple
@@ -0,0 +1,10 @@
+
+#------------------------------------------------------------------------------
+# apple: file(1) magic for Apple II file formats
+#
+0 string FiLeStArTfIlEsTaRt binscii (apple ][) text
+0 string \x0aGL Binary II (apple ][) data
+0 string \x76\xff Squeezed (apple ][) data
+0 string SIT! StuffIt (macintosh) text
+0 string NuFile NuFile archive (apple ][) data
+0 string N\xf5F\xe9l\xe5 NuFile archive (apple ][) data
diff --git a/usr.bin/file/Magdir/ar b/usr.bin/file/Magdir/ar
new file mode 100644
index 0000000..583ec30
--- /dev/null
+++ b/usr.bin/file/Magdir/ar
@@ -0,0 +1,104 @@
+#
+# "ar", for all kinds of archives.
+#
+# XXX - why are there multiple <ar> thingies? Note that 0x213c6172 is
+# "!<ar", so, for new-style (4.xBSD/SVR2andup) archives, we have:
+#
+# 0 string !<arch> current ar archive
+# 0 long 0x213c6172 archive file
+#
+# and for SVR3.1 archives, we have:
+#
+# 0 string \<ar> System V Release 1 ar archive
+# 0 string =<ar> archive
+# 0 string =<ar> archive
+#
+# XXX - did Aegis really store shared libraries, breakpointed modules,
+# and absolute code program modules in the same format as new-style
+# "ar" archives?
+#
+0 string !<arch> current ar archive
+>8 string __.SYMDEF random library
+>0 belong =65538 - pre SR9.5
+>0 belong =65539 - post SR9.5
+>0 beshort 2 - object archive
+>0 beshort 3 - shared library module
+>0 beshort 4 - debug break-pointed module
+>0 beshort 5 - absolute code program module
+0 string \<ar> System V Release 1 ar archive
+0 string =<ar> archive
+#
+# XXX - from "vax", which appears to collect a bunch of byte-swapped
+# thingies, to help you recognize VAX files on big-endian machines;
+# with "leshort", "lelong", and "string", that's no longer necessary....
+#
+# 0 long 0x3c61723e VAX 5.0 archive
+#
+0 long 0x213c6172 archive file
+0 lelong 0177555 very old VAX archive
+0 leshort 0177555 very old PDP-11 archive
+#
+# XXX - "pdp" claims that 0177545 can have an __.SYMDEF member and thus
+# be a random library (it said 0xff65 rather than 0177545).
+#
+0 lelong 0177545 old VAX archive
+>8 string __.SYMDEF random library
+0 leshort 0177545 old PDP-11 archive
+>8 string __.SYMDEF random library
+#
+0 string =<ar> archive
+#
+# From "pdp":
+#
+0 lelong 0x39bed PDP-11 old archive
+0 lelong 0x39bee PDP-11 4.0 archive
+#
+0 string -h- Software Tools format archive text
+# "arc" archiver
+0 byte 26 'arc' archive
+>1 byte 0 (empty)
+>1 byte 1 (old format)
+# Rahul Dhesi's zoo archive format, from keith@cerberus.uchicago.edu.
+20 long 0xdca7c4fd Rahul Dhesi's "zoo" archive
+# ZIP archiver
+0 string PK zip archive file
+>4 byte x - version
+>4 byte 10 1.0
+>4 byte 20 2.0
+
+2 string -lh LHarc archive data
+>6 byte x type %c
+>20 byte x - header level %d
+
+# From: <u31b3hs@pool.informatik.rwth-aachen.de> (Michael Haardt)
+2 string -lh0- Lharc 1.x archive
+2 string -lh1- Lharc 1.x archive
+2 string -lz4- Lharc 1.x archive
+2 string -lz5- Lharc 1.x archive
+2 string -lzs- LHa 2.x? archive [lzs]
+2 string -lh - LHa 2.x? archive [lh ]
+2 string -lhd- LHa 2.x? archive [lhd]
+2 string -lh2- LHa 2.x? archive [lh2]
+2 string -lh3- LHa 2.x? archive [lh3]
+2 string -lh4- LHa 2.x? archive [lh4]
+2 string -lh5- LHa (2.x) archive
+
+# ARJ archive data from jason@jarthur.Claremont.EDU
+0 leshort 0xea60 ARJ archive data
+>5 byte x - version %d,
+>8 byte >0 flags:
+>>8 byte &0x04 multi-volume,
+>>8 byte &0x10 slash switched,
+>>8 byte &0x20 backup,
+>34 string x original name: %s,
+>7 byte 0 os: MS/DOS
+>7 byte 1 os: PRIMOS
+>7 byte 2 os: UNIX
+>7 byte 3 os: Amiga
+>7 byte 4 os: Macintosh
+>7 byte 5 os: OS/2
+>7 byte 6 os: Apple ][ GS
+>7 byte 7 os: Atari ST
+>7 byte 8 os: NeXT
+>7 byte 9 os: VAX/VMS
+>3 byte >0 %d]
diff --git a/usr.bin/file/Magdir/arc b/usr.bin/file/Magdir/arc
new file mode 100644
index 0000000..1ebb260
--- /dev/null
+++ b/usr.bin/file/Magdir/arc
@@ -0,0 +1,3 @@
+0 byte 26 'arc' archive
+>1 byte 0 (empty)
+>1 byte 1 (old format)
diff --git a/usr.bin/file/Magdir/archive b/usr.bin/file/Magdir/archive
new file mode 100644
index 0000000..f266b19
--- /dev/null
+++ b/usr.bin/file/Magdir/archive
@@ -0,0 +1,210 @@
+
+#------------------------------------------------------------------------------
+# archive: file(1) magic for archive formats (see also "msdos" for self-
+# extracting compressed archives)
+#
+# cpio, ar, arc, arj, hpack, lha/lharc, rar, squish, uc2, zip, zoo, etc.
+# pre-POSIX "tar" archives are handled in the C code.
+
+# POSIX tar archives
+257 string ustar\0 POSIX tar archive
+257 string ustar\040\040\0 GNU tar archive
+
+# cpio archives
+#
+# Yes, the top two "cpio archive" formats *are* supposed to just be "short".
+# The idea is to indicate archives produced on machines with the same
+# byte order as the machine running "file" with "cpio archive", and
+# to indicate archives produced on machines with the opposite byte order
+# from the machine running "file" with "byte-swapped cpio archive".
+#
+# The SVR4 "cpio(4)" hints that there are additional formats, but they
+# are defined as "short"s; I think all the new formats are
+# character-header formats and thus are strings, not numbers.
+0 short 070707 cpio archive
+0 short 0143561 byte-swapped cpio archive
+0 string 070707 ASCII cpio archive (pre-SVR4 or odc)
+0 string 070701 ASCII cpio archive (SVR4 with no CRC)
+0 string 070702 ASCII cpio archive (SVR4 with CRC)
+
+# other archives
+0 long 0177555 very old archive
+0 short 0177555 very old PDP-11 archive
+0 long 0177545 old archive
+0 short 0177545 old PDP-11 archive
+0 long 0100554 apl workspace
+0 string =<ar> archive
+
+# MIPS archive (needs to go first)
+#
+0 string !<arch>\n__________E MIPS archive
+>20 string U with MIPS Ucode members
+>21 string L with MIPSEL members
+>21 string B with MIPSEB members
+>19 string L and an EL hash table
+>19 string B and an EB hash table
+>22 string X -- out of date
+
+0 string -h- Software Tools format archive text
+
+#
+# XXX - why are there multiple <ar> thingies? Note that 0x213c6172 is
+# "!<ar", so, for new-style (4.xBSD/SVR2andup) archives, we have:
+#
+# 0 string !<arch> current ar archive
+# 0 long 0x213c6172 archive file
+#
+# and for SVR1 archives, we have:
+#
+# 0 string \<ar> System V Release 1 ar archive
+# 0 string =<ar> archive
+#
+# XXX - did Aegis really store shared libraries, breakpointed modules,
+# and absolute code program modules in the same format as new-style
+# "ar" archives?
+#
+0 string !<arch> current ar archive
+>8 string __.SYMDEF random library
+>8 string debian-split part of multipart Debian package
+>8 string debian-binary Debian binary package
+>0 belong =65538 - pre SR9.5
+>0 belong =65539 - post SR9.5
+>0 beshort 2 - object archive
+>0 beshort 3 - shared library module
+>0 beshort 4 - debug break-pointed module
+>0 beshort 5 - absolute code program module
+0 string \<ar> System V Release 1 ar archive
+0 string =<ar> archive
+#
+# XXX - from "vax", which appears to collect a bunch of byte-swapped
+# thingies, to help you recognize VAX files on big-endian machines;
+# with "leshort", "lelong", and "string", that's no longer necessary....
+#
+0 belong 0x65ff0000 VAX 3.0 archive
+0 belong 0x3c61723e VAX 5.0 archive
+#
+0 long 0x213c6172 archive file
+0 lelong 0177555 very old VAX archive
+0 leshort 0177555 very old PDP-11 archive
+#
+# XXX - "pdp" claims that 0177545 can have an __.SYMDEF member and thus
+# be a random library (it said 0xff65 rather than 0177545).
+#
+0 lelong 0177545 old VAX archive
+>8 string __.SYMDEF random library
+0 leshort 0177545 old PDP-11 archive
+>8 string __.SYMDEF random library
+#
+# From "pdp" (but why a 4-byte quantity?)
+#
+0 lelong 0x39bed PDP-11 old archive
+0 lelong 0x39bee PDP-11 4.0 archive
+
+# ARC archiver, from Daniel Quinlan (quinlan@yggdrasil.com)
+#
+# The first byte is the magic (0x1a), byte 2 is the compression type for
+# the first file (0x01 through 0x09), and bytes 3 to 15 are the MS-DOS
+# filename of the first file (null terminated). Since some types collide
+# we only test some types on basis of frequency: 0x08 (83%), 0x09 (5%),
+# 0x02 (5%), 0x03 (3%), 0x04 (2%), 0x06 (2%). 0x01 collides with terminfo.
+0 lelong&0x8080ffff 0x0000081a ARC archive data, dynamic LZW
+0 lelong&0x8080ffff 0x0000091a ARC archive data, squashed
+0 lelong&0x8080ffff 0x0000021a ARC archive data, uncompressed
+0 lelong&0x8080ffff 0x0000031a ARC archive data, packed
+0 lelong&0x8080ffff 0x0000041a ARC archive data, squeezed
+0 lelong&0x8080ffff 0x0000061a ARC archive data, crunched
+
+# Acorn archive formats (Disaster prone simpleton, m91dps@ecs.ox.ac.uk)
+# I can't create either SPARK or ArcFS archives so I have not tested this stuff
+# [GRR: the original entries collide with ARC, above; replaced with combined
+# version (not tested)]
+#0 byte 0x1a RISC OS archive
+#>1 string archive (ArcFS format)
+0 string \032archive RISC OS archive (ArcFS format)
+
+# ARJ archiver (jason@jarthur.Claremont.EDU)
+0 leshort 0xea60 ARJ archive data
+>5 byte x \b, v%d,
+>8 byte &0x04 multi-volume,
+>8 byte &0x10 slash-switched,
+>8 byte &0x20 backup,
+>34 string x original name: %s,
+>7 byte 0 os: MS-DOS
+>7 byte 1 os: PRIMOS
+>7 byte 2 os: Unix
+>7 byte 3 os: Amiga
+>7 byte 4 os: Macintosh
+>7 byte 5 os: OS/2
+>7 byte 6 os: Apple ][ GS
+>7 byte 7 os: Atari ST
+>7 byte 8 os: NeXT
+>7 byte 9 os: VAX/VMS
+>3 byte >0 %d]
+
+# HA archiver (Greg Roelofs, newt@uchicago.edu)
+# This is a really bad format. A file containing HAWAII will match this...
+#0 string HA HA archive data,
+#>2 leshort =1 1 file,
+#>2 leshort >1 %u files,
+#>4 byte&0x0f =0 first is type CPY
+#>4 byte&0x0f =1 first is type ASC
+#>4 byte&0x0f =2 first is type HSC
+#>4 byte&0x0f =0x0e first is type DIR
+#>4 byte&0x0f =0x0f first is type SPECIAL
+
+# HPACK archiver (Peter Gutmann, pgut1@cs.aukuni.ac.nz)
+0 string HPAK HPACK archive data
+
+# JAM Archive volume format, by Dmitry.Kohmanyuk@UA.net
+0 string \351,\001JAM\ JAM archive,
+>7 string >\0 version %.4s
+>0x26 byte =0x27 -
+>>0x2b string >\0 label %.11s,
+>>0x27 lelong x serial %08x,
+>>0x36 string >\0 fstype %.8s
+
+# LHARC/LHA archiver (Greg Roelofs, newt@uchicago.edu)
+2 string -lh0- LHarc 1.x archive data [lh0]
+2 string -lh1- LHarc 1.x archive data [lh1]
+2 string -lz4- LHarc 1.x archive data [lz4]
+2 string -lz5- LHarc 1.x archive data [lz5]
+# [never seen any but the last; -lh4- reported in comp.compression:]
+2 string -lzs- LHa 2.x? archive data [lzs]
+2 string -lh - LHa 2.x? archive data [lh ]
+2 string -lhd- LHa 2.x? archive data [lhd]
+2 string -lh2- LHa 2.x? archive data [lh2]
+2 string -lh3- LHa 2.x? archive data [lh3]
+2 string -lh4- LHa (2.x) archive data [lh4]
+2 string -lh5- LHa (2.x) archive data [lh5]
+>20 byte x - header level %d
+
+# RAR archiver (Greg Roelofs, newt@uchicago.edu)
+0 string Rar! RAR archive data
+
+# SQUISH archiver (Greg Roelofs, newt@uchicago.edu)
+0 string SQSH squished archive data (Acorn RISCOS)
+
+# UC2 archiver (Greg Roelofs, newt@uchicago.edu)
+# I can't figure out the self-extracting form of these buggers...
+0 string UC2\x1a UC2 archive data
+
+# ZIP archives (Greg Roelofs, c/o zip-bugs@wkuvx1.wku.edu)
+0 string PK\003\004 Zip archive data
+>4 byte 0x09 \b, at least v0.9 to extract
+>4 byte 0x0a \b, at least v1.0 to extract
+>4 byte 0x0b \b, at least v1.1 to extract
+>4 byte 0x14 \b, at least v2.0 to extract
+
+# Zoo archiver
+20 lelong 0xfdc4a7dc Zoo archive data
+>4 byte >48 \b, v%c.
+>>6 byte >47 \b%c
+>>>7 byte >47 \b%c
+>32 byte >0 \b, modify: v%d
+>>33 byte x \b.%d+
+>42 lelong 0xfdc4a7dc \b,
+>>70 byte >0 extract: v%d
+>>>71 byte x \b.%d+
+
+# Shell archives
+10 string #\ This\ is\ a\ shell\ archive shell archive text
diff --git a/usr.bin/file/Magdir/asterix b/usr.bin/file/Magdir/asterix
new file mode 100644
index 0000000..d89504a
--- /dev/null
+++ b/usr.bin/file/Magdir/asterix
@@ -0,0 +1,17 @@
+
+#------------------------------------------------------------------------------
+# asterix: file(1) magic for Aster*x; SunOS 5.5.1 gave the 4-character
+# strings as "long" - we assume they're just strings:
+# From: guy@netapp.com (Guy Harris)
+#
+0 string *STA Aster*x
+>7 string WORD Words Document
+>7 string GRAP Graphic
+>7 string SPRE Spreadsheet
+>7 string MACR Macro
+0 string 2278 Aster*x Version 2
+>29 byte 0x36 Words Document
+>29 byte 0x35 Graphic
+>29 byte 0x32 Spreadsheet
+>29 byte 0x38 Macro
+
diff --git a/usr.bin/file/Magdir/att3b b/usr.bin/file/Magdir/att3b
new file mode 100644
index 0000000..7723a7f
--- /dev/null
+++ b/usr.bin/file/Magdir/att3b
@@ -0,0 +1,39 @@
+
+#------------------------------------------------------------------------------
+# att3b: file(1) magic for AT&T 3B machines
+#
+# The `versions' should be un-commented if they work for you.
+# (Was the problem just one of endianness?)
+#
+# 3B20
+#
+0 beshort 0550 3b20 COFF executable
+>12 belong >0 not stripped
+#>22 beshort >0 - version %ld
+0 beshort 0551 3b20 COFF executable (TV)
+>12 belong >0 not stripped
+#>22 beshort >0 - version %ld
+#
+# WE32K
+#
+0 beshort 0560 WE32000 COFF
+>18 beshort ^00000020 object
+>18 beshort &00000020 executable
+>12 belong >0 not stripped
+>18 beshort ^00010000 N/A on 3b2/300 w/paging
+>18 beshort &00020000 32100 required
+>18 beshort &00040000 and MAU hardware required
+>20 beshort 0407 (impure)
+>20 beshort 0410 (pure)
+>20 beshort 0413 (demand paged)
+>20 beshort 0443 (target shared library)
+>22 beshort >0 - version %ld
+0 beshort 0561 WE32000 COFF executable (TV)
+>12 belong >0 not stripped
+#>18 beshort &00020000 - 32100 required
+#>18 beshort &00040000 and MAU hardware required
+#>22 beshort >0 - version %ld
+#
+# core file for 3b2
+0 string \000\004\036\212\200 3b2 core file
+>364 string >\0 of '%s'
diff --git a/usr.bin/file/Magdir/audio b/usr.bin/file/Magdir/audio
new file mode 100644
index 0000000..5433557
--- /dev/null
+++ b/usr.bin/file/Magdir/audio
@@ -0,0 +1,96 @@
+
+#------------------------------------------------------------------------------
+# audio: file(1) magic for sound formats (see also "iff")
+#
+# Jan Nicolai Langfeldt (janl@ifi.uio.no), Dan Quinlan (quinlan@yggdrasil.com),
+# and others
+#
+
+# Sun/NeXT audio data
+0 string .snd Sun/NeXT audio data:
+>12 belong 1 8-bit ISDN u-law,
+>12 belong 2 8-bit linear PCM [REF-PCM],
+>12 belong 3 16-bit linear PCM,
+>12 belong 4 24-bit linear PCM,
+>12 belong 5 32-bit linear PCM,
+>12 belong 6 32-bit IEEE floating point,
+>12 belong 7 64-bit IEEE floating point,
+>12 belong 23 8-bit ISDN u-law compressed (CCITT G.721 ADPCM voice data encoding),
+>12 belong 24 compressed (8-bit G.722 ADPCM)
+>12 belong 25 compressed (3-bit G.723 ADPCM),
+>12 belong 26 compressed (5-bit G.723 ADPCM),
+>12 belong 27 8-bit A-law,
+>20 belong 1 mono,
+>20 belong 2 stereo,
+>20 belong 4 quad,
+>16 belong >0 %d Hz
+
+# DEC systems (e.g. DECstation 5000) use a variant of the Sun/NeXT format
+# that uses little-endian encoding and has a different magic number
+0 lelong 0x0064732E DEC audio data:
+>12 lelong 1 8-bit ISDN u-law,
+>12 lelong 2 8-bit linear PCM [REF-PCM],
+>12 lelong 3 16-bit linear PCM,
+>12 lelong 4 24-bit linear PCM,
+>12 lelong 5 32-bit linear PCM,
+>12 lelong 6 32-bit IEEE floating point,
+>12 lelong 7 64-bit IEEE floating point,
+>12 lelong 23 8-bit ISDN u-law compressed (CCITT G.721 ADPCM voice data encoding),
+>20 lelong 1 mono,
+>20 lelong 2 stereo,
+>20 lelong 4 quad,
+>16 lelong >0 %d Hz
+
+# Creative Labs AUDIO stuff
+0 string MThd Standard MIDI data
+>9 byte >0 (format %d)
+>11 byte >1 using %d channels
+0 string CTMF Creative Music (CMF) data
+0 string SBI SoundBlaster instrument data
+0 string Creative\ Voice\ File Creative Labs voice data
+# is this next line right? it came this way...
+>19 byte 0x1A
+>23 byte >0 - version %d
+>22 byte >0 \b.%d
+
+# first entry is also the string "NTRK"
+0 belong 0x4e54524b MultiTrack sound data
+>4 belong x - version %ld
+
+# Microsoft WAVE format (*.wav)
+0 string RIFF Microsoft RIFF
+>8 string WAVE \b, WAVE audio data
+>>34 leshort >0 \b, %d bit
+>>22 leshort =1 \b, mono
+>>22 leshort =2 \b, stereo
+>>22 leshort >2 \b, %d channels
+>>24 lelong >0 %d Hz
+# AVI == Audio Video Interleave
+>8 string AVI\ \b, AVI data
+
+# Extended MOD format (*.emd) (Greg Roelofs, newt@uchicago.edu); NOT TESTED
+# [based on posting 940824 by "Dirk/Elastik", husberg@lehtori.cc.tut.fi]
+0 string EMOD Extended MOD sound data,
+>4 byte&0xf0 x version %d
+>4 byte&0x0f x \b.%d,
+>45 byte x %d instruments
+>83 byte 0 (module)
+>83 byte 1 (song)
+
+# Real Audio (Magic .ra\0375)
+0 belong 0x2e7261fd realaudio sound file
+
+# MTM/669/FAR/S3M/ULT/XM format checking [Aaron Eppert, aeppert@dialin.ind.net]
+# Oct 31, 1995
+0 string MTM MultiTracker Module sound file
+0 string if Composer 669 Module sound data
+0 string FAR Module sound data
+0 string MAS_U ULT(imate) Module sound data
+0x2c string SCRM ScreamTracker III Module sound data
+0 string Extended Module Extended Module sound data
+
+# Gravis UltraSound patches
+# From <ache@nagual.ru>
+
+0 string GF1PATCH110\0ID#000002\0 GUS patch
+0 string GF1PATCH100\0ID#000002\0 Old GUS patch
diff --git a/usr.bin/file/Magdir/blit b/usr.bin/file/Magdir/blit
new file mode 100644
index 0000000..7a470ed
--- /dev/null
+++ b/usr.bin/file/Magdir/blit
@@ -0,0 +1,19 @@
+
+#------------------------------------------------------------------------------
+# blit: file(1) magic for 68K Blit stuff as seen from 680x0 machine
+#
+# Note that this 0407 conflicts with several other a.out formats...
+#
+# XXX - should this be redone with "be" and "le", so that it works on
+# little-endian machines as well? If so, what's the deal with
+# "VAX-order" and "VAX-order2"?
+#
+#0 long 0407 68K Blit (standalone) executable
+#0 short 0407 VAX-order2 68K Blit (standalone) executable
+0 short 03401 VAX-order 68K Blit (standalone) executable
+0 long 0406 68k Blit mpx/mux executable
+0 short 0406 VAX-order2 68k Blit mpx/mux executable
+0 short 03001 VAX-order 68k Blit mpx/mux executable
+# Need more values for WE32 DMD executables.
+# Note that 0520 is the same as COFF
+#0 short 0520 tty630 layers executable
diff --git a/usr.bin/file/Magdir/bsdi b/usr.bin/file/Magdir/bsdi
new file mode 100644
index 0000000..2e3b646
--- /dev/null
+++ b/usr.bin/file/Magdir/bsdi
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# bsdi: file(1) magic for BSD/OS (from BSDI) objects
+#
+0 lelong 000000314 BSD/OS i386 compact demand paged executable
+>16 lelong >0 not stripped
+>32 byte 0x6a (uses shared libs)
diff --git a/usr.bin/file/Magdir/bzip b/usr.bin/file/Magdir/bzip
new file mode 100644
index 0000000..97692ce7
--- /dev/null
+++ b/usr.bin/file/Magdir/bzip
@@ -0,0 +1,14 @@
+# bzip a block-sorting file compressor
+# by Julian Seward <sewardj@cs.man.ac.uk> and others
+#
+0 string BZ bzip compressed data
+>2 byte x \b, version: %c
+>3 string =1 \b, compression block size 100k
+>3 string =2 \b, compression block size 200k
+>3 string =3 \b, compression block size 300k
+>3 string =4 \b, compression block size 400k
+>3 string =5 \b, compression block size 500k
+>3 string =6 \b, compression block size 600k
+>3 string =7 \b, compression block size 700k
+>3 string =8 \b, compression block size 800k
+>3 string =9 \b, compression block size 900k
diff --git a/usr.bin/file/Magdir/c-lang b/usr.bin/file/Magdir/c-lang
new file mode 100644
index 0000000..1b01475
--- /dev/null
+++ b/usr.bin/file/Magdir/c-lang
@@ -0,0 +1,13 @@
+
+#------------------------------------------------------------------------------
+# c-lang: file(1) magic for C programs (or REXX)
+#
+
+# XPM icons (Greg Roelofs, newt@uchicago.edu)
+# if you uncomment "/*" for C/REXX below, also uncomment this entry
+#0 string /*\ XPM\ */ X pixmap image data
+
+# this first will upset you if you're a PL/1 shop...
+# in which case rm it; ascmagic will catch real C programs
+#0 string /* C or REXX program text
+0 string // C++ program text
diff --git a/usr.bin/file/Magdir/chi b/usr.bin/file/Magdir/chi
new file mode 100644
index 0000000..ee450f5
--- /dev/null
+++ b/usr.bin/file/Magdir/chi
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# chi: file(1) magic for ChiWriter files
+#
+0 string \\1cw\ ChiWriter file
+>5 string >\0 version %s
+0 string \\1cw ChiWriter file
diff --git a/usr.bin/file/Magdir/clipper b/usr.bin/file/Magdir/clipper
new file mode 100644
index 0000000..c325cb8
--- /dev/null
+++ b/usr.bin/file/Magdir/clipper
@@ -0,0 +1,64 @@
+
+#------------------------------------------------------------------------------
+# clipper: file(1) magic for Intergraph (formerly Fairchild) Clipper.
+#
+# XXX - what byte order does the Clipper use?
+#
+# XXX - what's the "!" stuff:
+#
+# >18 short !074000,000000 C1 R1
+# >18 short !074000,004000 C2 R1
+# >18 short !074000,010000 C3 R1
+# >18 short !074000,074000 TEST
+#
+# I shall assume it's ANDing the field with the first value and
+# comparing it with the second, and rewrite it as:
+#
+# >18 short&074000 000000 C1 R1
+# >18 short&074000 004000 C2 R1
+# >18 short&074000 010000 C3 R1
+# >18 short&074000 074000 TEST
+#
+# as SVR3.1's "file" doesn't support anything of the "!074000,000000"
+# sort, nor does SunOS 4.x, so either it's something Intergraph added
+# in CLIX, or something AT&T added in SVR3.2 or later, or something
+# somebody else thought was a good idea; it's not documented in the
+# man page for this version of "magic", nor does it appear to be
+# implemented (at least not after I blew off the bogus code to turn
+# old-style "&"s into new-style "&"s, which just didn't work at all).
+#
+0 short 0575 CLIPPER COFF executable (VAX #)
+>20 short 0407 (impure)
+>20 short 0410 (5.2 compatible)
+>20 short 0411 (pure)
+>20 short 0413 (demand paged)
+>20 short 0443 (target shared library)
+>12 long >0 not stripped
+>22 short >0 - version %ld
+0 short 0577 CLIPPER COFF executable
+>18 short&074000 000000 C1 R1
+>18 short&074000 004000 C2 R1
+>18 short&074000 010000 C3 R1
+>18 short&074000 074000 TEST
+>20 short 0407 (impure)
+>20 short 0410 (pure)
+>20 short 0411 (separate I&D)
+>20 short 0413 (paged)
+>20 short 0443 (target shared library)
+>12 long >0 not stripped
+>22 short >0 - version %ld
+>48 long&01 01 alignment trap enabled
+>52 byte 1 -Ctnc
+>52 byte 2 -Ctsw
+>52 byte 3 -Ctpw
+>52 byte 4 -Ctcb
+>53 byte 1 -Cdnc
+>53 byte 2 -Cdsw
+>53 byte 3 -Cdpw
+>53 byte 4 -Cdcb
+>54 byte 1 -Csnc
+>54 byte 2 -Cssw
+>54 byte 3 -Cspw
+>54 byte 4 -Cscb
+4 string pipe CLIPPER instruction trace
+4 string prof CLIPPER instruction profile
diff --git a/usr.bin/file/Magdir/commands b/usr.bin/file/Magdir/commands
new file mode 100644
index 0000000..8a27607
--- /dev/null
+++ b/usr.bin/file/Magdir/commands
@@ -0,0 +1,75 @@
+
+#------------------------------------------------------------------------------
+# commands: file(1) magic for various shells and interpreters
+#
+0 string :\ shell archive or commands for antique kernel text
+0 string #!/bin/sh Bourne shell script text
+0 string #!\ /bin/sh Bourne shell script text
+0 string #!/bin/csh C shell script text
+0 string #!\ /bin/csh C shell script text
+# korn shell magic, sent by George Wu, gwu@clyde.att.com
+0 string #!/bin/ksh Korn shell script text
+0 string #!\ /bin/ksh Korn shell script text
+0 string #!/bin/tcsh Tenex C shell script text
+0 string #!\ /bin/tcsh Tenex C shell script text
+0 string #!/usr/local/tcsh Tenex C shell script text
+0 string #!\ /usr/local/tcsh Tenex C shell script text
+0 string #!/usr/local/bin/tcsh Tenex C shell script text
+0 string #!\ /usr/local/bin/tcsh Tenex C shell script text
+#
+# zsh/ash/ae/nawk/gawk magic from cameron@cs.unsw.oz.au (Cameron Simpson)
+0 string #!/usr/local/bin/zsh Paul Falstad's zsh
+0 string #!\ /usr/local/bin/zsh Paul Falstad's zsh
+0 string #!/usr/local/bin/ash Neil Brown's ash
+0 string #!\ /usr/local/bin/ash Neil Brown's ash
+0 string #!/usr/local/bin/ae Neil Brown's ae
+0 string #!\ /usr/local/bin/ae Neil Brown's ae
+0 string #!/bin/nawk new awk script text
+0 string #!\ /bin/nawk new awk script text
+0 string #!/usr/bin/nawk new awk script text
+0 string #!\ /usr/bin/nawk new awk script text
+0 string #!/usr/local/bin/nawk new awk script text
+0 string #!\ /usr/local/bin/nawk new awk script text
+0 string #!/bin/gawk GNU awk script text
+0 string #!\ /bin/gawk GNU awk script text
+0 string #!/usr/bin/gawk GNU awk script text
+0 string #!\ /usr/bin/gawk GNU awk script text
+0 string #!/usr/local/bin/gawk GNU awk script text
+0 string #!\ /usr/local/bin/gawk GNU awk script text
+#
+0 string #!/bin/awk awk commands text
+0 string #!\ /bin/awk awk commands text
+0 string #!/usr/bin/awk awk commands text
+0 string #!\ /usr/bin/awk awk commands text
+0 string BEGIN awk commands text
+
+# For Larry Wall's perl language. The ``eval'' line recognizes an
+# outrageously clever hack for USG systems.
+# Keith Waclena <keith@cerberus.uchicago.edu>
+0 string #!/bin/perl perl commands text
+0 string #!\ /bin/perl perl commands text
+0 string eval\ "exec\ /bin/perl perl commands text
+0 string #!/usr/bin/perl perl commands text
+0 string #!\ /usr/bin/perl perl commands text
+0 string eval\ "exec\ /usr/bin/perl perl commands text
+0 string #!/usr/local/bin/perl perl commands text
+0 string #!\ /usr/local/bin/perl perl commands text
+0 string eval\ "exec\ /usr/local/bin/perl perl commands text
+
+# AT&T Bell Labs' Plan 9 shell
+0 string #!/bin/rc Plan 9 rc shell script text
+0 string #!\ /bin/rc Plan 9 rc shell script text
+
+# bash shell magic, from Peter Tobias (tobias@server.et-inf.fho-emden.de)
+0 string #!/bin/bash Bourne-Again shell script text
+0 string #!\ /bin/bash Bourne-Again shell script text
+0 string #!/usr/local/bin/bash Bourne-Again shell script text
+0 string #!\ /usr/local/bin/bash Bourne-Again shell script text
+
+# generic shell magic
+0 string #!\ / a
+>3 string >\0 %s script text
+0 string #!/ a
+>2 string >\0 %s script text
+0 string #!\ commands text
+>3 string >\0 for %s
diff --git a/usr.bin/file/Magdir/compress b/usr.bin/file/Magdir/compress
new file mode 100644
index 0000000..a797f8f
--- /dev/null
+++ b/usr.bin/file/Magdir/compress
@@ -0,0 +1,92 @@
+
+#------------------------------------------------------------------------------
+# compress: file(1) magic for pure-compression formats (no archives)
+#
+# compress, gzip, pack, compact, huf, squeeze, crunch, freeze, yabba, etc.
+#
+# Formats for various forms of compressed data
+# Formats for "compress" proper have been moved into "compress.c",
+# because it tries to uncompress it to figure out what's inside.
+
+# standard unix compress
+0 string \037\235 compress'd data
+>2 byte&0x80 >0 block compressed
+>2 byte&0x1f x %d bits
+
+# gzip (GNU zip, not to be confused with Info-ZIP or PKWARE zip archiver)
+0 string \037\213 gzip compressed data
+>2 byte <8 \b, reserved method,
+>2 byte 8 \b, deflated,
+>3 byte &0x01 ASCII,
+>3 byte &0x02 continuation,
+>3 byte &0x04 extra field,
+>3 byte &0x08 original filename,
+>3 byte &0x10 comment,
+>3 byte &0x20 encrypted,
+>4 ledate x last modified: %s,
+>8 byte 2 max compression,
+>8 byte 4 max speed,
+>9 byte =0x00 os: MS-DOS
+>9 byte =0x01 os: Amiga
+>9 byte =0x02 os: VMS
+>9 byte =0x03 os: Unix
+>9 byte =0x05 os: Atari
+>9 byte =0x06 os: OS/2
+>9 byte =0x07 os: MacOS
+>9 byte =0x0A os: Tops/20
+>9 byte =0x0B os: Win/32
+
+# packed data, Huffman (minimum redundancy) codes on a byte-by-byte basis
+0 string \037\036 packed data
+>2 belong >1 \b, %d characters originally
+>2 belong =1 \b, %d character originally
+#
+# This magic number is byte-order-independent. XXX - Does that mean this
+# is big-endian, little-endian, either, or that you can't tell?
+# this short is valid for SunOS
+0 short 017437 old packed data
+
+# XXX - why *two* entries for "compacted data", one of which is
+# byte-order independent, and one of which is byte-order dependent?
+#
+0 short 0x1fff compacted data
+# This string is valid for SunOS (BE) and a matching "short" is listed
+# in the Ultrix (LE) magic file.
+0 string \377\037 compacted data
+0 short 0145405 huf output
+
+# Squeeze and Crunch...
+# These numbers were gleaned from the Unix versions of the programs to
+# handle these formats. Note that I can only uncrunch, not crunch, and
+# I didn't have a crunched file handy, so the crunch number is untested.
+# Keith Waclena <keith@cerberus.uchicago.edu>
+0 leshort 0x76FF squeezed data (CP/M, DOS)
+0 leshort 0x76FE crunched data (CP/M, DOS)
+
+# Freeze
+0 string \037\237 frozen file 2.1
+0 string \037\236 frozen file 1.0 (or gzip 0.5)
+
+# SCO compress -H (LZH)
+0 string \037\240 SCO compress -H (LZH) data
+
+# European GSM 06.10 is a provisional standard for full-rate speech
+# transcoding, prI-ETS 300 036, which uses RPE/LTP (residual pulse
+# excitation/long term prediction) coding at 13 kbit/s.
+#
+# There's only a magic nibble (4 bits); that nibble repeats every 33
+# bytes. This isn't suited for use, but maybe we can use it someday.
+#
+# This will cause very short GSM files to be declared as data and
+# mismatches to be declared as data too!
+#0 byte&0xF0 0xd0 data
+#>33 byte&0xF0 0xd0
+#>66 byte&0xF0 0xd0
+#>99 byte&0xF0 0xd0
+#>132 byte&0xF0 0xd0 GSM 06.10 compressed audio
+
+# Bzip from ulmo@Q.Net
+0 string BZ bzip compressed data,
+>2 byte x format v. %c,
+>3 byte x block size indicator %c
+
diff --git a/usr.bin/file/Magdir/convex b/usr.bin/file/Magdir/convex
new file mode 100644
index 0000000..b1235d7
--- /dev/null
+++ b/usr.bin/file/Magdir/convex
@@ -0,0 +1,69 @@
+#------------------------------------------------------------------------------
+# convex: file(1) magic for Convex boxes
+#
+# Convexes are big-endian.
+#
+# /*\
+# * Below are the magic numbers and tests added for Convex.
+# * Added at beginning, because they are expected to be used most.
+# \*/
+0 belong 0507 Convex old-style object
+>16 belong >0 not stripped
+0 belong 0513 Convex old-style demand paged executable
+>16 belong >0 not stripped
+0 belong 0515 Convex old-style pre-paged executable
+>16 belong >0 not stripped
+0 belong 0517 Convex old-style pre-paged, non-swapped executable
+>16 belong >0 not stripped
+0 belong 0x011257 Core file
+#
+# The following are a series of dump format magic numbers. Each one
+# corresponds to a drastically different dump format. The first on is
+# the original dump format on a 4.1 BSD or earlier file system. The
+# second marks the change between the 4.1 file system and the 4.2 file
+# system. The Third marks the changing of the block size from 1K
+# to 2K to be compatible with an IDC file system. The fourth indicates
+# a dump that is dependent on Convex Storage Manager, because data in
+# secondary storage is not physically contained within the dump.
+# The restore program uses these number to determine how the data is
+# to be extracted.
+#
+24 belong =60011 dump format, 4.1 BSD or earlier
+24 belong =60012 dump format, 4.2 or 4.3 BSD without IDC
+24 belong =60013 dump format, 4.2 or 4.3 BSD (IDC compatible)
+24 belong =60014 dump format, Convex Storage Manager by-reference dump
+#
+# what follows is a bunch of bit-mask checks on the flags field of the opthdr.
+# If there is no `=' sign, assume just checking for whether the bit is set?
+#
+0 belong 0601 Convex SOFF
+>88 belong&0x000f0000 =0x00000000 c1
+>88 belong &0x00010000 c2
+>88 belong &0x00020000 c2mp
+>88 belong &0x00040000 parallel
+>88 belong &0x00080000 intrinsic
+>88 belong &0x00000001 demand paged
+>88 belong &0x00000002 pre-paged
+>88 belong &0x00000004 non-swapped
+>88 belong &0x00000008 POSIX
+#
+>84 belong &0x80000000 executable
+>84 belong &0x40000000 object
+>84 belong&0x20000000 =0 not stripped
+>84 belong&0x18000000 =0x00000000 native fpmode
+>84 belong&0x18000000 =0x10000000 ieee fpmode
+>84 belong&0x18000000 =0x18000000 undefined fpmode
+#
+0 belong 0605 Convex SOFF core
+#
+0 belong 0607 Convex SOFF checkpoint
+>88 belong&0x000f0000 =0x00000000 c1
+>88 belong &0x00010000 c2
+>88 belong &0x00020000 c2mp
+>88 belong &0x00040000 parallel
+>88 belong &0x00080000 intrinsic
+>88 belong &0x00000008 POSIX
+#
+>84 belong&0x18000000 =0x00000000 native fpmode
+>84 belong&0x18000000 =0x10000000 ieee fpmode
+>84 belong&0x18000000 =0x18000000 undefined fpmode
diff --git a/usr.bin/file/Magdir/cpio b/usr.bin/file/Magdir/cpio
new file mode 100644
index 0000000..d1805cc
--- /dev/null
+++ b/usr.bin/file/Magdir/cpio
@@ -0,0 +1,16 @@
+#
+# Yes, the two "cpio archive" formats *are* supposed to just be "short".
+# The idea is to indicate archives produced on machines with the same
+# byte order as the machine running "file" with "cpio archive", and
+# to indicate archives produced on machines with the opposite byte order
+# from the machine running "file" with "byte-swapped cpio archive".
+#
+# The SVR4 "cpio(4)" hints that there are additional formats, but they
+# are defined as "short"s; I think all the new formats are
+# character-header formats, and thus are strings not numbers.
+#
+0 short 070707 cpio archive
+0 short 0143561 byte-swapped cpio archive
+0 string 070707 ASCII cpio archive (pre-SVR4 or odc)
+0 string 070701 ASCII cpio archive (SVR4 with no CRC)
+0 string 070702 ASCII cpio archive (SVR4 with CRC)
diff --git a/usr.bin/file/Magdir/database b/usr.bin/file/Magdir/database
new file mode 100644
index 0000000..146c310
--- /dev/null
+++ b/usr.bin/file/Magdir/database
@@ -0,0 +1,38 @@
+
+#------------------------------------------------------------------------------
+# database: file(1) magic for various databases
+#
+# extracted from header/code files by Graeme Wilford (eep2gw@ee.surrey.ac.uk)
+#
+#
+# GDBM magic numbers
+# Will be maintained as part of the GDBM distribution in the future.
+# <downsj@teeny.org>
+0 belong 0x13579ace GNU dbm 1.x or ndbm database, big endian
+0 lelong 0x13579ace GNU dbm 1.x or ndbm database, little endian
+0 string GDBM GNU dbm 2.x database
+#
+0 belong 0x061561 Berkeley DB Hash file
+>4 belong >0 (Version %d,
+>8 belong 1234 Little Endian,
+>8 belong 4321 Big Endian,
+>12 belong x Bucket Size %d,
+>16 belong x Bucket Shift %d,
+>20 belong x Directory Size %d,
+>24 belong x Segment Size %d,
+>28 belong x Segment Shift %d,
+>32 belong x Overflow Point %d,
+>36 belong x Last Freed %d,
+>40 belong x Max Bucket %d,
+>44 belong x High Mask 0x%x,
+>48 belong x Low Mask 0x%x,
+>52 belong x Fill Factor %d,
+>56 belong x Number of Keys %d)
+#
+#
+0 belong 0x053162 Berkeley DB Btree file
+>4 belong >0 (Version %d,
+>8 belong x Page Size %d,
+>12 belong x Free Page %d,
+>16 belong x Number of Records %d,
+>20 belong x Flags 0x%x)
diff --git a/usr.bin/file/Magdir/diamond b/usr.bin/file/Magdir/diamond
new file mode 100644
index 0000000..1abd01e
--- /dev/null
+++ b/usr.bin/file/Magdir/diamond
@@ -0,0 +1,11 @@
+
+#------------------------------------------------------------------------------
+# diamond: file(1) magic for Diamond system
+#
+# ... diamond is a multi-media mail and electronic conferencing system....
+#
+# XXX - I think it was either renamed Slate, or replaced by Slate....
+#
+# The full deal is too long...
+#0 string <list>\n<protocol\ bbn-multimedia-format> Diamond Multimedia Document
+0 string =<list>\n<protocol\ bbn-m Diamond Multimedia Document
diff --git a/usr.bin/file/Magdir/diff b/usr.bin/file/Magdir/diff
new file mode 100644
index 0000000..9e65146
--- /dev/null
+++ b/usr.bin/file/Magdir/diff
@@ -0,0 +1,8 @@
+
+#------------------------------------------------------------------------------
+# diff: file(1) magic for diff(1) output
+#
+0 string diff\ 'diff' output text
+0 string ***\ 'diff' output text
+0 string Only\ in\ 'diff' output text
+0 string Common\ subdirectories:\ 'diff' output text
diff --git a/usr.bin/file/Magdir/digital b/usr.bin/file/Magdir/digital
new file mode 100644
index 0000000..f4ebbff
--- /dev/null
+++ b/usr.bin/file/Magdir/digital
@@ -0,0 +1,41 @@
+# Digital UNIX - Info
+#
+0 string ^!<arch>\n_______64E Alpha archive
+>22 string X -- out of date
+#
+# Alpha COFF Based Executables
+# The stripped stuff really needs to be an 8 byte (64 bit) compare,
+# but this works
+0 leshort 0x183 COFF format alpha
+>22 leshort&020000 &010000 sharable library,
+>22 leshort&020000 ^010000 dynamically linked,
+>24 leshort 0410 pure
+>24 leshort 0413 demand paged
+>8 lelong >0 executable or object module, not stripped
+>8 lelong 0
+>>12 lelong 0 executable or object module, stripped
+>>12 lelong >0 executable or object module, not stripped
+>27 byte >0 - version %d.
+>26 byte >0 %d-
+>28 leshort >0 %d
+#
+# The next is incomplete, we could tell more about this format,
+# but its not worth it.
+0 leshort 0x188 Alpha compressed COFF
+0 leshort 0x18f Alpha u-code object
+#
+#
+# Some other interesting Digital formats,
+0 string \377\377\177 ddis/ddif
+0 string \377\377\174 ddis/dots archive
+0 string \377\377\176 ddis/dtif table data
+0 string \033c\033 LN03 output
+0 long 04553207 X image
+#
+0 string !<PDF>!\n profiling data file
+#
+# Locale data tables (MIPS and Alpha).
+#
+0 short 0x0501 locale data table
+>6 short 0x24 for MIPS
+>6 short 0x40 for Alpha
diff --git a/usr.bin/file/Magdir/ditroff b/usr.bin/file/Magdir/ditroff
new file mode 100644
index 0000000..1fff178
--- /dev/null
+++ b/usr.bin/file/Magdir/ditroff
@@ -0,0 +1,4 @@
+# Magic numbers for ditroff intermediate language
+0 string x\ T\ cat titroff output for the C/A/T text
+0 string x\ T\ ps titroff output for PostScript
+0 string x\ T titroff output text
diff --git a/usr.bin/file/Magdir/dump b/usr.bin/file/Magdir/dump
new file mode 100644
index 0000000..628ead8
--- /dev/null
+++ b/usr.bin/file/Magdir/dump
@@ -0,0 +1,81 @@
+
+#------------------------------------------------------------------------------
+# dump: file(1) magic for dump file format--for new and old dump filesystems
+#
+# We specify both byte orders in order to recognize byte-swapped dumps.
+#
+24 belong 60012 new-fs dump file (big endian),
+>4 bedate x Previous dump %s,
+>8 bedate x This dump %s,
+>12 belong >0 Volume %ld,
+>692 belong 0 Level zero, type:
+>692 belong >0 Level %d, type:
+>0 belong 1 tape header,
+>0 belong 2 beginning of file record,
+>0 belong 3 map of inodes on tape,
+>0 belong 4 continuation of file record,
+>0 belong 5 end of volume,
+>0 belong 6 map of inodes deleted,
+>0 belong 7 end of medium (for floppy),
+>676 string >\0 Label %s,
+>696 string >\0 Filesystem %s,
+>760 string >\0 Device %s,
+>824 string >\0 Host %s,
+>888 belong >0 Flags %x
+
+24 belong 60011 old-fs dump file (big endian),
+#>4 bedate x Previous dump %s,
+#>8 bedate x This dump %s,
+>12 belong >0 Volume %ld,
+>692 belong 0 Level zero, type:
+>692 belong >0 Level %d, type:
+>0 belong 1 tape header,
+>0 belong 2 beginning of file record,
+>0 belong 3 map of inodes on tape,
+>0 belong 4 continuation of file record,
+>0 belong 5 end of volume,
+>0 belong 6 map of inodes deleted,
+>0 belong 7 end of medium (for floppy),
+>676 string >\0 Label %s,
+>696 string >\0 Filesystem %s,
+>760 string >\0 Device %s,
+>824 string >\0 Host %s,
+>888 belong >0 Flags %x
+
+24 lelong 60012 new-fs dump file (little endian),
+>4 ledate x This dump %s,
+>8 ledate x Previous dump %s,
+>12 lelong >0 Volume %ld,
+>692 lelong 0 Level zero, type:
+>692 lelong >0 Level %d, type:
+>0 lelong 1 tape header,
+>0 lelong 2 beginning of file record,
+>0 lelong 3 map of inodes on tape,
+>0 lelong 4 continuation of file record,
+>0 lelong 5 end of volume,
+>0 lelong 6 map of inodes deleted,
+>0 lelong 7 end of medium (for floppy),
+>676 string >\0 Label %s,
+>696 string >\0 Filesystem %s,
+>760 string >\0 Device %s,
+>824 string >\0 Host %s,
+>888 lelong >0 Flags %x
+
+24 lelong 60011 old-fs dump file (little endian),
+#>4 ledate x Previous dump %s,
+#>8 ledate x This dump %s,
+>12 lelong >0 Volume %ld,
+>692 lelong 0 Level zero, type:
+>692 lelong >0 Level %d, type:
+>0 lelong 1 tape header,
+>0 lelong 2 beginning of file record,
+>0 lelong 3 map of inodes on tape,
+>0 lelong 4 continuation of file record,
+>0 lelong 5 end of volume,
+>0 lelong 6 map of inodes deleted,
+>0 lelong 7 end of medium (for floppy),
+>676 string >\0 Label %s,
+>696 string >\0 Filesystem %s,
+>760 string >\0 Device %s,
+>824 string >\0 Host %s,
+>888 lelong >0 Flags %x
diff --git a/usr.bin/file/Magdir/elf b/usr.bin/file/Magdir/elf
new file mode 100644
index 0000000..58f4f36
--- /dev/null
+++ b/usr.bin/file/Magdir/elf
@@ -0,0 +1,76 @@
+
+#------------------------------------------------------------------------------
+# elf: file(1) magic for ELF executables
+#
+# We have to check the byte order flag to see what byte order all the
+# other stuff in the header is in.
+#
+# MIPS RS3000 may also be for MIPS RS2000.
+# What're the correct byte orders for the nCUBE and the Fujitsu VPP500?
+#
+# updated by Daniel Quinlan (quinlan@yggdrasil.com)
+0 string \177ELF ELF
+>4 byte 0 invalid class
+>4 byte 1 32-bit
+>4 byte 2 64-bit
+>5 byte 0 invalid byte order
+>5 byte 1 LSB
+>>16 leshort 0 no file type,
+>>16 leshort 1 relocatable,
+>>16 leshort 2 executable,
+>>16 leshort 3 shared object,
+# Core handling from Peter Tobias <tobias@server.et-inf.fho-emden.de>
+>>16 leshort 4 core file
+>>>400 lelong >0 (signal %d),
+>>16 leshort &0xff00 processor-specific,
+>>18 leshort 0 no machine,
+>>18 leshort 1 AT&T WE32100 - invalid byte order,
+>>18 leshort 2 SPARC - invalid byte order,
+>>18 leshort 3 Intel 80386,
+>>18 leshort 4 Motorola 68000 - invalid byte order,
+>>18 leshort 5 Motorola 88000 - invalid byte order,
+>>18 leshort 6 Intel 80486,
+>>18 leshort 7 Intel 80860,
+>>18 leshort 8 MIPS RS3000_BE - invalid byte order,
+>>18 leshort 9 Amdahl - invalid byte order,
+>>18 leshort 10 MIPS RS3000_LE,
+>>18 leshort 11 RS6000 - invalid byte order,
+>>18 leshort 15 PA_RISC - invalid byte order,
+>>18 leshort 16 nCUBE,
+>>18 leshort 17 VPP500,
+>>18 leshort 18 SPARC32PLUS,
+>>18 leshort 20 PowerPC,
+>>18 leshort 0x9026 Alpha,
+>>20 lelong 0 invalid version
+>>20 lelong 1 version 1
+>>36 lelong 1 MathCoPro/FPU/MAU Required
+>5 byte 2 MSB
+>>16 beshort 0 no file type,
+>>16 beshort 1 relocatable,
+>>16 beshort 2 executable,
+>>16 beshort 3 shared object,
+>>16 beshort 4 core file,
+>>>400 lelong >0 (signal %d),
+>>16 beshort &0xff00 processor-specific,
+>>18 beshort 0 no machine,
+>>18 beshort 1 AT&T WE32100,
+>>18 beshort 2 SPARC,
+>>18 beshort 3 Intel 80386 - invalid byte order,
+>>18 beshort 4 Motorola 68000,
+>>18 beshort 5 Motorola 88000,
+>>18 beshort 6 Intel 80486 - invalid byte order,
+>>18 beshort 7 Intel 80860,
+>>18 beshort 8 MIPS RS3000_BE,
+>>18 beshort 9 Amdahl,
+>>18 beshort 10 MIPS RS3000_LE - invalid byte order,
+>>18 beshort 11 RS6000,
+>>18 beshort 15 PA_RISC,
+>>18 beshort 16 nCUBE,
+>>18 beshort 17 VPP500,
+>>18 beshort 18 SPARC32PLUS,
+>>18 beshort 20 PowerPC,
+>>18 beshort 0x9026 Alpha,
+>>20 belong 0 invalid version
+>>20 belong 1 version 1
+>>36 belong 1 MathCoPro/FPU/MAU Required
+>8 string >\0 (%s)
diff --git a/usr.bin/file/Magdir/encore b/usr.bin/file/Magdir/encore
new file mode 100644
index 0000000..63cb5d4
--- /dev/null
+++ b/usr.bin/file/Magdir/encore
@@ -0,0 +1,21 @@
+
+#------------------------------------------------------------------------------
+# encore: file(1) magic for Encore machines
+#
+# XXX - needs to have the byte order specified (NS32K was little-endian,
+# dunno whether they run the 88K in little-endian mode or not).
+#
+0 short 0x154 Encore
+>20 short 0x107 executable
+>20 short 0x108 pure executable
+>20 short 0x10b demand-paged executable
+>20 short 0x10f unsupported executable
+>12 long >0 not stripped
+>22 short >0 - version %ld
+>22 short 0 -
+#>4 date x stamp %s
+0 short 0x155 Encore unsupported executable
+>12 long >0 not stripped
+>22 short >0 - version %ld
+>22 short 0 -
+#>4 date x stamp %s
diff --git a/usr.bin/file/Magdir/figlet b/usr.bin/file/Magdir/figlet
new file mode 100644
index 0000000..ac650b1
--- /dev/null
+++ b/usr.bin/file/Magdir/figlet
@@ -0,0 +1,9 @@
+
+#------------------------------------------------------------------------------
+# figlet: file(1) magic for FIGlet fonts and controlfiles
+# From figmagic supplied with Figlet version 2.2
+#
+0 string flf FIGlet font
+>3 string >2a version %-2.2s
+0 string flc FIGlet controlfile
+>3 string >2a version %-2.2s
diff --git a/usr.bin/file/Magdir/filesystems b/usr.bin/file/Magdir/filesystems
new file mode 100644
index 0000000..125250d
--- /dev/null
+++ b/usr.bin/file/Magdir/filesystems
@@ -0,0 +1,6 @@
+
+#------------------------------------------------------------------------------
+# filesystems: file(1) magic for different filesystems
+#
+0x438 leshort 0xEF53 Linux/i386 ext2 filesystem
+0 string \366\366\366\366 PC formatted floppy with no filesystem
diff --git a/usr.bin/file/Magdir/floppy.raw b/usr.bin/file/Magdir/floppy.raw
new file mode 100644
index 0000000..75091b9
--- /dev/null
+++ b/usr.bin/file/Magdir/floppy.raw
@@ -0,0 +1 @@
+0 string \366\366\366\366 Formatted floppy w/ no filesystem data
diff --git a/usr.bin/file/Magdir/fonts b/usr.bin/file/Magdir/fonts
new file mode 100644
index 0000000..dd7907f
--- /dev/null
+++ b/usr.bin/file/Magdir/fonts
@@ -0,0 +1,26 @@
+
+#------------------------------------------------------------------------------
+# fonts: file(1) magic for font data
+#
+0 string FONT ASCII vfont text
+0 short 0436 Berkeley vfont data
+0 short 017001 byte-swapped Berkeley vfont data
+
+# PostScript fonts (must precede "printer" entries), quinlan@yggdrasil.com
+0 string %!PS-AdobeFont-1.0 PostScript Type 1 font text
+>20 string >\0 (%s)
+6 string %!PS-AdobeFont-1.0 PostScript Type 1 font program data
+
+# X11 font files in SNF (Server Natural Format) format
+0 belong 00000004 X11 SNF font data, MSB first
+0 lelong 00000004 X11 SNF font data, LSB first
+
+# X11 Bitmap Distribution Format, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string STARTFONT\040 X11 BDF font text
+
+# X11 fonts, from Daniel Quinlan (quinlan@yggdrasil.com)
+# PCF must come before SGI additions ("MIPSEL MIPS-II COFF" collides)
+0 string \001fcp X11 Portable Compiled Font data
+>12 byte 0x02 \b, LSB first
+>12 byte 0x0a \b, MSB first
+0 string D1.0\015 X11 Speedo font data
diff --git a/usr.bin/file/Magdir/frame b/usr.bin/file/Magdir/frame
new file mode 100644
index 0000000..e2c10f1
--- /dev/null
+++ b/usr.bin/file/Magdir/frame
@@ -0,0 +1,37 @@
+
+#------------------------------------------------------------------------------
+# frame: file(1) magic for FrameMaker files
+#
+# This stuff came on a FrameMaker demo tape, most of which is
+# copyright, but this file is "published" as witness the following:
+#
+0 string \<MakerFile FrameMaker document
+>11 string 5.0 (5.0
+>11 string 4.0 (4.0
+>11 string 3.0 (3.0
+>11 string 2.0 (2.0
+>11 string 1.0 (1.0
+>14 byte x %c)
+0 string \<MIFFile FrameMaker MIF (ASCII) file
+>9 string 4.0 (4.0)
+>9 string 3.0 (3.0)
+>9 string 2.0 (2.0)
+>9 string 1.0 (1.x)
+0 string \<MakerDictionary FrameMaker Dictionary text
+>17 string 3.0 (3.0)
+>17 string 2.0 (2.0)
+>17 string 1.0 (1.x)
+0 string \<MakerScreenFont FrameMaker Font file
+>17 string 1.01 (%s)
+0 string \<MML FrameMaker MML file
+0 string \<BookFile FrameMaker Book file
+>10 string 3.0 (3.0
+>10 string 2.0 (2.0
+>10 string 1.0 (1.0
+>13 byte x %c)
+# XXX - this book entry should be verified, if you find one, uncomment this
+#0 string \<Book\ FrameMaker Book (ASCII) file
+#>6 string 3.0 (3.0)
+#>6 string 2.0 (2.0)
+#>6 string 1.0 (1.0)
+0 string \<Maker Intermediate Print File FrameMaker IPL file
diff --git a/usr.bin/file/Magdir/freebsd b/usr.bin/file/Magdir/freebsd
new file mode 100644
index 0000000..2370c25
--- /dev/null
+++ b/usr.bin/file/Magdir/freebsd
@@ -0,0 +1,130 @@
+
+#------------------------------------------------------------------------------
+# freebsd: file(1) magic for FreeBSD objects
+#
+# All new-style FreeBSD magic numbers are in host byte order (i.e.,
+# little-endian on x86).
+#
+# XXX - this comes from the file "freebsd" in a recent FreeBSD version of
+# "file"; it, and the NetBSD stuff in "netbsd", appear to use different
+# schemes for distinguishing between executable images, shared libraries,
+# and object files.
+#
+# FreeBSD says:
+#
+# Regardless of whether it's pure, demand-paged, or none of the
+# above:
+#
+# if the entry point is < 4096, then it's a shared library if
+# the "has run-time loader information" bit is set, and is
+# position-independent if the "is position-independent" bit
+# is set;
+#
+# if the entry point is >= 4096 (or >4095, same thing), then it's
+# an executable, and is dynamically-linked if the "has run-time
+# loader information" bit is set.
+#
+# On x86, NetBSD says:
+#
+# If it's neither pure nor demand-paged:
+#
+# if it has the "has run-time loader information" bit set, it's
+# a dynamically-linked executable;
+#
+# if it doesn't have that bit set, then:
+#
+# if it has the "is position-independent" bit set, it's
+# position-independent;
+#
+# if the entry point is non-zero, it's an executable, otherwise
+# it's an object file.
+#
+# If it's pure:
+#
+# if it has the "has run-time loader information" bit set, it's
+# a dynamically-linked executable, otherwise it's just an
+# executable.
+#
+# If it's demand-paged:
+#
+# if it has the "has run-time loader information" bit set,
+# then:
+#
+# if the entry point is < 4096, it's a shared library;
+#
+# if the entry point is = 4096 or > 4096 (i.e., >= 4096),
+# it's a dynamically-linked executable);
+#
+# if it doesn't have the "has run-time loader information" bit
+# set, then it's just an executable.
+#
+# (On non-x86, NetBSD does much the same thing, except that it uses
+# 8192 on 68K - except for "68k4k", which is presumably "68K with 4K
+# pages - SPARC, and MIPS, presumably because Sun-3's and Sun-4's
+# had 8K pages; dunno about MIPS.)
+#
+# I suspect the two will differ only in perverse and uninteresting cases
+# ("shared" libraries that aren't demand-paged and whose pages probably
+# won't actually be shared, executables with entry points <4096).
+#
+# I leave it to those more familiar with FreeBSD and NetBSD to figure out
+# what the right answer is (although using ">4095", FreeBSD-style, is
+# probably better than separately checking for "=4096" and ">4096",
+# NetBSD-style). (The old "netbsd" file analyzed FreeBSD demand paged
+# executables using the NetBSD technique.)
+#
+0 lelong&0377777777 041400407 FreeBSD/i386
+>20 lelong <4096
+>>3 byte&0xC0 &0x80 shared library
+>>3 byte&0xC0 0x40 PIC object
+>>3 byte&0xC0 0x00 object
+>20 lelong >4095
+>>3 byte&0x80 0x80 dynamically linked executable
+>>3 byte&0x80 0x00 executable
+>16 lelong >0 not stripped
+
+0 lelong&0377777777 041400410 FreeBSD/i386 pure
+>20 lelong <4096
+>>3 byte&0xC0 &0x80 shared library
+>>3 byte&0xC0 0x40 PIC object
+>>3 byte&0xC0 0x00 object
+>20 lelong >4095
+>>3 byte&0x80 0x80 dynamically linked executable
+>>3 byte&0x80 0x00 executable
+>16 lelong >0 not stripped
+
+0 lelong&0377777777 041400413 FreeBSD/i386 demand paged
+>20 lelong <4096
+>>3 byte&0xC0 &0x80 shared library
+>>3 byte&0xC0 0x40 PIC object
+>>3 byte&0xC0 0x00 object
+>20 lelong >4095
+>>3 byte&0x80 0x80 dynamically linked executable
+>>3 byte&0x80 0x00 executable
+>16 lelong >0 not stripped
+
+0 lelong&0377777777 041400314 FreeBSD/i386 compact demand paged
+>20 lelong <4096
+>>3 byte&0xC0 &0x80 shared library
+>>3 byte&0xC0 0x40 PIC object
+>>3 byte&0xC0 0x00 object
+>20 lelong >4095
+>>3 byte&0x80 0x80 dynamically linked executable
+>>3 byte&0x80 0x00 executable
+>16 lelong >0 not stripped
+
+# XXX gross hack to identify core files
+# cores start with a struct tss; we take advantage of the following:
+# byte 7: highest byte of the kernel stack pointer, always 0xfe
+# 8/9: kernel (ring 0) ss value, always 0x0010
+# 10 - 27: ring 1 and 2 ss/esp, unused, thus always 0
+# 28: low order byte of the current PTD entry, always 0 since the
+# PTD is page-aligned
+#
+7 string \357\020\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 FreeBSD/i386 a.out core file
+>1039 string >\0 from '%s'
+
+# /var/run/ld.so.hints
+# What are you laughing about?
+0 lelong 011421044151 ld.so hints file
+>4 lelong >0 (version %d)
diff --git a/usr.bin/file/Magdir/gzip b/usr.bin/file/Magdir/gzip
new file mode 100644
index 0000000..a19a654
--- /dev/null
+++ b/usr.bin/file/Magdir/gzip
@@ -0,0 +1,21 @@
+0 string \037\213 gzip compressed data
+>2 byte <8 - reserved method
+>2 byte 8 - deflate method
+>3 byte &0x01 , ascii
+>3 byte &0x02 , continuation
+>3 byte &0x04 , extra field
+>3 byte &0x08 , original file name
+>3 byte &0x10 , comment
+>3 byte &0x20 , encrypted
+>4 ledate x , last modified: %s
+>8 byte 2 , max compression
+>8 byte 4 , max speed
+>9 byte =0x00 os: MS/DOS
+>9 byte =0x01 os: Amiga
+>9 byte =0x02 os: VMS
+>9 byte =0x03 os: Unix
+>9 byte =0x05 os: Atari
+>9 byte =0x06 os: OS/2
+>9 byte =0x07 os: MacOS
+>9 byte =0x0A os: Tops/20
+>9 byte =0x0B os: Win/32
diff --git a/usr.bin/file/Magdir/hp b/usr.bin/file/Magdir/hp
new file mode 100644
index 0000000..e1efdbd
--- /dev/null
+++ b/usr.bin/file/Magdir/hp
@@ -0,0 +1,228 @@
+
+#------------------------------------------------------------------------------
+# hp: file(1) magic for Hewlett Packard machines (see also "printer")
+#
+# XXX - somebody should figure out whether any byte order needs to be
+# applied to the "TML" stuff; I'm assuming the Apollo stuff is
+# big-endian as it was mostly 68K-based.
+#
+# I think the 500 series was the old stack-based machines, running a
+# UNIX environment atop the "SUN kernel"; dunno whether it was
+# big-endian or little-endian.
+#
+# Daniel Quinlan (quinlan@yggdrasil.com): hp200 machines are 68010 based;
+# hp300 are 68020+68881 based; hp400 are also 68k. The following basic
+# HP magic is useful for reference, but using "long" magic is a better
+# practice in order to avoid collisions.
+#
+# Guy Harris (guy@netapp.com): some additions to this list came from
+# HP-UX 10.0's "/usr/include/sys/unistd.h" (68030, 68040, PA-RISC 1.1,
+# 1.2, and 2.0). The 1.2 and 2.0 stuff isn't in the HP-UX 10.0
+# "/etc/magic", though, except for the "archive file relocatable library"
+# stuff, and the 68030 and 68040 stuff isn't there at all - are they not
+# used in executables, or have they just not yet updated "/etc/magic"
+# completely?
+#
+# 0 beshort 200 hp200 (68010) BSD binary
+# 0 beshort 300 hp300 (68020+68881) BSD binary
+# 0 beshort 0x20c hp200/300 HP-UX binary
+# 0 beshort 0x20d hp400 (68030) HP-UX binary
+# 0 beshort 0x20e hp400 (68040?) HP-UX binary
+# 0 beshort 0x20b PA-RISC1.0 HP-UX binary
+# 0 beshort 0x210 PA-RISC1.1 HP-UX binary
+# 0 beshort 0x211 PA-RISC1.2 HP-UX binary
+# 0 beshort 0x214 PA-RISC2.0 HP-UX binary
+
+#
+# The "misc" stuff needs a byte order; the archives look suspiciously
+# like the old 177545 archives (0xff65 = 0177545).
+#
+#### Old Apollo stuff
+0 beshort 0627 Apollo m68k COFF executable
+>18 beshort ^040000 not stripped
+>22 beshort >0 - version %ld
+0 beshort 0624 apollo a88k COFF executable
+>18 beshort ^040000 not stripped
+>22 beshort >0 - version %ld
+0 long 01203604016 TML 0123 byte-order format
+0 long 01702407010 TML 1032 byte-order format
+0 long 01003405017 TML 2301 byte-order format
+0 long 01602007412 TML 3210 byte-order format
+#### PA-RISC
+0 belong 0x02100106 PA-RISC1.1 relocatable object
+0 belong 0x02100107 PA-RISC1.1 executable
+>168 belong &=0x00000004 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x02100108 PA-RISC1.1 shared executable
+>168 belong&0x4 0x4 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x0210010b PA-RISC1.1 demand-load executable
+>168 belong&0x4 0x4 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x0210010e PA-RISC1.1 shared library
+>96 belong >0 - not stripped
+
+0 belong 0x0210010d PA-RISC1.1 dynamic load library
+>96 belong >0 - not stripped
+
+#### 800
+0 belong 0x020b0106 PA-RISC1.0 relocatable object
+
+0 belong 0x020b0107 PA-RISC1.0 executable
+>168 belong&0x4 0x4 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x020b0108 PA-RISC1.0 shared executable
+>168 belong&0x4 0x4 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x020b010b PA-RISC1.0 demand-load executable
+>168 belong&0x4 0x4 dynamically linked
+>(144) belong 0x054ef630 dynamically linked
+>96 belong >0 - not stripped
+
+0 belong 0x020b010e PA-RISC1.0 shared library
+>96 belong >0 - not stripped
+
+0 belong 0x020b010d PA-RISC1.0 dynamic load library
+>96 belong >0 - not stripped
+
+0 belong 0x213c6172 archive file
+>68 belong 0x020b0619 - PA-RISC1.0 relocatable library
+>68 belong 0x02100619 - PA-RISC1.1 relocatable library
+>68 belong 0x02110619 - PA-RISC1.2 relocatable library
+>68 belong 0x02140619 - PA-RISC2.0 relocatable library
+
+#### 500
+0 long 0x02080106 HP s500 relocatable executable
+>16 long >0 - version %ld
+
+0 long 0x02080107 HP s500 executable
+>16 long >0 - version %ld
+
+0 long 0x02080108 HP s500 pure executable
+>16 long >0 - version %ld
+
+#### 200
+0 belong 0x020c0108 HP s200 pure executable
+>4 beshort >0 - version %ld
+>8 belong &0x80000000 save fp regs
+>8 belong &0x40000000 dynamically linked
+>8 belong &0x20000000 debuggable
+>36 belong >0 not stripped
+
+0 belong 0x020c0107 HP s200 executable
+>4 beshort >0 - version %ld
+>8 belong &0x80000000 save fp regs
+>8 belong &0x40000000 dynamically linked
+>8 belong &0x20000000 debuggable
+>36 belong >0 not stripped
+
+0 belong 0x020c010b HP s200 demand-load executable
+>4 beshort >0 - version %ld
+>8 belong &0x80000000 save fp regs
+>8 belong &0x40000000 dynamically linked
+>8 belong &0x20000000 debuggable
+>36 belong >0 not stripped
+
+0 belong 0x020c0106 HP s200 relocatable executable
+>4 beshort >0 - version %ld
+>6 beshort >0 - highwater %d
+>8 belong &0x80000000 save fp regs
+>8 belong &0x20000000 debuggable
+>8 belong &0x10000000 PIC
+
+0 belong 0x020a0108 HP s200 (2.x release) pure executable
+>4 beshort >0 - version %ld
+>36 belong >0 not stripped
+
+0 belong 0x020a0107 HP s200 (2.x release) executable
+>4 beshort >0 - version %ld
+>36 belong >0 not stripped
+
+0 belong 0x020c010e HP s200 shared library
+>4 beshort >0 - version %ld
+>6 beshort >0 - highwater %d
+>36 belong >0 not stripped
+
+0 belong 0x020c010d HP s200 dynamic load library
+>4 beshort >0 - version %ld
+>6 beshort >0 - highwater %d
+>36 belong >0 not stripped
+
+#### MISC
+0 long 0x0000ff65 HP old archive
+0 long 0x020aff65 HP s200 old archive
+0 long 0x020cff65 HP s200 old archive
+0 long 0x0208ff65 HP s500 old archive
+
+0 long 0x015821a6 HP core file
+
+0 long 0x4da7eee8 HP-WINDOWS font
+>8 byte >0 - version %ld
+0 string Bitmapfile HP Bitmapfile
+
+0 string IMGfile CIS compimg HP Bitmapfile
+# XXX - see "lif"
+#0 short 0x8000 lif file
+0 long 0x020c010c compiled Lisp
+
+0 string msgcat01 HP NLS message catalog,
+>8 long >0 %d messages
+
+# addendum to /etc/magic with HP-48sx file-types by phk@data.fls.dk 1jan92
+0 string HPHP48- HP48 binary
+>7 byte >0 - Rev %c
+>8 short 0x1129 (ADR)
+>8 short 0x3329 (REAL)
+>8 short 0x5529 (LREAL)
+>8 short 0x7729 (COMPLX)
+>8 short 0x9d29 (LCOMPLX)
+>8 short 0xbf29 (CHAR)
+>8 short 0xe829 (ARRAY)
+>8 short 0x0a2a (LNKARRAY)
+>8 short 0x2c2a (STRING)
+>8 short 0x4e2a (HXS)
+>8 short 0x742a (LIST)
+>8 short 0x962a (DIR)
+>8 short 0xb82a (ALG)
+>8 short 0xda2a (UNIT)
+>8 short 0xfc2a (TAGGED)
+>8 short 0x1e2b (GROB)
+>8 short 0x402b (LIB)
+>8 short 0x622b (BACKUP)
+>8 short 0x882b (LIBDATA)
+>8 short 0x9d2d (PROG)
+>8 short 0xcc2d (CODE)
+>8 short 0x482e (GNAME)
+>8 short 0x6d2e (LNAME)
+>8 short 0x922e (XLIB)
+0 string %%HP: HP48 text
+>6 string T(0) - T(0)
+>6 string T(1) - T(1)
+>6 string T(2) - T(2)
+>6 string T(3) - T(3)
+>10 string A(D) A(D)
+>10 string A(R) A(R)
+>10 string A(G) A(G)
+>14 string F(.) F(.);
+>14 string F(,) F(,);
+
+# hpBSD magic numbers
+0 beshort 200 hp200 (68010) BSD
+>2 beshort 0407 impure binary
+>2 beshort 0410 read-only binary
+>2 beshort 0413 demand paged binary
+0 beshort 300 hp300 (68020+68881) BSD
+>2 beshort 0407 impure binary
+>2 beshort 0410 read-only binary
+>2 beshort 0413 demand paged binary
+
diff --git a/usr.bin/file/Magdir/ibm370 b/usr.bin/file/Magdir/ibm370
new file mode 100644
index 0000000..8cd9da2
--- /dev/null
+++ b/usr.bin/file/Magdir/ibm370
@@ -0,0 +1,47 @@
+
+#------------------------------------------------------------------------------
+# ibm370: file(1) magic for IBM 370 and compatibles.
+#
+# "ibm370" said that 0x15d == 0535 was "ibm 370 pure executable".
+# What the heck *is* "USS/370"?
+# AIX 4.1's "/etc/magic" has
+#
+# 0 short 0535 370 sysV executable
+# >12 long >0 not stripped
+# >22 short >0 - version %d
+# >30 long >0 - 5.2 format
+# 0 short 0530 370 sysV pure executable
+# >12 long >0 not stripped
+# >22 short >0 - version %d
+# >30 long >0 - 5.2 format
+#
+# instead of the "USS/370" versions of the same magic numbers.
+#
+0 beshort 0537 370 XA sysV executable
+>12 belong >0 not stripped
+>22 beshort >0 - version %d
+>30 belong >0 - 5.2 format
+0 beshort 0532 370 XA sysV pure executable
+>12 belong >0 not stripped
+>22 beshort >0 - version %d
+>30 belong >0 - 5.2 format
+0 beshort 054001 370 sysV pure executable
+>12 belong >0 not stripped
+0 beshort 055001 370 XA sysV pure executable
+>12 belong >0 not stripped
+0 beshort 056401 370 sysV executable
+>12 belong >0 not stripped
+0 beshort 057401 370 XA sysV executable
+>12 belong >0 not stripped
+0 beshort 0531 SVR2 executable (Amdahl-UTS)
+>12 belong >0 not stripped
+>24 belong >0 - version %ld
+0 beshort 0534 SVR2 pure executable (Amdahl-UTS)
+>12 belong >0 not stripped
+>24 belong >0 - version %ld
+0 beshort 0530 SVR2 pure executable (USS/370)
+>12 belong >0 not stripped
+>24 belong >0 - version %ld
+0 beshort 0535 SVR2 executable (USS/370)
+>12 belong >0 not stripped
+>24 belong >0 - version %ld
diff --git a/usr.bin/file/Magdir/ibm6000 b/usr.bin/file/Magdir/ibm6000
new file mode 100644
index 0000000..8e1077b
--- /dev/null
+++ b/usr.bin/file/Magdir/ibm6000
@@ -0,0 +1,17 @@
+
+#------------------------------------------------------------------------------
+# ibm6000: file(1) magic for RS/6000 and the RT PC.
+#
+0 beshort 0x01df executable (RISC System/6000 V3.1) or obj module
+>12 belong >0 not stripped
+# Breaks sun4 statically linked execs.
+#0 beshort 0x0103 executable (RT Version 2) or obj module
+#>2 byte 0x50 pure
+#>28 belong >0 not stripped
+#>6 beshort >0 - version %ld
+0 beshort 0x0104 shared library
+0 beshort 0x0105 ctab data
+0 beshort 0xfe04 structured file
+0 string 0xabcdef AIX message catalog
+0 belong 0x000001f9 AIX compiled message catalog
+0 string \<aiaff> archive
diff --git a/usr.bin/file/Magdir/iff b/usr.bin/file/Magdir/iff
new file mode 100644
index 0000000..68d1b79
--- /dev/null
+++ b/usr.bin/file/Magdir/iff
@@ -0,0 +1,28 @@
+
+#------------------------------------------------------------------------------
+# iff: file(1) magic for Interchange File Format (see also "audio" & "images")
+#
+# Daniel Quinlan (quinlan@yggdrasil.com) -- IFF was designed by Electronic
+# Arts for file interchange. It has also been used by Apple, SGI, and
+# especially Commodore-Amiga.
+#
+# IFF files begin with an 8 byte FORM header, followed by a 4 character
+# FORM type, which is followed by the first chunk in the FORM.
+
+0 string FORM IFF data
+#>4 belong x \b, FORM is %d bytes long
+# audio formats
+>8 string AIFF \b, AIFF audio
+>8 string AIFC \b, AIFF-C compressed audio
+>8 string 8SVX \b, 8SVX 8-bit sampled sound voice
+>8 string SAMP \b, SAMP sampled audio
+# image formats
+>8 string ILBMBMHD \b, ILBM interleaved image
+>>20 beshort x \b, %d x
+>>22 beshort x %d
+>8 string RGBN \b, RGBN 12-bit RGB image
+>8 string RGB8 \b, RGB8 24-bit RGB image
+>8 string DR2D \b, DR2D 2-D object
+>8 string TDDD \b, TDDD 3-D rendering
+# other formats
+>8 string FTXT \b, FTXT formatted text
diff --git a/usr.bin/file/Magdir/imagen b/usr.bin/file/Magdir/imagen
new file mode 100644
index 0000000..5fa4f6c
--- /dev/null
+++ b/usr.bin/file/Magdir/imagen
@@ -0,0 +1,14 @@
+# Tell file about magic for IMAGEN printer-ready files:
+0 string @document( Imagen printer
+# this only works if "language xxx" is first item in Imagen header.
+>10 string language\ impress (imPRESS data)
+>10 string language\ daisy (daisywheel text)
+>10 string language\ diablo (daisywheel text)
+>10 string language\ printer (line printer emulation)
+>10 string language\ tektronix (Tektronix 4014 emulation)
+# Add any other languages that your Imagen uses - remember
+# to keep the word `text' if the file is human-readable.
+#
+# Now magic for IMAGEN font files...
+0 string Rast RST-format raster font data
+>45 string >0 face %
diff --git a/usr.bin/file/Magdir/images b/usr.bin/file/Magdir/images
new file mode 100644
index 0000000..271b169
--- /dev/null
+++ b/usr.bin/file/Magdir/images
@@ -0,0 +1,236 @@
+
+#------------------------------------------------------------------------------
+# images: file(1) magic for image formats (see also "iff")
+#
+# originally from jef@helios.ee.lbl.gov (Jef Poskanzer),
+# additions by janl@ifi.uio.no as well as others. Jan also suggested
+# merging several one- and two-line files into here.
+#
+# little magic: PCX (first byte is 0x0a)
+# no magic: Targa
+
+# PBMPLUS images
+# The next byte following the magic is always whitespace.
+0 string P1 PBM image text
+0 string P2 PGM image text
+0 string P3 PPM image text
+0 string P4 PBM "rawbits" image data
+0 string P5 PGM "rawbits" image data
+0 string P6 PPM "rawbits" image data
+
+# NIFF (Navy Interchange File Format, a modification of TIFF) images
+0 string IIN1 NIFF image data
+
+# Tag Image File Format, from Daniel Quinlan (quinlan@yggdrasil.com)
+# The second word of TIFF files is the TIFF version number, 42, which has
+# never changed. The TIFF specification recommends testing for it.
+0 string MM\x00\x2a TIFF image data, big-endian
+0 string II\x2a\x00 TIFF image data, little-endian
+
+# PNG [Portable Network Graphics, or "PNG's Not GIF"] images
+# (Greg Roelofs, newt@uchicago.edu)
+#
+# 137 P N G \r \n ^Z \n [4-byte length] H E A D [HEAD data] [HEAD crc] ...
+#
+0 string \x89PNG PNG image data,
+>4 belong !0x0d0a1a0a CORRUPTED,
+>16 belong x %ld x
+>20 belong x %ld,
+>24 byte x %d-bit
+>25 byte 0 grayscale,
+>25 byte 2 \b/color RGB,
+>25 byte 3 colormap,
+>25 byte 4 gray+alpha,
+>25 byte 6 \b/color RGBA,
+#>26 byte 0 deflate/32K,
+>28 byte 0 non-interlaced
+>28 byte 1 interlaced
+
+# GIF
+0 string GIF8 GIF image data
+>4 string 7a \b, version 8%s,
+>4 string 9a \b, version 8%s,
+>6 leshort >0 %hd x
+>8 leshort >0 %hd,
+#>10 byte &0x80 color mapped,
+#>10 byte&0x07 =0x00 2 colors
+#>10 byte&0x07 =0x01 4 colors
+#>10 byte&0x07 =0x02 8 colors
+#>10 byte&0x07 =0x03 16 colors
+#>10 byte&0x07 =0x04 32 colors
+#>10 byte&0x07 =0x05 64 colors
+#>10 byte&0x07 =0x06 128 colors
+#>10 byte&0x07 =0x07 256 colors
+
+# ITC (CMU WM) raster files. It is essentially a byte-reversed Sun raster,
+# 1 plane, no encoding.
+0 string \361\0\100\273 CMU window manager raster image data
+>4 lelong >0 %d x
+>8 lelong >0 %d,
+>12 lelong >0 %d-bit
+
+# Magick Image File Format
+0 string id=ImageMagick MIFF image data
+
+# Artisan
+0 long 1123028772 Artisan image data
+>4 long 1 \b, rectangular 24-bit
+>4 long 2 \b, rectangular 8-bit with colormap
+>4 long 3 \b, rectangular 32-bit (24-bit with matte)
+
+# FIG (Facility for Interactive Generation of figures), an object-based format
+0 string #FIG FIG image text
+>5 string x \b, version %.3s
+
+# PHIGS
+0 string ARF_BEGARF PHIGS clear text archive
+0 string @(#)SunPHIGS SunPHIGS
+# version number follows, in the form m.n
+>40 string SunBin binary
+>32 string archive archive
+
+# GKS (Graphics Kernel System)
+0 string GKSM GKS Metafile
+>24 string SunGKS \b, SunGKS
+
+# CGM image files
+0 string BEGMF clear text Computer Graphics Metafile
+# XXX - questionable magic
+0 beshort&0xffe0 0x0020 binary Computer Graphics Metafile
+0 beshort 0x3020 character Computer Graphics Metafile
+
+# MGR bitmaps (Michael Haardt, u31b3hs@pool.informatik.rwth-aachen.de)
+0 string yz MGR bitmap, modern format, 8-bit aligned
+0 string zz MGR bitmap, old format, 1-bit deep, 16-bit aligned
+0 string xz MGR bitmap, old format, 1-bit deep, 32-bit aligned
+0 string yx MGR bitmap, modern format, squeezed
+
+# Fuzzy Bitmap (FBM) images
+0 string %bitmap\0 FBM image data
+>30 long 0x31 \b, mono
+>30 long 0x33 \b, color
+
+# facsimile data
+1 string PC\ Research,\ Inc group 3 fax data
+>29 byte 0 \b, normal resolution (204x98 DPI)
+>29 byte 1 \b, fine resolution (204x196 DPI)
+
+# JPEG images
+# SunOS 5.5.1 had
+#
+# 0 string \377\330\377\340 JPEG file
+# 0 string \377\330\377\356 JPG file
+#
+# both of which turn into "JPEG image data" here.
+#
+0 beshort 0xffd8 JPEG image data
+>6 string JFIF \b, JFIF standard
+# HSI is Handmade Software's proprietary JPEG encoding scheme
+0 string hsi1 JPEG image data, HSI proprietary
+
+# PC bitmaps (OS/2, Windoze BMP files) (Greg Roelofs, newt@uchicago.edu)
+0 string BM PC bitmap data
+>14 leshort 12 \b, OS/2 1.x format
+>>18 leshort x \b, %d x
+>>20 leshort x %d
+>14 leshort 64 \b, OS/2 2.x format
+>>18 leshort x \b, %d x
+>>20 leshort x %d
+>14 leshort 40 \b, Windows 3.x format
+>>18 lelong x \b, %d x
+>>22 lelong x %d x
+>>28 leshort x %d
+0 string IC PC icon data
+0 string PI PC pointer image data
+0 string CI PC color icon data
+0 string CP PC color pointer image data
+# Conflicts with other entries [BABYL]
+#0 string BA PC bitmap array data
+
+# XPM icons (Greg Roelofs, newt@uchicago.edu)
+# note possible collision with C/REXX entry in c-lang; currently commented out
+0 string /*\ XPM\ */ X pixmap image text
+
+# Utah Raster Toolkit RLE images (janl@ifi.uio.no)
+0 leshort 0xcc52 RLE image data,
+>6 leshort x %d x
+>8 leshort x %d
+>2 leshort >0 \b, lower left corner: %d
+>4 leshort >0 \b, lower right corner: %d
+>10 byte&0x1 =0x1 \b, clear first
+>10 byte&0x2 =0x2 \b, no background
+>10 byte&0x4 =0x4 \b, alpha channel
+>10 byte&0x8 =0x8 \b, comment
+>11 byte >0 \b, %d color channels
+>12 byte >0 \b, %d bits per pixel
+>13 byte >0 \b, %d color map channels
+
+# image file format (Robert Potter, potter@cs.rochester.edu)
+0 string Imagefile\ version- iff image data
+# this adds the whole header (inc. version number), informative but longish
+>10 string >\0 %s
+
+# Sun raster images, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 belong 0x59a66a95 Sun raster image data
+>4 belong >0 \b, %d x
+>8 belong >0 %d,
+>12 belong >0 %d-bit,
+#>16 belong >0 %d bytes long,
+>20 belong 0 old format,
+#>20 belong 1 standard,
+>20 belong 2 compressed,
+>20 belong 3 RGB,
+>20 belong 4 TIFF,
+>20 belong 5 IFF,
+>20 belong 0xffff reserved for testing,
+>24 belong 0 no colormap
+>24 belong 1 RGB colormap
+>24 belong 2 raw colormap
+#>28 belong >0 colormap is %d bytes long
+
+# SGI image file format, from Daniel Quinlan (quinlan@yggdrasil.com)
+# file://sgi.com/graphics/SGIIMAGESPEC
+0 beshort 474 SGI image data
+#>2 byte 0 \b, verbatim
+>2 byte 1 \b, RLE
+#>3 byte 1 \b, normal precision
+>3 byte 2 \b, high precision
+>4 beshort x \b, %d-D
+>6 beshort x \b, %d x
+>8 beshort x %d
+>10 beshort x \b, %d channel
+>10 beshort !1 \bs
+>80 string >0 \b, "%s"
+
+0 string IT01 FIT image data
+>4 belong x \b, %d x
+>8 belong x %d x
+>12 belong x %d
+#
+0 string IT02 FIT image data
+>4 belong x \b, %d x
+>8 belong x %d x
+>12 belong x %d
+#
+2048 string PCD_IPI Kodak Photo CD image pack file
+0 string PCD_OPA Kodak Photo CD overview pack file
+
+# FITS format. Jeff Uphoff <juphoff@tarsier.cv.nrao.edu>
+# FITS is the Flexible Image Transport System, the de facto standard for
+# data and image transfer, storage, etc., for the astronomical community.
+# (FITS floating point formats are big-endian.)
+0 string SIMPLE\ \ = FITS image data
+>109 string 8 \b, 8-bit, character or unsigned binary integer
+>108 string 16 \b, 16-bit, two's complement binary integer
+>107 string \ 32 \b, 32-bit, two's complement binary integer
+>107 string -32 \b, 32-bit, floating point, single precision
+>107 string -64 \b, 64-bit, floating point, double precision
+
+# other images
+0 string This\ is\ a\ BitMap\ file Lisp Machine bit-array-file
+0 string !! Bennet Yee's "face" format
+
+# From SunOS 5.5.1 "/etc/magic" - appeared right before Sun raster image
+# stuff.
+#
+0 beshort 0x1010 PEX Binary Archive
diff --git a/usr.bin/file/Magdir/intel b/usr.bin/file/Magdir/intel
new file mode 100644
index 0000000..d450e26
--- /dev/null
+++ b/usr.bin/file/Magdir/intel
@@ -0,0 +1,35 @@
+
+#------------------------------------------------------------------------------
+# intel: file(1) magic for x86 Unix
+#
+# Various flavors of x86 UNIX executable/object (other than Xenix, which
+# is in "microsoft"). DOS is in "msdos"; the ambitious soul can do
+# Windows as well.
+#
+# Windows NT belongs elsewhere, as you need x86 and MIPS and Alpha and
+# whatever comes next (HP-PA Hummingbird?). OS/2 may also go elsewhere
+# as well, if, as, and when IBM makes it portable.
+#
+# The `versions' should be un-commented if they work for you.
+# (Was the problem just one of endianness?)
+#
+0 leshort 0502 basic-16 executable
+>12 lelong >0 not stripped
+#>22 leshort >0 - version %ld
+0 leshort 0503 basic-16 executable (TV)
+>12 lelong >0 not stripped
+#>22 leshort >0 - version %ld
+0 leshort 0510 x86 executable
+>12 lelong >0 not stripped
+0 leshort 0511 x86 executable (TV)
+>12 lelong >0 not stripped
+0 leshort =0512 iAPX 286 executable small model (COFF)
+>12 lelong >0 not stripped
+#>22 leshort >0 - version %ld
+0 leshort =0522 iAPX 286 executable large model (COFF)
+>12 lelong >0 not stripped
+#>22 leshort >0 - version %ld
+# SGI labeled the next entry as "iAPX 386 executable" --Dan Quinlan
+0 leshort =0514 80386 COFF executable
+>12 lelong >0 not stripped
+>22 leshort >0 - version %ld
diff --git a/usr.bin/file/Magdir/interleaf b/usr.bin/file/Magdir/interleaf
new file mode 100644
index 0000000..3eea3cf
--- /dev/null
+++ b/usr.bin/file/Magdir/interleaf
@@ -0,0 +1,8 @@
+
+#------------------------------------------------------------------------------
+# interleaf: file(1) magic for InterLeaf TPS:
+#
+0 string =\210OPS Interleaf saved data
+0 string =<!OPS Interleaf document text
+>5 string ,\ Version\ = \b, version
+>>17 string >\0 %.3s
diff --git a/usr.bin/file/Magdir/iris b/usr.bin/file/Magdir/iris
new file mode 100644
index 0000000..952a5f1
--- /dev/null
+++ b/usr.bin/file/Magdir/iris
@@ -0,0 +1,57 @@
+#
+# magic.iris: Magic for mips from an iris4d
+#
+# Dunno what byte-order munging is needed; all of SGI's *current*
+# machines and OSes run in big-endian mode on the MIPS machines,
+# as far as I know, but they do have the MIPSEB and MIPSEL stuff
+# here....
+#
+0 short 0x0160 mipseb
+>20 short 0407 executable
+>20 short 0410 pure
+>20 short 0413 demand paged
+>8 long >0 not stripped
+>8 long 0 stripped
+>22 byte >0 - version %ld.
+>23 byte >0 %ld
+0 short 0x0162 mipsel
+>20 short 0407 executable
+>20 short 0410 pure
+>20 short 0413 demand paged
+>8 long >0 not stripped
+>8 long 0 stripped
+>23 byte >0 - version %ld.
+>22 byte >0 %ld
+0 short 0x6001 swapped mipseb
+>20 short 03401 executable
+>20 short 04001 pure
+>20 short 05401 demand paged
+>8 long >0 not stripped
+>8 long 0 stripped
+>22 byte >0 - version %ld.
+>23 byte >0 %ld
+0 short 0x6201 swapped mipsel
+>20 short 03401 executable
+>20 short 04001 pure
+>20 short 05401 demand paged
+>8 long >0 not stripped
+>8 long 0 stripped
+>22 byte >0 - version %ld.
+>23 byte >0 %ld
+0 short 0x180 mipseb ucode
+0 short 0x182 mipsel ucode
+#
+# IRIX core format version 1 (from /usr/include/core.out.h)
+0 long 0xdeadadb0 IRIX core dump
+>4 long 1 of
+>16 string >\0 '%s'
+#
+# Archives - This handles archive subtypes
+#
+0 string !<arch>\n__________E MIPS archive
+>20 string U with mipsucode members
+>21 string L with mipsel members
+>21 string B with mipseb members
+>19 string L and a EL hash table
+>19 string B and a EB hash table
+>22 string X -- out of date
diff --git a/usr.bin/file/Magdir/island b/usr.bin/file/Magdir/island
new file mode 100644
index 0000000..9903cdd
--- /dev/null
+++ b/usr.bin/file/Magdir/island
@@ -0,0 +1,9 @@
+
+#------------------------------------------------------------------------------
+# island: file(1) magic for IslandWite/IslandDraw, from SunOS 5.5.1
+# "/etc/magic":
+# From: guy@netapp.com (Guy Harris)
+#
+4 string pgscriptver IslandWrite document
+13 string DrawFile IslandDraw document
+
diff --git a/usr.bin/file/Magdir/ispell b/usr.bin/file/Magdir/ispell
new file mode 100644
index 0000000..3c6bcdc
--- /dev/null
+++ b/usr.bin/file/Magdir/ispell
@@ -0,0 +1,54 @@
+
+#------------------------------------------------------------------------------
+# ispell: file(1) magic for ispell
+#
+# Ispell 3.0 has a magic of 0x9601 and ispell 3.1 has 0x9602. This magic
+# will match 0x9600 through 0x9603 in *both* little endian and big endian.
+# (No other current magic entries collide.)
+#
+# Updated by Daniel Quinlan (quinlan@yggdrasil.com)
+#
+0 leshort&0xFFFC 0x9600 little endian ispell
+>0 byte 0 hash file (?),
+>0 byte 1 3.0 hash file,
+>0 byte 2 3.1 hash file,
+>0 byte 3 hash file (?),
+>2 leshort 0x00 8-bit, no capitalization, 26 flags
+>2 leshort 0x01 7-bit, no capitalization, 26 flags
+>2 leshort 0x02 8-bit, capitalization, 26 flags
+>2 leshort 0x03 7-bit, capitalization, 26 flags
+>2 leshort 0x04 8-bit, no capitalization, 52 flags
+>2 leshort 0x05 7-bit, no capitalization, 52 flags
+>2 leshort 0x06 8-bit, capitalization, 52 flags
+>2 leshort 0x07 7-bit, capitalization, 52 flags
+>2 leshort 0x08 8-bit, no capitalization, 128 flags
+>2 leshort 0x09 7-bit, no capitalization, 128 flags
+>2 leshort 0x0A 8-bit, capitalization, 128 flags
+>2 leshort 0x0B 7-bit, capitalization, 128 flags
+>2 leshort 0x0C 8-bit, no capitalization, 256 flags
+>2 leshort 0x0D 7-bit, no capitalization, 256 flags
+>2 leshort 0x0E 8-bit, capitalization, 256 flags
+>2 leshort 0x0F 7-bit, capitalization, 256 flags
+>4 leshort >0 and %d string characters
+0 beshort&0xFFFC 0x9600 big endian ispell
+>1 byte 0 hash file (?),
+>1 byte 1 3.0 hash file,
+>1 byte 2 3.1 hash file,
+>1 byte 3 hash file (?),
+>2 beshort 0x00 8-bit, no capitalization, 26 flags
+>2 beshort 0x01 7-bit, no capitalization, 26 flags
+>2 beshort 0x02 8-bit, capitalization, 26 flags
+>2 beshort 0x03 7-bit, capitalization, 26 flags
+>2 beshort 0x04 8-bit, no capitalization, 52 flags
+>2 beshort 0x05 7-bit, no capitalization, 52 flags
+>2 beshort 0x06 8-bit, capitalization, 52 flags
+>2 beshort 0x07 7-bit, capitalization, 52 flags
+>2 beshort 0x08 8-bit, no capitalization, 128 flags
+>2 beshort 0x09 7-bit, no capitalization, 128 flags
+>2 beshort 0x0A 8-bit, capitalization, 128 flags
+>2 beshort 0x0B 7-bit, capitalization, 128 flags
+>2 beshort 0x0C 8-bit, no capitalization, 256 flags
+>2 beshort 0x0D 7-bit, no capitalization, 256 flags
+>2 beshort 0x0E 8-bit, capitalization, 256 flags
+>2 beshort 0x0F 7-bit, capitalization, 256 flags
+>4 beshort >0 and %d string characters
diff --git a/usr.bin/file/Magdir/java b/usr.bin/file/Magdir/java
new file mode 100644
index 0000000..219f93e
--- /dev/null
+++ b/usr.bin/file/Magdir/java
@@ -0,0 +1,13 @@
+#------------------------------------------------------------
+# Java ByteCode
+# From Larry Schwimmer (schwim@cs.stanford.edu)
+0 belong 0xcafebabe
+>4 belong 0x0003002d Java bytecode
+#
+# java: file(1) magic for java compiled classes
+#
+
+0 belong 0xCafeBabe compiled java class data,
+>4 beshort x version %d.
+>6 beshort x \b%d
+
diff --git a/usr.bin/file/Magdir/karma b/usr.bin/file/Magdir/karma
new file mode 100644
index 0000000..e256abf
--- /dev/null
+++ b/usr.bin/file/Magdir/karma
@@ -0,0 +1,8 @@
+
+#------------------------------------------------------------------------------
+# karma: file(1) magic for Karma data files
+#
+# From <rgooch@atnf.csiro.au>
+
+0 string KarmaRHD Version Karma Data Structure Version
+>16 long x %lu
diff --git a/usr.bin/file/Magdir/lex b/usr.bin/file/Magdir/lex
new file mode 100644
index 0000000..7b6d0f7
--- /dev/null
+++ b/usr.bin/file/Magdir/lex
@@ -0,0 +1,11 @@
+
+#------------------------------------------------------------------------------
+# lex: file(1) magic for lex
+#
+# derived empirically, your offsets may vary!
+53 string yyprevious C program text (from lex)
+>3 string >\0 for %s
+# C program text from GNU flex, from Daniel Quinlan <quinlan@yggdrasil.com>
+21 string generated\ by\ flex C program text (from flex)
+# lex description file, from Daniel Quinlan <quinlan@yggdrasil.com>
+0 string %{ lex description text
diff --git a/usr.bin/file/Magdir/lif b/usr.bin/file/Magdir/lif
new file mode 100644
index 0000000..f6d7901
--- /dev/null
+++ b/usr.bin/file/Magdir/lif
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# lif: file(1) magic for lif
+#
+# XXX - byte order? (Probably beshort, Daniel Quinlan <quinlan@yggdrasil.com>)
+#
+0 short 0x8000 lif file
diff --git a/usr.bin/file/Magdir/linux b/usr.bin/file/Magdir/linux
new file mode 100644
index 0000000..75a2a2b
--- /dev/null
+++ b/usr.bin/file/Magdir/linux
@@ -0,0 +1,73 @@
+
+#------------------------------------------------------------------------------
+# linux: file(1) magic for Linux files
+#
+# Values for Linux/i386 binaries, from Daniel Quinlan <quinlan@yggdrasil.com>
+# The following basic Linux magic is useful for reference, but using
+# "long" magic is a better practice in order to avoid collisions.
+#
+# 2 leshort 100 Linux/i386
+# >0 leshort 0407 impure executable (OMAGIC)
+# >0 leshort 0410 pure executable (NMAGIC)
+# >0 leshort 0413 demand-paged executable (ZMAGIC)
+# >0 leshort 0314 demand-paged executable (QMAGIC)
+#
+0 lelong 0x00640107 Linux/i386 impure executable (OMAGIC)
+>16 lelong 0 \b, stripped
+0 lelong 0x00640108 Linux/i386 pure executable (NMAGIC)
+>16 lelong 0 \b, stripped
+0 lelong 0x0064010b Linux/i386 demand-paged executable (ZMAGIC)
+>16 lelong 0 \b, stripped
+0 lelong 0x006400cc Linux/i386 demand-paged executable (QMAGIC)
+>16 lelong 0 \b, stripped
+#
+0 string \007\001\000 Linux/i386 object file
+>20 lelong >0x1020 \b, DLL library
+# message catalogs, from Mitchum DSouza <m.dsouza@mrc-apu.cam.ac.uk>
+0 string *nazgul* Linux compiled message catalog
+>8 lelong >0 \b, version %ld
+# core dump file, from Bill Reynolds <bill@goshawk.lanl.gov>
+216 lelong 0421 Linux/i386 core file
+>220 string >\0 of '%s'
+>200 lelong >0 (signal %d)
+#
+# LILO boot/chain loaders, from Daniel Quinlan <quinlan@yggdrasil.com>
+# this can be overridden by the DOS executable (COM) entry
+2 string LILO Linux/i386 LILO boot/chain loader
+#
+# Debian Packages, from Peter Tobias <tobias@server.et-inf.fho-emden.de>
+0 string 0.9
+>8 byte 0x0a Debian Binary Package
+>>3 byte >0 \b, created by dpkg 0.9%c
+>>4 byte >0 pl%c
+# PSF fonts, from H. Peter Anvin <hpa@yggdrasil.com>
+0 leshort 0x0436 Linux/i386 PC Screen Font data,
+>2 byte 0 256 characters, no directory,
+>2 byte 1 512 characters, no directory,
+>2 byte 2 256 characters, Unicode directory,
+>2 byte 3 512 characters, Unicode directory,
+>3 byte >0 8x%d
+# Linux swap file, from Daniel Quinlan <quinlan@yggdrasil.com>
+4086 string SWAP-SPACE Linux/i386 swap file
+# ECOFF magic for OSF/1 and Linux (only tested under Linux though)
+#
+# from Erik Troan (ewt@redhat.com) examining od dumps, so this
+# could be wrong
+# updated by David Mosberger (davidm@azstarnet.com) based on
+# GNU BFD and MIPS info found below.
+#
+0 leshort 0x0183 ECOFF alpha
+>24 leshort 0407 executable
+>24 leshort 0410 pure
+>24 leshort 0413 demand paged
+>8 long >0 not stripped
+>8 long 0 stripped
+>23 leshort >0 - version %ld.
+# linux Kernel images version 1.3.80 - ?
+# from Axel Kohlmeyer <akohlmey@rincewind.chemie.uni-ulm.de>
+0 belong 0xb8c0078e Linux/x86 kernel image,
+>0x048c byte 0x31
+>>0x048c string x version %s
+>0x0493 byte 0x31
+>>0x0493 string x version %s
+#
diff --git a/usr.bin/file/Magdir/lisp b/usr.bin/file/Magdir/lisp
new file mode 100644
index 0000000..ac4ba77
--- /dev/null
+++ b/usr.bin/file/Magdir/lisp
@@ -0,0 +1,10 @@
+
+#------------------------------------------------------------------------------
+# lisp: file(1) magic for lisp programs
+#
+# various lisp types, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string ;; Lisp/Scheme program text
+# Emacs 18 - this is always correct, but not very magical.
+0 string \012( byte-compiled Emacs-Lisp program data
+# Emacs 19
+0 string ;ELC\023\000\000\000 byte-compiled Emacs-Lisp program data
diff --git a/usr.bin/file/Magdir/mach b/usr.bin/file/Magdir/mach
new file mode 100644
index 0000000..308325e
--- /dev/null
+++ b/usr.bin/file/Magdir/mach
@@ -0,0 +1,38 @@
+#------------------------------------------------------------------------------
+# mach file description
+#
+0 belong 0xcafebabe mach-o fat file
+>4 belong 1 with 1 architecture
+>4 belong >1
+>>4 belong x with %ld architectures
+#
+0 belong 0xfeedface mach-o
+>12 belong 1 object
+>12 belong 2 executable
+>12 belong 3 shared library
+>12 belong 4 core
+>12 belong 5 preload executable
+>12 belong >5
+>>12 belong x filetype=%ld
+>4 belong <0
+>>4 belong x architecture=%ld
+>4 belong 1 vax
+>4 belong 2 romp
+>4 belong 3 architecture=3
+>4 belong 4 ns32032
+>4 belong 5 ns32332
+>4 belong 6 for m68k architecture
+>4 belong 7 i386
+>4 belong 8 mips
+>4 belong 9 ns32532
+>4 belong 10 architecture=10
+>4 belong 11 hp pa-risc
+>4 belong 12 acorn
+>4 belong 13 m88k
+>4 belong 14 sparc
+>4 belong 15 i860-big
+>4 belong 16 i860
+>4 belong 17 rs6000
+>4 belong 18 powerPC
+>4 belong >18
+>>4 belong x architecture=%ld
diff --git a/usr.bin/file/Magdir/magic b/usr.bin/file/Magdir/magic
new file mode 100644
index 0000000..4a639c6
--- /dev/null
+++ b/usr.bin/file/Magdir/magic
@@ -0,0 +1,5 @@
+
+#------------------------------------------------------------------------------
+# magic: file(1) magic for magic files
+#
+0 string #\ Magic magic text file for file(1) cmd
diff --git a/usr.bin/file/Magdir/mail.news b/usr.bin/file/Magdir/mail.news
new file mode 100644
index 0000000..bd3fd2d
--- /dev/null
+++ b/usr.bin/file/Magdir/mail.news
@@ -0,0 +1,21 @@
+
+#------------------------------------------------------------------------------
+# mail.news: file(1) magic for mail and news
+#
+# Unfortunately, saved netnews also has From line added in some news software.
+#0 string From mail text
+# There are tests to ascmagic.c to cope with mail and news.
+0 string Relay-Version: old news text
+0 string #!\ rnews batched news text
+0 string N#!\ rnews mailed, batched news text
+0 string Forward\ to mail forwarding text
+0 string Pipe\ to mail piping text
+0 string Return-Path: smtp mail text
+0 string Path: news text
+0 string Xref: news text
+0 string From: news or mail text
+0 string Article saved news text
+0 string BABYL Emacs RMAIL text
+0 string Received: RFC 822 mail text
+0 string MIME-Version: MIME entity text
+0 string Content- MIME entity text
diff --git a/usr.bin/file/Magdir/microsoft b/usr.bin/file/Magdir/microsoft
new file mode 100644
index 0000000..74d1daf
--- /dev/null
+++ b/usr.bin/file/Magdir/microsoft
@@ -0,0 +1,72 @@
+
+#------------------------------------------------------------------------------
+# microsoft: file(1) magic for Microsoft Xenix
+#
+# "Middle model" stuff, and "Xenix 8086 relocatable or 80286 small
+# model" lifted from "magic.xenix", with comment "derived empirically;
+# treat as folklore until proven"
+#
+# "small model", "large model", "huge model" stuff lifted from XXX
+#
+# XXX - "x.out" collides with PDP-11 archives
+#
+0 string core core file (Xenix)
+0 byte 0x80 8086 relocatable (Microsoft)
+0 leshort 0xff65 x.out
+>2 string __.SYMDEF randomized
+>0 byte x archive
+0 leshort 0x206 Microsoft a.out
+>8 leshort 1 Middle model
+>0x1e leshort &0x10 overlay
+>0x1e leshort &0x2 separate
+>0x1e leshort &0x4 pure
+>0x1e leshort &0x800 segmented
+>0x1e leshort &0x400 standalone
+>0x1e leshort &0x8 fixed-stack
+>0x1c byte &0x80 byte-swapped
+>0x1c byte &0x40 word-swapped
+>0x10 lelong >0 not-stripped
+>0x1e leshort ^0xc000 pre-SysV
+>0x1e leshort &0x4000 V2.3
+>0x1e leshort &0x8000 V3.0
+>0x1c byte &0x4 86
+>0x1c byte &0xb 186
+>0x1c byte &0x9 286
+>0x1c byte &0xa 386
+>0x1f byte <0x040 small model
+>0x1f byte =0x048 large model
+>0x1f byte =0x049 huge model
+>0x1e leshort &0x1 executable
+>0x1e leshort ^0x1 object file
+>0x1e leshort &0x40 Large Text
+>0x1e leshort &0x20 Large Data
+>0x1e leshort &0x120 Huge Objects Enabled
+>0x10 lelong >0 not stripped
+
+0 leshort 0x140 old Microsoft 8086 x.out
+>0x3 byte &0x4 separate
+>0x3 byte &0x2 pure
+>0 byte &0x1 executable
+>0 byte ^0x1 relocatable
+>0x14 lelong >0 not stripped
+
+0 lelong 0x206 b.out
+>0x1e leshort &0x10 overlay
+>0x1e leshort &0x2 separate
+>0x1e leshort &0x4 pure
+>0x1e leshort &0x800 segmented
+>0x1e leshort &0x400 standalone
+>0x1e leshort &0x1 executable
+>0x1e leshort ^0x1 object file
+>0x1e leshort &0x4000 V2.3
+>0x1e leshort &0x8000 V3.0
+>0x1c byte &0x4 86
+>0x1c byte &0xb 186
+>0x1c byte &0x9 286
+>0x1c byte &0x29 286
+>0x1c byte &0xa 386
+>0x1e leshort &0x4 Large Text
+>0x1e leshort &0x2 Large Data
+>0x1e leshort &0x102 Huge Objects Enabled
+
+0 leshort 0x580 XENIX 8086 relocatable or 80286 small model
diff --git a/usr.bin/file/Magdir/mips b/usr.bin/file/Magdir/mips
new file mode 100644
index 0000000..ae17cbd
--- /dev/null
+++ b/usr.bin/file/Magdir/mips
@@ -0,0 +1,8 @@
+#
+# RISC MIPS decstation
+# Should this be "leshort", given that DEC ran the DECstations in
+# little-endian mode?
+#
+# Where is the non-SGI, non-DEC MIPS stuff?
+#
+0 short 0x6201 MIPS executable
diff --git a/usr.bin/file/Magdir/mirage b/usr.bin/file/Magdir/mirage
new file mode 100644
index 0000000..73c3747
--- /dev/null
+++ b/usr.bin/file/Magdir/mirage
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# mirage: file(1) magic for Mirage executables
+#
+# XXX - byte order?
+#
+0 long 31415 Mirage Assembler m.out executable
diff --git a/usr.bin/file/Magdir/mkid b/usr.bin/file/Magdir/mkid
new file mode 100644
index 0000000..dfb2d93
--- /dev/null
+++ b/usr.bin/file/Magdir/mkid
@@ -0,0 +1,10 @@
+
+#------------------------------------------------------------------------------
+# mkid: file(1) magic for mkid(1) databases
+#
+# ID is the binary tags database produced by mkid(1).
+#
+# XXX - byte order?
+#
+0 string \311\304 ID tags data
+>2 short >0 version %d
diff --git a/usr.bin/file/Magdir/mmdf b/usr.bin/file/Magdir/mmdf
new file mode 100644
index 0000000..72cd9f3
--- /dev/null
+++ b/usr.bin/file/Magdir/mmdf
@@ -0,0 +1,5 @@
+
+#------------------------------------------------------------------------------
+# mmdf: file(1) magic for MMDF mail files
+#
+0 string \001\001\001\001 MMDF mailbox
diff --git a/usr.bin/file/Magdir/motorola b/usr.bin/file/Magdir/motorola
new file mode 100644
index 0000000..efed159
--- /dev/null
+++ b/usr.bin/file/Magdir/motorola
@@ -0,0 +1,32 @@
+
+#------------------------------------------------------------------------------
+# motorola: file(1) magic for Motorola 68K and 88K binaries
+#
+# 68K
+#
+0 beshort 0520 mc68k COFF
+>18 beshort ^00000020 object
+>18 beshort &00000020 executable
+>12 belong >0 not stripped
+>168 string .lowmem Apple toolbox
+>20 beshort 0407 (impure)
+>20 beshort 0410 (pure)
+>20 beshort 0413 (demand paged)
+>20 beshort 0421 (standalone)
+0 beshort 0521 mc68k executable (shared)
+>12 belong >0 not stripped
+0 beshort 0522 mc68k executable (shared demand paged)
+>12 belong >0 not stripped
+#
+# Motorola/UniSoft 68K Binary Compatibility Standard (BCS)
+#
+0 beshort 0554 68K BCS executable
+#
+# 88K
+#
+# Motorola/88Open BCS
+#
+0 beshort 0555 88K BCS executable
+#
+# Motorola S-Records, from Gerd Truschinski <gt@freebsd.first.gmd.de>
+0 string S0 Motorola S-Record; binary data in text format
diff --git a/usr.bin/file/Magdir/ms-dos b/usr.bin/file/Magdir/ms-dos
new file mode 100644
index 0000000..db2c03e
--- /dev/null
+++ b/usr.bin/file/Magdir/ms-dos
@@ -0,0 +1,73 @@
+
+#------------------------------------------------------------------------------
+# msdos: file(1) magic for MS-DOS files
+#
+
+# .BAT files (Daniel Quinlan, quinlan@yggdrasil.com)
+0 string @echo\ off MS-DOS batch file text
+
+# .EXE formats (Greg Roelofs, newt@uchicago.edu)
+#
+0 string MZ MS-DOS executable (EXE)
+>24 string @ \b, OS/2 or Windows
+>1638 string -lh5- \b, LHa SFX archive v2.13S
+>7195 string Rar! \b, RAR self-extracting archive
+#
+# [GRR 950118: file 3.15 has a buffer-size limitation; offsets bigger than
+# 8161 bytes are ignored. To make the following entries work, increase
+# HOWMANY in file.h to 32K at least, and maybe to 70K or more for OS/2,
+# NT/Win32 and VMS.]
+# [GRR: some company sells a self-extractor/displayer for image data(!)]
+#
+>11696 string PK\003\004 \b, PKZIP SFX archive v1.1
+>13297 string PK\003\004 \b, PKZIP SFX archive v1.93a
+>15588 string PK\003\004 \b, PKZIP2 SFX archive v1.09
+>15770 string PK\003\004 \b, PKZIP SFX archive v2.04g
+>28374 string PK\003\004 \b, PKZIP2 SFX archive v1.02
+#
+# Info-ZIP self-extractors
+# these are the DOS versions:
+>25115 string PK\003\004 \b, Info-ZIP SFX archive v5.12
+>26331 string PK\003\004 \b, Info-ZIP SFX archive v5.12 w/decryption
+# these are the OS/2 versions (OS/2 is flagged above):
+>47031 string PK\003\004 \b, Info-ZIP SFX archive v5.12
+>49845 string PK\003\004 \b, Info-ZIP SFX archive v5.12 w/decryption
+# this is the NT/Win32 version:
+>69120 string PK\003\004 \b, Info-ZIP NT SFX archive v5.12 w/decryption
+#
+# TELVOX Teleinformatica CODEC self-extractor for OS/2:
+>49801 string \x79\xff\x80\xff\x76\xff \b, CODEC archive v3.21
+>>49824 leshort =1 \b, 1 file
+>>49824 leshort >1 \b, %u files
+
+# .COM formats (Daniel Quinlan, quinlan@yggdrasil.com)
+# Uncommenting only the first two lines will cover about 2/3 of COM files,
+# but it isn't feasible to match all COM files since there must be at least
+# two dozen different one-byte "magics".
+#0 byte 0xe9 MS-DOS executable (COM)
+#0 byte 0x8c MS-DOS executable (COM)
+# 0xeb conflicts with "sequent" magic
+#0 byte 0xeb MS-DOS executable (COM)
+#0 byte 0xb8 MS-DOS executable (COM)
+
+# miscellaneous formats
+0 string LZ MS-DOS executable (built-in)
+#0 byte 0xf0 MS-DOS program library data
+#
+
+# Popular applications
+2080 string Microsoft\ Word\ 6.0\ Document %s
+#
+0 belong 0x31be0000 Microsoft Word Document
+#
+2080 string Microsoft\ Excel\ 5.0\ Worksheet %s
+#
+0 belong 0x00001a00 Lotus 1-2-3
+>4 belong 0x00100400 wk3 document
+>4 belong 0x02100400 wk4 document
+>4 belong 0x07800100 fm3 or fmb document
+>4 belong 0x07800000 fm3 or fmb document
+#
+0 belong 0x00000200 Lotus 1-2-3
+>4 belong 0x06040600 wk1 document
+>4 belong 0x06800200 fmt document
diff --git a/usr.bin/file/Magdir/ncr b/usr.bin/file/Magdir/ncr
new file mode 100644
index 0000000..987c94e
--- /dev/null
+++ b/usr.bin/file/Magdir/ncr
@@ -0,0 +1,48 @@
+
+#------------------------------------------------------------------------------
+# ncr: file(1) magic for NCR Tower objects
+#
+# contributed by
+# Michael R. Wayne *** TMC & Associates *** INTERNET: wayne@ford-vax.arpa
+# uucp: {philabs | pyramid} !fmsrl7!wayne OR wayne@fmsrl7.UUCP
+#
+0 beshort 000610 Tower/XP rel 2 object
+>12 belong >0 not stripped
+>20 beshort 0407 executable
+>20 beshort 0410 pure executable
+>22 beshort >0 - version %ld
+0 beshort 000615 Tower/XP rel 2 object
+>12 belong >0 not stripped
+>20 beshort 0407 executable
+>20 beshort 0410 pure executable
+>22 beshort >0 - version %ld
+0 beshort 000620 Tower/XP rel 3 object
+>12 belong >0 not stripped
+>20 beshort 0407 executable
+>20 beshort 0410 pure executable
+>22 beshort >0 - version %ld
+0 beshort 000625 Tower/XP rel 3 object
+>12 belong >0 not stripped
+>20 beshort 0407 executable
+>20 beshort 0410 pure executable
+>22 beshort >0 - version %ld
+0 beshort 000630 Tower32/600/400 68020 object
+>12 belong >0 not stripped
+>20 beshort 0407 executable
+>20 beshort 0410 pure executable
+>22 beshort >0 - version %ld
+0 beshort 000640 Tower32/800 68020
+>18 beshort &020000 w/68881 object
+>18 beshort &040000 compatible object
+>18 beshort &~060000 object
+>20 beshort 0407 executable
+>20 beshort 0413 pure executable
+>12 belong >0 not stripped
+>22 beshort >0 - version %ld
+0 beshort 000645 Tower32/800 68010
+>18 beshort &040000 compatible object
+>18 beshort &~060000 object
+>20 beshort 0407 executable
+>20 beshort 0413 pure executable
+>12 belong >0 not stripped
+>22 beshort >0 - version %ld
diff --git a/usr.bin/file/Magdir/netbsd b/usr.bin/file/Magdir/netbsd
new file mode 100644
index 0000000..7d92ef5
--- /dev/null
+++ b/usr.bin/file/Magdir/netbsd
@@ -0,0 +1,209 @@
+
+#------------------------------------------------------------------------------
+# netbsd: file(1) magic for NetBSD objects
+#
+# All new-style magic numbers are in network byte order.
+#
+
+0 lelong 000000407 NetBSD little-endian object file
+>16 lelong >0 not stripped
+0 belong 000000407 NetBSD big-endian object file
+>16 belong >0 not stripped
+
+0 belong&0377777777 041400413 NetBSD/i386 demand paged
+>0 byte &0x80
+>>20 lelong <4096 shared library
+>>20 lelong =4096 dynamically linked executable
+>>20 lelong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 041400410 NetBSD/i386 pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 041400407 NetBSD/i386
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 lelong !0 executable
+>>20 lelong =0 object file
+>16 lelong >0 not stripped
+0 belong&0377777777 041400507 NetBSD/i386 core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 041600413 NetBSD/m68k demand paged
+>0 byte &0x80
+>>20 belong <8192 shared library
+>>20 belong =8192 dynamically linked executable
+>>20 belong >8192 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 041600410 NetBSD/m68k pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 041600407 NetBSD/m68k
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 belong !0 executable
+>>20 belong =0 object file
+>16 belong >0 not stripped
+0 belong&0377777777 041600507 NetBSD/m68k core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 042000413 NetBSD/m68k4k demand paged
+>0 byte &0x80
+>>20 belong <4096 shared library
+>>20 belong =4096 dynamically linked executable
+>>20 belong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 042000410 NetBSD/m68k4k pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 042000407 NetBSD/m68k4k
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 belong !0 executable
+>>20 belong =0 object file
+>16 belong >0 not stripped
+0 belong&0377777777 042000507 NetBSD/m68k4k core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 042200413 NetBSD/ns32532 demand paged
+>0 byte &0x80
+>>20 lelong <4096 shared library
+>>20 lelong =4096 dynamically linked executable
+>>20 lelong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 042200410 NetBSD/ns32532 pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 042200407 NetBSD/ns32532
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 lelong !0 executable
+>>20 lelong =0 object file
+>16 lelong >0 not stripped
+0 belong&0377777777 042200507 NetBSD/ns32532 core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 042400413 NetBSD/sparc demand paged
+>0 byte &0x80
+>>20 belong <8192 shared library
+>>20 belong =8192 dynamically linked executable
+>>20 belong >8192 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 042400410 NetBSD/sparc pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 042400407 NetBSD/sparc
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 belong !0 executable
+>>20 belong =0 object file
+>16 belong >0 not stripped
+0 belong&0377777777 042400507 NetBSD/sparc core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 042600413 NetBSD/pmax demand paged
+>0 byte &0x80
+>>20 lelong <4096 shared library
+>>20 lelong =4096 dynamically linked executable
+>>20 lelong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 042600410 NetBSD/pmax pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 042600407 NetBSD/pmax
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 lelong !0 executable
+>>20 lelong =0 object file
+>16 lelong >0 not stripped
+0 belong&0377777777 042600507 NetBSD/pmax core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 043000413 NetBSD/vax demand paged
+>0 byte &0x80
+>>20 lelong <4096 shared library
+>>20 lelong =4096 dynamically linked executable
+>>20 lelong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 043000410 NetBSD/vax pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 043000407 NetBSD/vax
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 lelong !0 executable
+>>20 lelong =0 object file
+>16 lelong >0 not stripped
+0 belong&0377777777 043000507 NetBSD/vax core
+>12 string >\0 from '%s'
+
+# NetBSD/alpha does not support (and has never supported) a.out objects,
+# so no rules are provided for them. NetBSD/alpha ELF objects are
+# dealt with in "elf".
+0 leshort 0x00070185 ECOFF NetBSD/alpha binary
+>10 leshort 0x0001 not stripped
+>10 leshort 0x0000 stripped
+0 belong&0377777777 043200507 NetBSD/alpha core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 043400413 NetBSD/mips demand paged
+>0 byte &0x80
+>>20 belong <8192 shared library
+>>20 belong =8192 dynamically linked executable
+>>20 belong >8192 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 043400410 NetBSD/mips pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&0377777777 043400407 NetBSD/mips
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 belong !0 executable
+>>20 belong =0 object file
+>16 belong >0 not stripped
+0 belong&0377777777 043400507 NetBSD/mips core
+>12 string >\0 from '%s'
+
+0 belong&0377777777 043600413 NetBSD/arm32 demand paged
+>0 byte &0x80
+>>20 lelong <8192 shared library
+>>20 lelong =8192 dynamically linked executable
+>>20 lelong >8192 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 043600410 NetBSD/arm32 pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 lelong >0 not stripped
+0 belong&0377777777 043600407 NetBSD/arm32
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80
+>>0 byte &0x40 position independent
+>>20 lelong !0 executable
+>>20 lelong =0 object file
+>16 lelong >0 not stripped
+0 belong&0377777777 043600507 NetBSD/arm32 core
+>12 string >\0 from '%s'
diff --git a/usr.bin/file/Magdir/news b/usr.bin/file/Magdir/news
new file mode 100644
index 0000000..0ac4fa2
--- /dev/null
+++ b/usr.bin/file/Magdir/news
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# news: file(1) magic for SunOS NeWS fonts (not "news" as in "netnews")
+#
+0 string StartFontMetrics ASCII font metrics
+0 string StartFont ASCII font bits
+0 belong 0x137A2944 NeWS bitmap font
+0 belong 0x137A2947 NeWS font family
+0 belong 0x137A2950 scalable OpenFont binary
+0 belong 0x137A2951 encrypted scalable OpenFont binary
+8 belong 0x137A2B45 X11/NeWS bitmap font
+8 belong 0x137A2B48 X11/NeWS font family
diff --git a/usr.bin/file/Magdir/osf1 b/usr.bin/file/Magdir/osf1
new file mode 100644
index 0000000..d2868c3
--- /dev/null
+++ b/usr.bin/file/Magdir/osf1
@@ -0,0 +1,10 @@
+#
+# Mach magic number info
+#
+0 long 0xefbe OSF/Rose object
+# I386 magic number info
+#
+0 short 0565 i386 COFF object
+#
+0 string Core Alpha Digital UNIX core file
+>24 string >\0 \b, generated from '%s'
diff --git a/usr.bin/file/Magdir/pbm b/usr.bin/file/Magdir/pbm
new file mode 100644
index 0000000..98c15f7
--- /dev/null
+++ b/usr.bin/file/Magdir/pbm
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# pbm: file(1) magic for Portable Bitmap files
+#
+# XXX - byte order?
+#
+0 short 0x2a17 "compact bitmap" format (Poskanzer)
diff --git a/usr.bin/file/Magdir/pdf b/usr.bin/file/Magdir/pdf
new file mode 100644
index 0000000..a1aef13
--- /dev/null
+++ b/usr.bin/file/Magdir/pdf
@@ -0,0 +1,7 @@
+#------------------------------------------------------------------------------
+# pdf: file(1) magic for Portable Document Format
+#
+
+0 string %PDF- PDF document
+>5 byte x \b, version %c
+>7 byte x \b.%c
diff --git a/usr.bin/file/Magdir/pdp b/usr.bin/file/Magdir/pdp
new file mode 100644
index 0000000..201dede
--- /dev/null
+++ b/usr.bin/file/Magdir/pdp
@@ -0,0 +1,25 @@
+
+#------------------------------------------------------------------------------
+# pdp: file(1) magic for PDP-11 executable/object and APL workspace
+#
+0 lelong 0101555 PDP-11 single precision APL workspace
+0 lelong 0101554 PDP-11 double precision APL workspace
+#
+# PDP-11 a.out
+#
+0 leshort 0407 PDP-11 executable
+>8 leshort >0 not stripped
+>15 byte >0 - version %ld
+
+0 leshort 0401 PDP-11 UNIX/RT ldp
+0 leshort 0405 PDP-11 old overlay
+
+0 leshort 0410 PDP-11 pure executable
+>8 leshort >0 not stripped
+>15 byte >0 - version %ld
+
+0 leshort 0411 PDP-11 separate I&D executable
+>8 leshort >0 not stripped
+>15 byte >0 - version %ld
+
+0 leshort 0437 PDP-11 kernel overlay
diff --git a/usr.bin/file/Magdir/pgp b/usr.bin/file/Magdir/pgp
new file mode 100644
index 0000000..038d098
--- /dev/null
+++ b/usr.bin/file/Magdir/pgp
@@ -0,0 +1,13 @@
+
+#------------------------------------------------------------------------------
+# pgp: file(1) magic for Pretty Good Privacy
+#
+0 beshort 0x9900 PGP key public ring
+0 beshort 0x9501 PGP key security ring
+0 beshort 0x9500 PGP key security ring
+0 beshort 0xa600 PGP encrypted data
+0 string -----BEGIN\040PGP PGP armored data
+>15 string PUBLIC\040KEY\040BLOCK- public key block
+>15 string MESSAGE- message
+>15 string SIGNED\040MESSAGE- signed message
+>15 string PGP\040SIGNATURE- signature
diff --git a/usr.bin/file/Magdir/pjl b/usr.bin/file/Magdir/pjl
new file mode 100644
index 0000000..fa7d298
--- /dev/null
+++ b/usr.bin/file/Magdir/pjl
@@ -0,0 +1,5 @@
+#
+# magic.pjl: HP Printer Job Language (PJL)
+#
+0 string %-12345X@PJL HP PJL (printer job language) commands
+0 string @PJL HP PJL (printer job language) commands
diff --git a/usr.bin/file/Magdir/pkgadd b/usr.bin/file/Magdir/pkgadd
new file mode 100644
index 0000000..dc8ef5d
--- /dev/null
+++ b/usr.bin/file/Magdir/pkgadd
@@ -0,0 +1,5 @@
+
+#------------------------------------------------------------------------------
+# pkgadd: file(1) magic for SysV R4 PKG Datastreams
+#
+0 string #\ PaCkAgE\ DaTaStReAm pkg Datastream (SVR4)
diff --git a/usr.bin/file/Magdir/plus5 b/usr.bin/file/Magdir/plus5
new file mode 100644
index 0000000..acf3bf4
--- /dev/null
+++ b/usr.bin/file/Magdir/plus5
@@ -0,0 +1,17 @@
+
+#------------------------------------------------------------------------------
+# plus5: file(1) magic for Plus Five's UNIX MUMPS
+#
+# XXX - byte order? Paging Hokey....
+#
+0 short 0x259 mumps avl global
+>2 byte >0 (V%d)
+>6 byte >0 with %d byte name
+>7 byte >0 and %d byte data cells
+0 short 0x25a mumps blt global
+>2 byte >0 (V%d)
+>8 short >0 - %d byte blocks
+>15 byte 0x00 - P/D format
+>15 byte 0x01 - P/K/D format
+>15 byte 0x02 - K/D format
+>15 byte >0x02 - Bad Flags
diff --git a/usr.bin/file/Magdir/postscript b/usr.bin/file/Magdir/postscript
new file mode 100644
index 0000000..7d5992b
--- /dev/null
+++ b/usr.bin/file/Magdir/postscript
@@ -0,0 +1,20 @@
+#
+# magic.postscript: Magic for postscript files
+#
+# XXX - should we match only versions 1.0 and 2.0, or should we wildcard
+# it?
+#
+0 string %! PostScript document
+>2 string PS-Adobe- conforming
+>>11 string 1.0 at level %s
+>>11 string 2.0 at level %s
+>>11 string 3.0 at level %s
+# Some pc's have the annoying habit of adding a ^D
+0 string \004%! PostScript document
+>3 string PS-Adobe- conforming
+>>12 string 1.0 at level %s
+>>12 string 2.0 at level %s
+>>12 string 3.0 at level %s
+0 string %PDF Adobe Acrobat document
+>5 string x at level %s
+
diff --git a/usr.bin/file/Magdir/printer b/usr.bin/file/Magdir/printer
new file mode 100644
index 0000000..d20330f
--- /dev/null
+++ b/usr.bin/file/Magdir/printer
@@ -0,0 +1,55 @@
+
+#------------------------------------------------------------------------------
+# printer: file(1) magic for printer-formatted files
+#
+
+# PostScript, updated by Daniel Quinlan (quinlan@yggdrasil.com)
+0 string %! PostScript document text
+>2 string PS-Adobe- conforming
+>>11 string >\0 at level %.3s
+>>>15 string EPS - type %s
+>>>15 string Query - type %s
+>>>15 string ExitServer - type %s
+# Some PCs have the annoying habit of adding a ^D as a document separator
+0 string \004%! PostScript document text
+>3 string PS-Adobe- conforming
+>>12 string >\0 at level %.3s
+>>>16 string EPS - type %s
+>>>16 string Query - type %s
+>>>16 string ExitServer - type %s
+
+# HP Printer Job Language
+0 string \033%-12345X@PJL HP Printer Job Language data
+>15 string \ ENTER\ LANGUAGE\ =
+>31 string PostScript PostScript
+
+# HP Printer Control Language, Daniel Quinlan (quinlan@yggdrasil.com)
+0 string \033E\033 HP PCL printer data
+>3 string \&l0A - default page size
+>3 string \&l1A - US executive page size
+>3 string \&l2A - US letter page size
+>3 string \&l3A - US legal page size
+>3 string \&l26A - A4 page size
+>3 string \&l80A - Monarch envelope size
+>3 string \&l81A - No. 10 envelope size
+>3 string \&l90A - Intl. DL envelope size
+>3 string \&l91A - Intl. C5 envelope size
+>3 string \&l100A - Intl. B5 envelope size
+>3 string \&l-81A - No. 10 envelope size (landscape)
+>3 string \&l-90A - Intl. DL envelope size (landscape)
+
+# IMAGEN printer-ready files:
+0 string @document( Imagen printer
+# this only works if "language xxx" is first item in Imagen header.
+>10 string language\ impress (imPRESS data)
+>10 string language\ daisy (daisywheel text)
+>10 string language\ diablo (daisywheel text)
+>10 string language\ printer (line printer emulation)
+>10 string language\ tektronix (Tektronix 4014 emulation)
+# Add any other languages that your Imagen uses - remember
+# to keep the word `text' if the file is human-readable.
+# [GRR 950115: missing "postscript" or "ultrascript" (whatever it was called)]
+#
+# Now magic for IMAGEN font files...
+0 string Rast RST-format raster font data
+>45 string >0 face %
diff --git a/usr.bin/file/Magdir/psdbms b/usr.bin/file/Magdir/psdbms
new file mode 100644
index 0000000..f36121f
--- /dev/null
+++ b/usr.bin/file/Magdir/psdbms
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# psdbms: file(1) magic for psdatabase
+#
+0 belong&0xff00ffff 0x56000000 ps database
+>1 string >\0 version %s
+>4 string >\0 from kernel %s
diff --git a/usr.bin/file/Magdir/pyramid b/usr.bin/file/Magdir/pyramid
new file mode 100644
index 0000000..fe16608
--- /dev/null
+++ b/usr.bin/file/Magdir/pyramid
@@ -0,0 +1,11 @@
+
+#------------------------------------------------------------------------------
+# pyramid: file(1) magic for Pyramids
+#
+# XXX - byte order?
+#
+0 long 0x50900107 Pyramid 90x family executable
+0 long 0x50900108 Pyramid 90x family pure executable
+>16 long >0 not stripped
+0 long 0x5090010b Pyramid 90x family demand paged pure executable
+>16 long >0 not stripped
diff --git a/usr.bin/file/Magdir/rle b/usr.bin/file/Magdir/rle
new file mode 100644
index 0000000..f45605b
--- /dev/null
+++ b/usr.bin/file/Magdir/rle
@@ -0,0 +1,19 @@
+# From <janl@ifi.uio.no>
+# I made this with the help of the man page for rle(5). Ihey missing
+# from the magic numbers I have:
+
+#
+# rle
+#
+0 short 0xcc52 Utah Raster Toolkit RLE
+>2 short >0 lower left corner: %d
+>4 short >0 lower right corner: %d
+>6 short >0 %d x
+>8 short >0 %d
+>10 byte&0x1 =0x1 CLEARFIRST
+>10 byte&0x2 =0x2 NO_BACKGROUND
+>10 byte&0x4 =0x4 ALPHA
+>10 byte&0x8 =0x8 COMMENT
+>11 byte >0 %d colour channels
+>12 byte >0 %d bits pr. pixel
+>13 byte >0 %d colour map channels
diff --git a/usr.bin/file/Magdir/rpm b/usr.bin/file/Magdir/rpm
new file mode 100644
index 0000000..14ad6db
--- /dev/null
+++ b/usr.bin/file/Magdir/rpm
@@ -0,0 +1,17 @@
+#------------------------------------------------------------------------------
+#
+# RPM: file(1) magic for Red Hat Packages Erik Troan (ewt@redhat.com)
+#
+0 beshort 0xedab
+>2 beshort 0xeedb RPM
+>>4 byte x v%d
+>>6 beshort 0 bin
+>>6 beshort 1 src
+>>8 beshort 1 i386
+>>8 beshort 2 Alpha
+>>8 beshort 3 Sparc
+>>8 beshort 4 MIPS
+>>8 beshort 5 PowerPC
+>>8 beshort 6 68000
+>>8 beshort 7 SGI
+>>10 string x %s
diff --git a/usr.bin/file/Magdir/rtf b/usr.bin/file/Magdir/rtf
new file mode 100644
index 0000000..8e2d416
--- /dev/null
+++ b/usr.bin/file/Magdir/rtf
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# rtf: file(1) magic for Rich Text Format (RTF)
+#
+# Duncan P. Simpson, D.P.Simpson@dcs.warwick.ac.uk
+#
+0 string {\\rtf Rich Text Format data,
+>5 byte x version %c,
+>6 string \\ansi ANSI
+>6 string \\mac Apple Macintosh
+>6 string \\pc IBM PC, code page 437
+>6 string \\pca IBM PS/2, code page 850
diff --git a/usr.bin/file/Magdir/sc b/usr.bin/file/Magdir/sc
new file mode 100644
index 0000000..98599f2
--- /dev/null
+++ b/usr.bin/file/Magdir/sc
@@ -0,0 +1,5 @@
+
+#------------------------------------------------------------------------------
+# sc: file(1) magic for "sc" spreadsheet
+#
+38 string Spreadsheet sc spreadsheet file
diff --git a/usr.bin/file/Magdir/sccs b/usr.bin/file/Magdir/sccs
new file mode 100644
index 0000000..11d50b2
--- /dev/null
+++ b/usr.bin/file/Magdir/sccs
@@ -0,0 +1,21 @@
+
+#------------------------------------------------------------------------------
+# sccs: file(1) magic for SCCS archives
+#
+# SCCS archive structure:
+# \001h01207
+# \001s 00276/00000/00000
+# \001d D 1.1 87/09/23 08:09:20 ian 1 0
+# \001c date and time created 87/09/23 08:09:20 by ian
+# \001e
+# \001u
+# \001U
+# ... etc.
+# Now '\001h' happens to be the same as the 3B20's a.out magic number (0550).
+# *Sigh*. And these both came from various parts of the USG.
+# Maybe we should just switch everybody from SCCS to RCS!
+# Further, you can't just say '\001h0', because the five-digit number
+# is a checksum that could (presumably) have any leading digit,
+# and we don't have regular expression matching yet.
+# Hence the following official kludge:
+8 string \001s\ SCCS archive data
diff --git a/usr.bin/file/Magdir/sendmail b/usr.bin/file/Magdir/sendmail
new file mode 100644
index 0000000..503ef89
--- /dev/null
+++ b/usr.bin/file/Magdir/sendmail
@@ -0,0 +1,10 @@
+
+#------------------------------------------------------------------------------
+# sendmail: file(1) magic for sendmail config files
+#
+# XXX - byte order?
+#
+0 byte 046 Sendmail frozen configuration
+>16 string >\0 - version %s
+0 short 0x271c Sendmail frozen configuration
+>16 string >\0 - version %s
diff --git a/usr.bin/file/Magdir/sequent b/usr.bin/file/Magdir/sequent
new file mode 100644
index 0000000..e6f7b52
--- /dev/null
+++ b/usr.bin/file/Magdir/sequent
@@ -0,0 +1,34 @@
+
+#------------------------------------------------------------------------------
+# sequent: file(1) magic for Sequent machines
+#
+# Sequent information updated by Don Dwiggins <atsun!dwiggins>.
+# For Sequent's multiprocessor systems (incomplete).
+0 lelong 0x00ea BALANCE NS32000 .o
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 lelong 0x10ea BALANCE NS32000 executable (0 @ 0)
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 lelong 0x20ea BALANCE NS32000 executable (invalid @ 0)
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 lelong 0x30ea BALANCE NS32000 standalone executable
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+#
+# Symmetry information added by Jason Merrill <jason@jarthur.claremont.edu>.
+# Symmetry magic nums will not be reached if DOS COM comes before them;
+# byte 0xeb is matched before these get a chance.
+0 leshort 0x12eb SYMMETRY i386 .o
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 leshort 0x22eb SYMMETRY i386 executable (0 @ 0)
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 leshort 0x32eb SYMMETRY i386 executable (invalid @ 0)
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
+0 leshort 0x42eb SYMMETRY i386 standalone executable
+>16 lelong >0 not stripped
+>124 lelong >0 version %ld
diff --git a/usr.bin/file/Magdir/sgi b/usr.bin/file/Magdir/sgi
new file mode 100644
index 0000000..ce9dbc8
--- /dev/null
+++ b/usr.bin/file/Magdir/sgi
@@ -0,0 +1,170 @@
+
+#------------------------------------------------------------------------------
+# sgi: file(1) magic for Silicon Graphics (MIPS, IRIS, IRIX, etc.)
+# Dec Ultrix (MIPS)
+# all of SGI's *current* machines and OSes run in big-endian mode on the
+# MIPS machines, as far as I know.
+#
+# XXX - what is the blank "-" line?
+#
+# kbd file definitions
+0 string kbd!map kbd map file
+>8 byte >0 Ver %d:
+>10 short >0 with %d table(s)
+0 belong 0407 old SGI 68020 executable
+0 belong 0410 old SGI 68020 pure executable
+0 beshort 0x8765 disk quotas file
+0 beshort 0x0506 IRIS Showcase file
+>2 byte 0x49 -
+>3 byte x - version %ld
+0 beshort 0x0226 IRIS Showcase template
+>2 byte 0x63 -
+>3 byte x - version %ld
+0 belong 0x5343464d IRIS Showcase file
+>4 byte x - version %ld
+0 belong 0x5443464d IRIS Showcase template
+>4 byte x - version %ld
+0 belong 0xdeadbabe IRIX Parallel Arena
+>8 belong >0 - version %ld
+#
+0 beshort 0x0160 MIPSEB COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>22 byte x - version %ld
+>23 byte x .%ld
+#
+0 beshort 0x0162 MIPSEL COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %d
+>22 byte x .%ld
+#
+0 beshort 0x6001 MIPSEB-LE COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %d
+>22 byte x .%ld
+#
+0 beshort 0x6201 MIPSEL-LE COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %ld
+>22 byte x .%ld
+#
+# MIPS 2 additions
+#
+0 beshort 0x0163 MIPSEB MIPS-II COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>22 byte x - version %ld
+>23 byte x .%ld
+#
+0 beshort 0x0166 MIPSEL MIPS-II COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>22 byte x - version %ld
+>23 byte x .%ld
+#
+0 beshort 0x6301 MIPSEB-LE MIPS-II COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %ld
+>22 byte x .%ld
+#
+0 beshort 0x6601 MIPSEL-LE MIPS-II COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %ld
+>22 byte x .%ld
+#
+# MIPS 3 additions
+#
+0 beshort 0x0140 MIPSEB MIPS-III COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>22 byte x - version %ld
+>23 byte x .%ld
+#
+0 beshort 0x0142 MIPSEL MIPS-III COFF executable
+>20 beshort 0407 (impure)
+>20 beshort 0410 (swapped)
+>20 beshort 0413 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>22 byte x - version %ld
+>23 byte x .%ld
+#
+0 beshort 0x4001 MIPSEB-LE MIPS-III COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %ld
+>22 byte x .%ld
+#
+0 beshort 0x4201 MIPSEL-LE MIPS-III COFF executable
+>20 beshort 03401 (impure)
+>20 beshort 04001 (swapped)
+>20 beshort 05401 (paged)
+>8 belong >0 not stripped
+>8 belong 0 stripped
+>23 byte x - version %ld
+>22 byte x .%ld
+#
+0 beshort 0x180 MIPSEB Ucode
+0 beshort 0x182 MIPSEL Ucode
+# 32bit core file
+0 belong 0xdeadadb0 IRIX core dump
+>4 belong 1 of
+>16 string >\0 '%s'
+# 64bit core file
+0 belong 0xdeadad40 IRIX 64-bit core dump
+>4 belong 1 of
+>16 string >\0 '%s'
+# New style crash dump file
+0 string \x43\x72\x73\x68\x44\x75\x6d\x70 IRIX vmcore dump of
+>36 string >\0 '%s'
+# Trusted IRIX info
+0 string SGIAUDIT SGI Audit file
+>8 byte x - version %d
+>9 byte x .%ld
+# Are these three SGI-based file types or general ones?
+0 string WNGZWZSC Wingz compiled script
+0 string WNGZWZSS Wingz spreadsheet
+0 string WNGZWZHP Wingz help file
+#
+0 string \#Inventor V IRIS Inventor 1.0 file
+0 string \#Inventor V2 Open Inventor 2.0 file
+# XXX - I don't know what next thing is! It is likely to be an image
+# (or movie) format
+0 string glfHeadMagic(); GLF_TEXT
+4 belong 0x41010000 GLF_BINARY_LSB_FIRST
+4 belong 0x00000141 GLF_BINARY_MSB_FIRST
diff --git a/usr.bin/file/Magdir/sgml b/usr.bin/file/Magdir/sgml
new file mode 100644
index 0000000..985bbec
--- /dev/null
+++ b/usr.bin/file/Magdir/sgml
@@ -0,0 +1,21 @@
+
+#------------------------------------------------------------------------------
+# sgml: file(1) magic for Standard Generalized Markup Language
+
+# HyperText Markup Language (HTML) is an SGML document type,
+# from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string \<!DOCTYPE\ HTML HTML document text
+0 string \<!doctype\ html HTML document text
+0 string \<HEAD HTML document text
+0 string \<head HTML document text
+0 string \<TITLE HTML document text
+0 string \<title HTML document text
+0 string \<html HTML document text
+0 string \<HTML HTML document text
+
+# SGML, mostly from rph@sq
+0 string \<!DOCTYPE exported SGML document text
+0 string \<!doctype exported SGML document text
+0 string \<!SUBDOC exported SGML subdocument text
+0 string \<!subdoc exported SGML subdocument text
+0 string \<!-- exported SGML document text
diff --git a/usr.bin/file/Magdir/sniffer b/usr.bin/file/Magdir/sniffer
new file mode 100644
index 0000000..861ec8c
--- /dev/null
+++ b/usr.bin/file/Magdir/sniffer
@@ -0,0 +1,63 @@
+
+#------------------------------------------------------------------------------
+# sniffer: file(1) magic for packet captured files
+#
+# From: guy@netapp.com (Guy Harris)
+#
+# Microsoft NetMon (packet capture/display program) capture files.
+#
+0 string RTSS NetMon capture file
+>4 byte x - version %d
+>5 byte x \b.%d
+#
+# Network General Sniffer capture files (the Sniffer software does,
+# after all, run under MS-DOS...).
+#
+0 string TRSNIFF\ data\ \ \ \ \032 Sniffer capture file
+>23 leshort x - version %d
+>25 leshort x \b.%d
+>33 byte x (Format %d,
+>32 byte 0 Token ring)
+>32 byte 1 Ethernet)
+>32 byte 2 ARCnet)
+>32 byte 3 StarLAN)
+>32 byte 4 PC Network broadband)
+>32 byte 5 LocalTalk)
+>32 byte 6 Znet)
+#
+# (We call them "tcpdump capture file(s)" for now, as "tcpdump" is
+# the main program that uses that format, but there's also "tcpview",
+# and there may be others in the future.)
+#
+0 ubelong 0xa1b2c3d4 tcpdump capture file (big-endian)
+>4 beshort x - version %d
+>6 beshort x \b.%d
+>20 belong 0 (No link-layer encapsulation
+>20 belong 1 (Ethernet
+>20 belong 2 (3Mb Ethernet
+>20 belong 3 (AX.25
+>20 belong 4 (ProNet
+>20 belong 5 (Chaos
+>20 belong 6 (IEEE 802.x network
+>20 belong 7 (ARCnet
+>20 belong 8 (SLIP
+>20 belong 9 (PPP
+>20 belong 10 (FDDI
+>20 belong 11 (RFC 1483 ATM
+>16 belong x \b, capture length %d)
+0 ulelong 0xa1b2c3d4 tcpdump capture file (little-endian)
+>4 leshort x - version %d
+>6 leshort x \b.%d
+>20 lelong 0 (No link-layer encapsulation
+>20 lelong 1 (Ethernet
+>20 lelong 2 (3Mb Ethernet
+>20 lelong 3 (AX.25
+>20 lelong 4 (ProNet
+>20 lelong 5 (Chaos
+>20 lelong 6 (IEEE 802.x network
+>20 lelong 7 (ARCnet
+>20 lelong 8 (SLIP
+>20 lelong 9 (PPP
+>20 lelong 10 (FDDI
+>20 lelong 11 (RFC 1483 ATM
+>16 lelong x \b, capture length %d)
diff --git a/usr.bin/file/Magdir/softquad b/usr.bin/file/Magdir/softquad
new file mode 100644
index 0000000..f570b09
--- /dev/null
+++ b/usr.bin/file/Magdir/softquad
@@ -0,0 +1,30 @@
+
+#------------------------------------------------------------------------------
+# softquad: file(1) magic for SoftQuad Publishing Software
+#
+# $Id$
+# Author/Editor and RulesBuilder
+#
+# XXX - byte order?
+#
+0 string \<!SQ\ DTD> Compiled SGML rules file
+>9 string >\0 Type %s
+0 string \<!SQ\ A/E> A/E SGML Document binary
+>9 string >\0 Type %s
+0 string \<!SQ\ STS> A/E SGML binary styles file
+>9 string >\0 Type %s
+0 short 0xc0de Compiled PSI (v1) data
+0 short 0xc0da Compiled PSI (v2) data
+>3 string >\0 (%s)
+# Binary sqtroff font/desc files...
+0 short 0125252 SoftQuad DESC or font file binary
+>2 short >0 - version %d
+# Bitmaps...
+0 string SQ\ BITMAP1 SoftQuad Raster Format text
+#0 string SQ\ BITMAP2 SoftQuad Raster Format data
+# sqtroff intermediate language (replacement for ditroff int. lang.)
+0 string X\ SoftQuad troff Context intermediate
+>2 string 495 for AT&T 495 laser printer
+>2 string hp for Hewlett-Packard LaserJet
+>2 string impr for IMAGEN imPRESS
+>2 string ps for PostScript
diff --git a/usr.bin/file/Magdir/sun b/usr.bin/file/Magdir/sun
new file mode 100644
index 0000000..2f0336a
--- /dev/null
+++ b/usr.bin/file/Magdir/sun
@@ -0,0 +1,110 @@
+
+#------------------------------------------------------------------------------
+# sun: file(1) magic for Sun machines
+#
+# Values for big-endian Sun (MC680x0, SPARC) binaries on pre-5.x
+# releases. (5.x uses ELF.)
+#
+0 belong&077777777 0600413 sparc demand paged
+>0 byte &0x80
+>>20 belong <4096 shared library
+>>20 belong =4096 dynamically linked executable
+>>20 belong >4096 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&077777777 0600410 sparc pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&077777777 0600407 sparc
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+
+0 belong&077777777 0400413 mc68020 demand paged
+>0 byte &0x80
+>>20 belong <4096 shared library
+>>20 belong =4096 dynamically linked executable
+>>20 belong >4096 dynamically linked executable
+>16 belong >0 not stripped
+0 belong&077777777 0400410 mc68020 pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&077777777 0400407 mc68020
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+
+0 belong&077777777 0200413 mc68010 demand paged
+>0 byte &0x80
+>>20 belong <4096 shared library
+>>20 belong =4096 dynamically linked executable
+>>20 belong >4096 dynamically linked executable
+>16 belong >0 not stripped
+0 belong&077777777 0200410 mc68010 pure
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+0 belong&077777777 0200407 mc68010
+>0 byte &0x80 dynamically linked executable
+>0 byte ^0x80 executable
+>16 belong >0 not stripped
+
+# reworked these to avoid anything beginning with zero becoming "old sun-2"
+0 belong 0407 old sun-2 executable
+>16 belong >0 not stripped
+0 belong 0410 old sun-2 pure executable
+>16 belong >0 not stripped
+0 belong 0413 old sun-2 demand paged executable
+>16 belong >0 not stripped
+
+#
+# Core files. "SPARC 4.x BCP" means "core file from a SunOS 4.x SPARC
+# binary executed in compatibility mode under SunOS 5.x".
+#
+0 belong 0x080456 SunOS core file
+>4 belong 432 (SPARC)
+>>132 string >\0 from '%s'
+>>116 belong =3 (quit)
+>>116 belong =4 (illegal instruction)
+>>116 belong =5 (trace trap)
+>>116 belong =6 (abort)
+>>116 belong =7 (emulator trap)
+>>116 belong =8 (arithmetic exception)
+>>116 belong =9 (kill)
+>>116 belong =10 (bus error)
+>>116 belong =11 (segmentation violation)
+>>116 belong =12 (bad argument to system call)
+>>116 belong =29 (resource lost)
+>>120 belong x (T=%dK,
+>>124 belong x D=%dK,
+>>128 belong x S=%dK)
+>4 belong 826 (68K)
+>>128 string >\0 from '%s'
+>4 belong 456 (SPARC 4.x BCP)
+>>152 string >\0 from '%s'
+# Sun SunPC
+0 long 0xfa33c08e SunPC 4.0 Hard Disk
+0 string #SUNPC_CONFIG SunPC 4.0 Properties Values
+# Sun snoop
+#
+# XXX - are numbers stored in big-endian format, or in host byte order?
+# They're the same on SPARC, but not the same on x86.
+#
+0 string snoop Snoop capture file
+>8 long >0 - version %ld
+>12 long 0 (IEEE 802.3)
+>12 long 1 (IEEE 802.4)
+>12 long 2 (IEEE 802.5)
+>12 long 3 (IEEE 802.6)
+>12 long 4 (Ethernet)
+>12 long 5 (HDLC)
+>12 long 6 (Character synchronous)
+>12 long 7 (IBM channel-to-channel adapter)
+>12 long 8 (FDDI)
+>12 long 9 (Unknown)
+# Sun KCMS
+36 string acsp Kodak Color Management System, ICC Profile
+
+
diff --git a/usr.bin/file/Magdir/sunraster b/usr.bin/file/Magdir/sunraster
new file mode 100644
index 0000000..39db3a3
--- /dev/null
+++ b/usr.bin/file/Magdir/sunraster
@@ -0,0 +1,12 @@
+#
+# Sun rasterfiles
+#
+# XXX - byte order? What about the 386i?
+#
+0 string \x59\xa6\x6a\x95 rasterfile
+>4 belong >0 %d
+>8 belong >0 x %d
+>12 belong >0 x %d
+>20 belong 0 old format
+>20 belong 2 compressed
+>24 belong 1 with color map
diff --git a/usr.bin/file/Magdir/terminfo b/usr.bin/file/Magdir/terminfo
new file mode 100644
index 0000000..2226ce8
--- /dev/null
+++ b/usr.bin/file/Magdir/terminfo
@@ -0,0 +1,9 @@
+
+#------------------------------------------------------------------------------
+# terminfo: file(1) magic for terminfo
+#
+# XXX - byte order for screen images?
+#
+0 string \032\001 Compiled terminfo entry
+0 short 0433 Curses screen image
+0 short 0434 Curses screen image
diff --git a/usr.bin/file/Magdir/tex b/usr.bin/file/Magdir/tex
new file mode 100644
index 0000000..5126be8
--- /dev/null
+++ b/usr.bin/file/Magdir/tex
@@ -0,0 +1,36 @@
+
+#------------------------------------------------------------------------------
+# tex: file(1) magic for TeX files
+#
+# From <conklin@talisman.kaleida.com>
+
+# Although we may know the offset of certain text fields in TeX DVI
+# and font files, we can't use them reliably because they are not
+# zero terminated. [but we do anyway, christos]
+0 string \367\002 TeX DVI file
+>16 string >\0 (%s)
+0 string \367\203 TeX generic font data
+0 string \367\131 TeX packed font data
+>3 string >\0 (%s)
+0 string \367\312 TeX virtual font data
+0 string This\ is\ TeX, TeX transcript text
+0 string This\ is\ METAFONT, METAFONT transcript text
+
+# There is no way to detect TeX Font Metric (*.tfm) files without
+# breaking them apart and reading the data. The following patterns
+# match most *.tfm files generated by METAFONT or afm2tfm.
+2 string \000\021 TeX font metric data
+>33 string >\0 (%s)
+2 string \000\022 TeX font metric data
+>33 string >\0 (%s)
+
+# Texinfo and GNU Info, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string \\input\ texinfo Texinfo source text
+0 string This\ is\ Info\ file GNU Info text
+
+# TeX documents, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string \\input TeX document text
+0 string \\section LaTeX document text
+0 string \\setlength LaTeX document text
+0 string \\documentstyle LaTeX document text
+0 string \\chapter LaTeX document text
diff --git a/usr.bin/file/Magdir/timezone b/usr.bin/file/Magdir/timezone
new file mode 100644
index 0000000..e47a371
--- /dev/null
+++ b/usr.bin/file/Magdir/timezone
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# timezone: file(1) magic for timezone data
+#
+# from Daniel Quinlan (quinlan@yggdrasil.com)
+# this should work on Linux, SunOS, and maybe others
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0 timezone data
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0 timezone data
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0 timezone data
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0 timezone data
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\5\0 timezone data
+0 string \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\6\0 timezone data
diff --git a/usr.bin/file/Magdir/troff b/usr.bin/file/Magdir/troff
new file mode 100644
index 0000000..ea75e85
--- /dev/null
+++ b/usr.bin/file/Magdir/troff
@@ -0,0 +1,27 @@
+
+#------------------------------------------------------------------------------
+# troff: file(1) magic for *roff
+#
+# updated by Daniel Quinlan (quinlan@yggdrasil.com)
+
+# troff input
+0 string .\\" troff or preprocessor input text
+0 string '\\" troff or preprocessor input text
+0 string '.\\" troff or preprocessor input text
+0 string \\" troff or preprocessor input text
+
+# ditroff intermediate output text
+0 string x\ T ditroff text
+>4 string cat for the C/A/T phototypesetter
+>4 string ps for PostScript
+>4 string dvi for DVI
+>4 string ascii for ASCII
+>4 string lj4 for LaserJet 4
+>4 string latin1 for ISO 8859-1 (Latin 1)
+>4 string X75 for xditview at 75dpi
+>>7 string -12 (12pt)
+>4 string X100 for xditview at 100dpi
+>>8 string -12 (12pt)
+
+# output data formats
+0 string \100\357 very old (C/A/T) troff output data
diff --git a/usr.bin/file/Magdir/typeset b/usr.bin/file/Magdir/typeset
new file mode 100644
index 0000000..2eda7c3
--- /dev/null
+++ b/usr.bin/file/Magdir/typeset
@@ -0,0 +1,7 @@
+
+#------------------------------------------------------------------------------
+# typeset: file(1) magic for other typesetting
+#
+0 string Interpress/Xerox Xerox InterPress data
+>16 string / (version
+>>17 string >\0 %s)
diff --git a/usr.bin/file/Magdir/unknown b/usr.bin/file/Magdir/unknown
new file mode 100644
index 0000000..843dc293
--- /dev/null
+++ b/usr.bin/file/Magdir/unknown
@@ -0,0 +1,36 @@
+
+#------------------------------------------------------------------------------
+# unknown: file(1) magic for unknown machines
+#
+# XXX - this probably should be pruned, as it'll match PDP-11 and
+# VAX image formats.
+#
+# 0x107 is 0407; 0x108 is 0410; both are PDP-11 (executable and pure,
+# respectively).
+#
+# 0x109 is 0411; that's PDP-11 split I&D, but the PDP-11 version doesn't
+# have the "version %ld", which may be a bogus COFFism (I don't think
+# there ever was COFF for the PDP-11).
+#
+# 0x10B is 0413; that's VAX demand-paged, but this is a short, not a
+# long, as it would be on a VAX.
+#
+# 0x10C is 0414, 0x10D is 0415, and 0x10E is 416; those *are* unknown.
+#
+0 short 0x107 unknown machine executable
+>8 short >0 not stripped
+>15 byte >0 - version %ld
+0 short 0x108 unknown pure executable
+>8 short >0 not stripped
+>15 byte >0 - version %ld
+0 short 0x109 PDP-11 separate I&D
+>8 short >0 not stripped
+>15 byte >0 - version %ld
+0 short 0x10b unknown pure executable
+>8 short >0 not stripped
+>15 byte >0 - version %ld
+0 long 0x10c unknown demand paged pure executable
+>16 long >0 not stripped
+0 long 0x10d unknown demand paged pure executable
+>16 long >0 not stripped
+0 long 0x10e unknown readable demand paged pure executable
diff --git a/usr.bin/file/Magdir/uuencode b/usr.bin/file/Magdir/uuencode
new file mode 100644
index 0000000..7e88619
--- /dev/null
+++ b/usr.bin/file/Magdir/uuencode
@@ -0,0 +1,30 @@
+
+#------------------------------------------------------------------------------
+# uuencode: file(1) magic for ASCII-encoded files
+#
+
+# GRR: the first line of xxencoded files is identical to that in uuencoded
+# files, but the first character in most subsequent lines is 'h' instead of
+# 'M'. (xxencoding uses lowercase letters in place of most of uuencode's
+# punctuation and survives BITNET gateways better.) If regular expressions
+# were supported, this entry could possibly be split into two with
+# "begin\040\.\*\012M" or "begin\040\.\*\012h" (where \. and \* are REs).
+0 string begin\040 uuencoded or xxencoded text
+
+# btoa(1) is an alternative to uuencode that requires less space.
+0 string xbtoa\ Begin btoa'd text
+
+# ship(1) is another, much cooler alternative to uuencode.
+# Greg Roelofs, newt@uchicago.edu
+0 string $\012ship ship'd binary text
+
+# bencode(8) is used to encode compressed news batches (Bnews/Cnews only?)
+# Greg Roelofs, newt@uchicago.edu
+0 string Decode\ the\ following\ with\ bdeco bencoded News text
+
+# BinHex is the Macintosh ASCII-encoded file format (see also "apple")
+# Daniel Quinlan, quinlan@yggdrasil.com
+11 string must\ be\ converted\ with\ BinHex BinHex binary text
+>41 string x \b, version %.3s
+
+# GRR: is MIME BASE64 encoding handled somewhere?
diff --git a/usr.bin/file/Magdir/varied.out b/usr.bin/file/Magdir/varied.out
new file mode 100644
index 0000000..9245cfc
--- /dev/null
+++ b/usr.bin/file/Magdir/varied.out
@@ -0,0 +1,18 @@
+
+#------------------------------------------------------------------------------
+# varied.out: file(1) magic for various USG systems
+#
+# Herewith many of the object file formats used by USG systems.
+# Most have been moved to files for a particular processor,
+# and deleted if they duplicate other entries.
+#
+0 short 0610 Perkin-Elmer executable
+# AMD 29K
+0 beshort 0572 amd 29k coff noprebar executable
+0 beshort 01572 amd 29k coff prebar executable
+0 beshort 0160007 amd 29k coff archive
+# Cray
+6 beshort 0407 unicos (cray) executable
+# Ultrix 4.3
+596 string \130\337\377\377 Ultrix core file
+>600 string >\0 '%s'
diff --git a/usr.bin/file/Magdir/vax b/usr.bin/file/Magdir/vax
new file mode 100644
index 0000000..7dd86cc
--- /dev/null
+++ b/usr.bin/file/Magdir/vax
@@ -0,0 +1,34 @@
+
+#------------------------------------------------------------------------------
+# vax: file(1) magic for VAX executable/object and APL workspace
+#
+0 lelong 0101557 VAX single precision APL workspace
+0 lelong 0101556 VAX double precision APL workspace
+
+#
+# VAX a.out (32V, BSD)
+#
+0 lelong 0407 VAX executable
+>16 lelong >0 not stripped
+
+0 lelong 0410 VAX pure executable
+>16 lelong >0 not stripped
+
+0 lelong 0413 VAX demand paged pure executable
+>16 lelong >0 not stripped
+
+0 lelong 0420 VAX demand paged (first page unmapped) pure executable
+>16 lelong >0 not stripped
+
+#
+# VAX COFF
+#
+# The `versions' should be un-commented if they work for you.
+# (Was the problem just one of endianness?)
+#
+0 leshort 0570 VAX COFF executable
+>12 lelong >0 not stripped
+>22 leshort >0 - version %ld
+0 leshort 0575 VAX COFF pure executable
+>12 lelong >0 not stripped
+>22 leshort >0 - version %ld
diff --git a/usr.bin/file/Magdir/visx b/usr.bin/file/Magdir/visx
new file mode 100644
index 0000000..4919964
--- /dev/null
+++ b/usr.bin/file/Magdir/visx
@@ -0,0 +1,31 @@
+
+#------------------------------------------------------------------------------
+# visx: file(1) magic for Visx format files
+#
+0 short 0x5555 VISX image file
+>2 byte 0 (zero)
+>2 byte 1 (unsigned char)
+>2 byte 2 (short integer)
+>2 byte 3 (float 32)
+>2 byte 4 (float 64)
+>2 byte 5 (signed char)
+>2 byte 6 (bit-plane)
+>2 byte 7 (classes)
+>2 byte 8 (statistics)
+>2 byte 10 (ascii text)
+>2 byte 15 (image segments)
+>2 byte 100 (image set)
+>2 byte 101 (unsigned char vector)
+>2 byte 102 (short integer vector)
+>2 byte 103 (float 32 vector)
+>2 byte 104 (float 64 vector)
+>2 byte 105 (signed char vector)
+>2 byte 106 (bit plane vector)
+>2 byte 121 (feature vector)
+>2 byte 122 (feature vector library)
+>2 byte 124 (chain code)
+>2 byte 126 (bit vector)
+>2 byte 130 (graph)
+>2 byte 131 (adjacency graph)
+>2 byte 132 (adjacency graph library)
+>2 string .VISIX (ascii text)
diff --git a/usr.bin/file/Magdir/vms b/usr.bin/file/Magdir/vms
new file mode 100644
index 0000000..c91186f
--- /dev/null
+++ b/usr.bin/file/Magdir/vms
@@ -0,0 +1,27 @@
+
+#------------------------------------------------------------------------------
+# vms: file(1) magic for VMS executables (experimental)
+#
+# VMS .exe formats, both VAX and AXP (Greg Roelofs, newt@uchicago.edu)
+
+# GRR 950122: I'm just guessing on these, based on inspection of the headers
+# of three executables each for Alpha and VAX architectures. The VAX files
+# all had headers similar to this:
+#
+# 00000 b0 00 30 00 44 00 60 00 00 00 00 00 30 32 30 35 ..0.D.`.....0205
+# 00010 01 01 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 ................
+#
+0 string \xb0\0\x30\0 VMS VAX executable
+>44032 string PK\003\004 \b, Info-ZIP SFX archive v5.12 w/decryption
+#
+# The AXP files all looked like this, except that the byte at offset 0x22
+# was 06 in some of them and 07 in others:
+#
+# 00000 03 00 00 00 00 00 00 00 ec 02 00 00 10 01 00 00 ................
+# 00010 68 00 00 00 98 00 00 00 b8 00 00 00 00 00 00 00 h...............
+# 00020 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+# 00030 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
+# 00040 00 00 00 00 ff ff ff ff ff ff ff ff 02 00 00 00 ................
+#
+0 belong 0x03000000 VMS Alpha executable
+>75264 string PK\003\004 \b, Info-ZIP SFX archive v5.12 w/decryption
diff --git a/usr.bin/file/Magdir/x11 b/usr.bin/file/Magdir/x11
new file mode 100644
index 0000000..a0f3b92
--- /dev/null
+++ b/usr.bin/file/Magdir/x11
@@ -0,0 +1,11 @@
+#
+# magic.x11
+#
+# I think this is byte-order-dependent; if so, it should become:
+#
+# 0 belong 00000004 X11 big-endian snf font
+# 0 lelong 00000004 X11 little-endian snf font
+#
+0 long 00000004 X11 snf font
+0 string STARTFONT X11 bdf font text
+0 string /*\040XPM\040*/ X11 XPM pixmap text
diff --git a/usr.bin/file/Magdir/xenix b/usr.bin/file/Magdir/xenix
new file mode 100644
index 0000000..1acadec
--- /dev/null
+++ b/usr.bin/file/Magdir/xenix
@@ -0,0 +1,72 @@
+
+#------------------------------------------------------------------------------
+# xenix: file(1) magic for Microsoft Xenix
+#
+# "Middle model" stuff, and "Xenix 8086 relocatable or 80286 small
+# model" lifted from "magic.xenix", with comment "derived empirically;
+# treat as folklore until proven"
+#
+# "small model", "large model", "huge model" stuff lifted from XXX
+#
+# XXX - "x.out" collides with PDP-11 archives
+#
+0 string core core file (Xenix)
+0 byte 0x80 8086 relocatable (Microsoft)
+0 leshort 0xff65 x.out
+>2 string __.SYMDEF randomized
+>0 byte x archive
+0 leshort 0x206 Microsoft a.out
+>8 leshort 1 Middle model
+>0x1e leshort &0x10 overlay
+>0x1e leshort &0x2 separate
+>0x1e leshort &0x4 pure
+>0x1e leshort &0x800 segmented
+>0x1e leshort &0x400 standalone
+>0x1e leshort &0x8 fixed-stack
+>0x1c byte &0x80 byte-swapped
+>0x1c byte &0x40 word-swapped
+>0x10 lelong >0 not-stripped
+>0x1e leshort ^0xc000 pre-SysV
+>0x1e leshort &0x4000 V2.3
+>0x1e leshort &0x8000 V3.0
+>0x1c byte &0x4 86
+>0x1c byte &0xb 186
+>0x1c byte &0x9 286
+>0x1c byte &0xa 386
+>0x1f byte <0x040 small model
+>0x1f byte =0x048 large model
+>0x1f byte =0x049 huge model
+>0x1e leshort &0x1 executable
+>0x1e leshort ^0x1 object file
+>0x1e leshort &0x40 Large Text
+>0x1e leshort &0x20 Large Data
+>0x1e leshort &0x120 Huge Objects Enabled
+>0x10 lelong >0 not stripped
+
+0 leshort 0x140 old Microsoft 8086 x.out
+>0x3 byte &0x4 separate
+>0x3 byte &0x2 pure
+>0 byte &0x1 executable
+>0 byte ^0x1 relocatable
+>0x14 lelong >0 not stripped
+
+0 lelong 0x206 b.out
+>0x1e leshort &0x10 overlay
+>0x1e leshort &0x2 separate
+>0x1e leshort &0x4 pure
+>0x1e leshort &0x800 segmented
+>0x1e leshort &0x400 standalone
+>0x1e leshort &0x1 executable
+>0x1e leshort ^0x1 object file
+>0x1e leshort &0x4000 V2.3
+>0x1e leshort &0x8000 V3.0
+>0x1c byte &0x4 86
+>0x1c byte &0xb 186
+>0x1c byte &0x9 286
+>0x1c byte &0x29 286
+>0x1c byte &0xa 386
+>0x1e leshort &0x4 Large Text
+>0x1e leshort &0x2 Large Data
+>0x1e leshort &0x102 Huge Objects Enabled
+
+0 leshort 0x580 XENIX 8086 relocatable or 80286 small model
diff --git a/usr.bin/file/Magdir/zilog b/usr.bin/file/Magdir/zilog
new file mode 100644
index 0000000..b746e20
--- /dev/null
+++ b/usr.bin/file/Magdir/zilog
@@ -0,0 +1,11 @@
+
+#------------------------------------------------------------------------------
+# zilog: file(1) magic for Zilog Z8000.
+#
+# Was it big-endian or little-endian? My Product Specification doesn't
+# say.
+#
+0 long 0xe807 object file (z8000 a.out)
+0 long 0xe808 pure object file (z8000 a.out)
+0 long 0xe809 separate object file (z8000 a.out)
+0 long 0xe805 overlay object file (z8000 a.out)
diff --git a/usr.bin/file/Magdir/zyxel b/usr.bin/file/Magdir/zyxel
new file mode 100644
index 0000000..12a6abd
--- /dev/null
+++ b/usr.bin/file/Magdir/zyxel
@@ -0,0 +1,16 @@
+
+#------------------------------------------------------------------------------
+# zyxel: file(1) magic for ZyXEL modems
+#
+# From <rob@pe1chl.ampr.org>
+# These are the /etc/magic entries to decode datafiles as used for the
+# ZyXEL U-1496E DATA/FAX/VOICE modems. (This header conforms to a
+# ZyXEL-defined standard)
+
+0 string ZyXEL\002 ZyXEL voice data
+>10 byte 0 - CELP encoding
+>10 byte&0x0B 1 - ADPCM2 encoding
+>10 byte&0x0B 2 - ADPCM3 encoding
+>10 byte&0x0B 3 - ADPCM4 encoding
+>10 byte&0x0B 8 - New ADPCM3 encoding
+>10 byte&0x04 4 with resync
diff --git a/usr.bin/file/Makefile b/usr.bin/file/Makefile
new file mode 100644
index 0000000..5ca63c6
--- /dev/null
+++ b/usr.bin/file/Makefile
@@ -0,0 +1,56 @@
+# Makefile for file(1) cmd.
+# Copyright (c) Ian F. Darwin 86/09/01 - see LEGAL.NOTICE.
+# @(#)$Id: Makefile,v 1.10 1997/03/18 19:37:15 mpp Exp $
+#
+# This software is not subject to any license of the American Telephone
+# and Telegraph Company or of the Regents of the University of California.
+#
+# Permission is granted to anyone to use this software for any purpose on
+# any computer system, and to alter it and redistribute it freely, subject
+# to the following restrictions:
+#
+# 1. The author is not responsible for the consequences of use of this
+# software, no matter how awful, even if they arise from flaws in it.
+#
+# 2. The origin of this software must not be misrepresented, either by
+# explicit claim or by omission. Since few users ever read sources,
+# credits must appear in the documentation.
+#
+# 3. Altered versions must be plainly marked as such, and must not be
+# misrepresented as being the original software. Since few users
+# ever read sources, credits must appear in the documentation.
+#
+# 4. This notice may not be removed or altered.
+#
+# Hacked and dismembered for bmake (Geoff Rehmet).
+
+MAGICDIR= /usr/share/misc
+MAGICOWN= bin
+MAGICGRP= bin
+MAGICMODE= 444
+
+CFLAGS+= -DMAGIC='"$(MAGICDIR)/magic"' -DBUILTIN_ELF
+
+PROG= file
+SRCS= file.c apprentice.c fsmagic.c softmagic.c ascmagic.c \
+ compress.c is_tar.c readelf.c internat.c print.c
+
+MAN1= file.1
+MAN5= magic.5
+
+CLEANFILES+= magic
+
+MAGFILES= $(.CURDIR)/Magdir/Header\
+ $(.CURDIR)/Magdir/Localstuff\
+ $(.CURDIR)/Magdir/[a-z]*
+
+all: file magic
+
+magic: $(MAGFILES)
+ cat $(MAGFILES) > $(.TARGET)
+
+beforeinstall:
+ $(INSTALL) $(COPY) -o $(MAGICOWN) -g $(MAGICGRP) -m $(MAGICMODE) \
+ magic $(DESTDIR)$(MAGICDIR)/magic
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/file/PORTING b/usr.bin/file/PORTING
new file mode 100644
index 0000000..1fa5da1
--- /dev/null
+++ b/usr.bin/file/PORTING
@@ -0,0 +1,76 @@
+Portability of the new file(1) command.
+@(#) $Id$
+
+Read this file only if the program doesn't compile on your system.
+
+This release has been around UNIX; it has been compiled and tested
+in the following environments:
+
+SunOS sqarc 4.1.1 8 sun4
+ No problems.
+ULTRIX squint 4.2 0 RISC
+ No problems.
+A/UX sqmac 3.0a9 SVR22 mc68020
+ No problems.
+AIX sqibm 2 3 000XXXXXX100
+ Had weird "make" problems making "magic" file automatically; just
+ built it by hand. Your mileage may vary.
+SCO sqwang 3.2 2 i386
+ Compiles fine; their weird make can't handle "[a-z]*" as a dependancy,
+ so build magic by hand. Runs fine.
+sqzme sqzme 3.1.1 3 3B2
+ The 3B2 SVR3 needed a few tweaks as well as COPTS = -Ilocalinc
+ in order to compile.
+
+This version, reluctanly, includes <stdlib.h>, which won't exist
+on older systems or those that aren't even close to the ANSI C
+standard. There is a null "stdlib.h", and some other bogus headers,
+in subdirectory "localinc"; if you get complaints about missing
+stdlib.h and others, uncomment the line with COPTS=-Ilocalinc
+in the Makefile, and try again.
+
+You must have either <stdarg.h> or the older <varargs.h>, otherwise you'll
+have to butcher some routines in print.c.
+
+Beyond that, I have tried to make a program that doesn't need any
+command-line defines (-D) to specify what version of UNIX is in use,
+by using the definitions available in the system #include
+files. For example, the lstat(2) call is normally found in
+4BSD systems, but might be grafted into some other variant
+of UNIX. If it's done right (ie., using the same definitions),
+my program will compile and work correctly. Look at the #ifdefs
+to see how it's done.
+
+I've also tried to include source for all the non-portable library routines
+I used (getopt, str*). Non-portable here means `not in every
+reasonably standard UNIX out there: V7, System V, 4BSD'.
+These are in subdirectory "localsrc", and not used unless you
+need them; again, see the Makefile.
+
+There is one area that just might cause problems. On System
+V, they moved the definition of major() and minor() out of
+<sys/types.h> into <sys/sysmacros.h>. Hence, if major isn't
+defined after including types.h, I automatically include sys/sysmacros.h.
+This will work for 99% of the systems out there. ONLY if you
+have a system in which neither types.h nor sysmacros.h defines
+`major' will this automatic include fail (I hope). On such
+systems, you will get a compilation error in trying to compile
+a warning message. Please do the following:
+
+ 1) change the appropriate #include at the start of fsmagic.c
+and 2) let me know the name of the system, the release number,
+ and the name of the header file that *does* include
+ this "standard" definition.
+
+If you are running the old Ritchie PDP-11 C compiler or
+some other compiler that doesn't know about `void', you will have
+to include `-Dvoid=int' in the variable COPTS in the Makefile.
+
+Other than this, there should be no portability problems,
+but one never knows these days. Please let me know of any
+other problems you find porting to a UNIX system. I don't much
+care about non-UNIX systems but will collect widely-used magic
+numbers for them as well as for UNIX systems.
+
+Mark Moraes and Christos Zoulas
+(address in README)
diff --git a/usr.bin/file/README b/usr.bin/file/README
new file mode 100644
index 0000000..2193292
--- /dev/null
+++ b/usr.bin/file/README
@@ -0,0 +1,91 @@
+** README for file(1) Command **
+@(#) $Id: README,v 1.1.1.2 1997/03/18 17:58:39 mpp Exp $
+
+This is Release 3.x of Ian Darwin's (copyright but distributable)
+file(1) command. This version is the standard "file" command for Linux,
+*BSD, and other systems. (See "patchlevel.h" for the exact release number).
+
+UNIX is a trademark of UNIX System Laboratories.
+
+The prime contributor to Release 3.8 was Guy Harris, who put in megachanges
+including byte-order independance.
+
+The prime contributor to Release 3.0 was Christos Zoulas, who put
+in hundreds of lines of source code changes, including his own
+ANSIfication of the code (I liked my own ANSIfication better, but
+his (__P()) is the "Berkeley standard" way of doing it, and I wanted UCB
+to include the code...), his HP-like "indirection" (a feature of
+the HP file command, I think), and his mods that finally got the
+uncompress (-z) mode finished and working.
+
+This release has compiled in numerous environments; see PORTING
+for a list and problems.
+
+This fine freeware file(1) follows the USG (System V) model of the file
+command, rather than the Research (V7) version or the V7-derived 4.[23]
+Berkeley one. That is, the file /etc/magic contains much of the ritual
+information that is the source of this program's power. My version
+knows a little more magic (including tar archives) than System V; the
+/etc/magic parsing seems to be compatible with the (poorly documented)
+System V /etc/magic format (with one exception; see the man page).
+
+In addition, the /etc/magic file is built from a subdirectory
+for easier(?) maintenance. I will act as a clearinghouse for
+magic numbers assigned to all sorts of data files that
+are in reasonable circulation. Send your magic numbers,
+in magic(4) format please, to the maintainer, Christos Zoulas.
+
+LEGAL.NOTICE - read this first.
+README - read this second (you are currently reading this file).
+PORTING - read this only if the program won't compile.
+Makefile - read this next, adapt it as needed (particularly
+ the location of the old existing file command and
+ the man page layouts), type "make" to compile,
+ "make try" to try it out against your old version.
+ Expect some diffs, particularly since your original
+ file(1) may not grok the imbedded-space ("\ ") in
+ the current magic file, or may even not use the
+ magic file.
+apprentice.c - parses /etc/magic to learn magic
+ascmagic.c - third & last set of tests, based on hardwired assumptions.
+core - not included in distribution due to mailer limitations.
+debug.c - includes -c printout routine
+file.1 - man page for the command
+magic.4 - man page for the magic file, courtesy Guy Harris.
+ Install as magic.4 on USG and magic.5 on V7 or Berkeley; cf Makefile.
+file.c - main program
+file.h - header file
+fsmagic.c - first set of tests the program runs, based on filesystem info
+is_tar.c, tar.h - knows about tarchives (courtesy John Gilmore).
+magdir - directory of /etc/magic pieces
+ magdir/Makefile - ADJUST THIS FOR YOUR CONFIGURATION
+names.h - header file for ascmagic.c
+softmagic.c - 2nd set of tests, based on /etc/magic
+readelf.[ch] - Standalone elf parsing code.
+compress.c - on-the-fly decompression.
+internat.c - recognize international `text' files.
+print.c - print results, errors, warnings.
+
+If your gzip sometimes fails to decompress things complaining about a short
+file, apply this patch [which is going to be in the next version of gzip]:
+*** - Tue Oct 29 02:06:35 1996
+--- util.c Sun Jul 21 21:51:38 1996
+*** 106,111 ****
+--- 108,114 ----
+
+ if (insize == 0) {
+ if (eof_ok) return EOF;
++ flush_window();
+ read_error();
+ }
+ bytes_in += (ulg)insize;
+
+E-mail: christos@deshaw.com, moraes@deshaw.com
+
+Phone: Do not even think of telephoning me about this program. Send cash first!
+
+Parts of this software were developed at SoftQuad Inc., 56 Aberfoyle
+Cres, # 810, Toronto, Ontario CANADA M8X 2W4. Phone: 416-239-4801 or
+800-387-2777. Email: mail@sq.com. Call for information on SGML editing
+and browsing, Unix text processing, and customised products on Unix,
+DOS and Mac.
diff --git a/usr.bin/file/apprentice.c b/usr.bin/file/apprentice.c
new file mode 100644
index 0000000..9b358c1
--- /dev/null
+++ b/usr.bin/file/apprentice.c
@@ -0,0 +1,621 @@
+/*
+ * apprentice - make one pass through /etc/magic, learning its secrets.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "file.h"
+
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: apprentice.c,v 1.1.1.3 1997/03/18 17:58:42 mpp Exp $";
+#endif /* lint */
+
+#define EATAB {while (isascii((unsigned char) *l) && \
+ isspace((unsigned char) *l)) ++l;}
+#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
+ tolower((unsigned char) (l)) : (l))
+
+
+static int getvalue __P((struct magic *, char **));
+static int hextoint __P((int));
+static char *getstr __P((char *, char *, int, int *));
+static int parse __P((char *, int *, int));
+static void eatsize __P((char **));
+
+static int maxmagic = 0;
+
+static int apprentice_1 __P((char *, int));
+
+int
+apprentice(fn, check)
+char *fn; /* list of magic files */
+int check; /* non-zero? checking-only run. */
+{
+ char *p, *mfn;
+ int file_err, errs = -1;
+
+ maxmagic = MAXMAGIS;
+ magic = (struct magic *) calloc(sizeof(struct magic), maxmagic);
+ mfn = malloc(strlen(fn)+1);
+ if (magic == NULL || mfn == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ if (check)
+ return -1;
+ else
+ exit(1);
+ }
+ fn = strcpy(mfn, fn);
+
+ while (fn) {
+ p = strchr(fn, ':');
+ if (p)
+ *p++ = '\0';
+ file_err = apprentice_1(fn, check);
+ if (file_err > errs)
+ errs = file_err;
+ fn = p;
+ }
+ if (errs == -1)
+ (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
+ progname);
+ if (!check && errs)
+ exit(1);
+
+ free(mfn);
+ return errs;
+}
+
+static int
+apprentice_1(fn, check)
+char *fn; /* name of magic file */
+int check; /* non-zero? checking-only run. */
+{
+ static const char hdr[] =
+ "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
+ FILE *f;
+ char line[BUFSIZ+1];
+ int errs = 0;
+
+ f = fopen(fn, "r");
+ if (f==NULL) {
+ if (errno != ENOENT)
+ (void) fprintf(stderr,
+ "%s: can't read magic file %s (%s)\n",
+ progname, fn, strerror(errno));
+ return -1;
+ }
+
+ /* parse it */
+ if (check) /* print silly verbose header for USG compat. */
+ (void) printf("%s\n", hdr);
+
+ for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
+ if (line[0]=='#') /* comment, do not parse */
+ continue;
+ if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
+ continue;
+ line[strlen(line)-1] = '\0'; /* delete newline */
+ if (parse(line, &nmagic, check) != 0)
+ errs = 1;
+ }
+
+ (void) fclose(f);
+ return errs;
+}
+
+/*
+ * extend the sign bit if the comparison is to be signed
+ */
+uint32
+signextend(m, v)
+struct magic *m;
+uint32 v;
+{
+ if (!(m->flag & UNSIGNED))
+ switch(m->type) {
+ /*
+ * Do not remove the casts below. They are
+ * vital. When later compared with the data,
+ * the sign extension must have happened.
+ */
+ case BYTE:
+ v = (char) v;
+ break;
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = (short) v;
+ break;
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ case LONG:
+ case BELONG:
+ case LELONG:
+ v = (int32) v;
+ break;
+ case STRING:
+ break;
+ default:
+ magwarn("can't happen: m->type=%d\n",
+ m->type);
+ return -1;
+ }
+ return v;
+}
+
+/*
+ * parse one line from magic file, put into magic[index++] if valid
+ */
+static int
+parse(l, ndx, check)
+char *l;
+int *ndx, check;
+{
+ int i = 0, nd = *ndx;
+ struct magic *m;
+ char *t, *s;
+
+#define ALLOC_INCR 20
+ if (nd+1 >= maxmagic){
+ maxmagic += ALLOC_INCR;
+ if ((magic = (struct magic *) realloc(magic,
+ sizeof(struct magic) *
+ maxmagic)) == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ if (check)
+ return -1;
+ else
+ exit(1);
+ }
+ memset(&magic[*ndx], 0, sizeof(struct magic) * ALLOC_INCR);
+ }
+ m = &magic[*ndx];
+ m->flag = 0;
+ m->cont_level = 0;
+
+ while (*l == '>') {
+ ++l; /* step over */
+ m->cont_level++;
+ }
+
+ if (m->cont_level != 0 && *l == '(') {
+ ++l; /* step over */
+ m->flag |= INDIR;
+ }
+ if (m->cont_level != 0 && *l == '&') {
+ ++l; /* step over */
+ m->flag |= ADD;
+ }
+
+ /* get offset, then skip over it */
+ m->offset = (int) strtoul(l,&t,0);
+ if (l == t)
+ magwarn("offset %s invalid", l);
+ l = t;
+
+ if (m->flag & INDIR) {
+ m->in.type = LONG;
+ m->in.offset = 0;
+ /*
+ * read [.lbs][+-]nnnnn)
+ */
+ if (*l == '.') {
+ l++;
+ switch (LOWCASE(*l)) {
+ case 'l':
+ m->in.type = LONG;
+ break;
+ case 'h':
+ case 's':
+ m->in.type = SHORT;
+ break;
+ case 'c':
+ case 'b':
+ m->in.type = BYTE;
+ break;
+ default:
+ magwarn("indirect offset type %c invalid", *l);
+ break;
+ }
+ l++;
+ }
+ s = l;
+ if (*l == '+' || *l == '-') l++;
+ if (isdigit((unsigned char)*l)) {
+ m->in.offset = strtoul(l, &t, 0);
+ if (*s == '-') m->in.offset = - m->in.offset;
+ }
+ else
+ t = l;
+ if (*t++ != ')')
+ magwarn("missing ')' in indirect offset");
+ l = t;
+ }
+
+
+ while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
+ ++l;
+ EATAB;
+
+#define NBYTE 4
+#define NSHORT 5
+#define NLONG 4
+#define NSTRING 6
+#define NDATE 4
+#define NBESHORT 7
+#define NBELONG 6
+#define NBEDATE 6
+#define NLESHORT 7
+#define NLELONG 6
+#define NLEDATE 6
+
+ if (*l == 'u') {
+ ++l;
+ m->flag |= UNSIGNED;
+ }
+
+ /* get type, skip it */
+ if (strncmp(l, "byte", NBYTE)==0) {
+ m->type = BYTE;
+ l += NBYTE;
+ } else if (strncmp(l, "short", NSHORT)==0) {
+ m->type = SHORT;
+ l += NSHORT;
+ } else if (strncmp(l, "long", NLONG)==0) {
+ m->type = LONG;
+ l += NLONG;
+ } else if (strncmp(l, "string", NSTRING)==0) {
+ m->type = STRING;
+ l += NSTRING;
+ } else if (strncmp(l, "date", NDATE)==0) {
+ m->type = DATE;
+ l += NDATE;
+ } else if (strncmp(l, "beshort", NBESHORT)==0) {
+ m->type = BESHORT;
+ l += NBESHORT;
+ } else if (strncmp(l, "belong", NBELONG)==0) {
+ m->type = BELONG;
+ l += NBELONG;
+ } else if (strncmp(l, "bedate", NBEDATE)==0) {
+ m->type = BEDATE;
+ l += NBEDATE;
+ } else if (strncmp(l, "leshort", NLESHORT)==0) {
+ m->type = LESHORT;
+ l += NLESHORT;
+ } else if (strncmp(l, "lelong", NLELONG)==0) {
+ m->type = LELONG;
+ l += NLELONG;
+ } else if (strncmp(l, "ledate", NLEDATE)==0) {
+ m->type = LEDATE;
+ l += NLEDATE;
+ } else {
+ magwarn("type %s invalid", l);
+ return -1;
+ }
+ /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
+ if (*l == '&') {
+ ++l;
+ m->mask = signextend(m, strtoul(l, &l, 0));
+ eatsize(&l);
+ } else
+ m->mask = ~0L;
+ EATAB;
+
+ switch (*l) {
+ case '>':
+ case '<':
+ /* Old-style anding: "0 byte &0x80 dynamically linked" */
+ case '&':
+ case '^':
+ case '=':
+ m->reln = *l;
+ ++l;
+ break;
+ case '!':
+ if (m->type != STRING) {
+ m->reln = *l;
+ ++l;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ if (*l == 'x' && isascii((unsigned char)l[1]) &&
+ isspace((unsigned char)l[1])) {
+ m->reln = *l;
+ ++l;
+ goto GetDesc; /* Bill The Cat */
+ }
+ m->reln = '=';
+ break;
+ }
+ EATAB;
+
+ if (getvalue(m, &l))
+ return -1;
+ /*
+ * TODO finish this macro and start using it!
+ * #define offsetcheck {if (offset > HOWMANY-1)
+ * magwarn("offset too big"); }
+ */
+
+ /*
+ * now get last part - the description
+ */
+GetDesc:
+ EATAB;
+ if (l[0] == '\b') {
+ ++l;
+ m->nospflag = 1;
+ } else if ((l[0] == '\\') && (l[1] == 'b')) {
+ ++l;
+ ++l;
+ m->nospflag = 1;
+ } else
+ m->nospflag = 0;
+ while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
+ /* NULLBODY */;
+
+ if (check) {
+ mdump(m);
+ }
+ ++(*ndx); /* make room for next */
+ return 0;
+}
+
+/*
+ * Read a numeric value from a pointer, into the value union of a magic
+ * pointer, according to the magic type. Update the string pointer to point
+ * just after the number read. Return 0 for success, non-zero for failure.
+ */
+static int
+getvalue(m, p)
+struct magic *m;
+char **p;
+{
+ int slen;
+
+ if (m->type == STRING) {
+ *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
+ m->vallen = slen;
+ } else
+ if (m->reln != 'x') {
+ m->value.l = signextend(m, strtoul(*p, p, 0));
+ eatsize(p);
+ }
+ return 0;
+}
+
+/*
+ * Convert a string containing C character escapes. Stop at an unescaped
+ * space or tab.
+ * Copy the converted version to "p", returning its length in *slen.
+ * Return updated scan pointer as function result.
+ */
+static char *
+getstr(s, p, plen, slen)
+register char *s;
+register char *p;
+int plen, *slen;
+{
+ char *origs = s, *origp = p;
+ char *pmax = p + plen - 1;
+ register int c;
+ register int val;
+
+ while ((c = *s++) != '\0') {
+ if (isspace((unsigned char) c))
+ break;
+ if (p >= pmax) {
+ fprintf(stderr, "String too long: %s\n", origs);
+ break;
+ }
+ if(c == '\\') {
+ switch(c = *s++) {
+
+ case '\0':
+ goto out;
+
+ default:
+ *p++ = (char) c;
+ break;
+
+ case 'n':
+ *p++ = '\n';
+ break;
+
+ case 'r':
+ *p++ = '\r';
+ break;
+
+ case 'b':
+ *p++ = '\b';
+ break;
+
+ case 't':
+ *p++ = '\t';
+ break;
+
+ case 'f':
+ *p++ = '\f';
+ break;
+
+ case 'v':
+ *p++ = '\v';
+ break;
+
+ /* \ and up to 3 octal digits */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = c - '0';
+ c = *s++; /* try for 2 */
+ if(c >= '0' && c <= '7') {
+ val = (val<<3) | (c - '0');
+ c = *s++; /* try for 3 */
+ if(c >= '0' && c <= '7')
+ val = (val<<3) | (c-'0');
+ else
+ --s;
+ }
+ else
+ --s;
+ *p++ = (char)val;
+ break;
+
+ /* \x and up to 2 hex digits */
+ case 'x':
+ val = 'x'; /* Default if no digits */
+ c = hextoint(*s++); /* Get next char */
+ if (c >= 0) {
+ val = c;
+ c = hextoint(*s++);
+ if (c >= 0)
+ val = (val << 4) + c;
+ else
+ --s;
+ } else
+ --s;
+ *p++ = (char)val;
+ break;
+ }
+ } else
+ *p++ = (char)c;
+ }
+out:
+ *p = '\0';
+ *slen = p - origp;
+ return s;
+}
+
+
+/* Single hex char to int; -1 if not a hex char. */
+static int
+hextoint(c)
+int c;
+{
+ if (!isascii((unsigned char) c)) return -1;
+ if (isdigit((unsigned char) c)) return c - '0';
+ if ((c>='a')&&(c<='f')) return c + 10 - 'a';
+ if ((c>='A')&&(c<='F')) return c + 10 - 'A';
+ return -1;
+}
+
+
+/*
+ * Print a string containing C character escapes.
+ */
+void
+showstr(fp, s, len)
+FILE *fp;
+const char *s;
+int len;
+{
+ register char c;
+
+ for (;;) {
+ c = *s++;
+ if (len == -1) {
+ if (c == '\0')
+ break;
+ }
+ else {
+ if (len-- == 0)
+ break;
+ }
+ if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
+ (void) fputc(c, fp);
+ else {
+ (void) fputc('\\', fp);
+ switch (c) {
+
+ case '\n':
+ (void) fputc('n', fp);
+ break;
+
+ case '\r':
+ (void) fputc('r', fp);
+ break;
+
+ case '\b':
+ (void) fputc('b', fp);
+ break;
+
+ case '\t':
+ (void) fputc('t', fp);
+ break;
+
+ case '\f':
+ (void) fputc('f', fp);
+ break;
+
+ case '\v':
+ (void) fputc('v', fp);
+ break;
+
+ default:
+ (void) fprintf(fp, "%.3o", c & 0377);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * eatsize(): Eat the size spec from a number [eg. 10UL]
+ */
+static void
+eatsize(p)
+char **p;
+{
+ char *l = *p;
+
+ if (LOWCASE(*l) == 'u')
+ l++;
+
+ switch (LOWCASE(*l)) {
+ case 'l': /* long */
+ case 's': /* short */
+ case 'h': /* short */
+ case 'b': /* char/byte */
+ case 'c': /* char/byte */
+ l++;
+ /*FALLTHROUGH*/
+ default:
+ break;
+ }
+
+ *p = l;
+}
diff --git a/usr.bin/file/ascmagic.c b/usr.bin/file/ascmagic.c
new file mode 100644
index 0000000..52f5090
--- /dev/null
+++ b/usr.bin/file/ascmagic.c
@@ -0,0 +1,124 @@
+/*
+ * ASCII magic -- file types that we know based on keywords
+ * that can appear anywhere in the file.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "file.h"
+#include "names.h"
+
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: ascmagic.c,v 1.1.1.3 1997/03/18 17:58:46 mpp Exp $";
+#endif /* lint */
+
+ /* an optimisation over plain strcmp() */
+#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+int
+ascmagic(buf, nbytes)
+unsigned char *buf;
+int nbytes; /* size actually read */
+{
+ int i, has_escapes = 0;
+ unsigned char *s;
+ char nbuf[HOWMANY+1]; /* one extra for terminating '\0' */
+ char *token;
+ register struct names *p;
+
+ /*
+ * Do the tar test first, because if the first file in the tar
+ * archive starts with a dot, we can confuse it with an nroff file.
+ */
+ switch (is_tar(buf, nbytes)) {
+ case 1:
+ ckfputs("tar archive", stdout);
+ return 1;
+ case 2:
+ ckfputs("POSIX tar archive", stdout);
+ return 1;
+ }
+
+ /*
+ * for troff, look for . + letter + letter or .\";
+ * this must be done to disambiguate tar archives' ./file
+ * and other trash from real troff input.
+ */
+ if (*buf == '.') {
+ unsigned char *tp = buf + 1;
+
+ while (isascii(*tp) && isspace(*tp))
+ ++tp; /* skip leading whitespace */
+ if ((isascii(*tp) && (isalnum(*tp) || *tp=='\\') &&
+ isascii(tp[1]) && (isalnum(tp[1]) || tp[1] == '"'))) {
+ ckfputs("troff or preprocessor input text", stdout);
+ return 1;
+ }
+ }
+ if ((*buf == 'c' || *buf == 'C') &&
+ isascii(buf[1]) && isspace(buf[1])) {
+ ckfputs("fortran program text", stdout);
+ return 1;
+ }
+
+
+ /* Make sure we are dealing with ascii text before looking for tokens */
+ for (i = 0; i < nbytes; i++) {
+ if (!isascii(buf[i]))
+ return 0; /* not all ASCII */
+ }
+
+ /* look for tokens from names.h - this is expensive! */
+ /* make a copy of the buffer here because strtok() will destroy it */
+ s = (unsigned char*) memcpy(nbuf, buf, nbytes);
+ s[nbytes] = '\0';
+ has_escapes = (memchr(s, '\033', nbytes) != NULL);
+ while ((token = strtok((char *) s, " \t\n\r\f")) != NULL) {
+ s = NULL; /* make strtok() keep on tokin' */
+ for (p = names; p < names + NNAMES; p++) {
+ if (STREQ(p->name, token)) {
+ ckfputs(types[p->type], stdout);
+ if (has_escapes)
+ ckfputs(" (with escape sequences)",
+ stdout);
+ return 1;
+ }
+ }
+ }
+
+ /* all else fails, but it is ASCII... */
+ ckfputs("ASCII text", stdout);
+ if (has_escapes) {
+ ckfputs(" (with escape sequences)", stdout);
+ }
+ return 1;
+}
+
+
diff --git a/usr.bin/file/compress.c b/usr.bin/file/compress.c
new file mode 100644
index 0000000..95b3f9a
--- /dev/null
+++ b/usr.bin/file/compress.c
@@ -0,0 +1,122 @@
+/*
+ * compress routines:
+ * zmagic() - returns 0 if not recognized, uncompresses and prints
+ * information if recognized
+ * uncompress(method, old, n, newch) - uncompress old into new,
+ * using method, return sizeof new
+ * $Id$
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "file.h"
+
+static struct {
+ char *magic;
+ int maglen;
+ char *argv[3];
+ int silent;
+} compr[] = {
+ { "\037\235", 2, { "uncompress", "-c", NULL }, 0 }, /* compressed */
+ { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */
+ { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */
+ { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */
+ /* the standard pack utilities do not accept standard input */
+ { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */
+};
+
+static int ncompr = sizeof(compr) / sizeof(compr[0]);
+
+
+static int uncompress __P((int, const unsigned char *, unsigned char **, int));
+
+int
+zmagic(buf, nbytes)
+unsigned char *buf;
+int nbytes;
+{
+ unsigned char *newbuf;
+ int newsize;
+ int i;
+
+ for (i = 0; i < ncompr; i++) {
+ if (nbytes < compr[i].maglen)
+ continue;
+ if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0)
+ break;
+ }
+
+ if (i == ncompr)
+ return 0;
+
+ if ((newsize = uncompress(i, buf, &newbuf, nbytes)) != 0) {
+ tryit(newbuf, newsize, 1);
+ free(newbuf);
+ printf(" (");
+ tryit(buf, nbytes, 0);
+ printf(")");
+ }
+ return 1;
+}
+
+
+static int
+uncompress(method, old, newch, n)
+int method;
+const unsigned char *old;
+unsigned char **newch;
+int n;
+{
+ int fdin[2], fdout[2];
+
+ if (pipe(fdin) == -1 || pipe(fdout) == -1) {
+ error("cannot create pipe (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ switch (fork()) {
+ case 0: /* child */
+ (void) close(0);
+ (void) dup(fdin[0]);
+ (void) close(fdin[0]);
+ (void) close(fdin[1]);
+
+ (void) close(1);
+ (void) dup(fdout[1]);
+ (void) close(fdout[0]);
+ (void) close(fdout[1]);
+ if (compr[method].silent)
+ (void) close(2);
+
+ execvp(compr[method].argv[0], compr[method].argv);
+ error("could not execute `%s' (%s).\n",
+ compr[method].argv[0], strerror(errno));
+ /*NOTREACHED*/
+ case -1:
+ error("could not fork (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+
+ default: /* parent */
+ (void) close(fdin[0]);
+ (void) close(fdout[1]);
+ if (write(fdin[1], old, n) != n) {
+ error("write failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ (void) close(fdin[1]);
+ if ((*newch = (unsigned char *) malloc(n)) == NULL) {
+ error("out of memory.\n");
+ /*NOTREACHED*/
+ }
+ if ((n = read(fdout[0], *newch, n)) <= 0) {
+ free(*newch);
+ error("read failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ (void) close(fdout[0]);
+ (void) wait(NULL);
+ return n;
+ }
+}
diff --git a/usr.bin/file/cvsimport.sh b/usr.bin/file/cvsimport.sh
new file mode 100644
index 0000000..f9818fa
--- /dev/null
+++ b/usr.bin/file/cvsimport.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+# import sequence for file(1)
+# This shell script can be used in order to handle future imports
+# of newer versions of file(1)
+#
+# $Id: cvsimport.sh,v 1.3 1997/02/22 19:29:10 peter Exp $
+if [ $# -ne 2 ] ; then
+ echo "usage: $0 <major> <minor>" 1>&2
+ exit 1
+fi
+version=$1.$2
+tar xzf file-$version.tar.gz
+cd file-$version
+mv file.man file.1
+mv magic.man magic.5
+rm Magdir/Makefile
+mv Magdir/msdos Magdir/ms-dos
+cvs -n import src/usr.bin/file DARWIN file_$1_$2
diff --git a/usr.bin/file/file.1 b/usr.bin/file/file.1
new file mode 100644
index 0000000..ba28b3f
--- /dev/null
+++ b/usr.bin/file/file.1
@@ -0,0 +1,366 @@
+.TH FILE 1 "Copyright but distributable"
+.\" $Id: file.1,v 1.9 1997/03/18 19:37:17 mpp Exp $
+.SH NAME
+file \- determine file type
+.SH SYNOPSIS
+.B file
+[
+.B \-vczL
+]
+[
+.B \-f
+namefile ]
+[
+.B \-m
+magicfiles ]
+file ...
+.SH DESCRIPTION
+This manual page documents version 3.22 of the
+.B file
+command.
+.B File
+tests each argument in an attempt to classify it.
+There are three sets of tests, performed in this order:
+filesystem tests, magic number tests, and language tests.
+The
+.I first
+test that succeeds causes the file type to be printed.
+.PP
+The type printed will usually contain one of the words
+.B text
+(the file contains only
+.SM ASCII
+characters and is probably safe to read on an
+.SM ASCII
+terminal),
+.B executable
+(the file contains the result of compiling a program
+in a form understandable to some \s-1UNIX\s0 kernel or another),
+or
+.B data
+meaning anything else (data is usually `binary' or non-printable).
+Exceptions are well-known file formats (core files, tar archives)
+that are known to contain binary data.
+When modifying the file
+.I /usr/share/misc/magic
+or the program itself,
+.B "preserve these keywords" .
+People depend on knowing that all the readable files in a directory
+have the word ``text'' printed.
+Don't do as Berkeley did \- change ``shell commands text''
+to ``shell script''.
+.PP
+The filesystem tests are based on examining the return from a
+.BR stat (2)
+system call.
+The program checks to see if the file is empty,
+or if it's some sort of special file.
+Any known file types appropriate to the system you are running on
+(sockets, symbolic links, or named pipes (FIFOs) on those systems that
+implement them)
+are intuited if they are defined in
+the system header file
+.IR sys/stat.h .
+.PP
+The magic number tests are used to check for files with data in
+particular fixed formats.
+The canonical example of this is a binary executable (compiled program)
+.I a.out
+file, whose format is defined in
+.I a.out.h
+and possibly
+.I exec.h
+in the standard include directory.
+These files have a `magic number' stored in a particular place
+near the beginning of the file that tells the \s-1UNIX\s0 operating system
+that the file is a binary executable, and which of several types thereof.
+The concept of `magic number' has been applied by extension to data files.
+Any file with some invariant identifier at a small fixed
+offset into the file can usually be described in this way.
+The information in these files is read from the magic file
+.I /usr/share/misc/magic.
+.PP
+If an argument appears to be an
+.SM ASCII
+file,
+.B file
+attempts to guess its language.
+The language tests look for particular strings (cf
+.IR names.h )
+that can appear anywhere in the first few blocks of a file.
+For example, the keyword
+.B .br
+indicates that the file is most likely a
+.BR troff (1)
+input file, just as the keyword
+.B struct
+indicates a C program.
+These tests are less reliable than the previous
+two groups, so they are performed last.
+The language test routines also test for some miscellany
+(such as
+.BR tar (1)
+archives) and determine whether an unknown file should be
+labelled as `ascii text' or `data'.
+.SH OPTIONS
+.TP 8
+.B \-v
+Print the version of the program and exit.
+.TP 8
+.B \-m list
+Specify an alternate list of files containing magic numbers.
+This can be a single file, or a colon-separated list of files.
+.TP 8
+.B \-z
+Try to look inside compressed files.
+.TP 8
+.B \-c
+Cause a checking printout of the parsed form of the magic file.
+This is usually used in conjunction with
+.B \-m
+to debug a new magic file before installing it.
+.TP 8
+.B \-f namefile
+Read the names of the files to be examined from
+.I namefile
+(one per line)
+before the argument list.
+Either
+.I namefile
+or at least one filename argument must be present;
+to test the standard input, use ``-'' as a filename argument.
+.TP 8
+.B \-L
+option causes symlinks to be followed, as the like-named option in
+.BR ls (1).
+(on systems that support symbolic links).
+.SH FILES
+.I /usr/share/misc/magic
+\- default list of magic numbers (used to be
+.I /etc/magic
+in previous versions of FreeBSD)
+.SH ENVIRONMENT
+The environment variable
+.B MAGIC
+can be used to set the default magic number files.
+.SH SEE ALSO
+.BR magic (5)
+\- description of magic file format.
+.br
+.BR strings (1), " od" (1)
+\- tools for examining non-textfiles.
+.SH STANDARDS CONFORMANCE
+This program is believed to exceed the System V Interface Definition
+of FILE(CMD), as near as one can determine from the vague language
+contained therein.
+Its behavior is mostly compatible with the System V program of the same name.
+This version knows more magic, however, so it will produce
+different (albeit more accurate) output in many cases.
+.PP
+The one significant difference
+between this version and System V
+is that this version treats any white space
+as a delimiter, so that spaces in pattern strings must be escaped.
+For example,
+.br
+>10 string language impress\ (imPRESS data)
+.br
+in an existing magic file would have to be changed to
+.br
+>10 string language\e impress (imPRESS data)
+.br
+In addition, in this version, if a pattern string contains a backslash,
+it must be escaped. For example
+.br
+0 string \ebegindata Andrew Toolkit document
+.br
+in an existing magic file would have to be changed to
+.br
+0 string \e\ebegindata Andrew Toolkit document
+.br
+.PP
+SunOS releases 3.2 and later from Sun Microsystems include a
+.BR file (1)
+command derived from the System V one, but with some extensions.
+My version differs from Sun's only in minor ways.
+It includes the extension of the `&' operator, used as,
+for example,
+.br
+>16 long&0x7fffffff >0 not stripped
+.SH MAGIC DIRECTORY
+The magic file entries have been collected from various sources,
+mainly USENET, and contributed by various authors.
+Christos Zoulas (address below) will collect additional
+or corrected magic file entries.
+A consolidation of magic file entries
+will be distributed periodically.
+.PP
+The order of entries in the magic file is significant.
+Depending on what system you are using, the order that
+they are put together may be incorrect.
+If your old
+.B file
+command uses a magic file,
+keep the old magic file around for comparison purposes
+(rename it to
+.IR /usr/share/misc/magic.orig ).
+.SH HISTORY
+There has been a
+.B file
+command in every \s-1UNIX\s0 since at least Research Version 6
+(man page dated January, 1975).
+The System V version introduced one significant major change:
+the external list of magic number types.
+This slowed the program down slightly but made it a lot more flexible.
+.PP
+This program, based on the System V version,
+was written by Ian Darwin without looking at anybody else's source code.
+.PP
+John Gilmore revised the code extensively, making it better than
+the first version.
+Geoff Collyer found several inadequacies
+and provided some magic file entries.
+The program has undergone continued evolution since.
+.SH AUTHOR
+Written by Ian F. Darwin, UUCP address {utzoo | ihnp4}!darwin!ian,
+Internet address ian@sq.com,
+postal address: P.O. Box 603, Station F, Toronto, Ontario, CANADA M4Y 2L8.
+.PP
+Altered by Rob McMahon, cudcv@warwick.ac.uk, 1989, to extend the `&' operator
+from simple `x&y != 0' to `x&y op z'.
+.PP
+Altered by Guy Harris, guy@auspex.com, 1993, to:
+.RS
+.PP
+put the ``old-style'' `&'
+operator back the way it was, because 1) Rob McMahon's change broke the
+previous style of usage, 2) the SunOS ``new-style'' `&' operator,
+which this version of
+.B file
+supports, also handles `x&y op z', and 3) Rob's change wasn't documented
+in any case;
+.PP
+put in multiple levels of `>';
+.PP
+put in ``beshort'', ``leshort'', etc. keywords to look at numbers in the
+file in a specific byte order, rather than in the native byte order of
+the process running
+.BR file .
+.RE
+.PP
+Changes by Ian Darwin and various authors including
+Christos Zoulas (christos@deshaw.com), 1990-1992.
+.SH LEGAL NOTICE
+Copyright (c) Ian F. Darwin, Toronto, Canada,
+1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993.
+.PP
+This software is not subject to and may not be made subject to any
+license of the American Telephone and Telegraph Company, Sun
+Microsystems Inc., Digital Equipment Inc., Lotus Development Inc., the
+Regents of the University of California, The X Consortium or MIT, or
+The Free Software Foundation.
+.PP
+This software is not subject to any export provision of the United States
+Department of Commerce, and may be exported to any country or planet.
+.PP
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it freely, subject
+to the following restrictions:
+.PP
+1. The author is not responsible for the consequences of use of this
+software, no matter how awful, even if they arise from flaws in it.
+.PP
+2. The origin of this software must not be misrepresented, either by
+explicit claim or by omission. Since few users ever read sources,
+credits must appear in the documentation.
+.PP
+3. Altered versions must be plainly marked as such, and must not be
+misrepresented as being the original software. Since few users
+ever read sources, credits must appear in the documentation.
+.PP
+4. This notice may not be removed or altered.
+.PP
+A few support files (\fIgetopt\fP, \fIstrtok\fP)
+distributed with this package
+are by Henry Spencer and are subject to the same terms as above.
+.PP
+A few simple support files (\fIstrtol\fP, \fIstrchr\fP)
+distributed with this package
+are in the public domain; they are so marked.
+.PP
+The files
+.I tar.h
+and
+.I is_tar.c
+were written by John Gilmore from his public-domain
+.B tar
+program, and are not covered by the above restrictions.
+.SH BUGS
+There must be a better way to automate the construction of the Magic
+file from all the glop in Magdir. What is it?
+Better yet, the magic file should be compiled into binary (say,
+.BR ndbm (3)
+or, better yet, fixed-length
+.SM ASCII
+strings for use in heterogenous network environments) for faster startup.
+Then the program would run as fast as the Version 7 program of the same name,
+with the flexibility of the System V version.
+.PP
+.B File
+uses several algorithms that favor speed over accuracy,
+thus it can be misled about the contents of
+.SM ASCII
+files.
+.PP
+The support for
+.SM ASCII
+files (primarily for programming languages)
+is simplistic, inefficient and requires recompilation to update.
+.PP
+There should be an ``else'' clause to follow a series of continuation lines.
+.PP
+The magic file and keywords should have regular expression support.
+Their use of
+.SM "ASCII TAB"
+as a field delimiter is ugly and makes
+it hard to edit the files, but is entrenched.
+.PP
+It might be advisable to allow upper-case letters in keywords
+for e.g.,
+.BR troff (1)
+commands vs man page macros.
+Regular expression support would make this easy.
+.PP
+The program doesn't grok \s-2FORTRAN\s0.
+It should be able to figure \s-2FORTRAN\s0 by seeing some keywords which
+appear indented at the start of line.
+Regular expression support would make this easy.
+.PP
+The list of keywords in
+.I ascmagic
+probably belongs in the Magic file.
+This could be done by using some keyword like `*' for the offset value.
+.PP
+Another optimization would be to sort
+the magic file so that we can just run down all the
+tests for the first byte, first word, first long, etc, once we
+have fetched it. Complain about conflicts in the magic file entries.
+Make a rule that the magic entries sort based on file offset rather
+than position within the magic file?
+.PP
+The program should provide a way to give an estimate
+of ``how good'' a guess is.
+We end up removing guesses (e.g. ``From '' as first 5 chars of file) because
+they are not as good as other guesses (e.g. ``Newsgroups:'' versus
+"Return-Path:"). Still, if the others don't pan out, it should be
+possible to use the first guess.
+.PP
+This program is slower than some vendors' file commands.
+.PP
+This manual page, and particularly this section, is too long.
+.SH AVAILABILITY
+You can obtain the original author's latest version by anonymous FTP
+on
+.B ftp.deshaw.com
+in the directory
+.I /pub/file/file-X.YY.tar.gz
diff --git a/usr.bin/file/file.c b/usr.bin/file/file.c
new file mode 100644
index 0000000..a5fe4b9
--- /dev/null
+++ b/usr.bin/file/file.c
@@ -0,0 +1,398 @@
+/*
+ * file - find type of a file or files - main program.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: file.c,v 1.7 1997/03/18 19:37:18 mpp Exp $";
+#endif /* lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h> /* for MAXPATHLEN */
+#include <sys/stat.h>
+#include <fcntl.h> /* for open() */
+#if (__COHERENT__ >= 0x420)
+# include <sys/utime.h>
+#else
+# ifdef USE_UTIMES
+# include <sys/time.h>
+# else
+# include <utime.h>
+# endif
+#endif
+#include <unistd.h> /* for read() */
+
+#include <netinet/in.h> /* for byte swapping */
+
+#include "patchlevel.h"
+#include "file.h"
+
+#ifdef S_IFLNK
+# define USAGE "Usage: %s [-vczL] [-f namefile] [-m magicfiles] file...\n"
+#else
+# define USAGE "Usage: %s [-vcz] [-f namefile] [-m magicfiles] file...\n"
+#endif
+
+#ifndef MAGIC
+# define MAGIC "/etc/magic"
+#endif
+
+int /* Global command-line options */
+ debug = 0, /* debugging */
+ lflag = 0, /* follow Symlinks (BSD only) */
+ zflag = 0; /* follow (uncompress) compressed files */
+
+int /* Misc globals */
+ nmagic = 0; /* number of valid magic[]s */
+
+struct magic *magic; /* array of magic entries */
+
+char *magicfile; /* where magic be found */
+
+char *progname; /* used throughout */
+int lineno; /* line number in the magic file */
+
+
+static void unwrap __P((char *fn));
+#if 0
+static int byteconv4 __P((int, int, int));
+static short byteconv2 __P((int, int, int));
+#endif
+
+/*
+ * main - parse arguments and handle options
+ */
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int c;
+ int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
+
+ if ((progname = strrchr(argv[0], '/')) != NULL)
+ progname++;
+ else
+ progname = argv[0];
+
+ if (!(magicfile = getenv("MAGIC")))
+ magicfile = MAGIC;
+
+ while ((c = getopt(argc, argv, "vcdf:Lm:z")) != -1)
+ switch (c) {
+ case 'v':
+ (void) fprintf(stdout, "%s-%d.%d\n", progname,
+ FILE_VERSION_MAJOR, patchlevel);
+ return 1;
+ case 'c':
+ ++check;
+ break;
+ case 'd':
+ ++debug;
+ break;
+ case 'f':
+ if (!app) {
+ ret = apprentice(magicfile, check);
+ if (check)
+ exit(ret);
+ app = 1;
+ }
+ unwrap(optarg);
+ ++didsomefiles;
+ break;
+#ifdef S_IFLNK
+ case 'L':
+ ++lflag;
+ break;
+#endif
+ case 'm':
+ magicfile = optarg;
+ break;
+ case 'z':
+ zflag++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+
+ if (errflg) {
+ (void) fprintf(stderr, USAGE, progname);
+ exit(2);
+ }
+
+ if (!app) {
+ ret = apprentice(magicfile, check);
+ if (check)
+ exit(ret);
+ app = 1;
+ }
+
+ if (optind == argc) {
+ if (!didsomefiles) {
+ (void)fprintf(stderr, USAGE, progname);
+ exit(2);
+ }
+ }
+ else {
+ int i, wid, nw;
+ for (wid = 0, i = optind; i < argc; i++) {
+ nw = strlen(argv[i]);
+ if (nw > wid)
+ wid = nw;
+ }
+ for (; optind < argc; optind++)
+ process(argv[optind], wid);
+ }
+
+ return 0;
+}
+
+
+/*
+ * unwrap -- read a file of filenames, do each one.
+ */
+static void
+unwrap(fn)
+char *fn;
+{
+ char buf[MAXPATHLEN];
+ FILE *f;
+ int wid = 0, cwid;
+
+ if (strcmp("-", fn) == 0) {
+ f = stdin;
+ wid = 1;
+ } else {
+ if ((f = fopen(fn, "r")) == NULL) {
+ error("Cannot open `%s' (%s).\n", fn, strerror(errno));
+ /*NOTREACHED*/
+ }
+
+ while (fgets(buf, MAXPATHLEN, f) != NULL) {
+ cwid = strlen(buf) - 1;
+ if (cwid > wid)
+ wid = cwid;
+ }
+
+ rewind(f);
+ }
+
+ while (fgets(buf, MAXPATHLEN, f) != NULL) {
+ buf[strlen(buf)-1] = '\0';
+ process(buf, wid);
+ }
+
+ (void) fclose(f);
+}
+
+
+#if 0
+/*
+ * byteconv4
+ * Input:
+ * from 4 byte quantity to convert
+ * same whether to perform byte swapping
+ * big_endian whether we are a big endian host
+ */
+static int
+byteconv4(from, same, big_endian)
+ int from;
+ int same;
+ int big_endian;
+{
+ if (same)
+ return from;
+ else if (big_endian) /* lsb -> msb conversion on msb */
+ {
+ union {
+ int i;
+ char c[4];
+ } retval, tmpval;
+
+ tmpval.i = from;
+ retval.c[0] = tmpval.c[3];
+ retval.c[1] = tmpval.c[2];
+ retval.c[2] = tmpval.c[1];
+ retval.c[3] = tmpval.c[0];
+
+ return retval.i;
+ }
+ else
+ return ntohl(from); /* msb -> lsb conversion on lsb */
+}
+
+/*
+ * byteconv2
+ * Same as byteconv4, but for shorts
+ */
+static short
+byteconv2(from, same, big_endian)
+ int from;
+ int same;
+ int big_endian;
+{
+ if (same)
+ return from;
+ else if (big_endian) /* lsb -> msb conversion on msb */
+ {
+ union {
+ short s;
+ char c[2];
+ } retval, tmpval;
+
+ tmpval.s = (short) from;
+ retval.c[0] = tmpval.c[1];
+ retval.c[1] = tmpval.c[0];
+
+ return retval.s;
+ }
+ else
+ return ntohs(from); /* msb -> lsb conversion on lsb */
+}
+#endif
+
+/*
+ * process - process input file
+ */
+void
+process(inname, wid)
+const char *inname;
+int wid;
+{
+ int fd = 0;
+ static const char stdname[] = "standard input";
+ unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
+ struct stat sb;
+ int nbytes = 0; /* number of bytes read from a datafile */
+ char match = '\0';
+
+ if (strcmp("-", inname) == 0) {
+ if (fstat(0, &sb)<0) {
+ error("cannot fstat `%s' (%s).\n", stdname,
+ strerror(errno));
+ /*NOTREACHED*/
+ }
+ inname = stdname;
+ }
+
+ if (wid > 0)
+ (void) printf("%s:%*s ", inname,
+ (int) (wid - strlen(inname)), "");
+
+ if (inname != stdname) {
+ /*
+ * first try judging the file based on its filesystem status
+ */
+ if (fsmagic(inname, &sb) != 0) {
+ putchar('\n');
+ return;
+ }
+
+ if ((fd = open(inname, O_RDONLY)) < 0) {
+ /* We can't open it, but we were able to stat it. */
+ if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
+ if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
+ ckfprintf(stdout, "can't read `%s' (%s).\n",
+ inname, strerror(errno));
+ return;
+ }
+ }
+
+
+ /*
+ * try looking at the first HOWMANY bytes
+ */
+ if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
+ error("read failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+
+ if (nbytes == 0)
+ ckfputs("empty", stdout);
+ else {
+ buf[nbytes++] = '\0'; /* null-terminate it */
+ match = tryit(buf, nbytes, zflag);
+ }
+
+#ifdef BUILTIN_ELF
+ if (match == 's' && nbytes > 5)
+ tryelf(fd, buf, nbytes);
+#endif
+
+ if (inname != stdname) {
+#ifdef RESTORE_TIME
+ /*
+ * Try to restore access, modification times if read it.
+ */
+# ifdef USE_UTIMES
+ struct timeval utsbuf[2];
+ utsbuf[0].tv_sec = sb.st_atime;
+ utsbuf[1].tv_sec = sb.st_mtime;
+
+ (void) utimes(inname, utsbuf); /* don't care if loses */
+# else
+ struct utimbuf utbuf;
+
+ utbuf.actime = sb.st_atime;
+ utbuf.modtime = sb.st_mtime;
+ (void) utime(inname, &utbuf); /* don't care if loses */
+# endif
+#endif
+ (void) close(fd);
+ }
+ (void) putchar('\n');
+}
+
+
+int
+tryit(buf, nb, zflag)
+unsigned char *buf;
+int nb, zflag;
+{
+ /* try compression stuff */
+ if (zflag && zmagic(buf, nb))
+ return 'z';
+
+ /* try tests in /etc/magic (or surrogate magic file) */
+ if (softmagic(buf, nb))
+ return 's';
+
+ /* try known keywords, check whether it is ASCII */
+ if (ascmagic(buf, nb))
+ return 'a';
+
+ /* see if it's international language text */
+ if (internatmagic(buf, nb))
+ return 'i';
+
+ /* abandon hope, all ye who remain here */
+ ckfputs("data", stdout);
+ return '\0';
+}
diff --git a/usr.bin/file/file.h b/usr.bin/file/file.h
new file mode 100644
index 0000000..bdca97b
--- /dev/null
+++ b/usr.bin/file/file.h
@@ -0,0 +1,151 @@
+/*
+ * file.h - definitions for file(1) program
+ * @(#)$Id: file.h,v 1.1.1.3 1997/03/18 17:58:51 mpp Exp $
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef __file_h__
+#define __file_h__
+
+typedef int int32;
+typedef unsigned int uint32;
+
+#ifndef HOWMANY
+# define HOWMANY 8192 /* how much of the file to look at */
+#endif
+#define MAXMAGIS 1000 /* max entries in /etc/magic */
+#define MAXDESC 50 /* max leng of text description */
+#define MAXstring 32 /* max leng of "string" types */
+
+struct magic {
+ short flag;
+#define INDIR 1 /* if '>(...)' appears, */
+#define UNSIGNED 2 /* comparison is unsigned */
+#define ADD 4 /* if '>&' appears, */
+ short cont_level; /* level of ">" */
+ struct {
+ char type; /* byte short long */
+ int32 offset; /* offset from indirection */
+ } in;
+ int32 offset; /* offset to magic number */
+ unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
+ char type; /* int, short, long or string. */
+ char vallen; /* length of string value, if any */
+#define BYTE 1
+#define SHORT 2
+#define LONG 4
+#define STRING 5
+#define DATE 6
+#define BESHORT 7
+#define BELONG 8
+#define BEDATE 9
+#define LESHORT 10
+#define LELONG 11
+#define LEDATE 12
+ union VALUETYPE {
+ unsigned char b;
+ unsigned short h;
+ uint32 l;
+ char s[MAXstring];
+ unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
+ unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
+ } value; /* either number or string */
+ uint32 mask; /* mask before comparison with value */
+ char nospflag; /* supress space character */
+ char desc[MAXDESC]; /* description */
+};
+
+#include <stdio.h> /* Include that here, to make sure __P gets defined */
+
+#ifndef __P
+# if __STDC__ || __cplusplus
+# define __P(a) a
+# else
+# define __P(a) ()
+# define const
+# endif
+#endif
+
+extern int apprentice __P((char *, int));
+extern int ascmagic __P((unsigned char *, int));
+extern void error __P((const char *, ...));
+extern void ckfputs __P((const char *, FILE *));
+struct stat;
+extern int fsmagic __P((const char *, struct stat *));
+extern int internatmagic __P((unsigned char *, int));
+extern int is_compress __P((const unsigned char *, int *));
+extern int is_tar __P((unsigned char *, int));
+extern void magwarn __P((const char *, ...));
+extern void mdump __P((struct magic *));
+extern void process __P((const char *, int));
+extern void showstr __P((FILE *, const char *, int));
+extern int softmagic __P((unsigned char *, int));
+extern int tryit __P((unsigned char *, int, int));
+extern int zmagic __P((unsigned char *, int));
+extern void ckfprintf __P((FILE *, const char *, ...));
+extern uint32 signextend __P((struct magic *, unsigned int32));
+extern int internatmagic __P((unsigned char *, int));
+extern void tryelf __P((int, char *, int));
+
+
+extern int errno; /* Some unixes don't define this.. */
+
+extern char *progname; /* the program name */
+extern char *magicfile; /* name of the magic file */
+extern int lineno; /* current line number in magic file */
+
+extern struct magic *magic; /* array of magic entries */
+extern int nmagic; /* number of valid magic[]s */
+
+
+extern int debug; /* enable debugging? */
+extern int zflag; /* process compressed files? */
+extern int lflag; /* follow symbolic links? */
+
+extern int optind; /* From getopt(3) */
+extern char *optarg;
+
+#if defined(sun) || defined(__sun__) || defined (__sun)
+# if defined(__svr4) || defined (__SVR4) || defined(__svr4__)
+# define SOLARIS
+# else
+# define SUNOS
+# endif
+#endif
+
+
+#if !defined(__STDC__) || defined(SUNOS) || defined(__convex__)
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define strerror(e) \
+ (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
+#define strtoul(a, b, c) strtol(a, b, c)
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 512
+#endif
+
+#endif /* __file_h__ */
diff --git a/usr.bin/file/fsmagic.c b/usr.bin/file/fsmagic.c
new file mode 100644
index 0000000..056d3ea
--- /dev/null
+++ b/usr.bin/file/fsmagic.c
@@ -0,0 +1,181 @@
+/*
+ * fsmagic - magic based on filesystem info - directory, special files, etc.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifndef major
+# if defined(__SVR4) || defined(_SVR4_SOURCE)
+# include <sys/mkdev.h>
+# endif
+#endif
+#ifndef major /* if `major' not defined in types.h, */
+#include <sys/sysmacros.h> /* try this one. */
+#endif
+#ifndef major /* still not defined? give up, manual intervention needed */
+ /* If cc tries to compile this, read and act on it. */
+ /* On most systems cpp will discard it automatically */
+ Congratulations, you have found a portability bug.
+ Please grep /usr/include/sys and edit the above #include
+ to point at the file that defines the "major" macro.
+#endif /*major*/
+
+#include "file.h"
+
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: fsmagic.c,v 1.1.1.3 1997/03/18 17:58:44 mpp Exp $";
+#endif /* lint */
+
+int
+fsmagic(fn, sb)
+const char *fn;
+struct stat *sb;
+{
+ int ret = 0;
+
+ /*
+ * Fstat is cheaper but fails for files you don't have read perms on.
+ * On 4.2BSD and similar systems, use lstat() to identify symlinks.
+ */
+#ifdef S_IFLNK
+ if (!lflag)
+ ret = lstat(fn, sb);
+ else
+#endif
+ ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
+
+ if (ret) {
+ ckfprintf(stdout,
+ /* Yes, I do mean stdout. */
+ /* No \n, caller will provide. */
+ "can't stat `%s' (%s).", fn, strerror(errno));
+ return 1;
+ }
+
+ if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout);
+ if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout);
+ if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout);
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFDIR:
+ ckfputs("directory", stdout);
+ return 1;
+ case S_IFCHR:
+ (void) printf("character special (%ld/%ld)",
+ (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
+ return 1;
+ case S_IFBLK:
+ (void) printf("block special (%ld/%ld)",
+ (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
+ return 1;
+ /* TODO add code to handle V7 MUX and Blit MUX files */
+#ifdef S_IFIFO
+ case S_IFIFO:
+ ckfputs("fifo (named pipe)", stdout);
+ return 1;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ {
+ char buf[BUFSIZ+4];
+ register int nch;
+ struct stat tstatbuf;
+
+ if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
+ ckfprintf(stdout, "unreadable symlink (%s).",
+ strerror(errno));
+ return 1;
+ }
+ buf[nch] = '\0'; /* readlink(2) forgets this */
+
+ /* If broken symlink, say so and quit early. */
+ if (*buf == '/') {
+ if (stat(buf, &tstatbuf) < 0) {
+ ckfprintf(stdout,
+ "broken symbolic link to %s", buf);
+ return 1;
+ }
+ }
+ else {
+ char *tmp;
+ char buf2[BUFSIZ+BUFSIZ+4];
+
+ if ((tmp = strrchr(fn, '/')) == NULL) {
+ tmp = buf; /* in current directory anyway */
+ }
+ else {
+ strcpy (buf2, fn); /* take directory part */
+ buf2[tmp-fn+1] = '\0';
+ strcat (buf2, buf); /* plus (relative) symlink */
+ tmp = buf2;
+ }
+ if (stat(tmp, &tstatbuf) < 0) {
+ ckfprintf(stdout,
+ "broken symbolic link to %s", buf);
+ return 1;
+ }
+ }
+
+ /* Otherwise, handle it. */
+ if (lflag) {
+ process(buf, strlen(buf));
+ return 1;
+ } else { /* just print what it points to */
+ ckfputs("symbolic link to ", stdout);
+ ckfputs(buf, stdout);
+ }
+ }
+ return 1;
+#endif
+#ifdef S_IFSOCK
+#ifndef __COHERENT__
+ case S_IFSOCK:
+ ckfputs("socket", stdout);
+ return 1;
+#endif
+#endif
+ case S_IFREG:
+ break;
+ default:
+ error("invalid mode 0%o.\n", sb->st_mode);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * regular file, check next possibility
+ */
+ if (sb->st_size == 0) {
+ ckfputs("empty", stdout);
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/usr.bin/file/internat.c b/usr.bin/file/internat.c
new file mode 100644
index 0000000..59a508a
--- /dev/null
+++ b/usr.bin/file/internat.c
@@ -0,0 +1,72 @@
+#include "file.h"
+
+#include <string.h>
+
+#define F 0
+#define T 1
+
+/*
+ * List of characters that look "reasonable" in international
+ * language texts. That's almost all characters :), except a
+ * few in the control range of ASCII (all the known international
+ * charactersets share the bottom half with ASCII).
+ */
+static char maybe_internat[256] = {
+ F, F, F, F, F, F, F, F, T, T, T, T, T, T, F, F, /* 0x0X */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x8X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x9X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0xaX */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0xbX */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0xcX */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0xdX */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0xeX */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T /* 0xfX */
+};
+
+/* Maximal length of a line we consider "reasonable". */
+#define MAXLINELEN 300
+
+int
+internatmagic(buf, nbytes)
+ unsigned char *buf;
+ int nbytes;
+{
+ int i;
+ unsigned char *cp;
+
+ nbytes--;
+
+ /* First, look whether there are "unreasonable" characters. */
+ for (i = 0, cp = buf; i < nbytes; i++, cp++)
+ if (!maybe_internat[*cp])
+ return 0;
+
+ /*
+ * Now, look whether the file consists of lines of
+ * "reasonable" length.
+ */
+
+ for (i = 0; i < nbytes;) {
+ cp = memchr(buf, '\n', nbytes - i);
+ if (cp == NULL) {
+ /* Don't fail if we hit the end of buffer. */
+ if (i + MAXLINELEN >= nbytes)
+ break;
+ else
+ return 0;
+ }
+ if (cp - buf > MAXLINELEN)
+ return 0;
+ i += (cp - buf + 1);
+ buf = cp + 1;
+ }
+ ckfputs("International language text", stdout);
+ return 1;
+}
diff --git a/usr.bin/file/is_tar.c b/usr.bin/file/is_tar.c
new file mode 100644
index 0000000..7008a40
--- /dev/null
+++ b/usr.bin/file/is_tar.c
@@ -0,0 +1,100 @@
+/*
+ * is_tar() -- figure out whether file is a tar archive.
+ *
+ * Stolen (by the author!) from the public domain tar program:
+ * Pubic Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
+ *
+ * @(#)list.c 1.18 9/23/86 Public Domain - gnu
+ * $Id: is_tar.c,v 1.1.1.2 1997/03/18 17:58:48 mpp Exp $
+ *
+ * Comments changed and some code/comments reformatted
+ * for file command by Ian Darwin.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "tar.h"
+
+#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
+
+#if defined(__STDC__) || defined(__cplusplus)
+static int from_oct(int, char*); /* Decode octal number */
+#else
+static int from_oct();
+#endif
+
+/*
+ * Return
+ * 0 if the checksum is bad (i.e., probably not a tar archive),
+ * 1 for old UNIX tar file,
+ * 2 for Unix Std (POSIX) tar file.
+ */
+int
+is_tar(buf, nbytes)
+unsigned char *buf;
+int nbytes;
+{
+ register union record *header = (union record *)buf;
+ register int i;
+ register int sum, recsum;
+ register char *p;
+
+ if (nbytes < sizeof(union record))
+ return 0;
+
+ recsum = from_oct(8, header->header.chksum);
+
+ sum = 0;
+ p = header->charptr;
+ for (i = sizeof(union record); --i >= 0;) {
+ /*
+ * We can't use unsigned char here because of old compilers,
+ * e.g. V7.
+ */
+ sum += 0xFF & *p++;
+ }
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+ for (i = sizeof(header->header.chksum); --i >= 0;)
+ sum -= 0xFF & header->header.chksum[i];
+ sum += ' '* sizeof header->header.chksum;
+
+ if (sum != recsum)
+ return 0; /* Not a tar archive */
+
+ if (0==strcmp(header->header.magic, TMAGIC))
+ return 2; /* Unix Standard tar archive */
+
+ return 1; /* Old fashioned tar archive */
+}
+
+
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or nonoctal).
+ */
+static int
+from_oct(digs, where)
+ register int digs;
+ register char *where;
+{
+ register int value;
+
+ while (isspace(*where)) { /* Skip spaces */
+ where++;
+ if (--digs <= 0)
+ return -1; /* All blank field */
+ }
+ value = 0;
+ while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
+ value = (value << 3) | (*where++ - '0');
+ --digs;
+ }
+
+ if (digs > 0 && *where && !isspace(*where))
+ return -1; /* Ended on non-space/nul */
+
+ return value;
+}
diff --git a/usr.bin/file/magic.5 b/usr.bin/file/magic.5
new file mode 100644
index 0000000..bd1a5a5
--- /dev/null
+++ b/usr.bin/file/magic.5
@@ -0,0 +1,206 @@
+.TH MAGIC 5 "Public Domain"
+.\" install as magic.4 on USG, magic.5 on V7 or Berkeley systems.
+.SH NAME
+magic \- file command's magic number file
+.SH DESCRIPTION
+This manual page documents the format of the magic file as
+used by the
+.BR file (1)
+command, version 3.22. The
+.B file
+command identifies the type of a file using,
+among other tests,
+a test for whether the file begins with a certain
+.IR "magic number" .
+The file
+.I /etc/magic
+specifies what magic numbers are to be tested for,
+what message to print if a particular magic number is found,
+and additional information to extract from the file.
+.PP
+Each line of the file specifies a test to be performed.
+A test compares the data starting at a particular offset
+in the file with a 1-byte, 2-byte, or 4-byte numeric value or
+a string. If the test succeeds, a message is printed.
+The line consists of the following fields:
+.IP offset \w'message'u+2n
+A number specifying the offset, in bytes, into the file of the data
+which is to be tested.
+.IP type
+The type of the data to be tested. The possible values are:
+.RS
+.IP byte \w'message'u+2n
+A one-byte value.
+.IP short
+A two-byte value (on most systems) in this machine's native byte order.
+.IP long
+A four-byte value (on most systems) in this machine's native byte order.
+.IP string
+A string of bytes.
+.IP date
+A four-byte value interpreted as a unix date.
+.IP beshort
+A two-byte value (on most systems) in big-endian byte order.
+.IP belong
+A four-byte value (on most systems) in big-endian byte order.
+.IP bedate
+A four-byte value (on most systems) in big-endian byte order,
+interpreted as a unix date.
+.IP leshort
+A two-byte value (on most systems) in little-endian byte order.
+.IP lelong
+A four-byte value (on most systems) in little-endian byte order.
+.IP ledate
+A four-byte value (on most systems) in little-endian byte order,
+interpreted as a unix date.
+.RE
+.PP
+The numeric types may optionally be followed by
+.B &
+and a numeric value,
+to specify that the value is to be AND'ed with the
+numeric value before any comparisons are done. Prepending a
+.B u
+to the type indicates that ordered comparisons should be unsigned.
+.IP test
+The value to be compared with the value from the file. If the type is
+numeric, this value
+is specified in C form; if it is a string, it is specified as a C string
+with the usual escapes permitted (e.g. \en for new-line).
+.IP
+Numeric values
+may be preceded by a character indicating the operation to be performed.
+It may be
+.BR = ,
+to specify that the value from the file must equal the specified value,
+.BR < ,
+to specify that the value from the file must be less than the specified
+value,
+.BR > ,
+to specify that the value from the file must be greater than the specified
+value,
+.BR & ,
+to specify that the value from the file must have set all of the bits
+that are set in the specified value,
+.BR ^ ,
+to specify that the value from the file must have clear any of the bits
+that are set in the specified value, or
+.BR x ,
+to specify that any value will match. If the character is omitted,
+it is assumed to be
+.BR = .
+.IP
+Numeric values are specified in C form; e.g.
+.B 13
+is decimal,
+.B 013
+is octal, and
+.B 0x13
+is hexadecimal.
+.IP
+For string values, the byte string from the
+file must match the specified byte string.
+The operators
+.BR = ,
+.B <
+and
+.B >
+(but not
+.BR & )
+can be applied to strings.
+The length used for matching is that of the string argument
+in the magic file. This means that a line can match any string, and
+then presumably print that string, by doing
+.B >\e0
+(because all strings are greater than the null string).
+.IP message
+The message to be printed if the comparison succeeds. If the string
+contains a
+.BR printf (3S)
+format specification, the value from the file (with any specified masking
+performed) is printed using the message as the format string.
+.PP
+Some file formats contain additional information which is to be printed
+along with the file type. A line which begins with the character
+.B >
+indicates additional tests and messages to be printed. The number of
+.B >
+on the line indicates the level of the test; a line with no
+.B >
+at the beginning is considered to be at level 0.
+Each line at level
+.IB n \(pl1
+is under the control of the line at level
+.IB n
+most closely preceding it in the magic file.
+If the test on a line at level
+.I n
+succeeds, the tests specified in all the subsequent lines at level
+.IB n \(pl1
+are performed, and the messages printed if the tests succeed. The next
+line at level
+.I n
+terminates this.
+If the first character following the last
+.B >
+is a
+.B (
+then the string after the parenthesis is interpreted as an indirect offset.
+That means that the number after the parenthesis is used as an offset in
+the file. The value at that offset is read, and is used again as an offset
+in the file. Indirect offsets are of the form:
+.BI ( x [.[bsl]][+-][ y ]).
+The value of
+.I x
+is used as an offset in the file. A byte, short or long is read at that offset
+depending on the
+.B [bsl]
+type specifier. To that number the value of
+.I y
+is added and the result is used as an offset in the file. The default type
+if one is not specified is long.
+.PP
+Sometimes you do not know the exact offset as this depends on the length of
+preceding fields. You can specify an offset relative to the end of the
+last uplevel field (of course this may only be done for sublevel tests, i.e.
+test beginning with
+.B >
+). Such a relative offset is specified using
+.B &
+as a prefix to the offset.
+.SH BUGS
+The formats
+.IR long ,
+.IR belong ,
+.IR lelong ,
+.IR short ,
+.IR beshort ,
+.IR leshort ,
+.IR date ,
+.IR bedate ,
+and
+.I ledate
+are system-dependent; perhaps they should be specified as a number
+of bytes (2B, 4B, etc),
+since the files being recognized typically come from
+a system on which the lengths are invariant.
+.PP
+There is (currently) no support for specified-endian data to be used in
+indirect offsets.
+.SH SEE ALSO
+.BR file (1)
+\- the command that reads this file.
+.\"
+.\" From: guy@sun.uucp (Guy Harris)
+.\" Newsgroups: net.bugs.usg
+.\" Subject: /etc/magic's format isn't well documented
+.\" Message-ID: <2752@sun.uucp>
+.\" Date: 3 Sep 85 08:19:07 GMT
+.\" Organization: Sun Microsystems, Inc.
+.\" Lines: 136
+.\"
+.\" Here's a manual page for the format accepted by the "file" made by adding
+.\" the changes I posted to the S5R2 version.
+.\"
+.\" Modified for Ian Darwin's version of the file command.
+.\" @(#)$Id: magic.5,v 1.1.1.3 1997/03/18 17:58:57 mpp Exp $
diff --git a/usr.bin/file/names.h b/usr.bin/file/names.h
new file mode 100644
index 0000000..1fed1bf
--- /dev/null
+++ b/usr.bin/file/names.h
@@ -0,0 +1,99 @@
+/*
+ * Names.h - names and types used by ascmagic in file(1).
+ * These tokens are here because they can appear anywhere in
+ * the first HOWMANY bytes, while tokens in /etc/magic must
+ * appear at fixed offsets into the file. Don't make HOWMANY
+ * too high unless you have a very fast CPU.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * See LEGAL.NOTICE
+ *
+ * $Id: names.h,v 1.1.1.3 1997/03/18 17:58:52 mpp Exp $
+ */
+
+/* these types are used to index the table 'types': keep em in sync! */
+#define L_C 0 /* first and foremost on UNIX */
+#define L_CC 1 /* Bjarne's postincrement */
+#define L_FORT 2 /* the oldest one */
+#define L_MAKE 3 /* Makefiles */
+#define L_PLI 4 /* PL/1 */
+#define L_MACH 5 /* some kinda assembler */
+#define L_ENG 6 /* English */
+#define L_PAS 7 /* Pascal */
+#define L_MAIL 8 /* Electronic mail */
+#define L_NEWS 9 /* Usenet Netnews */
+
+static char *types[] = {
+ "C program text",
+ "C++ program text",
+ "FORTRAN program text",
+ "make commands text" ,
+ "PL/1 program text",
+ "assembler program text",
+ "English text",
+ "Pascal program text",
+ "mail text",
+ "news text",
+ "can't happen error on names.h/types",
+ 0};
+
+static struct names {
+ char *name;
+ short type;
+} names[] = {
+ /* These must be sorted by eye for optimal hit rate */
+ /* Add to this list only after substantial meditation */
+ {"//", L_CC},
+ {"template", L_CC},
+ {"virtual", L_CC},
+ {"class", L_CC},
+ {"public:", L_CC},
+ {"private:", L_CC},
+ {"/*", L_C}, /* must precede "The", "the", etc. */
+ {"#include", L_C},
+ {"char", L_C},
+ {"The", L_ENG},
+ {"the", L_ENG},
+ {"double", L_C},
+ {"extern", L_C},
+ {"float", L_C},
+ {"real", L_C},
+ {"struct", L_C},
+ {"union", L_C},
+ {"CFLAGS", L_MAKE},
+ {"LDFLAGS", L_MAKE},
+ {"all:", L_MAKE},
+ {".PRECIOUS", L_MAKE},
+/* Too many files of text have these words in them. Find another way
+ * to recognize Fortrash.
+ */
+#ifdef NOTDEF
+ {"subroutine", L_FORT},
+ {"function", L_FORT},
+ {"block", L_FORT},
+ {"common", L_FORT},
+ {"dimension", L_FORT},
+ {"integer", L_FORT},
+ {"data", L_FORT},
+#endif /*NOTDEF*/
+ {".ascii", L_MACH},
+ {".asciiz", L_MACH},
+ {".byte", L_MACH},
+ {".even", L_MACH},
+ {".globl", L_MACH},
+ {".text", L_MACH},
+ {"clr", L_MACH},
+ {"(input,", L_PAS},
+ {"dcl", L_PLI},
+ {"Received:", L_MAIL},
+ {">From", L_MAIL},
+ {"Return-Path:",L_MAIL},
+ {"Cc:", L_MAIL},
+ {"Newsgroups:", L_NEWS},
+ {"Path:", L_NEWS},
+ {"Organization:",L_NEWS},
+ {NULL, 0}
+};
+#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1)
diff --git a/usr.bin/file/patchlevel.h b/usr.bin/file/patchlevel.h
new file mode 100644
index 0000000..620a57f
--- /dev/null
+++ b/usr.bin/file/patchlevel.h
@@ -0,0 +1,146 @@
+#define FILE_VERSION_MAJOR 3
+#define patchlevel 22
+
+/*
+ * Patchlevel file for Ian Darwin's MAGIC command.
+ * $Id: patchlevel.h,v 1.1.1.3 1997/03/18 17:58:54 mpp Exp $
+ *
+ * $Log: patchlevel.h,v $
+ * Revision 1.6 1997/02/22 19:54:59 peter
+ * Revert $FreeBSD$ to $Id$
+ *
+ * Revision 1.5 1997/02/22 19:29:15 peter
+ * Revert $Id: patchlevel.h,v 1.6 1997/02/22 19:54:59 peter Exp $ to $Id: patchlevel.h,v 1.6 1997/02/22 19:54:59 peter Exp $
+ *
+ * Revision 1.4 1997/01/14 06:59:48 jkh
+ * Make the long-awaited change from $Id: patchlevel.h,v 1.6 1997/02/22 19:54:59 peter Exp $ to $Id: patchlevel.h,v 1.6 1997/02/22 19:54:59 peter Exp $
+ *
+ * This will make a number of things easier in the future, as well as (finally!)
+ * avoiding the Id-smashing problem which has plagued developers for so long.
+ *
+ * Boy, I'm glad we're not using sup anymore. This update would have been
+ * insane otherwise.
+ *
+ * Revision 1.3 1996/01/23 12:40:20 mpp
+ * Merged changes to resolve conflicts with file 3.19 import.
+ *
+ * Revision 1.2 1995/05/30 06:30:06 rgrimes
+ * Remove trailing whitespace.
+ *
+ * Revision 1.1.1.2 1996/01/22 22:31:44 mpp
+ * Upgrade to file version 3.19.
+ *
+ * Revision 1.1.1.1 1994/09/03 19:16:23 csgr
+ * Bring in file 3.14 by Ian Darwin (and Christos Zoulas)
+ *
+ * The following files were moved to different names:
+ * - file.man -> file.1
+ * - magic.man -> magic.5
+ *
+ * The following file was removed:
+ * - Magdir/Makefile
+ *
+ * Revision 1.1.1.3 1997/03/18 17:58:54 mpp
+ * Upgrade to file version 3.22.
+ *
+ * Obtained from: ftp://ftp.deshaw.com/pub/file/file-3.22.tar.gz
+ *
+ * Revision 1.22 1997/01/15 17:23:24 christos
+ * - add support for elf core files: find the program name under SVR4 [Ken Pizzini]
+ * - print strings only up to the first carriage return [various]
+ * - freebsd international ascii support [J Wunsch]
+ * - magic fixes and additions [Guy Harris]
+ * - 64 bit fixes [Larry Schwimmer]
+ * - support for both utime and utimes, but don't restore file access times
+ * by default [various]
+ * - \xXX only takes 2 hex digits, not 3.
+ * - re-implement support for core files [Guy Harris]
+ *
+ * Revision 1.21 1996/10/05 18:15:29 christos
+ * Segregate elf stuff and conditionally enable it with -DBUILTIN_ELF
+ * More magic fixes
+ *
+ * Revision 1.20 1996/06/22 22:15:52 christos
+ * - support relative offsets of the form >&
+ * - fix bug with truncating magic strings that contain \n
+ * - file -f - did not read from stdin as documented
+ * - support elf file parsing using our own elf support.
+ * - as always magdir fixes and additions.
+ *
+ * Revision 1.19 1995/10/27 23:14:46 christos
+ * Ability to parse colon separated list of magic files
+ * New LEGAL.NOTICE
+ * Various magic file changes
+ *
+ * Revision 1.18 1995/05/20 22:09:21 christos
+ * Passed incorrect argument to eatsize().
+ * Use %ld and %lx where appropriate.
+ * Remove unused variables
+ * ELF support for both big and little endian
+ * Fixes for small files again.
+ *
+ * Revision 1.17 1995/04/28 17:29:13 christos
+ * - Incorrect nroff detection fix from der Mouse
+ * - Lost and incorrect magic entries.
+ * - Added ELF stripped binary detection [in C; ugh]
+ * - Look for $MAGIC to find the magic file.
+ * - Eat trailing size specifications from numbers i.e. ignore 10L
+ * - More fixes for very short files
+ *
+ * Revision 1.16 1995/03/25 22:06:45 christos
+ * - use strtoul() where it exists.
+ * - fix sign-extend bug
+ * - try to detect tar archives before nroff files, otherwise
+ * tar files where the first file starts with a . will not work
+ *
+ * Revision 1.15 1995/01/21 21:03:35 christos
+ * Added CSECTION for the file man page
+ * Added version flag -v
+ * Fixed bug with -f input flag (from iorio@violet.berkeley.edu)
+ * Lots of magic fixes and reorganization...
+ *
+ * Revision 1.14 1994/05/03 17:58:23 christos
+ * changes from mycroft@gnu.ai.mit.edu (Charles Hannum) for unsigned
+ *
+ * Revision 1.13 1994/01/21 01:27:01 christos
+ * Fixed null termination bug from Don Seeley at BSDI in ascmagic.c
+ *
+ * Revision 1.12 1993/10/27 20:59:05 christos
+ * Changed -z flag to understand gzip format too.
+ * Moved builtin compression detection to a table, and move
+ * the compress magic entry out of the source.
+ * Made printing of numbers unsigned, and added the mask to it.
+ * Changed the buffer size to 8k, because gzip will refuse to
+ * unzip just a few bytes.
+ *
+ * Revision 1.11 1993/09/24 18:49:06 christos
+ * Fixed small bug in softmagic.c introduced by
+ * copying the data to be examined out of the input
+ * buffer. Changed the Makefile to use sed to create
+ * the correct man pages.
+ *
+ * Revision 1.10 1993/09/23 21:56:23 christos
+ * Passed purify. Fixed indirections. Fixed byte order printing.
+ * Fixed segmentation faults caused by referencing past the end
+ * of the magic buffer. Fixed bus errors caused by referencing
+ * unaligned shorts or longs.
+ *
+ * Revision 1.9 1993/03/24 14:23:40 ian
+ * Batch of minor changes from several contributors.
+ *
+ * Revision 1.8 93/02/19 15:01:26 ian
+ * Numerous changes from Guy Harris too numerous to mention but including
+ * byte-order independance, fixing "old-style masking", etc. etc. A bugfix
+ * for broken symlinks from martin@@d255s004.zfe.siemens.de.
+ *
+ * Revision 1.7 93/01/05 14:57:27 ian
+ * Couple of nits picked by Christos (again, thanks).
+ *
+ * Revision 1.6 93/01/05 13:51:09 ian
+ * Lotsa work on the Magic directory.
+ *
+ * Revision 1.5 92/09/14 14:54:51 ian
+ * Fix a tiny null-pointer bug in previous fix for tar archive + uncompress.
+ *
+ */
+
diff --git a/usr.bin/file/print.c b/usr.bin/file/print.c
new file mode 100644
index 0000000..09c3fc8
--- /dev/null
+++ b/usr.bin/file/print.c
@@ -0,0 +1,204 @@
+/*
+ * print.c - debugging printout routines
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#if __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include "file.h"
+
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: print.c,v 1.1.1.3 1997/03/18 17:58:49 mpp Exp $";
+#endif /* lint */
+
+#define SZOF(a) (sizeof(a) / sizeof(a[0]))
+
+void
+mdump(m)
+struct magic *m;
+{
+ static char *typ[] = { "invalid", "byte", "short", "invalid",
+ "long", "string", "date", "beshort",
+ "belong", "bedate", "leshort", "lelong",
+ "ledate" };
+ (void) fputc('[', stderr);
+ (void) fprintf(stderr, ">>>>>>>> %d" + 8 - (m->cont_level & 7),
+ m->offset);
+
+ if (m->flag & INDIR)
+ (void) fprintf(stderr, "(%s,%d),",
+ (m->in.type >= 0 && m->in.type < SZOF(typ)) ?
+ typ[(unsigned char) m->in.type] :
+ "*bad*",
+ m->in.offset);
+
+ (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "",
+ (m->type >= 0 && m->type < SZOF(typ)) ?
+ typ[(unsigned char) m->type] :
+ "*bad*");
+ if (m->mask != ~0L)
+ (void) fprintf(stderr, " & %.8x", m->mask);
+
+ (void) fprintf(stderr, ",%c", m->reln);
+
+ if (m->reln != 'x') {
+ switch (m->type) {
+ case BYTE:
+ case SHORT:
+ case LONG:
+ case LESHORT:
+ case LELONG:
+ case BESHORT:
+ case BELONG:
+ (void) fprintf(stderr, "%d", m->value.l);
+ break;
+ case STRING:
+ showstr(stderr, m->value.s, -1);
+ break;
+ case DATE:
+ case LEDATE:
+ case BEDATE:
+ {
+ char *rt, *pp = ctime((time_t*) &m->value.l);
+ if ((rt = strchr(pp, '\n')) != NULL)
+ *rt = '\0';
+ (void) fprintf(stderr, "%s,", pp);
+ if (rt)
+ *rt = '\n';
+ }
+ break;
+ default:
+ (void) fputs("*bad*", stderr);
+ break;
+ }
+ }
+ (void) fprintf(stderr, ",\"%s\"]\n", m->desc);
+}
+
+/*
+ * ckfputs - futs, but with error checking
+ * ckfprintf - fprintf, but with error checking
+ */
+void
+ckfputs(str, fil)
+ const char *str;
+ FILE *fil;
+{
+ if (fputs(str,fil) == EOF)
+ error("write failed.\n");
+}
+
+/*VARARGS*/
+void
+#if __STDC__
+ckfprintf(FILE *f, const char *fmt, ...)
+#else
+ckfprintf(va_alist)
+ va_dcl
+#endif
+{
+ va_list va;
+#if __STDC__
+ va_start(va, fmt);
+#else
+ FILE *f;
+ const char *fmt;
+ va_start(va);
+ f = va_arg(va, FILE *);
+ fmt = va_arg(va, const char *);
+#endif
+ (void) vfprintf(f, fmt, va);
+ if (ferror(f))
+ error("write failed.\n");
+ va_end(va);
+}
+
+/*
+ * error - print best error message possible and exit
+ */
+/*VARARGS*/
+void
+#if __STDC__
+error(const char *f, ...)
+#else
+error(va_alist)
+ va_dcl
+#endif
+{
+ va_list va;
+#if __STDC__
+ va_start(va, f);
+#else
+ const char *f;
+ va_start(va);
+ f = va_arg(va, const char *);
+#endif
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
+
+ if (progname != NULL)
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ exit(1);
+}
+
+/*VARARGS*/
+void
+#if __STDC__
+magwarn(const char *f, ...)
+#else
+magwarn(va_alist)
+ va_dcl
+#endif
+{
+ va_list va;
+#if __STDC__
+ va_start(va, f);
+#else
+ const char *f;
+ va_start(va);
+ f = va_arg(va, const char *);
+#endif
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
+
+ if (progname != NULL)
+ (void) fprintf(stderr, "%s: %s, %d: ",
+ progname, magicfile, lineno);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ fputc('\n', stderr);
+}
diff --git a/usr.bin/file/readelf.c b/usr.bin/file/readelf.c
new file mode 100644
index 0000000..2ae533b
--- /dev/null
+++ b/usr.bin/file/readelf.c
@@ -0,0 +1,318 @@
+
+#ifdef BUILTIN_ELF
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "readelf.h"
+#include "file.h"
+
+static void doshn __P((int, off_t, int, size_t, char *));
+static void dophn_exec __P((int, off_t, int, size_t, char *));
+static void dophn_core __P((int, off_t, int, size_t, char *));
+
+static void
+doshn(fd, off, num, size, buf)
+ int fd;
+ off_t off;
+ int num;
+ size_t size;
+ char *buf;
+{
+ /*
+ * This works for both 32-bit and 64-bit ELF formats,
+ * because it looks only at the "sh_type" field, which is
+ * always 32 bits, and is preceded only by the "sh_name"
+ * field which is also always 32 bits, and because it uses
+ * the shdr size from the ELF header rather than using
+ * the size of an "Elf32_Shdr".
+ */
+ Elf32_Shdr *sh = (Elf32_Shdr *) buf;
+
+ if (lseek(fd, off, SEEK_SET) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
+
+ for ( ; num; num--) {
+ if (read(fd, buf, size) == -1)
+ error("read failed (%s).\n", strerror(errno));
+ if (sh->sh_type == SHT_SYMTAB) {
+ (void) printf (", not stripped");
+ return;
+ }
+ }
+ (void) printf (", stripped");
+}
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_INTERP section; if one is found, it's dynamically linked,
+ * otherwise it's statically linked.
+ */
+static void
+dophn_exec(fd, off, num, size, buf)
+ int fd;
+ off_t off;
+ int num;
+ size_t size;
+ char *buf;
+{
+ /* I am not sure if this works for 64 bit elf formats */
+ Elf32_Phdr *ph = (Elf32_Phdr *) buf;
+
+ if (lseek(fd, off, SEEK_SET) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
+
+ for ( ; num; num--) {
+ if (read(fd, buf, size) == -1)
+ error("read failed (%s).\n", strerror(errno));
+ if (ph->p_type == PT_INTERP) {
+ /*
+ * Has an interpreter - must be a dynamically-linked
+ * executable.
+ */
+ printf(", dynamically linked");
+ return;
+ }
+ }
+ printf(", statically linked");
+}
+
+size_t prpsoffsets[] = {
+ 100, /* SunOS 5.x */
+ 32, /* Linux */
+};
+
+#define NOFFSETS (sizeof prpsoffsets / sizeof prpsoffsets[0])
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one
+ * is found, try looking in various places in its contents for a 16-character
+ * string containing only printable characters - if found, that string
+ * should be the name of the program that dropped core.
+ * Note: right after that 16-character string is, at least in SunOS 5.x
+ * (and possibly other SVR4-flavored systems) and Linux, a longer string
+ * (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux)
+ * containing the start of the command line for that program.
+ */
+static void
+dophn_core(fd, off, num, size, buf)
+ int fd;
+ off_t off;
+ int num;
+ size_t size;
+ char *buf;
+{
+ /*
+ * This doesn't work for 64-bit ELF, as the "p_offset" field is
+ * 64 bits in 64-bit ELF.
+ */
+ /*
+ * This doesn't work for 64-bit ELF, as the "p_offset" field is
+ * 64 bits in 64-bit ELF.
+ */
+ Elf32_Phdr *ph = (Elf32_Phdr *) buf;
+ Elf32_Nhdr *nh;
+ size_t offset, noffset, reloffset;
+ unsigned char c;
+ int i, j;
+ char nbuf[BUFSIZ];
+ int bufsize;
+
+ for ( ; num; num--) {
+ if (lseek(fd, off, SEEK_SET) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
+ if (read(fd, buf, size) == -1)
+ error("read failed (%s).\n", strerror(errno));
+ off += size;
+ if (ph->p_type != PT_NOTE)
+ continue;
+ if (lseek(fd, ph->p_offset, SEEK_SET) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
+ bufsize = read(fd, nbuf, BUFSIZ);
+ if (bufsize == -1)
+ error("read failed (%s).\n", strerror(errno));
+ offset = 0;
+ for (;;) {
+ if (offset >= bufsize)
+ break;
+ nh = (Elf32_Nhdr *)&nbuf[offset];
+ offset += sizeof *nh;
+
+ /*
+ * If this note isn't an NT_PRPSINFO note, it's
+ * not what we're looking for.
+ */
+ if (nh->n_type != NT_PRPSINFO) {
+ offset += nh->n_namesz;
+ offset = ((offset + 3)/4)*4;
+ offset += nh->n_descsz;
+ offset = ((offset + 3)/4)*4;
+ continue;
+ }
+
+ /*
+ * Make sure this note has the name "CORE".
+ */
+ if (offset + nh->n_namesz >= bufsize) {
+ /*
+ * We're past the end of the buffer.
+ */
+ break;
+ }
+ if (nh->n_namesz != 5
+ || strcmp(&nbuf[offset], "CORE") != 0)
+ continue;
+ offset += nh->n_namesz;
+ offset = ((offset + 3)/4)*4;
+
+ /*
+ * Extract the program name. We assume it to be
+ * 16 characters (that's what it is in SunOS 5.x
+ * and Linux).
+ *
+ * Unfortunately, it's at a different offset in
+ * SunOS 5.x and Linux, so try multiple offsets.
+ * If the characters aren't all printable, reject
+ * it.
+ */
+ for (i = 0; i < NOFFSETS; i++) {
+ reloffset = prpsoffsets[i];
+ noffset = offset + reloffset;
+ for (j = 0; j < 16;
+ j++, noffset++, reloffset++) {
+ /*
+ * Make sure we're not past the end
+ * of the buffer; if we are, just
+ * give up.
+ */
+ if (noffset >= bufsize)
+ return;
+
+ /*
+ * Make sure we're not past the
+ * end of the contents; if we
+ * are, this obviously isn't
+ * the right offset.
+ */
+ if (reloffset >= nh->n_descsz)
+ goto tryanother;
+
+ c = nbuf[noffset];
+ if (c != '\0' && !isprint(c))
+ goto tryanother;
+ }
+
+ /*
+ * Well, that worked.
+ */
+ printf(", from '%.16s'",
+ &nbuf[offset + prpsoffsets[i]]);
+ return;
+
+ tryanother:
+ ;
+ }
+ offset += nh->n_descsz;
+ offset = ((offset + 3)/4)*4;
+ }
+ }
+}
+
+void
+tryelf(fd, buf, nbytes)
+ int fd;
+ char *buf;
+ int nbytes;
+{
+ union {
+ int32 l;
+ char c[sizeof (int32)];
+ } u;
+
+ /*
+ * ELF executables have multiple section headers in arbitrary
+ * file locations and thus file(1) cannot determine it from easily.
+ * Instead we traverse thru all section headers until a symbol table
+ * one is found or else the binary is stripped.
+ */
+ if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1
+ || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
+ return;
+
+
+ if (buf[4] == ELFCLASS32) {
+ Elf32_Ehdr elfhdr;
+ if (nbytes <= sizeof (Elf32_Ehdr))
+ return;
+
+
+ u.l = 1;
+ (void) memcpy(&elfhdr, buf, sizeof elfhdr);
+ /*
+ * If the system byteorder does not equal the
+ * object byteorder then don't test.
+ * XXX - we could conceivably fix up the "dophn_XXX()" and
+ * "doshn()" routines to extract stuff in the right
+ * byte order....
+ */
+ if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
+ if (elfhdr.e_type == ET_CORE)
+ dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum,
+ elfhdr.e_phentsize, buf);
+ else {
+ if (elfhdr.e_type == ET_EXEC) {
+ dophn_exec(fd, elfhdr.e_phoff,
+ elfhdr.e_phnum,
+ elfhdr.e_phentsize, buf);
+ }
+ doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum,
+ elfhdr.e_shentsize, buf);
+ }
+ }
+ return;
+ }
+
+ if (buf[4] == ELFCLASS64) {
+ Elf64_Ehdr elfhdr;
+ if (nbytes <= sizeof (Elf64_Ehdr))
+ return;
+
+
+ u.l = 1;
+ (void) memcpy(&elfhdr, buf, sizeof elfhdr);
+
+ /*
+ * If the system byteorder does not equal the
+ * object byteorder then don't test.
+ * XXX - we could conceivably fix up the "dophn_XXX()" and
+ * "doshn()" routines to extract stuff in the right
+ * byte order....
+ */
+ if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
+#ifdef notyet
+ if (elfhdr.e_type == ET_CORE)
+ dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum,
+ elfhdr.e_phentsize, buf);
+ else
+#endif
+ {
+#ifdef notyet
+ if (elfhdr.e_type == ET_EXEC) {
+ dophn_exec(fd, elfhdr.e_phoff,
+ elfhdr.e_phnum,
+ elfhdr.e_phentsize, buf);
+ }
+#endif
+ doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum,
+ elfhdr.e_shentsize, buf);
+ }
+ }
+ return;
+ }
+}
+#endif
diff --git a/usr.bin/file/readelf.h b/usr.bin/file/readelf.h
new file mode 100644
index 0000000..853eed6
--- /dev/null
+++ b/usr.bin/file/readelf.h
@@ -0,0 +1,167 @@
+/*
+ * readelf.h
+ * @(#)$Id: readelf.h,v 1.1.1.1 1997/03/18 17:58:55 mpp Exp $
+ *
+ * Provide elf data structures for non-elf machines, allowing file
+ * non-elf hosts to determine if an elf binary is stripped.
+ * Note: cobbled from the linux header file, with modifications
+ */
+#ifndef __fake_elf_h__
+#define __fake_elf_h__
+
+typedef unsigned int Elf32_Addr;
+typedef unsigned short Elf32_Half;
+typedef unsigned int Elf32_Off;
+typedef unsigned int Elf32_Word;
+typedef unsigned char Elf32_Char;
+
+/* XXX: We need 64 bit numbers here */
+typedef u_quad_t Elf64_Addr;
+typedef unsigned short Elf64_Half;
+typedef u_quad_t Elf64_Off;
+typedef unsigned int Elf64_Word;
+typedef unsigned char Elf64_Char;
+
+#define EI_NIDENT 16
+
+typedef struct {
+ Elf32_Char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ Elf64_Char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry; /* Entry point */
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* e_type */
+#define ET_EXEC 2
+#define ET_CORE 4
+
+/* sh_type */
+#define SHT_SYMTAB 2
+#define SHT_NOTE 7
+
+/* elf type */
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+/* elf class */
+#define ELFCLASSNONE 0
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+/* magic number */
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_PAD 7
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+#define PT_NULL 0 /* p_type */
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_NUM 7
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Off sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Off sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Off sh_addralign;
+ Elf64_Off sh_entsize;
+} Elf64_Shdr;
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_TASKSTRUCT 4
+
+/* Note header in a PT_NOTE section */
+typedef struct elf_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+typedef struct {
+ Elf64_Word n_namesz;
+ Elf64_Word n_descsz;
+ Elf64_Word n_type;
+} Elf64_Nhdr;
+
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_PRXREG 4
+#define NT_PLATFORM 5
+#define NT_AUXV 6
+
+#endif
diff --git a/usr.bin/file/softmagic.c b/usr.bin/file/softmagic.c
new file mode 100644
index 0000000..5383eb8
--- /dev/null
+++ b/usr.bin/file/softmagic.c
@@ -0,0 +1,513 @@
+/*
+ * softmagic - interpret variable magic from /etc/magic
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include "file.h"
+
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: softmagic.c,v 1.1.1.3 1997/03/18 17:58:45 mpp Exp $";
+#endif /* lint */
+
+static int match __P((unsigned char *, int));
+static int mget __P((union VALUETYPE *,
+ unsigned char *, struct magic *, int));
+static int mcheck __P((union VALUETYPE *, struct magic *));
+static int32 mprint __P((union VALUETYPE *, struct magic *));
+static void mdebug __P((int32, char *, int));
+static int mconvert __P((union VALUETYPE *, struct magic *));
+
+/*
+ * softmagic - lookup one file in database
+ * (already read from /etc/magic by apprentice.c).
+ * Passed the name and FILE * of one file to be typed.
+ */
+/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
+int
+softmagic(buf, nbytes)
+unsigned char *buf;
+int nbytes;
+{
+ if (match(buf, nbytes))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Go through the whole list, stopping if you find a match. Process all
+ * the continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ * At any time when processing a successful top-level match, there is a
+ * current continuation level; it represents the level of the last
+ * successfully matched continuation.
+ *
+ * Continuations above that level are skipped as, if we see one, it
+ * means that the continuation that controls them - i.e, the
+ * lower-level continuation preceding them - failed to match.
+ *
+ * Continuations below that level are processed as, if we see one,
+ * it means we've finished processing or skipping higher-level
+ * continuations under the control of a successful or unsuccessful
+ * lower-level continuation, and are now seeing the next lower-level
+ * continuation and should process it. The current continuation
+ * level reverts to the level of the one we're seeing.
+ *
+ * Continuations at the current level are processed as, if we see
+ * one, there's no lower-level continuation that may have failed.
+ *
+ * If a continuation matches, we bump the current continuation level
+ * so that higher-level continuations are processed.
+ */
+static int
+match(s, nbytes)
+unsigned char *s;
+int nbytes;
+{
+ int magindex = 0;
+ int cont_level = 0;
+ int need_separator = 0;
+ union VALUETYPE p;
+ static int32 *tmpoff = NULL;
+ static size_t tmplen = 0;
+ int32 oldoff = 0;
+
+ if (tmpoff == NULL)
+ if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
+ error("out of memory\n");
+
+ for (magindex = 0; magindex < nmagic; magindex++) {
+ /* if main entry matches, print it... */
+ if (!mget(&p, s, &magic[magindex], nbytes) ||
+ !mcheck(&p, &magic[magindex])) {
+ /*
+ * main entry didn't match,
+ * flush its continuations
+ */
+ while (magindex < nmagic &&
+ magic[magindex + 1].cont_level != 0)
+ magindex++;
+ continue;
+ }
+
+ tmpoff[cont_level] = mprint(&p, &magic[magindex]);
+ /*
+ * If we printed something, we'll need to print
+ * a blank before we print something else.
+ */
+ if (magic[magindex].desc[0])
+ need_separator = 1;
+ /* and any continuations that match */
+ if (++cont_level >= tmplen)
+ if ((tmpoff = (int32 *) realloc(tmpoff,
+ tmplen += 20)) == NULL)
+ error("out of memory\n");
+ while (magic[magindex+1].cont_level != 0 &&
+ ++magindex < nmagic) {
+ if (cont_level >= magic[magindex].cont_level) {
+ if (cont_level > magic[magindex].cont_level) {
+ /*
+ * We're at the end of the level
+ * "cont_level" continuations.
+ */
+ cont_level = magic[magindex].cont_level;
+ }
+ if (magic[magindex].flag & ADD) {
+ oldoff=magic[magindex].offset;
+ magic[magindex].offset += tmpoff[cont_level-1];
+ }
+ if (mget(&p, s, &magic[magindex], nbytes) &&
+ mcheck(&p, &magic[magindex])) {
+ /*
+ * This continuation matched.
+ * Print its message, with
+ * a blank before it if
+ * the previous item printed
+ * and this item isn't empty.
+ */
+ /* space if previous printed */
+ if (need_separator
+ && (magic[magindex].nospflag == 0)
+ && (magic[magindex].desc[0] != '\0')
+ ) {
+ (void) putchar(' ');
+ need_separator = 0;
+ }
+ tmpoff[cont_level] = mprint(&p, &magic[magindex]);
+ if (magic[magindex].desc[0])
+ need_separator = 1;
+
+ /*
+ * If we see any continuations
+ * at a higher level,
+ * process them.
+ */
+ if (++cont_level >= tmplen)
+ if ((tmpoff =
+ (int32 *) realloc(tmpoff,
+ tmplen += 20)) == NULL)
+ error("out of memory\n");
+ }
+ if (magic[magindex].flag & ADD) {
+ magic[magindex].offset = oldoff;
+ }
+ }
+ }
+ return 1; /* all through */
+ }
+ return 0; /* no match at all */
+}
+
+static int32
+mprint(p, m)
+union VALUETYPE *p;
+struct magic *m;
+{
+ char *pp, *rt;
+ uint32 v;
+ int32 t=0 ;
+
+
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (unsigned char) v);
+ t = m->offset + sizeof(char);
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (unsigned short) v);
+ t = m->offset + sizeof(short);
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ v = p->l;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (uint32) v);
+ t = m->offset + sizeof(int32);
+ break;
+
+ case STRING:
+ if (m->reln == '=') {
+ (void) printf(m->desc, m->value.s);
+ t = m->offset + strlen(m->value.s);
+ }
+ else {
+ if (*m->value.s == '\0') {
+ char *cp = strchr(p->s,'\n');
+ if (cp)
+ *cp = '\0';
+ }
+ (void) printf(m->desc, p->s);
+ t = m->offset + strlen(p->s);
+ }
+ break;
+
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ pp = ctime((time_t*) &p->l);
+ if ((rt = strchr(pp, '\n')) != NULL)
+ *rt = '\0';
+ (void) printf(m->desc, pp);
+ t = m->offset + sizeof(time_t);
+ break;
+
+ default:
+ error("invalid m->type (%d) in mprint().\n", m->type);
+ /*NOTREACHED*/
+ }
+ return(t);
+}
+
+/*
+ * Convert the byte order of the data we are looking at
+ */
+static int
+mconvert(p, m)
+union VALUETYPE *p;
+struct magic *m;
+{
+ switch (m->type) {
+ case BYTE:
+ case SHORT:
+ case LONG:
+ case DATE:
+ return 1;
+ case STRING:
+ {
+ char *ptr;
+
+ /* Null terminate and eat the return */
+ p->s[sizeof(p->s) - 1] = '\0';
+ if ((ptr = strchr(p->s, '\n')) != NULL)
+ *ptr = '\0';
+ return 1;
+ }
+ case BESHORT:
+ p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
+ return 1;
+ case BELONG:
+ case BEDATE:
+ p->l = (int32)
+ ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
+ return 1;
+ case LESHORT:
+ p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
+ return 1;
+ case LELONG:
+ case LEDATE:
+ p->l = (int32)
+ ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
+ return 1;
+ default:
+ error("invalid type %d in mconvert().\n", m->type);
+ return 0;
+ }
+}
+
+
+static void
+mdebug(offset, str, len)
+int32 offset;
+char *str;
+int len;
+{
+ (void) fprintf(stderr, "mget @%d: ", offset);
+ showstr(stderr, (char *) str, len);
+ (void) fputc('\n', stderr);
+ (void) fputc('\n', stderr);
+}
+
+static int
+mget(p, s, m, nbytes)
+union VALUETYPE* p;
+unsigned char *s;
+struct magic *m;
+int nbytes;
+{
+ int32 offset = m->offset;
+
+ if (offset + sizeof(union VALUETYPE) <= nbytes)
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+ else {
+ /*
+ * the usefulness of padding with zeroes eludes me, it
+ * might even cause problems
+ */
+ int32 have = nbytes - offset;
+ memset(p, 0, sizeof(union VALUETYPE));
+ if (have > 0)
+ memcpy(p, s + offset, have);
+ }
+
+
+ if (debug) {
+ mdebug(offset, (char *) p, sizeof(union VALUETYPE));
+ mdump(m);
+ }
+
+ if (!mconvert(p, m))
+ return 0;
+
+ if (m->flag & INDIR) {
+
+ switch (m->in.type) {
+ case BYTE:
+ offset = p->b + m->in.offset;
+ break;
+ case SHORT:
+ offset = p->h + m->in.offset;
+ break;
+ case LONG:
+ offset = p->l + m->in.offset;
+ break;
+ }
+
+ if (offset + sizeof(union VALUETYPE) > nbytes)
+ return 0;
+
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+
+ if (debug) {
+ mdebug(offset, (char *) p, sizeof(union VALUETYPE));
+ mdump(m);
+ }
+
+ if (!mconvert(p, m))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+mcheck(p, m)
+union VALUETYPE* p;
+struct magic *m;
+{
+ register uint32 l = m->value.l;
+ register uint32 v;
+ int matched;
+
+ if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
+ fprintf(stderr, "BOINK");
+ return 1;
+ }
+
+
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ v = p->l;
+ break;
+
+ case STRING:
+ l = 0;
+ /* What we want here is:
+ * v = strncmp(m->value.s, p->s, m->vallen);
+ * but ignoring any nulls. bcmp doesn't give -/+/0
+ * and isn't universally available anyway.
+ */
+ v = 0;
+ {
+ register unsigned char *a = (unsigned char*)m->value.s;
+ register unsigned char *b = (unsigned char*)p->s;
+ register int len = m->vallen;
+
+ while (--len >= 0)
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
+ break;
+ default:
+ error("invalid type %d in mcheck().\n", m->type);
+ return 0;/*NOTREACHED*/
+ }
+
+ v = signextend(m, v) & m->mask;
+
+ switch (m->reln) {
+ case 'x':
+ if (debug)
+ (void) fprintf(stderr, "%u == *any* = 1\n", v);
+ matched = 1;
+ break;
+
+ case '!':
+ matched = v != l;
+ if (debug)
+ (void) fprintf(stderr, "%u != %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '=':
+ matched = v == l;
+ if (debug)
+ (void) fprintf(stderr, "%u == %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '>':
+ if (m->flag & UNSIGNED) {
+ matched = v > l;
+ if (debug)
+ (void) fprintf(stderr, "%u > %u = %d\n",
+ v, l, matched);
+ }
+ else {
+ matched = (int32) v > (int32) l;
+ if (debug)
+ (void) fprintf(stderr, "%d > %d = %d\n",
+ v, l, matched);
+ }
+ break;
+
+ case '<':
+ if (m->flag & UNSIGNED) {
+ matched = v < l;
+ if (debug)
+ (void) fprintf(stderr, "%u < %u = %d\n",
+ v, l, matched);
+ }
+ else {
+ matched = (int32) v < (int32) l;
+ if (debug)
+ (void) fprintf(stderr, "%d < %d = %d\n",
+ v, l, matched);
+ }
+ break;
+
+ case '&':
+ matched = (v & l) == l;
+ if (debug)
+ (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
+ v, l, l, matched);
+ break;
+
+ case '^':
+ matched = (v & l) != l;
+ if (debug)
+ (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
+ v, l, l, matched);
+ break;
+
+ default:
+ matched = 0;
+ error("mcheck: can't happen: invalid relation %d.\n", m->reln);
+ break;/*NOTREACHED*/
+ }
+
+ return matched;
+}
diff --git a/usr.bin/file/tar.h b/usr.bin/file/tar.h
new file mode 100644
index 0000000..6a9e1dd
--- /dev/null
+++ b/usr.bin/file/tar.h
@@ -0,0 +1,179 @@
+/*
+ * Header file for public domain tar (tape archive) program.
+ *
+ * @(#)tar.h 1.20 86/10/29 Public Domain.
+ *
+ * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu.
+ *
+ * $Id$ # checkin only
+ */
+
+/*
+ * Kludge for handling systems that can't cope with multiple
+ * external definitions of a variable. In ONE routine (tar.c),
+ * we #define TAR_EXTERN to null; here, we set it to "extern" if
+ * it is not already set.
+ */
+#ifndef TAR_EXTERN
+#define TAR_EXTERN extern
+#endif
+
+/*
+ * Header block on tape.
+ *
+ * I'm going to use traditional DP naming conventions here.
+ * A "block" is a big chunk of stuff that we do I/O on.
+ * A "record" is a piece of info that we care about.
+ * Typically many "record"s fit into a "block".
+ */
+#define RECORDSIZE 512
+#define NAMSIZ 100
+#define TUNMLEN 32
+#define TGNMLEN 32
+
+union record {
+ char charptr[RECORDSIZE];
+ struct header {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ char magic[8];
+ char uname[TUNMLEN];
+ char gname[TGNMLEN];
+ char devmajor[8];
+ char devminor[8];
+ } header;
+};
+
+/* The checksum field is filled with this while the checksum is computed. */
+#define CHKBLANKS " " /* 8 blanks, no null */
+
+/* The magic field is filled with this if uname and gname are valid. */
+#define TMAGIC "ustar " /* 7 chars and a null */
+
+/* The linkflag defines the type of file */
+#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
+#define LF_NORMAL '0' /* Normal disk file */
+#define LF_LINK '1' /* Link to previously dumped file */
+#define LF_SYMLINK '2' /* Symbolic link */
+#define LF_CHR '3' /* Character special file */
+#define LF_BLK '4' /* Block special file */
+#define LF_DIR '5' /* Directory */
+#define LF_FIFO '6' /* FIFO special file */
+#define LF_CONTIG '7' /* Contiguous file */
+/* Further link types may be defined later. */
+
+/*
+ * Exit codes from the "tar" program
+ */
+#define EX_SUCCESS 0 /* success! */
+#define EX_ARGSBAD 1 /* invalid args */
+#define EX_BADFILE 2 /* invalid filename */
+#define EX_BADARCH 3 /* bad archive */
+#define EX_SYSTEM 4 /* system gave unexpected error */
+
+
+/*
+ * Global variables
+ */
+TAR_EXTERN union record *ar_block; /* Start of block of archive */
+TAR_EXTERN union record *ar_record; /* Current record of archive */
+TAR_EXTERN union record *ar_last; /* Last+1 record of archive block */
+TAR_EXTERN char ar_reading; /* 0 writing, !0 reading archive */
+TAR_EXTERN int blocking; /* Size of each block, in records */
+TAR_EXTERN int blocksize; /* Size of each block, in bytes */
+TAR_EXTERN char *ar_file; /* File containing archive */
+TAR_EXTERN char *name_file; /* File containing names to work on */
+TAR_EXTERN char *tar; /* Name of this program */
+
+/*
+ * Flags from the command line
+ */
+TAR_EXTERN char f_reblock; /* -B */
+TAR_EXTERN char f_create; /* -c */
+TAR_EXTERN char f_debug; /* -d */
+TAR_EXTERN char f_sayblock; /* -D */
+TAR_EXTERN char f_follow_links; /* -h */
+TAR_EXTERN char f_ignorez; /* -i */
+TAR_EXTERN char f_keep; /* -k */
+TAR_EXTERN char f_modified; /* -m */
+TAR_EXTERN char f_oldarch; /* -o */
+TAR_EXTERN char f_use_protection; /* -p */
+TAR_EXTERN char f_sorted_names; /* -s */
+TAR_EXTERN char f_list; /* -t */
+TAR_EXTERN char f_namefile; /* -T */
+TAR_EXTERN char f_verbose; /* -v */
+TAR_EXTERN char f_extract; /* -x */
+TAR_EXTERN char f_compress; /* -z */
+
+/*
+ * We now default to Unix Standard format rather than 4.2BSD tar format.
+ * The code can actually produce all three:
+ * f_standard ANSI standard
+ * f_oldarch V7
+ * neither 4.2BSD
+ * but we don't bother, since 4.2BSD can read ANSI standard format anyway.
+ * The only advantage to the "neither" option is that we can cmp(1) our
+ * output to the output of 4.2BSD tar, for debugging.
+ */
+#define f_standard (!f_oldarch)
+
+/*
+ * Structure for keeping track of filenames and lists thereof.
+ */
+struct name {
+ struct name *next;
+ short length;
+ char found;
+ char name[NAMSIZ+1];
+};
+
+TAR_EXTERN struct name *namelist; /* Points to first name in list */
+TAR_EXTERN struct name *namelast; /* Points to last name in list */
+
+TAR_EXTERN int archive; /* File descriptor for archive file */
+TAR_EXTERN int errors; /* # of files in error */
+
+/*
+ *
+ * Due to the next struct declaration, each routine that includes
+ * "tar.h" must also include <sys/types.h>. I tried to make it automatic,
+ * but System V has no defines in <sys/types.h>, so there is no way of
+ * knowing when it has been included. In addition, it cannot be included
+ * twice, but must be included exactly once. Argghh!
+ *
+ * Thanks, typedef. Thanks, USG.
+ */
+struct link {
+ struct link *next;
+ dev_t dev;
+ ino_t ino;
+ short linkcount;
+ char name[NAMSIZ+1];
+};
+
+TAR_EXTERN struct link *linklist; /* Points to first link in list */
+
+
+/*
+ * Error recovery stuff
+ */
+TAR_EXTERN char read_error_flag;
+
+
+/*
+ * Declarations of functions available to the world.
+ */
+/*LINTLIBRARY*/
+union record *findrec();
+void userec();
+union record *endofrecs();
+void anno();
+#define annorec(stream, msg) anno(stream, msg, 0) /* Cur rec */
+#define annofile(stream, msg) anno(stream, msg, 1) /* Saved rec */
diff --git a/usr.bin/file2c/Makefile b/usr.bin/file2c/Makefile
new file mode 100644
index 0000000..28cd21e
--- /dev/null
+++ b/usr.bin/file2c/Makefile
@@ -0,0 +1,6 @@
+# $Id$
+
+PROG= file2c
+MAN1= file2c.1
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/file2c/file2c.1 b/usr.bin/file2c/file2c.1
new file mode 100644
index 0000000..ef4e77b
--- /dev/null
+++ b/usr.bin/file2c/file2c.1
@@ -0,0 +1,46 @@
+.\"----------------------------------------------------------------------------
+.\" "THE BEER-WARE LICENSE" (Revision 42):
+.\" <phk@freebsd.org> wrote this file. As long as you retain this notice, you
+.\" can do whatever you want with this file. If we meet some day, and you think
+.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+.\" ---------------------------------------------------------------------------
+.\"
+.\" $Id: file2c.1,v 1.4 1997/06/23 04:51:58 steve Exp $
+.\"
+.Dd January 28, 1995
+.Dt FILE2C 1
+.Os
+.Sh NAME
+.Nm file2c
+.Nd convert file to c-source
+.Sh SYNOPSIS
+.Nm
+.Op "string"
+.Op "string"
+.Sh DESCRIPTION
+The
+.Nm
+utility reads a file from stdin and writes it to stdout, converting each
+byte to its decimal representation on the fly.
+.Pp
+If the first
+.Op string
+is present, it is printed before the data, if the second
+.Op string
+is present, it is printed after the data.
+.Pp
+This program is used to embedd binary or other files into C source files,
+for instance as a char[].
+.Sh EXAMPLE
+The command:
+.Bd -literal -offset indent
+date | file2c 'const char date[] = {' ',0};'
+.Ed
+.Pp
+will produce:
+.Bd -literal -offset indent
+const char date[] = {
+83,97,116,32,74,97,110,32,50,56,32,49,54,58,50,56,58,48,53,
+32,80,83,84,32,49,57,57,53,10
+,0};
+.Ed
diff --git a/usr.bin/file2c/file2c.c b/usr.bin/file2c/file2c.c
new file mode 100644
index 0000000..0bad904
--- /dev/null
+++ b/usr.bin/file2c/file2c.c
@@ -0,0 +1,46 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ int i,j,k;
+ char s[10];
+
+ if (argc > 1)
+ printf("%s\n",argv[1]);
+ k = 0;
+ j = 0;
+ while((i = getchar()) != EOF) {
+ if(k++) {
+ putchar(',');
+ j++;
+ }
+ if (j > 70) {
+ putchar('\n');
+ j = 0;
+ }
+ printf("%d",i);
+ if (i > 99)
+ j += 3;
+ else if (i > 9)
+ j += 2;
+ else
+ j++;
+ }
+ putchar('\n');
+ if (argc > 2)
+ printf("%s\n",argv[2]);
+ return 0;
+}
diff --git a/usr.bin/find/Makefile b/usr.bin/find/Makefile
index c305d6a..af1ea26 100644
--- a/usr.bin/find/Makefile
+++ b/usr.bin/find/Makefile
@@ -2,5 +2,6 @@
PROG= find
SRCS= find.c function.c ls.c main.c misc.c operator.c option.c
+CFLAGS+=-D_NEW_VFSCONF
.include <bsd.prog.mk>
diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h
index 3db2d5f..eb63ecd 100644
--- a/usr.bin/find/extern.h
+++ b/usr.bin/find/extern.h
@@ -49,6 +49,7 @@ int queryuser __P((char **));
PLAN *c_atime __P((char *));
PLAN *c_ctime __P((char *));
+PLAN *c_delete __P((void));
PLAN *c_depth __P((void));
PLAN *c_exec __P((char ***, int));
PLAN *c_follow __P((void));
@@ -64,6 +65,7 @@ PLAN *c_nouser __P((void));
PLAN *c_path __P((char *));
PLAN *c_perm __P((char *));
PLAN *c_print __P((void));
+PLAN *c_print0 __P((void));
PLAN *c_prune __P((void));
PLAN *c_size __P((char *));
PLAN *c_type __P((char *));
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
index a5fc173..652011e 100644
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)find.1 8.7 (Berkeley) 5/9/95
+.\" $Id: find.1,v 1.9 1997/05/19 16:33:26 eivind Exp $
.\"
.Dd May 9, 1995
.Dt FIND 1
@@ -84,6 +85,7 @@ The
option causes the file information and file type (see
.Xr stat 2)
returned for each symbolic link to be those of the link itself.
+This is the default.
.It Fl X
The
.Fl X
@@ -142,6 +144,13 @@ information and the time
was started, rounded up to the next full 24\-hour period, is
.Ar n
24\-hour periods.
+.It Ic -delete
+Delete found files and/or directories. Always returns True. This executes
+from the current working directory as
+.Nm
+recurses down the tree. It will not attempt to delete a filename with a ``/''
+character in its pathname relative to "." for security reasons.
+Depth\-first traversal processing is implied by this option.
.It Ic -exec Ar utility Op argument ... ;
True if the program named
.Ar utility
@@ -273,11 +282,18 @@ It prints the pathname of the current file to standard output.
If none of
.Ic -exec ,
.Ic -ls ,
+.Ic -print0 ,
or
.Ic \&-ok
is specified, the given expression shall be effectively replaced by
.Cm \&( Ns Ar given\& expression Ns Cm \&)
.Ic -print .
+.It Ic -print0
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output, followed by an
+.Tn ASCII
+.Tn NUL
+character (character code 0).
.It Ic -prune
This primary always evaluates to true.
It causes
@@ -411,7 +427,9 @@ The
and
.Fl X
options and the
-.Ic -inum
+.Ic -inum ,
+.Ic -print0 ,
+.Ic -delete ,
and
.Ic -ls
primaries are extensions to
@@ -459,3 +477,13 @@ These problems are handled by the
option and the
.Xr getopt 3
``--'' construct.
+.Pp
+The
+.Ic -delete
+primary do not interact well with other options that cause the filesystem
+tree traversal options to be changed.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
index dbc6c68..8afadf8b 100644
--- a/usr.bin/find/find.c
+++ b/usr.bin/find/find.c
@@ -87,7 +87,7 @@ find_formplan(argv)
tail = new;
}
}
-
+
/*
* if the user didn't specify one of -print, -ok or -exec, then -print
* is assumed so we bracket the current expression with parens, if
@@ -109,7 +109,7 @@ find_formplan(argv)
tail = new;
}
}
-
+
/*
* the command line has been completely processed into a search plan
* except for the (, ), !, and -o operators. Rearrange the plan so
@@ -138,7 +138,7 @@ find_formplan(argv)
plan = or_squish(plan); /* -o's */
return (plan);
}
-
+
FTS *tree; /* pointer to top of FTS hierarchy */
/*
@@ -154,7 +154,7 @@ find_execute(plan, paths)
register FTSENT *entry;
PLAN *p;
int rval;
-
+
if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL)
err(1, "ftsopen");
@@ -188,7 +188,7 @@ find_execute(plan, paths)
rval = 1;
continue;
}
-
+
/*
* Call all the functions in the execution plan until one is
* false or all have been executed. This is where we do all
diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h
index 4c4ffa5..ff007e7 100644
--- a/usr.bin/find/find.h
+++ b/usr.bin/find/find.h
@@ -43,6 +43,7 @@ enum ntype {
N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, N_MTIME, N_NAME, N_NEWER,
N_NOGROUP, N_NOT, N_NOUSER, N_OK, N_OPENPAREN, N_OR, N_PATH,
N_PERM, N_PRINT, N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
+ N_PRINT0, N_DELETE
};
/* node definition */
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
index 02ff6f6..97d63c5 100644
--- a/usr.bin/find/function.c
+++ b/usr.bin/find/function.c
@@ -53,7 +53,6 @@ static char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <tzfile.h>
#include <unistd.h>
#include "find.h"
@@ -77,14 +76,14 @@ static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
* find_parsenum --
* Parse a string of the form [+-]# and return the value.
*/
-static long
+static long long
find_parsenum(plan, option, vp, endch)
PLAN *plan;
char *option, *vp, *endch;
{
- long value;
+ long long value;
char *endchar, *str; /* Pointer to character ending conversion. */
-
+
/* Determine comparison from leading + or -. */
str = vp;
switch (*str) {
@@ -100,13 +99,13 @@ find_parsenum(plan, option, vp, endch)
plan->flags = F_EQUAL;
break;
}
-
+
/*
- * Convert the string with strtol(). Note, if strtol() returns zero
+ * Convert the string with strtoq(). Note, if strtoq() returns zero
* and endchar points to the beginning of the string we know we have
* a syntax error.
*/
- value = strtol(str, &endchar, 10);
+ value = strtoq(str, &endchar, 10);
if (value == 0 && endchar == str)
errx(1, "%s: %s: illegal numeric value", option, vp);
if (endchar[0] && (endch == NULL || endchar[0] != *endch))
@@ -140,9 +139,9 @@ f_atime(plan, entry)
extern time_t now;
COMPARE((now - entry->fts_statp->st_atime +
- SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+ 86400 - 1) / 86400, plan->t_data);
}
-
+
PLAN *
c_atime(arg)
char *arg;
@@ -170,9 +169,9 @@ f_ctime(plan, entry)
extern time_t now;
COMPARE((now - entry->fts_statp->st_ctime +
- SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+ 86400 - 1) / 86400, plan->t_data);
}
-
+
PLAN *
c_ctime(arg)
char *arg;
@@ -201,7 +200,7 @@ f_always_true(plan, entry)
{
return (1);
}
-
+
PLAN *
c_depth()
{
@@ -209,7 +208,7 @@ c_depth()
return (palloc(N_DEPTH, f_always_true));
}
-
+
/*
* [-exec | -ok] utility [arg ... ] ; functions --
*
@@ -240,6 +239,9 @@ f_exec(plan, entry)
if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
return (0);
+ /* make sure find output is interspersed correctly with subprocesses */
+ fflush(stdout);
+
switch (pid = vfork()) {
case -1:
err(1, "fork");
@@ -256,7 +258,7 @@ f_exec(plan, entry)
pid = waitpid(pid, &status, 0);
return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
}
-
+
/*
* c_exec --
* build three parallel arrays, one with pointers to the strings passed
@@ -274,7 +276,7 @@ c_exec(argvp, isok)
register char **argv, **ap, *p;
isoutput = 1;
-
+
new = palloc(N_EXEC, f_exec);
if (isok)
new->flags = F_NEEDOK;
@@ -310,7 +312,7 @@ c_exec(argvp, isok)
*argvp = argv + 1;
return (new);
}
-
+
/*
* -follow functions --
*
@@ -325,7 +327,7 @@ c_follow()
return (palloc(N_FOLLOW, f_always_true));
}
-
+
/*
* -fstype functions --
*
@@ -339,7 +341,7 @@ f_fstype(plan, entry)
static dev_t curdev; /* need a guaranteed illegal dev value */
static int first = 1;
struct statfs sb;
- static short val;
+ static int val_type, val_flags;
char *p, save[2];
/* Only check when we cross mount point. */
@@ -360,8 +362,8 @@ f_fstype(plan, entry)
p[0] = '.';
save[1] = p[1];
p[1] = '\0';
-
- } else
+
+ } else
p = NULL;
if (statfs(entry->fts_accpath, &sb))
@@ -378,19 +380,19 @@ f_fstype(plan, entry)
* Further tests may need both of these values, so
* always copy both of them.
*/
- val = sb.f_flags;
- val = sb.f_type;
+ val_flags = sb.f_flags;
+ val_type = sb.f_type;
}
switch (plan->flags) {
case F_MTFLAG:
- return (val & plan->mt_data);
+ return (val_flags & plan->mt_data) != 0;
case F_MTTYPE:
- return (val == plan->mt_data);
+ return (val_type == plan->mt_data);
default:
abort();
}
}
-
+
PLAN *
c_fstype(arg)
char *arg;
@@ -399,7 +401,7 @@ c_fstype(arg)
struct vfsconf vfc;
ftsoptions &= ~FTS_NOSTAT;
-
+
new = palloc(N_FSTYPE, f_fstype);
/*
@@ -430,7 +432,7 @@ c_fstype(arg)
errx(1, "%s: unknown file type", arg);
/* NOTREACHED */
}
-
+
/*
* -group gname functions --
*
@@ -445,7 +447,7 @@ f_group(plan, entry)
{
return (entry->fts_statp->st_gid == plan->g_data);
}
-
+
PLAN *
c_group(gname)
char *gname;
@@ -453,7 +455,7 @@ c_group(gname)
PLAN *new;
struct group *g;
gid_t gid;
-
+
ftsoptions &= ~FTS_NOSTAT;
g = getgrnam(gname);
@@ -463,7 +465,7 @@ c_group(gname)
errx(1, "-group: %s: no such group", gname);
} else
gid = g->gr_gid;
-
+
new = palloc(N_GROUP, f_group);
new->g_data = gid;
return (new);
@@ -481,20 +483,20 @@ f_inum(plan, entry)
{
COMPARE(entry->fts_statp->st_ino, plan->i_data);
}
-
+
PLAN *
c_inum(arg)
char *arg;
{
PLAN *new;
-
+
ftsoptions &= ~FTS_NOSTAT;
-
+
new = palloc(N_INUM, f_inum);
new->i_data = find_parsenum(new, "-inum", arg, NULL);
return (new);
}
-
+
/*
* -links n functions --
*
@@ -507,20 +509,20 @@ f_links(plan, entry)
{
COMPARE(entry->fts_statp->st_nlink, plan->l_data);
}
-
+
PLAN *
c_links(arg)
char *arg;
{
PLAN *new;
-
+
ftsoptions &= ~FTS_NOSTAT;
-
+
new = palloc(N_LINKS, f_links);
new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
return (new);
}
-
+
/*
* -ls functions --
*
@@ -534,13 +536,13 @@ f_ls(plan, entry)
printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
return (1);
}
-
+
PLAN *
c_ls()
{
ftsoptions &= ~FTS_NOSTAT;
isoutput = 1;
-
+
return (palloc(N_LS, f_ls));
}
@@ -557,10 +559,10 @@ f_mtime(plan, entry)
{
extern time_t now;
- COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
- SECSPERDAY, plan->t_data);
+ COMPARE((now - entry->fts_statp->st_mtime + 86400 - 1) /
+ 86400, plan->t_data);
}
-
+
PLAN *
c_mtime(arg)
char *arg;
@@ -588,7 +590,7 @@ f_name(plan, entry)
{
return (!fnmatch(plan->c_data, entry->fts_name, 0));
}
-
+
PLAN *
c_name(pattern)
char *pattern;
@@ -599,7 +601,7 @@ c_name(pattern)
new->c_data = pattern;
return (new);
}
-
+
/*
* -newer file functions --
*
@@ -614,14 +616,14 @@ f_newer(plan, entry)
{
return (entry->fts_statp->st_mtime > plan->t_data);
}
-
+
PLAN *
c_newer(filename)
char *filename;
{
PLAN *new;
struct stat sb;
-
+
ftsoptions &= ~FTS_NOSTAT;
if (stat(filename, &sb))
@@ -630,7 +632,7 @@ c_newer(filename)
new->t_data = sb.st_mtime;
return (new);
}
-
+
/*
* -nogroup functions --
*
@@ -646,7 +648,7 @@ f_nogroup(plan, entry)
return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
}
-
+
PLAN *
c_nogroup()
{
@@ -654,7 +656,7 @@ c_nogroup()
return (palloc(N_NOGROUP, f_nogroup));
}
-
+
/*
* -nouser functions --
*
@@ -670,7 +672,7 @@ f_nouser(plan, entry)
return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
}
-
+
PLAN *
c_nouser()
{
@@ -678,7 +680,7 @@ c_nouser()
return (palloc(N_NOUSER, f_nouser));
}
-
+
/*
* -path functions --
*
@@ -692,7 +694,7 @@ f_path(plan, entry)
{
return (!fnmatch(plan->c_data, entry->fts_path, 0));
}
-
+
PLAN *
c_path(pattern)
char *pattern;
@@ -703,7 +705,7 @@ c_path(pattern)
new->c_data = pattern;
return (new);
}
-
+
/*
* -perm functions --
*
@@ -726,7 +728,7 @@ f_perm(plan, entry)
return (mode == plan->m_data);
/* NOTREACHED */
}
-
+
PLAN *
c_perm(perm)
char *perm;
@@ -749,7 +751,7 @@ c_perm(perm)
new->m_data = getmode(set, 0);
return (new);
}
-
+
/*
* -print functions --
*
@@ -761,10 +763,10 @@ f_print(plan, entry)
PLAN *plan;
FTSENT *entry;
{
- (void)printf("%s\n", entry->fts_path);
+ (void)puts(entry->fts_path);
return (1);
}
-
+
PLAN *
c_print()
{
@@ -772,7 +774,31 @@ c_print()
return (palloc(N_PRINT, f_print));
}
-
+
+/*
+ * -print0 functions --
+ *
+ * Always true, causes the current pathame to be written to
+ * standard output followed by a NUL character
+ */
+int
+f_print0(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ fputs(entry->fts_path, stdout);
+ fputc('\0', stdout);
+ return (1);
+}
+
+PLAN *
+c_print0()
+{
+ isoutput = 1;
+
+ return (palloc(N_PRINT0, f_print0));
+}
+
/*
* -prune functions --
*
@@ -789,13 +815,13 @@ f_prune(plan, entry)
err(1, "%s", entry->fts_path);
return (1);
}
-
+
PLAN *
c_prune()
{
return (palloc(N_PRUNE, f_prune));
}
-
+
/*
* -size n[c] functions --
*
@@ -817,14 +843,14 @@ f_size(plan, entry)
FIND_SIZE : entry->fts_statp->st_size;
COMPARE(size, plan->o_data);
}
-
+
PLAN *
c_size(arg)
char *arg;
{
PLAN *new;
char endch;
-
+
ftsoptions &= ~FTS_NOSTAT;
new = palloc(N_SIZE, f_size);
@@ -834,7 +860,7 @@ c_size(arg)
divsize = 0;
return (new);
}
-
+
/*
* -type c functions --
*
@@ -849,14 +875,14 @@ f_type(plan, entry)
{
return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
}
-
+
PLAN *
c_type(typestring)
char *typestring;
{
PLAN *new;
mode_t mask;
-
+
ftsoptions &= ~FTS_NOSTAT;
switch (typestring[0]) {
@@ -890,12 +916,72 @@ c_type(typestring)
default:
errx(1, "-type: %s: unknown type", typestring);
}
-
+
new = palloc(N_TYPE, f_type);
new->m_data = mask;
return (new);
}
-
+
+/*
+ * -delete functions --
+ *
+ * True always. Makes it's best shot and continues on regardless.
+ */
+int
+f_delete(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ /* ignore these from fts */
+ if (strcmp(entry->fts_accpath, ".") == 0 ||
+ strcmp(entry->fts_accpath, "..") == 0)
+ return (1);
+
+ /* sanity check */
+ if (isdepth == 0 || /* depth off */
+ (ftsoptions & FTS_NOSTAT) || /* not stat()ing */
+ !(ftsoptions & FTS_PHYSICAL) || /* physical off */
+ (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
+ errx(1, "-delete: insecure options got turned on");
+
+ /* Potentially unsafe - do not accept relative paths whatsoever */
+ if (strchr(entry->fts_accpath, '/') != NULL)
+ errx(1, "-delete: %s: relative path potentially not safe",
+ entry->fts_accpath);
+
+ /* Turn off user immutable bits if running as root */
+ if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+ geteuid() == 0)
+ chflags(entry->fts_accpath,
+ entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
+
+ /* rmdir directories, unlink everything else */
+ if (S_ISDIR(entry->fts_statp->st_mode)) {
+ if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
+ warn("-delete: rmdir(%s)", entry->fts_path);
+ } else {
+ if (unlink(entry->fts_accpath) < 0)
+ warn("-delete: unlink(%s)", entry->fts_path);
+ }
+
+ /* "succeed" */
+ return (1);
+}
+
+PLAN *
+c_delete()
+{
+
+ ftsoptions &= ~FTS_NOSTAT; /* no optimise */
+ ftsoptions |= FTS_PHYSICAL; /* disable -follow */
+ ftsoptions &= ~FTS_LOGICAL; /* disable -follow */
+ isoutput = 1; /* possible output */
+ isdepth = 1; /* -depth implied */
+
+ return (palloc(N_DELETE, f_delete));
+}
+
/*
* -user uname functions --
*
@@ -910,7 +996,7 @@ f_user(plan, entry)
{
return (entry->fts_statp->st_uid == plan->u_data);
}
-
+
PLAN *
c_user(username)
char *username;
@@ -918,7 +1004,7 @@ c_user(username)
PLAN *new;
struct passwd *p;
uid_t uid;
-
+
ftsoptions &= ~FTS_NOSTAT;
p = getpwnam(username);
@@ -933,7 +1019,7 @@ c_user(username)
new->u_data = uid;
return (new);
}
-
+
/*
* -xdev functions --
*
@@ -965,7 +1051,7 @@ f_expr(plan, entry)
p && (state = (p->eval)(p, entry)); p = p->next);
return (state);
}
-
+
/*
* N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
* eliminated during phase 2 of find_formplan() --- the '(' node is converted
@@ -976,13 +1062,13 @@ c_openparen()
{
return (palloc(N_OPENPAREN, (int (*)())-1));
}
-
+
PLAN *
c_closeparen()
{
return (palloc(N_CLOSEPAREN, (int (*)())-1));
}
-
+
/*
* ! expression functions --
*
@@ -1000,13 +1086,13 @@ f_not(plan, entry)
p && (state = (p->eval)(p, entry)); p = p->next);
return (!state);
}
-
+
PLAN *
c_not()
{
return (palloc(N_NOT, f_not));
}
-
+
/*
* expression -o expression functions --
*
diff --git a/usr.bin/find/ls.c b/usr.bin/find/ls.c
index dd51f97..29c068d 100644
--- a/usr.bin/find/ls.c
+++ b/usr.bin/find/ls.c
@@ -43,7 +43,6 @@ static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <string.h>
#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
#include <utmp.h>
@@ -83,14 +82,13 @@ printtime(ftime)
time_t ftime;
{
int i;
- char *longstring, *ctime();
- time_t time();
+ char longstring[80];
- longstring = ctime((long *)&ftime);
+ strftime(longstring, sizeof(longstring), "%c", localtime(&ftime));
for (i = 4; i < 11; ++i)
(void)putchar(longstring[i]);
-#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
+#define SIXMONTHS ((365 / 2) * 86400)
if (ftime + SIXMONTHS > time((time_t *)NULL))
for (i = 11; i < 16; ++i)
(void)putchar(longstring[i]);
diff --git a/usr.bin/find/main.c b/usr.bin/find/main.c
index 20985c8..49ad226 100644
--- a/usr.bin/find/main.c
+++ b/usr.bin/find/main.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
@@ -74,25 +75,26 @@ main(argc, argv)
char *argv[];
{
register char **p, **start;
- int Hflag, Lflag, Pflag, ch;
+ int Hflag, Lflag, ch;
+
+ (void)setlocale(LC_ALL, "");
(void)time(&now); /* initialize the time-of-day */
p = start = argv;
- Hflag = Lflag = Pflag = 0;
+ Hflag = Lflag = 0;
ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "HLPXdf:x")) != EOF)
+ while ((ch = getopt(argc, argv, "HLPXdf:x")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
- Lflag = Pflag = 0;
+ Lflag = 0;
break;
case 'L':
Lflag = 1;
- Hflag = Pflag = 0;
+ Hflag = 0;
break;
case 'P':
- Pflag = 1;
Hflag = Lflag = 0;
break;
case 'X':
@@ -112,7 +114,7 @@ main(argc, argv)
break;
}
- argc -= optind;
+ argc -= optind;
argv += optind;
if (Hflag)
diff --git a/usr.bin/find/misc.c b/usr.bin/find/misc.c
index 1db34ce..71316ee 100644
--- a/usr.bin/find/misc.c
+++ b/usr.bin/find/misc.c
@@ -49,7 +49,7 @@ static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
#include <string.h>
#include "find.h"
-
+
/*
* brace_subst --
* Replace occurrences of {} in s1 with s2 and return the result string.
@@ -110,7 +110,7 @@ queryuser(argv)
}
return (first == 'y');
}
-
+
/*
* emalloc --
* malloc with error checking.
diff --git a/usr.bin/find/operator.c b/usr.bin/find/operator.c
index a706b88..22bfeb6 100644
--- a/usr.bin/find/operator.c
+++ b/usr.bin/find/operator.c
@@ -45,24 +45,24 @@ static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include "find.h"
-
+
/*
* yanknode --
* destructively removes the top from the plan
*/
static PLAN *
-yanknode(planp)
+yanknode(planp)
PLAN **planp; /* pointer to top of plan (modified) */
{
PLAN *node; /* top node removed from the plan */
-
+
if ((node = (*planp)) == NULL)
return (NULL);
(*planp) = (*planp)->next;
node->next = NULL;
return (node);
}
-
+
/*
* yankexpr --
* Removes one expression from the plan. This is used mainly by
@@ -70,7 +70,7 @@ yanknode(planp)
* simple node or a N_EXPR node containing a list of simple nodes.
*/
static PLAN *
-yankexpr(planp)
+yankexpr(planp)
PLAN **planp; /* pointer to top of plan (modified) */
{
register PLAN *next; /* temp node holding subexpression results */
@@ -78,11 +78,11 @@ yankexpr(planp)
PLAN *tail; /* pointer to tail of subplan */
PLAN *subplan; /* pointer to head of ( ) expression */
int f_expr();
-
+
/* first pull the top node from the plan */
if ((node = yanknode(planp)) == NULL)
return (NULL);
-
+
/*
* If the node is an '(' then we recursively slurp up expressions
* until we find its associated ')'. If it's a closing paren we
@@ -119,7 +119,7 @@ yankexpr(planp)
}
return (node);
}
-
+
/*
* paren_squish --
* replaces "parentheisized" plans in our search plan with "expr" nodes.
@@ -131,7 +131,7 @@ paren_squish(plan)
register PLAN *expr; /* pointer to next expression */
register PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
-
+
result = tail = NULL;
/*
@@ -157,7 +157,7 @@ paren_squish(plan)
}
return (result);
}
-
+
/*
* not_squish --
* compresses "!" expressions in our search plan.
@@ -170,9 +170,9 @@ not_squish(plan)
register PLAN *node; /* temporary node used in N_NOT processing */
register PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
-
+
tail = result = next = NULL;
-
+
while ((next = yanknode(&plan)) != NULL) {
/*
* if we encounter a ( expression ) then look for nots in
@@ -198,6 +198,12 @@ not_squish(plan)
errx(1, "!: no following expression");
if (node->type == N_OR)
errx(1, "!: nothing between ! and -o");
+ /*
+ * If we encounter ! ( expr ) then look for nots in
+ * the expr subplan.
+ */
+ if (node->type == N_EXPR)
+ node->p_data[0] = not_squish(node->p_data[0]);
if (notlevel % 2 != 1)
next = node;
else
@@ -215,7 +221,7 @@ not_squish(plan)
}
return (result);
}
-
+
/*
* or_squish --
* compresses -o expressions in our search plan.
@@ -227,9 +233,9 @@ or_squish(plan)
register PLAN *next; /* next node being processed */
register PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
-
+
tail = result = next = NULL;
-
+
while ((next = yanknode(&plan)) != NULL) {
/*
* if we encounter a ( expression ) then look for or's in
@@ -238,7 +244,7 @@ or_squish(plan)
if (next->type == N_EXPR)
next->p_data[0] = or_squish(next->p_data[0]);
- /* if we encounter a not then look for not's in the subplan */
+ /* if we encounter a not then look for or's in the subplan */
if (next->type == N_NOT)
next->p_data[0] = or_squish(next->p_data[0]);
diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c
index 9b25cee..c316d4a 100644
--- a/usr.bin/find/option.c
+++ b/usr.bin/find/option.c
@@ -60,6 +60,7 @@ static OPTION const options[] = {
{ "-and", N_AND, NULL, O_NONE },
{ "-atime", N_ATIME, c_atime, O_ARGV },
{ "-ctime", N_CTIME, c_ctime, O_ARGV },
+ { "-delete", N_DELETE, c_delete, O_ZERO },
{ "-depth", N_DEPTH, c_depth, O_ZERO },
{ "-exec", N_EXEC, c_exec, O_ARGVP },
{ "-follow", N_FOLLOW, c_follow, O_ZERO },
@@ -79,6 +80,7 @@ static OPTION const options[] = {
{ "-path", N_PATH, c_path, O_ARGV },
{ "-perm", N_PERM, c_perm, O_ARGV },
{ "-print", N_PRINT, c_print, O_ZERO },
+ { "-print0", N_PRINT0, c_print0, O_ZERO },
{ "-prune", N_PRUNE, c_prune, O_ZERO },
{ "-size", N_SIZE, c_size, O_ARGV },
{ "-type", N_TYPE, c_type, O_ARGV },
diff --git a/usr.bin/finger/extern.h b/usr.bin/finger/extern.h
index b213fe4..e9abd72 100644
--- a/usr.bin/finger/extern.h
+++ b/usr.bin/finger/extern.h
@@ -41,6 +41,7 @@ void enter_lastlog __P((PERSON *));
PERSON *enter_person __P((struct passwd *));
void enter_where __P((struct utmp *, PERSON *));
PERSON *find_person __P((char *));
+int hide __P((struct passwd *));
void lflag_print __P((void));
int match __P((struct passwd *, char *));
void netfinger __P((char *));
diff --git a/usr.bin/finger/finger.1 b/usr.bin/finger/finger.1
index 045084a..9d0755c 100644
--- a/usr.bin/finger/finger.1
+++ b/usr.bin/finger/finger.1
@@ -39,7 +39,7 @@
.Nd user information lookup program
.Sh SYNOPSIS
.Nm finger
-.Op Fl lmsp
+.Op Fl lmpshoT
.Op Ar user ...
.Op Ar user@host ...
.Sh DESCRIPTION
@@ -53,24 +53,41 @@ Options are:
.Nm Finger
displays the user's login name, real name, terminal name and write
status (as a ``*'' before the terminal name if write permission is
-denied), idle time, login time, office location and office phone
-number.
+denied), idle time, login time, and either office location and office
+phone number, or the remote host. If
+.Fl h
+is given, the remote host is printed (the default.) If
+.Fl o
+is given, the office location and office phone number is printed
+instead.
.Pp
Idle time is in minutes if it is a single integer, hours and minutes
if a ``:'' is present, or days if a ``d'' is present.
-Login time is displayed as month, day, hours and minutes, unless
-more than six months ago, in which case the year is displayed rather
-than the hours and minutes.
+Login time is displayed as the dayname if less than 6 days, else month, day;
+hours and minutes, unless more than six months ago, in which case the year
+is displayed rather than the hours and minutes.
.Pp
Unknown devices as well as nonexistent idle and login times are
displayed as single asterisks.
.Pp
+.It Fl h
+When used in conjunction with the
+.Fl s
+option, the name of the remote host is displayed instead of the office
+location and office phone.
+.Pp
+.It Fl o
+When used in conjunction with the
+.Fl s
+option, the office location and office phone information is displayed
+instead of the name of the remote host.
+.Pp
.It Fl l
Produces a multi-line format displaying all of the information
described for the
.Fl s
option as well as the user's home directory, home phone number, login
-shell, and the contents of the files
+shell, mail status, and the contents of the files
.Dq Pa .forward ,
.Dq Pa .plan
and
@@ -85,6 +102,7 @@ Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''.
Numbers specified as ten or seven digits are printed as the appropriate
subset of that string.
Numbers specified as five digits are printed as ``xN-NNNN''.
+Numbers specified as four digits are printed as ``xNNNN''.
.Pp
If write permission is denied to the device, the phrase ``(messages off)''
is appended to the line containing the device name.
@@ -93,6 +111,11 @@ One entry per user is displayed with the
option; if a user is logged on multiple times, terminal information
is repeated once per login.
.Pp
+Mail status is shown as ``No Mail.'' if there is no mail at all, ``Mail
+last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their
+mailbox since new mail arriving, or ``New mail received ...'', ``Unread
+since ...'' if they have new mail.
+.Pp
.It Fl p
Prevents
the
@@ -117,6 +140,11 @@ option is supplied.
All name matching performed by
.Nm finger
is case insensitive.
+.Pp
+.It Fl T
+Disable the use of T/TCP (see
+.Xr ttcp 4 ).
+This option is needed to finger hosts with a broken TCP implementation.
.El
.Pp
If no options are specified,
@@ -150,6 +178,20 @@ style.
The
.Fl l
option is the only option that may be passed to a remote machine.
+.Pp
+If the file
+.Dq Pa .nofinger
+exists in the user's home directory,
+.Nm finger
+behaves as if the user in question does not exist.
+.Sh ENVIRONMENT
+.Nm Finger
+utilizes the following environment variable, if it exists:
+.Bl -tag -width Fl
+.It Ev FINGER
+This variable may be set with favored options to
+.Nm finger .
+.El
.Sh FILES
.Bl -tag -width /var/log/lastlog -compact
.It Pa /var/log/lastlog
@@ -159,6 +201,7 @@ last login data base
.Xr chpass 1 ,
.Xr w 1 ,
.Xr who 1 ,
+.Xr ttcp 4 .
.Sh HISTORY
The
.Nm finger
diff --git a/usr.bin/finger/finger.c b/usr.bin/finger/finger.c
index f4ece3a..091ac16 100644
--- a/usr.bin/finger/finger.c
+++ b/usr.bin/finger/finger.c
@@ -34,6 +34,16 @@
* SUCH DAMAGE.
*/
+/*
+ * Luke Mewburn <lm@rmit.edu.au> added the following on 940622:
+ * - mail status ("No Mail", "Mail read:...", or "New Mail ...,
+ * Unread since ...".)
+ * - 4 digit phone extensions (3210 is printed as x3210.)
+ * - host/office toggling in short format with -h & -o.
+ * - short day names (`Tue' printed instead of `Jun 21' if the
+ * login time is < 6 days.
+ */
+
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
@@ -41,7 +51,12 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
+#if 0
static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
/*
@@ -52,9 +67,10 @@ static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
*
* There are currently two output formats; the short format is one line
* per user and displays login name, tty, login time, real name, idle time,
- * and office location/phone number. The long format gives the same
- * information (in a more legible format) as well as home directory, shell,
- * mail info, and .plan/.project files.
+ * and either remote host information (default) or office location/phone
+ * number, depending on if -h or -o is used respectively.
+ * The long format gives the same information (in a more legible format) as
+ * well as home directory, shell, mail info, and .plan/.project files.
*/
#include <sys/param.h>
@@ -70,25 +86,30 @@ static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
#include <time.h>
#include <unistd.h>
#include <utmp.h>
+#include <db.h>
+#include <locale.h>
#include "finger.h"
DB *db;
time_t now;
-int entries, lflag, mflag, pplan, sflag;
+int entries, lflag, mflag, pplan, sflag, oflag, Tflag;
char tbuf[1024];
static void loginlist __P((void));
+static void usage __P((void));
static void userlist __P((int, char **));
int
-main(argc, argv)
+option(argc, argv)
int argc;
char **argv;
{
int ch;
- while ((ch = getopt(argc, argv, "lmps")) != EOF)
+ optind = 1; /* reset getopt */
+
+ while ((ch = getopt(argc, argv, "lmpshoT")) != -1)
switch(ch) {
case 'l':
lflag = 1; /* long format */
@@ -102,14 +123,56 @@ main(argc, argv)
case 's':
sflag = 1; /* short format */
break;
+ case 'h':
+ oflag = 0; /* remote host info */
+ break;
+ case 'o':
+ oflag = 1; /* office info */
+ break;
+ case 'T':
+ Tflag = 1; /* disable T/TCP */
+ break;
case '?':
default:
- (void)fprintf(stderr,
- "usage: finger [-lmps] [login ...]\n");
- exit(1);
+ usage();
}
- argc -= optind;
- argv += optind;
+
+ return optind;
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: finger [-lmpshoT] [login ...]\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int envargc, argcnt;
+ char *envargv[3];
+
+ (void) setlocale(LC_ALL, "");
+
+ /* remove this line to get remote host */
+ oflag = 1; /* default to old "office" behavior */
+
+ /*
+ * Process environment variables followed by command line arguments.
+ */
+ if ((envargv[1] = getenv("FINGER"))) {
+ envargc = 2;
+ envargv[0] = "finger";
+ envargv[2] = NULL;
+ (void) option(envargc, envargv);
+ }
+
+ argcnt = option(argc, argv);
+ argc -= argcnt;
+ argv += argcnt;
(void)time(&now);
setpassent(1);
@@ -154,7 +217,7 @@ loginlist()
if (!freopen(_PATH_UTMP, "r", stdin))
err(1, "%s", _PATH_UTMP);
- name[UT_NAMESIZE] = NULL;
+ name[UT_NAMESIZE] = '\0';
while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
if (!user.ut_name[0])
continue;
@@ -162,6 +225,8 @@ loginlist()
bcopy(user.ut_name, name, UT_NAMESIZE);
if ((pw = getpwnam(name)) == NULL)
continue;
+ if (hide(pw))
+ continue;
pn = enter_person(pw);
}
enter_where(&user, pn);
@@ -215,27 +280,29 @@ userlist(argc, argv)
*/
if (mflag)
for (p = argv; *p; ++p)
- if ((pw = getpwnam(*p)) != NULL)
+ if (((pw = getpwnam(*p)) != NULL) && !hide(pw))
enter_person(pw);
else
- (void)fprintf(stderr,
- "finger: %s: no such user\n", *p);
+ warnx("%s: no such user", *p);
else {
- while ((pw = getpwent()) != NULL)
+ while ((pw = getpwent()) != NULL) {
for (p = argv, ip = used; *p; ++p, ++ip)
- if (match(pw, *p)) {
+ if (match(pw, *p) && !hide(pw)) {
enter_person(pw);
*ip = 1;
}
+ }
for (p = argv, ip = used; *p; ++p, ++ip)
if (!*ip)
- (void)fprintf(stderr,
- "finger: %s: no such user\n", *p);
+ warnx("%s: no such user", *p);
}
/* Handle network requests. */
-net: for (p = nargv; *p;)
+net: for (p = nargv; *p;) {
netfinger(*p++);
+ if (*p || entries)
+ printf("\n");
+ }
if (entries == 0)
return;
diff --git a/usr.bin/finger/finger.h b/usr.bin/finger/finger.h
index 5104425..b8538fa 100644
--- a/usr.bin/finger/finger.h
+++ b/usr.bin/finger/finger.h
@@ -45,6 +45,8 @@ typedef struct person {
char *officephone; /* pointer to office phone no. */
char *realname; /* pointer to full name */
char *shell; /* user's shell */
+ time_t mailread; /* last time mail was read */
+ time_t mailrecv; /* last time mail was received */
struct where *whead, *wtail; /* list of where user is or has been */
} PERSON;
diff --git a/usr.bin/finger/lprint.c b/usr.bin/finger/lprint.c
index 96edb1b..a0643ca 100644
--- a/usr.bin/finger/lprint.c
+++ b/usr.bin/finger/lprint.c
@@ -35,7 +35,12 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
#include <sys/types.h>
@@ -43,7 +48,6 @@ static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95";
#include <sys/time.h>
#include <fcntl.h>
#include <time.h>
-#include <tzfile.h>
#include <db.h>
#include <err.h>
#include <pwd.h>
@@ -107,7 +111,8 @@ lprint(pn)
register int cpr, len, maxlen;
struct tm *tp;
int oddfield;
- char *t, *tzn;
+ char *tzn;
+ char t[80];
/*
* long format --
@@ -116,6 +121,7 @@ lprint(pn)
* home directory
* shell
* office, office phone, home phone if available
+ * mail status
*/
(void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
pn->name, pn->realname, pn->dir);
@@ -155,7 +161,8 @@ lprint(pn)
putchar('\n');
/*
- * long format con't: * if logged in
+ * long format con't:
+ * if logged in
* terminal
* idle time
* if messages allowed
@@ -172,7 +179,7 @@ lprint(pn)
switch (w->info) {
case LOGGEDIN:
tp = localtime(&w->loginat);
- t = asctime(tp);
+ strftime(t, sizeof(t), "%c", tp);
tzn = tp->tm_zone;
cpr = printf("On since %.16s (%s) on %s",
t, tzn, w->tty);
@@ -206,9 +213,9 @@ lprint(pn)
break;
}
tp = localtime(&w->loginat);
- t = asctime(tp);
+ strftime(t, sizeof(t), "%c", tp);
tzn = tp->tm_zone;
- if (now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2)
+ if (now - w->loginat > 86400 * 365 / 2)
cpr =
printf("Last login %.16s %.4s (%s) on %s",
t, t + 20, tzn, w->tty);
@@ -224,6 +231,23 @@ lprint(pn)
}
putchar('\n');
}
+ if (pn->mailrecv == -1)
+ printf("No Mail.\n");
+ else if (pn->mailrecv > pn->mailread) {
+ tp = localtime(&pn->mailrecv);
+ strftime(t, sizeof(t), "%c", tp);
+ tzn = tp->tm_zone;
+ printf("New mail received %.16s %.4s (%s)\n", t, t + 20, tzn);
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t), "%c", tp);
+ tzn = tp->tm_zone;
+ printf(" Unread since %.16s %.4s (%s)\n", t, t + 20, tzn);
+ } else {
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t), "%c", tp);
+ tzn = tp->tm_zone;
+ printf("Mail last read %.16s %.4s (%s)\n", t, t + 20, tzn);
+ }
}
static int
@@ -294,7 +318,8 @@ show_text(directory, file_name, header)
if (cnt <= 1) {
(void)printf("%s: ", header);
for (p = tbuf, cnt = nr; cnt--; ++p)
- vputc(lastc = *p);
+ if (*p != '\r')
+ vputc(lastc = *p);
if (lastc != '\n')
(void)putchar('\n');
(void)close(fd);
@@ -307,7 +332,8 @@ show_text(directory, file_name, header)
return(0);
(void)printf("%s:\n", header);
while ((ch = getc(fp)) != EOF)
- vputc(lastc = ch);
+ if (ch != '\r')
+ vputc(lastc = ch);
if (lastc != '\n')
(void)putchar('\n');
(void)fclose(fp);
@@ -320,7 +346,7 @@ vputc(ch)
{
int meta;
- if (!isascii(ch)) {
+ if (!isprint(ch) && !isascii(ch)) {
(void)putchar('M');
(void)putchar('-');
ch = toascii(ch);
diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c
index 3eb7518..e4bbfc6 100644
--- a/usr.bin/finger/net.c
+++ b/usr.bin/finger/net.c
@@ -35,7 +35,12 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
#include <sys/types.h>
@@ -44,12 +49,14 @@ static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95";
#include <arpa/inet.h>
#include <netdb.h>
#include <db.h>
+#include <err.h>
#include <unistd.h>
#include <pwd.h>
#include <utmp.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
+#include <sys/uio.h>
#include "finger.h"
void
@@ -57,6 +64,7 @@ netfinger(name)
char *name;
{
extern int lflag;
+ extern int Tflag;
register FILE *fp;
register int c, lastc;
struct in_addr defaddr;
@@ -65,10 +73,12 @@ netfinger(name)
struct sockaddr_in sin;
int s;
char *alist[1], *host;
+ struct iovec iov[3];
+ struct msghdr msg;
if (!(host = rindex(name, '@')))
return;
- *host++ = NULL;
+ *host++ = '\0';
if (isdigit(*host) && (defaddr.s_addr = inet_addr(host)) != -1) {
def.h_name = host;
def.h_addr_list = alist;
@@ -78,12 +88,11 @@ netfinger(name)
def.h_aliases = 0;
hp = &def;
} else if (!(hp = gethostbyname(host))) {
- (void)fprintf(stderr,
- "finger: unknown host: %s\n", host);
+ warnx("unknown host: %s", host);
return;
}
if (!(sp = getservbyname("finger", "tcp"))) {
- (void)fprintf(stderr, "finger: tcp/finger: unknown service\n");
+ warnx("tcp/finger: unknown service");
return;
}
sin.sin_family = hp->h_addrtype;
@@ -96,18 +105,37 @@ netfinger(name)
/* have network connection; identify the host connected with */
(void)printf("[%s]\n", hp->h_name);
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+
+ msg.msg_name = (void *)&sin;
+ msg.msg_namelen = sizeof sin;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 0;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_EOF;
+
+ /* -l flag for remote fingerd */
+ if (lflag) {
+ iov[msg.msg_iovlen].iov_base = "/W ";
+ iov[msg.msg_iovlen++].iov_len = 3;
+ }
+ /* send the name followed by <CR><LF> */
+ iov[msg.msg_iovlen].iov_base = name;
+ iov[msg.msg_iovlen++].iov_len = strlen(name);
+ iov[msg.msg_iovlen].iov_base = "\r\n";
+ iov[msg.msg_iovlen++].iov_len = 2;
+
+ /* -T disables T/TCP: compatibility option to finger broken hosts */
+ if (Tflag && connect(s, (struct sockaddr *)&sin, sizeof (sin))) {
perror("finger: connect");
- (void)close(s);
return;
}
- /* -l flag for remote fingerd */
- if (lflag)
- write(s, "/W ", 3);
- /* send the name followed by <CR><LF> */
- (void)write(s, name, strlen(name));
- (void)write(s, "\r\n", 2);
+ if (sendmsg(s, &msg, MSG_EOF) < 0) {
+ perror("finger: sendmsg");
+ close(s);
+ return;
+ }
/*
* Read from the remote system; once we're connected, we assume some
@@ -120,19 +148,20 @@ netfinger(name)
* Otherwise, all high bits are stripped; if it isn't printable and
* it isn't a space, we can simply set the 7th bit. Every ASCII
* character with bit 7 set is printable.
- */
+ */
lastc = 0;
- if ((fp = fdopen(s, "r")) != NULL)
+ if ((fp = fdopen(s, "r")) != NULL) {
while ((c = getc(fp)) != EOF) {
- c &= 0x7f;
if (c == 0x0d) {
if (lastc == '\r') /* ^M^M - skip dupes */
continue;
c = '\n';
lastc = '\r';
} else {
- if (!isprint(c) && !isspace(c))
+ if (!isprint(c) && !isspace(c)) {
+ c &= 0x7f;
c |= 0x40;
+ }
if (lastc != '\r' || c != '\n')
lastc = c;
else {
@@ -142,8 +171,15 @@ netfinger(name)
}
putchar(c);
}
- if (lastc != '\n')
- putchar('\n');
- putchar('\n');
- (void)fclose(fp);
+ if (lastc != '\n')
+ putchar('\n');
+
+ if (ferror(fp)) {
+ /*
+ * Assume that whatever it was set errno...
+ */
+ perror("finger: read");
+ }
+ (void)fclose(fp);
+ }
}
diff --git a/usr.bin/finger/sprint.c b/usr.bin/finger/sprint.c
index 54c7eea..8c38d7c 100644
--- a/usr.bin/finger/sprint.c
+++ b/usr.bin/finger/sprint.c
@@ -35,13 +35,17 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
-#include <tzfile.h>
#include <db.h>
#include <err.h>
#include <pwd.h>
@@ -58,10 +62,11 @@ void
sflag_print()
{
extern time_t now;
+ extern int oflag;
register PERSON *pn;
register WHERE *w;
- register int sflag, r;
- register char *p;
+ register int sflag, r, namelen;
+ char p[80];
PERSON *tmp;
DBT data, key;
@@ -73,14 +78,19 @@ sflag_print()
* if terminal writeable (add an '*' to the terminal name
* if not)
* if logged in show idle time and day logged in, else
- * show last login date and time. If > 6 moths,
- * show year instead of time.
- * office location
- * office phone
+ * show last login date and time.
+ * If > 6 months, show year instead of time.
+ * if (-o)
+ * office location
+ * office phone
+ * else
+ * remote host
*/
#define MAXREALNAME 20
- (void)printf("%-*s %-*s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
- "Name", "Tty Idle Login Time Office Office Phone");
+#define MAXHOSTNAME 17 /* in reality, hosts are never longer than 16 */
+ (void)printf("%-*s %-*s%s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
+ "Name", " TTY Idle Login Time",
+ oflag ? " Office Phone" : " Where");
for (sflag = R_FIRST;; sflag = R_NEXT) {
r = (*db->seq)(db, &key, &data, sflag);
@@ -92,9 +102,12 @@ sflag_print()
pn = tmp;
for (w = pn->whead; w != NULL; w = w->next) {
- (void)printf("%-*.*s %-*.*s ", UT_NAMESIZE, UT_NAMESIZE,
- pn->name, MAXREALNAME, MAXREALNAME,
- pn->realname ? pn->realname : "");
+ namelen = MAXREALNAME;
+ if (w->info == LOGGEDIN && !w->writable)
+ --namelen; /* leave space before `*' */
+ (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, UT_NAMESIZE,
+ pn->name, MAXREALNAME, namelen,
+ pn->realname ? pn->realname : "");
if (!w->loginat) {
(void)printf(" * * No logins ");
goto office;
@@ -102,29 +115,39 @@ sflag_print()
(void)putchar(w->info == LOGGEDIN && !w->writable ?
'*' : ' ');
if (*w->tty)
- (void)printf("%-2.2s ",
- w->tty[0] != 't' || w->tty[1] != 't' ||
- w->tty[2] != 'y' ? w->tty : w->tty + 3);
+ (void)printf("%-3.3s ",
+ (strncmp(w->tty, "tty", 3)
+ && strncmp(w->tty, "cua", 3))
+ ? w->tty : w->tty + 3);
else
- (void)printf(" ");
+ (void)printf(" ");
if (w->info == LOGGEDIN) {
stimeprint(w);
(void)printf(" ");
} else
(void)printf(" * ");
- p = ctime(&w->loginat);
- (void)printf("%.6s", p + 4);
+ strftime(p, sizeof(p), "%c", localtime(&w->loginat));
+#define SECSPERDAY 86400
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+ if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1))
+ (void)printf("%.3s ", p);
+ else
+ (void)printf("%.6s", p + 4);
if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2)
(void)printf(" %.4s", p + 20);
else
(void)printf(" %.5s", p + 11);
-office: if (pn->office)
- (void)printf(" %-10.10s", pn->office);
- else if (pn->officephone)
- (void)printf(" %-10.10s", " ");
- if (pn->officephone)
- (void)printf(" %-.15s",
- prphone(pn->officephone));
+office: if (oflag) {
+ if (pn->office)
+ (void)printf(" %-7.7s", pn->office);
+ else if (pn->officephone)
+ (void)printf(" %-7.7s", " ");
+ if (pn->officephone)
+ (void)printf(" %-.9s",
+ prphone(pn->officephone));
+ } else
+ (void)printf(" %.*s", MAXHOSTNAME, w->host);
putchar('\n');
}
}
diff --git a/usr.bin/finger/util.c b/usr.bin/finger/util.c
index b51b7ab..0a48d46 100644
--- a/usr.bin/finger/util.c
+++ b/usr.bin/finger/util.c
@@ -35,7 +35,12 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
#include <sys/param.h>
@@ -52,6 +57,7 @@ static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
#include <stdlib.h>
#include <string.h>
#include <paths.h>
+#include <errno.h>
#include "finger.h"
static void find_idle_and_ttywrite __P((WHERE *));
@@ -113,7 +119,7 @@ enter_lastlog(pn)
(long)pn->uid * sizeof(ll) ||
read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
/* as if never logged in */
- ll.ll_line[0] = ll.ll_host[0] = NULL;
+ ll.ll_line[0] = ll.ll_host[0] = '\0';
ll.ll_time = 0;
}
if ((w = pn->whead) == NULL)
@@ -201,6 +207,8 @@ PERSON *
find_person(name)
char *name;
{
+ struct passwd *pw;
+
register int cnt;
DBT data, key;
PERSON *p;
@@ -209,6 +217,9 @@ find_person(name)
if (!db)
return(NULL);
+ if ((pw = getpwnam(name)) && hide(pw))
+ return(NULL);
+
/* Name may be only UT_NAMESIZE long and not NUL terminated. */
for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
buf[cnt] = *name;
@@ -282,14 +293,17 @@ prphone(num)
*p++ = *num++;
break;
case 5: /* x0-1234 */
+ case 4: /* x1234 */
*p++ = 'x';
*p++ = *num++;
break;
default:
return(num);
}
- *p++ = '-';
- *p++ = *num++;
+ if (len != 4) {
+ *p++ = '-';
+ *p++ = *num++;
+ }
*p++ = *num++;
*p++ = *num++;
*p++ = *num++;
@@ -322,6 +336,7 @@ userinfo(pn, pw)
{
register char *p, *t;
char *bp, name[1024];
+ struct stat sb;
pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
@@ -354,4 +369,37 @@ userinfo(pn, pw)
strdup(p) : NULL;
pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
strdup(p) : NULL;
+ (void)sprintf(tbuf,"%s/%s", _PATH_MAILDIR, pw->pw_name);
+ pn->mailrecv = -1; /* -1 == not_valid */
+ if (stat(tbuf, &sb) < 0) {
+ if (errno != ENOENT) {
+ warn("%s", tbuf);
+ return;
+ }
+ } else if (sb.st_size != 0) {
+ pn->mailrecv = sb.st_mtime;
+ pn->mailread = sb.st_atime;
+ }
+}
+
+/*
+ * Is this user hiding from finger?
+ * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
+ */
+
+int
+hide(pw)
+ struct passwd *pw;
+{
+ char buf[MAXPATHLEN+1];
+
+ if (!pw->pw_dir)
+ return 0;
+
+ sprintf (buf, "%s/.nofinger", pw->pw_dir);
+
+ if (access (buf, F_OK) == 0)
+ return 1;
+
+ return 0;
}
diff --git a/usr.bin/fmt/fmt.1 b/usr.bin/fmt/fmt.1
index 4c76cc7..7581055 100644
--- a/usr.bin/fmt/fmt.1
+++ b/usr.bin/fmt/fmt.1
@@ -38,7 +38,8 @@
.Nm fmt
.Nd simple text formatter
.Sh SYNOPSIS
-.Nm fmt
+.Nm
+.Fl c
.Oo
.Ar goal
.Op Ar maximum
@@ -58,6 +59,11 @@ to 65 and the maximum to 75. The spacing at the beginning of the
input lines is preserved in the output, as are blank lines and
interword spacing.
.Pp
+.Fl c
+instructs
+.Nm
+to center the text.
+.Pp
.Nm Fmt
is meant to format mail messages prior to sending, but may also be useful
for other simple tasks.
@@ -73,11 +79,11 @@ the command
will reformat a paragraph,
evening the lines.
.Sh SEE ALSO
-.Xr nroff 1 ,
-.Xr mail 1
+.Xr mail 1 ,
+.Xr nroff 1
.Sh HISTORY
The
-.Nm fmt
+.Nm
command appeared in
.Bx 3 .
.\" .Sh AUTHOR
diff --git a/usr.bin/fmt/fmt.c b/usr.bin/fmt/fmt.c
index 565adf4..3c85550 100644
--- a/usr.bin/fmt/fmt.c
+++ b/usr.bin/fmt/fmt.c
@@ -38,11 +38,20 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
+#if 0
static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93";
+#else
+static const char rcsid[] =
+ "$Id$";
+#endif
#endif /* not lint */
-#include <stdio.h>
#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
/*
* fmt -- format the concatenation of input files or standard input
@@ -66,16 +75,27 @@ int max_length; /* Max line length in output */
int pfx; /* Current leading blank count */
int lineno; /* Current input line */
int mark; /* Last place we saw a head line */
+int center;
-char *malloc(); /* for lint . . . */
char *headnames[] = {"To", "Subject", "Cc", 0};
+void fmt __P((FILE *));
+int ispref __P((char *, char *));
+void leadin __P((void));
+void oflush __P((void));
+void pack __P((char [], int));
+void prefix __P((char []));
+void setout __P((void));
+void split __P((char []));
+void tabulate __P((char []));
+
/*
* Drive the whole formatter by managing input files. Also,
* cause initialization of the output stuff and flush it out
* at the end.
*/
+int
main(argc, argv)
int argc;
char **argv;
@@ -84,14 +104,21 @@ main(argc, argv)
register int errs = 0;
int number; /* LIZ@UOM 6/18/85 */
+ (void) setlocale(LC_CTYPE, "");
+
goal_length = GOAL_LENGTH;
max_length = MAX_LENGTH;
setout();
lineno = 1;
mark = -10;
/*
- * LIZ@UOM 6/18/85 -- Check for goal and max length arguments
+ * LIZ@UOM 6/18/85 -- Check for goal and max length arguments
*/
+ if (argc > 1 && !strcmp(argv[1], "-c")) {
+ center++;
+ argc--;
+ argv++;
+ }
if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) {
argv++;
argc--;
@@ -102,11 +129,8 @@ main(argc, argv)
max_length = number;
}
}
- if (max_length <= goal_length) {
- fprintf(stderr, "Max length must be greater than %s\n",
- "goal length");
- exit(1);
- }
+ if (max_length <= goal_length)
+ errx(1, "max length must be greater than goal length");
if (argc < 2) {
fmt(stdin);
oflush();
@@ -130,13 +154,37 @@ main(argc, argv)
* doing ^H processing, expanding tabs, stripping trailing blanks,
* and sending each line down for analysis.
*/
+void
fmt(fi)
FILE *fi;
{
- char linebuf[BUFSIZ], canonb[BUFSIZ];
- register char *cp, *cp2;
+ static char *linebuf = 0, *canonb = 0;
+ register char *cp, *cp2, cc;
register int c, col;
-
+#define CHUNKSIZE 1024
+ static int lbufsize = 0, cbufsize = 0;
+
+ if (center) {
+ linebuf = malloc(BUFSIZ);
+ while (1) {
+ cp = fgets(linebuf, BUFSIZ, fi);
+ if (!cp)
+ return;
+ while (*cp && isspace(*cp))
+ cp++;
+ cp2 = cp + strlen(cp) - 1;
+ while (cp2 > cp && isspace(*cp2))
+ cp2--;
+ if (cp == cp2)
+ putchar('\n');
+ col = cp2 - cp;
+ for (c = 0; c < (goal_length-col)/2; c++)
+ putchar(' ');
+ while (cp <= cp2)
+ putchar(*cp++);
+ putchar('\n');
+ }
+ }
c = getc(fi);
while (c != EOF) {
/*
@@ -144,44 +192,73 @@ fmt(fi)
* Leave tabs for now.
*/
cp = linebuf;
- while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) {
+ while (c != '\n' && c != EOF) {
+ if (cp - linebuf >= lbufsize) {
+ int offset = cp - linebuf;
+ lbufsize += CHUNKSIZE;
+ linebuf = realloc(linebuf, lbufsize);
+ if(linebuf == 0)
+ abort();
+ cp = linebuf + offset;
+ }
if (c == '\b') {
if (cp > linebuf)
cp--;
c = getc(fi);
continue;
}
- if ((c < ' ' || c >= 0177) && c != '\t') {
+ if (!isprint(c) && c != '\t') {
c = getc(fi);
continue;
}
*cp++ = c;
c = getc(fi);
}
- *cp = '\0';
/*
* Toss anything remaining on the input line.
*/
while (c != '\n' && c != EOF)
c = getc(fi);
-
+
+ if (cp != NULL) {
+ *cp = '\0';
+ } else {
+ putchar('\n');
+ c = getc(fi);
+ continue;
+ }
+
/*
* Expand tabs on the way to canonb.
*/
col = 0;
cp = linebuf;
cp2 = canonb;
- while (c = *cp++) {
- if (c != '\t') {
+ while ((cc = *cp++)) {
+ if (cc != '\t') {
col++;
- if (cp2-canonb < BUFSIZ-1)
- *cp2++ = c;
+ if (cp2 - canonb >= cbufsize) {
+ int offset = cp2 - canonb;
+ cbufsize += CHUNKSIZE;
+ canonb = realloc(canonb, cbufsize);
+ if(canonb == 0)
+ abort();
+ cp2 = canonb + offset;
+ }
+ *cp2++ = cc;
continue;
}
do {
- if (cp2-canonb < BUFSIZ-1)
- *cp2++ = ' ';
+ if (cp2 - canonb >= cbufsize) {
+ int offset = cp2 - canonb;
+ cbufsize += CHUNKSIZE;
+ canonb = realloc(canonb, cbufsize);
+ if(canonb == 0)
+ abort();
+ cp2 = canonb + offset;
+ }
+ *cp2++ = ' ';
col++;
} while ((col & 07) != 0);
}
@@ -205,13 +282,14 @@ fmt(fi)
* Finally, if the line minus the prefix is a mail header, try to keep
* it on a line by itself.
*/
+void
prefix(line)
char line[];
{
register char *cp, **hp;
register int np, h;
- if (strlen(line) == 0) {
+ if (!*line) {
oflush();
putchar('\n');
return;
@@ -226,7 +304,7 @@ prefix(line)
*/
if (np != pfx && (np > pfx || abs(pfx-np) > 8))
oflush();
- if (h = ishead(cp))
+ if ((h = ishead(cp)))
oflush(), mark = lineno;
if (lineno - mark < 3 && lineno - mark > 0)
for (hp = &headnames[0]; *hp != (char *) 0; hp++)
@@ -252,6 +330,7 @@ prefix(line)
* attached at the end. Pass these words along to the output
* line packer.
*/
+void
split(line)
char line[];
{
@@ -266,7 +345,7 @@ split(line)
/*
* Collect a 'word,' allowing it to contain escaped white
- * space.
+ * space.
*/
while (*cp && *cp != ' ') {
if (*cp == '\\' && isspace(cp[1]))
@@ -277,7 +356,7 @@ split(line)
/*
* Guarantee a space at end of line. Two spaces after end of
- * sentence punctuation.
+ * sentence punctuation.
*/
if (*cp == '\0') {
*cp2++ = ' ';
@@ -288,7 +367,7 @@ split(line)
*cp2++ = *cp++;
*cp2 = '\0';
/*
- * LIZ@UOM 6/18/85 pack(word);
+ * LIZ@UOM 6/18/85 pack(word);
*/
pack(word, wordl);
}
@@ -309,6 +388,7 @@ char *outp; /* Pointer in above */
/*
* Initialize the output section.
*/
+void
setout()
{
outp = NOSTR;
@@ -334,6 +414,7 @@ setout()
* pack(word)
* char word[];
*/
+void
pack(word,wl)
char word[];
int wl;
@@ -348,14 +429,14 @@ pack(word,wl)
* length of the line before the word is added; t is now the length
* of the line after the word is added
* t = strlen(word);
- * if (t+s <= LENGTH)
+ * if (t+s <= LENGTH)
*/
s = outp - outbuf;
t = wl + s;
if ((t <= goal_length) ||
((t <= max_length) && (t - goal_length <= goal_length - s))) {
/*
- * In like flint!
+ * In like flint!
*/
for (cp = word; *cp; *outp++ = *cp++);
return;
@@ -372,6 +453,7 @@ pack(word,wl)
* its way. Set outp to NOSTR to indicate the absence of the current
* line prefix.
*/
+void
oflush()
{
if (outp == NOSTR)
@@ -385,6 +467,7 @@ oflush()
* Take the passed line buffer, insert leading tabs where possible, and
* output on standard output (finally).
*/
+void
tabulate(line)
char line[];
{
@@ -398,7 +481,7 @@ tabulate(line)
while (cp >= line && *cp == ' ')
cp--;
*++cp = '\0';
-
+
/*
* Count the leading blank space and tabulate.
*/
@@ -424,6 +507,7 @@ tabulate(line)
* Initialize the output line with the appropriate number of
* leading blanks.
*/
+void
leadin()
{
register int b;
@@ -446,10 +530,8 @@ savestr(str)
register char *top;
top = malloc(strlen(str) + 1);
- if (top == NOSTR) {
- fprintf(stderr, "fmt: Ran out of memory\n");
- exit(1);
- }
+ if (top == NOSTR)
+ errx(1, "ran out of memory");
strcpy(top, str);
return (top);
}
@@ -457,6 +539,7 @@ savestr(str)
/*
* Is s1 a prefix of s2??
*/
+int
ispref(s1, s2)
register char *s1, *s2;
{
diff --git a/usr.bin/fold/fold.c b/usr.bin/fold/fold.c
index 983a492..dd5b541 100644
--- a/usr.bin/fold/fold.c
+++ b/usr.bin/fold/fold.c
@@ -60,7 +60,7 @@ main(argc, argv)
char *p;
width = -1;
- while ((ch = getopt(argc, argv, "0123456789w:")) != EOF)
+ while ((ch = getopt(argc, argv, "0123456789w:")) != -1)
switch (ch) {
case 'w':
if ((width = atoi(optarg)) <= 0) {
diff --git a/usr.bin/from/from.1 b/usr.bin/from/from.1
index f935b89..780eba8 100644
--- a/usr.bin/from/from.1
+++ b/usr.bin/from/from.1
@@ -57,6 +57,9 @@ If the
option is used, the
.Ar user
argument should not be used.
+Read from standard input if file name
+.Ar -
+is given.
.It Fl s Ar sender
Only mail from addresses containing
the
@@ -69,6 +72,11 @@ is given, the
.Ar user Ns 's
mailbox, is examined instead of the invoker's own mailbox.
(Privileges are required.)
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev MAIL
+If set, the location of the invoker's mailbox. Otherwise, the default
+in /var/mail is used.
.Sh FILES
.Bl -tag -width /var/mail/* -compact
.It Pa /var/mail/*
diff --git a/usr.bin/from/from.c b/usr.bin/from/from.c
index 324bceb..8d20ad5 100644
--- a/usr.bin/from/from.c
+++ b/usr.bin/from/from.c
@@ -42,9 +42,12 @@ static char sccsid[] = "@(#)from.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/types.h>
+
#include <ctype.h>
#include <pwd.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <paths.h>
main(argc, argv)
@@ -63,7 +66,7 @@ main(argc, argv)
#endif
file = sender = NULL;
- while ((ch = getopt(argc, argv, "f:s:")) != EOF)
+ while ((ch = getopt(argc, argv, "f:s:?")) != -1)
switch((char)ch) {
case 'f':
file = optarg;
@@ -82,18 +85,28 @@ main(argc, argv)
argv += optind;
if (!file) {
- if (!(file = *argv)) {
- if (!(pwd = getpwuid(getuid()))) {
- fprintf(stderr,
+ if (*argv) {
+ (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, *argv);
+ file = buf;
+ } else {
+ if (!(file = getenv("MAIL"))) {
+ if (!(pwd = getpwuid(getuid()))) {
+ (void)fprintf(stderr,
"from: no password file entry for you.\n");
- exit(1);
+ exit(1);
+ }
+ file = pwd->pw_name;
+ (void)sprintf(buf,
+ "%s/%s", _PATH_MAILDIR, file);
+ file = buf;
}
- file = pwd->pw_name;
}
- (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, file);
- file = buf;
}
- if (!freopen(file, "r", stdin)) {
+
+ /* read from stdin */
+ if (strcmp(file, "-") == 0) {
+ }
+ else if (!freopen(file, "r", stdin)) {
fprintf(stderr, "from: can't read %s.\n", file);
exit(1);
}
diff --git a/usr.bin/fsplit/fsplit.c b/usr.bin/fsplit/fsplit.c
index 19cc965..a6135cc 100644
--- a/usr.bin/fsplit/fsplit.c
+++ b/usr.bin/fsplit/fsplit.c
@@ -63,7 +63,7 @@ static char sccsid[] = "@(#)fsplit.c 8.1 (Berkeley) 6/6/93";
* If -e option is used, then only those subprograms named in the -e
* option are split off; e.g.:
* fsplit -esub1 -e sub2 prog.f
- * isolates sub1 and sub2 in sub1.f and sub2.f. The space
+ * isolates sub1 and sub2 in sub1.f and sub2.f. The space
* after -e is optional.
*
* Modified Feb., 1983 by Jerry Berkman, Computing Services, U.C. Berkeley.
@@ -201,7 +201,7 @@ char *name;
while(*name) *fptr++ = *name++;
*--fptr = 0;
*--fptr = 0;
- for ( i=0 ; i<=extrknt; i++ )
+ for ( i=0 ; i<=extrknt; i++ )
if( strcmp(fname, extrnames[i]) == 0 ) {
extrfnd[i] = TRUE;
return(1);
@@ -269,14 +269,14 @@ lend()
return (0);
}
-/* check for keywords for subprograms
+/* check for keywords for subprograms
return 0 if comment card, 1 if found
name and put in arg string. invent name for unnamed
block datas and main programs. */
lname(s)
char *s;
{
-# define LINESIZE 80
+# define LINESIZE 80
register char *ptr, *p, *sptr;
char line[LINESIZE], *iptr = line;
diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1
index 1db0330..d3f7c2d 100644
--- a/usr.bin/fstat/fstat.1
+++ b/usr.bin/fstat/fstat.1
@@ -49,7 +49,7 @@
.Nm Fstat
identifies open files.
A file is considered open by a process if it was explicitly opened,
-is the working directory, root directory, active pure text, or kernel
+is the working directory, root directory, active executable text, or kernel
trace file for that process.
If no options are specified,
.Nm fstat
@@ -72,7 +72,7 @@ instead of the default
.Pa /dev/kmem .
.It Fl N
Extract the name list from the specified system instead of the default
-.Pa /vmunix .
+.Pa /kernel .
.It Fl n
Numerical format. Print the device number (maj,min) of the filesystem
the file resides in rather than the mount point name; for special
@@ -112,7 +112,7 @@ The file number in the per-process open file table or one of the following
special names:
.Pp
.Bd -ragged -offset indent -compact
-text - pure text inode
+text - executable text inode
wd - current working directory
root - root inode
tr - kernel trace file
@@ -173,7 +173,7 @@ Normally the name cannot be determined since there is no mapping
from an open file back to the directory entry that was used to open
that file. Also, since different directory entries may reference
the same file (via
-.Xr ln 2 ) ,
+.Xr ln 1 ) ,
the name printed may not be the actual
name that the process originally used to open that file.
.El
@@ -209,9 +209,9 @@ of time.
.Xr nfsstat 1 ,
.Xr ps 1 ,
.Xr systat 1 ,
-.Xr vmstat 1 ,
.Xr iostat 8 ,
-.Xr pstat 8
+.Xr pstat 8 ,
+.Xr vmstat 8
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c
index c2bf826..4ffab31 100644
--- a/usr.bin/fstat/fstat.c
+++ b/usr.bin/fstat/fstat.c
@@ -54,18 +54,18 @@ static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
#include <sys/unpcb.h>
#include <sys/sysctl.h>
#include <sys/filedesc.h>
+#include <sys/queue.h>
+#include <sys/pipe.h>
#define KERNEL
#include <sys/file.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#undef KERNEL
-#define NFS
#include <sys/mount.h>
#include <nfs/nfsproto.h>
#include <nfs/rpcv2.h>
#include <nfs/nfs.h>
#include <nfs/nfsnode.h>
-#undef NFS
#include <net/route.h>
#include <netinet/in.h>
@@ -75,6 +75,7 @@ static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
@@ -83,6 +84,7 @@ static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#define TEXT -1
#define CDIR -2
@@ -134,23 +136,30 @@ int maxfiles;
}
/*
- * a kvm_read that returns true if everything is read
+ * a kvm_read that returns true if everything is read
*/
#define KVM_READ(kaddr, paddr, len) \
(kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len))
kvm_t *kd;
-int ufs_filestat(), nfs_filestat();
-void dofiles(), getinetproto(), socktrans();
-void usage(), vtrans();
+void dofiles __P((struct kinfo_proc *kp));
+void vtrans __P((struct vnode *vp, int i, int flag));
+int ufs_filestat __P((struct vnode *vp, struct filestat *fsp));
+int nfs_filestat __P((struct vnode *vp, struct filestat *fsp));
+char *getmnton __P((struct mount *m));
+void pipetrans __P((struct pipe *pi, int i, int flag));
+void socktrans __P((struct socket *sock, int i));
+void getinetproto __P((int number));
+int getfname __P((char *filename));
+void usage __P((void));
+
+int
main(argc, argv)
int argc;
char **argv;
{
- extern char *optarg;
- extern int optind;
register struct passwd *passwd;
struct kinfo_proc *p, *plast;
int arg, ch, what;
@@ -161,7 +170,7 @@ main(argc, argv)
arg = 0;
what = KERN_PROC_ALL;
nlistf = memf = NULL;
- while ((ch = getopt(argc, argv, "fnp:u:vNM")) != EOF)
+ while ((ch = getopt(argc, argv, "fnp:u:vNM")) != -1)
switch((char)ch) {
case 'f':
fsflg = 1;
@@ -216,7 +225,7 @@ main(argc, argv)
ALLOC_OFILES(256); /* reserve space for file pointers */
- if (fsflg && !checkfile) {
+ if (fsflg && !checkfile) {
/* -f with no files means use wd */
if (getfname(".") == 0)
exit(1);
@@ -299,8 +308,6 @@ dofiles(kp)
struct proc *p = &kp->kp_proc;
struct eproc *ep = &kp->kp_eproc;
- extern char *user_from_uid();
-
Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
Pid = p->p_pid;
Comm = p->p_comm;
@@ -327,6 +334,11 @@ dofiles(kp)
if (p->p_tracep)
vtrans(p->p_tracep, TRACE, FREAD|FWRITE);
/*
+ * text vnode, if one
+ */
+ if (p->p_textvp)
+ vtrans(p->p_textvp, TEXT, FREAD);
+ /*
* open files
*/
#define FPSIZE (sizeof (struct file *))
@@ -355,8 +367,15 @@ dofiles(kp)
if (checkfile == 0)
socktrans((struct socket *)file.f_data, i);
}
+#ifdef DTYPE_PIPE
+ else if (file.f_type == DTYPE_PIPE) {
+ if (checkfile == 0)
+ pipetrans((struct pipe *)file.f_data, i,
+ file.f_flag);
+ }
+#endif
else {
- dprintf(stderr,
+ dprintf(stderr,
"unknown file type %d for file %d of pid %d\n",
file.f_type, i, Pid);
}
@@ -440,7 +459,7 @@ vtrans(vp, i, flag)
case VCHR: {
char *name;
- if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
+ if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
S_IFCHR : S_IFBLK)) == NULL))
printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
else
@@ -560,6 +579,38 @@ getmnton(m)
}
void
+pipetrans(pi, i, flag)
+ struct pipe *pi;
+ int i;
+ int flag;
+{
+ struct pipe pip;
+ char rw[3];
+
+ PREFIX(i);
+
+ /* fill in socket */
+ if (!KVM_READ(pi, &pip, sizeof(struct pipe))) {
+ dprintf(stderr, "can't read pipe at %x\n", pi);
+ goto bad;
+ }
+
+ printf("* pipe %8x <-> %8x", (int)pi, (int)pip.pipe_peer);
+ printf(" %6d", (int)pip.pipe_buffer.cnt);
+ rw[0] = '\0';
+ if (flag & FREAD)
+ strcat(rw, "r");
+ if (flag & FWRITE)
+ strcat(rw, "w");
+ printf(" %2s", rw);
+ putchar('\n');
+ return;
+
+bad:
+ printf("* error\n");
+}
+
+void
socktrans(sock, i)
struct socket *sock;
int i;
@@ -615,7 +666,7 @@ socktrans(sock, i)
else
printf("* %s %s", dname, stypename[so.so_type]);
- /*
+ /*
* protocol specific formatting
*
* Try to find interesting things to print. For tcp, the interesting
@@ -634,7 +685,7 @@ socktrans(sock, i)
if (kvm_read(kd, (u_long)so.so_pcb,
(char *)&inpcb, sizeof(struct inpcb))
!= sizeof(struct inpcb)) {
- dprintf(stderr,
+ dprintf(stderr,
"can't read inpcb at %x\n",
so.so_pcb);
goto bad;
@@ -716,6 +767,7 @@ getinetproto(number)
printf(" %s", cp);
}
+int
getfname(filename)
char *filename;
{
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile
index fbb5a91..4bb9dc0 100644
--- a/usr.bin/ftp/Makefile
+++ b/usr.bin/ftp/Makefile
@@ -1,6 +1,15 @@
-# @(#)Makefile 8.2 (Berkeley) 4/3/94
+# $Id$
+# $NetBSD: Makefile,v 1.11 1997/03/24 21:59:36 christos Exp $
+# from: @(#)Makefile 8.2 (Berkeley) 4/3/94
PROG= ftp
-SRCS= cmds.c cmdtab.c ftp.c main.c ruserpass.c domacro.c
+SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c ruserpass.c \
+ util.c
+
+LDADD+= -ledit -ltermcap
+DPADD+= ${LIBEDIT} ${LIBTERMCAP}
+
+LINKS= ${BINDIR}/ftp ${BINDIR}/pftp
+MLINKS= ftp.1 pftp.1
.include <bsd.prog.mk>
diff --git a/usr.bin/ftp/cmds.c b/usr.bin/ftp/cmds.c
index f64c73e..2232553 100644
--- a/usr.bin/ftp/cmds.c
+++ b/usr.bin/ftp/cmds.c
@@ -1,3 +1,6 @@
+/* $Id: cmds.c,v 1.8 1997/06/27 09:30:01 ache Exp $ */
+/* $NetBSD: cmds.c,v 1.24 1997/05/17 19:44:36 pk Exp $ */
+
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -32,28 +35,29 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
+#else
+static char rcsid[] = "$Id: cmds.c,v 1.8 1997/06/27 09:30:01 ache Exp $";
+#endif
#endif /* not lint */
/*
* FTP User Program -- Command Routines.
*/
-#include <sys/param.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/socket.h>
-#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#include <arpa/ftp.h>
#include <ctype.h>
#include <err.h>
#include <glob.h>
#include <netdb.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include <unistd.h>
#include "ftp_var.h"
@@ -63,147 +67,6 @@ jmp_buf jabort;
char *mname;
char *home = "/";
-/*
- * `Another' gets another argument, and stores the new argc and argv.
- * It reverts to the top level (via main.c's intr()) on EOF/error.
- *
- * Returns false if no new arguments have been added.
- */
-int
-another(pargc, pargv, prompt)
- int *pargc;
- char ***pargv;
- char *prompt;
-{
- int len = strlen(line), ret;
-
- if (len >= sizeof(line) - 3) {
- printf("sorry, arguments too long\n");
- intr();
- }
- printf("(%s) ", prompt);
- line[len++] = ' ';
- if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
- intr();
- len += strlen(&line[len]);
- if (len > 0 && line[len - 1] == '\n')
- line[len - 1] = '\0';
- makeargv();
- ret = margc > *pargc;
- *pargc = margc;
- *pargv = margv;
- return (ret);
-}
-
-/*
- * Connect to peer server and
- * auto-login, if possible.
- */
-void
-setpeer(argc, argv)
- int argc;
- char *argv[];
-{
- char *host;
- short port;
-
- if (connected) {
- printf("Already connected to %s, use close first.\n",
- hostname);
- code = -1;
- return;
- }
- if (argc < 2)
- (void) another(&argc, &argv, "to");
- if (argc < 2 || argc > 3) {
- printf("usage: %s host-name [port]\n", argv[0]);
- code = -1;
- return;
- }
- port = sp->s_port;
- if (argc > 2) {
- port = atoi(argv[2]);
- if (port <= 0) {
- printf("%s: bad port number-- %s\n", argv[1], argv[2]);
- printf ("usage: %s host-name [port]\n", argv[0]);
- code = -1;
- return;
- }
- port = htons(port);
- }
- host = hookup(argv[1], port);
- if (host) {
- int overbose;
-
- connected = 1;
- /*
- * Set up defaults for FTP.
- */
- (void) strcpy(typename, "ascii"), type = TYPE_A;
- curtype = TYPE_A;
- (void) strcpy(formname, "non-print"), form = FORM_N;
- (void) strcpy(modename, "stream"), mode = MODE_S;
- (void) strcpy(structname, "file"), stru = STRU_F;
- (void) strcpy(bytename, "8"), bytesize = 8;
- if (autologin)
- (void) login(argv[1]);
-
-#if defined(unix) && NBBY == 8
-/*
- * this ifdef is to keep someone form "porting" this to an incompatible
- * system and not checking this out. This way they have to think about it.
- */
- overbose = verbose;
- if (debug == 0)
- verbose = -1;
- if (command("SYST") == COMPLETE && overbose) {
- char *cp, c;
- cp = strchr(reply_string+4, ' ');
- if (cp == NULL)
- cp = strchr(reply_string+4, '\r');
- if (cp) {
- if (cp[-1] == '.')
- cp--;
- c = *cp;
- *cp = '\0';
- }
-
- printf("Remote system type is %s.\n",
- reply_string+4);
- if (cp)
- *cp = c;
- }
- if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
- if (proxy)
- unix_proxy = 1;
- else
- unix_server = 1;
- /*
- * Set type to 0 (not specified by user),
- * meaning binary by default, but don't bother
- * telling server. We can use binary
- * for text files unless changed by the user.
- */
- type = 0;
- (void) strcpy(typename, "binary");
- if (overbose)
- printf("Using %s mode to transfer files.\n",
- typename);
- } else {
- if (proxy)
- unix_proxy = 0;
- else
- unix_server = 0;
- if (overbose &&
- !strncmp(reply_string, "215 TOPS20", 10))
- printf(
-"Remember to set tenex mode when transfering binary files from this machine.\n");
- }
- verbose = overbose;
-#endif /* unix */
- }
-}
-
struct types {
char *t_name;
char *t_mode;
@@ -238,7 +101,7 @@ settype(argc, argv)
printf("%s%s", sep, p->t_name);
sep = " | ";
}
- printf(" ]\n");
+ puts(" ]");
code = -1;
return;
}
@@ -251,16 +114,16 @@ settype(argc, argv)
if (strcmp(argv[1], p->t_name) == 0)
break;
if (p->t_name == 0) {
- printf("%s: unknown mode\n", argv[1]);
+ printf("%s: unknown mode.\n", argv[1]);
code = -1;
return;
}
if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
- comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
+ comret = command("TYPE %s %s", p->t_mode, p->t_arg);
else
comret = command("TYPE %s", p->t_mode);
if (comret == COMPLETE) {
- (void) strcpy(typename, p->t_name);
+ (void)strcpy(typename, p->t_name);
curtype = type = p->t_type;
}
}
@@ -287,7 +150,7 @@ changetype(newtype, show)
if (newtype == p->t_type)
break;
if (p->t_name == 0) {
- printf("ftp: internal error: unknown type %d\n", newtype);
+ warnx("internal error: unknown type %d.", newtype);
return;
}
if (newtype == TYPE_L && bytename[0] != '\0')
@@ -312,7 +175,7 @@ char *stype[] = {
void
setbinary(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
stype[1] = "binary";
@@ -408,9 +271,9 @@ put(argc, argv)
}
if (argc < 2 && !another(&argc, &argv, "local-file"))
goto usage;
- if (argc < 3 && !another(&argc, &argv, "remote-file")) {
+ if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
usage:
- printf("usage: %s local-file remote-file\n", argv[0]);
+ printf("usage: %s local-file [ remote-file ]\n", argv[0]);
code = -1;
return;
}
@@ -444,7 +307,7 @@ usage:
void
mput(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
int i;
sig_t oldintr;
@@ -459,28 +322,27 @@ mput(argc, argv)
mname = argv[0];
mflag = 1;
oldintr = signal(SIGINT, mabort);
- (void) setjmp(jabort);
+ (void)setjmp(jabort);
if (proxy) {
char *cp, *tp2, tmpbuf[MAXPATHLEN];
- while ((cp = remglob(argv,0)) != NULL) {
- if (*cp == 0) {
+ while ((cp = remglob(argv, 0, NULL)) != NULL) {
+ if (*cp == '\0') {
mflag = 0;
continue;
}
if (mflag && confirm(argv[0], cp)) {
tp = cp;
if (mcase) {
- while (*tp && !islower(*tp)) {
+ while (*tp && !islower((unsigned char)*tp)) {
tp++;
}
if (!*tp) {
tp = cp;
tp2 = tmpbuf;
- while ((*tp2 = *tp) != NULL) {
- if (isupper(*tp2)) {
- *tp2 = 'a' + *tp2 - 'A';
- }
+ while ((*tp2 = *tp) != '\0') {
+ if (isupper((unsigned char)*tp2))
+ *tp2 = tolower((unsigned char)*tp2);
tp++;
tp2++;
}
@@ -498,19 +360,19 @@ mput(argc, argv)
if (!mflag && fromatty) {
ointer = interactive;
interactive = 1;
- if (confirm("Continue with","mput")) {
+ if (confirm("Continue with", "mput")) {
mflag++;
}
interactive = ointer;
}
}
}
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
mflag = 0;
return;
}
for (i = 1; i < argc; i++) {
- char **cpp, **gargs;
+ char **cpp;
glob_t gl;
int flags;
@@ -523,7 +385,7 @@ mput(argc, argv)
if (!mflag && fromatty) {
ointer = interactive;
interactive = 1;
- if (confirm("Continue with","mput")) {
+ if (confirm("Continue with", "mput")) {
mflag++;
}
interactive = ointer;
@@ -548,7 +410,7 @@ mput(argc, argv)
if (!mflag && fromatty) {
ointer = interactive;
interactive = 1;
- if (confirm("Continue with","mput")) {
+ if (confirm("Continue with", "mput")) {
mflag++;
}
interactive = ointer;
@@ -557,7 +419,7 @@ mput(argc, argv)
}
globfree(&gl);
}
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
mflag = 0;
}
@@ -567,7 +429,7 @@ reget(argc, argv)
char *argv[];
{
- (void) getit(argc, argv, 1, "r+w");
+ (void)getit(argc, argv, 1, "r+w");
}
void
@@ -576,7 +438,7 @@ get(argc, argv)
char *argv[];
{
- (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
+ (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
}
/*
@@ -586,8 +448,8 @@ int
getit(argc, argv, restartit, mode)
int argc;
char *argv[];
- char *mode;
int restartit;
+ const char *mode;
{
int loc = 0;
char *oldargv1, *oldargv2;
@@ -599,7 +461,7 @@ getit(argc, argv, restartit, mode)
}
if (argc < 2 && !another(&argc, &argv, "remote-file"))
goto usage;
- if (argc < 3 && !another(&argc, &argv, "local-file")) {
+ if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
usage:
printf("usage: %s remote-file [ local-file ]\n", argv[0]);
code = -1;
@@ -614,16 +476,15 @@ usage:
if (loc && mcase) {
char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
- while (*tp && !islower(*tp)) {
+ while (*tp && !islower((unsigned char)*tp)) {
tp++;
}
if (!*tp) {
tp = argv[2];
tp2 = tmpbuf;
- while ((*tp2 = *tp) != NULL) {
- if (isupper(*tp2)) {
- *tp2 = 'a' + *tp2 - 'A';
- }
+ while ((*tp2 = *tp) != '\0') {
+ if (isupper((unsigned char)*tp2))
+ *tp2 = tolower((unsigned char)*tp2);
tp++;
tp2++;
}
@@ -647,38 +508,13 @@ usage:
restart_point = stbuf.st_size;
} else {
if (ret == 0) {
- int overbose;
-
- overbose = verbose;
- if (debug == 0)
- verbose = -1;
- if (command("MDTM %s", argv[1]) == COMPLETE) {
- int yy, mo, day, hour, min, sec;
- struct tm *tm;
- verbose = overbose;
- sscanf(reply_string,
- "%*s %04d%02d%02d%02d%02d%02d",
- &yy, &mo, &day, &hour, &min, &sec);
- tm = gmtime(&stbuf.st_mtime);
- tm->tm_mon++;
- if (tm->tm_year > yy%100)
- return (1);
- if ((tm->tm_year == yy%100 &&
- tm->tm_mon > mo) ||
- (tm->tm_mon == mo &&
- tm->tm_mday > day) ||
- (tm->tm_mday == day &&
- tm->tm_hour > hour) ||
- (tm->tm_hour == hour &&
- tm->tm_min > min) ||
- (tm->tm_min == min &&
- tm->tm_sec > sec))
- return (1);
- } else {
- printf("%s\n", reply_string);
- verbose = overbose;
+ time_t mtime;
+
+ mtime = remotemodtime(argv[1], 0);
+ if (mtime == -1)
return (0);
- }
+ if (stbuf.st_mtime >= mtime)
+ return (1);
}
}
}
@@ -694,21 +530,26 @@ void
mabort(signo)
int signo;
{
- int ointer;
+ int ointer, oconf;
- printf("\n");
- (void) fflush(stdout);
+ alarmtimer(0);
+ putchar('\n');
+ (void)fflush(stdout);
if (mflag && fromatty) {
ointer = interactive;
+ oconf = confirmrest;
interactive = 1;
+ confirmrest = 0;
if (confirm("Continue with", mname)) {
interactive = ointer;
- longjmp(jabort,0);
+ confirmrest = oconf;
+ longjmp(jabort, 0);
}
interactive = ointer;
+ confirmrest = oconf;
}
mflag = 0;
- longjmp(jabort,0);
+ longjmp(jabort, 0);
}
/*
@@ -717,7 +558,7 @@ mabort(signo)
void
mget(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
sig_t oldintr;
int ch, ointer;
@@ -731,8 +572,8 @@ mget(argc, argv)
mname = argv[0];
mflag = 1;
oldintr = signal(SIGINT, mabort);
- (void) setjmp(jabort);
- while ((cp = remglob(argv,proxy)) != NULL) {
+ (void)setjmp(jabort);
+ while ((cp = remglob(argv, proxy, NULL)) != NULL) {
if (*cp == '\0') {
mflag = 0;
continue;
@@ -740,8 +581,9 @@ mget(argc, argv)
if (mflag && confirm(argv[0], cp)) {
tp = cp;
if (mcase) {
- for (tp2 = tmpbuf; ch = *tp++;)
+ for (tp2 = tmpbuf; (ch = (unsigned char)*tp++) != 0; )
*tp2++ = isupper(ch) ? tolower(ch) : ch;
+ *tp2 = '\0';
tp = tmpbuf;
}
if (ntflag) {
@@ -755,79 +597,18 @@ mget(argc, argv)
if (!mflag && fromatty) {
ointer = interactive;
interactive = 1;
- if (confirm("Continue with","mget")) {
+ if (confirm("Continue with", "mget")) {
mflag++;
}
interactive = ointer;
}
}
}
- (void) signal(SIGINT,oldintr);
+ (void)signal(SIGINT, oldintr);
mflag = 0;
}
char *
-remglob(argv,doswitch)
- char *argv[];
- int doswitch;
-{
- char temp[16];
- static char buf[MAXPATHLEN];
- static FILE *ftemp = NULL;
- static char **args;
- int oldverbose, oldhash;
- char *cp, *mode;
-
- if (!mflag) {
- if (!doglob) {
- args = NULL;
- }
- else {
- if (ftemp) {
- (void) fclose(ftemp);
- ftemp = NULL;
- }
- }
- return (NULL);
- }
- if (!doglob) {
- if (args == NULL)
- args = argv;
- if ((cp = *++args) == NULL)
- args = NULL;
- return (cp);
- }
- if (ftemp == NULL) {
- (void) strcpy(temp, _PATH_TMP);
- (void) mktemp(temp);
- oldverbose = verbose, verbose = 0;
- oldhash = hash, hash = 0;
- if (doswitch) {
- pswitch(!proxy);
- }
- for (mode = "w"; *++argv != NULL; mode = "a")
- recvrequest ("NLST", temp, *argv, mode, 0);
- if (doswitch) {
- pswitch(!proxy);
- }
- verbose = oldverbose; hash = oldhash;
- ftemp = fopen(temp, "r");
- (void) unlink(temp);
- if (ftemp == NULL) {
- printf("can't find list of remote files, oops\n");
- return (NULL);
- }
- }
- if (fgets(buf, sizeof (buf), ftemp) == NULL) {
- (void) fclose(ftemp), ftemp = NULL;
- return (NULL);
- }
- if ((cp = strchr(buf, '\n')) != NULL)
- *cp = '\0';
- return (buf);
-}
-
-char *
onoff(bool)
int bool;
{
@@ -847,51 +628,84 @@ status(argc, argv)
int i;
if (connected)
- printf("Connected to %s.\n", hostname);
+ printf("Connected %sto %s.\n",
+ connected == -1 ? "and logged in" : "", hostname);
else
- printf("Not connected.\n");
+ puts("Not connected.");
if (!proxy) {
pswitch(1);
if (connected) {
- printf("Connected for proxy commands to %s.\n", hostname);
+ printf("Connected for proxy commands to %s.\n",
+ hostname);
}
else {
- printf("No proxy connection.\n");
+ puts("No proxy connection.");
}
pswitch(0);
}
- printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
+ printf("Passive mode: %s.\n", onoff(passivemode));
+ printf("Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
modename, typename, formname, structname);
- printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
+ printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
onoff(verbose), onoff(bell), onoff(interactive),
onoff(doglob));
- printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
+ printf("Store unique: %s; Receive unique: %s.\n", onoff(sunique),
onoff(runique));
- printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
+ printf("Preserve modification times: %s.\n", onoff(preserve));
+ printf("Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
if (ntflag) {
- printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
+ printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
}
else {
- printf("Ntrans: off\n");
+ puts("Ntrans: off.");
}
if (mapflag) {
printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
}
else {
- printf("Nmap: off\n");
- }
- printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
- onoff(hash), onoff(sendport));
+ puts("Nmap: off.");
+ }
+ printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
+ onoff(hash), mark, onoff(progress));
+ printf("Use of PORT cmds: %s.\n", onoff(sendport));
+#ifndef SMALL
+ printf("Command line editing: %s.\n", onoff(editing));
+#endif /* !SMALL */
if (macnum > 0) {
- printf("Macros:\n");
+ puts("Macros:");
for (i=0; i<macnum; i++) {
- printf("\t%s\n",macros[i].mac_name);
+ printf("\t%s\n", macros[i].mac_name);
}
}
code = 0;
}
/*
+ * Toggle a variable
+ */
+int
+togglevar(argc, argv, var, mesg)
+ int argc;
+ char *argv[];
+ int *var;
+ const char *mesg;
+{
+ if (argc < 2) {
+ *var = !*var;
+ } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
+ *var = 1;
+ } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
+ *var = 0;
+ } else {
+ printf("usage: %s [ on | off ]\n", argv[0]);
+ return (-1);
+ }
+ if (mesg)
+ printf("%s %s.\n", mesg, onoff(*var));
+ return (*var);
+}
+
+/*
* Set beep on cmd completed mode.
*/
/*VARARGS*/
@@ -901,10 +715,24 @@ setbell(argc, argv)
char *argv[];
{
- bell = !bell;
- printf("Bell mode %s.\n", onoff(bell));
- code = bell;
+ code = togglevar(argc, argv, &bell, "Bell mode");
+}
+
+#ifndef SMALL
+/*
+ * Set command line editing
+ */
+/*VARARGS*/
+void
+setedit(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ code = togglevar(argc, argv, &editing, "Editing mode");
+ controlediting();
}
+#endif /* !SMALL */
/*
* Turn on packet tracing.
@@ -916,13 +744,11 @@ settrace(argc, argv)
char *argv[];
{
- trace = !trace;
- printf("Packet tracing %s.\n", onoff(trace));
- code = trace;
+ code = togglevar(argc, argv, &trace, "Packet tracing");
}
/*
- * Toggle hash mark printing during transfers.
+ * Toggle hash mark printing during transfers, or set hash mark bytecount.
*/
/*VARARGS*/
void
@@ -930,13 +756,31 @@ sethash(argc, argv)
int argc;
char *argv[];
{
-
- hash = !hash;
+ if (argc == 1)
+ hash = !hash;
+ else if (argc != 2) {
+ printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
+ code = -1;
+ return;
+ } else if (strcasecmp(argv[1], "on") == 0)
+ hash = 1;
+ else if (strcasecmp(argv[1], "off") == 0)
+ hash = 0;
+ else {
+ int nmark = atol(argv[1]);
+ if (nmark < 1) {
+ printf("%s: bad bytecount value.\n", argv[1]);
+ code = -1;
+ return;
+ }
+ mark = nmark;
+ hash = 1;
+ }
printf("Hash mark printing %s", onoff(hash));
- code = hash;
if (hash)
- printf(" (%d bytes/hash mark)", 1024);
- printf(".\n");
+ printf(" (%d bytes/hash mark)", mark);
+ puts(".");
+ code = hash;
}
/*
@@ -949,9 +793,7 @@ setverbose(argc, argv)
char *argv[];
{
- verbose = !verbose;
- printf("Verbose mode %s.\n", onoff(verbose));
- code = verbose;
+ code = togglevar(argc, argv, &verbose, "Verbose mode");
}
/*
@@ -964,9 +806,20 @@ setport(argc, argv)
char *argv[];
{
- sendport = !sendport;
- printf("Use of PORT cmds %s.\n", onoff(sendport));
- code = sendport;
+ code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
+}
+
+/*
+ * Toggle transfer progress bar.
+ */
+/*VARARGS*/
+void
+setprogress(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ code = togglevar(argc, argv, &progress, "Progress bar");
}
/*
@@ -980,9 +833,7 @@ setprompt(argc, argv)
char *argv[];
{
- interactive = !interactive;
- printf("Interactive mode %s.\n", onoff(interactive));
- code = interactive;
+ code = togglevar(argc, argv, &interactive, "Interactive mode");
}
/*
@@ -995,10 +846,21 @@ setglob(argc, argv)
int argc;
char *argv[];
{
-
- doglob = !doglob;
- printf("Globbing %s.\n", onoff(doglob));
- code = doglob;
+
+ code = togglevar(argc, argv, &doglob, "Globbing");
+}
+
+/*
+ * Toggle preserving modification times on retreived files.
+ */
+/*VARARGS*/
+void
+setpreserve(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ code = togglevar(argc, argv, &preserve, "Preserve modification times");
}
/*
@@ -1013,16 +875,26 @@ setdebug(argc, argv)
{
int val;
- if (argc > 1) {
- val = atoi(argv[1]);
- if (val < 0) {
- printf("%s: bad debugging value.\n", argv[1]);
- code = -1;
- return;
+ if (argc > 2) {
+ printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
+ code = -1;
+ return;
+ } else if (argc == 2) {
+ if (strcasecmp(argv[1], "on") == 0)
+ debug = 1;
+ else if (strcasecmp(argv[1], "off") == 0)
+ debug = 0;
+ else {
+ val = atoi(argv[1]);
+ if (val < 0) {
+ printf("%s: bad debugging value.\n", argv[1]);
+ code = -1;
+ return;
+ }
+ debug = val;
}
} else
- val = !debug;
- debug = val;
+ debug = !debug;
if (debug)
options |= SO_DEBUG;
else
@@ -1040,17 +912,22 @@ cd(argc, argv)
int argc;
char *argv[];
{
+ int r;
- if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
+ if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
+ argc > 2) {
printf("usage: %s remote-directory\n", argv[0]);
code = -1;
return;
}
- if (command("CWD %s", argv[1]) == ERROR && code == 500) {
+ r = command("CWD %s", argv[1]);
+ if (r == ERROR && code == 500) {
if (verbose)
- printf("CWD command not recognized, trying XCWD\n");
- (void) command("XCWD %s", argv[1]);
+ puts("CWD command not recognized, trying XCWD.");
+ r = command("XCWD %s", argv[1]);
}
+ if (r == COMPLETE)
+ dirchange = 1;
}
/*
@@ -1080,10 +957,10 @@ lcd(argc, argv)
code = -1;
return;
}
- if (getwd(buf) != NULL)
+ if (getcwd(buf, sizeof(buf)) != NULL)
printf("Local directory now %s\n", buf);
else
- warnx("getwd: %s", buf);
+ warn("getcwd: %s", argv[1]);
code = 0;
}
@@ -1096,12 +973,12 @@ delete(argc, argv)
char *argv[];
{
- if (argc < 2 && !another(&argc, &argv, "remote-file")) {
+ if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
printf("usage: %s remote-file\n", argv[0]);
code = -1;
return;
}
- (void) command("DELE %s", argv[1]);
+ (void)command("DELE %s", argv[1]);
}
/*
@@ -1110,7 +987,7 @@ delete(argc, argv)
void
mdelete(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
sig_t oldintr;
int ointer;
@@ -1124,14 +1001,14 @@ mdelete(argc, argv)
mname = argv[0];
mflag = 1;
oldintr = signal(SIGINT, mabort);
- (void) setjmp(jabort);
- while ((cp = remglob(argv,0)) != NULL) {
+ (void)setjmp(jabort);
+ while ((cp = remglob(argv, 0, NULL)) != NULL) {
if (*cp == '\0') {
mflag = 0;
continue;
}
if (mflag && confirm(argv[0], cp)) {
- (void) command("DELE %s", cp);
+ (void)command("DELE %s", cp);
if (!mflag && fromatty) {
ointer = interactive;
interactive = 1;
@@ -1142,7 +1019,7 @@ mdelete(argc, argv)
}
}
}
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
mflag = 0;
}
@@ -1157,14 +1034,14 @@ renamefile(argc, argv)
if (argc < 2 && !another(&argc, &argv, "from-name"))
goto usage;
- if (argc < 3 && !another(&argc, &argv, "to-name")) {
+ if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
usage:
- printf("%s from-name to-name\n", argv[0]);
+ printf("usage: %s from-name to-name\n", argv[0]);
code = -1;
return;
}
if (command("RNFR %s", argv[1]) == CONTINUE)
- (void) command("RNTO %s", argv[2]);
+ (void)command("RNTO %s", argv[2]);
}
/*
@@ -1176,7 +1053,7 @@ ls(argc, argv)
int argc;
char *argv[];
{
- char *cmd;
+ const char *cmd;
if (argc < 2)
argc++, argv[1] = NULL;
@@ -1187,17 +1064,21 @@ ls(argc, argv)
code = -1;
return;
}
- cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
+ cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
code = -1;
return;
}
if (strcmp(argv[2], "-") && *argv[2] != '|')
- if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
+ if (!globulize(&argv[2]) || !confirm("output to local-file:",
+ argv[2])) {
code = -1;
return;
}
recvrequest(cmd, argv[2], argv[1], "w", 0);
+
+ /* flush results in case commands are coming from a pipe */
+ fflush(stdout);
}
/*
@@ -1207,11 +1088,12 @@ ls(argc, argv)
void
mls(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
sig_t oldintr;
int ointer, i;
- char *cmd, mode[1], *dest;
+ const char *cmd;
+ char mode[1], *dest;
if (argc < 2 && !another(&argc, &argv, "remote-files"))
goto usage;
@@ -1229,11 +1111,11 @@ usage:
code = -1;
return;
}
- cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
+ cmd = strcmp(argv[0], "mls") == 0 ? "NLST" : "LIST";
mname = argv[0];
mflag = 1;
oldintr = signal(SIGINT, mabort);
- (void) setjmp(jabort);
+ (void)setjmp(jabort);
for (i = 1; mflag && i < argc-1; ++i) {
*mode = (i == 1) ? 'w' : 'a';
recvrequest(cmd, dest, argv[i], mode, 0);
@@ -1246,7 +1128,7 @@ usage:
interactive = ointer;
}
}
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
mflag = 0;
}
@@ -1257,39 +1139,40 @@ usage:
void
shell(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
pid_t pid;
sig_t old1, old2;
- char shellnam[40], *shell, *namep;
+ char shellnam[MAXPATHLEN], *shell, *namep;
union wait status;
old1 = signal (SIGINT, SIG_IGN);
old2 = signal (SIGQUIT, SIG_IGN);
if ((pid = fork()) == 0) {
for (pid = 3; pid < 20; pid++)
- (void) close(pid);
- (void) signal(SIGINT, SIG_DFL);
- (void) signal(SIGQUIT, SIG_DFL);
+ (void)close(pid);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
shell = getenv("SHELL");
if (shell == NULL)
shell = _PATH_BSHELL;
- namep = strrchr(shell,'/');
+ namep = strrchr(shell, '/');
if (namep == NULL)
namep = shell;
- (void) strcpy(shellnam,"-");
- (void) strcat(shellnam, ++namep);
+ shellnam[0] = '-';
+ (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
+ shellnam[sizeof(shellnam) - 1] = '\0';
if (strcmp(namep, "sh") != 0)
shellnam[0] = '+';
if (debug) {
- printf ("%s\n", shell);
- (void) fflush (stdout);
+ puts(shell);
+ (void)fflush(stdout);
}
if (argc > 1) {
- execl(shell,shellnam,"-c",altarg,(char *)0);
+ execl(shell, shellnam, "-c", altarg, (char *)0);
}
else {
- execl(shell,shellnam,(char *)0);
+ execl(shell, shellnam, (char *)0);
}
warn("%s", shell);
code = -1;
@@ -1298,10 +1181,10 @@ shell(argc, argv)
if (pid > 0)
while (wait((int *)&status) != pid)
;
- (void) signal(SIGINT, old1);
- (void) signal(SIGQUIT, old2);
+ (void)signal(SIGINT, old1);
+ (void)signal(SIGQUIT, old2);
if (pid == -1) {
- warn("%s", "Try again later");
+ warn("Try again later");
code = -1;
}
else {
@@ -1315,13 +1198,13 @@ shell(argc, argv)
void
user(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
char acct[80];
int n, aflag = 0;
if (argc < 2)
- (void) another(&argc, &argv, "username");
+ (void)another(&argc, &argv, "username");
if (argc < 2 || argc > 4) {
printf("usage: %s username [password] [account]\n", argv[0]);
code = -1;
@@ -1335,8 +1218,9 @@ user(argc, argv)
}
if (n == CONTINUE) {
if (argc < 4) {
- printf("Account: "); (void) fflush(stdout);
- (void) fgets(acct, sizeof(acct) - 1, stdin);
+ (void)fputs("Account: ", stdout);
+ (void)fflush(stdout);
+ (void)fgets(acct, sizeof(acct) - 1, stdin);
acct[strlen(acct) - 1] = '\0';
argv[3] = acct; argc++;
}
@@ -1344,16 +1228,17 @@ user(argc, argv)
aflag++;
}
if (n != COMPLETE) {
- fprintf(stdout, "Login failed.\n");
+ puts("Login failed.");
return;
}
if (!aflag && argc == 4) {
- (void) command("ACCT %s", argv[3]);
+ (void)command("ACCT %s", argv[3]);
}
+ connected = -1;
}
/*
- * Print working directory.
+ * Print working directory on remote machine.
*/
/*VARARGS*/
void
@@ -1368,13 +1253,30 @@ pwd(argc, argv)
*/
verbose = 1;
if (command("PWD") == ERROR && code == 500) {
- printf("PWD command not recognized, trying XPWD\n");
- (void) command("XPWD");
+ puts("PWD command not recognized, trying XPWD.");
+ (void)command("XPWD");
}
verbose = oldverbose;
}
/*
+ * Print working directory on local machine.
+ */
+void
+lpwd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char buf[MAXPATHLEN];
+
+ if (getcwd(buf, sizeof(buf)) != NULL)
+ printf("Local directory %s\n", buf);
+ else
+ warn("getcwd");
+ code = 0;
+}
+
+/*
* Make a directory.
*/
void
@@ -1383,15 +1285,16 @@ makedir(argc, argv)
char *argv[];
{
- if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+ if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
+ argc > 2) {
printf("usage: %s directory-name\n", argv[0]);
code = -1;
return;
}
if (command("MKD %s", argv[1]) == ERROR && code == 500) {
if (verbose)
- printf("MKD command not recognized, trying XMKD\n");
- (void) command("XMKD %s", argv[1]);
+ puts("MKD command not recognized, trying XMKD.");
+ (void)command("XMKD %s", argv[1]);
}
}
@@ -1404,15 +1307,16 @@ removedir(argc, argv)
char *argv[];
{
- if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+ if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
+ argc > 2) {
printf("usage: %s directory-name\n", argv[0]);
code = -1;
return;
}
if (command("RMD %s", argv[1]) == ERROR && code == 500) {
if (verbose)
- printf("RMD command not recognized, trying XRMD\n");
- (void) command("XRMD %s", argv[1]);
+ puts("RMD command not recognized, trying XRMD.");
+ (void)command("XRMD %s", argv[1]);
}
}
@@ -1458,20 +1362,23 @@ site(argc, argv)
*/
void
quote1(initial, argc, argv)
- char *initial;
+ const char *initial;
int argc;
- char **argv;
+ char *argv[];
{
int i, len;
char buf[BUFSIZ]; /* must be >= sizeof(line) */
- (void) strcpy(buf, initial);
+ (void)strncpy(buf, initial, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
if (argc > 1) {
len = strlen(buf);
- len += strlen(strcpy(&buf[len], argv[1]));
- for (i = 2; i < argc; i++) {
+ len += strlen(strncpy(&buf[len], argv[1],
+ sizeof(buf) - len - 1));
+ for (i = 2; i < argc && len < sizeof(buf); i++) {
buf[len++] = ' ';
- len += strlen(strcpy(&buf[len], argv[i]));
+ len += strlen(strncpy(&buf[len], argv[i],
+ sizeof(buf) - len) - 1);
}
}
if (command(buf) == PRELIM) {
@@ -1488,13 +1395,13 @@ do_chmod(argc, argv)
if (argc < 2 && !another(&argc, &argv, "mode"))
goto usage;
- if (argc < 3 && !another(&argc, &argv, "file-name")) {
+ if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
usage:
printf("usage: %s mode file-name\n", argv[0]);
code = -1;
return;
}
- (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
+ (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
}
void
@@ -1505,7 +1412,7 @@ do_umask(argc, argv)
int oldverbose = verbose;
verbose = 1;
- (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
+ (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
verbose = oldverbose;
}
@@ -1517,7 +1424,7 @@ idle(argc, argv)
int oldverbose = verbose;
verbose = 1;
- (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
+ (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
verbose = oldverbose;
}
@@ -1532,7 +1439,7 @@ rmthelp(argc, argv)
int oldverbose = verbose;
verbose = 1;
- (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
+ (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
verbose = oldverbose;
}
@@ -1566,9 +1473,9 @@ disconnect(argc, argv)
if (!connected)
return;
- (void) command("QUIT");
+ (void)command("QUIT");
if (cout) {
- (void) fclose(cout);
+ (void)fclose(cout);
}
cout = NULL;
connected = 0;
@@ -1578,89 +1485,33 @@ disconnect(argc, argv)
}
}
-int
-confirm(cmd, file)
- char *cmd, *file;
-{
- char line[BUFSIZ];
-
- if (!interactive)
- return (1);
- printf("%s %s? ", cmd, file);
- (void) fflush(stdout);
- if (fgets(line, sizeof line, stdin) == NULL)
- return (0);
- return (*line != 'n' && *line != 'N');
-}
-
-void
-fatal(msg)
- char *msg;
-{
-
- errx(1, "%s", msg);
-}
-
-/*
- * Glob a local file name specification with
- * the expectation of a single return value.
- * Can't control multiple values being expanded
- * from the expression, we return only the first.
- */
-int
-globulize(cpp)
- char **cpp;
-{
- glob_t gl;
- int flags;
-
- if (!doglob)
- return (1);
-
- flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
- memset(&gl, 0, sizeof(gl));
- if (glob(*cpp, flags, NULL, &gl) ||
- gl.gl_pathc == 0) {
- warnx("%s: not found", *cpp);
- globfree(&gl);
- return (0);
- }
- *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
- globfree(&gl);
- return (1);
-}
-
void
-account(argc,argv)
+account(argc, argv)
int argc;
- char **argv;
+ char *argv[];
{
- char acct[50], *ap;
+ char *ap;
- if (argc > 1) {
- ++argv;
- --argc;
- (void) strncpy(acct,*argv,49);
- acct[49] = '\0';
- while (argc > 1) {
- --argc;
- ++argv;
- (void) strncat(acct,*argv, 49-strlen(acct));
- }
- ap = acct;
+ if (argc > 2) {
+ printf("usage: %s [password]\n", argv[0]);
+ code = -1;
+ return;
}
- else {
+ else if (argc == 2)
+ ap = argv[1];
+ else
ap = getpass("Account:");
- }
- (void) command("ACCT %s", ap);
+ (void)command("ACCT %s", ap);
}
jmp_buf abortprox;
void
-proxabort()
+proxabort(notused)
+ int notused;
{
+ alarmtimer(0);
if (!proxy) {
pswitch(1);
}
@@ -1671,7 +1522,7 @@ proxabort()
proxflag = 0;
}
pswitch(0);
- longjmp(abortprox,1);
+ longjmp(abortprox, 1);
}
void
@@ -1680,6 +1531,7 @@ doproxy(argc, argv)
char *argv[];
{
struct cmd *c;
+ int cmdpos;
sig_t oldintr;
if (argc < 2 && !another(&argc, &argv, "command")) {
@@ -1689,20 +1541,20 @@ doproxy(argc, argv)
}
c = getcmd(argv[1]);
if (c == (struct cmd *) -1) {
- printf("?Ambiguous command\n");
- (void) fflush(stdout);
+ puts("?Ambiguous command.");
+ (void)fflush(stdout);
code = -1;
return;
}
if (c == 0) {
- printf("?Invalid command\n");
- (void) fflush(stdout);
+ puts("?Invalid command.");
+ (void)fflush(stdout);
code = -1;
return;
}
if (!c->c_proxy) {
- printf("?Invalid proxy command\n");
- (void) fflush(stdout);
+ puts("?Invalid proxy command.");
+ (void)fflush(stdout);
code = -1;
return;
}
@@ -1713,13 +1565,16 @@ doproxy(argc, argv)
oldintr = signal(SIGINT, proxabort);
pswitch(1);
if (c->c_conn && !connected) {
- printf("Not connected\n");
- (void) fflush(stdout);
+ puts("Not connected.");
+ (void)fflush(stdout);
pswitch(0);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
code = -1;
return;
}
+ cmdpos = strcspn(line, " \t");
+ if (cmdpos > 0) /* remove leading "proxy " from input buffer */
+ memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
(*c->c_handler)(argc-1, argv+1);
if (connected) {
proxflag = 1;
@@ -1728,7 +1583,7 @@ doproxy(argc, argv)
proxflag = 0;
}
pswitch(0);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
}
void
@@ -1737,9 +1592,7 @@ setcase(argc, argv)
char *argv[];
{
- mcase = !mcase;
- printf("Case mapping %s.\n", onoff(mcase));
- code = mcase;
+ code = togglevar(argc, argv, &mcase, "Case mapping");
}
void
@@ -1748,32 +1601,30 @@ setcr(argc, argv)
char *argv[];
{
- crflag = !crflag;
- printf("Carriage Return stripping %s.\n", onoff(crflag));
- code = crflag;
+ code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
}
void
-setntrans(argc,argv)
+setntrans(argc, argv)
int argc;
char *argv[];
{
if (argc == 1) {
ntflag = 0;
- printf("Ntrans off.\n");
+ puts("Ntrans off.");
code = ntflag;
return;
}
ntflag++;
code = ntflag;
- (void) strncpy(ntin, argv[1], 16);
- ntin[16] = '\0';
+ (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
+ ntin[sizeof(ntin) - 1] = '\0';
if (argc == 2) {
ntout[0] = '\0';
return;
}
- (void) strncpy(ntout, argv[2], 16);
- ntout[16] = '\0';
+ (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
+ ntout[sizeof(ntout) - 1] = '\0';
}
char *
@@ -1814,12 +1665,12 @@ setnmap(argc, argv)
if (argc == 1) {
mapflag = 0;
- printf("Nmap off.\n");
+ puts("Nmap off.");
code = mapflag;
return;
}
- if (argc < 3 && !another(&argc, &argv, "mapout")) {
- printf("Usage: %s [mapin mapout]\n",argv[0]);
+ if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
+ printf("usage: %s [mapin mapout]\n", argv[0]);
code = -1;
return;
}
@@ -1833,10 +1684,10 @@ setnmap(argc, argv)
cp = strchr(altarg, ' ');
}
*cp = '\0';
- (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
+ (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
while (*++cp == ' ')
continue;
- (void) strncpy(mapout, cp, MAXPATHLEN - 1);
+ (void)strncpy(mapout, cp, MAXPATHLEN - 1);
}
char *
@@ -1901,7 +1752,7 @@ domap(name)
break;
case '[':
LOOP:
- if (*++cp2 == '$' && isdigit(*(cp2+1))) {
+ if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
if (*++cp2 == '0') {
char *cp3 = name;
@@ -1920,13 +1771,13 @@ LOOP:
}
}
else {
- while (*cp2 && *cp2 != ',' &&
+ while (*cp2 && *cp2 != ',' &&
*cp2 != ']') {
if (*cp2 == '\\') {
cp2++;
}
else if (*cp2 == '$' &&
- isdigit(*(cp2+1))) {
+ isdigit((unsigned char)*(cp2+1))) {
if (*++cp2 == '0') {
char *cp3 = name;
@@ -1949,7 +1800,8 @@ LOOP:
}
}
if (!*cp2) {
- printf("nmap: unbalanced brackets\n");
+ puts(
+"nmap: unbalanced brackets.");
return (name);
}
match = 1;
@@ -1962,7 +1814,8 @@ LOOP:
}
}
if (!*cp2) {
- printf("nmap: unbalanced brackets\n");
+ puts(
+"nmap: unbalanced brackets.");
return (name);
}
break;
@@ -1978,7 +1831,7 @@ LOOP:
}
break;
case '$':
- if (isdigit(*(cp2 + 1))) {
+ if (isdigit((unsigned char)*(cp2 + 1))) {
if (*++cp2 == '0') {
char *cp3 = name;
@@ -2015,9 +1868,8 @@ setpassive(argc, argv)
char *argv[];
{
- passivemode = !passivemode;
- printf("Passive mode %s.\n", onoff(passivemode));
- code = passivemode;
+ code = togglevar(argc, argv, &passivemode,
+ verbose ? "Passive mode" : NULL);
}
void
@@ -2026,9 +1878,7 @@ setsunique(argc, argv)
char *argv[];
{
- sunique = !sunique;
- printf("Store unique %s.\n", onoff(sunique));
- code = sunique;
+ code = togglevar(argc, argv, &sunique, "Store unique");
}
void
@@ -2037,23 +1887,25 @@ setrunique(argc, argv)
char *argv[];
{
- runique = !runique;
- printf("Receive unique %s.\n", onoff(runique));
- code = runique;
+ code = togglevar(argc, argv, &runique, "Receive unique");
}
-/* change directory to perent directory */
+/* change directory to parent directory */
void
cdup(argc, argv)
int argc;
char *argv[];
{
+ int r;
- if (command("CDUP") == ERROR && code == 500) {
+ r = command("CDUP");
+ if (r == ERROR && code == 500) {
if (verbose)
- printf("CDUP command not recognized, trying XCUP\n");
- (void) command("XCUP");
+ puts("CDUP command not recognized, trying XCUP.");
+ r = command("XCUP");
}
+ if (r == COMPLETE)
+ dirchange = 1;
}
/* restart transfer at specific point */
@@ -2064,11 +1916,11 @@ restart(argc, argv)
{
if (argc != 2)
- printf("restart: offset not specified\n");
+ puts("restart: offset not specified.");
else {
restart_point = atol(argv[1]);
- printf("restarting at %qd. %s\n", restart_point,
- "execute get, put or append to initiate transfer");
+ printf("Restarting at %qd. Execute get, put or append to"
+ "initiate transfer\n", restart_point);
}
}
@@ -2079,7 +1931,7 @@ syst(argc, argv)
char *argv[];
{
- (void) command("SYST");
+ (void)command("SYST");
}
void
@@ -2091,29 +1943,29 @@ macdef(argc, argv)
int c;
if (macnum == 16) {
- printf("Limit of 16 macros have already been defined\n");
+ puts("Limit of 16 macros have already been defined.");
code = -1;
return;
}
- if (argc < 2 && !another(&argc, &argv, "macro name")) {
- printf("Usage: %s macro_name\n",argv[0]);
+ if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
+ printf("usage: %s macro_name\n", argv[0]);
code = -1;
return;
}
- if (interactive) {
- printf("Enter macro line by line, terminating it with a null line\n");
- }
- (void) strncpy(macros[macnum].mac_name, argv[1], 8);
- if (macnum == 0) {
+ if (interactive)
+ puts(
+"Enter macro line by line, terminating it with a null line.");
+ (void)strncpy(macros[macnum].mac_name, argv[1],
+ sizeof(macros[macnum].mac_name) - 1);
+ macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
+ if (macnum == 0)
macros[macnum].mac_start = macbuf;
- }
- else {
+ else
macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
- }
tmp = macros[macnum].mac_start;
while (tmp != macbuf+4096) {
if ((c = getchar()) == EOF) {
- printf("macdef:end of file encountered\n");
+ puts("macdef: end of file encountered.");
code = -1;
return;
}
@@ -2136,7 +1988,7 @@ macdef(argc, argv)
while ((c = getchar()) != '\n' && c != EOF)
/* LOOP */;
if (c == EOF || getchar() == '\n') {
- printf("Macro not defined - 4k buffer exceeded\n");
+ puts("Macro not defined - 4K buffer exceeded.");
code = -1;
return;
}
@@ -2144,6 +1996,18 @@ macdef(argc, argv)
}
/*
+ * Restrict FTP data port range to a high group of "safe" ports
+ */
+void
+setrestrict(argc, argv)
+ int argc;
+ char *argv[];
+{
+ code = togglevar(argc, argv, &restricted_data_ports,
+ verbose ? "Restricted data ports" : NULL);
+}
+
+/*
* get size of file on remote machine
*/
void
@@ -2151,13 +2015,17 @@ sizecmd(argc, argv)
int argc;
char *argv[];
{
+ off_t size;
- if (argc < 2 && !another(&argc, &argv, "filename")) {
+ if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
printf("usage: %s filename\n", argv[0]);
code = -1;
return;
}
- (void) command("SIZE %s", argv[1]);
+ size = remotesize(argv[1], 1);
+ if (size != -1)
+ printf("%s\t%qd\n", argv[1], size);
+ code = size;
}
/*
@@ -2168,30 +2036,21 @@ modtime(argc, argv)
int argc;
char *argv[];
{
- int overbose;
+ time_t mtime;
- if (argc < 2 && !another(&argc, &argv, "filename")) {
+ if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
printf("usage: %s filename\n", argv[0]);
code = -1;
return;
}
- overbose = verbose;
- if (debug == 0)
- verbose = -1;
- if (command("MDTM %s", argv[1]) == COMPLETE) {
- int yy, mo, day, hour, min, sec;
- sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
- &day, &hour, &min, &sec);
- /* might want to print this in local time */
- printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
- mo, day, yy, hour, min, sec);
- } else
- printf("%s\n", reply_string);
- verbose = overbose;
+ mtime = remotemodtime(argv[1], 1);
+ if (mtime != -1)
+ printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
+ code = mtime;
}
/*
- * show status on reomte machine
+ * show status on remote machine
*/
void
rmtstatus(argc, argv)
@@ -2199,7 +2058,7 @@ rmtstatus(argc, argv)
char *argv[];
{
- (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
+ (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
}
/*
@@ -2212,6 +2071,44 @@ newer(argc, argv)
{
if (getit(argc, argv, -1, "w"))
- printf("Local file \"%s\" is newer than remote file \"%s\"\n",
+ printf("Local file \"%s\" is newer than remote file \"%s\".\n",
argv[2], argv[1]);
}
+
+/*
+ * Display one file through $PAGER (defaults to "more").
+ */
+void
+page(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int orestart_point, ohash, overbose;
+ char *p, *pager;
+
+ if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
+ printf("usage: %s filename\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (!globulize(&argv[1])) {
+ code = -1;
+ return;
+ }
+ p = getenv("PAGER");
+ if (p == NULL)
+ p = PAGER;
+ if ((pager = malloc(strlen(p) + 2)) == NULL)
+ errx(1, "Can't allocate memory for $PAGER");
+ (void)sprintf(pager, "|%s", p);
+
+ orestart_point = restart_point;
+ ohash = hash;
+ overbose = verbose;
+ restart_point = hash = verbose = 0;
+ recvrequest("RETR", pager, argv[1], "r+w", 1);
+ (void)free(pager);
+ restart_point = orestart_point;
+ hash = ohash;
+ verbose = overbose;
+}
diff --git a/usr.bin/ftp/cmdtab.c b/usr.bin/ftp/cmdtab.c
index 1b6da8c..f67eeb0 100644
--- a/usr.bin/ftp/cmdtab.c
+++ b/usr.bin/ftp/cmdtab.c
@@ -1,3 +1,6 @@
+/* $Id$ */
+/* $NetBSD: cmdtab.c,v 1.15 1997/04/05 03:27:33 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -32,7 +35,11 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)cmdtab.c 8.4 (Berkeley) 10/9/94";
+#else
+static char rcsid[] = "$Id$";
+#endif
#endif /* not lint */
#include <stdio.h>
@@ -49,21 +56,25 @@ char beephelp[] = "beep when command completed";
char binaryhelp[] = "set binary transfer type";
char casehelp[] = "toggle mget upper/lower case id mapping";
char cdhelp[] = "change remote working directory";
-char cduphelp[] = "change remote working directory to parent directory";
+char cduphelp[] = "change remote working directory to parent directory";
char chmodhelp[] = "change file permissions of remote file";
-char connecthelp[] = "connect to remote tftp";
+char connecthelp[] = "connect to remote ftp server";
char crhelp[] = "toggle carriage return stripping on ascii gets";
-char deletehelp[] = "delete remote file";
char debughelp[] = "toggle/set debugging mode";
+char deletehelp[] = "delete remote file";
char dirhelp[] = "list contents of remote directory";
char disconhelp[] = "terminate ftp session";
-char domachelp[] = "execute macro";
+char domachelp[] = "execute macro";
+#ifndef SMALL
+char edithelp[] = "toggle command line editing";
+#endif /* !SMALL */
char formhelp[] = "set file transfer format";
char globhelp[] = "toggle metacharacter expansion of local file names";
-char hashhelp[] = "toggle printing `#' for each buffer transferred";
+char hashhelp[] = "toggle printing `#' marks; specify number to set size";
char helphelp[] = "print local help information";
char idlehelp[] = "get (set) idle timer on remote side";
char lcdhelp[] = "change local working directory";
+char lpwdhelp[] = "print local working directory";
char lshelp[] = "list contents of remote directory";
char macdefhelp[] = "define a macro";
char mdeletehelp[] = "delete multiple files";
@@ -71,14 +82,19 @@ char mdirhelp[] = "list contents of multiple remote directories";
char mgethelp[] = "get multiple files";
char mkdirhelp[] = "make directory on the remote machine";
char mlshelp[] = "list contents of multiple remote directories";
-char modtimehelp[] = "show last modification time of remote file";
char modehelp[] = "set file transfer mode";
+char modtimehelp[] = "show last modification time of remote file";
char mputhelp[] = "send multiple files";
char newerhelp[] = "get file if remote file is newer than local file ";
char nlisthelp[] = "nlist contents of remote directory";
char nmaphelp[] = "set templates for default file name mapping";
char ntranshelp[] = "set translation table for default file name mapping";
+char pagehelp[] = "view a remote file through your pager";
+char passivehelp[] = "enter passive transfer mode";
char porthelp[] = "toggle use of PORT cmd for each data connection";
+char preservehelp[] ="toggle preservation of modification time of "
+ "retreived files";
+char progresshelp[] ="toggle transfer progress meter";
char prompthelp[] = "force interactive prompting on multiple commands";
char proxyhelp[] = "issue command on alternate connection";
char pwdhelp[] = "print working directory on remote machine";
@@ -88,15 +104,17 @@ char receivehelp[] = "receive file";
char regethelp[] = "get file restarting at end of local file";
char remotehelp[] = "get help from remote server";
char renamehelp[] = "rename file";
+char resethelp[] = "clear queued command replies";
char restarthelp[]= "restart file transfer at bytecount";
+char restricthelp[]= "toggle restriction of data port range";
char rmdirhelp[] = "remove directory on the remote machine";
char rmtstatushelp[]="show status of remote machine";
char runiquehelp[] = "toggle store unique for local files";
-char resethelp[] = "clear queued command replies";
char sendhelp[] = "send one file";
-char passivehelp[] = "enter passive transfer mode";
-char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information";
char shellhelp[] = "escape to the shell";
+char sitehelp[] = "send site specific command to remote server\n"
+ "\t\tTry \"rhelp site\" or \"site help\" "
+ "for more information";
char sizecmdhelp[] = "show size of remote file";
char statushelp[] = "show current status";
char structhelp[] = "set file transfer structure";
@@ -109,80 +127,101 @@ char umaskhelp[] = "get (set) umask on remote side";
char userhelp[] = "send new user information";
char verbosehelp[] = "toggle verbose mode";
+#ifdef SMALL
+#define CMPL(x)
+#define CMPL0
+#else /* !SMALL */
+#define CMPL(x) __STRING(x),
+#define CMPL0 "",
+#endif /* !SMALL */
+
struct cmd cmdtab[] = {
- { "!", shellhelp, 0, 0, 0, shell },
- { "$", domachelp, 1, 0, 0, domacro },
- { "account", accounthelp, 0, 1, 1, account},
- { "append", appendhelp, 1, 1, 1, put },
- { "ascii", asciihelp, 0, 1, 1, setascii },
- { "bell", beephelp, 0, 0, 0, setbell },
- { "binary", binaryhelp, 0, 1, 1, setbinary },
- { "bye", quithelp, 0, 0, 0, quit },
- { "case", casehelp, 0, 0, 1, setcase },
- { "cd", cdhelp, 0, 1, 1, cd },
- { "cdup", cduphelp, 0, 1, 1, cdup },
- { "chmod", chmodhelp, 0, 1, 1, do_chmod },
- { "close", disconhelp, 0, 1, 1, disconnect },
- { "cr", crhelp, 0, 0, 0, setcr },
- { "delete", deletehelp, 0, 1, 1, delete },
- { "debug", debughelp, 0, 0, 0, setdebug },
- { "dir", dirhelp, 1, 1, 1, ls },
- { "disconnect", disconhelp, 0, 1, 1, disconnect },
- { "form", formhelp, 0, 1, 1, setform },
- { "get", receivehelp, 1, 1, 1, get },
- { "glob", globhelp, 0, 0, 0, setglob },
- { "hash", hashhelp, 0, 0, 0, sethash },
- { "help", helphelp, 0, 0, 1, help },
- { "idle", idlehelp, 0, 1, 1, idle },
- { "image", binaryhelp, 0, 1, 1, setbinary },
- { "lcd", lcdhelp, 0, 0, 0, lcd },
- { "ls", lshelp, 1, 1, 1, ls },
- { "macdef", macdefhelp, 0, 0, 0, macdef },
- { "mdelete", mdeletehelp, 1, 1, 1, mdelete },
- { "mdir", mdirhelp, 1, 1, 1, mls },
- { "mget", mgethelp, 1, 1, 1, mget },
- { "mkdir", mkdirhelp, 0, 1, 1, makedir },
- { "mls", mlshelp, 1, 1, 1, mls },
- { "mode", modehelp, 0, 1, 1, setftmode },
- { "modtime", modtimehelp, 0, 1, 1, modtime },
- { "mput", mputhelp, 1, 1, 1, mput },
- { "newer", newerhelp, 1, 1, 1, newer },
- { "nmap", nmaphelp, 0, 0, 1, setnmap },
- { "nlist", nlisthelp, 1, 1, 1, ls },
- { "ntrans", ntranshelp, 0, 0, 1, setntrans },
- { "open", connecthelp, 0, 0, 1, setpeer },
- { "passive", passivehelp, 0, 0, 0, setpassive },
- { "prompt", prompthelp, 0, 0, 0, setprompt },
- { "proxy", proxyhelp, 0, 0, 1, doproxy },
- { "sendport", porthelp, 0, 0, 0, setport },
- { "put", sendhelp, 1, 1, 1, put },
- { "pwd", pwdhelp, 0, 1, 1, pwd },
- { "quit", quithelp, 0, 0, 0, quit },
- { "quote", quotehelp, 1, 1, 1, quote },
- { "recv", receivehelp, 1, 1, 1, get },
- { "reget", regethelp, 1, 1, 1, reget },
- { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus },
- { "rhelp", remotehelp, 0, 1, 1, rmthelp },
- { "rename", renamehelp, 0, 1, 1, renamefile },
- { "reset", resethelp, 0, 1, 1, reset },
- { "restart", restarthelp, 1, 1, 1, restart },
- { "rmdir", rmdirhelp, 0, 1, 1, removedir },
- { "runique", runiquehelp, 0, 0, 1, setrunique },
- { "send", sendhelp, 1, 1, 1, put },
- { "site", sitehelp, 0, 1, 1, site },
- { "size", sizecmdhelp, 1, 1, 1, sizecmd },
- { "status", statushelp, 0, 0, 1, status },
- { "struct", structhelp, 0, 1, 1, setstruct },
- { "system", systemhelp, 0, 1, 1, syst },
- { "sunique", suniquehelp, 0, 0, 1, setsunique },
- { "tenex", tenexhelp, 0, 1, 1, settenex },
- { "trace", tracehelp, 0, 0, 0, settrace },
- { "type", typehelp, 0, 1, 1, settype },
- { "user", userhelp, 0, 1, 1, user },
- { "umask", umaskhelp, 0, 1, 1, do_umask },
- { "verbose", verbosehelp, 0, 0, 0, setverbose },
- { "?", helphelp, 0, 0, 1, help },
+ { "!", shellhelp, 0, 0, 0, CMPL0 shell },
+ { "$", domachelp, 1, 0, 0, CMPL0 domacro },
+ { "account", accounthelp, 0, 1, 1, CMPL0 account},
+ { "append", appendhelp, 1, 1, 1, CMPL(lr) put },
+ { "ascii", asciihelp, 0, 1, 1, CMPL0 setascii },
+ { "bell", beephelp, 0, 0, 0, CMPL0 setbell },
+ { "binary", binaryhelp, 0, 1, 1, CMPL0 setbinary },
+ { "bye", quithelp, 0, 0, 0, CMPL0 quit },
+ { "case", casehelp, 0, 0, 1, CMPL0 setcase },
+ { "cd", cdhelp, 0, 1, 1, CMPL(r) cd },
+ { "cdup", cduphelp, 0, 1, 1, CMPL0 cdup },
+ { "chmod", chmodhelp, 0, 1, 1, CMPL(nr) do_chmod },
+ { "close", disconhelp, 0, 1, 1, CMPL0 disconnect },
+ { "cr", crhelp, 0, 0, 0, CMPL0 setcr },
+ { "debug", debughelp, 0, 0, 0, CMPL0 setdebug },
+ { "delete", deletehelp, 0, 1, 1, CMPL(r) delete },
+ { "dir", dirhelp, 1, 1, 1, CMPL(rl) ls },
+ { "disconnect", disconhelp, 0, 1, 1, CMPL0 disconnect },
+#ifndef SMALL
+ { "edit", edithelp, 0, 0, 0, CMPL0 setedit },
+#endif /* !SMALL */
+ { "exit", quithelp, 0, 0, 0, CMPL0 quit },
+ { "form", formhelp, 0, 1, 1, CMPL0 setform },
+ { "ftp", connecthelp, 0, 0, 1, CMPL0 setpeer },
+ { "get", receivehelp, 1, 1, 1, CMPL(rl) get },
+ { "glob", globhelp, 0, 0, 0, CMPL0 setglob },
+ { "hash", hashhelp, 0, 0, 0, CMPL0 sethash },
+ { "help", helphelp, 0, 0, 1, CMPL(C) help },
+ { "idle", idlehelp, 0, 1, 1, CMPL0 idle },
+ { "image", binaryhelp, 0, 1, 1, CMPL0 setbinary },
+ { "lcd", lcdhelp, 0, 0, 0, CMPL(l) lcd },
+ { "less", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "lpwd", lpwdhelp, 0, 0, 0, CMPL0 lpwd },
+ { "ls", lshelp, 1, 1, 1, CMPL(rl) ls },
+ { "macdef", macdefhelp, 0, 0, 0, CMPL0 macdef },
+ { "mdelete", mdeletehelp, 1, 1, 1, CMPL(R) mdelete },
+ { "mdir", mdirhelp, 1, 1, 1, CMPL(R) mls },
+ { "mget", mgethelp, 1, 1, 1, CMPL(R) mget },
+ { "mkdir", mkdirhelp, 0, 1, 1, CMPL(r) makedir },
+ { "mls", mlshelp, 1, 1, 1, CMPL(R) mls },
+ { "mode", modehelp, 0, 1, 1, CMPL0 setftmode },
+ { "modtime", modtimehelp, 0, 1, 1, CMPL(r) modtime },
+ { "more", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "mput", mputhelp, 1, 1, 1, CMPL(L) mput },
+ { "msend", mputhelp, 1, 1, 1, CMPL(L) mput },
+ { "newer", newerhelp, 1, 1, 1, CMPL(r) newer },
+ { "nlist", nlisthelp, 1, 1, 1, CMPL(rl) ls },
+ { "nmap", nmaphelp, 0, 0, 1, CMPL0 setnmap },
+ { "ntrans", ntranshelp, 0, 0, 1, CMPL0 setntrans },
+ { "open", connecthelp, 0, 0, 1, CMPL0 setpeer },
+ { "page", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "passive", passivehelp, 0, 0, 0, CMPL0 setpassive },
+ { "preserve", preservehelp, 0, 0, 0, CMPL0 setpreserve },
+ { "progress", progresshelp, 0, 0, 0, CMPL0 setprogress },
+ { "prompt", prompthelp, 0, 0, 0, CMPL0 setprompt },
+ { "proxy", proxyhelp, 0, 0, 1, CMPL(c) doproxy },
+ { "put", sendhelp, 1, 1, 1, CMPL(lr) put },
+ { "pwd", pwdhelp, 0, 1, 1, CMPL0 pwd },
+ { "quit", quithelp, 0, 0, 0, CMPL0 quit },
+ { "quote", quotehelp, 1, 1, 1, CMPL0 quote },
+ { "recv", receivehelp, 1, 1, 1, CMPL(rl) get },
+ { "reget", regethelp, 1, 1, 1, CMPL(rl) reget },
+ { "rename", renamehelp, 0, 1, 1, CMPL(rr) renamefile },
+ { "reset", resethelp, 0, 1, 1, CMPL0 reset },
+ { "restart", restarthelp, 1, 1, 1, CMPL0 restart },
+ { "restrict", restricthelp, 0, 0, 0, CMPL0 setrestrict },
+ { "rhelp", remotehelp, 0, 1, 1, CMPL0 rmthelp },
+ { "rmdir", rmdirhelp, 0, 1, 1, CMPL(r) removedir },
+ { "rstatus", rmtstatushelp, 0, 1, 1, CMPL(r) rmtstatus },
+ { "runique", runiquehelp, 0, 0, 1, CMPL0 setrunique },
+ { "send", sendhelp, 1, 1, 1, CMPL(lr) put },
+ { "sendport", porthelp, 0, 0, 0, CMPL0 setport },
+ { "site", sitehelp, 0, 1, 1, CMPL0 site },
+ { "size", sizecmdhelp, 1, 1, 1, CMPL(r) sizecmd },
+ { "status", statushelp, 0, 0, 1, CMPL0 status },
+ { "struct", structhelp, 0, 1, 1, CMPL0 setstruct },
+ { "sunique", suniquehelp, 0, 0, 1, CMPL0 setsunique },
+ { "system", systemhelp, 0, 1, 1, CMPL0 syst },
+ { "tenex", tenexhelp, 0, 1, 1, CMPL0 settenex },
+ { "trace", tracehelp, 0, 0, 0, CMPL0 settrace },
+ { "type", typehelp, 0, 1, 1, CMPL0 settype },
+ { "umask", umaskhelp, 0, 1, 1, CMPL0 do_umask },
+ { "user", userhelp, 0, 1, 1, CMPL0 user },
+ { "verbose", verbosehelp, 0, 0, 0, CMPL0 setverbose },
+ { "?", helphelp, 0, 0, 1, CMPL(C) help },
{ 0 },
};
-int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
+int NCMDS = (sizeof(cmdtab) / sizeof(cmdtab[0])) - 1;
diff --git a/usr.bin/ftp/complete.c b/usr.bin/ftp/complete.c
new file mode 100644
index 0000000..689c1f8
--- /dev/null
+++ b/usr.bin/ftp/complete.c
@@ -0,0 +1,367 @@
+/* $Id: complete.c,v 1.2 1997/06/27 09:30:04 ache Exp $ */
+/* $NetBSD: complete.c,v 1.8 1997/05/24 16:34:30 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SMALL
+#ifndef lint
+static char rcsid[] = "$Id: complete.c,v 1.2 1997/06/27 09:30:04 ache Exp $";
+#endif /* not lint */
+
+/*
+ * FTP user program - command and file completion routines
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ftp_var.h"
+
+static int
+comparstr(a, b)
+ const void *a, *b;
+{
+ return (strcoll(*(char **)a, *(char **)b));
+}
+
+/*
+ * Determine if complete is ambiguous. If unique, insert.
+ * If no choices, error. If unambiguous prefix, insert that.
+ * Otherwise, list choices. words is assumed to be filtered
+ * to only contain possible choices.
+ * Args:
+ * word word which started the match
+ * list list by default
+ * words stringlist containing possible matches
+ */
+static unsigned char
+complete_ambiguous(word, list, words)
+ char *word;
+ int list;
+ StringList *words;
+{
+ char insertstr[MAXPATHLEN];
+ char *lastmatch;
+ int i, j, matchlen, wordlen;
+
+ wordlen = strlen(word);
+ if (words->sl_cur == 0)
+ return (CC_ERROR); /* no choices available */
+
+ if (words->sl_cur == 1) { /* only once choice available */
+ (void)strcpy(insertstr, words->sl_str[0]);
+ if (el_insertstr(el, insertstr + wordlen) == -1)
+ return (CC_ERROR);
+ else
+ return (CC_REFRESH);
+ }
+
+ if (!list) {
+ matchlen = 0;
+ lastmatch = words->sl_str[0];
+ matchlen = strlen(lastmatch);
+ for (i = 1 ; i < words->sl_cur ; i++) {
+ for (j = wordlen ; j < strlen(words->sl_str[i]); j++)
+ if (lastmatch[j] != words->sl_str[i][j])
+ break;
+ if (j < matchlen)
+ matchlen = j;
+ }
+ if (matchlen > wordlen) {
+ (void)strncpy(insertstr, lastmatch, matchlen);
+ insertstr[matchlen] = '\0';
+ if (el_insertstr(el, insertstr + wordlen) == -1)
+ return (CC_ERROR);
+ else
+ /*
+ * XXX: really want CC_REFRESH_BEEP
+ */
+ return (CC_REFRESH);
+ }
+ }
+
+ putchar('\n');
+ qsort(words->sl_str, words->sl_cur, sizeof(char *), comparstr);
+ list_vertical(words);
+ return (CC_REDISPLAY);
+}
+
+/*
+ * Complete a command
+ */
+static unsigned char
+complete_command(word, list)
+ char *word;
+ int list;
+{
+ struct cmd *c;
+ StringList *words;
+ int wordlen;
+ unsigned char rv;
+
+ words = sl_init();
+ wordlen = strlen(word);
+
+ for (c = cmdtab; c->c_name != NULL; c++) {
+ if (wordlen > strlen(c->c_name))
+ continue;
+ if (strncmp(word, c->c_name, wordlen) == 0)
+ sl_add(words, c->c_name);
+ }
+
+ rv = complete_ambiguous(word, list, words);
+ sl_free(words, 0);
+ return (rv);
+}
+
+/*
+ * Complete a local file
+ */
+static unsigned char
+complete_local(word, list)
+ char *word;
+ int list;
+{
+ StringList *words;
+ char dir[MAXPATHLEN];
+ char *file;
+ DIR *dd;
+ struct dirent *dp;
+ unsigned char rv;
+
+ if ((file = strrchr(word, '/')) == NULL) {
+ dir[0] = '.';
+ dir[1] = '\0';
+ file = word;
+ } else {
+ if (file == word) {
+ dir[0] = '/';
+ dir[1] = '\0';
+ } else {
+ (void)strncpy(dir, word, file - word);
+ dir[file - word] = '\0';
+ }
+ file++;
+ }
+
+ if ((dd = opendir(dir)) == NULL)
+ return (CC_ERROR);
+
+ words = sl_init();
+
+ for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
+ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+ continue;
+ if (strlen(file) > dp->d_namlen)
+ continue;
+ if (strncmp(file, dp->d_name, strlen(file)) == 0) {
+ char *tcp;
+
+ tcp = strdup(dp->d_name);
+ if (tcp == NULL)
+ errx(1, "Can't allocate memory for local dir");
+ sl_add(words, tcp);
+ }
+ }
+ closedir(dd);
+
+ rv = complete_ambiguous(file, list, words);
+ sl_free(words, 1);
+ return (rv);
+}
+
+/*
+ * Complete a remote file
+ */
+static unsigned char
+complete_remote(word, list)
+ char *word;
+ int list;
+{
+ static StringList *dirlist;
+ static char lastdir[MAXPATHLEN];
+ StringList *words;
+ char dir[MAXPATHLEN];
+ char *file, *cp;
+ int i;
+ unsigned char rv;
+
+ char *dummyargv[] = { "complete", dir, NULL };
+
+ if ((file = strrchr(word, '/')) == NULL) {
+ dir[0] = '.';
+ dir[1] = '\0';
+ file = word;
+ } else {
+ cp = file;
+ while (*cp == '/' && cp > word)
+ cp--;
+ (void)strncpy(dir, word, cp - word + 1);
+ dir[cp - word + 1] = '\0';
+ file++;
+ }
+
+ if (dirchange || strcmp(dir, lastdir) != 0) { /* dir not cached */
+ char *emesg;
+
+ if (dirlist != NULL)
+ sl_free(dirlist, 1);
+ dirlist = sl_init();
+
+ mflag = 1;
+ emesg = NULL;
+ while ((cp = remglob(dummyargv, 0, &emesg)) != NULL) {
+ char *tcp;
+
+ if (!mflag)
+ continue;
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ tcp = strrchr(cp, '/');
+ if (tcp)
+ tcp++;
+ else
+ tcp = cp;
+ tcp = strdup(tcp);
+ if (tcp == NULL)
+ errx(1, "Can't allocate memory for remote dir");
+ sl_add(dirlist, tcp);
+ }
+ if (emesg != NULL) {
+ printf("\n%s\n", emesg);
+ return (CC_REDISPLAY);
+ }
+ (void)strcpy(lastdir, dir);
+ dirchange = 0;
+ }
+
+ words = sl_init();
+ for (i = 0; i < dirlist->sl_cur; i++) {
+ cp = dirlist->sl_str[i];
+ if (strlen(file) > strlen(cp))
+ continue;
+ if (strncmp(file, cp, strlen(file)) == 0)
+ sl_add(words, cp);
+ }
+ rv = complete_ambiguous(file, list, words);
+ sl_free(words, 0);
+ return (rv);
+}
+
+/*
+ * Generic complete routine
+ */
+unsigned char
+complete(el, ch)
+ EditLine *el;
+ int ch;
+{
+ static char word[FTPBUFLEN];
+ static int lastc_argc, lastc_argo;
+
+ struct cmd *c;
+ const LineInfo *lf;
+ int len, celems, dolist;
+
+ lf = el_line(el);
+ len = lf->lastchar - lf->buffer;
+ if (len >= sizeof(line))
+ return (CC_ERROR);
+ (void)strncpy(line, lf->buffer, len);
+ line[len] = '\0';
+ cursor_pos = line + (lf->cursor - lf->buffer);
+ lastc_argc = cursor_argc; /* remember last cursor pos */
+ lastc_argo = cursor_argo;
+ makeargv(); /* build argc/argv of current line */
+
+ if (cursor_argo >= sizeof(word))
+ return (CC_ERROR);
+
+ dolist = 0;
+ /* if cursor and word is same, list alternatives */
+ if (lastc_argc == cursor_argc && lastc_argo == cursor_argo
+ && strncmp(word, margv[cursor_argc], cursor_argo) == 0)
+ dolist = 1;
+ else
+ (void)strncpy(word, margv[cursor_argc], cursor_argo);
+ word[cursor_argo] = '\0';
+
+ if (cursor_argc == 0)
+ return (complete_command(word, dolist));
+
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1 || c == 0)
+ return (CC_ERROR);
+ celems = strlen(c->c_complete);
+
+ /* check for 'continuation' completes (which are uppercase) */
+ if ((cursor_argc > celems) && (celems > 0)
+ && isupper((unsigned char)c->c_complete[celems-1]))
+ cursor_argc = celems;
+
+ if (cursor_argc > celems)
+ return (CC_ERROR);
+
+ switch (c->c_complete[cursor_argc - 1]) {
+ case 'l': /* local complete */
+ case 'L':
+ return (complete_local(word, dolist));
+ case 'r': /* remote complete */
+ case 'R':
+ if (connected != -1) {
+ puts("\nMust be logged in to complete.");
+ return (CC_REDISPLAY);
+ }
+ return (complete_remote(word, dolist));
+ case 'c': /* command complete */
+ case 'C':
+ return (complete_command(word, dolist));
+ case 'n': /* no complete */
+ default:
+ return (CC_ERROR);
+ }
+
+ return (CC_ERROR);
+}
+#endif
diff --git a/usr.bin/ftp/domacro.c b/usr.bin/ftp/domacro.c
index 9644487..a28d068 100644
--- a/usr.bin/ftp/domacro.c
+++ b/usr.bin/ftp/domacro.c
@@ -1,3 +1,6 @@
+/* $Id: domacro.c,v 1.3 1997/06/27 09:30:09 ache Exp $ */
+/* $NetBSD: domacro.c,v 1.9 1997/03/13 06:23:14 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -32,13 +35,17 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)domacro.c 8.3 (Berkeley) 4/2/94";
+#else
+static char rcsid[] = "$Id: domacro.c,v 1.3 1997/06/27 09:30:09 ache Exp $";
+#endif
#endif /* not lint */
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
-#include <strings.h>
+#include <string.h>
#include "ftp_var.h"
@@ -52,7 +59,7 @@ domacro(argc, argv)
struct cmd *c;
if (argc < 2 && !another(&argc, &argv, "macro name")) {
- printf("Usage: %s macro_name.\n", argv[0]);
+ printf("usage: %s macro_name\n", argv[0]);
code = -1;
return;
}
@@ -66,11 +73,11 @@ domacro(argc, argv)
code = -1;
return;
}
- (void) strcpy(line2, line);
+ (void)strcpy(line2, line);
TOP:
cp1 = macros[i].mac_start;
while (cp1 != macros[i].mac_end) {
- while (isspace(*cp1)) {
+ while (isascii(*cp1) && isspace(*cp1)) {
cp1++;
}
cp2 = line;
@@ -80,14 +87,14 @@ TOP:
*cp2++ = *++cp1;
break;
case '$':
- if (isdigit(*(cp1+1))) {
+ if (isdigit((unsigned char)*(cp1+1))) {
j = 0;
- while (isdigit(*++cp1)) {
+ while (isdigit((unsigned char)*++cp1)) {
j = 10*j + *cp1 - '0';
}
cp1--;
if (argc - 2 >= j) {
- (void) strcpy(cp2, argv[j+1]);
+ (void)strcpy(cp2, argv[j+1]);
cp2 += strlen(argv[j+1]);
}
break;
@@ -96,7 +103,7 @@ TOP:
loopflg = 1;
cp1++;
if (count < argc) {
- (void) strcpy(cp2, argv[count]);
+ (void)strcpy(cp2, argv[count]);
cp2 += strlen(argv[count]);
}
break;
@@ -114,26 +121,25 @@ TOP:
makeargv();
c = getcmd(margv[0]);
if (c == (struct cmd *)-1) {
- printf("?Ambiguous command\n");
+ puts("?Ambiguous command.");
code = -1;
}
else if (c == 0) {
- printf("?Invalid command\n");
+ puts("?Invalid command.");
code = -1;
}
else if (c->c_conn && !connected) {
- printf("Not connected.\n");
+ puts("Not connected.");
code = -1;
}
else {
- if (verbose) {
- printf("%s\n",line);
- }
+ if (verbose)
+ puts(line);
(*c->c_handler)(margc, margv);
if (bell && c->c_bell) {
- (void) putchar('\007');
+ (void)putchar('\007');
}
- (void) strcpy(line, line2);
+ (void)strcpy(line, line2);
makeargv();
argc = margc;
argv = margv;
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index 2a8bb26..3acc671 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -1,3 +1,6 @@
+/* $Id$ */
+/* $NetBSD: extern.h,v 1.15 1997/04/14 09:09:17 lukem Exp $ */
+
/*-
* Copyright (c) 1994 The Regents of the University of California.
* All rights reserved.
@@ -33,24 +36,30 @@
* @(#)extern.h 8.3 (Berkeley) 10/9/94
*/
-struct timeval;
struct fd_set;
void abort_remote __P((FILE *));
-void abortpt __P(());
-void abortrecv __P(());
-void abortsend __P(());
+void abortpt __P((int));
+void abortrecv __P((int));
+void abortsend __P((int));
+void aborthttp __P((int));
void account __P((int, char **));
-int another __P((int *, char ***, char *));
+void alarmtimer __P((int));
+int another __P((int *, char ***, const char *));
+int auto_fetch __P((int, char **));
void blkfree __P((char **));
void cd __P((int, char **));
void cdup __P((int, char **));
void changetype __P((int, int));
-void cmdabort __P(());
+void cmdabort __P((int));
void cmdscanner __P((int));
-int command __P(());
-int confirm __P((char *, char *));
-FILE *dataconn __P((char *));
+int command __P((const char *, ...));
+#ifndef SMALL
+unsigned char complete __P((EditLine *, int));
+void controlediting __P((void));
+#endif /* !SMALL */
+int confirm __P((const char *, const char *));
+FILE *dataconn __P((const char *));
void delete __P((int, char **));
void disconnect __P((int, char **));
void do_chmod __P((int, char **));
@@ -60,21 +69,22 @@ char *domap __P((char *));
void doproxy __P((int, char **));
char *dotrans __P((char *));
int empty __P((struct fd_set *, int));
-void fatal __P((char *));
void get __P((int, char **));
-struct cmd *getcmd __P((char *));
-int getit __P((int, char **, int, char *));
+struct cmd *getcmd __P((const char *));
+int getit __P((int, char **, int, const char *));
int getreply __P((int));
int globulize __P((char **));
-char *gunique __P((char *));
+char *gunique __P((const char *));
void help __P((int, char **));
-char *hookup __P((char *, int));
+char *hookup __P((const char *, int));
void idle __P((int, char **));
int initconn __P((void));
-void intr __P(());
+void intr __P((void));
+void list_vertical __P((StringList *));
void lcd __P((int, char **));
-int login __P((char *));
-void lostpeer __P(());
+int login __P((const char *, char *, char *));
+void lostpeer __P((void));
+void lpwd __P((int, char **));
void ls __P((int, char **));
void mabort __P((int));
void macdef __P((int, char **));
@@ -87,33 +97,41 @@ void modtime __P((int, char **));
void mput __P((int, char **));
char *onoff __P((int));
void newer __P((int, char **));
-void proxabort __P(());
-void proxtrans __P((char *, char *, char *));
-void psabort __P(());
+void page __P((int, char **));
+void progressmeter __P((int));
+char *prompt __P((void));
+void proxabort __P((int));
+void proxtrans __P((const char *, const char *, const char *));
+void psabort __P((int));
+void psummary __P((int));
void pswitch __P((int));
-void ptransfer __P((char *, long, struct timeval *, struct timeval *));
+void ptransfer __P((int));
void put __P((int, char **));
void pwd __P((int, char **));
void quit __P((int, char **));
void quote __P((int, char **));
-void quote1 __P((char *, int, char **));
-void recvrequest __P((char *, char *, char *, char *, int));
+void quote1 __P((const char *, int, char **));
+void recvrequest __P((const char *, const char *, const char *,
+ const char *, int));
void reget __P((int, char **));
-char *remglob __P((char **, int));
+char *remglob __P((char **, int, char **));
+off_t remotesize __P((const char *, int));
+time_t remotemodtime __P((const char *, int));
void removedir __P((int, char **));
void renamefile __P((int, char **));
void reset __P((int, char **));
void restart __P((int, char **));
void rmthelp __P((int, char **));
void rmtstatus __P((int, char **));
-int ruserpass __P((char *, char **, char **, char **));
-void sendrequest __P((char *, char *, char *, int));
+int ruserpass __P((const char *, char **, char **, char **));
+void sendrequest __P((const char *, const char *, const char *, int));
void setascii __P((int, char **));
void setbell __P((int, char **));
void setbinary __P((int, char **));
void setcase __P((int, char **));
void setcr __P((int, char **));
void setdebug __P((int, char **));
+void setedit __P((int, char **));
void setform __P((int, char **));
void setftmode __P((int, char **));
void setglob __P((int, char **));
@@ -123,12 +141,16 @@ void setntrans __P((int, char **));
void setpassive __P((int, char **));
void setpeer __P((int, char **));
void setport __P((int, char **));
+void setpreserve __P((int, char **));
+void setprogress __P((int, char **));
void setprompt __P((int, char **));
+void setrestrict __P((int, char **));
void setrunique __P((int, char **));
void setstruct __P((int, char **));
void setsunique __P((int, char **));
void settenex __P((int, char **));
void settrace __P((int, char **));
+void setttywidth __P((int));
void settype __P((int, char **));
void setverbose __P((int, char **));
void shell __P((int, char **));
@@ -137,13 +159,15 @@ void sizecmd __P((int, char **));
char *slurpstring __P((void));
void status __P((int, char **));
void syst __P((int, char **));
-void tvsub __P((struct timeval *, struct timeval *, struct timeval *));
+int togglevar __P((int, char **, int *, const char *));
+void usage __P((void));
void user __P((int, char **));
+
extern jmp_buf abortprox;
extern int abrtflag;
extern struct cmd cmdtab[];
-extern FILE *cout;
+extern FILE *cout;
extern int data;
extern char *home;
extern jmp_buf jabort;
@@ -151,3 +175,6 @@ extern int proxy;
extern char reply_string[];
extern off_t restart_point;
extern int NCMDS;
+
+extern char *__progname; /* from crt0.o */
+
diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c
new file mode 100644
index 0000000..e79c0a7
--- /dev/null
+++ b/usr.bin/ftp/fetch.c
@@ -0,0 +1,608 @@
+/* $Id: fetch.c,v 1.1 1997/06/25 08:56:39 msmith Exp $ */
+/* $NetBSD: fetch.c,v 1.10 1997/05/23 18:54:18 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason Thorpe and Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: fetch.c,v 1.1 1997/06/25 08:56:39 msmith Exp $";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command line file retrieval
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/ftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ftp_var.h"
+
+#define FTP_URL "ftp://" /* ftp URL prefix */
+#define HTTP_URL "http://" /* http URL prefix */
+#define FTP_PROXY "ftp_proxy" /* env var with ftp proxy location */
+#define HTTP_PROXY "http_proxy" /* env var with http proxy location */
+
+
+#define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0'))
+
+jmp_buf httpabort;
+
+/*
+ * Retrieve URL, via the proxy in $proxyvar if necessary.
+ * Modifies the string argument given.
+ * Returns -1 on failure, 0 on success
+ */
+int
+url_get(origline, proxyenv)
+ const char *origline;
+ const char *proxyenv;
+{
+ struct sockaddr_in sin;
+ int i, out, port, s;
+ size_t buflen, len;
+ char c, *cp, *cp2, *savefile, *portnum, *path, buf[4096];
+ char *line, *proxy, *host;
+ sig_t oldintr;
+ off_t hashbytes;
+
+ s = -1;
+ proxy = NULL;
+
+ line = strdup(origline);
+ if (line == NULL)
+ errx(1, "Can't allocate memory to parse URL");
+ if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0)
+ host = line + sizeof(HTTP_URL) - 1;
+ else if (strncasecmp(line, FTP_URL, sizeof(FTP_URL) - 1) == 0)
+ host = line + sizeof(FTP_URL) - 1;
+ else
+ errx(1, "url_get: Invalid URL '%s'", line);
+
+ path = strchr(host, '/'); /* find path */
+ if (EMPTYSTRING(path)) {
+ warnx("Invalid URL: %s", origline);
+ goto cleanup_url_get;
+ }
+ *path++ = '\0';
+ if (EMPTYSTRING(path)) {
+ warnx("Invalid URL: %s", origline);
+ goto cleanup_url_get;
+ }
+
+ savefile = strrchr(path, '/'); /* find savefile */
+ if (savefile != NULL)
+ savefile++;
+ else
+ savefile = path;
+ if (EMPTYSTRING(savefile)) {
+ warnx("Invalid URL: %s", origline);
+ goto cleanup_url_get;
+ }
+
+ if (proxyenv != NULL) { /* use proxy */
+ proxy = strdup(proxyenv);
+ if (proxy == NULL)
+ errx(1, "Can't allocate memory for proxy URL.");
+ if (strncasecmp(proxy, HTTP_URL, sizeof(HTTP_URL) - 1) == 0)
+ host = proxy + sizeof(HTTP_URL) - 1;
+ else if (strncasecmp(proxy, FTP_URL, sizeof(FTP_URL) - 1) == 0)
+ host = proxy + sizeof(FTP_URL) - 1;
+ else {
+ warnx("Malformed proxy URL: %s", proxyenv);
+ goto cleanup_url_get;
+ }
+ if (EMPTYSTRING(host)) {
+ warnx("Malformed proxy URL: %s", proxyenv);
+ goto cleanup_url_get;
+ }
+ *--path = '/'; /* add / back to real path */
+ path = strchr(host, '/'); /* remove trailing / on host */
+ if (! EMPTYSTRING(path))
+ *path++ = '\0';
+ path = line;
+ }
+
+ portnum = strchr(host, ':'); /* find portnum */
+ if (portnum != NULL)
+ *portnum++ = '\0';
+
+ if (debug)
+ printf("host %s, port %s, path %s, save as %s.\n",
+ host, portnum, path, savefile);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if (isdigit((unsigned char)host[0])) {
+ if (inet_aton(host, &sin.sin_addr) == 0) {
+ warnx("Invalid IP address: %s", host);
+ goto cleanup_url_get;
+ }
+ } else {
+ struct hostent *hp;
+
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ warnx("%s: %s", host, hstrerror(h_errno));
+ goto cleanup_url_get;
+ }
+ if (hp->h_addrtype != AF_INET) {
+ warnx("%s: not an Internet address?", host);
+ goto cleanup_url_get;
+ }
+ memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ if (! EMPTYSTRING(portnum)) {
+ port = atoi(portnum);
+ if (port < 1 || (port & 0xffff) != port) {
+ warnx("Invalid port: %s", portnum);
+ goto cleanup_url_get;
+ }
+ port = htons(port);
+ } else
+ port = httpport;
+ sin.sin_port = port;
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s == -1) {
+ warn("Can't create socket");
+ goto cleanup_url_get;
+ }
+
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ warn("Can't connect to %s", host);
+ goto cleanup_url_get;
+ }
+
+ /*
+ * Construct and send the request. We're expecting a return
+ * status of "200". Proxy requests don't want leading /.
+ */
+ if (!proxy)
+ printf("Requesting %s\n", origline);
+ else
+ printf("Requesting %s (via %s)\n", origline, proxyenv);
+ snprintf(buf, sizeof(buf), "GET %s%s HTTP/1.0\n\n",
+ proxy ? "" : "/", path);
+ buflen = strlen(buf);
+ if (write(s, buf, buflen) < buflen) {
+ warn("Writing HTTP request");
+ goto cleanup_url_get;
+ }
+ memset(buf, 0, sizeof(buf));
+ for (i = 0, buflen = sizeof(buf), cp = buf; i < buflen; cp++, i++) {
+ if (read(s, cp, 1) != 1)
+ goto improper;
+ if (*cp == '\r')
+ continue;
+ if (*cp == '\n')
+ break;
+ }
+ buf[buflen - 1] = '\0'; /* sanity */
+ cp = strchr(buf, ' ');
+ if (cp == NULL)
+ goto improper;
+ else
+ cp++;
+ if (strncmp(cp, "200", 3)) {
+ warnx("Error retrieving file: %s", cp);
+ goto cleanup_url_get;
+ }
+
+ /*
+ * Read the rest of the header.
+ */
+ memset(buf, 0, sizeof(buf));
+ c = '\0';
+ for (i = 0, buflen = sizeof(buf), cp = buf; i < buflen; cp++, i++) {
+ if (read(s, cp, 1) != 1)
+ goto improper;
+ if (*cp == '\r')
+ continue;
+ if (*cp == '\n' && c == '\n')
+ break;
+ c = *cp;
+ }
+ buf[buflen - 1] = '\0'; /* sanity */
+
+ /*
+ * Look for the "Content-length: " header.
+ */
+#define CONTENTLEN "Content-Length: "
+ for (cp = buf; *cp != '\0'; cp++) {
+ if (tolower((unsigned char)*cp) == 'c' &&
+ strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0)
+ break;
+ }
+ if (*cp == '\0')
+ goto improper;
+ cp += sizeof(CONTENTLEN) - 1;
+ cp2 = strchr(cp, '\n');
+ if (cp2 == NULL)
+ goto improper;
+ else
+ *cp2 = '\0';
+ filesize = atoi(cp);
+ if (filesize < 1)
+ goto improper;
+
+ /* Open the output file. */
+ out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if (out < 0) {
+ warn("Can't open %s", savefile);
+ goto cleanup_url_get;
+ }
+
+ /* Trap signals */
+ oldintr = NULL;
+ if (setjmp(httpabort)) {
+ if (oldintr)
+ (void)signal(SIGINT, oldintr);
+ goto cleanup_url_get;
+ }
+ oldintr = signal(SIGINT, aborthttp);
+
+ bytes = 0;
+ hashbytes = mark;
+ progressmeter(-1);
+
+ /* Finally, suck down the file. */
+ i = 0;
+ while ((len = read(s, buf, sizeof(buf))) > 0) {
+ bytes += len;
+ for (cp = buf; len > 0; len -= i, cp += i) {
+ if ((i = write(out, cp, len)) == -1) {
+ warn("Writing %s", savefile);
+ goto cleanup_url_get;
+ }
+ else if (i == 0)
+ break;
+ }
+ if (hash && !progress) {
+ while (bytes >= hashbytes) {
+ (void)putchar('#');
+ hashbytes += mark;
+ }
+ (void)fflush(stdout);
+ }
+ }
+ if (hash && !progress && bytes > 0) {
+ if (bytes < mark)
+ (void)putchar('#');
+ (void)putchar('\n');
+ (void)fflush(stdout);
+ }
+ if (len != 0) {
+ warn("Reading from socket");
+ goto cleanup_url_get;
+ }
+ progressmeter(1);
+ if (verbose)
+ puts("Successfully retrieved file.");
+ (void)signal(SIGINT, oldintr);
+
+ close(s);
+ close(out);
+ if (proxy)
+ free(proxy);
+ free(line);
+ return (0);
+
+improper:
+ warnx("Improper response from %s", host);
+cleanup_url_get:
+ if (s != -1)
+ close(s);
+ if (proxy)
+ free(proxy);
+ free(line);
+ return (-1);
+}
+
+/*
+ * Abort a http retrieval
+ */
+void
+aborthttp(notused)
+ int notused;
+{
+
+ alarmtimer(0);
+ puts("\nhttp fetch aborted.");
+ (void)fflush(stdout);
+ longjmp(httpabort, 1);
+}
+
+/*
+ * Retrieve multiple files from the command line, transferring
+ * files of the form "host:path", "ftp://host/path" using the
+ * ftp protocol, and files of the form "http://host/path" using
+ * the http protocol.
+ * If path has a trailing "/", then return (-1);
+ * the path will be cd-ed into and the connection remains open,
+ * and the function will return -1 (to indicate the connection
+ * is alive).
+ * If an error occurs the return value will be the offset+1 in
+ * argv[] of the file that caused a problem (i.e, argv[x]
+ * returns x+1)
+ * Otherwise, 0 is returned if all files retrieved successfully.
+ */
+int
+auto_fetch(argc, argv)
+ int argc;
+ char *argv[];
+{
+ static char lasthost[MAXHOSTNAMELEN];
+ char *xargv[5];
+ char *cp, *line, *host, *dir, *file, *portnum;
+ char *user, *pass;
+ char *ftpproxy, *httpproxy;
+ int rval, xargc, argpos;
+ int dirhasglob, filehasglob;
+ char rempath[MAXPATHLEN];
+
+ argpos = 0;
+
+ if (setjmp(toplevel)) {
+ if (connected)
+ disconnect(0, NULL);
+ return (argpos + 1);
+ }
+ (void)signal(SIGINT, (sig_t)intr);
+ (void)signal(SIGPIPE, (sig_t)lostpeer);
+
+ ftpproxy = getenv(FTP_PROXY);
+ httpproxy = getenv(HTTP_PROXY);
+
+ /*
+ * Loop through as long as there's files to fetch.
+ */
+ for (rval = 0; (rval == 0) && (argpos < argc); free(line), argpos++) {
+ if (strchr(argv[argpos], ':') == NULL)
+ break;
+ host = dir = file = portnum = user = pass = NULL;
+
+ /*
+ * We muck with the string, so we make a copy.
+ */
+ line = strdup(argv[argpos]);
+ if (line == NULL)
+ errx(1, "Can't allocate memory for auto-fetch.");
+
+ /*
+ * Try HTTP URL-style arguments first.
+ */
+ if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
+ if (url_get(line, httpproxy) == -1)
+ rval = argpos + 1;
+ continue;
+ }
+
+ /*
+ * Try FTP URL-style arguments next. If ftpproxy is
+ * set, use url_get() instead of standard ftp.
+ * Finally, try host:file.
+ */
+ host = line;
+ if (strncasecmp(line, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
+ if (ftpproxy) {
+ if (url_get(line, ftpproxy) == -1)
+ rval = argpos + 1;
+ continue;
+ }
+ host += sizeof(FTP_URL) - 1;
+ dir = strchr(host, '/');
+
+ /* look for [user:pass@]host[:port] */
+ pass = strpbrk(host, ":@/");
+ if (pass == NULL || *pass == '/') {
+ pass = NULL;
+ goto parsed_url;
+ }
+ if (pass == host || *pass == '@') {
+bad_ftp_url:
+ warnx("Invalid URL: %s", argv[argpos]);
+ rval = argpos + 1;
+ continue;
+ }
+ *pass++ = '\0';
+ cp = strpbrk(pass, ":@/");
+ if (cp == NULL || *cp == '/') {
+ portnum = pass;
+ pass = NULL;
+ goto parsed_url;
+ }
+ if (EMPTYSTRING(cp) || *cp == ':')
+ goto bad_ftp_url;
+ *cp++ = '\0';
+ user = host;
+ if (EMPTYSTRING(user))
+ goto bad_ftp_url;
+ host = cp;
+ portnum = strchr(host, ':');
+ if (portnum != NULL)
+ *portnum++ = '\0';
+parsed_url:
+ } else { /* classic style `host:file' */
+ dir = strchr(host, ':');
+ }
+ if (EMPTYSTRING(host)) {
+ rval = argpos + 1;
+ continue;
+ }
+
+ /*
+ * If cp is NULL, the file wasn't specified
+ * (URL looked something like ftp://host)
+ */
+ if (dir != NULL)
+ *dir++ = '\0';
+
+ /*
+ * Extract the file and (if present) directory name.
+ */
+ if (! EMPTYSTRING(dir)) {
+ cp = strrchr(dir, '/');
+ if (cp != NULL) {
+ *cp++ = '\0';
+ file = cp;
+ } else {
+ file = dir;
+ dir = NULL;
+ }
+ }
+ if (debug)
+ printf("user %s:%s host %s port %s dir %s file %s\n",
+ user, pass, host, portnum, dir, file);
+
+ /*
+ * Set up the connection if we don't have one.
+ */
+ if (strcmp(host, lasthost) != 0) {
+ int oautologin;
+
+ (void)strcpy(lasthost, host);
+ if (connected)
+ disconnect(0, NULL);
+ xargv[0] = __progname;
+ xargv[1] = host;
+ xargv[2] = NULL;
+ xargc = 2;
+ if (! EMPTYSTRING(portnum)) {
+ xargv[2] = portnum;
+ xargv[3] = NULL;
+ xargc = 3;
+ }
+ oautologin = autologin;
+ if (user != NULL)
+ autologin = 0;
+ setpeer(xargc, xargv);
+ autologin = oautologin;
+ if ((connected == 0)
+ || ((connected == 1) && !login(host, user, pass)) ) {
+ warnx("Can't connect or login to host `%s'",
+ host);
+ rval = argpos + 1;
+ continue;
+ }
+
+ /* Always use binary transfers. */
+ setbinary(0, NULL);
+ }
+ /* cd back to '/' */
+ xargv[0] = "cd";
+ xargv[1] = "/";
+ xargv[2] = NULL;
+ cd(2, xargv);
+ if (! dirchange) {
+ rval = argpos + 1;
+ continue;
+ }
+
+ dirhasglob = filehasglob = 0;
+ if (doglob) {
+ if (! EMPTYSTRING(dir) &&
+ strpbrk(dir, "*?[]{}") != NULL)
+ dirhasglob = 1;
+ if (! EMPTYSTRING(file) &&
+ strpbrk(file, "*?[]{}") != NULL)
+ filehasglob = 1;
+ }
+
+ /* Change directories, if necessary. */
+ if (! EMPTYSTRING(dir) && !dirhasglob) {
+ xargv[0] = "cd";
+ xargv[1] = dir;
+ xargv[2] = NULL;
+ cd(2, xargv);
+ if (! dirchange) {
+ rval = argpos + 1;
+ continue;
+ }
+ }
+
+ if (EMPTYSTRING(file)) {
+ rval = -1;
+ continue;
+ }
+
+ if (!verbose)
+ printf("Retrieving %s/%s\n", dir ? dir : "", file);
+
+ if (dirhasglob) {
+ snprintf(rempath, sizeof(rempath), "%s/%s", dir, file);
+ file = rempath;
+ }
+
+ /* Fetch the file(s). */
+ xargv[0] = "get";
+ xargv[1] = file;
+ xargv[2] = NULL;
+ if (dirhasglob || filehasglob) {
+ int ointeractive;
+
+ ointeractive = interactive;
+ interactive = 0;
+ xargv[0] = "mget";
+ mget(2, xargv);
+ interactive = ointeractive;
+ } else
+ get(2, xargv);
+
+ if ((code / 100) != COMPLETE)
+ rval = argpos + 1;
+ }
+ if (connected && rval != -1)
+ disconnect(0, NULL);
+ return (rval);
+}
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index 79dcbae..c288d48 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -1,3 +1,6 @@
+.\" $Id$
+.\" $NetBSD: ftp.1,v 1.21 1997/06/10 21:59:58 lukem Exp $
+.\"
.\" Copyright (c) 1985, 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -31,7 +34,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd October 9, 1994
+.Dd February 23, 1997
.Dt FTP 1
.Os BSD 4.2
.Sh NAME
@@ -40,66 +43,108 @@
.Tn ARPANET
file transfer program
.Sh SYNOPSIS
-.Nm ftp
-.Op Fl v
+.Nm
+.Op Fl a
.Op Fl d
+.Op Fl e
+.Op Fl g
.Op Fl i
.Op Fl n
-.Op Fl g
-.Op Ar host
+.Op Fl U
+.Op Fl p
+.Op Fl P Ar port
+.Op Fl t
+.Op Fl v
+.Op Fl V
+.Op Ar host Op Ar port
+.Nm ftp
+ftp://[\fIuser\fR:\fIpassword\fR@]\fIhost\fR[:\fIport\fR]/\fIfile\fR[/]
+.Nm ftp
+http://\fIhost\fR[:\fIport\fR]/\fIfile\fR
+.Nm ftp
+\fIhost\fR:[/\fIpath\fR/]\fIfile\fR[/]
.Sh DESCRIPTION
-.Nm Ftp
+.Nm
is the user interface to the
.Tn ARPANET
standard File Transfer Protocol.
The program allows a user to transfer files to and from a
remote network site.
.Pp
+The latter three usage formats will fetch a file using either the
+HTTP or FTP protocols into the current directory.
+This is ideal for scripts.
+Refer to
+.Sx AUTO-FETCHING FILES
+below for more information.
+.Pp
Options may be specified at the command line, or to the
command interpreter.
-.Bl -tag -width flag
-.It Fl v
-Verbose option forces
-.Nm ftp
-to show all responses from the remote server, as well
-as report on data transfer statistics.
+.Bl -tag -width "port "
+.It Fl a
+Causes
+.Nm
+to bypass normal login procedure, and use an anonymous login instead.
+.It Fl d
+Enables debugging.
+.It Fl e
+Disables command line editing.
+.It Fl g
+Disables file name globbing.
+.It Fl U
+Disable data port range restrictions.
+.It Fl i
+Turns off interactive prompting during
+multiple file transfers.
.It Fl n
Restrains
-.Nm ftp
-from attempting \*(Lqauto-login\*(Rq upon initial connection.
+.Nm
+from attempting
+.Dq auto-login
+upon initial connection.
If auto-login is enabled,
-.Nm ftp
+.Nm
will check the
.Pa .netrc
(see below) file in the user's home directory for an entry describing
an account on the remote machine.
If no entry exists,
-.Nm ftp
+.Nm
will prompt for the remote machine login name (default is the user
identity on the local machine), and, if necessary, prompt for a password
and an account with which to login.
-.It Fl i
-Turns off interactive prompting during
-multiple file transfers.
-.It Fl d
-Enables debugging.
-.It Fl g
-Disables file name globbing.
+.It Fl p
+Enable passive mode operation for use behind connection filtering firewalls.
+.It Fl P Ar port
+Sets the port number to
+.Ar port .
+.It Fl t
+Enables packet tracing.
+.It Fl v
+Enable verbose mode.
+This is the default if input is from a terminal.
+Forces
+.Nm
+to show all responses from the remote server, as well
+as report on data transfer statistics.
+.It Fl V
+Disable verbose mode, overriding the default of enabled when input
+is from a terminal.
.El
.Pp
The client host with which
-.Nm ftp
+.Nm
is to communicate may be specified on the command line.
If this is done,
-.Nm ftp
+.Nm
will immediately attempt to establish a connection to an
.Tn FTP
server on that host; otherwise,
-.Nm ftp
+.Nm
will enter its command interpreter and await instructions
from the user.
When
-.Nm ftp
+.Nm
is awaiting commands from the user the prompt
.Ql ftp>
is provided to the user.
@@ -157,7 +202,7 @@ Terminate the
.Tn FTP
session with the remote server
and exit
-.Nm ftp .
+.Nm ftp .
An end of file will also terminate the session and exit.
.It Ic case
Toggle remote computer file name case mapping during
@@ -171,7 +216,7 @@ to lower case.
.It Ic \&cd Ar remote-directory
Change the working directory on the remote machine
to
-.Ar remote-directory .
+.Ar remote-directory .
.It Ic cdup
Change the remote machine working directory to the parent of the
current remote machine working directory.
@@ -179,8 +224,8 @@ current remote machine working directory.
Change the permission modes of the file
.Ar file-name
on the remote
-sytem to
-.Ar mode .
+system to
+.Ar mode .
.It Ic close
Terminate the
.Tn FTP
@@ -216,42 +261,54 @@ If an optional
.Ar debug-value
is specified it is used to set the debugging level.
When debugging is on,
-.Nm ftp
+.Nm
prints each command sent to the remote machine, preceded
by the string
.Ql \-\->
-.It Xo
-.Ic dir
-.Op Ar remote-directory
-.Op Ar local-file
-.Xc
-Print a listing of the directory contents in the
-directory,
-.Ar remote-directory ,
-and, optionally, placing the output in
-.Ar local-file .
+.It Ic dir Op Ar remote-directory Op Ar local-file
+Print a listing of the contents of a
+directory on the remote machine.
+The listing includes any system-dependent information that the server
+chooses to include; for example, most
+.Ux
+systems will produce
+output from the command
+.Ql ls \-l .
+(See also
+.Ic ls . )
+If
+.Ar remote-directory
+is left unspecified, the current working directory is used.
If interactive prompting is on,
-.Nm ftp
+.Nm
will prompt the user to verify that the last argument is indeed the
target local file for receiving
.Ic dir
output.
-If no directory is specified, the current working
-directory on the remote machine is used.
-If no local
-file is specified, or
+If no local file is specified, or if
.Ar local-file
is
-.Fl ,
-output comes to the terminal.
+.Sq Fl ,
+the output is sent to the terminal.
.It Ic disconnect
A synonym for
-.Ar close .
+.Ic close .
+.It Ic edit
+Toggle command line editing, and context sensitive command and file
+completion.
+This is automatically enabled if input is from a terminal, and
+disabled otherwise.
+.It Ic exit
+A synonym for
+.Ic bye .
+.It Ic ftp Ar host Op Ar port
+A synonym for
+.Ic open .
.It Ic form Ar format
Set the file transfer
.Ic form
to
-.Ar format .
+.Ar format .
The default format is \*(Lqfile\*(Rq.
.It Ic get Ar remote-file Op Ar local-file
Retrieve the
@@ -278,7 +335,7 @@ Toggle filename expansion for
.Ic mdelete ,
.Ic mget
and
-.Ic mput .
+.Ic mput .
If globbing is turned off with
.Ic glob ,
the file name arguments
@@ -308,15 +365,18 @@ That can be done by
transferring a
.Xr tar 1
archive of the subtree (in binary mode).
-.It Ic hash
+.It Ic hash Op Ar size
Toggle hash-sign (``#'') printing for each data block
transferred.
-The size of a data block is 1024 bytes.
+The size of a data block defaults to 1024 bytes.
+This can be changed by specifying
+.Ar size
+in bytes.
.It Ic help Op Ar command
Print an informative message about the meaning of
-.Ar command .
+.Ar command .
If no argument is given,
-.Nm ftp
+.Nm
prints a list of the known commands.
.It Ic idle Op Ar seconds
Set the inactivity timer on the remote server to
@@ -331,34 +391,27 @@ If
no
.Ar directory
is specified, the user's home directory is used.
-.It Xo
-.Ic \&ls
-.Op Ar remote-directory
-.Op Ar local-file
-.Xc
-Print a listing of the contents of a
+.It Ic less Ar file
+A synonym for
+.Ic page .
+.It Ic lpwd
+Print the working directory on the local machine.
+.It Ic \&ls Op Ar remote-directory Op Ar local-file
+Print a list of the files in a
directory on the remote machine.
-The listing includes any system-dependent information that the server
-chooses to include; for example, most
-.Ux
-systems will produce
-output from the command
-.Ql ls \-l .
-(See also
-.Ic nlist . )
If
.Ar remote-directory
is left unspecified, the current working directory is used.
If interactive prompting is on,
-.Nm ftp
+.Nm
will prompt the user to verify that the last argument is indeed the
target local file for receiving
-.Ic \&ls
+.Ic ls
output.
If no local file is specified, or if
.Ar local-file
is
-.Sq Fl ,
+.Fl ,
the output is sent to the terminal.
.It Ic macdef Ar macro-name
Define a macro.
@@ -391,7 +444,7 @@ Like
.Ic dir ,
except multiple remote files may be specified.
If interactive prompting is on,
-.Nm ftp
+.Nm
will prompt the user to verify that the last argument is indeed the
target local file for receiving
.Ic mdir
@@ -421,13 +474,13 @@ new local directories can be created with
Make a directory on the remote machine.
.It Ic mls Ar remote-files local-file
Like
-.Ic nlist ,
+.Ic ls ,
except multiple remote files may be specified,
and the
.Ar local-file
must be specified.
If interactive prompting is on,
-.Nm ftp
+.Nm
will prompt the user to verify that the last argument is indeed the
target local file for receiving
.Ic mls
@@ -436,10 +489,13 @@ output.
Set the file transfer
.Ic mode
to
-.Ar mode-name .
+.Ar mode-name .
The default mode is \*(Lqstream\*(Rq mode.
.It Ic modtime Ar file-name
Show the last modification time of the file on the remote machine.
+.It Ic more Ar file
+A synonym for
+.Ic page .
.It Ic mput Ar local-files
Expand wild cards in the list of local files given as arguments
and do a
@@ -453,35 +509,20 @@ Resulting file names will then be processed according to
and
.Ic nmap
settings.
+.It Ic msend Ar local-files
+A synonym for
+.Ic mput .
.It Ic newer Ar file-name
Get the file only if the modification time of the remote file is more
recent that the file on the current system.
If the file does not
exist on the current system, the remote file is considered
-.Ic newer .
+.Ic newer .
Otherwise, this command is identical to
-.Ar get .
-.It Xo
-.Ic nlist
-.Op Ar remote-directory
-.Op Ar local-file
-.Xc
-Print a list of the files in a
-directory on the remote machine.
-If
-.Ar remote-directory
-is left unspecified, the current working directory is used.
-If interactive prompting is on,
-.Nm ftp
-will prompt the user to verify that the last argument is indeed the
-target local file for receiving
-.Ic nlist
-output.
-If no local file is specified, or if
-.Ar local-file
-is
-.Fl ,
-the output is sent to the terminal.
+.Ar get .
+.It Ic nlist Op Ar remote-directory Op Ar local-file
+A synonym for
+.Ic ls .
.It Ic nmap Op Ar inpattern outpattern
Set or unset the filename mapping mechanism.
If no arguments are specified, the filename mapping mechanism is unset.
@@ -502,7 +543,7 @@ with different file naming conventions or practices.
The mapping follows the pattern set by
.Ar inpattern
and
-.Ar outpattern .
+.Ar outpattern .
.Op Ar Inpattern
is a template for incoming filenames (which may have already been
processed according to the
@@ -512,7 +553,7 @@ and
settings).
Variable templating is accomplished by including the
sequences `$1', `$2', ..., `$9' in
-.Ar inpattern .
+.Ar inpattern .
Use `\\' to prevent this special treatment of the `$' character.
All other characters are treated literally, and are used to determine the
.Ic nmap
@@ -576,7 +617,7 @@ with different file naming conventions or practices.
Characters in a filename matching a character in
.Ar inchars
are replaced with the corresponding character in
-.Ar outchars .
+.Ar outchars .
If the character's position in
.Ar inchars
is longer than the length of
@@ -589,18 +630,25 @@ Establish a connection to the specified
server.
An optional port number may be supplied,
in which case,
-.Nm ftp
+.Nm
will attempt to contact an
.Tn FTP
server at that port.
If the
.Ic auto-login
option is on (default),
-.Nm ftp
+.Nm
will also attempt to automatically log the user in to
the
.Tn FTP
server (see below).
+.It Ic page Ar file
+Retrieve
+.Ic file
+and display with the program defined in
+.Ev PAGER
+(which defaults to
+.Xr less 1 ).
.It Ic passive
Toggle passive mode. If passive mode is turned on
(default is off), the ftp client will
@@ -616,12 +664,25 @@ port and the client connects to it. When using the more traditional
.Dv PORT
command, the client listens on a port and sends that address to the remote
server, who connects back to it. Passive mode is useful when using
-.Nm ftp
+.Nm
through a gateway router or host that controls the directionality of
traffic.
(Note that though ftp servers are required to support the
.Dv PASV
command by RFC 1123, some do not.)
+.It Ic preserve
+Toggle preservation of modification times on retrieved files.
+.It Ic progress
+Toggle display of transfer progress bar.
+The progress bar will be disabled for a transfer that has
+.Ar local-file
+as
+.Sq Fl
+or a command that starts with
+.Sq \&| .
+Refer to
+.Sx FILE NAMING CONVENTIONS
+for more information.
.It Ic prompt
Toggle interactive prompting.
Interactive prompting
@@ -634,6 +695,29 @@ or
will transfer all files, and any
.Ic mdelete
will delete all files.
+.Pp
+When prompting is on, the following commands are available at a prompt:
+.Bl -tag -width 2n -offset indent
+.It Ic n
+Do not transfer the file.
+.It Ic a
+Answer
+.Sq yes
+to the current file, and automatically answer
+.Sq yes
+to any remaining files for the current command.
+.It Ic p
+Answer
+.Sq yes
+to the current file, and turn off prompt mode
+(as is
+.Dq prompt off
+had been given).
+.El
+.Pp
+Any other reponse will answer
+.Sq yes
+to the current file.
.It Ic proxy Ar ftp-command
Execute an ftp command on a secondary control connection.
This command allows simultaneous connection to two remote ftp
@@ -682,19 +766,20 @@ current settings for
.Ic format ,
.Ic mode ,
and
-.Ic structure .
+.Ic structure .
.It Ic pwd
Print the name of the current working directory on the remote
machine.
.It Ic quit
A synonym for
-.Ic bye .
+.Ic bye .
.It Ic quote Ar arg1 arg2 ...
The arguments specified are sent, verbatim, to the remote
.Tn FTP
server.
.It Ic recv Ar remote-file Op Ar local-file
-A synonym for get.
+A synonym for
+.Ic get .
.It Ic reget Ar remote-file Op Ar local-file
Reget acts like get, except that if
.Ar local-file
@@ -717,22 +802,18 @@ server.
If a
.Ar command-name
is specified it is supplied to the server as well.
-.It Ic remotestatus Op Ar file-name
+.It Ic rstatus Op Ar file-name
With no arguments, show status of remote machine.
If
.Ar file-name
is specified, show status of
.Ar file-name
on remote machine.
-.It Xo
-.Ic rename
-.Op Ar from
-.Op Ar to
-.Xc
+.It Ic rename Op Ar from Op Ar to
Rename the file
.Ar from
on the remote machine, to the file
-.Ar to .
+.Ar to .
.It Ic reset
Clear reply queue.
This command re-synchronizes command/reply sequencing with the remote
@@ -746,11 +827,23 @@ or
.Ic put
at the
indicated
-.Ar marker .
+.Ar marker .
On
.Ux
systems, marker is usually a byte
offset into the file.
++.It Ic restrict
+Toggle data port range restrictions.
+When not operating in passive mode, the
+.Nm ftp ,
+client program requests that the remote server open a connection back
+to the client host on a separate data port. In previous versions, that
+remote port fell in the range 1024..4999. However, most firewall setups
+filter that range of TCP ports because other services reside there.
+The default behavior now is for the client to request that the server
+connect back to the client using the port range 40000..44999. Firewall
+administrators can chose to allow TCP connections in that range, if they
+deem it to not be a security risk.
.It Ic rmdir Ar directory-name
Delete a directory on the remote machine.
.It Ic runique
@@ -772,13 +865,14 @@ will not affect local files generated from a shell command
(see below).
The default value is off.
.It Ic send Ar local-file Op Ar remote-file
-A synonym for put.
+A synonym for
+.Ic put .
.It Ic sendport
Toggle the use of
.Dv PORT
commands.
By default,
-.Nm ftp
+.Nm
will attempt to use a
.Dv PORT
command when establishing
@@ -790,7 +884,7 @@ when performing multiple file transfers.
If the
.Dv PORT
command fails,
-.Nm ftp
+.Nm
will use the default data port.
When the use of
.Dv PORT
@@ -815,7 +909,7 @@ Return size of
on remote machine.
.It Ic status
Show the current status of
-.Nm ftp .
+.Nm ftp .
.It Ic struct Op Ar struct-name
Set the file transfer
.Ar structure
@@ -843,21 +937,20 @@ Toggle packet tracing.
Set the file transfer
.Ic type
to
-.Ar type-name .
+.Ar type-name .
If no type is specified, the current type
is printed.
The default type is network
.Tn ASCII .
.It Ic umask Op Ar newmask
Set the default umask on the remote server to
-.Ar newmask .
+.Ar newmask .
If
.Ar newmask
is omitted, the current umask is printed.
.It Xo
.Ic user Ar user-name
-.Op Ar password
-.Op Ar account
+.Op Ar password Op Ar account
.Xc
Identify yourself to the remote
.Tn FTP
@@ -865,7 +958,7 @@ server.
If the
.Ar password
is not specified and the server requires it,
-.Nm ftp
+.Nm
will prompt the user for it (after disabling local echo).
If an
.Ar account
@@ -880,7 +973,7 @@ be relayed to the remote server after the login sequence
is completed if the remote server did not require it
for logging in.
Unless
-.Nm ftp
+.Nm
is invoked with \*(Lqauto-login\*(Rq disabled, this
process is done automatically on initial connection to
the
@@ -898,11 +991,93 @@ regarding the efficiency of the transfer are reported.
By default,
verbose is on.
.It Ic ? Op Ar command
-A synonym for help.
+A synonym for
+.Ic help .
.El
.Pp
Command arguments which have embedded spaces may be quoted with
quote `"' marks.
+.Pp
+Commands which toggle settings can take an explicit
+.Ic on
+or
+.Ic off
+argument to force the setting appropriately.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Dq status
+argument of
+.Xr stty 1 )
+signal whilst a transfer is in progress, the current transfer rate
+statistics will be written to the standard error output, in the
+same format as the standard completion message.
+.Sh AUTO-FETCHING FILES
+In addition to standard commands, this version of
+.Nm
+supports an auto-fetch feature.
+To enable auto-fetch, simply pass the list of hostnames/files
+on the command line.
+.Pp
+The following formats are valid syntax for an auto-fetch element:
+.Bl -tag -width "host:/file"
+.It host:/file
+.Dq Classic
+ftp format
+.It ftp://[user:password@]host[:port]/file
+An ftp URL, retrieved using the ftp protocol if
+.Ev ftp_proxy
+isn't defined.
+Otherwise, transfer using http via the proxy defined in
+.Ev ftp_proxy .
+If
+.Ar user:password@
+is given and
+.Ev ftp_proxy
+isn't defined, login as
+.Ar user
+with a password of
+.Ar password .
+.It http://host[:port]/file
+An HTTP URL, retrieved using the http protocol.
+If
+.Ev http_proxy
+is defined, it is used as a URL to an HTTP proxy server.
+.El
+.Pp
+If a classic format or a ftp URL format has a trailing
+.Sq / ,
+then
+.Nm
+will connect to the site and
+.Ic cd
+to the directory given as the path, and leave the user in interactive
+mode ready for further input.
+.Pp
+If successive auto-fetch ftp elements refer to the same host, then
+the connection is maintained between transfers, reducing overhead on
+connection creation and deletion.
+.Pp
+If
+.Ic file
+contains a glob character and globbing is enabled,
+(see
+.Ic glob ) ,
+then the equivalent of
+.Ic "mget file"
+is performed.
+.Pp
+If the directory component of
+.Ic file
+contains no globbing characters,
+it is stored in the current directory as the
+.Xr basename 1
+of
+.Ic file .
+Otherwise, the remote name is used as the local name.
.Sh ABORTING A FILE TRANSFER
To abort a file transfer, use the terminal interrupt key
(usually Ctrl-C).
@@ -922,18 +1097,18 @@ prompt will not appear until the remote server has completed
sending the requested file.
.Pp
The terminal interrupt key sequence will be ignored when
-.Nm ftp
+.Nm
has completed any local processing and is awaiting a reply
from the remote server.
A long delay in this mode may result from the ABOR processing described
above, or from unexpected behavior by the remote server, including
violations of the ftp protocol.
If the delay results from unexpected remote server behavior, the local
-.Nm ftp
+.Nm
program must be killed by hand.
.Sh FILE NAMING CONVENTIONS
Files specified as arguments to
-.Nm ftp
+.Nm
commands are processed according to the following rules.
.Bl -enum
.It
@@ -949,7 +1124,7 @@ If the first character of the file name is
.Sq \&| ,
the
remainder of the argument is interpreted as a shell command.
-.Nm Ftp
+.Nm
then forks a shell, using
.Xr popen 3
with the argument supplied, and reads (writes) from the stdout
@@ -958,7 +1133,7 @@ If the shell command includes spaces, the argument
must be quoted; e.g.
\*(Lq" ls -lt"\*(Rq.
A particularly
-useful example of this mechanism is: \*(Lqdir more\*(Rq.
+useful example of this mechanism is: \*(Lqdir \&|more\*(Rq.
.It
Failing the above checks, if ``globbing'' is enabled,
local file names are expanded
@@ -968,7 +1143,7 @@ c.f. the
.Ic glob
command.
If the
-.Nm ftp
+.Nm
command expects a single local file (.e.g.
.Ic put ) ,
only the first filename generated by the "globbing" operation is used.
@@ -1013,19 +1188,19 @@ may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary),
and
.Tn PDP Ns -20's
mostly).
-.Nm Ftp
+.Nm
supports the ascii and image types of file transfer,
plus local byte size 8 for
.Ic tenex
mode transfers.
.Pp
-.Nm Ftp
+.Nm
supports only the default values for the remaining
file transfer parameters:
.Ic mode ,
.Ic form ,
and
-.Ic struct .
+.Ic struct .
.Sh THE .netrc FILE
The
.Pa .netrc
@@ -1043,7 +1218,7 @@ The auto-login process searches the
file for a
.Ic machine
token that matches the remote machine specified on the
-.Nm ftp
+.Nm
command line or as an
.Ic open
command argument.
@@ -1095,7 +1270,7 @@ Note that if this token is present in the
file for any user other
than
.Ar anonymous ,
-.Nm ftp
+.Nm
will abort the auto-login process if the
.Pa .netrc
is readable by
@@ -1110,7 +1285,7 @@ command if it does not.
.It Ic macdef Ar name
Define a macro.
This token functions like the
-.Nm ftp
+.Nm
.Ic macdef
command functions.
A macro is defined with the specified name; its contents begin with the
@@ -1123,24 +1298,69 @@ If a macro named
is defined, it is automatically executed as the last step in the
auto-login process.
.El
+.Sh COMMAND LINE EDITING
+.Nm
+supports interactive command line editing, via the
+.Xr editline 3
+library.
+It is enabled with the
+.Ic edit
+command, and is enabled by default if input is from a tty.
+Previous lines can be recalled and edited with the arrow keys,
+and other GNU Emacs-style editing keys may be used as well.
+.Pp
+The
+.Xr editline 3
+library is configured with a
+.Pa .editrc
+file - refer to
+.Xr editrc 5
+for more information.
+.Pp
+An extra key binding is available to
+.Nm
+to provide context sensitive command and filename completion
+(including remote file completion).
+To use this, bind a key to the
+.Xr editline 3
+command
+.Ic ftp-complete .
+By default, this is bound to the TAB key.
.Sh ENVIRONMENT
-.Nm Ftp
+.Nm
utilizes the following environment variables.
-.Bl -tag -width Fl
+.Bl -tag -width "http_proxy"
.It Ev HOME
For default location of a
.Pa .netrc
file, if one exists.
+.It Ev PAGER
+Used by
+.Ic page
+to display files.
.It Ev SHELL
For default shell.
+.It Ev ftp_proxy
+URL of FTP proxy to use when making FTP URL requests
+(if not defined, use the standard ftp protocol).
+.It Ev http_proxy
+URL of HTTP proxy to use when making HTTP URL requests.
.El
.Sh SEE ALSO
+.Xr editrc 5 ,
.Xr ftpd 8
.Sh HISTORY
The
-.Nm ftp
+.Nm
command appeared in
.Bx 4.2 .
+.Pp
+Various features such as command line editing, context sensitive
+command and file completion, dynamic progress bar, automatic
+fetching of files, ftp and http URLs, and modification time
+preservation were implemented in
+.Nx 1.3
+by Luke Mewburn, with assistance from Jason Thorpe.
.Sh BUGS
Correct execution of many commands depends upon proper behavior
by the remote server.
diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c
index 90eccb0..f3914c1 100644
--- a/usr.bin/ftp/ftp.c
+++ b/usr.bin/ftp/ftp.c
@@ -1,3 +1,6 @@
+/* $Id$ */
+/* $NetBSD: ftp.c,v 1.25 1997/04/14 09:09:22 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -32,15 +35,16 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
+#else
+static char rcsid[] = "$Id$";
+#endif
#endif /* not lint */
-#include <sys/param.h>
+#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/file.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -52,20 +56,19 @@ static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#include <ctype.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
#include <netdb.h>
-#include <pwd.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
#include <varargs.h>
+#endif
#include "ftp_var.h"
-extern int h_errno;
-
struct sockaddr_in hisctladdr;
struct sockaddr_in data_addr;
int data = -1;
@@ -81,18 +84,18 @@ FILE *cin, *cout;
char *
hookup(host, port)
- char *host;
+ const char *host;
int port;
{
struct hostent *hp = 0;
int s, len, tos;
- static char hostnamebuf[80];
+ static char hostnamebuf[MAXHOSTNAMELEN];
- memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
- hisctladdr.sin_addr.s_addr = inet_addr(host);
- if (hisctladdr.sin_addr.s_addr != -1) {
+ memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
+ if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
hisctladdr.sin_family = AF_INET;
- (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
+ (void)strncpy(hostnamebuf, host, sizeof(hostnamebuf) - 1);
+ hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
} else {
hp = gethostbyname(host);
if (hp == NULL) {
@@ -101,9 +104,9 @@ hookup(host, port)
return ((char *) 0);
}
hisctladdr.sin_family = hp->h_addrtype;
- memmove((caddr_t)&hisctladdr.sin_addr,
- hp->h_addr_list[0], hp->h_length);
- (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
+ memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
+ (void)strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf) - 1);
+ hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
}
hostname = hostnamebuf;
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
@@ -113,7 +116,8 @@ hookup(host, port)
return (0);
}
hisctladdr.sin_port = port;
- while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
+ while (connect(s, (struct sockaddr *)&hisctladdr,
+ sizeof(hisctladdr)) < 0) {
if (hp && hp->h_addr_list[1]) {
int oerrno = errno;
char *ia;
@@ -122,11 +126,10 @@ hookup(host, port)
errno = oerrno;
warn("connect to address %s", ia);
hp->h_addr_list++;
- memmove((caddr_t)&hisctladdr.sin_addr,
- hp->h_addr_list[0], hp->h_length);
- fprintf(stdout, "Trying %s...\n",
- inet_ntoa(hisctladdr.sin_addr));
- (void) close(s);
+ memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
+ printf("Trying %s...\n",
+ inet_ntoa(hisctladdr.sin_addr));
+ (void)close(s);
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
if (s < 0) {
warn("socket");
@@ -139,7 +142,7 @@ hookup(host, port)
code = -1;
goto bad;
}
- len = sizeof (myctladdr);
+ len = sizeof(myctladdr);
if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
warn("getsockname");
code = -1;
@@ -155,9 +158,9 @@ hookup(host, port)
if (cin == NULL || cout == NULL) {
warnx("fdopen failed.");
if (cin)
- (void) fclose(cin);
+ (void)fclose(cin);
if (cout)
- (void) fclose(cout);
+ (void)fclose(cout);
code = -1;
goto bad;
}
@@ -165,9 +168,9 @@ hookup(host, port)
printf("Connected to %s.\n", hostname);
if (getreply(0) > 2) { /* read startup message from server */
if (cin)
- (void) fclose(cin);
+ (void)fclose(cin);
if (cout)
- (void) fclose(cout);
+ (void)fclose(cout);
code = -1;
goto bad;
}
@@ -184,134 +187,90 @@ hookup(host, port)
return (hostname);
bad:
- (void) close(s);
+ (void)close(s);
return ((char *)0);
}
-int
-login(host)
- char *host;
-{
- char tmp[80];
- char *user, *pass, *acct;
- int n, aflag = 0;
-
- user = pass = acct = 0;
- if (ruserpass(host, &user, &pass, &acct) < 0) {
- code = -1;
- return (0);
- }
- while (user == NULL) {
- char *myname = getlogin();
-
- if (myname == NULL) {
- struct passwd *pp = getpwuid(getuid());
-
- if (pp != NULL)
- myname = pp->pw_name;
- }
- if (myname)
- printf("Name (%s:%s): ", host, myname);
- else
- printf("Name (%s): ", host);
- (void) fgets(tmp, sizeof(tmp) - 1, stdin);
- tmp[strlen(tmp) - 1] = '\0';
- if (*tmp == '\0')
- user = myname;
- else
- user = tmp;
- }
- n = command("USER %s", user);
- if (n == CONTINUE) {
- if (pass == NULL)
- pass = getpass("Password:");
- n = command("PASS %s", pass);
- }
- if (n == CONTINUE) {
- aflag++;
- acct = getpass("Account:");
- n = command("ACCT %s", acct);
- }
- if (n != COMPLETE) {
- warnx("Login failed.");
- return (0);
- }
- if (!aflag && acct != NULL)
- (void) command("ACCT %s", acct);
- if (proxy)
- return (1);
- for (n = 0; n < macnum; ++n) {
- if (!strcmp("init", macros[n].mac_name)) {
- (void) strcpy(line, "$init");
- makeargv();
- domacro(margc, margv);
- break;
- }
- }
- return (1);
-}
-
void
-cmdabort()
+cmdabort(notused)
+ int notused;
{
- printf("\n");
- (void) fflush(stdout);
+ alarmtimer(0);
+ putchar('\n');
+ (void)fflush(stdout);
abrtflag++;
if (ptflag)
- longjmp(ptabort,1);
+ longjmp(ptabort, 1);
}
/*VARARGS*/
int
+#ifdef __STDC__
+command(const char *fmt, ...)
+#else
command(va_alist)
-va_dcl
+ va_dcl
+#endif
{
va_list ap;
- char *fmt;
int r;
sig_t oldintr;
+#ifndef __STDC__
+ const char *fmt;
+#endif
abrtflag = 0;
if (debug) {
- printf("---> ");
+ fputs("---> ", stdout);
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
va_start(ap);
- fmt = va_arg(ap, char *);
+ fmt = va_arg(ap, const char *);
+#endif
if (strncmp("PASS ", fmt, 5) == 0)
- printf("PASS XXXX");
- else
- vfprintf(stdout, fmt, ap);
+ fputs("PASS XXXX", stdout);
+ else if (strncmp("ACCT ", fmt, 5) == 0)
+ fputs("ACCT XXXX", stdout);
+ else
+ vprintf(fmt, ap);
va_end(ap);
- printf("\n");
- (void) fflush(stdout);
+ putchar('\n');
+ (void)fflush(stdout);
}
if (cout == NULL) {
- warn("No control connection for command");
+ warnx("No control connection for command.");
code = -1;
return (0);
}
oldintr = signal(SIGINT, cmdabort);
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
va_start(ap);
fmt = va_arg(ap, char *);
+#endif
vfprintf(cout, fmt, ap);
va_end(ap);
- fprintf(cout, "\r\n");
- (void) fflush(cout);
+ fputs("\r\n", cout);
+ (void)fflush(cout);
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
if (abrtflag && oldintr != SIG_IGN)
(*oldintr)(SIGINT);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
return (r);
}
-char reply_string[BUFSIZ]; /* last line of previous reply */
+char reply_string[BUFSIZ]; /* first line of previous reply */
int
getreply(expecteof)
int expecteof;
{
- int c, n;
+ char current_line[BUFSIZ]; /* last line of previous reply */
+ int c, n, line;
int dig;
int originalcode = 0, continuation = 0;
sig_t oldintr;
@@ -319,9 +278,9 @@ getreply(expecteof)
char *cp, *pt = pasv;
oldintr = signal(SIGINT, cmdabort);
- for (;;) {
+ for (line = 0 ;; line++) {
dig = n = code = 0;
- cp = reply_string;
+ cp = current_line;
while ((c = getc(cin)) != '\n') {
if (c == IAC) { /* handle telnet commands */
switch (c = getc(cin)) {
@@ -329,13 +288,13 @@ getreply(expecteof)
case WONT:
c = getc(cin);
fprintf(cout, "%c%c%c", IAC, DONT, c);
- (void) fflush(cout);
+ (void)fflush(cout);
break;
case DO:
case DONT:
c = getc(cin);
fprintf(cout, "%c%c%c", IAC, WONT, c);
- (void) fflush(cout);
+ (void)fflush(cout);
break;
default:
break;
@@ -345,14 +304,15 @@ getreply(expecteof)
dig++;
if (c == EOF) {
if (expecteof) {
- (void) signal(SIGINT,oldintr);
+ (void)signal(SIGINT, oldintr);
code = 221;
return (0);
}
lostpeer();
if (verbose) {
- printf("421 Service not available, remote server has closed connection\n");
- (void) fflush(stdout);
+ puts(
+"421 Service not available, remote server has closed connection.");
+ (void)fflush(stdout);
}
code = 421;
return (4);
@@ -360,9 +320,9 @@ getreply(expecteof)
if (c != '\r' && (verbose > 0 ||
(verbose > -1 && n == '5' && dig > 4))) {
if (proxflag &&
- (dig == 1 || dig == 5 && verbose == 0))
- printf("%s:",hostname);
- (void) putchar(c);
+ (dig == 1 || (dig == 5 && verbose == 0)))
+ printf("%s:", hostname);
+ (void)putchar(c);
}
if (dig < 4 && isdigit(c))
code = code * 10 + (c - '0');
@@ -385,12 +345,21 @@ getreply(expecteof)
}
if (n == 0)
n = c;
- if (cp < &reply_string[sizeof(reply_string) - 1])
+ if (cp < &current_line[sizeof(current_line) - 1])
*cp++ = c;
}
- if (verbose > 0 || verbose > -1 && n == '5') {
- (void) putchar(c);
- (void) fflush (stdout);
+ if (verbose > 0 || (verbose > -1 && n == '5')) {
+ (void)putchar(c);
+ (void)fflush (stdout);
+ }
+ if (line == 0) {
+ size_t len = cp - current_line;
+
+ if (len > sizeof(reply_string))
+ len = sizeof(reply_string);
+
+ (void)strncpy(reply_string, current_line, len);
+ reply_string[len] = '\0';
}
if (continuation && code != originalcode) {
if (originalcode == 0)
@@ -400,7 +369,7 @@ getreply(expecteof)
*cp = '\0';
if (n != '1')
cpend = 0;
- (void) signal(SIGINT,oldintr);
+ (void)signal(SIGINT, oldintr);
if (code == 421 || originalcode == 421)
lostpeer();
if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
@@ -424,32 +393,37 @@ empty(mask, sec)
jmp_buf sendabort;
void
-abortsend()
+abortsend(notused)
+ int notused;
{
+ alarmtimer(0);
mflag = 0;
abrtflag = 0;
- printf("\nsend aborted\nwaiting for remote to finish abort\n");
- (void) fflush(stdout);
+ puts("\nsend aborted\nwaiting for remote to finish abort.");
+ (void)fflush(stdout);
longjmp(sendabort, 1);
}
-#define HASHBYTES 1024
-
void
sendrequest(cmd, local, remote, printnames)
- char *cmd, *local, *remote;
+ const char *cmd, *local, *remote;
int printnames;
{
struct stat st;
- struct timeval start, stop;
int c, d;
- FILE *fin, *dout = 0, *popen();
+ FILE *fin, *dout = 0;
int (*closefunc) __P((FILE *));
- sig_t oldintr, oldintp;
- long bytes = 0, hashbytes = HASHBYTES;
+ sig_t oldinti, oldintr, oldintp;
+ off_t hashbytes;
char *lmode, buf[BUFSIZ], *bufp;
+ int oprogress;
+ hashbytes = mark;
+ direction = "sent";
+ bytes = 0;
+ filesize = -1;
+ oprogress = progress;
if (verbose && printnames) {
if (local && *local != '-')
printf("local: %s ", local);
@@ -465,59 +439,72 @@ sendrequest(cmd, local, remote, printnames)
closefunc = NULL;
oldintr = NULL;
oldintp = NULL;
+ oldinti = NULL;
lmode = "w";
if (setjmp(sendabort)) {
while (cpend) {
- (void) getreply(0);
+ (void)getreply(0);
}
if (data >= 0) {
- (void) close(data);
+ (void)close(data);
data = -1;
}
if (oldintr)
- (void) signal(SIGINT,oldintr);
+ (void)signal(SIGINT, oldintr);
if (oldintp)
- (void) signal(SIGPIPE,oldintp);
+ (void)signal(SIGPIPE, oldintp);
+ if (oldinti)
+ (void)signal(SIGINFO, oldinti);
+ progress = oprogress;
code = -1;
return;
}
oldintr = signal(SIGINT, abortsend);
- if (strcmp(local, "-") == 0)
+ oldinti = signal(SIGINFO, psummary);
+ if (strcmp(local, "-") == 0) {
fin = stdin;
- else if (*local == '|') {
- oldintp = signal(SIGPIPE,SIG_IGN);
+ progress = 0;
+ } else if (*local == '|') {
+ oldintp = signal(SIGPIPE, SIG_IGN);
fin = popen(local + 1, "r");
if (fin == NULL) {
warn("%s", local + 1);
- (void) signal(SIGINT, oldintr);
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGPIPE, oldintp);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
+ progress = 0;
closefunc = pclose;
} else {
fin = fopen(local, "r");
if (fin == NULL) {
warn("local: %s", local);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
closefunc = fclose;
if (fstat(fileno(fin), &st) < 0 ||
- (st.st_mode&S_IFMT) != S_IFREG) {
- fprintf(stdout, "%s: not a plain file.\n", local);
- (void) signal(SIGINT, oldintr);
+ (st.st_mode & S_IFMT) != S_IFREG) {
+ printf("%s: not a plain file.\n", local);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
fclose(fin);
code = -1;
return;
}
+ filesize = st.st_size;
}
if (initconn()) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGPIPE, oldintp);
code = -1;
+ progress = oprogress;
if (closefunc != NULL)
(*closefunc)(fin);
return;
@@ -529,6 +516,7 @@ sendrequest(cmd, local, remote, printnames)
(strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
int rc;
+ rc = -1;
switch (curtype) {
case TYPE_A:
rc = fseek(fin, (long) restart_point, SEEK_SET);
@@ -541,6 +529,7 @@ sendrequest(cmd, local, remote, printnames)
if (rc < 0) {
warn("local: %s", local);
restart_point = 0;
+ progress = oprogress;
if (closefunc != NULL)
(*closefunc)(fin);
return;
@@ -548,6 +537,7 @@ sendrequest(cmd, local, remote, printnames)
if (command("REST %ld", (long) restart_point)
!= CONTINUE) {
restart_point = 0;
+ progress = oprogress;
if (closefunc != NULL)
(*closefunc)(fin);
return;
@@ -557,18 +547,22 @@ sendrequest(cmd, local, remote, printnames)
}
if (remote) {
if (command("%s %s", cmd, remote) != PRELIM) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
+ progress = oprogress;
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGPIPE, oldintp);
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
} else
if (command("%s", cmd) != PRELIM) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
+ progress = oprogress;
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGPIPE, oldintp);
if (closefunc != NULL)
(*closefunc)(fin);
return;
@@ -576,36 +570,36 @@ sendrequest(cmd, local, remote, printnames)
dout = dataconn(lmode);
if (dout == NULL)
goto abort;
- (void) gettimeofday(&start, (struct timezone *)0);
+ progressmeter(-1);
oldintp = signal(SIGPIPE, SIG_IGN);
switch (curtype) {
case TYPE_I:
case TYPE_L:
errno = d = 0;
- while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
+ while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
bytes += c;
for (bufp = buf; c > 0; c -= d, bufp += d)
if ((d = write(fileno(dout), bufp, c)) <= 0)
break;
- if (hash) {
+ if (hash && (!progress || filesize < 0) ) {
while (bytes >= hashbytes) {
- (void) putchar('#');
- hashbytes += HASHBYTES;
+ (void)putchar('#');
+ hashbytes += mark;
}
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
}
- if (hash && bytes > 0) {
- if (bytes < HASHBYTES)
- (void) putchar('#');
- (void) putchar('\n');
- (void) fflush(stdout);
+ if (hash && (!progress || filesize < 0) && bytes > 0) {
+ if (bytes < mark)
+ (void)putchar('#');
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
if (c < 0)
warn("local: %s", local);
if (d < 0) {
- if (errno != EPIPE)
+ if (errno != EPIPE)
warn("netout");
bytes = -1;
}
@@ -614,28 +608,31 @@ sendrequest(cmd, local, remote, printnames)
case TYPE_A:
while ((c = getc(fin)) != EOF) {
if (c == '\n') {
- while (hash && (bytes >= hashbytes)) {
- (void) putchar('#');
- (void) fflush(stdout);
- hashbytes += HASHBYTES;
+ while (hash && (!progress || filesize < 0) &&
+ (bytes >= hashbytes)) {
+ (void)putchar('#');
+ (void)fflush(stdout);
+ hashbytes += mark;
}
if (ferror(dout))
break;
- (void) putc('\r', dout);
+ (void)putc('\r', dout);
bytes++;
}
- (void) putc(c, dout);
+ (void)putc(c, dout);
bytes++;
- /* if (c == '\r') { */
- /* (void) putc('\0', dout); // this violates rfc */
- /* bytes++; */
- /* } */
+#if 0 /* this violates RFC */
+ if (c == '\r') {
+ (void)putc('\0', dout);
+ bytes++;
+ }
+#endif
}
- if (hash) {
+ if (hash && (!progress || filesize < 0)) {
if (bytes < hashbytes)
- (void) putchar('#');
- (void) putchar('\n');
- (void) fflush(stdout);
+ (void)putchar('#');
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
if (ferror(fin))
warn("local: %s", local);
@@ -646,68 +643,82 @@ sendrequest(cmd, local, remote, printnames)
}
break;
}
+ progressmeter(1);
+ progress = oprogress;
if (closefunc != NULL)
(*closefunc)(fin);
- (void) fclose(dout);
- (void) gettimeofday(&stop, (struct timezone *)0);
- (void) getreply(0);
- (void) signal(SIGINT, oldintr);
+ (void)fclose(dout);
+ (void)getreply(0);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGPIPE, oldintp);
if (bytes > 0)
- ptransfer("sent", bytes, &start, &stop);
+ ptransfer(0);
return;
abort:
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
+ progress = oprogress;
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
+ (void)signal(SIGPIPE, oldintp);
if (!cpend) {
code = -1;
return;
}
if (data >= 0) {
- (void) close(data);
+ (void)close(data);
data = -1;
}
if (dout)
- (void) fclose(dout);
- (void) getreply(0);
+ (void)fclose(dout);
+ (void)getreply(0);
code = -1;
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
- (void) gettimeofday(&stop, (struct timezone *)0);
if (bytes > 0)
- ptransfer("sent", bytes, &start, &stop);
+ ptransfer(0);
}
jmp_buf recvabort;
void
-abortrecv()
+abortrecv(notused)
+ int notused;
{
+ alarmtimer(0);
mflag = 0;
abrtflag = 0;
- printf("\nreceive aborted\nwaiting for remote to finish abort\n");
- (void) fflush(stdout);
+ puts("\nreceive aborted\nwaiting for remote to finish abort.");
+ (void)fflush(stdout);
longjmp(recvabort, 1);
}
void
recvrequest(cmd, local, remote, lmode, printnames)
- char *cmd, *local, *remote, *lmode;
+ const char *cmd, *local, *remote, *lmode;
int printnames;
{
FILE *fout, *din = 0;
int (*closefunc) __P((FILE *));
- sig_t oldintr, oldintp;
+ sig_t oldinti, oldintr, oldintp;
int c, d, is_retr, tcrflag, bare_lfs = 0;
static int bufsize;
static char *buf;
- long bytes = 0, hashbytes = HASHBYTES;
- struct timeval start, stop;
+ off_t hashbytes;
struct stat st;
-
+ time_t mtime;
+ struct timeval tval[2];
+ int oprogress;
+ int opreserve;
+
+ hashbytes = mark;
+ direction = "received";
+ bytes = 0;
+ filesize = -1;
+ oprogress = progress;
+ opreserve = preserve;
is_retr = strcmp(cmd, "RETR") == 0;
if (is_retr && verbose && printnames) {
if (local && *local != '-')
@@ -725,56 +736,65 @@ recvrequest(cmd, local, remote, lmode, printnames)
tcrflag = !crflag && is_retr;
if (setjmp(recvabort)) {
while (cpend) {
- (void) getreply(0);
+ (void)getreply(0);
}
if (data >= 0) {
- (void) close(data);
+ (void)close(data);
data = -1;
}
if (oldintr)
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ if (oldinti)
+ (void)signal(SIGINFO, oldinti);
+ progress = oprogress;
+ preserve = opreserve;
code = -1;
return;
}
oldintr = signal(SIGINT, abortrecv);
+ oldinti = signal(SIGINFO, psummary);
if (strcmp(local, "-") && *local != '|') {
if (access(local, 2) < 0) {
char *dir = strrchr(local, '/');
if (errno != ENOENT && errno != EACCES) {
warn("local: %s", local);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
if (dir != NULL)
*dir = 0;
- d = access(dir ? local : ".", 2);
+ d = access(dir == local ? "/" : dir ? local : ".", 2);
if (dir != NULL)
*dir = '/';
if (d < 0) {
warn("local: %s", local);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
if (!runique && errno == EACCES &&
chmod(local, 0600) < 0) {
warn("local: %s", local);
- (void) signal(SIGINT, oldintr);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
if (runique && errno == EACCES &&
(local = gunique(local)) == NULL) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
}
else if (runique && (local = gunique(local)) == NULL) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
@@ -782,10 +802,14 @@ recvrequest(cmd, local, remote, lmode, printnames)
if (!is_retr) {
if (curtype != TYPE_A)
changetype(TYPE_A, 0);
- } else if (curtype != type)
- changetype(type, 0);
+ } else {
+ if (curtype != type)
+ changetype(type, 0);
+ filesize = remotesize(remote, 0);
+ }
if (initconn()) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
code = -1;
return;
}
@@ -796,27 +820,33 @@ recvrequest(cmd, local, remote, lmode, printnames)
return;
if (remote) {
if (command("%s %s", cmd, remote) != PRELIM) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
return;
}
} else {
if (command("%s", cmd) != PRELIM) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
return;
}
}
din = dataconn("r");
if (din == NULL)
goto abort;
- if (strcmp(local, "-") == 0)
+ if (strcmp(local, "-") == 0) {
fout = stdout;
- else if (*local == '|') {
+ progress = 0;
+ preserve = 0;
+ } else if (*local == '|') {
oldintp = signal(SIGPIPE, SIG_IGN);
fout = popen(local + 1, "w");
if (fout == NULL) {
warn("%s", local+1);
goto abort;
}
+ progress = 0;
+ preserve = 0;
closefunc = pclose;
} else {
fout = fopen(local, lmode);
@@ -830,7 +860,7 @@ recvrequest(cmd, local, remote, lmode, printnames)
st.st_blksize = BUFSIZ;
if (st.st_blksize > bufsize) {
if (buf)
- (void) free(buf);
+ (void)free(buf);
buf = malloc((unsigned)st.st_blksize);
if (buf == NULL) {
warn("malloc");
@@ -839,7 +869,11 @@ recvrequest(cmd, local, remote, lmode, printnames)
}
bufsize = st.st_blksize;
}
- (void) gettimeofday(&start, (struct timezone *)0);
+ if ((st.st_mode & S_IFMT) != S_IFREG) {
+ progress = 0;
+ preserve = 0;
+ }
+ progressmeter(-1);
switch (curtype) {
case TYPE_I:
@@ -847,6 +881,8 @@ recvrequest(cmd, local, remote, lmode, printnames)
if (restart_point &&
lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
warn("local: %s", local);
+ progress = oprogress;
+ preserve = opreserve;
if (closefunc != NULL)
(*closefunc)(fout);
return;
@@ -856,19 +892,19 @@ recvrequest(cmd, local, remote, lmode, printnames)
if ((d = write(fileno(fout), buf, c)) != c)
break;
bytes += c;
- if (hash) {
+ if (hash && (!progress || filesize < 0)) {
while (bytes >= hashbytes) {
- (void) putchar('#');
- hashbytes += HASHBYTES;
+ (void)putchar('#');
+ hashbytes += mark;
}
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
}
- if (hash && bytes > 0) {
- if (bytes < HASHBYTES)
- (void) putchar('#');
- (void) putchar('\n');
- (void) fflush(stdout);
+ if (hash && (!progress || filesize < 0) && bytes > 0) {
+ if (bytes < mark)
+ (void)putchar('#');
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
if (c < 0) {
if (errno != EPIPE)
@@ -899,6 +935,8 @@ recvrequest(cmd, local, remote, lmode, printnames)
if (fseek(fout, 0L, SEEK_CUR) < 0) {
done:
warn("local: %s", local);
+ progress = oprogress;
+ preserve = opreserve;
if (closefunc != NULL)
(*closefunc)(fout);
return;
@@ -908,16 +946,17 @@ done:
if (c == '\n')
bare_lfs++;
while (c == '\r') {
- while (hash && (bytes >= hashbytes)) {
- (void) putchar('#');
- (void) fflush(stdout);
- hashbytes += HASHBYTES;
+ while (hash && (!progress || filesize < 0) &&
+ (bytes >= hashbytes)) {
+ (void)putchar('#');
+ (void)fflush(stdout);
+ hashbytes += mark;
}
bytes++;
if ((c = getc(din)) != '\n' || tcrflag) {
if (ferror(fout))
goto break2;
- (void) putc('\r', fout);
+ (void)putc('\r', fout);
if (c == '\0') {
bytes++;
goto contin2;
@@ -926,20 +965,21 @@ done:
goto contin2;
}
}
- (void) putc(c, fout);
+ (void)putc(c, fout);
bytes++;
contin2: ;
}
break2:
if (bare_lfs) {
- printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
- printf("File may not have transferred correctly.\n");
+ printf(
+"WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
+ puts("File may not have transferred correctly.");
}
- if (hash) {
+ if (hash && (!progress || filesize < 0)) {
if (bytes < hashbytes)
- (void) putchar('#');
- (void) putchar('\n');
- (void) fflush(stdout);
+ (void)putchar('#');
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
if (ferror(din)) {
if (errno != EPIPE)
@@ -950,44 +990,67 @@ break2:
warn("local: %s", local);
break;
}
+ progressmeter(1);
+ progress = oprogress;
+ preserve = opreserve;
if (closefunc != NULL)
(*closefunc)(fout);
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
if (oldintp)
- (void) signal(SIGPIPE, oldintp);
- (void) fclose(din);
- (void) gettimeofday(&stop, (struct timezone *)0);
- (void) getreply(0);
- if (bytes > 0 && is_retr)
- ptransfer("received", bytes, &start, &stop);
+ (void)signal(SIGPIPE, oldintp);
+ (void)fclose(din);
+ (void)getreply(0);
+ if (bytes >= 0 && is_retr) {
+ if (bytes > 0)
+ ptransfer(0);
+ if (preserve && (closefunc == fclose)) {
+ mtime = remotemodtime(remote, 0);
+ if (mtime != -1) {
+ (void)gettimeofday(&tval[0],
+ (struct timezone *)0);
+ tval[1].tv_sec = mtime;
+ tval[1].tv_usec = 0;
+ if (utimes(local, tval) == -1) {
+ printf(
+ "Can't change modification time on %s to %s",
+ local, asctime(localtime(&mtime)));
+ }
+ }
+ }
+ }
return;
+
abort:
-/* abort using RFC959 recommended IP,SYNC sequence */
+/* abort using RFC959 recommended IP,SYNC sequence */
+ progress = oprogress;
+ preserve = opreserve;
if (oldintp)
- (void) signal(SIGPIPE, oldintr);
- (void) signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, oldintp);
+ (void)signal(SIGINT, SIG_IGN);
if (!cpend) {
code = -1;
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
return;
}
abort_remote(din);
code = -1;
if (data >= 0) {
- (void) close(data);
+ (void)close(data);
data = -1;
}
if (closefunc != NULL && fout != NULL)
(*closefunc)(fout);
if (din)
- (void) fclose(din);
- (void) gettimeofday(&stop, (struct timezone *)0);
+ (void)fclose(din);
if (bytes > 0)
- ptransfer("received", bytes, &start, &stop);
- (void) signal(SIGINT, oldintr);
+ ptransfer(0);
+ (void)signal(SIGINT, oldintr);
+ (void)signal(SIGINFO, oldinti);
}
/*
@@ -1000,20 +1063,21 @@ initconn()
char *p, *a;
int result, len, tmpno = 0;
int on = 1;
+ int tos, ports;
int a0, a1, a2, a3, p0, p1;
if (passivemode) {
data = socket(AF_INET, SOCK_STREAM, 0);
if (data < 0) {
- perror("ftp: socket");
- return(1);
+ warn("socket");
+ return (1);
}
if ((options & SO_DEBUG) &&
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
- sizeof (on)) < 0)
- perror("ftp: setsockopt (ignored)");
+ sizeof(on)) < 0)
+ warn("setsockopt (ignored)");
if (command("PASV") != COMPLETE) {
- printf("Passive mode refused.\n");
+ puts("Passive mode refused.");
goto bad;
}
@@ -1025,14 +1089,14 @@ initconn()
* From that we'll prepare a sockaddr_in.
*/
- if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",
+ if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
- printf("Passive mode address scan failure. "
- "Shouldn't happen!\n");
+ puts(
+"Passive mode address scan failure. Shouldn't happen!");
goto bad;
}
- bzero(&data_addr, sizeof(data_addr));
+ memset(&data_addr, 0, sizeof(data_addr));
data_addr.sin_family = AF_INET;
a = (char *)&data_addr.sin_addr.s_addr;
a[0] = a0 & 0xff;
@@ -1045,24 +1109,24 @@ initconn()
if (connect(data, (struct sockaddr *)&data_addr,
sizeof(data_addr)) < 0) {
- perror("ftp: connect");
+ warn("connect");
goto bad;
}
#ifdef IP_TOS
- on = IPTOS_THROUGHPUT;
- if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
+ tos = IPTOS_THROUGHPUT;
+ if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos,
sizeof(int)) < 0)
- perror("ftp: setsockopt TOS (ignored)");
+ warn("setsockopt TOS (ignored)");
#endif
- return(0);
+ return (0);
}
noport:
data_addr = myctladdr;
if (sendport)
- data_addr.sin_port = 0; /* let system pick one */
+ data_addr.sin_port = 0; /* let system pick one */
if (data != -1)
- (void) close(data);
+ (void)close(data);
data = socket(AF_INET, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
@@ -1071,18 +1135,26 @@ noport:
return (1);
}
if (!sendport)
- if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
+ if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) < 0) {
warn("setsockopt (reuse address)");
goto bad;
}
- if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
+#ifdef IP_PORTRANGE
+ ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
+ if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
+ sizeof(ports)) < 0)
+ warn("setsockopt PORTRANGE (ignored)");
+#endif
+ if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
warn("bind");
goto bad;
}
if (options & SO_DEBUG &&
- setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on)) < 0)
warn("setsockopt (ignored)");
- len = sizeof (data_addr);
+ len = sizeof(data_addr);
if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
warn("getsockname");
goto bad;
@@ -1113,7 +1185,7 @@ noport:
#endif
return (0);
bad:
- (void) close(data), data = -1;
+ (void)close(data), data = -1;
if (tmpno)
sendport = 1;
return (1);
@@ -1121,10 +1193,12 @@ bad:
FILE *
dataconn(lmode)
- char *lmode;
+ const char *lmode;
{
struct sockaddr_in from;
- int s, fromlen = sizeof (from), tos;
+ int s, fromlen, tos;
+
+ fromlen = sizeof(from);
if (passivemode)
return (fdopen(data, lmode));
@@ -1132,10 +1206,10 @@ dataconn(lmode)
s = accept(data, (struct sockaddr *) &from, &fromlen);
if (s < 0) {
warn("accept");
- (void) close(data), data = -1;
+ (void)close(data), data = -1;
return (NULL);
}
- (void) close(data);
+ (void)close(data);
data = s;
#ifdef IP_TOS
tos = IPTOS_THROUGHPUT;
@@ -1146,53 +1220,20 @@ dataconn(lmode)
}
void
-ptransfer(direction, bytes, t0, t1)
- char *direction;
- long bytes;
- struct timeval *t0, *t1;
-{
- struct timeval td;
- float s;
- long bs;
-
- if (verbose) {
- tvsub(&td, t1, t0);
- s = td.tv_sec + (td.tv_usec / 1000000.);
-#define nz(x) ((x) == 0 ? 1 : (x))
- bs = bytes / nz(s);
- printf("%ld bytes %s in %.3g seconds (%ld bytes/s)\n",
- bytes, direction, s, bs);
- }
-}
-
-/*
-void
-tvadd(tsum, t0)
- struct timeval *tsum, *t0;
-{
-
- tsum->tv_sec += t0->tv_sec;
- tsum->tv_usec += t0->tv_usec;
- if (tsum->tv_usec > 1000000)
- tsum->tv_sec++, tsum->tv_usec -= 1000000;
-}
-*/
-
-void
-tvsub(tdiff, t1, t0)
- struct timeval *tdiff, *t1, *t0;
+psummary(notused)
+ int notused;
{
- tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
- tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
- if (tdiff->tv_usec < 0)
- tdiff->tv_sec--, tdiff->tv_usec += 1000000;
+ if (bytes > 0)
+ ptransfer(1);
}
void
-psabort()
+psabort(notused)
+ int notused;
{
+ alarmtimer(0);
abrtflag++;
}
@@ -1241,10 +1282,10 @@ pswitch(flag)
ip->connect = connected;
connected = op->connect;
if (hostname) {
- (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
- ip->name[strlen(ip->name)] = '\0';
+ (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
+ ip->name[sizeof(ip->name) - 1] = '\0';
} else
- ip->name[0] = 0;
+ ip->name[0] = '\0';
hostname = op->name;
ip->hctl = hisctladdr;
hisctladdr = op->hctl;
@@ -1268,21 +1309,21 @@ pswitch(flag)
mcase = op->mcse;
ip->ntflg = ntflag;
ntflag = op->ntflg;
- (void) strncpy(ip->nti, ntin, 16);
- (ip->nti)[strlen(ip->nti)] = '\0';
- (void) strcpy(ntin, op->nti);
- (void) strncpy(ip->nto, ntout, 16);
- (ip->nto)[strlen(ip->nto)] = '\0';
- (void) strcpy(ntout, op->nto);
+ (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
+ (ip->nti)[sizeof(ip->nti) - 1] = '\0';
+ (void)strcpy(ntin, op->nti);
+ (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
+ (ip->nto)[sizeof(ip->nto) - 1] = '\0';
+ (void)strcpy(ntout, op->nto);
ip->mapflg = mapflag;
mapflag = op->mapflg;
- (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
- (ip->mi)[strlen(ip->mi)] = '\0';
- (void) strcpy(mapin, op->mi);
- (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
- (ip->mo)[strlen(ip->mo)] = '\0';
- (void) strcpy(mapout, op->mo);
- (void) signal(SIGINT, oldintr);
+ (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
+ (ip->mi)[sizeof(ip->mi) - 1] = '\0';
+ (void)strcpy(mapin, op->mi);
+ (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
+ (ip->mo)[sizeof(ip->mo) - 1] = '\0';
+ (void)strcpy(mapout, op->mo);
+ (void)signal(SIGINT, oldintr);
if (abrtflag) {
abrtflag = 0;
(*oldintr)(SIGINT);
@@ -1290,11 +1331,13 @@ pswitch(flag)
}
void
-abortpt()
+abortpt(notused)
+ int notused;
{
- printf("\n");
- (void) fflush(stdout);
+ alarmtimer(0);
+ putchar('\n');
+ (void)fflush(stdout);
ptabflg++;
mflag = 0;
abrtflag = 0;
@@ -1303,7 +1346,7 @@ abortpt()
void
proxtrans(cmd, local, remote)
- char *cmd, *local, *remote;
+ const char *cmd, *local, *remote;
{
sig_t oldintr;
int secndflag = 0, prox_type, nfnd;
@@ -1323,12 +1366,12 @@ proxtrans(cmd, local, remote)
if (curtype != prox_type)
changetype(prox_type, 1);
if (command("PASV") != COMPLETE) {
- printf("proxy server does not support third party transfers.\n");
+ puts("proxy server does not support third party transfers.");
return;
}
pswitch(0);
if (!connected) {
- printf("No primary connection\n");
+ puts("No primary connection.");
pswitch(1);
code = -1;
return;
@@ -1343,7 +1386,7 @@ proxtrans(cmd, local, remote)
goto abort;
oldintr = signal(SIGINT, abortpt);
if (command("%s %s", cmd, remote) != PRELIM) {
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
pswitch(1);
return;
}
@@ -1353,16 +1396,16 @@ proxtrans(cmd, local, remote)
if (command("%s %s", cmd2, local) != PRELIM)
goto abort;
ptflag++;
- (void) getreply(0);
+ (void)getreply(0);
pswitch(0);
- (void) getreply(0);
- (void) signal(SIGINT, oldintr);
+ (void)getreply(0);
+ (void)signal(SIGINT, oldintr);
pswitch(1);
ptflag = 0;
printf("local: %s remote: %s\n", local, remote);
return;
abort:
- (void) signal(SIGINT, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
ptflag = 0;
if (strcmp(cmd, "RETR") && !proxy)
pswitch(1);
@@ -1377,7 +1420,7 @@ abort:
pswitch(1);
if (ptabflg)
code = -1;
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
return;
}
if (cpend)
@@ -1391,7 +1434,7 @@ abort:
pswitch(1);
if (ptabflg)
code = -1;
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
return;
}
}
@@ -1409,15 +1452,15 @@ abort:
code = -1;
lostpeer();
}
- (void) getreply(0);
- (void) getreply(0);
+ (void)getreply(0);
+ (void)getreply(0);
}
if (proxy)
pswitch(0);
pswitch(1);
if (ptabflg)
code = -1;
- (void) signal(SIGINT, oldintr);
+ (void)signal(SIGINT, oldintr);
}
void
@@ -1431,20 +1474,20 @@ reset(argc, argv)
FD_ZERO(&mask);
while (nfnd > 0) {
FD_SET(fileno(cin), &mask);
- if ((nfnd = empty(&mask,0)) < 0) {
+ if ((nfnd = empty(&mask, 0)) < 0) {
warn("reset");
code = -1;
lostpeer();
}
else if (nfnd) {
- (void) getreply(0);
+ (void)getreply(0);
}
}
}
char *
gunique(local)
- char *local;
+ const char *local;
{
static char new[MAXPATHLEN];
char *cp = strrchr(local, '/');
@@ -1453,19 +1496,19 @@ gunique(local)
if (cp)
*cp = '\0';
- d = access(cp ? local : ".", 2);
+ d = access(cp == local ? "/" : cp ? local : ".", 2);
if (cp)
*cp = '/';
if (d < 0) {
warn("local: %s", local);
return ((char *) 0);
}
- (void) strcpy(new, local);
+ (void)strcpy(new, local);
cp = new + strlen(new);
*cp++ = '.';
while (!d) {
if (++count == 100) {
- printf("runique: can't find unique file name.\n");
+ puts("runique: can't find unique file name.");
return ((char *) 0);
}
*cp++ = ext;
@@ -1496,6 +1539,13 @@ abort_remote(din)
int nfnd;
struct fd_set mask;
+ if (cout == NULL) {
+ warnx("Lost control connection for abort.");
+ if (ptabflg)
+ code = -1;
+ lostpeer();
+ return;
+ }
/*
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
* after urgent byte rather than before as is protocol now
@@ -1503,11 +1553,11 @@ abort_remote(din)
sprintf(buf, "%c%c%c", IAC, IP, IAC);
if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
warn("abort");
- fprintf(cout,"%cABOR\r\n", DM);
- (void) fflush(cout);
+ fprintf(cout, "%cABOR\r\n", DM);
+ (void)fflush(cout);
FD_ZERO(&mask);
FD_SET(fileno(cin), &mask);
- if (din) {
+ if (din) {
FD_SET(fileno(din), &mask);
}
if ((nfnd = empty(&mask, 10)) <= 0) {
@@ -1524,7 +1574,7 @@ abort_remote(din)
}
if (getreply(0) == ERROR && code == 552) {
/* 552 needed for nic style abort */
- (void) getreply(0);
+ (void)getreply(0);
}
- (void) getreply(0);
+ (void)getreply(0);
}
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index 8252f5e..3a7423f 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -1,3 +1,6 @@
+/* $Id$ */
+/* $NetBSD: ftp_var.h,v 1.16 1997/04/14 09:09:23 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -39,19 +42,36 @@
#include <sys/param.h>
#include <setjmp.h>
+#include <stringlist.h>
+
+#ifndef SMALL
+#include <histedit.h>
+#endif /* !SMALL */
#include "extern.h"
+#define HASHBYTES 1024
+#define FTPBUFLEN MAXPATHLEN + 200
+
+#define STALLTIME 5 /* # of seconds of no xfer before "stalling" */
+
+#define FTP_PORT 21 /* default if getservbyname("ftp/tcp") fails */
+#define HTTP_PORT 80 /* default if getservbyname("http/tcp") fails */
+
+#define PAGER "less" /* default pager if $PAGER isn't set */
+
/*
* Options and other state info.
*/
int trace; /* trace packets exchanged */
int hash; /* print # for each buffer transferred */
+int mark; /* number of bytes between hashes */
int sendport; /* use PORT cmd for each data connection */
int verbose; /* print messages coming back from server */
-int connected; /* connected to server */
+int connected; /* 1 = connected to server, -1 = logged in */
int fromatty; /* input is from a terminal */
int interactive; /* interactively prompt on m* cmds */
+int confirmrest; /* confirm rest of current m* cmd */
int debug; /* debugging level */
int bell; /* ring bell on cmd completion */
int doglob; /* glob local file names */
@@ -63,10 +83,13 @@ int runique; /* store local files with unique name */
int mcase; /* map upper to lower case for mget names */
int ntflag; /* use ntin ntout tables for name translation */
int mapflag; /* use mapin mapout templates on file names */
+int preserve; /* preserve modification time on files */
+int progress; /* display transfer progress bar */
int code; /* return/reply code for ftp command */
int crflag; /* if 1, strip car. rets. on ascii gets */
char pasv[64]; /* passive port for proxy data connection */
int passivemode; /* passive mode enabled */
+int restricted_data_ports; /* restrict data port range */
char *altarg; /* argv[1] with no shell-like preprocessing */
char ntin[17]; /* input translation table */
char ntout[17]; /* output translation table */
@@ -83,21 +106,38 @@ char modename[32]; /* name of file transfer mode */
int mode; /* file transfer mode */
char bytename[32]; /* local byte size in ascii */
int bytesize; /* local byte size in binary */
+int anonftp; /* automatic anonymous login */
+int dirchange; /* remote directory changed by cd command */
+int ttywidth; /* width of tty */
+
+#ifndef SMALL
+int editing; /* command line editing enabled */
+EditLine *el; /* editline(3) status structure */
+History *hist; /* editline(3) history structure */
+char *cursor_pos; /* cursor position we're looking for */
+int cursor_argc; /* location of cursor in margv */
+int cursor_argo; /* offset of cursor in margv[cursor_argc] */
+#endif /* !SMALL */
+
+off_t bytes; /* current # of bytes read */
+off_t filesize; /* size of file being transferred */
+char *direction; /* direction transfer is occurring */
char *hostname; /* name of host connected to */
int unix_server; /* server is unix, can use binary for ascii */
int unix_proxy; /* proxy is unix, can use binary for ascii */
-
-struct servent *sp; /* service spec for tcp/ftp */
+int ftpport; /* port number to use for ftp connections */
+int httpport; /* port number to use for http connections */
jmp_buf toplevel; /* non-local goto stuff for cmd scanner */
-char line[200]; /* input line buffer */
+char line[FTPBUFLEN]; /* input line buffer */
char *stringbase; /* current scan point in line buffer */
-char argbuf[200]; /* argument storage buffer */
+char argbuf[FTPBUFLEN]; /* argument storage buffer */
char *argbase; /* current storage point in arg buffer */
+StringList *marg_sl; /* stringlist containing margv */
int margc; /* count of arguments on input line */
-char *margv[20]; /* args parsed from input line */
+#define margv (marg_sl->sl_str) /* args parsed from input line */
int cpend; /* flag: if != 0, then pending server reply */
int mflag; /* flag: if != 0, then active multi command */
@@ -109,9 +149,12 @@ int options; /* used during socket creation */
struct cmd {
char *c_name; /* name of command */
char *c_help; /* help string */
- char c_bell; /* give bell when command completes */
- char c_conn; /* must be connected to use command */
- char c_proxy; /* proxy server may execute */
+ char c_bell; /* give bell when command completes */
+ char c_conn; /* must be connected to use command */
+ char c_proxy; /* proxy server may execute */
+#ifndef SMALL
+ char *c_complete; /* context sensitive completion list */
+#endif /* !SMALL */
void (*c_handler) __P((int, char **)); /* function to call */
};
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index 72c63cd..f94b951 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -1,3 +1,6 @@
+/* $Id: main.c,v 1.14 1997/06/27 09:30:13 ache Exp $ */
+/* $NetBSD: main.c,v 1.22 1997/06/10 07:04:43 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -38,25 +41,26 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
+#if 0
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
+#else
+static char rcsid[] = "$Id: main.c,v 1.14 1997/06/27 09:30:13 ache Exp $";
+#endif
#endif /* not lint */
/*
* FTP User Program -- Command Interface.
*/
-/*#include <sys/ioctl.h>*/
#include <sys/types.h>
#include <sys/socket.h>
-#include <arpa/ftp.h>
-
-#include <ctype.h>
#include <err.h>
+#include <locale.h>
#include <netdb.h>
#include <pwd.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "ftp_var.h"
@@ -66,24 +70,78 @@ main(argc, argv)
int argc;
char *argv[];
{
- int ch, top;
+ struct servent *sp;
+ int ch, top, port, rval;
struct passwd *pw = NULL;
char *cp, homedir[MAXPATHLEN];
+ int dumbterm;
+
+ (void) setlocale(LC_ALL, "");
sp = getservbyname("ftp", "tcp");
if (sp == 0)
- errx(1, "ftp/tcp: unknown service");
+ ftpport = htons(FTP_PORT); /* good fallback */
+ else
+ ftpport = sp->s_port;
+ sp = getservbyname("http", "tcp");
+ if (sp == 0)
+ httpport = htons(HTTP_PORT); /* good fallback */
+ else
+ httpport = sp->s_port;
doglob = 1;
interactive = 1;
autologin = 1;
+ passivemode = 0;
+ restricted_data_ports = 1;
+ preserve = 1;
+ verbose = 0;
+ progress = 0;
+#ifndef SMALL
+ editing = 0;
+ el = NULL;
+ hist = NULL;
+#endif
+ mark = HASHBYTES;
+ marg_sl = sl_init();
+
+ cp = strrchr(argv[0], '/');
+ cp = (cp == NULL) ? argv[0] : cp + 1;
+ if (getenv("FTP_PASSIVE_MODE") || strcmp(cp, "pftp") == 0)
+ passivemode = 1;
+
+ cp = getenv("TERM");
+ if (cp == NULL || strcmp(cp, "dumb") == 0)
+ dumbterm = 1;
+ else
+ dumbterm = 0;
+ fromatty = isatty(fileno(stdin));
+ if (fromatty) {
+ verbose = 1; /* verbose if from a tty */
+#ifndef SMALL
+ if (! dumbterm)
+ editing = 1; /* editing mode on if tty is usable */
+#endif
+ }
+ if (isatty(fileno(stdout)) && !dumbterm)
+ progress = 1; /* progress bar on if tty is usable */
- while ((ch = getopt(argc, argv, "dgintv")) != EOF) {
+ while ((ch = getopt(argc, argv, "adeginpP:tvVU")) != -1) {
switch (ch) {
+ case 'a':
+ anonftp = 1;
+ break;
+
case 'd':
options |= SO_DEBUG;
debug++;
break;
-
+
+ case 'e':
+#ifndef SMALL
+ editing = 0;
+#endif
+ break;
+
case 'g':
doglob = 0;
break;
@@ -96,29 +154,43 @@ main(argc, argv)
autologin = 0;
break;
+ case 'p':
+ passivemode = 1;
+ break;
+
+ case 'P':
+ port = atoi(optarg);
+ if (port <= 0)
+ warnx("bad port number: %s (ignored)", optarg);
+ else
+ ftpport = htons(port);
+ break;
+
case 't':
- trace++;
+ trace = 1;
break;
case 'v':
- verbose++;
+ verbose = 1;
+ break;
+
+ case 'V':
+ verbose = 0;
+ break;
+
+ case 'U':
+ restricted_data_ports = 0;
break;
default:
- (void)fprintf(stderr,
- "usage: ftp [-dgintv] [host [port]]\n");
- exit(1);
+ usage();
}
}
argc -= optind;
argv += optind;
- fromatty = isatty(fileno(stdin));
- if (fromatty)
- verbose++;
cpend = 0; /* no pending replies */
proxy = 0; /* proxy not active */
- passivemode = 0; /* passive mode not active */
crflag = 1; /* strip c.r. on ascii gets */
sendport = -1; /* not using ports */
/*
@@ -132,27 +204,40 @@ main(argc, argv)
pw = getpwuid(getuid());
if (pw != NULL) {
home = homedir;
- (void) strcpy(home, pw->pw_dir);
+ (void)strcpy(home, pw->pw_dir);
}
+
+ setttywidth(0);
+ (void)signal(SIGWINCH, setttywidth);
+
if (argc > 0) {
- char *xargv[5];
- extern char *__progname;
-
- if (setjmp(toplevel))
- exit(0);
- (void) signal(SIGINT, intr);
- (void) signal(SIGPIPE, lostpeer);
- xargv[0] = __progname;
- xargv[1] = argv[0];
- xargv[2] = argv[1];
- xargv[3] = argv[2];
- xargv[4] = NULL;
- setpeer(argc+1, xargv);
+ if (strchr(argv[0], ':') != NULL) {
+ anonftp = 1; /* Handle "automatic" transfers. */
+ rval = auto_fetch(argc, argv);
+ if (rval >= 0) /* -1 == connected and cd-ed */
+ exit(rval);
+ } else {
+ char *xargv[5];
+
+ if (setjmp(toplevel))
+ exit(0);
+ (void)signal(SIGINT, (sig_t)intr);
+ (void)signal(SIGPIPE, (sig_t)lostpeer);
+ xargv[0] = __progname;
+ xargv[1] = argv[0];
+ xargv[2] = argv[1];
+ xargv[3] = argv[2];
+ xargv[4] = NULL;
+ setpeer(argc+1, xargv);
+ }
}
+#ifndef SMALL
+ controlediting();
+#endif /* !SMALL */
top = setjmp(toplevel) == 0;
if (top) {
- (void) signal(SIGINT, intr);
- (void) signal(SIGPIPE, lostpeer);
+ (void)signal(SIGINT, (sig_t)intr);
+ (void)signal(SIGPIPE, (sig_t)lostpeer);
}
for (;;) {
cmdscanner(top);
@@ -164,6 +249,7 @@ void
intr()
{
+ alarmtimer(0);
longjmp(toplevel, 1);
}
@@ -171,15 +257,16 @@ void
lostpeer()
{
+ alarmtimer(0);
if (connected) {
if (cout != NULL) {
- (void) shutdown(fileno(cout), 1+1);
- (void) fclose(cout);
+ (void)shutdown(fileno(cout), 1+1);
+ (void)fclose(cout);
cout = NULL;
}
if (data >= 0) {
- (void) shutdown(data, 1+1);
- (void) close(data);
+ (void)shutdown(data, 1+1);
+ (void)close(data);
data = -1;
}
connected = 0;
@@ -187,8 +274,8 @@ lostpeer()
pswitch(1);
if (connected) {
if (cout != NULL) {
- (void) shutdown(fileno(cout), 1+1);
- (void) fclose(cout);
+ (void)shutdown(fileno(cout), 1+1);
+ (void)fclose(cout);
cout = NULL;
}
connected = 0;
@@ -198,23 +285,13 @@ lostpeer()
}
/*
+ * Generate a prompt
+ */
char *
-tail(filename)
- char *filename;
+prompt()
{
- char *s;
-
- while (*filename) {
- s = strrchr(filename, '/');
- if (s == NULL)
- break;
- if (s[1])
- return (s + 1);
- *s = '\0';
- }
- return (filename);
+ return ("ftp> ");
}
-*/
/*
* Command parser.
@@ -224,69 +301,107 @@ cmdscanner(top)
int top;
{
struct cmd *c;
- int l;
-
- if (!top)
- (void) putchar('\n');
+ int num;
+
+ if (!top
+#ifndef SMALL
+ && !editing
+#endif /* !SMALL */
+ )
+ (void)putchar('\n');
for (;;) {
- if (fromatty) {
- printf("ftp> ");
- (void) fflush(stdout);
- }
- if (fgets(line, sizeof line, stdin) == NULL)
- quit(0, 0);
- l = strlen(line);
- if (l == 0)
- break;
- if (line[--l] == '\n') {
- if (l == 0)
+#ifndef SMALL
+ if (!editing) {
+#endif /* !SMALL */
+ if (fromatty) {
+ fputs(prompt(), stdout);
+ (void)fflush(stdout);
+ }
+ if (fgets(line, sizeof(line), stdin) == NULL)
+ quit(0, 0);
+ num = strlen(line);
+ if (num == 0)
break;
- line[l] = '\0';
- } else if (l == sizeof(line) - 2) {
- printf("sorry, input line too long\n");
- while ((l = getchar()) != '\n' && l != EOF)
- /* void */;
- break;
- } /* else it was a line without a newline */
+ if (line[--num] == '\n') {
+ if (num == 0)
+ break;
+ line[num] = '\0';
+ } else if (num == sizeof(line) - 2) {
+ puts("sorry, input line too long.");
+ while ((num = getchar()) != '\n' && num != EOF)
+ /* void */;
+ break;
+ } /* else it was a line without a newline */
+#ifndef SMALL
+ } else {
+ const char *buf;
+ cursor_pos = NULL;
+
+ if ((buf = el_gets(el, &num)) == NULL || num == 0)
+ quit(0, 0);
+ if (line[--num] == '\n') {
+ if (num == 0)
+ break;
+ } else if (num >= sizeof(line)) {
+ puts("sorry, input line too long.");
+ break;
+ }
+ memcpy(line, buf, num);
+ line[num] = '\0';
+ history(hist, H_ENTER, buf);
+ }
+#endif /* !SMALL */
+
makeargv();
- if (margc == 0) {
+ if (margc == 0)
continue;
- }
+#if 0 && !defined(SMALL) /* XXX: don't want el_parse */
+ /*
+ * el_parse returns -1 to signal that it's not been handled
+ * internally.
+ */
+ if (el_parse(el, margc, margv) != -1)
+ continue;
+#endif /* !SMALL */
c = getcmd(margv[0]);
if (c == (struct cmd *)-1) {
- printf("?Ambiguous command\n");
+ puts("?Ambiguous command.");
continue;
}
if (c == 0) {
- printf("?Invalid command\n");
+ puts("?Invalid command.");
continue;
}
if (c->c_conn && !connected) {
- printf("Not connected.\n");
+ puts("Not connected.");
continue;
}
+ confirmrest = 0;
(*c->c_handler)(margc, margv);
if (bell && c->c_bell)
- (void) putchar('\007');
+ (void)putchar('\007');
if (c->c_handler != help)
break;
}
- (void) signal(SIGINT, intr);
- (void) signal(SIGPIPE, lostpeer);
+ (void)signal(SIGINT, (sig_t)intr);
+ (void)signal(SIGPIPE, (sig_t)lostpeer);
}
struct cmd *
getcmd(name)
- char *name;
+ const char *name;
{
- char *p, *q;
+ const char *p, *q;
struct cmd *c, *found;
int nmatches, longest;
+ if (name == NULL)
+ return (0);
+
longest = 0;
nmatches = 0;
found = 0;
- for (c = cmdtab; p = c->c_name; c++) {
+ for (c = cmdtab; (p = c->c_name) != NULL; c++) {
for (q = name; *q == *p++; q++)
if (*q == 0) /* exact match? */
return (c);
@@ -313,17 +428,41 @@ int slrflag;
void
makeargv()
{
- char **argp;
+ char *argp;
- margc = 0;
- argp = margv;
stringbase = line; /* scan from first of buffer */
argbase = argbuf; /* store from first of buffer */
slrflag = 0;
- while (*argp++ = slurpstring())
- margc++;
+ marg_sl->sl_cur = 0; /* reset to start of marg_sl */
+ for (margc = 0; ; margc++) {
+ argp = slurpstring();
+ sl_add(marg_sl, argp);
+ if (argp == NULL)
+ break;
+ }
+#ifndef SMALL
+ if (cursor_pos == line) {
+ cursor_argc = 0;
+ cursor_argo = 0;
+ } else if (cursor_pos != NULL) {
+ cursor_argc = margc;
+ cursor_argo = strlen(margv[margc-1]);
+ }
+#endif /* !SMALL */
}
+#ifdef SMALL
+#define INC_CHKCURSOR(x) (x)++
+#else /* !SMALL */
+#define INC_CHKCURSOR(x) { (x)++ ; \
+ if (x == cursor_pos) { \
+ cursor_argc = margc; \
+ cursor_argo = ap-argbase; \
+ cursor_pos = NULL; \
+ } }
+
+#endif /* !SMALL */
+
/*
* Parse string into argbuf;
* implemented with FSM to
@@ -341,7 +480,7 @@ slurpstring()
switch (slrflag) { /* and $ as token for macro invoke */
case 0:
slrflag++;
- stringbase++;
+ INC_CHKCURSOR(stringbase);
return ((*sb == '!') ? "!" : "$");
/* NOTREACHED */
case 1:
@@ -361,7 +500,8 @@ S0:
case ' ':
case '\t':
- sb++; goto S0;
+ INC_CHKCURSOR(sb);
+ goto S0;
default:
switch (slrflag) {
@@ -387,13 +527,17 @@ S1:
goto OUT; /* end of token */
case '\\':
- sb++; goto S2; /* slurp next character */
+ INC_CHKCURSOR(sb);
+ goto S2; /* slurp next character */
case '"':
- sb++; goto S3; /* slurp quoted string */
+ INC_CHKCURSOR(sb);
+ goto S3; /* slurp quoted string */
default:
- *ap++ = *sb++; /* add character to token */
+ *ap = *sb; /* add character to token */
+ ap++;
+ INC_CHKCURSOR(sb);
got_one = 1;
goto S1;
}
@@ -405,7 +549,9 @@ S2:
goto OUT;
default:
- *ap++ = *sb++;
+ *ap = *sb;
+ ap++;
+ INC_CHKCURSOR(sb);
got_one = 1;
goto S1;
}
@@ -417,10 +563,13 @@ S3:
goto OUT;
case '"':
- sb++; goto S1;
+ INC_CHKCURSOR(sb);
+ goto S1;
default:
- *ap++ = *sb++;
+ *ap = *sb;
+ ap++;
+ INC_CHKCURSOR(sb);
got_one = 1;
goto S3;
}
@@ -447,8 +596,6 @@ OUT:
return ((char *)0);
}
-#define HELPINDENT ((int) sizeof ("directory"))
-
/*
* Help command.
* Call each command handler with argc == 0 and argv[0] == name.
@@ -461,47 +608,24 @@ help(argc, argv)
struct cmd *c;
if (argc == 1) {
- int i, j, w, k;
- int columns, width = 0, lines;
-
- printf("Commands may be abbreviated. Commands are:\n\n");
- for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
- int len = strlen(c->c_name);
-
- if (len > width)
- width = len;
- }
- width = (width + 8) &~ 7;
- columns = 80 / width;
- if (columns == 0)
- columns = 1;
- lines = (NCMDS + columns - 1) / columns;
- for (i = 0; i < lines; i++) {
- for (j = 0; j < columns; j++) {
- c = cmdtab + j * lines + i;
- if (c->c_name && (!proxy || c->c_proxy)) {
- printf("%s", c->c_name);
- }
- else if (c->c_name) {
- for (k=0; k < strlen(c->c_name); k++) {
- (void) putchar(' ');
- }
- }
- if (c + lines >= &cmdtab[NCMDS]) {
- printf("\n");
- break;
- }
- w = strlen(c->c_name);
- while (w < width) {
- w = (w + 8) &~ 7;
- (void) putchar('\t');
- }
- }
- }
+ StringList *buf;
+
+ buf = sl_init();
+ printf("%sommands may be abbreviated. Commands are:\n\n",
+ proxy ? "Proxy c" : "C");
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
+ if (c->c_name && (!proxy || c->c_proxy))
+ sl_add(buf, c->c_name);
+ list_vertical(buf);
+ sl_free(buf, 0);
return;
}
+
+#define HELPINDENT ((int) sizeof("disconnect"))
+
while (--argc > 0) {
char *arg;
+
arg = *++argv;
c = getcmd(arg);
if (c == (struct cmd *)-1)
@@ -513,3 +637,15 @@ help(argc, argv)
c->c_name, c->c_help);
}
}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-adeginptvV] [host [port]]\n"
+ " %s host:path[/]\n"
+ " %s ftp://host[:port]/path[/]\n"
+ " %s http://host[:port]/file\n",
+ __progname, __progname, __progname, __progname);
+ exit(1);
+}
diff --git a/usr.bin/ftp/pathnames.h b/usr.bin/ftp/pathnames.h
index be72b7e..c764add 100644
--- a/usr.bin/ftp/pathnames.h
+++ b/usr.bin/ftp/pathnames.h
@@ -1,3 +1,6 @@
+/* $Id$ */
+/* $NetBSD: pathnames.h,v 1.7 1997/01/09 20:19:40 tls Exp $ */
+
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,5 +38,4 @@
#include <paths.h>
-#undef _PATH_TMP
-#define _PATH_TMP "/tmp/ftpXXXXXX"
+#define TMPFILE "ftpXXXXXX"
diff --git a/usr.bin/ftp/ruserpass.c b/usr.bin/ftp/ruserpass.c
index 0a13fcd..35302a0 100644
--- a/usr.bin/ftp/ruserpass.c
+++ b/usr.bin/ftp/ruserpass.c
@@ -1,3 +1,6 @@
+/* $Id: ruserpass.c,v 1.5 1997/06/25 08:56:45 msmith Exp $ */
+/* $NetBSD: ruserpass.c,v 1.13 1997/04/01 14:20:34 mrg Exp $ */
+
/*
* Copyright (c) 1985, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -32,7 +35,11 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95";
+#else
+static char rcsid[] = "$Id: ruserpass.c,v 1.5 1997/06/25 08:56:45 msmith Exp $";
+#endif
#endif /* not lint */
#include <sys/types.h>
@@ -77,7 +84,8 @@ static struct toktab {
int
ruserpass(host, aname, apass, aacct)
- char *host, **aname, **apass, **aacct;
+ const char *host;
+ char **aname, **apass, **aacct;
{
char *hdir, buf[BUFSIZ], *tmp;
char myname[MAXHOSTNAMELEN], *mydomain;
@@ -87,7 +95,12 @@ ruserpass(host, aname, apass, aacct)
hdir = getenv("HOME");
if (hdir == NULL)
hdir = ".";
- (void) sprintf(buf, "%s/.netrc", hdir);
+ if (strlen(hdir) + sizeof(".netrc") < sizeof(buf)) {
+ (void)snprintf(buf, sizeof buf, "%s/.netrc", hdir);
+ } else {
+ warnx("%s/.netrc: %s", hdir, strerror(ENAMETOOLONG));
+ return (0);
+ }
cfile = fopen(buf, "r");
if (cfile == NULL) {
if (errno != ENOENT)
@@ -111,7 +124,7 @@ next:
continue;
/*
* Allow match either for user's input host name
- * or official hostname. Also allow match of
+ * or official hostname. Also allow match of
* incompletely-specified host in local domain.
*/
if (strcasecmp(host, tokval) == 0)
@@ -135,9 +148,10 @@ next:
case LOGIN:
if (token())
- if (*aname == 0) {
- *aname = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*aname, tokval);
+ if (*aname == 0) {
+ *aname = malloc((unsigned)
+ strlen(tokval) + 1);
+ (void)strcpy(*aname, tokval);
} else {
if (strcmp(*aname, tokval))
goto next;
@@ -153,7 +167,7 @@ next:
}
if (token() && *apass == 0) {
*apass = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*apass, tokval);
+ (void)strcpy(*apass, tokval);
}
break;
case ACCOUNT:
@@ -165,31 +179,35 @@ next:
}
if (token() && *aacct == 0) {
*aacct = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*aacct, tokval);
+ (void)strcpy(*aacct, tokval);
}
break;
case MACDEF:
if (proxy) {
- (void) fclose(cfile);
+ (void)fclose(cfile);
return (0);
}
- while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t');
+ while ((c=getc(cfile)) != EOF)
+ if (c != ' ' && c != '\t')
+ break;
if (c == EOF || c == '\n') {
- printf("Missing macdef name argument.\n");
+ puts("Missing macdef name argument.");
goto bad;
}
if (macnum == 16) {
- printf("Limit of 16 macros have already been defined\n");
+ puts(
+"Limit of 16 macros have already been defined.");
goto bad;
}
tmp = macros[macnum].mac_name;
*tmp++ = c;
for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
- !isspace(c); ++i) {
+ (!isascii(c) || !isspace(c)); ++i) {
*tmp++ = c;
}
if (c == EOF) {
- printf("Macro definition missing null line terminator.\n");
+ puts(
+"Macro definition missing null line terminator.");
goto bad;
}
*tmp = '\0';
@@ -197,19 +215,22 @@ next:
while ((c=getc(cfile)) != EOF && c != '\n');
}
if (c == EOF) {
- printf("Macro definition missing null line terminator.\n");
+ puts(
+"Macro definition missing null line terminator.");
goto bad;
}
if (macnum == 0) {
macros[macnum].mac_start = macbuf;
}
else {
- macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
+ macros[macnum].mac_start =
+ macros[macnum-1].mac_end + 1;
}
tmp = macros[macnum].mac_start;
while (tmp != macbuf + 4096) {
if ((c=getc(cfile)) == EOF) {
- printf("Macro definition missing null line terminator.\n");
+ puts(
+"Macro definition missing null line terminator.");
goto bad;
}
*tmp = c;
@@ -223,7 +244,7 @@ next:
tmp++;
}
if (tmp == macbuf + 4096) {
- printf("4K macro buffer exceeded\n");
+ puts("4K macro buffer exceeded.");
goto bad;
}
break;
@@ -234,10 +255,10 @@ next:
goto done;
}
done:
- (void) fclose(cfile);
+ (void)fclose(cfile);
return (0);
bad:
- (void) fclose(cfile);
+ (void)fclose(cfile);
return (-1);
}
diff --git a/usr.bin/ftp/util.c b/usr.bin/ftp/util.c
new file mode 100644
index 0000000..30b48c7
--- /dev/null
+++ b/usr.bin/ftp/util.c
@@ -0,0 +1,779 @@
+/* $Id: util.c,v 1.1 1997/06/25 08:56:46 msmith Exp $ */
+/* $NetBSD: util.c,v 1.9 1997/06/10 22:00:01 lukem Exp $ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: util.c,v 1.1 1997/06/25 08:56:46 msmith Exp $";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Misc support routines
+ */
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <arpa/ftp.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "ftp_var.h"
+#include "pathnames.h"
+
+/*
+ * Connect to peer server and
+ * auto-login, if possible.
+ */
+void
+setpeer(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *host;
+ short port;
+
+ if (connected) {
+ printf("Already connected to %s, use close first.\n",
+ hostname);
+ code = -1;
+ return;
+ }
+ if (argc < 2)
+ (void)another(&argc, &argv, "to");
+ if (argc < 2 || argc > 3) {
+ printf("usage: %s host-name [port]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ port = ftpport;
+ if (argc > 2) {
+ port = atoi(argv[2]);
+ if (port <= 0) {
+ printf("%s: bad port number '%s'.\n", argv[1], argv[2]);
+ printf("usage: %s host-name [port]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ port = htons(port);
+ }
+ host = hookup(argv[1], port);
+ if (host) {
+ int overbose;
+
+ connected = 1;
+ /*
+ * Set up defaults for FTP.
+ */
+ (void)strcpy(typename, "ascii"), type = TYPE_A;
+ curtype = TYPE_A;
+ (void)strcpy(formname, "non-print"), form = FORM_N;
+ (void)strcpy(modename, "stream"), mode = MODE_S;
+ (void)strcpy(structname, "file"), stru = STRU_F;
+ (void)strcpy(bytename, "8"), bytesize = 8;
+ if (autologin)
+ (void)login(argv[1], NULL, NULL);
+
+ overbose = verbose;
+ if (debug == 0)
+ verbose = -1;
+ if (command("SYST") == COMPLETE && overbose) {
+ char *cp, c;
+ c = 0;
+ cp = strchr(reply_string+4, ' ');
+ if (cp == NULL)
+ cp = strchr(reply_string+4, '\r');
+ if (cp) {
+ if (cp[-1] == '.')
+ cp--;
+ c = *cp;
+ *cp = '\0';
+ }
+
+ printf("Remote system type is %s.\n", reply_string + 4);
+ if (cp)
+ *cp = c;
+ }
+ if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
+ if (proxy)
+ unix_proxy = 1;
+ else
+ unix_server = 1;
+ /*
+ * Set type to 0 (not specified by user),
+ * meaning binary by default, but don't bother
+ * telling server. We can use binary
+ * for text files unless changed by the user.
+ */
+ type = 0;
+ (void)strcpy(typename, "binary");
+ if (overbose)
+ printf("Using %s mode to transfer files.\n",
+ typename);
+ } else {
+ if (proxy)
+ unix_proxy = 0;
+ else
+ unix_server = 0;
+ if (overbose &&
+ !strncmp(reply_string, "215 TOPS20", 10))
+ puts(
+"Remember to set tenex mode when transferring binary files from this machine.");
+ }
+ verbose = overbose;
+ }
+}
+
+
+/*
+ * login to remote host, using given username & password if supplied
+ */
+int
+login(host, user, pass)
+ const char *host;
+ char *user, *pass;
+{
+ char tmp[80];
+ char *acct;
+ char anonpass[MAXLOGNAME + 1 + MAXHOSTNAMELEN]; /* "user@hostname" */
+ char hostname[MAXHOSTNAMELEN];
+ int n, aflag = 0;
+
+ acct = NULL;
+ if (user == NULL) {
+ if (ruserpass(host, &user, &pass, &acct) < 0) {
+ code = -1;
+ return (0);
+ }
+ }
+
+ /*
+ * Set up arguments for an anonymous FTP session, if necessary.
+ */
+ if ((user == NULL || pass == NULL) && anonftp) {
+ memset(anonpass, 0, sizeof(anonpass));
+ memset(hostname, 0, sizeof(hostname));
+
+ /*
+ * Set up anonymous login password.
+ */
+ user = getlogin();
+ gethostname(hostname, MAXHOSTNAMELEN);
+#ifndef DONT_CHEAT_ANONPASS
+ /*
+ * Every anonymous FTP server I've encountered
+ * will accept the string "username@", and will
+ * append the hostname itself. We do this by default
+ * since many servers are picky about not having
+ * a FQDN in the anonymous password. - thorpej@netbsd.org
+ */
+ snprintf(anonpass, sizeof(anonpass) - 1, "%s@",
+ user);
+#else
+ snprintf(anonpass, sizeof(anonpass) - 1, "%s@%s",
+ user, hp->h_name);
+#endif
+ pass = anonpass;
+ user = "anonymous"; /* as per RFC 1635 */
+ }
+
+ while (user == NULL) {
+ char *myname = getlogin();
+
+ if (myname == NULL) {
+ struct passwd *pp = getpwuid(getuid());
+
+ if (pp != NULL)
+ myname = pp->pw_name;
+ }
+ if (myname)
+ printf("Name (%s:%s): ", host, myname);
+ else
+ printf("Name (%s): ", host);
+ (void)fgets(tmp, sizeof(tmp) - 1, stdin);
+ tmp[strlen(tmp) - 1] = '\0';
+ if (*tmp == '\0')
+ user = myname;
+ else
+ user = tmp;
+ }
+ n = command("USER %s", user);
+ if (n == CONTINUE) {
+ if (pass == NULL)
+ pass = getpass("Password:");
+ n = command("PASS %s", pass);
+ }
+ if (n == CONTINUE) {
+ aflag++;
+ if (acct == NULL)
+ acct = getpass("Account:");
+ n = command("ACCT %s", acct);
+ }
+ if ((n != COMPLETE) ||
+ (!aflag && acct != NULL && command("ACCT %s", acct) != COMPLETE)) {
+ warnx("Login failed.");
+ return (0);
+ }
+ if (proxy)
+ return (1);
+ connected = -1;
+ for (n = 0; n < macnum; ++n) {
+ if (!strcmp("init", macros[n].mac_name)) {
+ (void)strcpy(line, "$init");
+ makeargv();
+ domacro(margc, margv);
+ break;
+ }
+ }
+ return (1);
+}
+
+/*
+ * `another' gets another argument, and stores the new argc and argv.
+ * It reverts to the top level (via main.c's intr()) on EOF/error.
+ *
+ * Returns false if no new arguments have been added.
+ */
+int
+another(pargc, pargv, prompt)
+ int *pargc;
+ char ***pargv;
+ const char *prompt;
+{
+ int len = strlen(line), ret;
+
+ if (len >= sizeof(line) - 3) {
+ puts("sorry, arguments too long.");
+ intr();
+ }
+ printf("(%s) ", prompt);
+ line[len++] = ' ';
+ if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
+ intr();
+ len += strlen(&line[len]);
+ if (len > 0 && line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ makeargv();
+ ret = margc > *pargc;
+ *pargc = margc;
+ *pargv = margv;
+ return (ret);
+}
+
+/*
+ * glob files given in argv[] from the remote server.
+ * if errbuf isn't NULL, store error messages there instead
+ * of writing to the screen.
+ */
+char *
+remglob(argv, doswitch, errbuf)
+ char *argv[];
+ int doswitch;
+ char **errbuf;
+{
+ char temp[MAXPATHLEN];
+ static char buf[MAXPATHLEN];
+ static FILE *ftemp = NULL;
+ static char **args;
+ int oldverbose, oldhash, fd;
+ char *cp, *mode;
+
+ if (!mflag) {
+ if (!doglob)
+ args = NULL;
+ else {
+ if (ftemp) {
+ (void)fclose(ftemp);
+ ftemp = NULL;
+ }
+ }
+ return (NULL);
+ }
+ if (!doglob) {
+ if (args == NULL)
+ args = argv;
+ if ((cp = *++args) == NULL)
+ args = NULL;
+ return (cp);
+ }
+ if (ftemp == NULL) {
+ (void)snprintf(temp, sizeof(temp), "%s%s", _PATH_TMP, TMPFILE);
+ if ((fd = mkstemp(temp)) < 0) {
+ warn("unable to create temporary file %s", temp);
+ return (NULL);
+ }
+ close(fd);
+ oldverbose = verbose;
+ verbose = (errbuf != NULL) ? -1 : 0;
+ oldhash = hash;
+ hash = 0;
+ if (doswitch)
+ pswitch(!proxy);
+ for (mode = "w"; *++argv != NULL; mode = "a")
+ recvrequest("NLST", temp, *argv, mode, 0);
+ if ((code / 100) != COMPLETE) {
+ if (errbuf != NULL)
+ *errbuf = reply_string;
+ }
+ if (doswitch)
+ pswitch(!proxy);
+ verbose = oldverbose;
+ hash = oldhash;
+ ftemp = fopen(temp, "r");
+ (void)unlink(temp);
+ if (ftemp == NULL) {
+ if (errbuf == NULL)
+ puts("can't find list of remote files, oops.");
+ else
+ *errbuf =
+ "can't find list of remote files, oops.";
+ return (NULL);
+ }
+ }
+ if (fgets(buf, sizeof(buf), ftemp) == NULL) {
+ (void)fclose(ftemp);
+ ftemp = NULL;
+ return (NULL);
+ }
+ if ((cp = strchr(buf, '\n')) != NULL)
+ *cp = '\0';
+ return (buf);
+}
+
+int
+confirm(cmd, file)
+ const char *cmd, *file;
+{
+ char line[BUFSIZ];
+
+ if (!interactive || confirmrest)
+ return (1);
+ printf("%s %s? ", cmd, file);
+ (void)fflush(stdout);
+ if (fgets(line, sizeof(line), stdin) == NULL)
+ return (0);
+ switch (tolower((unsigned char)*line)) {
+ case 'n':
+ return (0);
+ case 'p':
+ interactive = 0;
+ puts("Interactive mode: off.");
+ break;
+ case 'a':
+ confirmrest = 1;
+ printf("Prompting off for duration of %s.\n", cmd);
+ break;
+ }
+ return (1);
+}
+
+/*
+ * Glob a local file name specification with
+ * the expectation of a single return value.
+ * Can't control multiple values being expanded
+ * from the expression, we return only the first.
+ */
+int
+globulize(cpp)
+ char **cpp;
+{
+ glob_t gl;
+ int flags;
+
+ if (!doglob)
+ return (1);
+
+ flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
+ memset(&gl, 0, sizeof(gl));
+ if (glob(*cpp, flags, NULL, &gl) ||
+ gl.gl_pathc == 0) {
+ warnx("%s: not found", *cpp);
+ globfree(&gl);
+ return (0);
+ }
+ *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
+ globfree(&gl);
+ return (1);
+}
+
+/*
+ * determine size of remote file
+ */
+off_t
+remotesize(file, noisy)
+ const char *file;
+ int noisy;
+{
+ int overbose;
+ off_t size;
+
+ overbose = verbose;
+ size = -1;
+ if (debug == 0)
+ verbose = -1;
+ if (command("SIZE %s", file) == COMPLETE)
+ sscanf(reply_string, "%*s %qd", &size);
+ else if (noisy && debug == 0)
+ puts(reply_string);
+ verbose = overbose;
+ return (size);
+}
+
+/*
+ * determine last modification time (in GMT) of remote file
+ */
+time_t
+remotemodtime(file, noisy)
+ const char *file;
+ int noisy;
+{
+ int overbose;
+ time_t rtime;
+
+ overbose = verbose;
+ rtime = -1;
+ if (debug == 0)
+ verbose = -1;
+ if (command("MDTM %s", file) == COMPLETE) {
+ struct tm timebuf;
+ int yy, mo, day, hour, min, sec;
+ sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
+ &day, &hour, &min, &sec);
+ memset(&timebuf, 0, sizeof(timebuf));
+ timebuf.tm_sec = sec;
+ timebuf.tm_min = min;
+ timebuf.tm_hour = hour;
+ timebuf.tm_mday = day;
+ timebuf.tm_mon = mo - 1;
+ timebuf.tm_year = yy - 1900;
+ timebuf.tm_isdst = -1;
+ rtime = mktime(&timebuf);
+ if (rtime == -1 && (noisy || debug != 0))
+ printf("Can't convert %s to a time.\n", reply_string);
+ else
+ rtime += timebuf.tm_gmtoff; /* conv. local -> GMT */
+ } else if (noisy && debug == 0)
+ puts(reply_string);
+ verbose = overbose;
+ return (rtime);
+}
+
+void
+updateprogressmeter()
+{
+ static pid_t pgrp = -1;
+ int ctty_pgrp;
+
+ if (pgrp == -1)
+ pgrp = getpgrp();
+
+ /*
+ * print progress bar only if we are foreground process.
+ */
+ if (ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
+ ctty_pgrp == (int)pgrp)
+ progressmeter(0);
+}
+
+/*
+ * Display a transfer progress bar if progress is non-zero.
+ * SIGALRM is hijacked for use by this function.
+ * - Before the transfer, set filesize to size of file (or -1 if unknown),
+ * and call with flag = -1. This starts the once per second timer,
+ * and a call to updateprogressmeter() upon SIGALRM.
+ * - During the transfer, updateprogressmeter will call progressmeter
+ * with flag = 0
+ * - After the transfer, call with flag = 1
+ */
+static struct timeval start;
+
+void
+progressmeter(flag)
+ int flag;
+{
+ /*
+ * List of order of magnitude prefixes.
+ * The last is `P', as 2^64 = 16384 Petabytes
+ */
+ static const char prefixes[] = " KMGTP";
+
+ static struct timeval lastupdate;
+ static off_t lastsize;
+ struct timeval now, td, wait;
+ off_t cursize, abbrevsize;
+ double elapsed;
+ int ratio, barlength, i, remaining;
+ char buf[256];
+
+ if (flag == -1) {
+ (void)gettimeofday(&start, (struct timezone *)0);
+ lastupdate = start;
+ lastsize = restart_point;
+ }
+ (void)gettimeofday(&now, (struct timezone *)0);
+ if (!progress || filesize <= 0)
+ return;
+ cursize = bytes + restart_point;
+
+ ratio = cursize * 100 / filesize;
+ ratio = MAX(ratio, 0);
+ ratio = MIN(ratio, 100);
+ snprintf(buf, sizeof(buf), "\r%3d%% ", ratio);
+
+ barlength = ttywidth - 30;
+ if (barlength > 0) {
+ i = barlength * ratio / 100;
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "|%.*s%*s|", i,
+"*****************************************************************************"
+"*****************************************************************************",
+ barlength - i, "");
+ }
+
+ i = 0;
+ abbrevsize = cursize;
+ while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
+ i++;
+ abbrevsize >>= 10;
+ }
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ " %5qd %c%c ", abbrevsize, prefixes[i],
+ prefixes[i] == ' ' ? ' ' : 'B');
+
+ timersub(&now, &lastupdate, &wait);
+ if (cursize > lastsize) {
+ lastupdate = now;
+ lastsize = cursize;
+ if (wait.tv_sec >= STALLTIME) { /* fudge out stalled time */
+ start.tv_sec += wait.tv_sec;
+ start.tv_usec += wait.tv_usec;
+ }
+ wait.tv_sec = 0;
+ }
+
+ timersub(&now, &start, &td);
+ elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+
+ if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ " --:-- ETA");
+ } else if (wait.tv_sec >= STALLTIME) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ " - stalled -");
+ } else {
+ remaining = (int)((filesize - restart_point) /
+ (bytes / elapsed) - elapsed);
+ i = remaining / 3600;
+ if (i)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "%2d:", i);
+ else
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ " ");
+ i = remaining % 3600;
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "%02d:%02d ETA", i / 60, i % 60);
+ }
+ (void)write(STDOUT_FILENO, buf, strlen(buf));
+
+ if (flag == -1) {
+ (void)signal(SIGALRM, updateprogressmeter);
+ alarmtimer(1); /* set alarm timer for 1 Hz */
+ } else if (flag == 1) {
+ alarmtimer(0);
+ (void)putchar('\n');
+ }
+ fflush(stdout);
+}
+
+/*
+ * Display transfer statistics.
+ * Requires start to be initialised by progressmeter(-1),
+ * direction to be defined by xfer routines, and filesize and bytes
+ * to be updated by xfer routines
+ * If siginfo is nonzero, an ETA is displayed, and the output goes to STDERR
+ * instead of STDOUT.
+ */
+void
+ptransfer(siginfo)
+ int siginfo;
+{
+ struct timeval now, td;
+ double elapsed;
+ off_t bs;
+ int meg, remaining, hh;
+ char buf[100];
+
+ if (!verbose && !siginfo)
+ return;
+
+ (void)gettimeofday(&now, (struct timezone *)0);
+ timersub(&now, &start, &td);
+ elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+ bs = bytes / (elapsed == 0.0 ? 1 : elapsed);
+ meg = 0;
+ if (bs > (1024 * 1024))
+ meg = 1;
+ (void)snprintf(buf, sizeof(buf),
+ "%qd byte%s %s in %.2f seconds (%.2f %sB/s)\n",
+ bytes, bytes == 1 ? "" : "s", direction, elapsed,
+ bs / (1024.0 * (meg ? 1024.0 : 1.0)), meg ? "M" : "K");
+ if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
+ && bytes + restart_point <= filesize) {
+ remaining = (int)((filesize - restart_point) /
+ (bytes / elapsed) - elapsed);
+ hh = remaining / 3600;
+ remaining %= 3600;
+ /* "buf+len(buf) -1" to overwrite \n */
+ snprintf(buf + strlen(buf) - 1, sizeof(buf) - strlen(buf),
+ " ETA: %02d:%02d:%02d\n", hh, remaining / 60,
+ remaining % 60);
+ }
+ (void)write(siginfo ? STDERR_FILENO : STDOUT_FILENO, buf, strlen(buf));
+}
+
+/*
+ * List words in stringlist, vertically arranged
+ */
+void
+list_vertical(sl)
+ StringList *sl;
+{
+ int i, j, w;
+ int columns, width, lines, items;
+ char *p;
+
+ width = items = 0;
+
+ for (i = 0 ; i < sl->sl_cur ; i++) {
+ w = strlen(sl->sl_str[i]);
+ if (w > width)
+ width = w;
+ }
+ width = (width + 8) &~ 7;
+
+ columns = ttywidth / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (sl->sl_cur + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ p = sl->sl_str[j * lines + i];
+ if (p)
+ fputs(p, stdout);
+ if (j * lines + i + lines >= sl->sl_cur) {
+ putchar('\n');
+ break;
+ }
+ w = strlen(p);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ (void)putchar('\t');
+ }
+ }
+ }
+}
+
+/*
+ * Update the global ttywidth value, using TIOCGWINSZ.
+ */
+void
+setttywidth(a)
+ int a;
+{
+ struct winsize winsize;
+
+ if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
+ ttywidth = winsize.ws_col;
+ else
+ ttywidth = 80;
+}
+
+/*
+ * Set the SIGALRM interval timer for wait seconds, 0 to disable.
+ */
+void
+alarmtimer(wait)
+ int wait;
+{
+ struct itimerval itv;
+
+ itv.it_value.tv_sec = wait;
+ itv.it_value.tv_usec = 0;
+ itv.it_interval = itv.it_value;
+ setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+/*
+ * Setup or cleanup EditLine structures
+ */
+#ifndef SMALL
+void
+controlediting()
+{
+ if (editing && el == NULL && hist == NULL) {
+ el = el_init(__progname, stdin, stdout); /* init editline */
+ hist = history_init(); /* init the builtin history */
+ history(hist, H_EVENT, 100); /* remember 100 events */
+ el_set(el, EL_HIST, history, hist); /* use history */
+
+ el_set(el, EL_EDITOR, "emacs"); /* default editor is emacs */
+ el_set(el, EL_PROMPT, prompt); /* set the prompt function */
+
+ /* add local file completion, bind to TAB */
+ el_set(el, EL_ADDFN, "ftp-complete",
+ "Context sensitive argument completion",
+ complete);
+ el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
+
+ el_source(el, NULL); /* read ~/.editrc */
+ el_set(el, EL_SIGNAL, 1);
+ } else if (!editing) {
+ if (hist) {
+ history_end(hist);
+ hist = NULL;
+ }
+ if (el) {
+ el_end(el);
+ el = NULL;
+ }
+ }
+}
+#endif /* !SMALL */
diff --git a/usr.bin/gcore/Makefile b/usr.bin/gcore/Makefile
index c7bf6e0..664813f 100644
--- a/usr.bin/gcore/Makefile
+++ b/usr.bin/gcore/Makefile
@@ -1,7 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= gcore
-SRCS= gcore.c md-${MACHINE}.c
+SRCS= gcore.c
+DPADD= ${LIBKVM}
LDADD= -lkvm
+.if ${MACHINE} != "sparc"
+SRCS+= md-nop.c
+.else
+SRCS+= md-${MACHINDE}.c
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/gcore/aoutcore.c b/usr.bin/gcore/aoutcore.c
new file mode 100644
index 0000000..7ecbe1c
--- /dev/null
+++ b/usr.bin/gcore/aoutcore.c
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+
+/*
+ * Originally written by Eric Cooper in Fall 1981.
+ * Inspired by a version 6 program by Len Levin, 1978.
+ * Several pieces of code lifted from Bill Joy's 4BSD ps.
+ * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
+ * Lawrence Berkeley Laboratory.
+ *
+ * Portions of this software were developed by the Computer Systems
+ * Engineering group at Lawrence Berkeley Laboratory under DARPA
+ * contract BG 91-66 and contributed to Berkeley.
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+
+#include <machine/vmparam.h>
+
+#include <a.out.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+void core __P((int, int, struct kinfo_proc *));
+void datadump __P((int, int, struct proc *, u_long, int));
+void usage __P((void));
+void userdump __P((int, struct proc *, u_long, int));
+
+kvm_t *kd;
+/* XXX undocumented routine, should be in kvm.h? */
+ssize_t kvm_uread __P((kvm_t *, const struct proc *, u_long, char *, size_t));
+
+
+static int data_offset;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct proc *p;
+ struct kinfo_proc *ki;
+ struct exec exec;
+ int ch, cnt, efd, fd, pid, sflag, uid;
+ char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
+
+ sflag = 0;
+ corefile = NULL;
+ while ((ch = getopt(argc, argv, "c:s")) != -1) {
+ switch (ch) {
+ case 'c':
+ corefile = optarg;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 2)
+ usage();
+
+ kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
+ if (kd == NULL)
+ err(1, "%s", errbuf);
+
+ uid = getuid();
+ pid = atoi(argv[1]);
+
+ ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
+ if (ki == NULL || cnt != 1)
+ err(1, "%d: not found", pid);
+
+ p = &ki->kp_proc;
+ if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
+ err(1, "%d: not owner", pid);
+
+ if (p->p_stat == SZOMB)
+ err(1, "%d: zombie", pid);
+
+ if (p->p_flag & P_WEXIT)
+ err(0, "process exiting");
+ if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
+ err(1, "%d: system process");
+
+ if (corefile == NULL) {
+ (void)snprintf(fname, sizeof(fname), "core.%d", pid);
+ corefile = fname;
+ }
+ fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
+ if (fd < 0)
+ err(1, "%s: %s\n", corefile, strerror(errno));
+
+ efd = open(argv[0], O_RDONLY, 0);
+ if (efd < 0)
+ err(1, "%s: %s\n", argv[0], strerror(errno));
+
+ cnt = read(efd, &exec, sizeof(exec));
+ if (cnt != sizeof(exec))
+ err(1, "%s exec header: %s",
+ argv[0], cnt > 0 ? strerror(EIO) : strerror(errno));
+
+ data_offset = N_DATOFF(exec);
+
+ if (sflag && kill(pid, SIGSTOP) < 0)
+ err(0, "%d: stop signal: %s", pid, strerror(errno));
+
+ core(efd, fd, ki);
+
+ if (sflag && kill(pid, SIGCONT) < 0)
+ err(0, "%d: continue signal: %s", pid, strerror(errno));
+ (void)close(fd);
+
+ exit(0);
+}
+
+/*
+ * core --
+ * Build the core file.
+ */
+void
+core(efd, fd, ki)
+ int efd;
+ int fd;
+ struct kinfo_proc *ki;
+{
+ union {
+ struct user user;
+ char ubytes[ctob(UPAGES)];
+ } uarea;
+ struct proc *p = &ki->kp_proc;
+ int tsize = ki->kp_eproc.e_vm.vm_tsize;
+ int dsize = ki->kp_eproc.e_vm.vm_dsize;
+ int ssize = ki->kp_eproc.e_vm.vm_ssize;
+ int cnt;
+
+ /* Read in user struct */
+ cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea));
+ if (cnt != sizeof(uarea))
+ err(1, "read user structure: %s",
+ cnt > 0 ? strerror(EIO) : strerror(errno));
+
+ /*
+ * Fill in the eproc vm parameters, since these are garbage unless
+ * the kernel is dumping core or something.
+ */
+ uarea.user.u_kproc = *ki;
+
+ /* Dump user area */
+ cnt = write(fd, &uarea, sizeof(uarea));
+ if (cnt != sizeof(uarea))
+ err(1, "write user structure: %s",
+ cnt > 0 ? strerror(EIO) : strerror(errno));
+
+ /* Dump data segment */
+ datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize);
+
+ /* Dump stack segment */
+ userdump(fd, p, USRSTACK - ctob(ssize), ssize);
+
+ /* Dump machine dependent portions of the core. */
+ md_core(kd, fd, ki);
+}
+
+void
+datadump(efd, fd, p, addr, npage)
+ register int efd;
+ register int fd;
+ struct proc *p;
+ register u_long addr;
+ register int npage;
+{
+ register int cc, delta;
+ char buffer[PAGE_SIZE];
+
+ delta = data_offset - addr;
+ while (--npage >= 0) {
+ cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE) {
+ /* Try to read the page from the executable. */
+ if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
+ err(1, "seek executable: %s", strerror(errno));
+ cc = read(efd, buffer, sizeof(buffer));
+ if (cc != sizeof(buffer))
+ if (cc < 0)
+ err(1, "read executable: %s",
+ strerror(errno));
+ else /* Assume untouched bss page. */
+ bzero(buffer, sizeof(buffer));
+ }
+ cc = write(fd, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
+ err(1, "write data segment: %s",
+ cc > 0 ? strerror(EIO) : strerror(errno));
+ addr += PAGE_SIZE;
+ }
+}
+
+void
+userdump(fd, p, addr, npage)
+ register int fd;
+ struct proc *p;
+ register u_long addr;
+ register int npage;
+{
+ register int cc;
+ char buffer[PAGE_SIZE];
+
+ while (--npage >= 0) {
+ cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
+ /* Could be an untouched fill-with-zero page. */
+ bzero(buffer, PAGE_SIZE);
+ cc = write(fd, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
+ err(1, "write stack segment: %s",
+ cc > 0 ? strerror(EIO) : strerror(errno));
+ addr += PAGE_SIZE;
+ }
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n");
+ exit(1);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(int fatal, const char *fmt, ...)
+#else
+err(fatal, fmt, va_alist)
+ int fatal;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "gcore: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/usr.bin/gcore/gcore.1 b/usr.bin/gcore/gcore.1
index 42fddbc..ce8fc68 100644
--- a/usr.bin/gcore/gcore.1
+++ b/usr.bin/gcore/gcore.1
@@ -31,7 +31,7 @@
.\"
.\" @(#)gcore.1 8.2 (Berkeley) 4/18/94
.\"
-.Dd "April 18, 1994"
+.Dd April 18, 1994
.Dt GCORE 1
.Os BSD 4.2
.Sh NAME
@@ -76,7 +76,8 @@ The core image.
.Dp
.Sh HISTORY
.Nm Gcore
-appeared in 4.2BSD.
+appeared in
+.Bx 4.2 .
.Sh BUGS
Context switches or paging activity that occur while
.Nm gcore
@@ -84,7 +85,11 @@ is running may cause the program to become confused.
For best results, use -s to temporarily stop the target process.
.Pp
.Nm Gcore
-is not compatible with the original 4.2BSD version.
-In particular, 4.4BSD requires the
+is not compatible with the original
+.Bx 4.2
+version.
+In particular,
+.Bx 4.4
+requires the
.Ar exec
argument.
diff --git a/usr.bin/gcore/gcore.c b/usr.bin/gcore/gcore.c
index 2ecca18..7ecbe1c 100644
--- a/usr.bin/gcore/gcore.c
+++ b/usr.bin/gcore/gcore.c
@@ -80,7 +80,8 @@ void userdump __P((int, struct proc *, u_long, int));
kvm_t *kd;
/* XXX undocumented routine, should be in kvm.h? */
-ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t));
+ssize_t kvm_uread __P((kvm_t *, const struct proc *, u_long, char *, size_t));
+
static int data_offset;
@@ -97,7 +98,7 @@ main(argc, argv)
sflag = 0;
corefile = NULL;
- while ((ch = getopt(argc, argv, "c:s")) != EOF) {
+ while ((ch = getopt(argc, argv, "c:s")) != -1) {
switch (ch) {
case 'c':
corefile = optarg;
@@ -122,7 +123,7 @@ main(argc, argv)
uid = getuid();
pid = atoi(argv[1]);
-
+
ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
if (ki == NULL || cnt != 1)
err(1, "%d: not found", pid);
@@ -227,28 +228,28 @@ datadump(efd, fd, p, addr, npage)
register int npage;
{
register int cc, delta;
- char buffer[NBPG];
-
+ char buffer[PAGE_SIZE];
+
delta = data_offset - addr;
while (--npage >= 0) {
- cc = kvm_uread(kd, p, addr, buffer, NBPG);
- if (cc != NBPG) {
+ cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE) {
/* Try to read the page from the executable. */
if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
err(1, "seek executable: %s", strerror(errno));
cc = read(efd, buffer, sizeof(buffer));
if (cc != sizeof(buffer))
- if (cc < 0)
+ if (cc < 0)
err(1, "read executable: %s",
strerror(errno));
else /* Assume untouched bss page. */
bzero(buffer, sizeof(buffer));
}
- cc = write(fd, buffer, NBPG);
- if (cc != NBPG)
+ cc = write(fd, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
err(1, "write data segment: %s",
cc > 0 ? strerror(EIO) : strerror(errno));
- addr += NBPG;
+ addr += PAGE_SIZE;
}
}
@@ -260,18 +261,18 @@ userdump(fd, p, addr, npage)
register int npage;
{
register int cc;
- char buffer[NBPG];
+ char buffer[PAGE_SIZE];
while (--npage >= 0) {
- cc = kvm_uread(kd, p, addr, buffer, NBPG);
- if (cc != NBPG)
+ cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
/* Could be an untouched fill-with-zero page. */
- bzero(buffer, NBPG);
- cc = write(fd, buffer, NBPG);
- if (cc != NBPG)
+ bzero(buffer, PAGE_SIZE);
+ cc = write(fd, buffer, PAGE_SIZE);
+ if (cc != PAGE_SIZE)
err(1, "write stack segment: %s",
cc > 0 ? strerror(EIO) : strerror(errno));
- addr += NBPG;
+ addr += PAGE_SIZE;
}
}
diff --git a/usr.bin/gcore/md-sparc.c b/usr.bin/gcore/md-sparc.c
index 794ceb1..5df8a57 100644
--- a/usr.bin/gcore/md-sparc.c
+++ b/usr.bin/gcore/md-sparc.c
@@ -164,7 +164,7 @@ md_core(kd, fd, ki)
* It's possible to be missing the bottomost
* page because a stack page hasn't been allocated
* for the register save area. Shift over
- * the stack segment by a page, and update
+ * the stack segment by a page, and update
* the u-area to reflect the new stack size. YECH!
*/
shift_page(fd, off, ssize);
diff --git a/usr.bin/gencat/Makefile b/usr.bin/gencat/Makefile
new file mode 100644
index 0000000..b738deb
--- /dev/null
+++ b/usr.bin/gencat/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG= gencat
+SRCS= gencat.c genlib.c
+NOMAN= yes
+
+CFLAGS+= -I${.CURDIR}/../../lib/libc/nls
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/gencat/gencat.c b/usr.bin/gencat/gencat.c
new file mode 100644
index 0000000..37c7990
--- /dev/null
+++ b/usr.bin/gencat/gencat.c
@@ -0,0 +1,255 @@
+
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+/* Edit History
+
+01/18/91 3 hamilton #if not reparsed
+01/12/91 2 schulert conditionally use prototypes
+12/23/90 2 hamilton Fix fd == NULL to fd < 0
+11/03/90 1 hamilton Alphalpha->Alfalfa & OmegaMail->Poste
+08/13/90 1 schulert move from ua to omu
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef SYSV
+#include <sys/fcntl.h>
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#endif
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "gencat.h"
+
+/*
+ * The spec says the syntax is "gencat catfile msgfile...".
+ * We extend it to:
+ * gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
+ * Flags are order dependant, we'll take whatever lang was most recently chosen
+ * and use it to generate the next header file. The header files are generated
+ * at the point in the command line they are listed. Thus the sequence:
+ * gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
+ * will put constants from foo.mcs into foo.h and constants from bar.mcs into
+ * bar.h. Constants are not saved in the catalog file, so nothing will come
+ * from that, even if things have been defined before. The constants in foo.h
+ * will be in C syntax, in bar.H in C++ syntax.
+ */
+
+#if ANSI_C || defined(__cplusplus)
+# define P_(x) x
+#else
+# define P_(x) /**/
+#endif
+
+static void writeIfChanged P_((char *fname, int lang, int orConsts));
+
+#undef P_
+
+void usage() {
+ fprintf(stderr, "Use: gencat [-new] [-or] [-lang C|C++|ANSIC]\n");
+ fprintf(stderr, " catfile msgfile [-h <header-file>]...\n");
+}
+
+void main(
+#if ANSI_C || defined(__cplusplus)
+ int argc, char *argv[])
+#else
+ argc, argv)
+int argc;
+char *argv[];
+#endif
+{
+ int ofd, ifd, i;
+ FILE *fptr;
+ char *catfile = NULL;
+ char *input = NULL;
+ int lang = MCLangC;
+ int new = False;
+ int orConsts = False;
+
+ for (i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "-lang") == 0) {
+ ++i;
+ if (strcmp(argv[i], "C") == 0) lang = MCLangC;
+ else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
+ else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
+ else {
+ fprintf(stderr, "gencat: Unrecognized language: %s\n", argv[i]);
+ exit(1);
+ }
+ } else if (strcmp(argv[i], "-h") == 0) {
+ if (!input) {
+ fprintf(stderr, "gencat: Can't write to a header before reading something.\n");
+ exit(1);
+ }
+ ++i;
+ writeIfChanged(argv[i], lang, orConsts);
+ } else if (strcmp(argv[i], "-new") == 0) {
+ if (catfile) {
+ fprintf(stderr, "gencat: You must specify -new before the catalog file name\n");
+ exit(1);
+ }
+ new = True;
+ } else if (strcmp(argv[i], "-or") == 0) {
+ orConsts = ~orConsts;
+ } else {
+ usage();
+ exit(1);
+ }
+ } else {
+ if (!catfile) {
+ catfile = argv[i];
+ if (new) {
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "gencat: Unable to create a new %s.\n", catfile);
+ exit(1);
+ }
+ } else if ((ofd = open(catfile, O_RDONLY)) < 0) {
+ if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "gencat: Unable to create %s.\n", catfile);
+ exit(1);
+ }
+ } else {
+ MCReadCat(ofd);
+ close(ofd);
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) {
+ fprintf(stderr, "gencat: Unable to truncate %s.\n", catfile);
+ exit(1);
+ }
+ }
+ } else {
+ input = argv[i];
+ if ((ifd = open(input, O_RDONLY)) < 0) {
+ fprintf(stderr, "gencat: Unable to read %s\n", input);
+ exit(1);
+ }
+ MCParse(ifd);
+ close(ifd);
+ }
+ }
+ }
+ if (catfile) {
+ MCWriteCat(ofd);
+ exit(0);
+ } else {
+ usage();
+ exit(1);
+ }
+}
+
+static void writeIfChanged(
+#if ANSI_C || defined(__cplusplus)
+ char *fname, int lang, int orConsts)
+#else
+ fname, lang, orConsts)
+char *fname;
+int lang;
+int orConsts;
+#endif
+{
+ char tmpname[32];
+ char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
+ int fd, tfd;
+ int diff = False;
+ int c, len, tlen;
+ struct stat sbuf;
+
+ /* If it doesn't exist, just create it */
+ if (stat(fname, &sbuf)) {
+ if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "gencat: Unable to create header file %s.\n", fname);
+ exit(1);
+ }
+ MCWriteConst(fd, lang, orConsts);
+ close(fd);
+ return;
+ }
+
+ /* If it does exist, create a temp file for now */
+ sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
+ if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "gencat: Unable to open temporary file: %s\n", tmpname);
+ exit(1);
+ }
+ unlink(tmpname);
+
+ /* Write to the temp file and rewind */
+ MCWriteConst(tfd, lang, orConsts);
+
+ /* Open the real header file */
+ if ((fd = open(fname, O_RDONLY)) < 0) {
+ fprintf(stderr, "gencat: Unable to read header file: %s\n", fname);
+ exit(1);
+ }
+
+ /* Backup to the start of the temp file */
+ if (lseek(tfd, 0L, L_SET) < 0) {
+ fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
+ exit(1);
+ }
+
+ /* Now compare them */
+ while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
+ if ((len = read(fd, buf, BUFSIZ)) != tlen) {
+ diff = True;
+ goto done;
+ }
+ for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
+ if (*tptr != *cptr) {
+ diff = True;
+ goto done;
+ }
+ }
+ }
+done:
+ if (diff) {
+ if (lseek(tfd, 0L, L_SET) < 0) {
+ fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
+ exit(1);
+ }
+ close(fd);
+ if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) {
+ fprintf(stderr, "gencat: Unable to truncate header file: %s\n", fname);
+ exit(1);
+ }
+ while ((len = read(tfd, buf, BUFSIZ)) > 0) {
+ if (write(fd, buf, len) != len) {
+ fprintf(stderr, "gencat: Error writing to header file: %s\n", fname);
+ }
+ }
+ }
+ close(fd);
+ close(tfd);
+}
diff --git a/usr.bin/gencat/gencat.h b/usr.bin/gencat/gencat.h
new file mode 100644
index 0000000..c12a194
--- /dev/null
+++ b/usr.bin/gencat/gencat.h
@@ -0,0 +1,107 @@
+
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+/* Edit History
+
+02/25/91 2 nazgul Added MCGetByteOrder
+01/18/91 2 hamilton #if not reparsed
+01/12/91 2 schulert conditionally use prototypes
+11/03/90 1 hamilton Alphalpha->Alfalfa & OmegaMail->Poste
+08/13/90 1 schulert move from ua to omu
+*/
+
+#ifndef gencat_h
+#define gencat_h
+
+/*
+ * $set n comment
+ * My extension: If the comment begins with # treat the next string
+ * as a constant identifier.
+ * $delset n comment
+ * n goes from 1 to NL_SETMAX
+ * Deletes a set from the MC
+ * $ comment
+ * My extension: If comment begins with # treat the next string as
+ * a constant identifier for the next message.
+ * m message-text
+ * m goes from 1 to NL_MSGMAX
+ * If message-text is empty, and a space or tab is present, put
+ * empty string in catalog.
+ * If message-text is empty, delete the message.
+ * Length of text is 0 to NL_TEXTMAX
+ * My extension: If '#' is used instead of a number, the number
+ * is generated automatically. A # followed by anything is an empty message.
+ * $quote c
+ * Optional quote character which can suround message-text to
+ * show where spaces are.
+ *
+ * Escape Characters
+ * \n (newline), \t (horiz tab), \v (vert tab), \b (backspace),
+ * \r (carriage return), \f (formfeed), \\ (backslash), \ddd (bitpattern
+ * in octal).
+ * Also, \ at end of line is a continuation.
+ *
+ */
+
+#define MCLangC 0
+#define MCLangCPlusPlus 1
+#define MCLangANSIC 2
+
+#define MAXTOKEN 1024
+
+#if !defined(ANSI_C) && (defined(__STDC__) || defined(_AIX))
+# define ANSI_C 1
+#endif
+
+#if ANSI_C || defined(__cplusplus)
+# define P_(x) x
+#else
+# define P_(x) /**/
+#endif
+
+extern void MCAddSet P_((int setId, char *c));
+extern void MCDelSet P_((int setId));
+extern void MCAddMsg P_((int msgId, char *msg, char *c));
+extern void MCDelMsg P_((int msgId));
+extern void MCParse P_((int fd));
+extern void MCReadCat P_((int fd));
+extern void MCWriteConst P_((int fd, int type, int orConsts));
+extern void MCWriteCat P_((int fd));
+extern long MCGetByteOrder P_((void));
+
+#ifndef True
+# define True ~0
+# define False 0
+#endif
+
+#endif
diff --git a/usr.bin/gencat/genlib.c b/usr.bin/gencat/genlib.c
new file mode 100644
index 0000000..3b42987
--- /dev/null
+++ b/usr.bin/gencat/genlib.c
@@ -0,0 +1,896 @@
+/* -*-c++-*- */
+
+
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+/* Edit History
+
+02/25/91 5 nazgul Added flag for MS byteorder
+01/14/91 4 nazgul Off by one on number specified entries
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef SYSV
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#include <memory.h>
+static int bcopy(src, dst, length)
+char *src, *dst;
+int length;
+{
+ memcpy(dst, src, length);
+}
+static int bzero(b, length)
+char *b;
+int length;
+{
+ memset(b, '\0', length);
+}
+#endif
+#include <sys/file.h>
+#include <ctype.h>
+#include "msgcat.h"
+#include "gencat.h"
+
+static char *curline = NULL;
+static long lineno = 0;
+
+static void warning(cptr, msg)
+char *cptr;
+char *msg;
+{
+ fprintf(stderr, "gencat: %s on line %d\n", msg, lineno);
+ fprintf(stderr, "%s\n", curline);
+ if (cptr) {
+ char *tptr;
+ for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
+ fprintf(stderr, "^\n");
+ }
+}
+
+static void error(cptr, msg)
+char *cptr;
+char *msg;
+{
+ warning(cptr, msg);
+ exit(1);
+}
+
+static void corrupt() {
+ error(NULL, "corrupt message catalog");
+}
+static void nomem() {
+ error(NULL, "out of memory");
+}
+
+static char *getline(fd)
+int fd;
+{
+ static long len = 0, curlen = BUFSIZ;
+ static char buf[BUFSIZ], *bptr = buf, *bend = buf;
+ char *cptr, *cend;
+ long buflen;
+
+ if (!curline) {
+ curline = (char *) malloc(curlen);
+ if (!curline) nomem();
+ }
+ ++lineno;
+
+ cptr = curline;
+ cend = curline + curlen;
+ while (True) {
+ for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
+ if (*bptr == '\n') {
+ *cptr = '\0';
+ ++bptr;
+ return(curline);
+ } else *cptr = *bptr;
+ }
+ if (bptr == bend) {
+ buflen = read(fd, buf, BUFSIZ);
+ if (buflen <= 0) {
+ if (cptr > curline) {
+ *cptr = '\0';
+ return(curline);
+ }
+ return(NULL);
+ }
+ bend = buf + buflen;
+ bptr = buf;
+ }
+ if (cptr == cend) {
+ cptr = curline = (char *) realloc(curline, curlen *= 2);
+ cend = curline + curlen;
+ }
+ }
+}
+
+
+static char *token(cptr)
+char *cptr;
+{
+ static char tok[MAXTOKEN+1];
+ char *tptr = tok;
+
+ while (*cptr && isspace(*cptr)) ++cptr;
+ while (*cptr && !isspace(*cptr)) *tptr++ = *cptr++;
+ *tptr = '\0';
+ return(tok);
+}
+static char *wskip(cptr)
+char *cptr;
+{
+ if (!*cptr || !isspace(*cptr)) {
+ warning(cptr, "expected a space");
+ return(cptr);
+ }
+ while (*cptr && isspace(*cptr)) ++cptr;
+ return(cptr);
+}
+static char *cskip(cptr)
+char *cptr;
+{
+ if (!*cptr || isspace(*cptr)) {
+ warning(cptr, "wasn't expecting a space");
+ return(cptr);
+ }
+ while (*cptr && !isspace(*cptr)) ++cptr;
+ return(cptr);
+}
+
+static char *getmsg(fd, cptr, quote)
+int fd;
+char *cptr;
+char quote;
+{
+ static char *msg = NULL;
+ static long msglen = 0;
+ long clen, i;
+ char *tptr;
+
+ int needq;
+
+ if (quote && *cptr == quote) {
+ needq = True;
+ ++cptr;
+ } else needq = False;
+
+ clen = strlen(cptr) + 1;
+ if (clen > msglen) {
+ if (msglen) msg = (char *) realloc(msg, clen);
+ else msg = (char *) malloc(clen);
+ msglen = clen;
+ }
+ tptr = msg;
+
+ while (*cptr) {
+ if (quote && *cptr == quote) {
+ char *tmp;
+ tmp = cptr+1;
+ if (*tmp && (!isspace(*tmp) || *wskip(tmp))) {
+ warning(cptr, "unexpected quote character, ignoreing");
+ *tptr++ = *cptr++;
+ } else {
+ *cptr = '\0';
+ }
+ } else if (*cptr == '\\') {
+ ++cptr;
+ switch (*cptr) {
+ case '\0':
+ cptr = getline(fd);
+ if (!cptr) error(NULL, "premature end of file");
+ msglen += strlen(cptr);
+ i = tptr - msg;
+ msg = (char *) realloc(msg, msglen);
+ tptr = msg + i;
+ break;
+ case 'n':
+ *tptr++ = '\n';
+ ++cptr;
+ break;
+ case 't':
+ *tptr++ = '\t';
+ ++cptr;
+ break;
+ case 'v':
+ *tptr++ = '\v';
+ ++cptr;
+ break;
+ case 'b':
+ *tptr++ = '\b';
+ ++cptr;
+ break;
+ case 'r':
+ *tptr++ = '\r';
+ ++cptr;
+ break;
+ case 'f':
+ *tptr++ = '\f';
+ ++cptr;
+ break;
+ case '"':
+ *tptr++ = '"';
+ ++cptr;
+ break;
+ case '\'':
+ *tptr++ = '\'';
+ ++cptr;
+ break;
+ case '\\':
+ *tptr++ = '\\';
+ ++cptr;
+ break;
+ default:
+ if (isdigit(*cptr)) {
+ *tptr = 0;
+ for (i = 0; i < 3; ++i) {
+ if (!isdigit(*cptr)) break;
+ if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
+ *tptr *= 8;
+ *tptr += (*cptr - '0');
+ ++cptr;
+ }
+ } else {
+ warning(cptr, "unrecognized escape sequence");
+ }
+ }
+ } else {
+ *tptr++ = *cptr++;
+ }
+ }
+ *tptr = '\0';
+ return(msg);
+}
+
+
+
+static char *dupstr(ostr)
+char *ostr;
+{
+ char *nstr;
+
+ nstr = (char *) malloc(strlen(ostr) + 1);
+ if (!nstr) error(NULL, "unable to allocate storage");
+ strcpy(nstr, ostr);
+ return(nstr);
+}
+
+
+/*
+ * The Global Stuff
+ */
+
+
+typedef struct _msgT {
+ long msgId;
+ char *str;
+ char *hconst;
+ long offset;
+ struct _msgT *prev, *next;
+} msgT;
+typedef struct _setT {
+ long setId;
+ char *hconst;
+ msgT *first, *last;
+ struct _setT *prev, *next;
+} setT;
+typedef struct {
+ setT *first, *last;
+} catT;
+
+static setT *curSet;
+static catT *cat;
+
+/*
+ * Find the current byte order. There are of course some others, but this will do
+ * for now. Note that all we care about is "long".
+ */
+long MCGetByteOrder() {
+ long l = 0x00010203;
+ char *cptr = (char *) &l;
+
+ if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
+ return MC68KByteOrder;
+ else return MCn86ByteOrder;
+}
+
+
+void MCParse(
+#if PROTO
+ int fd)
+#else
+ fd)
+int fd;
+#endif
+{
+ char *cptr, *str;
+ int setid, msgid = 0;
+ char hconst[MAXTOKEN+1];
+ char quote = 0;
+ int i;
+
+ if (!cat) {
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+ }
+
+ hconst[0] = '\0';
+
+ while (cptr = getline(fd)) {
+ if (*cptr == '$') {
+ ++cptr;
+ if (strncmp(cptr, "set", 3) == 0) {
+ cptr += 3;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ cptr = cskip(cptr);
+ if (*cptr) cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ MCAddSet(setid, token(cptr));
+ } else MCAddSet(setid, NULL);
+ msgid = 0;
+ } else if (strncmp(cptr, "delset", 6) == 0) {
+ cptr += 6;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ MCDelSet(setid);
+ } else if (strncmp(cptr, "quote", 5) == 0) {
+ cptr += 5;
+ if (!*cptr) quote = 0;
+ else {
+ cptr = wskip(cptr);
+ if (!*cptr) quote = 0;
+ else quote = *cptr;
+ }
+ } else if (isspace(*cptr)) {
+ cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ strcpy(hconst, token(cptr));
+ }
+ } else {
+ if (*cptr) {
+ cptr = wskip(cptr);
+ if (*cptr) warning(cptr, "unrecognized line");
+ }
+ }
+ } else {
+ if (isdigit(*cptr) || *cptr == '#') {
+ if (*cptr == '#') {
+ ++msgid;
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ if (!isspace(*cptr)) warning(cptr, "expected a space");
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ } else {
+ msgid = atoi(cptr);
+ cptr = cskip(cptr);
+ cptr = wskip(cptr);
+ /* if (*cptr) ++cptr; */
+ }
+ if (!*cptr) MCDelMsg(msgid);
+ else {
+ str = getmsg(fd, cptr, quote);
+ MCAddMsg(msgid, str, hconst);
+ hconst[0] = '\0';
+ }
+ }
+ }
+ }
+}
+
+void MCReadCat(
+#if PROTO
+ int fd)
+#else
+ fd)
+int fd;
+#endif
+{
+ MCHeaderT mcHead;
+ MCMsgT mcMsg;
+ MCSetT mcSet;
+ msgT *msg;
+ setT *set;
+ int i;
+ char *data;
+
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+
+ if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt();
+ if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt();
+ if (mcHead.majorVer != MCMajorVer) error(NULL, "unrecognized catalog version");
+ if ((mcHead.flags & MCGetByteOrder()) == 0) error(NULL, "wrong byte order");
+
+ if (lseek(fd, mcHead.firstSet, L_SET) == -1) corrupt();
+
+ while (True) {
+ if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
+ if (mcSet.invalid) continue;
+
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(*set));
+ if (cat->first) {
+ cat->last->next = set;
+ set->prev = cat->last;
+ cat->last = set;
+ } else cat->first = cat->last = set;
+
+ set->setId = mcSet.setId;
+
+ /* Get the data */
+ if (mcSet.dataLen) {
+ data = (char *) malloc(mcSet.dataLen);
+ if (!data) nomem();
+ if (lseek(fd, mcSet.data.off, L_SET) == -1) corrupt();
+ if (read(fd, data, mcSet.dataLen) != mcSet.dataLen) corrupt();
+ if (lseek(fd, mcSet.u.firstMsg, L_SET) == -1) corrupt();
+
+ for (i = 0; i < mcSet.numMsgs; ++i) {
+ if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt();
+ if (mcMsg.invalid) {
+ --i;
+ continue;
+ }
+
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(*msg));
+ if (set->first) {
+ set->last->next = msg;
+ msg->prev = set->last;
+ set->last = msg;
+ } else set->first = set->last = msg;
+
+ msg->msgId = mcMsg.msgId;
+ msg->str = dupstr((char *) (data + mcMsg.msg.off));
+ }
+ free(data);
+ }
+ if (!mcSet.nextSet) break;
+ if (lseek(fd, mcSet.nextSet, L_SET) == -1) corrupt();
+ }
+}
+
+
+static void printS(fd, str)
+int fd;
+char *str;
+{
+ write(fd, str, strlen(str));
+}
+static void printL(fd, l)
+int fd;
+long l;
+{
+ char buf[32];
+ sprintf(buf, "%ld", l);
+ write(fd, buf, strlen(buf));
+}
+static void printLX(fd, l)
+int fd;
+long l;
+{
+ char buf[32];
+ sprintf(buf, "%lx", l);
+ write(fd, buf, strlen(buf));
+}
+
+static void genconst(fd, type, setConst, msgConst, val)
+int fd;
+int type;
+char *setConst;
+char *msgConst;
+long val;
+{
+ switch (type) {
+ case MCLangC:
+ if (!msgConst) {
+ printS(fd, "\n#define ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "#define ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t0x");
+ printLX(fd, val);
+ printS(fd, "\n");
+ break;
+ case MCLangCPlusPlus:
+ case MCLangANSIC:
+ if (!msgConst) {
+ printS(fd, "\nconst long ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "const long ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t= ");
+ printL(fd, val);
+ printS(fd, ";\n");
+ break;
+ default:
+ error(NULL, "not a recognized (programming) language type");
+ }
+}
+
+void MCWriteConst(
+#if PROTO
+ int fd, int type, int orConsts)
+#else
+ fd, type, orConsts)
+int fd;
+int type;
+int orConsts;
+#endif
+{
+ msgT *msg;
+ setT *set;
+ long id;
+
+ if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
+ printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
+ printS(fd, "#ifndef MCMakeId\n");
+ printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
+ printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
+ printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
+ printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
+ printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
+ printS(fd, "#endif\n");
+ }
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) {
+ if (orConsts) id = MCMakeId(set->setId, msg->msgId);
+ else id = msg->msgId;
+ genconst(fd, type, set->hconst, msg->hconst, id);
+ free(msg->hconst);
+ msg->hconst = NULL;
+ }
+ }
+ if (set->hconst) {
+ free(set->hconst);
+ set->hconst = NULL;
+ }
+ }
+}
+
+void MCWriteCat(
+#if PROTO
+ int fd)
+#else
+ fd)
+int fd;
+#endif
+{
+ MCHeaderT mcHead;
+ int cnt;
+ setT *set;
+ msgT *msg;
+ MCSetT mcSet;
+ MCMsgT mcMsg;
+ off_t pos;
+
+ bcopy(MCMagic, mcHead.magic, MCMagicLen);
+ mcHead.majorVer = MCMajorVer;
+ mcHead.minorVer = MCMinorVer;
+ mcHead.flags = MCGetByteOrder();
+ mcHead.firstSet = 0; /* We'll be back to set this in a minute */
+
+ for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
+ mcHead.numSets = cnt;
+
+ lseek(fd, 0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+ mcHead.firstSet = lseek(fd, 0, L_INCR);
+ lseek(fd, 0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+
+ for (set = cat->first; set; set = set->next) {
+ bzero(&mcSet, sizeof(mcSet));
+
+ mcSet.setId = set->setId;
+ mcSet.invalid = False;
+
+ /* The rest we'll have to come back and change in a moment */
+ pos = lseek(fd, 0, L_INCR);
+ write(fd, &mcSet, sizeof(mcSet));
+
+ /* Now write all the string data */
+ mcSet.data.off = lseek(fd, 0, L_INCR);
+ cnt = 0;
+ for (msg = set->first; msg; msg = msg->next) {
+ msg->offset = lseek(fd, 0, L_INCR) - mcSet.data.off;
+ mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
+ ++cnt;
+ }
+ mcSet.u.firstMsg = lseek(fd, 0, L_INCR);
+ mcSet.numMsgs = cnt;
+
+ /* Now write the message headers */
+ for (msg = set->first; msg; msg = msg->next) {
+ mcMsg.msgId = msg->msgId;
+ mcMsg.msg.off = msg->offset;
+ mcMsg.invalid = False;
+ write(fd, &mcMsg, sizeof(mcMsg));
+ }
+
+ /* Go back and fix things up */
+
+ if (set == cat->last) {
+ mcSet.nextSet = 0;
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ } else {
+ mcSet.nextSet = lseek(fd, 0, L_INCR);
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ lseek(fd, mcSet.nextSet, L_SET);
+ }
+ }
+}
+
+
+void MCAddSet(
+#if PROTO
+ int setId, char *hconst)
+#else
+ setId, hconst)
+int setId;
+char *hconst;
+#endif
+{
+ setT *set;
+
+ if (setId <= 0) {
+ error(NULL, "setId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ if (set->hconst && hconst) free(set->hconst);
+ set->hconst = NULL;
+ break;
+ } else if (set->setId > setId) {
+ setT *newSet;
+
+ newSet = (setT *) malloc(sizeof(setT));
+ if (!newSet) nomem();
+ bzero(newSet, sizeof(setT));
+ newSet->prev = set->prev;
+ newSet->next = set;
+ if (set->prev) set->prev->next = newSet;
+ else cat->first = newSet;
+ set->prev = newSet;
+ set = newSet;
+ break;
+ }
+ }
+ if (!set) {
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(setT));
+
+ if (cat->first) {
+ set->prev = cat->last;
+ set->next = NULL;
+ cat->last->next = set;
+ cat->last = set;
+ } else {
+ set->prev = set->next = NULL;
+ cat->first = cat->last = set;
+ }
+ }
+ set->setId = setId;
+ if (hconst) set->hconst = dupstr(hconst);
+ curSet = set;
+}
+
+void MCAddMsg(
+#if PROTO
+ int msgId, char *str, char *hconst)
+#else
+ msgId, str, hconst)
+int msgId;
+char *str;
+char *hconst;
+#endif
+{
+ msgT *msg;
+
+ if (!curSet) error(NULL, "can't specify a message when no set exists");
+
+ if (msgId <= 0) {
+ error(NULL, "msgId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst && hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ msg->hconst = msg->str = NULL;
+ break;
+ } else if (msg->msgId > msgId) {
+ msgT *newMsg;
+
+ newMsg = (msgT *) malloc(sizeof(msgT));
+ if (!newMsg) nomem();
+ bzero(newMsg, sizeof(msgT));
+ newMsg->prev = msg->prev;
+ newMsg->next = msg;
+ if (msg->prev) msg->prev->next = newMsg;
+ else curSet->first = newMsg;
+ msg->prev = newMsg;
+ msg = newMsg;
+ break;
+ }
+ }
+ if (!msg) {
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(msgT));
+
+ if (curSet->first) {
+ msg->prev = curSet->last;
+ msg->next = NULL;
+ curSet->last->next = msg;
+ curSet->last = msg;
+ } else {
+ msg->prev = msg->next = NULL;
+ curSet->first = curSet->last = msg;
+ }
+ }
+ msg->msgId = msgId;
+ if (hconst) msg->hconst = dupstr(hconst);
+ msg->str = dupstr(str);
+}
+
+void MCDelSet(
+#if PROTO
+ int setId)
+#else
+ setId)
+int setId;
+#endif
+{
+ setT *set;
+ msgT *msg;
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ free(msg);
+ }
+ if (set->hconst) free(set->hconst);
+
+ if (set->prev) set->prev->next = set->next;
+ else cat->first = set->next;
+
+ if (set->next) set->next->prev = set->prev;
+ else cat->last = set->prev;
+
+ free(set);
+ return;
+ } else if (set->setId > setId) break;
+ }
+ warning(NULL, "specified set doesn't exist");
+}
+
+void MCDelMsg(
+#if PROTO
+ int msgId)
+#else
+ msgId)
+int msgId;
+#endif
+{
+ msgT *msg;
+
+ if (!curSet) error(NULL, "you can't delete a message before defining the set");
+
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+
+ if (msg->prev) msg->prev->next = msg->next;
+ else curSet->first = msg->next;
+
+ if (msg->next) msg->next->prev = msg->prev;
+ else curSet->last = msg->prev;
+
+ free(msg);
+ return;
+ } else if (msg->msgId > msgId) break;
+ }
+ warning(NULL, "specified msg doesn't exist");
+}
+
+void MCDumpcat(fp)
+FILE *fp;
+{
+ msgT *msg;
+ setT *set;
+
+ if (!cat) {
+ fprintf(stderr, "No catalog open\n");
+ exit (1);
+ }
+
+ for (set = cat->first; set; set = set->next) {
+ fprintf(fp, "$set %d", set->setId);
+ if (set->hconst)
+ fprintf(fp, " # %s", set->hconst);
+ fprintf(fp, "\n\n");
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst)
+ fprintf(fp, "# %s\n", msg->hconst);
+ fprintf(fp, "%d\t%s\n", msg->msgId, msg->str);
+ }
+ fprintf(fp, "\n");
+ }
+
+}
diff --git a/usr.bin/getopt/Makefile b/usr.bin/getopt/Makefile
new file mode 100644
index 0000000..21dde95
--- /dev/null
+++ b/usr.bin/getopt/Makefile
@@ -0,0 +1,7 @@
+# $Header: /b/source/CVS/src/usr.bin/getopt/Makefile,v 1.1 1993/06/21 12:43:58 brezak Exp $
+#
+
+PROG = getopt
+MAN1 = getopt.1
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/getopt/README b/usr.bin/getopt/README
new file mode 100644
index 0000000..55e6998
--- /dev/null
+++ b/usr.bin/getopt/README
@@ -0,0 +1,57 @@
+/***** unido:mod.std.unix / ut-sally!jsq / 8:54 pm Jul 4, 1985*/
+From: John Quarterman (moderator) <ut-sally!std-unix>
+
+Topic: yet more on getopt (command line arguments)
+
+Two more messages, the first a followup to a previous posting, and
+the second public domain sources and man pages for getopt(3) and getopt(1).
+ -mod
+
+----------------------------------------------------------------------
+
+From: ihnp4!utzoo!henry
+Date: 3 Jul 85 18:34:41 CDT (Wed)
+To: ihnp4!ut-sally!std-unix
+Subject: Re: command line arguments
+
+> > A group of bundled options may end with an option that has an argument.
+>
+> This creates confusion in using C-Kermit when you want to send an image
+> file. For example:
+>
+> send -is filename < --- works fine
+> send -si filename < --- bombs the program
+
+The AT&T syntax standard (which getopt does not completely enforce)
+actually forbids both of these usages. Options with arguments are not
+allowed to be bundled, and they must be separated from their arguments
+by a space.
+
+> I would *much* prefer to bundle the flags, then
+> have those with arguments pick them up in the same order as the flags are
+> listed.
+
+The few existing commands that use such a convention, notably tar(1), are
+(in my experience) the worse for it. It's seriously error-prone. I think
+the AT&T people did the right thing.
+
+------------------------------
+
+Date: Tue, 2 Jul 85 13:07:09 edt
+From: ihnp4!utcs!ian (Ian F. Darwin)
+To: ihnp4!ut-sally!jsq@tzec.UTEXAS.ARPA
+Subject: here is getopt
+
+Here is the source for getopt(3), the function that should be in
+everybody's C program, and getopt(1), a program that uses it to
+make shell programs comprehensible and consistent. There are man
+pages for both. Please send these on to the mod. group. Thanks.
+
+[ I have hacked the following shell script slightly so that
+it doesn't extract directly into system source directories,
+rather into the current directory. It should be assumed that
+this code comes with no warranty from me, Ian Darwin, or anyone
+else as to whether it accurately represents getopt as distributed
+with System V, or any command line standard, or that it works
+at all, or that it will cause no damage when extracted or used. -mod]
+
diff --git a/usr.bin/getopt/getopt.1 b/usr.bin/getopt/getopt.1
new file mode 100644
index 0000000..ebf1c65
--- /dev/null
+++ b/usr.bin/getopt/getopt.1
@@ -0,0 +1,103 @@
+.Dd June 21, 1993
+.Dt GETOPT 1
+.Os
+.Sh NAME
+.Nm getopt
+.Nd parse command options
+.Sh SYNOPSIS
+.Nm set \-\- \`getopt Ar optstring $*\`
+.Sh DESCRIPTION
+.Nm Getopt
+is used to break up options in command lines for easy parsing by
+shell procedures, and to check for legal options.
+.Ar Optstring
+is a string of recognized option letters (see
+.Xr getopt 3
+);
+if a letter is followed by a colon, the option
+is expected to have an argument which may or may not be
+separated from it by white space.
+The special option
+.Ql \-\-
+is used to delimit the end of the options.
+.Nm Getopt
+will place
+.Ql \-\-
+in the arguments at the end of the options,
+or recognize it if used explicitly.
+The shell arguments
+(\fB$1 $2\fR ...) are reset so that each option is
+preceded by a
+.Ql \-
+and in its own shell argument;
+each option argument is also in its own shell argument.
+.Sh EXAMPLE
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Fl a
+and
+.Fl b ,
+and the option
+.Fl o ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+set \-\- \`getopt abo: $*\`
+if test $? != 0
+then
+ echo 'Usage: ...'
+ exit 2
+fi
+for i
+do
+ case "$i"
+ in
+ \-a|\-b)
+ flag=$i; shift;;
+ \-o)
+ oarg=$2; shift; shift;;
+ \-\-)
+ shift; break;;
+ esac
+done
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-aoarg file file
+cmd \-a \-o arg file file
+cmd \-oarg -a file file
+cmd \-a \-oarg \-\- file file
+.Ed
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr getopt 3
+.Sh DIAGNOSTICS
+.Nm Getopt
+prints an error message on the standard error output when it
+encounters an option letter not included in
+.Ar optstring .
+.Sh HISTORY
+Written by Henry Spencer, working from a Bell Labs manual page.
+Behavior believed identical to the Bell version.
+.Sh BUGS
+Whatever
+.Xr getopt 3
+has.
+.Pp
+Arguments containing white space or embedded shell metacharacters
+generally will not survive intact; this looks easy to fix but isn't.
+.Pp
+The error message for an invalid option is identified as coming
+from
+.Nm getopt
+rather than from the shell procedure containing the invocation
+of
+.Nm getopt ;
+this again is hard to fix.
+.Pp
+The precise best way to use the
+.Nm set
+command to set the arguments without disrupting the value(s) of
+shell options varies from one shell version to another.
diff --git a/usr.bin/getopt/getopt.c b/usr.bin/getopt/getopt.c
new file mode 100644
index 0000000..060e2c9
--- /dev/null
+++ b/usr.bin/getopt/getopt.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int c;
+ int status = 0;
+
+ optind = 2; /* Past the program name and the option letters. */
+ while ((c = getopt(argc, argv, argv[1])) != -1)
+ switch (c) {
+ case '?':
+ status = 1; /* getopt routine gave message */
+ break;
+ default:
+ if (optarg != NULL)
+ printf(" -%c %s", c, optarg);
+ else
+ printf(" -%c", c);
+ break;
+ }
+ printf(" --");
+ for (; optind < argc; optind++)
+ printf(" %s", argv[optind]);
+ printf("\n");
+ exit(status);
+}
diff --git a/usr.bin/global/HISTORY b/usr.bin/global/HISTORY
new file mode 100644
index 0000000..de9eb3c
--- /dev/null
+++ b/usr.bin/global/HISTORY
@@ -0,0 +1,161 @@
+GLOBAL history
+--------------
+
+version 1.0 initial version [21-Apr-96]
+
+version 1.1 only bugfix [2-May-96]
+
+ [fixed bug]
+ global - makes corrupted path name by conversion error.
+ - description of exit code in online manual is mistaken.
+ btreeop - cannot treat a long line over BUFSIZ. With the result
+ that gtags fails.
+ extended ctags - when using -r option, considers a reserved word
+ to be a function name. With the result that GRTAGS becomes
+ too large.
+
+version 1.2 mainly unification of files [7-Jun-96]
+
+ [changed]
+ extended ctags
+ - change to use bsearch(3) for searching reserved words.
+ - change to consider '__P' as a reserved word.
+ - unify the original patch (included in version1.0) and
+ the bugfix patch (included in version1.1).
+ extended vi
+ - unify the VI entended patch.
+
+version 1.3 support of GTAGSLIBPATH [28-Jul-96]
+
+ [changed]
+ global - search in not only a source tree but also library paths
+ specified by environment variable GTAGSLIBPATH.
+ extended ctags
+ - change print format a little when -x option
+
+version 1.4 support of yacc source file [26-Oct-96]
+
+ [changed]
+ extended ctags
+ - support of yacc source file.
+ - this version of ctags is NOT COMPATIBLE with original one.
+ * search all part of a yacc file for C functions.
+ (original only 3rd part)
+ * no longer considers a yacc rule to be an object.
+
+version 1.5 hypertext generator [12-Dec-96]
+
+ [fixed bug]
+ gtags - doesn't skip 'y.tab.c'.(we should treat only *.y)
+ extended vi
+ - free stack memory. free(3) in FreeBSD 2.1.5R seems to
+ show a warning message when receive stack address.
+ So it spoils the screen.
+ [added]
+ htags - new command (hypertext generator of C source file)
+ gtags - error check code added.
+
+version 1.6 support of 1.76 nvi and reconstruction for other OS [21-Jan-97]
+
+ [changed]
+ htags - cease using <BLOCKQUOTE> because lynx doesn't understand it.
+ global,htags
+ - replace 'sort -u' with 'sort | uniq' for compatibility reason.
+ [fixed bug]
+ global - makes illegal path name when using GTAGSLIBPATH.
+ gtags - error message mistaken.
+ [added]
+ nvi-1.76.diff
+ - patch for nvi 1.76 to make extended vi.
+ gctags - this is the same with extended ctags in older version.
+ now GLOBAL includes BSD ctags in it. so no longer has
+ patch file (ctags.diff).
+ (I brought original ctags from FreeBSD 2.1.5R)
+ global - -a option added.
+
+version 1.7 make suitable for large project (mainly FreeBSD kernel) [17-Feb-97]
+
+ [changed]
+ htags - htags no longer makes frame.html. Index.html offers frame
+ function too.
+ - works MUCH faster than previous version.
+ [fixed bug]
+ htags - generate path name including '&param'. (It means special
+ charactor in hypertertext.)
+ So, changed internal separator from '&' to '|'.
+ [added]
+ gtags - -s option added. If specified, gtags extract ENTRY() and
+ ALTENTRY() from *.[sS] files.
+ htags - supports one level nested index. It's always valid for file
+ index when directories found, and valid for function index
+ only when -a option specified.
+ - -v and -t option added.
+ systags.sh
+ - script to make all tags (GTAGS,GRTAGS,HTML) for kernel source.
+ (it is only for FreeBSD and Linux)
+
+version 1.8 fix some bugs, add options and make more portable [5-Apr-97]
+
+ [changed]
+ gctags, btreeop, Makefile
+ - modify for generic UNIX (Linux, Solaris)
+ - modify to quiet compiler.
+
+ Many thanks to
+ A.E. Brouwer
+ Oleg Checkulaev
+ Emile Heyns
+
+ gctags - modify to treat '\r' at the end of line.
+ htags - changed internal separator from '|' to ' '.
+ because some OS cannot treat '|' in a path.
+ [fixed bug]
+ htags - regard a part of path in #include as a reserved word.
+ - generate illegal links when same tags exist in a line.
+ - insufficient comment detection.
+ gctags - regard function name as a definition in extern statement.
+ - skip macro(no argment) body when -r specified.
+ gctags, htags
+ - regard 'entry' as a reserved word.
+ [added]
+ global - -c (complete) option added.
+ htags - -d tagdir option added.
+ - -w option added.
+
+version 1.81 make global to understand 'obj' directory and bug fix. [14-Apr-97]
+
+ [fixed bug]
+ extended vi
+ - doesn't hand '\' in a pattern to global.
+ [changed]
+ global
+ - can find tag file in obj directory.
+
+version 1.9 fix some bugs, add options and support of 1.79 nvi [21-Apr-97]
+
+ [fixed bug]
+ htags - doesn't keep the code formatted correctly.
+ So, changed to convert tabs in source files into spaces.
+ (expand(1) needed)
+
+ Thanks to Andy Newman.
+
+ - cannot print error message correctly.
+ [changed]
+ gctags, btreeop
+ - modify for SunOS 4.1.3.
+
+ Thanks to Yoshiharu Ito.
+
+ [added]
+ btreeop - META record and 'format version record' is available.
+ (It will be used in the furture.)
+ - -A and -D option added. (It will be used in the future.)
+ htags - use temporary directory specified by TMPDIR environment
+ variable.
+ - -l option added.
+
+ Thanks to Jeff Trawick. This option is his idea.
+
+ nvi-1.79.diff
+ - patch for nvi 1.79 to make extended vi.
diff --git a/usr.bin/global/MANIFEST b/usr.bin/global/MANIFEST
new file mode 100644
index 0000000..11e3b9e
--- /dev/null
+++ b/usr.bin/global/MANIFEST
@@ -0,0 +1,17 @@
+HISTORY Histroy of GLOBAL.
+INSTALL Installation method
+MANIFEST This file.
+Makefile Makefile for BSD.
+Makefile.inc A part of Makefile for BSD.
+Makefile.generic Makefile for generic UNIX(including BSD).
+README Readme (introduction and usage).
+VERSION Version number.
+btreeop/ Btreeop command directory.
+gctags/ Gctags command directory (extended ctags).
+global/ Global command directory.
+gtags/ Gtags command directory.
+htags/ Htags command directory.
+systags/ Script for kernel.
+nvi-1.34.diff Patch for nvi 1.34.
+nvi-1.76.diff Patch for nvi 1.76.
+nvi-1.79.diff Patch for nvi 1.79.
diff --git a/usr.bin/global/Makefile b/usr.bin/global/Makefile
new file mode 100644
index 0000000..2eb181e
--- /dev/null
+++ b/usr.bin/global/Makefile
@@ -0,0 +1,3 @@
+SUBDIR= gctags global gtags btreeop htags systags
+
+.include <bsd.subdir.mk>
diff --git a/usr.bin/global/Makefile.inc b/usr.bin/global/Makefile.inc
new file mode 100644
index 0000000..c24c4b1
--- /dev/null
+++ b/usr.bin/global/Makefile.inc
@@ -0,0 +1 @@
+BINDIR?= /usr/bin
diff --git a/usr.bin/global/README b/usr.bin/global/README
new file mode 100644
index 0000000..e69fba0
--- /dev/null
+++ b/usr.bin/global/README
@@ -0,0 +1,527 @@
+
+ @@@@@@@-
+ @- @-
+ @- @-
+ @- @- @@@@@- @@@@@@- @@- @-
+ @- F o r a l l h a c h e r s. version 1.9
+ @- @@@@@@-@- @- @- @@@@@- @- @- @-
+ @- @- @- @- @- @- @- @@@@@- @-
+ @- @- @- @- @- @- @-@- @- @-
+ @@@@@@@@- @@@@- @@@@@- @@@@@@-@@@- @@@@- @@@@@@-
+
+ Shigio Yamaguchi 21-Apr-97
+
+ Copyright 1996, 1997 Shigio Yamaguchi All right resereved.
+
+GLOBAL is a browsing system for C and Yacc source code.
+It brings benefits to all hackers. Enjoy!
+
+ Contents
+ --------------------------------
+ 0. Introduction
+
+ 1. Global
+
+ 1.1. Features
+ 1.2. Preparation
+ 1.3. Basic usage
+ 1.4. Applied usage
+
+ 2. Extended vi using global
+
+ 2.1. Features
+ 2.2. Preparation
+ 2.3. Basic usage
+ 2.4. Applied usage
+
+ 3. Hypertext generator
+
+ 3.1. Features
+ 3.2. Preparation
+ 3.3. Usage
+ 3.4. To make hypertext of kernel
+ --------------------------------
+
+0. Introduction
+
+GLOBAL is a browsing system for C and Yacc source files.
+You can locate the specified function in C source files and move there easily.
+It is useful to hack a large project containing many subdirectories,
+many '#ifdef' and many main() functions like MH, X or BSD kernel.
+
+It supports following environments.
+
+ o shell command line(see '1. Global')
+ o vi editor(see '2. Extended vi using global')
+ o web browser(see '3. Hypertext generator')
+
+GLOBAL is consist of global(1), gtags(1), btreeop(1), gctags(1), htags(1)
+and extended vi(1).
+
+ * 'extended' means being entended for GLOBAL.
+
+ * Btreeop and gctags are used internally, so you need not
+ understand about them.
+
+The extended vi is completely upper compatible with original one.
+All the functions for GLOBAL are enabled only in 'gtagsmode'.
+
+------------------------------------------------------------------------------
+
+1. Global
+
+1.1. Features
+
+ o Global can find the locations of a specified function quickly.
+ o Global can locate not only function definitions but also function references.
+ o Global allows duplicate entries.
+ o Global can treat a source tree containing subdirectories and you can
+ get relative path of objects from anywhere within the tree.
+ o Global can understand perl's regular expression.
+ o Global can search in not only a source tree but also library paths.
+ o Global can treat yacc source file.
+
+ I think these features are useful for a large project containing many
+ subdirectories, many '#ifdef' and many main() functions like MH.
+
+1.2. Preparation
+
+ First of all, you must execute gtags(1) at the root of source tree.
+ For example, if you want to browse vi's source code, please do like this.
+
+ % cd /usr/src/usr.bin/vi
+ % gtags
+
+ Gtags traverse subdirectories and makes
+ two database at the root of source tree.
+
+ % ls G*TAGS
+ GRTAGS GTAGS
+
+ GTAGS - database for function definition
+ GRTAGS - database for function reference
+
+ If you cannot find functions that should exist, please try -e option.
+
+ % gtags -e
+
+1.3. Basic usage
+
+ Please think of following source tree.
+
+ ROOT/ <- the root of source tree (GTAGS,GRTAGS)
+ |
+ |- DIR1/
+ | |
+ | |- fileA.c ..... +---------------+
+ | | |main(){ |
+ | | | func1();|
+ | | | func2();|
+ | | |} |
+ | | +---------------+
+ | |
+ | |- fileB.c ..... +---------------+
+ | |func1(){ ... } |
+ | +---------------+
+ |- DIR2/
+ |
+ |- fileC.c ..... +---------------+
+ |#ifdef X |
+ |func2(){ i++; }|
+ |#else |
+ |func2(){ i--; }|
+ |#endif |
+ |func3(){ |
+ | func1();|
+ |} |
+ +---------------+
+
+ You can get the relative path of your object from anywhere within
+ the source tree.
+
+ % cd ROOT
+ % global func1
+ DIR1/fileB.c <- func1() is defined in fileB.c
+ % cd DIR1
+ % global func1
+ fileB.c <- relative path from DIR1
+ % cd ../DIR2
+ % global func1
+ ../DIR1/fileB.c <- relative path from DIR2
+
+ -r option locates function references.
+
+ % global -r func2
+ ../DIR1/fileA.c <- func2() is referred from fileA.c
+
+ You can use perl's regular expression.
+
+ % cd ROOT
+ % global 'func[1-3]'
+ DIR1/fileB.c <- func1, func2 and func3 are matched
+ DIR2/fileC.c
+
+ -x option shows the detail. It's similar to ctags's -x option.
+
+ % global func2
+ DIR2/fileC.c
+ % global -x func2
+ func2 2 DIR2/fileC.c func2(){ i++; }
+ func2 4 DIR2/fileC.c func2(){ i--; }
+
+ -a option produces the absolute path name.
+
+ % global -a func1
+ /home/user/ROOT/DIR1/fileB.c
+
+ You can edit files including specified function directly like this.
+
+ % vi `global func1` <- edit fileB.c
+
+
+1.4. Applied usage
+
+ You can make multiple tag files.
+ For example, you can execute gtags at ROOT/, version1.0/ and version2.0/.
+
+ ROOT/ <- the root of source tree (GTAGS,GRTAGS)
+ |
+ |- version1.0/ <- the root of version1.0 (GTAGS,GRTAGS)
+ | |
+ | |- file.c ..... +---------------+
+ | |func1(){ i++; }|
+ | +---------------+
+ |
+ |- version2.0/ <- the root of version2.0 (GTAGS,GRTAGS)
+ |
+ |- file.c ..... +---------------+
+ |func1(){ i--; }|
+ +---------------+
+
+ When you are walking in version1.0 directory, global locates functions
+ only in version1.0.
+
+ % cd ROOT/version1.0
+ % global -x func1
+ func1 1 file.c func1(){ i++; }
+
+ When you are walking in version2.0, global locates functions only in
+ version2.0.
+
+ % cd ROOT/version2.0
+ % global -x func1
+ func1 1 file.c func1(){ i--; }
+
+ If you are at ROOT/ or you set GTAGSROOT environment variable to ROOT,
+ global locates functions in both version1.0 and version2.0 directories.
+
+ % cd ROOT
+ % global -x func1
+ func1 1 version1.0/file.c func1(){ i++; }
+ func1 1 version2.0/file.c func1(){ i--; }
+
+ =-=-=-=
+
+ There is another usage of GTAGSROOT.
+ If your source files are on a read only device like CDROM, you cannot
+ make database on the root of source tree.
+ In such case, please do the following.
+
+ % mkdir /var/dbpath
+ % cd /cdrom/src <- the root of source tree
+ % gtags /var/dbpath <- make tag file in /var/dbpath
+ % setenv GTAGSROOT `pwd`
+ % setenv GTAGSDBPATH /var/dbpath
+ % global func
+
+ =-=-=-=
+
+ If you want to treat the references to a function that is not defined
+ in the source tree like a library function or system call, you can specify
+ library directories with the GTAGSLIBPATH environment variable.
+ You should execute gtags at each directory of the path.
+ If GTAGS is not found in a directory, global ignores it.
+
+ % pwd
+ /develop/src/mh <- this is the source tree
+ % gtags
+ % ls G*TAGS
+ GRTAGS GTAGS
+ % global mhl
+ uip/mhlsbr.c <- mhl() is found
+ % global strlen <- strlen() is not found
+ % (cd /usr/src/lib; gtags) <- library source
+ % (cd /usr/src/sys; gtags) <- kernel source
+ % setenv GTAGSLIBPATH /usr/src/lib:/usr/src/sys
+ % global strlen
+ ../../../usr/src/lib/libc/string/strlen.c <- strlen() is found in library
+ % global access
+ ../../../usr/src/sys/kern/vfs_syscalls.c <- access() is found in kernel
+
+ Of course, user program doesn't call kernel function directly, but
+ at least it is useful.
+
+ =-=-=-=
+
+ If you forget function name, you can use -c (complete) option.
+
+ % global -c kmem <- maybe k..k.. kmem..
+ kmem_alloc
+ kmem_alloc_pageable
+ kmem_alloc_wait
+ kmem_free
+ kmem_free_wakeup
+ kmem_init
+ kmem_malloc
+ kmem_suballoc <- This is what I need!
+ % global kmem_suballoc
+ ../vm/vm_kern.c
+
+ You can use -c option with tcsh's complete command.
+
+ % set funcs=(`global -c`)
+ % complete global 'n/*/$funcs/'
+ % global kmem_<TAB>
+ kmem_alloc kmem_alloc_wait kmem_free_wakeup kmem_malloc
+ kmem_alloc_pageable kmem_free kmem_init kmem_suballoc
+ % global kmem_s<TAB>
+ % global kmem_suballoc
+ ../vm/vm_kern.c
+
+ * <TAB> means tab key or Ctrl-I.
+
+ =-=-=-=
+
+ If you want to browse many files in order, do the followings.
+
+ % global -xr fork | awk '{printf "view +%s %s\n",$2,$3}' | tee /tmp/list
+ view +650 ../dev/aic7xxx/aic7xxx_asm.c
+ view +250 ibcs2/ibcs2_misc.c
+ view +401 linux/linux_misc.c
+ view +310 ../kern/init_main.c
+ view +318 ../kern/init_main.c
+ view +336 ../kern/init_main.c
+ view +351 ../kern/init_main.c
+ % sh !$ <- from now on, go to next tag with 'ZZ'.
+
+2. Extended vi using global
+
+2.1. Features
+
+ o Tag function of extended vi can locate not only function definitions
+ but also function references.
+ o Extended vi allows duplicate tag entries.
+ o Extended vi can understand perl's regular expression as a tag name
+ for search.
+ o Extended vi is completely upper compatible with original one.
+ Above functions are available only in 'gtags mode'.
+
+2.2. Preparation
+
+ First do the preparation of global. (Please see "1.2. Preparation").
+
+ Second, to use global from vi, you need to get into 'gtagsmode'.
+ There are some ways to do it.
+
+ (a) Start vi with -G option
+
+ % vi -G file.c
+
+ (b) Start vi and execute "set gtagsmode"
+
+ % vi file.c
+ ~
+ ~
+ ~
+ :set gtagsmode
+
+ (c) Previously write the set command to .exrc or .nexrc file and start vi
+
+ $HOME/.exrc
+ +----------------------------
+ |set gtagsmode
+
+ You must start vi under the source tree described in "1.2. Preparation".
+
+2.3. Basic usage
+
+ o To go to func1, you can say
+
+ :tag func1
+
+ It seemes same with original vi, but extended vi use GTAGS
+ instead of tags.
+
+ o To go to referenced point of func1, add prefix 'r'
+
+ :rtag func1
+
+ Extended vi use GRTAGS.
+
+ o If a number of functions located, the action of extended vi differs
+ up to your nvi's version.
+
+ [Extended vi based 1.34 nvi]
+
+ Vi goes into 'GTAGS SELECT MODE' like this.
+
+ +-------------------------------------------------------------
+ |main 347 i386/isa/ultra14f.c main()
+ |main 128 kern/init_main.c main(framep)
+ |main 104 netiso/clnp_debug.c main()
+ |main 164 netiso/xebec/main.c main(argc, argv)
+ |~
+ |~
+ |~
+ |~
+ |~
+ |[GTAGS SELECT MODE] 4 lines
+ +-------------------------------------------------------------
+
+ You can select a tag line by any vi command and press [RETURN],
+ and you can go to the tag's point. In ex mode, type "select"
+ instead of [RETURN]. When you want to go to next or previous tag,
+ you can return to 'GTAGS SELECT MODE' with <control-T> and reselect.
+
+ Suggested .nexrc:
+ set gtagsmode
+ set leftright
+
+ [Extended vi based 1.79 nvi]
+
+ Vi goes to the first tag.
+ Then you can go to next tag by ':tagnext' or back by ':tagprev'.
+
+ Suggested .nexrc:
+ set gtagsmode
+ map ^N :tagnext^M
+ map ^P :tagprev^M
+
+ == WHY TWO STYLE EXIST ? ==
+ 1.34 nvi cannot treat duplicate tag entries, so I made 'GTAGS SELECT MODE'
+ in it. But 1.79 nvi (1.61 and later) can treat them, so I adapted GLOBAL
+ tags to nvi's tag structure.
+
+ o <control-]> command is available.
+
+ In gtagsmode, if you are on the first column of line, it is identical to
+ ":rtag <current token>[RETURN]", otherwise ":tag <current token>[RETURN]".
+
+ o Other tag commands are available too.
+
+ <control-T>
+ ":tagpop"
+ ":tagtop"
+ ":display tags"
+
+ Please read online manual.
+
+2.4. Applied usage
+
+ o In large project which include many main() function like MH,
+ you can start vi like this.
+
+ % vi -G -t main
+
+ You can browse all commands sequentially.
+
+ o When you want to check functions the name of which start with
+ "set" or "get",
+
+ % vi -G -t '^[sg]et'
+
+ Of cause, following command is available too.
+
+ :tag ^[sg]et
+
+ o If your source files are on a read only device like CDROM, please do
+ the followings.
+
+ % mkdir /var/dbpath <- directory for tag file
+ % cd /cdrom/src <- the root of source tree
+ % gtags /var/dbpath <- make tag files in /var/dbpath
+ % setenv GTAGSROOT `pwd`
+ % setenv GTAGSDBPATH /var/dbpath
+ % vi -G -t main
+
+ o If you want to treat the references to the function that is not defined
+ in the source tree like library functions or system calls,
+ do the followings.
+
+ % cd /usr/src/lib
+ % gtags <- probably as a root
+ % cd /usr/src/sys
+ % gtags
+ % setenv GTAGSLIBPATH /usr/src/lib:/usr/src/sys
+
+ If you examine vi's source,
+
+ % cd /usr/src/usr.bin/vi
+ % gtags
+ % vi -G -t main
+
+ You can start from vi and trip the whole unix world as if using
+ hypertext.
+
+
+3. Hypertext generator
+
+3.1. Features
+
+ o Htags makes hypertext from C source files.
+ o Once the hypertext generated, you need nothing other than WWW browser.
+ o You can use all of your browser's functions, for example, search,
+ history, bookmark, save, frame, windows and so on.
+
+3.2. Preparation
+
+ At first, you must prepare much disk space. Hypertext needs so much
+ disk space. For example, the source code of FreeBSD kernel needs the
+ following disk space.
+
+ source code(/usr/src/sys) 14MB
+ tag database(GTAGS,GRTAGS) 9MB(!)
+ hypertext(HTML/*) 45MB(!!!)
+
+ Please do the followings.
+
+ (at your source directory)
+ % gtags <- make tag database
+ % htags <- make hypertext
+
+ Then you will find 'HTML' directory in the current directory.
+
+3.3. Usage
+
+ Please start a web browser like this.
+
+ % lynx HTML/index.html
+
+ You can use any browsers, for example, Lynx, Chimera, Mosaic,
+ Netscape Navigator, Internet Explorer and so on.
+ (But IE3.0 doesn't work well about index.)
+
+ You will understand the usage for the looking.
+ You can move HTML directory to anywhere. It is independent of
+ the source code.
+
+3.4. To make hypertext of kernel
+
+ If you would like to make hypertext of FreeBSD or Linux kernel source,
+ it is convenient to use systags script in this package.
+
+ % cd /usr/src/sys
+ % systags
+ then
+
+ % netscape HTML/index.html
+
+ You can use one level nested index and browse assembler source file too.
+
+Thank you for your reading of my poor english.
+And of course, I'm grateful to Keith Bostic for his excellent nvi(1) and db(3).
+----------------------------------------------------------------------------
+E-Mail: <shigio@wafu.netgate.net>
+WWW: <http://wafu.netgate.net/tama/unix/indexe.html>
+ (You can find the latest version here.)
+----------------------------------------------------------------------------
diff --git a/usr.bin/global/VERSION b/usr.bin/global/VERSION
new file mode 100644
index 0000000..2e0e38c
--- /dev/null
+++ b/usr.bin/global/VERSION
@@ -0,0 +1 @@
+1.9
diff --git a/usr.bin/global/btreeop/Makefile b/usr.bin/global/btreeop/Makefile
new file mode 100644
index 0000000..c9e0409
--- /dev/null
+++ b/usr.bin/global/btreeop/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 1.0 (Berkeley) 4/21/96
+
+PROG= btreeop
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/btreeop/btreeop.1 b/usr.bin/global/btreeop/btreeop.1
new file mode 100644
index 0000000..08bbf51
--- /dev/null
+++ b/usr.bin/global/btreeop/btreeop.1
@@ -0,0 +1,168 @@
+.\"
+.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Shigio Yamaguchi.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 21, 1997
+.Dt BTREEOP 1
+.Os BSD 4
+.Sh NAME
+.Nm btreeop
+.Nd btree database maintenance tool
+.Sh SYNOPSIS
+.Nm btreeop
+.Op Fl A
+.Op Fl C
+.Op Fl D Ar key
+.Op Fl K Ar key
+.Op Fl b
+.Op Fl c Ar cashesize
+.Op Fl l
+.Op Fl p Ar psize
+.Op Ar dbname
+.Sh DESCRIPTION
+.Nm Btreeop
+execute simple operations for
+.Xr btree 3
+database.
+.Nm Btreeop
+can create database, write record, read record (sequential or index) and
+delete record from it.
+Duplicate entries are allowed.
+.Sh OPTIONS
+A capital letter means a command. If no command specified
+then it assume sequential read operation.
+.Bl -tag -width Ds
+.It Fl A
+append records. If database doesn't exist, btreeop creates it.
+.It Fl C
+create database and write records to it.
+.It Fl D Ar key
+delete records by the key.
+.It Fl K Ar key
+search records by the key.
+.It Fl b
+assume BIG_ENDIAN byte order. default is LITTLE_ENDIAN.
+.It Fl c Ar cashesize
+specify cashesize. It's identical to
+.Nm info.cachesize
+of BTREEINFO. (see btree(3))
+.It Fl l
+assume LITTLE_ENDIAN byte order. (the default)
+.It Fl p Ar psize
+specify page size. It's identical to
+.Nm info.psize
+of BTREEINFO. (see btree(3))
+.It Ar dbname
+database name. default is 'btree'.
+.Sh DATA FORMAT
+To creat (or append) database,
+.Nm btreeop
+read data from stdin.
+The format of the data is the following.
+
+ Key Data\\n
+ Key Data\\n
+ .
+ .
+ .
+
+.El
+
+.Bl -enum -offset indent
+.It
+Key and Data are separated by blank('\\t' or ' ').
+.It
+Key cannot include blank.
+.It
+Data can include blank.
+.It
+Null Data not allowed.
+.It
+Additionally, META record is available. META record has a key that start with
+a blank. You can read this record only by indexed search (with -K option).
+Usage is unlimited by Btreeop.
+.El
+.Sh EXAMPLES
+Create database.
+
+ % btreeop -C
+ key1 data1
+ key2 data2
+ key3 data3
+ ^D
+ %
+
+Append records.
+
+ % btreeop -A
+ __.VERSION 2
+ key2 data2-2
+ ^D
+ %
+
+Sequential read.
+
+ % btreeop
+ key2 data2
+ key3 data3
+ key2 data2-2
+ key1 data1
+ %
+
+Indexed read.
+
+ % btreeop -K key2
+ key2 data2-2
+ key2 data2
+ % btreeop -K ' __.VERSION'
+ __.VERSION 2
+ %
+
+Delete record.
+
+ % btreeop -D ' __.VERSION'
+ % btreeop -K ' __.VERSION'
+ %
+
+.Sh FILES
+.Bl -tag -width tags -compact
+.It Pa btree
+default database name.
+.El
+.Sh DIAGNOSTICS
+.Nm Btreeop
+exits with a value of 1 if an error occurred, 0 otherwise.
+.Sh SEE ALSO
+.Xr btree 3
+.Sh AUTHOR
+Shigio Yamaguchi (shigio@wafu.netgate.net)
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.2.
diff --git a/usr.bin/global/btreeop/btreeop.c b/usr.bin/global/btreeop/btreeop.c
new file mode 100644
index 0000000..a202578
--- /dev/null
+++ b/usr.bin/global/btreeop/btreeop.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Shigio Yamaguchi.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * btreeop.c 21-Apr-97
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <db.h>
+#include <fcntl.h>
+
+char *dbdefault = "btree"; /* default database name */
+char *progname = "btreeop"; /* command name */
+char *dbname;
+char buf[BUFSIZ+1];
+
+#ifndef __P
+#if defined(__STDC__)
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+void die __P((char *));
+void usage __P((void));
+void entab __P((char *));
+void main __P((int, char **));
+int dbwrite __P((DB *));
+int dbkey __P((DB *, char *));
+int dbscan __P((DB *));
+int dbdel __P((DB *, char *));
+DB *db;
+char *key;
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+void
+die(s)
+char *s;
+{
+ fprintf(stderr, "%s: %s\n", progname, s);
+ exit(1);
+}
+
+void
+usage() {
+ fprintf(stderr,
+ "usage: %s [-A][-C][-D key][-K key][-b][-c cachesize][-l][-p psize][dbname]\n",
+ progname);
+ exit(1);
+}
+
+#define TABPOS(i) ((i)%8 == 0)
+/*
+ * entab: convert spaces into tabs
+ *
+ * io) buf string buffer
+ */
+void
+entab(buf)
+char *buf;
+{
+ int blanks = 0;
+ int pos, src, dst;
+ char c;
+
+ pos = src = dst = 0;
+ while ((c = buf[src++]) != 0) {
+ if (c == ' ') {
+ if (!TABPOS(++pos)) {
+ blanks++; /* count blanks */
+ continue;
+ }
+ buf[dst++] = '\t';
+ } else if (c == '\t') {
+ while (!TABPOS(++pos))
+ ;
+ buf[dst++] = '\t';
+ } else {
+ ++pos;
+ while (blanks--)
+ buf[dst++] = ' ';
+ buf[dst++] = c;
+ }
+ blanks = 0;
+ }
+ buf[dst] = 0;
+}
+
+#include <errno.h>
+void
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char command = 'R';
+ char *key = NULL;
+ DB *db;
+ BTREEINFO info;
+ int c;
+ int flags;
+ extern char *optarg;
+ extern int optind;
+
+ info.flags = R_DUP; /* allow duplicate entries */
+ info.cachesize = 500000;
+ info.maxkeypage = 0;
+ info.minkeypage = 0;
+ info.psize = 0;
+ info.compare = NULL;
+ info.prefix = NULL;
+ info.lorder = LITTLE_ENDIAN;
+
+ while ((c = getopt(argc, argv, "ACD:K:bc:lp:")) != EOF) {
+ switch (c) {
+ case 'K':
+ case 'D':
+ key = optarg;
+ case 'A':
+ case 'C':
+ if (command != 'R')
+ usage();
+ command = c;
+ break;
+ case 'b':
+ info.lorder = BIG_ENDIAN;
+ break;
+ case 'c':
+ info.cachesize = atoi(optarg);
+ break;
+ case 'l':
+ info.lorder = LITTLE_ENDIAN;
+ break;
+ case 'p':
+ info.psize = atoi(optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ dbname = (optind < argc) ? argv[optind] : dbdefault;
+ switch (command) {
+ case 'A':
+ case 'D':
+ flags = O_RDWR|O_CREAT;
+ break;
+ case 'C':
+ flags = O_RDWR|O_CREAT|O_TRUNC;
+ break;
+ case 'K':
+ case 'R':
+ flags = O_RDONLY;
+ break;
+ }
+ db = dbopen(dbname, flags, 0644, DB_BTREE, &info);
+ if (db == NULL) {
+ die("dbopen failed.");
+ }
+ switch (command) {
+ case 'A': /* Append records */
+ case 'C': /* Create database */
+ dbwrite(db);
+ break;
+ case 'D': /* Delete records */
+ dbdel(db, key);
+ break;
+ case 'K': /* Keyed (indexed) read */
+ dbkey(db, key);
+ break;
+ case 'R': /* sequencial Read */
+ dbscan(db);
+ break;
+ }
+ if (db->close(db)) {
+ die("db->close failed.");
+ }
+ exit(0);
+}
+/*
+ * dbwrite: write to database
+ *
+ * i) db
+ * r) 0: normal
+ */
+int
+dbwrite(db)
+DB *db;
+{
+ DBT key, dat;
+ int status;
+#define IDENTLEN 80
+ char keybuf[IDENTLEN+1];
+ char *c;
+
+ /*
+ * Input file format:
+ * +------------------
+ * |Key Data\n
+ * |Key Data\n
+ * .
+ * .
+ * - Key and Data are separated by blank('\t' or ' ').
+ * - Key cannot include blank.
+ * - Data can include blank.
+ * - Null Data not allowed.
+ *
+ * META record:
+ * You can write meta record by making key start with a ' '.
+ * You can read this record only by indexed read ('-K' option).
+ * +------------------
+ * | __.VERSION 2
+ */
+ while (fgets(buf, BUFSIZ, stdin)) {
+ if (buf[strlen(buf)-1] == '\n') /* chop(buf) */
+ buf[strlen(buf)-1] = 0;
+ else
+ while (fgetc(stdin) != '\n')
+ ;
+ c = buf;
+ if (*c == ' ') { /* META record */
+ if (*++c == ' ')
+ die("illegal format.");
+ }
+ for (; *c && !isspace(*c); c++) /* skip key part */
+ ;
+ if (*c == 0)
+ die("data part not found.");
+ if (c - buf > IDENTLEN)
+ die("key too long.");
+ strncpy(keybuf, buf, c - buf); /* make key string */
+ keybuf[c - buf] = 0;
+ for (; *c && isspace(*c); c++) /* skip blanks */
+ ;
+ if (*c == 0)
+ die("data part is null.");
+ entab(buf);
+ key.data = keybuf;
+ key.size = strlen(keybuf)+1;
+ dat.data = buf;
+ dat.size = strlen(buf)+1;
+
+ status = (db->put)(db, &key, &dat, 0);
+ switch (status) {
+ case RET_SUCCESS:
+ break;
+ case RET_ERROR:
+ case RET_SPECIAL:
+ die("db->put: failed.");
+ }
+ }
+ return(0);
+}
+
+/*
+ * dbkey: Keyed search
+ *
+ * i) db
+ * i) skey
+ * r) 0: normal
+ * 1: not found
+ */
+int
+dbkey(db, skey)
+DB *db;
+char *skey;
+{
+ DBT dat, key;
+ int status;
+
+ key.data = skey;
+ key.size = strlen(skey)+1;
+
+ for (status = (*db->seq)(db, &key, &dat, R_CURSOR);
+ status == RET_SUCCESS && !strcmp(key.data, skey);
+ status = (*db->seq)(db, &key, &dat, R_NEXT)) {
+ (void)fprintf(stdout, "%s\n", (char *)dat.data);
+ }
+ if (status == RET_ERROR)
+ die("db->seq failed.");
+ return (0);
+}
+
+/*
+ * dbscan: Scan all records
+ *
+ * i) db
+ * r) 0: normal
+ * 1: not found
+ */
+int
+dbscan(db)
+DB *db;
+{
+ DBT dat, key;
+ int status;
+
+ for (status = (*db->seq)(db, &key, &dat, R_FIRST);
+ status == RET_SUCCESS;
+ status = (*db->seq)(db, &key, &dat, R_NEXT)) {
+ /* skip META record */
+ if (*(char *)key.data == ' ')
+ continue;
+ (void)fprintf(stdout, "%s\n", (char *)dat.data);
+ }
+ if (status == RET_ERROR)
+ die("db->seq failed.");
+ return (0);
+}
+
+/*
+ * dbdel: Delete records
+ *
+ * i) db
+ * i) key key
+ * r) 0: normal
+ * 1: not found
+ */
+int
+dbdel(db, skey)
+DB *db;
+char *skey;
+{
+ DBT key;
+ int status;
+
+ key.data = skey;
+ key.size = strlen(skey)+1;
+
+ status = (*db->del)(db, &key, 0);
+ if (status == RET_ERROR)
+ die("db->del failed.");
+ return (0);
+}
diff --git a/usr.bin/global/gctags/C.c b/usr.bin/global/gctags/C.c
new file mode 100644
index 0000000..87652b5
--- /dev/null
+++ b/usr.bin/global/gctags/C.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ctags.h"
+
+static int func_entry __P((void));
+static void hash_entry __P((void));
+static void skip_string __P((int));
+static int str_entry __P((int));
+#ifdef GTAGS
+static int cmp __P((const void *, const void *));
+static int isstatement __P((char *));
+static void define_line __P((void));
+#endif
+
+#ifdef YACC
+extern int yaccfile; /* true when *.y file */
+#endif
+/*
+ * c_entries --
+ * read .c and .h files and call appropriate routines
+ */
+void
+c_entries()
+{
+ int c; /* current character */
+ int level; /* brace level */
+ int token; /* if reading a token */
+ int t_def; /* if reading a typedef */
+ int t_level; /* typedef's brace level */
+ char *sp; /* buffer pointer */
+ char tok[MAXTOKEN]; /* token buffer */
+#ifdef YACC
+ /*
+ * yacc file format is like the following.
+ *
+ * declarations
+ * %%
+ * rules
+ * %%
+ * programs
+ *
+ */
+#define DECLARATIONS 0
+#define RULES 1
+#define PROGRAMS 2
+ int yaccstatus = (yaccfile) ? DECLARATIONS : PROGRAMS;
+ int inyacc = (yaccfile) ? YES : NO; /* NO while C source */
+#endif
+
+ lineftell = ftell(inf);
+ sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
+ while (GETC(!=, EOF)) {
+ switch (c) {
+ /*
+ * Here's where it DOESN'T handle: {
+ * foo(a)
+ * {
+ * #ifdef notdef
+ * }
+ * #endif
+ * if (a)
+ * puts("hello, world");
+ * }
+ */
+ case '{':
+#ifdef YACC
+ if (yaccstatus == RULES && level == 0)
+ inyacc = NO;
+#endif
+ ++level;
+ goto endtok;
+ case '}':
+ /*
+ * if level goes below zero, try and fix
+ * it, even though we've already messed up
+ */
+ if (--level < 0)
+ level = 0;
+#ifdef GTAGS
+ /*
+ * -e flag force a function to end when a '}' appear
+ * at column 0. If -e flag not specified, all functions
+ * after funcA() would be lost.
+ *
+ * funcA() {
+ * #ifdef A
+ * if (a) {
+ * ...
+ * #else
+ * if (nota) {
+ * ...
+ * #endif
+ * }
+ * }
+ */
+ if (eflag && ftell(inf) == lineftell+1) {
+ level = 0;
+ }
+#endif
+#if YACC
+ if (yaccstatus == RULES && level == 0)
+ inyacc = YES;
+#endif
+ goto endtok;
+
+ case '\n':
+ SETLINE;
+ /*
+ * the above 3 cases are similar in that they
+ * are special characters that also end tokens.
+ */
+ endtok: if (sp > tok) {
+ *sp = EOS;
+ token = YES;
+ sp = tok;
+ }
+ else
+ token = NO;
+ continue;
+
+ /*
+ * We ignore quoted strings and character constants
+ * completely.
+ */
+ case '"':
+ case '\'':
+ (void)skip_string(c);
+ break;
+
+ /*
+ * comments can be fun; note the state is unchanged after
+ * return, in case we found:
+ * "foo() XX comment XX { int bar; }"
+ */
+ case '/':
+ if (GETC(==, '*')) {
+ skip_comment();
+ continue;
+ }
+ (void)ungetc(c, inf);
+ c = '/';
+ goto storec;
+
+ /* hash marks flag #define's. */
+ case '#':
+ if (sp == tok) {
+ hash_entry();
+ break;
+ }
+ goto storec;
+
+ /*
+ * if we have a current token, parenthesis on
+ * level zero indicates a function.
+#ifdef GTAGS
+ * in the case of rflag == 1, if we have a current token,
+ * parenthesis on level > zero indicates a function reference.
+#endif
+#ifdef YACC
+ * inyacc == NO while C source.
+#endif
+ */
+ case '(':
+#ifdef YACC
+ if (inyacc == NO)
+#endif
+#ifdef GTAGS
+ if (!rflag && !level && token)
+#else
+ if (!level && token)
+#endif
+ {
+ int curline;
+
+ if (sp != tok)
+ *sp = EOS;
+ /*
+ * grab the line immediately, we may
+ * already be wrong, for example,
+ * foo\n
+ * (arg1,
+ */
+ getline();
+ curline = lineno;
+#ifdef GTAGS
+ /* to make sure. */
+ if (!isstatement(tok))
+#endif
+ if (func_entry()) {
+ ++level;
+ pfnote(tok, curline);
+ }
+ break;
+ }
+#ifdef GTAGS
+ else if (rflag && level && token) {
+ if (sp != tok)
+ *sp = EOS;
+ getline();
+ if (!isstatement(tok) && isdefined(tok))
+ pfnote(tok, lineno);
+ break;
+ }
+#endif
+ goto storec;
+
+ /*
+ * semi-colons indicate the end of a typedef; if we find a
+ * typedef we search for the next semi-colon of the same
+ * level as the typedef. Ignoring "structs", they are
+ * tricky, since you can find:
+ *
+ * "typedef long time_t;"
+ * "typedef unsigned int u_int;"
+ * "typedef unsigned int u_int [10];"
+ *
+ * If looking at a typedef, we save a copy of the last token
+ * found. Then, when we find the ';' we take the current
+ * token if it starts with a valid token name, else we take
+ * the one we saved. There's probably some reasonable
+ * alternative to this...
+ */
+ case ';':
+ if (t_def && level == t_level) {
+ t_def = NO;
+ getline();
+ if (sp != tok)
+ *sp = EOS;
+ pfnote(tok, lineno);
+ break;
+ }
+ goto storec;
+
+#if YACC
+ case '%':
+ if (yaccstatus == DECLARATIONS || yaccstatus == RULES) {
+ if (GETC(==, '%')) {
+ level = 0;
+ if (yaccstatus == DECLARATIONS) {
+ if (!rflag) {
+ getline();
+ pfnote("yyparse", lineno);
+ }
+ yaccstatus = RULES;
+ } else if (yaccstatus == RULES) {
+ yaccstatus = PROGRAMS;
+ }
+ inyacc = (yaccstatus == PROGRAMS) ? NO : YES;
+ } else if (c == '{') {
+ level = 0;
+ inyacc = NO;
+ } else if (c == '}') {
+ level = 0;
+ inyacc = YES;
+ } else {
+ (void)ungetc(c, inf);
+ }
+ break;
+ }
+ /* else fall throuth */
+#endif
+ /*
+ * store characters until one that can't be part of a token
+ * comes along; check the current token against certain
+ * reserved words.
+ */
+ default:
+#ifdef BUGFIX
+ /*
+ * to treat following function.
+ * func (arg) {
+ * ....
+ * }
+ */
+ if (c == ' ' || c == '\t') {
+ int save = c;
+ while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
+ ;
+ if (c == EOF)
+ return;
+ (void)ungetc(c, inf);
+ c = save;
+ }
+#endif
+ storec: if (!intoken(c)) {
+ if (sp == tok)
+ break;
+ *sp = EOS;
+#ifdef GTAGS
+ if (!memcmp(tok, "extern",7)) {
+ while (GETC(!=, EOF) && c != ';') {
+ if (c == '\n')
+ SETLINE;
+ }
+ if (c == EOF)
+ return;
+ break;
+ }
+#endif
+ if (tflag) {
+ /* no typedefs inside typedefs */
+ if (!t_def &&
+ !memcmp(tok, "typedef",8)) {
+ t_def = YES;
+ t_level = level;
+ break;
+ }
+ /* catch "typedef struct" */
+ if ((!t_def || t_level < level)
+ && (!memcmp(tok, "struct", 7)
+ || !memcmp(tok, "union", 6)
+ || !memcmp(tok, "enum", 5))) {
+ /*
+ * get line immediately;
+ * may change before '{'
+ */
+ getline();
+ if (str_entry(c))
+ ++level;
+ break;
+ /* } */
+ }
+ }
+ sp = tok;
+ }
+ else if (sp != tok || begtoken(c)) {
+ *sp++ = c;
+ token = YES;
+ }
+ continue;
+ /* end of default */
+ } /* end of switch */
+ /*
+ * 'break' statement in switch block come here.
+ */
+ sp = tok;
+ token = NO;
+ } /* end of while */
+}
+
+/*
+ * func_entry --
+ * handle a function reference
+ */
+static int
+func_entry()
+{
+ int c; /* current character */
+ int level = 0; /* for matching '()' */
+
+ /*
+ * Find the end of the assumed function declaration.
+ * Note that ANSI C functions can have type definitions so keep
+ * track of the parentheses nesting level.
+ */
+ while (GETC(!=, EOF)) {
+ switch (c) {
+ case '\'':
+ case '"':
+ /* skip strings and character constants */
+ skip_string(c);
+ break;
+ case '/':
+ /* skip comments */
+ if (GETC(==, '*'))
+ skip_comment();
+ break;
+ case '(':
+ level++;
+ break;
+ case ')':
+ if (level == 0)
+ goto fnd;
+ level--;
+ break;
+ case '\n':
+ SETLINE;
+ }
+ }
+ return (NO);
+fnd:
+ /*
+ * we assume that the character after a function's right paren
+ * is a token character if it's a function and a non-token
+ * character if it's a declaration. Comments don't count...
+ */
+ for (;;) {
+ while (GETC(!=, EOF) && iswhite(c))
+ if (c == '\n')
+ SETLINE;
+ if (intoken(c) || c == '{')
+ break;
+ if (c == '/' && GETC(==, '*'))
+ skip_comment();
+ else { /* don't ever "read" '/' */
+ (void)ungetc(c, inf);
+ return (NO);
+ }
+ }
+ if (c != '{')
+ (void)skip_key('{');
+ return (YES);
+}
+
+/*
+ * hash_entry --
+ * handle a line starting with a '#'
+ */
+static void
+hash_entry()
+{
+ int c; /* character read */
+ int curline; /* line started on */
+ char *sp; /* buffer pointer */
+ char tok[MAXTOKEN]; /* storage buffer */
+
+#ifdef BUGFIX
+ /*
+ * to treat following macro.
+ * # macro(arg) ....
+ */
+ while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
+ ;
+ (void)ungetc(c, inf);
+#endif
+ curline = lineno;
+ for (sp = tok;;) { /* get next token */
+ if (GETC(==, EOF))
+ return;
+ if (iswhite(c))
+ break;
+ *sp++ = c;
+ }
+ *sp = EOS;
+ if (memcmp(tok, "define", 6)) /* only interested in #define's */
+ goto skip;
+ for (;;) { /* this doesn't handle "#define \n" */
+ if (GETC(==, EOF))
+ return;
+ if (!iswhite(c))
+ break;
+ }
+ for (sp = tok;;) { /* get next token */
+ *sp++ = c;
+ if (GETC(==, EOF))
+ return;
+ /*
+ * this is where it DOESN'T handle
+ * "#define \n"
+ */
+ if (!intoken(c))
+ break;
+ }
+ *sp = EOS;
+#ifdef GTAGS
+ if (rflag) {
+ /*
+ * #define XXX\n
+ */
+ if (c == '\n' || (c == '\r' && GETC(==, '\n'))) {
+ SETLINE;
+ return;
+ }
+ /*
+ * v
+ * #define XXX(X) XXXXXX
+ */
+ if (c == '(')
+ (void)skip_key(')');
+ /*
+ * v
+ * #define XXX(X) XXXXXX
+ */
+ while (GETC(!=, EOF)) {
+ if (c != ' ' && c != '\t') {
+ (void)ungetc(c, inf);
+ break;
+ }
+ }
+ /*
+ * v
+ * #define XXX(X) XXXXXX
+ */
+ define_line();
+ return;
+ }
+#endif
+ if (dflag || c == '(') { /* only want macros */
+ getline();
+ pfnote(tok, curline);
+ }
+skip: if (c == '\n') { /* get rid of rest of define */
+ SETLINE
+#ifdef MODIFY
+ if (*(sp - 1) == '\r') {
+ if (*(sp - 2) != '\\')
+ return;
+ } else
+#endif
+ if (*(sp - 1) != '\\')
+ return;
+ }
+ (void)skip_key('\n');
+}
+
+#ifdef GTAGS
+ /* sorted by alphabet */
+static struct words {
+ char *name;
+} words[] = {
+ {"__P"},
+ {"auto"},
+ {"break"},
+ {"case"},
+ {"char"},
+ {"continue"},
+ {"default"},
+ {"do"},
+ {"double"},
+ {"else"},
+ {"extern"},
+ {"float"},
+ {"for"},
+ {"goto"},
+ {"if"},
+ {"int"},
+ {"long"},
+ {"register"},
+ {"return"},
+ {"short"},
+ {"sizeof"},
+ {"static"},
+ {"struct"},
+ {"switch"},
+ {"typedef"},
+ {"union"},
+ {"unsigned"},
+ {"void"},
+ {"while"},
+};
+
+static int
+cmp(s1, s2)
+ const void *s1, *s2;
+{
+ return strcmp(((struct words *)s1)->name, ((struct words *)s2)->name);
+}
+
+static int
+isstatement(token)
+ char *token;
+{
+ struct words tmp;
+
+ tmp.name = token;
+ if (bsearch(&tmp, words, sizeof(words)/sizeof(struct words), sizeof(struct words), cmp))
+ return YES;
+ return NO;
+}
+
+static void
+define_line()
+{
+ int c; /* character read */
+ int level; /* brace level */
+ int token; /* if reading a token */
+ char *sp; /* buffer pointer */
+ char tok[MAXTOKEN]; /* storage buffer */
+
+ sp = tok; token = NO; level = 0;
+ while (GETC(!=, EOF)) {
+ switch (c) {
+ case '{':
+ ++level;
+ goto endtok;
+ case '}':
+ if (--level < 0)
+ level = 0;
+ goto endtok;
+
+ case '\\':
+ if (GETC(==, '\n') || (c == '\r' && GETC(==, '\n'))) {
+ SETLINE;
+ }
+ continue;
+
+ case '\n':
+ SETLINE;
+ return;
+ endtok: if (sp > tok) {
+ *sp = EOS;
+ token = YES;
+ sp = tok;
+ }
+ else
+ token = NO;
+ continue;
+
+ case '"':
+ case '\'':
+ (void)skip_string(c);
+ break;
+
+ case '/':
+ if (GETC(==, '*')) {
+ skip_comment();
+ continue;
+ }
+ (void)ungetc(c, inf);
+ c = '/';
+ goto storec;
+
+ case '(':
+ if (token) {
+ if (sp != tok)
+ *sp = EOS;
+ getline();
+ if (!isstatement(tok) && isdefined(tok))
+ pfnote(tok, lineno);
+ break;
+ }
+ goto storec;
+
+ case ';':
+ goto storec;
+
+ default:
+storec: if (!intoken(c)) {
+ if (sp == tok)
+ break;
+ *sp = EOS;
+ sp = tok;
+ }
+ else if (sp != tok || begtoken(c)) {
+ *sp++ = c;
+ token = YES;
+ }
+ continue;
+ }
+
+ sp = tok;
+ token = NO;
+ }
+}
+#endif
+/*
+ * str_entry --
+ * handle a struct, union or enum entry
+ */
+static int
+str_entry(c)
+ int c; /* current character */
+{
+ int curline; /* line started on */
+ char *sp; /* buffer pointer */
+ char tok[LINE_MAX]; /* storage buffer */
+
+ curline = lineno;
+ while (iswhite(c))
+ if (GETC(==, EOF))
+ return (NO);
+ if (c == '{') /* it was "struct {" */
+ return (YES);
+ for (sp = tok;;) { /* get next token */
+ *sp++ = c;
+ if (GETC(==, EOF))
+ return (NO);
+ if (!intoken(c))
+ break;
+ }
+ switch (c) {
+ case '{': /* it was "struct foo{" */
+ --sp;
+ break;
+ case '\n': /* it was "struct foo\n" */
+ SETLINE;
+ /*FALLTHROUGH*/
+ default: /* probably "struct foo " */
+ while (GETC(!=, EOF))
+ if (!iswhite(c))
+ break;
+ if (c != '{') {
+ (void)ungetc(c, inf);
+ return (NO);
+ }
+ }
+ *sp = EOS;
+ pfnote(tok, curline);
+ return (YES);
+}
+
+/*
+ * skip_comment --
+ * skip over comment
+ */
+void
+skip_comment()
+{
+ int c; /* character read */
+ int star; /* '*' flag */
+
+ for (star = 0; GETC(!=, EOF);)
+ switch(c) {
+ /* comments don't nest, nor can they be escaped. */
+ case '*':
+ star = YES;
+ break;
+ case '/':
+ if (star)
+ return;
+ break;
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ star = NO;
+ break;
+ }
+}
+
+/*
+ * skip_string --
+ * skip to the end of a string or character constant.
+ */
+static void
+skip_string(key)
+ int key;
+{
+ int c,
+ skip;
+
+ for (skip = NO; GETC(!=, EOF); )
+ switch (c) {
+ case '\\': /* a backslash escapes anything */
+ skip = !skip; /* we toggle in case it's "\\" */
+ break;
+#ifdef MODIFY
+ case '\r':
+ break;
+#endif
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ if (c == key && !skip)
+ return;
+ skip = NO;
+ }
+}
+
+/*
+ * skip_key --
+ * skip to next char "key"
+ */
+int
+skip_key(key)
+ int key;
+{
+ int c,
+ skip,
+ retval;
+
+ for (skip = retval = NO; GETC(!=, EOF);)
+ switch(c) {
+ case '\\': /* a backslash escapes anything */
+ skip = !skip; /* we toggle in case it's "\\" */
+ break;
+ case ';': /* special case for yacc; if one */
+ case '|': /* of these chars occurs, we may */
+ retval = YES; /* have moved out of the rule */
+ break; /* not used by C */
+ case '\'':
+ case '"':
+ /* skip strings and character constants */
+ skip_string(c);
+ break;
+ case '/':
+ /* skip comments */
+ if (GETC(==, '*')) {
+ skip_comment();
+ break;
+ }
+ (void)ungetc(c, inf);
+ c = '/';
+ goto norm;
+#ifdef MODIFY
+ case '\r':
+ break;
+#endif
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ norm:
+ if (c == key && !skip)
+ return (retval);
+ skip = NO;
+ }
+ return (retval);
+}
diff --git a/usr.bin/global/gctags/Makefile b/usr.bin/global/gctags/Makefile
new file mode 100644
index 0000000..bc0cbbf
--- /dev/null
+++ b/usr.bin/global/gctags/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= gctags
+CFLAGS+=-I${.CURDIR} -DGTAGS -DBUGFIX -DMODIFY -DYACC
+SRCS= C.c ctags.c fortran.c lisp.c print.c tree.c yacc.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/gctags/ctags.c b/usr.bin/global/gctags/ctags.c
new file mode 100644
index 0000000..f73a6bd
--- /dev/null
+++ b/usr.bin/global/gctags/ctags.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ctags.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "ctags.h"
+
+/*
+ * ctags: create a tags file
+ */
+
+NODE *head; /* head of the sorted binary tree */
+
+ /* boolean "func" (see init()) */
+bool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
+
+FILE *inf; /* ioptr for current input file */
+FILE *outf; /* ioptr for tags file */
+
+long lineftell; /* ftell after getc( inf ) == '\n' */
+
+int lineno; /* line number of current line */
+int dflag; /* -d: non-macro defines */
+#ifdef GTAGS
+int eflag; /* -e: '{' at 0 column force function end */
+#endif
+int tflag; /* -t: create tags for typedefs */
+int vflag; /* -v: vgrind style index output */
+int wflag; /* -w: suppress warnings */
+int xflag; /* -x: cxref style output */
+#ifdef GTAGS
+int Dflag; /* -D: allow duplicate entrys */
+int rflag; /* -r: function reference */
+#endif
+#ifdef YACC
+int yaccfile; /* yacc file */
+#endif
+
+char *curfile; /* current input file name */
+char searchar = '/'; /* use /.../ searches by default */
+char lbuf[LINE_MAX];
+
+void init __P((void));
+void find_entries __P((char *));
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ static char *outfile = "tags"; /* output file */
+ int aflag; /* -a: append to tags */
+ int uflag; /* -u: update tags */
+ int exit_val; /* exit value */
+ int step; /* step through args */
+ int ch; /* getopts char */
+ char cmd[100]; /* too ugly to explain */
+ extern char *optarg;
+ extern int optind;
+
+#ifndef lint
+ copyright[0] = copyright[0]; /* to satisfy compiler */
+#endif
+ aflag = uflag = NO;
+#ifdef GTAGS
+ while ((ch = getopt(argc, argv, "BDFadef:rtuwvxy")) != EOF)
+#else
+ while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != EOF)
+#endif
+ switch(ch) {
+ case 'B':
+ searchar = '?';
+ break;
+#ifdef GTAGS
+ case 'D':
+ Dflag++;
+ break;
+#endif
+ case 'F':
+ searchar = '/';
+ break;
+ case 'a':
+ aflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+#ifdef GTAGS
+ case 'e':
+ eflag++;
+ break;
+#endif
+ case 'f':
+ outfile = optarg;
+ break;
+#ifdef GTAGS
+ case 'r':
+ rflag++;
+ break;
+#endif
+ case 't':
+ tflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'w':
+ wflag++;
+ break;
+ case 'v':
+ vflag++;
+ case 'x':
+ xflag++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argv += optind;
+ argc -= optind;
+ if (!argc) {
+usage: (void)fprintf(stderr,
+#ifdef GTAGS
+ "usage: ctags [-BDFadrtuwvx] [-f tagsfile] file ...\n");
+#else
+ "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
+#endif
+ exit(1);
+ }
+#ifdef GTAGS
+ if (rflag)
+ gtagopen();
+#endif
+ init();
+
+ for (exit_val = step = 0; step < argc; ++step)
+ if (!(inf = fopen(argv[step], "r"))) {
+ fprintf(stderr, "gctags: %s cannot open\n", argv[step]);
+ exit_val = 1;
+ }
+ else {
+ curfile = argv[step];
+ find_entries(argv[step]);
+ (void)fclose(inf);
+ }
+
+ if (head)
+ if (xflag)
+ put_entries(head);
+ else {
+ if (uflag) {
+ for (step = 0; step < argc; step++) {
+ (void)sprintf(cmd,
+ "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
+ outfile, argv[step],
+ outfile);
+ system(cmd);
+ }
+ ++aflag;
+ }
+ if (!(outf = fopen(outfile, aflag ? "a" : "w"))) {
+ fprintf(stderr, "gctags: %s cannot open\n", outfile);
+ exit(exit_val);
+ }
+ put_entries(head);
+ (void)fclose(outf);
+ if (uflag) {
+ (void)sprintf(cmd, "sort -o %s %s",
+ outfile, outfile);
+ system(cmd);
+ }
+ }
+#ifdef GTAGS
+ if (rflag)
+ gtagclose();
+#endif
+ exit(exit_val);
+}
+
+/*
+ * init --
+ * this routine sets up the boolean psuedo-functions which work by
+ * setting boolean flags dependent upon the corresponding character.
+ * Every char which is NOT in that string is false with respect to
+ * the pseudo-function. Therefore, all of the array "_wht" is NO
+ * by default and then the elements subscripted by the chars in
+ * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in
+ * the string CWHITE, else NO.
+ */
+void
+init()
+{
+ int i;
+ unsigned char *sp;
+
+ for (i = 0; i < 256; i++) {
+ _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
+ _gd[i] = YES;
+ }
+#define CWHITE " \f\t\n"
+ for (sp = (unsigned char *)CWHITE; *sp; sp++) /* white space chars */
+ _wht[*sp] = YES;
+#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
+ for (sp = (unsigned char *)CTOKEN; *sp; sp++) /* token ending chars */
+ _etk[*sp] = YES;
+#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
+ for (sp = (unsigned char *)CINTOK; *sp; sp++) /* valid in-token chars */
+ _itk[*sp] = YES;
+#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
+ for (sp = (unsigned char *)CBEGIN; *sp; sp++) /* token starting chars */
+ _btk[*sp] = YES;
+#define CNOTGD ",;"
+ for (sp = (unsigned char *)CNOTGD; *sp; sp++) /* invalid after-function chars */
+ _gd[*sp] = NO;
+}
+
+/*
+ * find_entries --
+ * this routine opens the specified file and calls the function
+ * which searches the file.
+ */
+void
+find_entries(file)
+ char *file;
+{
+ char *cp;
+
+ lineno = 0; /* should be 1 ?? KB */
+ if ((cp = strrchr(file, '.')) != NULL) {
+ if (cp[1] == 'l' && !cp[2]) {
+ int c;
+
+#ifdef GTAGS
+ if (rflag)
+ fprintf(stderr, "-r option is ignored in lisp file (Warning only)\n");
+#endif
+ for (;;) {
+ if (GETC(==, EOF))
+ return;
+ if (!iswhite(c)) {
+ rewind(inf);
+ break;
+ }
+ }
+#define LISPCHR ";(["
+/* lisp */ if (strchr(LISPCHR, c)) {
+ l_entries();
+ return;
+ }
+/* lex */ else {
+ /*
+ * we search all 3 parts of a lex file
+ * for C references. This may be wrong.
+ */
+ toss_yysec();
+ (void)strcpy(lbuf, "%%$");
+ pfnote("yylex", lineno);
+ rewind(inf);
+ }
+ }
+/* yacc */ else if (cp[1] == 'y' && !cp[2]) {
+#ifdef YACC
+ /*
+ * we search all part of a yacc file for C references.
+ * but ignore yacc rule tags.
+ */
+ yaccfile = YES;
+ c_entries();
+ return;
+#endif
+ /*
+ * we search only the 3rd part of a yacc file
+ * for C references. This may be wrong.
+ */
+ toss_yysec();
+ (void)strcpy(lbuf, "%%$");
+ pfnote("yyparse", lineno);
+ y_entries();
+ }
+/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
+#ifdef GTAGS
+ if (rflag)
+ fprintf(stderr, "-r option is ignored in fortran file (Warning only)\n");
+#endif
+ if (PF_funcs())
+ return;
+ rewind(inf);
+ }
+ }
+#ifdef YACC
+ yaccfile = NO;
+#endif
+/* C */ c_entries();
+}
+
+#ifdef GTAGS
+#include <db.h>
+DB *db;
+
+void
+gtagopen()
+{
+ BTREEINFO info;
+ char *env;
+ char dbname[200];
+
+ strcpy(dbname, ".");
+ if ((env = getenv("GTAGDBPATH"))) {
+ strcpy(dbname, env);
+ }
+ strcat(dbname, "/GTAGS");
+
+ info.flags = 0;
+ info.cachesize = 500000;
+ info.maxkeypage = 0;
+ info.minkeypage = 0;
+ info.psize = 0;
+ info.compare = 0;
+ info.prefix = 0;
+ info.lorder = 0;
+
+#define O_RDONLY 0x0000 /* open for reading only */
+ db = dbopen(dbname, O_RDONLY, 0, DB_BTREE, &info);
+ if (db == 0) {
+ fprintf(stderr, "GTAGS file needed.\n");
+ exit(1);
+ }
+}
+int
+isdefined(skey)
+char *skey;
+{
+ DBT dat, key;
+ int status;
+
+ key.data = skey;
+ key.size = strlen(skey)+1;
+
+ status = (*db->get)(db, &key, &dat, 0);
+ switch (status) {
+ case RET_SUCCESS:
+ return(1); /* exist */
+ case RET_ERROR:
+ fprintf(stderr, "db->get failed.\n");
+ exit(1);
+ case RET_SPECIAL: /* not exist */
+ break;
+ }
+ return 0;
+}
+void
+gtagclose()
+{
+ if (db->close(db)) {
+ fprintf(stderr, "GTAGS cannot close.(dbclose)\n");
+ exit(1);
+ }
+}
+#endif
diff --git a/usr.bin/global/gctags/ctags.h b/usr.bin/global/gctags/ctags.h
new file mode 100644
index 0000000..7fa84b8
--- /dev/null
+++ b/usr.bin/global/gctags/ctags.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ctags.h 8.3 (Berkeley) 4/2/94
+ */
+
+#define bool char
+
+#define YES 1
+#define NO 0
+#define EOS '\0'
+
+#define ENDLINE 50 /* max length of pattern */
+#define MAXTOKEN 250 /* max size of single token */
+
+#ifndef LINE_MAX
+#define LINE_MAX 2048
+#endif
+
+#define SETLINE {++lineno;lineftell = ftell(inf);}
+#define GETC(op,exp) ((c = getc(inf)) op (int)exp)
+
+#define iswhite(arg) (_wht[(unsigned)arg]) /* T if char is white */
+#define begtoken(arg) (_btk[(unsigned)arg]) /* T if char can start token */
+#define intoken(arg) (_itk[(unsigned)arg]) /* T if char can be in token */
+#define endtoken(arg) (_etk[(unsigned)arg]) /* T if char ends tokens */
+#define isgood(arg) (_gd[(unsigned)arg]) /* T if char can be after ')' */
+
+typedef struct nd_st { /* sorting structure */
+ struct nd_st *left,
+ *right; /* left and right sons */
+ char *entry, /* function or type name */
+ *file, /* file name */
+ *pat; /* search pattern */
+ int lno; /* for -x option */
+ bool been_warned; /* set if noticed dup */
+} NODE;
+
+extern char *curfile; /* current input file name */
+extern NODE *head; /* head of the sorted binary tree */
+extern FILE *inf; /* ioptr for current input file */
+extern FILE *outf; /* ioptr for current output file */
+extern long lineftell; /* ftell after getc( inf ) == '\n' */
+extern int lineno; /* line number of current line */
+#ifdef GTAGS
+extern int eflag; /* -e: '{' at 0 column force function end */
+extern int Dflag; /* -D: allow duplicate entrys */
+extern int rflag; /* -r: function reference */
+#endif /* GTAGS */
+extern int dflag; /* -d: non-macro defines */
+extern int tflag; /* -t: create tags for typedefs */
+extern int vflag; /* -v: vgrind style index output */
+extern int wflag; /* -w: suppress warnings */
+extern int xflag; /* -x: cxref style output */
+extern bool _wht[], _etk[], _itk[], _btk[], _gd[];
+extern char lbuf[LINE_MAX];
+extern char *lbp;
+extern char searchar; /* ex search character */
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+int cicmp __P((char *));
+void getline __P((void));
+void pfnote __P((char *, int));
+int skip_key __P((int));
+void put_entries __P((NODE *));
+void toss_yysec __P((void));
+void l_entries __P((void));
+void y_entries __P((void));
+int PF_funcs __P((void));
+void c_entries __P((void));
+void skip_comment __P((void));
+void gtagopen __P((void));
+int isdefined __P((char *));
+void gtagclose __P((void));
diff --git a/usr.bin/global/gctags/fortran.c b/usr.bin/global/gctags/fortran.c
new file mode 100644
index 0000000..2a33aff
--- /dev/null
+++ b/usr.bin/global/gctags/fortran.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fortran.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+static void takeprec __P((void));
+
+char *lbp; /* line buffer pointer */
+
+int
+PF_funcs()
+{
+ bool pfcnt; /* pascal/fortran functions found */
+ char *cp;
+ char tok[MAXTOKEN];
+
+ for (pfcnt = NO;;) {
+ lineftell = ftell(inf);
+ if (!fgets(lbuf, sizeof(lbuf), inf))
+ return (pfcnt);
+ ++lineno;
+ lbp = lbuf;
+ if (*lbp == '%') /* Ratfor escape to fortran */
+ ++lbp;
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ switch (*lbp | ' ') { /* convert to lower-case */
+ case 'c':
+ if (cicmp("complex") || cicmp("character"))
+ takeprec();
+ break;
+ case 'd':
+ if (cicmp("double")) {
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ if (cicmp("precision"))
+ break;
+ continue;
+ }
+ break;
+ case 'i':
+ if (cicmp("integer"))
+ takeprec();
+ break;
+ case 'l':
+ if (cicmp("logical"))
+ takeprec();
+ break;
+ case 'r':
+ if (cicmp("real"))
+ takeprec();
+ break;
+ }
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ switch (*lbp | ' ') {
+ case 'f':
+ if (cicmp("function"))
+ break;
+ continue;
+ case 'p':
+ if (cicmp("program") || cicmp("procedure"))
+ break;
+ continue;
+ case 's':
+ if (cicmp("subroutine"))
+ break;
+ default:
+ continue;
+ }
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ for (cp = lbp + 1; *cp && intoken(*cp); ++cp)
+ continue;
+ if (cp == lbp + 1)
+ continue;
+ *cp = EOS;
+ (void)strcpy(tok, lbp);
+ getline(); /* process line for ex(1) */
+ pfnote(tok, lineno);
+ pfcnt = YES;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * cicmp --
+ * do case-independent strcmp
+ */
+int
+cicmp(cp)
+ char *cp;
+{
+ int len;
+ char *bp;
+
+ for (len = 0, bp = lbp; *cp && (*cp &~ ' ') == (*bp++ &~ ' ');
+ ++cp, ++len)
+ continue;
+ if (!*cp) {
+ lbp += len;
+ return (YES);
+ }
+ return (NO);
+}
+
+static void
+takeprec()
+{
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (*lbp == '*') {
+ for (++lbp; isspace(*lbp); ++lbp)
+ continue;
+ if (!isdigit(*lbp))
+ --lbp; /* force failure */
+ else
+ while (isdigit(*++lbp))
+ continue;
+ }
+}
diff --git a/usr.bin/global/gctags/gctags.1 b/usr.bin/global/gctags/gctags.1
new file mode 100644
index 0000000..224ea76
--- /dev/null
+++ b/usr.bin/global/gctags/gctags.1
@@ -0,0 +1,227 @@
+.\" Copyright (c) 1987, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)gctags.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd April 21, 1997
+.Dt GCTAGS 1
+.Os BSD 4
+.Sh NAME
+.Nm gctags
+.Nd create a tags file (special command for GLOBAL)
+.Sh SYNOPSIS
+.Nm gctags
+.Op Fl BDFadertuwvx
+.Op Fl f Ar tagsfile
+.Ar name ...
+.Sh DESCRIPTION
+.Nm Gctags
+makes a tags file for
+.Xr ex 1
+from the specified C,
+Pascal, Fortran,
+.Tn YACC ,
+lex, and lisp sources.
+A tags file gives the locations of specified objects in a group of files.
+Each line of the tags file contains the object name, the file in which it
+is defined, and a search pattern for the object definition, separated by
+white-space.
+Using the
+.Ar tags
+file,
+.Xr ex 1
+can quickly locate these object definitions.
+Depending upon the options provided to
+.Nm gctags ,
+objects will consist of subroutines, typedefs, defines, structs,
+enums and unions.
+.Bl -tag -width Ds
+.It Fl B
+use backward searching patterns
+.Pq Li ?...? .
+.It Fl D
+allow duplicate object names.
+.It Fl F
+use forward searching patterns
+.Pq Li /.../
+(the default).
+.It Fl a
+append to
+.Ar tags
+file.
+.It Fl d
+create tags for
+.Li #defines
+that don't take arguments;
+.Li #defines
+that take arguments are tagged automatically.
+.It Fl e
+force a function to end when reach a '}' at the first column. (C source only)
+.It Fl f
+place the tag descriptions in a file called
+.Ar tagsfile .
+The default behavior is to place them in a file called
+.Ar tags .
+.It Fl r
+locate function references instead of function definitions. GTAGS file is
+needed at the current directory. (C source only)
+.It Fl t
+create tags for typedefs, structs, unions, and enums.
+.It Fl u
+update the specified files in the
+.Ar tags
+file, that is, all
+references to them are deleted, and the new values are appended to the
+file. (Beware: this option is implemented in a way which is rather
+slow; it is usually faster to simply rebuild the
+.Ar tags
+file.)
+.It Fl v
+An index of the form expected by
+.Xr vgrind 1
+is produced on the standard output. This listing
+contains the object name, file name, and page number (assuming 64
+line pages). Since the output will be sorted into lexicographic order,
+it may be desired to run the output through
+.Xr sort 1 .
+Sample use:
+.Bd -literal -offset indent
+gctags \-v files \&| sort \-f > index
+vgrind \-x index
+.Ed
+.It Fl w
+suppress warning diagnostics.
+.It Fl x
+.Nm gctags
+produces a list of object
+names, the line number and file name on which each is defined, as well
+as the text of that line and prints this on the standard output. This
+is a simple index which can be printed out as an off-line readable
+function index.
+.El
+.Pp
+Files whose names end in
+.Nm \&.c
+or
+.Nm \&.h
+are assumed to be C
+source files and are searched for C style routine and macro definitions.
+Files whose names end in
+.Nm \&.y
+are assumed to be
+.Tn YACC
+source files.
+Files whose names end in
+.Nm \&.l
+are assumed to be lisp files if their
+first non-blank character is `;', `(', or `[',
+otherwise, they are
+treated as lex files. Other files are first examined to see if they
+contain any Pascal or Fortran routine definitions, and, if not, are
+searched for C style definitions.
+.Pp
+The tag
+.Li main
+is treated specially in C programs. The tag formed
+is created by prepending
+.Ar M
+to the name of the file, with the
+trailing
+.Nm \&.c
+and any leading pathname components removed. This
+makes use of
+.Nm gctags
+practical in directories with more than one
+program.
+.Pp
+Yacc and lex files each have a special tag.
+.Ar Yyparse
+is the start
+of the second section of the yacc file, and
+.Ar yylex
+is the start of
+the second section of the lex file.
+.Sh FILES
+.Bl -tag -width tags -compact
+.It Pa tags
+default output tags file
+.It Pa GTAGS
+tags file for GLOBAL
+.El
+.Sh DIAGNOSTICS
+.Nm Gctags
+exits with a value of 1 if an error occurred, 0 otherwise.
+Duplicate objects are not considered errors.
+.Sh SEE ALSO
+.Xr btreeop 1 ,
+.Xr ex 1 ,
+.Xr global 1 ,
+.Xr gtags 1 ,
+.Xr htags 1 ,
+.Xr vi 1 .
+.Sh BUGS
+.Pp
+Recognition of
+.Nm functions ,
+.Nm subroutines
+and
+.Nm procedures
+for
+.Tn FORTRAN
+and Pascal is done is a very simpleminded way. No attempt
+is made to deal with block structure; if you have two Pascal procedures
+in different blocks with the same name you lose.
+.Nm Gctags
+doesn't
+understand about Pascal types.
+.Pp
+The method of deciding whether to look for C, Pascal or
+.Tn FORTRAN
+functions is a hack.
+.Pp
+.Nm Gctags
+relies on the input being well formed, and any syntactical
+errors will completely confuse it. It also finds some legal syntax
+confusing; for example, since it doesn't understand
+.Li #ifdef Ns 's
+(incidentally, that's a feature, not a bug), any code with unbalanced
+braces inside
+.Li #ifdef Ns 's
+will cause it to become somewhat disoriented.
+In a similar fashion, multiple line changes within a definition will
+cause it to enter the last line of the object, rather than the first, as
+the searching pattern. The last line of multiple line
+.Li typedef Ns 's
+will similarly be noted.
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.2.
diff --git a/usr.bin/global/gctags/lisp.c b/usr.bin/global/gctags/lisp.c
new file mode 100644
index 0000000..ebf5184
--- /dev/null
+++ b/usr.bin/global/gctags/lisp.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)lisp.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+/*
+ * lisp tag functions
+ * just look for (def or (DEF
+ */
+void
+l_entries()
+{
+ int special;
+ char *cp;
+ char savedc;
+ char tok[MAXTOKEN];
+
+ for (;;) {
+ lineftell = ftell(inf);
+ if (!fgets(lbuf, sizeof(lbuf), inf))
+ return;
+ ++lineno;
+ lbp = lbuf;
+ if (!cicmp("(def"))
+ continue;
+ special = NO;
+ switch(*lbp | ' ') {
+ case 'm':
+ if (cicmp("method"))
+ special = YES;
+ break;
+ case 'w':
+ if (cicmp("wrapper") || cicmp("whopper"))
+ special = YES;
+ }
+ for (; !isspace(*lbp); ++lbp)
+ continue;
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ for (cp = lbp; *cp && *cp != '\n'; ++cp)
+ continue;
+ *cp = EOS;
+ if (special) {
+ if (!(cp = strchr(lbp, ')')))
+ continue;
+ for (; cp >= lbp && *cp != ':'; --cp)
+ continue;
+ if (cp < lbp)
+ continue;
+ lbp = cp;
+ for (; *cp && *cp != ')' && *cp != ' '; ++cp)
+ continue;
+ }
+ else
+ for (cp = lbp + 1;
+ *cp && *cp != '(' && *cp != ' '; ++cp)
+ continue;
+ savedc = *cp;
+ *cp = EOS;
+ (void)strcpy(tok, lbp);
+ *cp = savedc;
+ getline();
+ pfnote(tok, lineno);
+ }
+ /*NOTREACHED*/
+}
diff --git a/usr.bin/global/gctags/print.c b/usr.bin/global/gctags/print.c
new file mode 100644
index 0000000..692d36b
--- /dev/null
+++ b/usr.bin/global/gctags/print.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)print.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ctags.h"
+
+/*
+ * getline --
+ * get the line the token of interest occurred on,
+ * prepare it for printing.
+ */
+void
+getline()
+{
+ long saveftell;
+ int c;
+ int cnt;
+ char *cp;
+
+ saveftell = ftell(inf);
+ (void)fseek(inf, lineftell, SEEK_SET);
+ if (xflag)
+ for (cp = lbuf; GETC(!=, '\n'); *cp++ = c)
+ continue;
+ /*
+ * do all processing here, so we don't step through the
+ * line more than once; means you don't call this routine
+ * unless you're sure you've got a keeper.
+ */
+ else for (cnt = 0, cp = lbuf; GETC(!=, EOF) && cnt < ENDLINE; ++cnt) {
+ if (c == '\\') { /* backslashes */
+ if (cnt > ENDLINE - 2)
+ break;
+ *cp++ = '\\'; *cp++ = '\\';
+ ++cnt;
+ }
+ else if (c == (int)searchar) { /* search character */
+ if (cnt > ENDLINE - 2)
+ break;
+ *cp++ = '\\'; *cp++ = c;
+ ++cnt;
+ }
+ else if (c == '\n') { /* end of keep */
+ *cp++ = '$'; /* can find whole line */
+ break;
+ }
+ else
+ *cp++ = c;
+ }
+ *cp = EOS;
+ (void)fseek(inf, saveftell, SEEK_SET);
+}
+
+/*
+ * put_entries --
+ * write out the tags
+ */
+void
+put_entries(node)
+ NODE *node;
+{
+
+ if (node->left)
+ put_entries(node->left);
+ if (vflag)
+ printf("%s %s %d\n",
+ node->entry, node->file, (node->lno + 63) / 64);
+ else if (xflag)
+#ifdef MODIFY
+ /* separate 'entry' and 'lno' */
+ if (strlen(node->entry) >= 16 && node->lno >= 1000)
+ printf("%-16s %4d %-16s %s\n",
+ node->entry, node->lno, node->file, node->pat);
+ else /* for compatibility */
+#endif
+ printf("%-16s%4d %-16s %s\n",
+ node->entry, node->lno, node->file, node->pat);
+ else
+ fprintf(outf, "%s\t%s\t%c^%s%c\n",
+ node->entry, node->file, searchar, node->pat, searchar);
+ if (node->right)
+ put_entries(node->right);
+}
diff --git a/usr.bin/global/gctags/test/ctags.test b/usr.bin/global/gctags/test/ctags.test
new file mode 100644
index 0000000..1f334ac
--- /dev/null
+++ b/usr.bin/global/gctags/test/ctags.test
@@ -0,0 +1,67 @@
+int bar = (1 + 5);
+
+FOO("here is a #define test: ) {");
+char sysent[20];
+int nsysent = sizeof (sysent) / sizeof (sysent[0]);
+/*
+ * now is the time for a comment.
+ * four lines in length...
+ */struct struct_xtra{int list;};r4(x,y){};typedef struct{int bar;}struct_xxe;
+#define FOO BAR
+struct struct_three {
+ int list;
+};
+#define SINGLE
+int BAD();
+enum color {red, green, gold, brown};
+char qq[] = " quote(one,two) {int bar;} ";
+typedef struct {
+ int bar;
+ struct struct_two {
+ int foo;
+ union union_3 {
+ struct struct_three entry;
+ char size[25];
+ };
+ struct last {
+ struct struct_three xentry;
+ char list[34];
+ };
+ };
+} struct_one;
+#define TWOLINE ((MAXLIST + FUTURE + 15) \
+ / (time_to_live ? 3 : 4))
+#if (defined(BAR))
+int bar;
+#endif
+#define MULTIPLE {\
+ multiple(one,two); \
+ lineno++; \
+ callroute(one,two); \
+}
+#if defined(BAR)
+int bar;
+#endif
+union union_one {
+ struct struct_three s3;
+ char foo[25];
+};
+#define XYZ(A,B) (A + B / 2) * (3 - 26 + l_lineno)
+routine1(one,two) /* comments here are fun... */
+ struct {
+ int entry;
+ char bar[34];
+ } *one;
+ char two[10];
+{
+typedef unsigned char u_char;
+ register struct buf *bp;
+ five(one,two);
+}
+ routine2 (one,two) { puts("hello\n"); }
+ routine3
+(one,
+two) { puts("world\n"); }
+routine4(int one, char (*two)(void)) /* test ANSI arguments */
+{
+}
diff --git a/usr.bin/global/gctags/tree.c b/usr.bin/global/gctags/tree.c
new file mode 100644
index 0000000..831691a
--- /dev/null
+++ b/usr.bin/global/gctags/tree.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tree.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ctags.h"
+
+static void add_node __P((NODE *, NODE *));
+static void free_tree __P((NODE *));
+
+/*
+ * pfnote --
+ * enter a new node in the tree
+ */
+void
+pfnote(name, ln)
+ char *name;
+ int ln;
+{
+ NODE *np;
+ char *fp;
+ char nbuf[MAXTOKEN];
+
+ /*NOSTRICT*/
+ if (!(np = (NODE *)malloc(sizeof(NODE)))) {
+ fprintf(stderr, "too many entries to sort");
+ put_entries(head);
+ free_tree(head);
+ /*NOSTRICT*/
+ if (!(head = np = (NODE *)malloc(sizeof(NODE)))) {
+ fprintf(stderr, "gctags: out of space\n");
+ exit(1);
+ }
+ }
+ if (!xflag && !strcmp(name, "main")) {
+ if (!(fp = strrchr(curfile, '/')))
+ fp = curfile;
+ else
+ ++fp;
+ (void)sprintf(nbuf, "M%s", fp);
+ fp = strrchr(nbuf, '.');
+ if (fp && !fp[2])
+ *fp = EOS;
+ name = nbuf;
+ }
+ if (!(np->entry = strdup(name))) {
+ fprintf(stderr, "gctags: out of space\n");
+ exit(1);
+ }
+ np->file = curfile;
+ np->lno = ln;
+ np->left = np->right = 0;
+ if (!(np->pat = strdup(lbuf))) {
+ fprintf(stderr, "gctags: out of space\n");
+ exit(1);
+ }
+ if (!head)
+ head = np;
+ else
+ add_node(np, head);
+}
+
+static void
+add_node(node, cur_node)
+ NODE *node,
+ *cur_node;
+{
+ int dif;
+
+ dif = strcmp(node->entry, cur_node->entry);
+#ifdef GTAGS
+ if (!Dflag && !dif) /* -D option allows duplicate entries. */
+#else
+ if (!dif)
+#endif
+ {
+ if (node->file == cur_node->file) {
+ if (!wflag)
+ fprintf(stderr, "Duplicate entry in file %s, line %d: %s\nSecond entry ignored\n", node->file, lineno, node->entry);
+ return;
+ }
+ if (!cur_node->been_warned)
+ if (!wflag)
+ fprintf(stderr, "Duplicate entry in files %s and %s: %s (Warning only)\n", node->file, cur_node->file, node->entry);
+ cur_node->been_warned = YES;
+ }
+ else if (dif < 0)
+ if (cur_node->left)
+ add_node(node, cur_node->left);
+ else
+ cur_node->left = node;
+ else if (cur_node->right)
+ add_node(node, cur_node->right);
+ else
+ cur_node->right = node;
+}
+
+static void
+free_tree(node)
+ NODE *node;
+{
+ while (node) {
+ if (node->right)
+ free_tree(node->right);
+ free(node);
+ node = node->left;
+ }
+}
diff --git a/usr.bin/global/gctags/yacc.c b/usr.bin/global/gctags/yacc.c
new file mode 100644
index 0000000..9dcdd5a
--- /dev/null
+++ b/usr.bin/global/gctags/yacc.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)yacc.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+/*
+ * y_entries:
+ * find the yacc tags and put them in.
+ */
+void
+y_entries()
+{
+ int c;
+ char *sp;
+ bool in_rule;
+ char tok[MAXTOKEN];
+
+ in_rule = NO;
+
+ while (GETC(!=, EOF))
+ switch (c) {
+ case '\n':
+ SETLINE;
+ /* FALLTHROUGH */
+ case ' ':
+ case '\f':
+ case '\r':
+ case '\t':
+ break;
+ case '{':
+ if (skip_key('}'))
+ in_rule = NO;
+ break;
+ case '\'':
+ case '"':
+ if (skip_key(c))
+ in_rule = NO;
+ break;
+ case '%':
+ if (GETC(==, '%'))
+ return;
+ (void)ungetc(c, inf);
+ break;
+ case '/':
+ if (GETC(==, '*'))
+ skip_comment();
+ else
+ (void)ungetc(c, inf);
+ break;
+ case '|':
+ case ';':
+ in_rule = NO;
+ break;
+ default:
+ if (in_rule || (!isalpha(c) && c != '.' && c != '_'))
+ break;
+ sp = tok;
+ *sp++ = c;
+ while (GETC(!=, EOF) && (intoken(c) || c == '.'))
+ *sp++ = c;
+ *sp = EOS;
+ getline(); /* may change before ':' */
+ while (iswhite(c)) {
+ if (c == '\n')
+ SETLINE;
+ if (GETC(==, EOF))
+ return;
+ }
+ if (c == ':') {
+ pfnote(tok, lineno);
+ in_rule = YES;
+ }
+ else
+ (void)ungetc(c, inf);
+ }
+}
+
+/*
+ * toss_yysec --
+ * throw away lines up to the next "\n%%\n"
+ */
+void
+toss_yysec()
+{
+ int c; /* read character */
+ int state;
+
+ /*
+ * state == 0 : waiting
+ * state == 1 : received a newline
+ * state == 2 : received first %
+ * state == 3 : recieved second %
+ */
+ lineftell = ftell(inf);
+ for (state = 0; GETC(!=, EOF);)
+ switch (c) {
+ case '\n':
+ ++lineno;
+ lineftell = ftell(inf);
+ if (state == 3) /* done! */
+ return;
+ state = 1; /* start over */
+ break;
+ case '%':
+ if (state) /* if 1 or 2 */
+ ++state; /* goto 3 */
+ break;
+ default:
+ state = 0; /* reset */
+ break;
+ }
+}
diff --git a/usr.bin/global/global/Makefile b/usr.bin/global/global/Makefile
new file mode 100644
index 0000000..256ea71
--- /dev/null
+++ b/usr.bin/global/global/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.0 (Berkeley) 4/21/96
+
+MAN1= global.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/global.pl ${DESTDIR}/usr/bin/global
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/global/global.1 b/usr.bin/global/global/global.1
new file mode 100644
index 0000000..613a915
--- /dev/null
+++ b/usr.bin/global/global/global.1
@@ -0,0 +1,136 @@
+.\"
+.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Shigio Yamaguchi.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 21, 1997
+.Dt GLOBAL 1
+.Os BSD 4
+.Sh NAME
+.Nm global
+.Nd print the locations of specified function.
+.Sh SYNOPSIS
+.Nm global
+.Op Fl acrx
+.Ar name
+.Sh DESCRIPTION
+.Nm Global
+find the locations of specified function in C and Yacc source files.
+.Nm Global
+can treat a source tree, that is, a directory that has subdirectories and
+source files.
+You can get the relative path of objects from anywhere within the tree.
+
+.Nm Global
+can locate not only function definitions but also function references and
+allow duplicate entries too.
+.Pp
+In advance of using this command, you must execute
+.Xr gtags 1
+at the root directory of the source tree.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+print absolute path name. By default, print relative path name.
+.It Fl c
+print candidate function names which start with specified string.
+If string is not specified, print all function names.
+.It Fl r
+print the locations of function references. By default, print function
+definitions.
+.It Fl x
+In addition to the default output, produce the line number and
+the line contents.
+.It Ar name
+function name. It can include perl's regular expression.
+.Sh FILES
+.Bl -tag -width tags -compact
+.It Pa GTAGS
+tags file for function definitions.
+.It Pa GRTAGS
+tags file for function references.
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of global.
+.Pp
+.Bl -tag -width indent
+.It Ev GTAGSROOT
+The directory which is the root of source tree.
+.It Ev GTAGSDBPATH
+The directory on which gtags database exist. This value is ignored
+when GTAGSROOT is not defined.
+.It Ev GTAGSLIBPATH
+If this variable is set, its value is used as the path to search for library
+functions. If specified function is not found in a source tree,
+global search in these path too.
+.Sh EXAMPLES
+
+ % ls -F
+ Makefile src/ lib/
+ % gtags
+ % global main
+ src/main.c
+ % global -x main
+ main 10 src/main.c main (argc, argv) {
+ % global -x '^[sg]et'
+ set_num 20 lib/util.c set_num(values)
+ get_num 30 lib/util.c get_num() {
+ % global -rx '^[sg]et'
+ set_num 113 src/op.c set_num(32);
+ set_num 225 src/opop.c if (set_num(0) > 0) {
+ get_num 90 src/op.c while (get_num() > 0) {
+ % cd lib
+ % global -rx '^[sg]et'
+ set_num 113 ../src/op.c set_num(32);
+ set_num 225 ../src/opop.c if (set_num(0) > 0) {
+ get_num 90 ../src/op.c while (get_num() > 0) {
+ % global strlen
+ % (cd /usr/src/sys; gtags)
+ % setenv GTAGSLIBPATH /usr/src/sys
+ % global strlen
+ ../../../usr/src/sys/libkern/strlen.c
+ % (cd /usr/src/lib; gtags)
+ % setenv GTAGSLIBPATH /usr/src/lib:/usr/src/sys
+ % global strlen
+ ../../../usr/src/lib/libc/string/strlen.c
+
+.Sh DIAGNOSTICS
+.Nm Global
+exits with a non 0 value if an error occurred, 0 otherwise.
+.Sh SEE ALSO
+.Xr btreeop 1 ,
+.Xr gctags 1 ,
+.Xr gtags 1 ,
+.Xr htags 1 .
+.Sh AUTHORS
+Shigio Yamaguchi (shigio@wafu.netgate.net)
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.2.
diff --git a/usr.bin/global/global/global.pl b/usr.bin/global/global/global.pl
new file mode 100644
index 0000000..ff00340
--- /dev/null
+++ b/usr.bin/global/global/global.pl
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Shigio Yamaguchi.
+# 4. Neither the name of the author nor the names of any co-contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# global.pl 21-Apr-97
+#
+sub getcwd {
+ local($dir);
+ chop($dir = `/bin/pwd`);
+ $dir;
+}
+$com = $0;
+$com =~ s/.*\///;
+$usage = "usage:\t$com [-a][-r][-x] pattern\n\t$com -c [name]\n";
+#
+# options check
+#
+while ($ARGV[0] =~ /^-/) {
+ $opt = shift;
+ if ($opt =~ /a/) { $aflag = 1; }
+ if ($opt =~ /c/) { $cflag = 1; }
+ if ($opt =~ /r/) { $rflag = 1; }
+ if ($opt =~ /x/) { $xflag = 1; }
+}
+if (@ARGV == 0) {
+ die($usage) if (! $cflag);
+}
+$ARGV[0] =~ s/^[ \t]+//; # remove leading blanks
+if ($ARGV[0] =~ /[][.*\^\$+?|(){}\\]/) { # include regular expression ?
+ $regex = 1;
+}
+if ($cflag) {
+ die($usage) if ($aflag || $rflag || $xflag);
+ die("$com: regular expression not allowed with -c option.\n") if ($regex);
+}
+$current = &getcwd;
+#
+# get $dbpath and $root
+#
+if (defined($ENV{'GTAGSROOT'})) {
+ $root = $ENV{'GTAGSROOT'};
+ if (defined($ENV{'GTAGSDBPATH'})) {
+ $dbpath = $ENV{'GTAGSDBPATH'};
+ } else {
+ $dbpath = $root;
+ }
+ unless ($current =~ /$root/) {
+ die("$com: illegal GTAGSROOT.\n");
+ }
+ chdir($dbpath) || die("$com: directory $dbpath not found.\n");
+ $dbpath = &getcwd;
+ chdir($current);
+ chdir($root) || die("$com: directory $root not found.\n");
+ $root = &getcwd;
+}
+chdir($current) || die("$com: cannot return current directory.\n");
+$gtagsname = ($rflag) ? 'GRTAGS' : 'GTAGS';
+#
+# make a sed command to make paths into relative
+#
+if (! defined($root)) {
+ chdir($current);
+ while (! -r $gtagsname && ! -r "obj/$gtagsname") {
+ if (&getcwd =~ m!^/$!) { die "$com: $gtagsname not found.\n"; }
+ chdir('..');
+ }
+ $dbpath = $root = &getcwd;
+ $dbpath = "$dbpath/obj" if (! -r $gtagsname);
+}
+$cur = $current;
+$cur =~ s!$root!!;
+$cur =~ s!^/!!;
+@step = split('/', $cur);
+$downpath = '\\.\\./' x @step;
+push(@com, "-e 's!\\./!$downpath!'");
+foreach $step (@step) {
+ push(@com, "-e 's!\\.\\./$step/!!'");
+}
+#
+# recognize format version of GTAGS. 'format version record' is saved as a
+# META record in GTAGS and GRTAGS. if 'format version record' is not found,
+# it's assumed version 1.
+ $support_version = 1; # accept this format version
+#
+open(GTAGS, "btreeop -K ' __.VERSION' $dbpath/$gtagsname |") || die("$com: GTAGS not found.\n");
+$rec = <GTAGS>;
+close(GTAGS);
+if ($rec =~ /^ __\.VERSION[ \t]+([0-9]+)$/) {
+ $format_version = $1;
+} else {
+ $format_version = 1;
+}
+if ($format_version > $support_version) {
+ die("$com: GTAGS seems new format. Please install the latest GLOBAL.\n");
+}
+#
+# complete function name
+#
+if ($cflag) {
+ open(PIPEIN, "btreeop $dbpath/GTAGS | awk '{print \$1}' | sort | uniq |") || die("$com: btreeop cannot exec.\n");
+ while (<PIPEIN>) {
+ print if (@ARGV == 0 || $_ =~ /^$ARGV[0]/o);
+ }
+ close(PIPEIN);
+ exit(0);
+}
+#
+# search in current source tree.
+#
+$cnt = &search($ARGV[0], $dbpath, $gtagsname, @com);
+#
+# search in library path.
+#
+if ($cnt == 0 && ! $regex && ! $rflag && defined($ENV{'GTAGSLIBPATH'})) {
+ foreach $lib (split(':', $ENV{'GTAGSLIBPATH'})) {
+ next unless (-f "$lib/GTAGS");
+ next if ($dbpath eq $lib);
+ chdir($lib) || die("$com: cannot chdir to $lib.\n");
+ $dbpath = &getcwd;
+ $common = &common($dbpath, $current);
+ $up = $dbpath;
+ $up =~ s/$common//;
+ $down = $current;
+ $down =~ s/$common//;
+ $down =~ s![^/]+!..!g;
+ next if ($down eq '' || $up eq '');
+ $cnt = &search($ARGV[0], $dbpath, 'GTAGS', ("-e 's!\\./!$down/$up/!'"));
+ last if ($cnt > 0);
+ }
+}
+exit(0);
+#
+# common: extract a common part of two paths.
+#
+# i) $p1, $p2 paths
+# r) common part
+#
+sub common {
+ local($p1, $p2) = @_;
+ local(@p1, @p2, @common, $common);
+
+ @p1 = split('/', $p1);
+ @p2 = split('/', $p2);
+ while (@p1 && @p2 && $p1[0] eq $p2[0]) {
+ push(@common, shift @p1);
+ shift @p2;
+ }
+ $common = join('/', @common);
+ $common .= '/';
+ $common;
+}
+#
+# search: search specified function
+#
+# i) $pattern search pattern
+# i) $dbpath where GTAGS exist
+# i) $gtagsname gtags name (GTAGS or GRTAGS)
+# i) @com sed's command
+# gi) $xflag -x option
+# gi) $rflag -r option
+# gi) $regex regular expression
+# r) count of output lines
+#
+sub search {
+ local($pattern, $dbpath, $gtagsname, @com) = @_;
+ local($cnt);
+ #
+ # make input filter
+ #
+ if ($regex) { # regular expression
+ $infilter = "btreeop $dbpath/$gtagsname |";
+ } else {
+ $infilter = "btreeop -K '$pattern' $dbpath/$gtagsname |";
+ }
+ #
+ # make output filter
+ # gtags fields is same to ctags -x format.
+ # 0:tag, 1:lineno, 2:filename, 3: pattern.
+ #
+ if ($xflag) {
+ $outfilter = "| sort +0b -1 +2b -3 +1n -2";
+ } else {
+ $outfilter = "| awk '{print \$3}' | sort | uniq";
+ }
+ #
+ # if absolute path needed
+ #
+ if ($aflag) {
+ @com = ("-e 's!\\.!$dbpath!'");
+ }
+ $outfilter .= "| sed @com";
+ open(PIPEIN, $infilter) || die("$com: database not found.\n");
+ open(PIPEOUT, $outfilter) || die("$com: pipe cannot open.\n");
+ $cnt = 0;
+ while (<PIPEIN>) {
+ ($tag) = split;
+ if (! $regex || $tag =~ /$pattern/o) {
+ $cnt++;
+ print PIPEOUT $_;
+ }
+ }
+ close(PIPEIN);
+ close(PIPEOUT);
+ $cnt;
+}
diff --git a/usr.bin/global/gtags/Makefile b/usr.bin/global/gtags/Makefile
new file mode 100644
index 0000000..cabb890
--- /dev/null
+++ b/usr.bin/global/gtags/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.0 (Berkeley) 4/21/96
+
+MAN1= gtags.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/gtags.sh ${DESTDIR}/usr/bin/gtags
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/gtags/gtags.1 b/usr.bin/global/gtags/gtags.1
new file mode 100644
index 0000000..c7fddf0
--- /dev/null
+++ b/usr.bin/global/gtags/gtags.1
@@ -0,0 +1,86 @@
+.\"
+.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Shigio Yamaguchi.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 21, 1997
+.Dt GTAGS 1
+.Os BSD 4
+.Sh NAME
+.Nm gtags
+.Nd create GTAGS, GRTAGS file
+.Sh SYNOPSIS
+.Nm gtags
+.Op Fl e
+.Op Fl s
+.Op Ar dbpath
+.Sh DESCRIPTION
+.Nm Gtags
+makes GTAGS, GRTAGS files for global(1).
+.Nm Gtags
+trace subdirectories, read source files,
+locate the functions and save the information into tag files.
+C, yacc and assembler source files are supported.
+You should execute this command at the root of the source tree.
+.Pp
+If your source directory is on a read only device like CDROM, specify
+.Ar dbpath
+of the directory on which make tags files.
+.Pp
+.Bl -tag -width Ds
+.It Fl e
+force a function to end when reach a '}' at the first column in C source file.
+.It Fl s
+treat assembler source file (*.s, *.S).
+.Sh FILES
+.Bl -tag -width tags -compact
+.It Pa GTAGS
+tags file for function definitions.
+.It Pa GRTAGS
+tags file for function references.
+.El
+.Sh DIAGNOSTICS
+.Nm Gtags
+exits with a value of 1 if an error occurred, 0 otherwise.
+.Sh SEE ALSO
+.Xr btreeop 1 ,
+.Xr gctags 1 ,
+.Xr global 1 ,
+.Xr htags 1 .
+.Sh BUG
+GTAGS, GRTAGS are very large. In advance, check the space of your disk.
+
+Assembler support is far from completeness. It extracts only ENTRY()
+and ALTENTRY() from source file. Probably valid only for FreeBSD and Linux
+kernel source.
+.Sh AUTHORS
+Shigio Yamaguchi (shigio@wafu.netgate.net)
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.2.
diff --git a/usr.bin/global/gtags/gtags.sh b/usr.bin/global/gtags/gtags.sh
new file mode 100644
index 0000000..79f19bc
--- /dev/null
+++ b/usr.bin/global/gtags/gtags.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Shigio Yamaguchi.
+# 4. Neither the name of the author nor the names of any co-contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# gtags.sh 21-Apr-97
+#
+com=`echo $0 | sed 's/.*\///'` # command name
+usage="usage: $com [-e][-s][dbpath]"
+#
+# ctags flag
+#
+eflag=
+sflag=
+while :; do
+ case $1 in
+ -*)
+ if echo $1 | grep '[^-es]' >/dev/null; then
+ echo $usage >/dev/tty; exit 1
+ fi
+ case $1 in
+ -*e*) eflag=e;;
+ esac
+ case $1 in
+ -*s*) sflag=1;;
+ esac
+ shift;;
+ *)
+ break;;
+ esac
+done
+export eflag sflag
+case $1 in
+"") dbpath=".";;
+*) dbpath=$1;;
+esac
+if [ -f $dbpath/GTAGS -a -f $dbpath/GRTAGS ]; then
+ if [ ! -w $dbpath/GTAGS ]; then
+ echo "$com: cannot write to GTAGS."
+ exit 1
+ elif [ ! -w $dbpath/GRTAGS ]; then
+ echo "$com: cannot write to GRTAGS."
+ exit 1
+ fi
+elif [ ! -w $dbpath ]; then
+ echo "$com: cannot write to the directory $dbpath."
+ exit 1
+fi
+#
+# make global database
+#
+for db in GTAGS GRTAGS; do
+ # currently only *.c *.h *.y are supported.
+ # *.s *.S is valid only when -s option specified.
+ find . -type f -name "*.[chysS]" -print | while read f; do
+ case $f in
+ *y.tab.c|*y.tab.h)
+ continue;;
+ *.s|*.S)
+ [ ${sflag}x = x -o $db = GRTAGS ] && continue
+ perl -ne '($nouse, $tag) = /^(ENTRY|ALTENTRY)\((\w+)\)/;
+ if ($tag) {printf("%-16s%4d %-16s %s", $tag, $., $ARGV, $_)} ' $f
+ continue;;
+ esac
+ case $db in
+ GRTAGS) flag=${eflag}Dxr;;
+ GTAGS) flag=${eflag}Dx;;
+ esac
+ GTAGDBPATH=$dbpath gctags -$flag $f || exit 1
+ done | btreeop -C $dbpath/$db
+done
+exit 0
diff --git a/usr.bin/global/htags/Makefile b/usr.bin/global/htags/Makefile
new file mode 100644
index 0000000..f53639a
--- /dev/null
+++ b/usr.bin/global/htags/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.0 (Berkeley) 4/21/96
+
+MAN1= htags.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/htags.pl ${DESTDIR}/usr/bin/htags
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/htags/htags.1 b/usr.bin/global/htags/htags.1
new file mode 100644
index 0000000..a887e47
--- /dev/null
+++ b/usr.bin/global/htags/htags.1
@@ -0,0 +1,117 @@
+.\"
+.\" Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Shigio Yamaguchi.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 21, 1997
+.Dt HTAGS 1
+.Os BSD 4
+.Sh NAME
+.Nm htags
+.Nd generate hypertext from C and Yacc source code
+.Sh SYNOPSIS
+.Nm htags
+.Op Fl a
+.Op Fl l
+.Op Fl v
+.Op Fl w
+.Op Fl d Ar tagdir
+.Op Fl t Ar title
+.Op Ar dir
+.Sh DESCRIPTION
+.Nm Htags
+makes hypertext from C and Yacc source code using GLOBAL database (GTAGS, GRTAGS).
+.Pp
+In advance of using this command, you must execute
+.Xr gtags 1
+at the root directory of the source tree.
+Then you can execute
+.Nm htags
+at the same place.
+.Nm Htags
+makes HTML directory and generate hypertext in it.
+.Pp
+You can start browsing from 'HTML/index.html'.
+Once hypertext generated, you can move it anywhere and browse it
+by any browsers.
+.Pp
+.br
+.Bl -tag -width Ds
+.It Fl a
+make an alphabetical function index. It's suitable for large project.
+.It Fl l
+make name tag(<A NAME=lno>) for each line so that outer hypertext
+can point any line of this hypertext.
+By default, make it only for lines which have referred object.
+.It Fl v
+verbose mode.
+.It Fl w
+print warning message.
+.It Fl d Ar tagdir
+the directory in which GTAGS and GRTAGS exist. Default is current directory.
+.It Fl t Ar title
+Tile of this hypertext. Default is the last conponent of current path.
+.It Ar dir
+the directory in which hypertext generated. Default is current directory.
+.Sh EXAMPLES
+ % cd /usr/src/sys
+ # gtags -se
+ # htags -vat 'Welcom to FreeBSD kernel source tour!'
+ % lynx HTML/index.html
+.Sh FILES
+.Bl -tag -width tags -compact
+.It Pa HTML/index.html
+Index file.
+.It Pa GTAGS
+tags file for function definitions.
+.It Pa GRTAGS
+tags file for function references.
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of htags.
+.Pp
+.Bl -tag -width indent
+.It Ev TMPDIR
+If this variable is set, its value is used as the directory to make temporary file.
+Default is /tmp.
+.Sh DIAGNOSTICS
+.Nm Htags
+exits with a value of 1 if an error occurred, 0 otherwise.
+.Sh SEE ALSO
+.Xr btreeop 1 ,
+.Xr gctags 1 ,
+.Xr global 1 ,
+.Xr gtags 1 .
+.Sh BUG
+Generated hypertext is VERY LARGE. In advance, check the space of your disk.
+.Sh AUTHORS
+Shigio Yamaguchi (shigio@wafu.netgate.net)
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.2.
diff --git a/usr.bin/global/htags/htags.pl b/usr.bin/global/htags/htags.pl
new file mode 100755
index 0000000..377a41c
--- /dev/null
+++ b/usr.bin/global/htags/htags.pl
@@ -0,0 +1,1082 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1996, 1997 Shigio Yamaguchi. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Shigio Yamaguchi.
+# 4. Neither the name of the author nor the names of any co-contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# htags.pl 21-Apr-97
+#
+$com = $0;
+$com =~ s/.*\///;
+$usage = "usage: $com [-a][-l][-v][-w][-t title][-d tagdir][dir]";
+#-------------------------------------------------------------------------
+# CONFIGURATION
+#-------------------------------------------------------------------------
+# columns of line number
+$ncol = 4;
+# font
+$comment_begin = '<I><FONT COLOR=green>'; # /* ... */
+$comment_end = '</FONT></I>';
+$sharp_begin = '<FONT COLOR=darkred>'; # #define, #include or so on
+$sharp_end = '</FONT>';
+$brace_begin = '<FONT COLOR=blue>'; # { ... }
+$brace_end = '</FONT>';
+$reserved_begin = '<B>'; # if, while, for or so on
+$reserved_end = '</B>';
+# reserved words
+$reserved_words = "auto|break|case|char|continue|default|do|double|else|extern|float|for|goto|if|int|long|register|return|short|sizeof|static|struct|switch|typedef|union|unsigned|void|while";
+# temporary directory
+$tmp = '/tmp';
+if (defined($ENV{'TMPDIR'}) && -d $ENV{'TMPDIR'}) {
+ $tmp = $ENV{'TMPDIR'};
+}
+#-------------------------------------------------------------------------
+# DEFINITION
+#-------------------------------------------------------------------------
+# unit for a path
+$SEP = ' '; # source file path must not include $SEP charactor
+$ESCSEP = &escape($SEP);
+$SRCS = 'S';
+$DEFS = 'D';
+$REFS = 'R';
+$FILES = 'files';
+$FUNCS = 'funcs';
+#-------------------------------------------------------------------------
+# JAVASCRIPT PARTS
+#-------------------------------------------------------------------------
+# escaped angle
+$langle = sprintf("unescape('%s')", &escape('<'));
+$rangle = sprintf("unescape('%s')", &escape('>'));
+# frame name
+$f_mains = 'mains'; # for main view
+$f_funcs = 'funcs'; # for function index
+$f_files = 'files'; # for file index
+$begin_script="<SCRIPT LANGUAGE=javascript>\n<!--\n";
+$end_script="<!-- end of script -->\n</SCRIPT>\n";
+$defaultview=
+ "// if your browser doesn't support javascript, write a BASE tag statically.\n" .
+ "if (parent.frames.length)\n" .
+ " document.write($langle+'BASE TARGET=$f_mains'+$rangle)\n";
+$rewrite_href_funcs =
+ "// IE3.0 seems to be not able to treat following code.\n" .
+ "if (parent.frames.length && parent.$f_funcs == self) {\n" .
+ " document.links[0].href = '../funcs.html';\n" .
+ " document.links[document.links.length - 1].href = '../funcs.html';\n" .
+ "}\n";
+$rewrite_href_files =
+ "// IE3.0 seems to be not able to treat following code.\n" .
+ "if (parent.frames.length && parent.$f_files == self) {\n" .
+ " document.links[0].href = '../files.html';\n" .
+ " document.links[document.links.length - 1].href = '../files.html';\n" .
+ "}\n";
+#-------------------------------------------------------------------------
+# UTIRITIES
+#-------------------------------------------------------------------------
+sub getcwd {
+ local($dir) = `/bin/pwd`;
+ chop($dir);
+ $dir;
+}
+sub date {
+ local($date) = `date`;
+ chop($date);
+ $date;
+}
+sub error {
+ local($msg) = @_;
+ &clean();
+ die($msg);
+}
+sub clean {
+ &anchor'finish();
+ &cache'close();
+}
+sub escape {
+ local($c) = @_;
+ '%' . sprintf("%x", ord($c));
+}
+sub usable {
+ local($com) = @_;
+
+ foreach $path (split(/:/, $ENV{'PATH'})) {
+ if (-x "$path/$com") {
+ return 1;
+ }
+ }
+ return 0;
+}
+#-------------------------------------------------------------------------
+# PROCESS START
+#-------------------------------------------------------------------------
+#
+# options check
+#
+$aflag = $lflag = $vflag = $wflag = $sflag = '';# $sflag is set internally
+while ($ARGV[0] =~ /^-/) {
+ $opt = shift;
+ if ($opt =~ /[^-alvwtd]/) {
+ print STDERR "$usage\n";
+ exit 1;
+ }
+ if ($opt =~ /a/) { $aflag = 1; }
+ if ($opt =~ /l/) { $lflag = 1; }
+ if ($opt =~ /v/) { $vflag = 1; }
+ if ($opt =~ /w/) { $wflag = 1; }
+ if ($opt =~ /t/) {
+ $opt = shift;
+ last if ($opt eq '');
+ $title = $opt;
+ } elsif ($opt =~ /d/) {
+ $opt = shift;
+ last if ($opt eq '');
+ $dbpath = $opt;
+ }
+}
+if (!$title) {
+ @cwd = split('/', &getcwd);
+ $title = $cwd[$#cwd];
+}
+if (!$dbpath) {
+ $dbpath = '.';
+}
+unless (-r "$dbpath/GTAGS" && -r "$dbpath/GRTAGS") {
+ &error("GTAGS and GRTAGS not found. please type 'gtags[RET]'\n");
+}
+#
+# recognize format version
+# if version record is not found, it's assumed version 1.
+#
+ $support_version = 1; # understand this format version
+#
+open(GTAGS, "btreeop -K ' __.VERSION' $dbpath/GTAGS |") || die("$com: GTAGS not found.\n");
+$rec = <GTAGS>;
+close(GTAGS);
+if ($rec =~ /^ __\.VERSION[ \t]+([0-9]+)$/) {
+ $format_version = $1;
+} else {
+ $format_version = 1;
+}
+if ($format_version != $support_version) {
+ die("$com: GTAGS format version unmatched. Please remake it.\n");
+}
+#
+# check directories
+#
+$html = &getcwd() . '/HTML';
+if ($ARGV[0]) {
+ $cwd = &getcwd();
+ unless (-w $ARGV[0]) {
+ &error("$ARGV[0] is not writable directory.\n");
+ }
+ chdir($ARGV[0]) || &error("directory $ARGV[0] not found.\n");
+ $html = &getcwd() . '/HTML';
+ chdir($cwd) || &error("cannot return directory.\n");
+}
+#
+# set sflag if *.[sS] are included.
+#
+open(CHECK, "btreeop $dbpath/GTAGS |") || &error("btreeop $dbpath/GTAGS failed.\n");
+while (<CHECK>) {
+ local($tag, $lno, $filename) = split;
+ if ($filename =~ /\.[sS]$/) {
+ $'sflag = 1;
+ last;
+ }
+}
+close(CHECK);
+#-------------------------------------------------------------------------
+# MAKE FILES
+#-------------------------------------------------------------------------
+# HTML/help.html ... help file (2)
+# HTML/funcs.html ... function index (3)
+# HTML/$FUNCS/* ... function index (3)
+# HTML/$REFS/* ... referencies (4)
+# HTML/$DEFS/* ... definitions (4)
+# HTML/files.html ... file index (5)
+# HTML/$FILES/* ... file index (5)
+# HTML/index.html ... index file (6)
+# HTML/mains.html ... main index (7)
+# HTML/$SRCS/ ... source files (8)
+#-------------------------------------------------------------------------
+print STDERR "[", &date, "] ", "Htags started\n" if ($vflag);
+#
+# (1) make directories
+#
+print STDERR "[", &date, "] ", "(1) making directories ...\n" if ($vflag);
+mkdir($html, 0777) || &error("cannot make directory <$html>.\n") if (! -d $html);
+foreach $d ($SRCS, $REFS, $DEFS, $FILES, $FUNCS) {
+ mkdir("$html/$d", 0775) || &error("cannot make HTML directory\n") if (! -d "$html/$d");
+}
+#
+# (2) make help file
+#
+print STDERR "[", &date, "] ", "(2) making help.html ...\n" if ($vflag);
+&makehelp("$html/help.html");
+#
+# (3) make function index (funcs.html and $FUNCS/*)
+# PRODUCE @funcs
+#
+print STDERR "[", &date, "] ", "(3) making function index ...\n" if ($vflag);
+$func_total = &makefuncindex("$html/funcs.html");
+print STDERR "Total $func_total functions.\n" if ($vflag);
+#
+# (4) make function entries ($DEFS/* and $REFS/*)
+# MAKING TAG CACHE
+#
+print STDERR "[", &date, "] ", "(4) making duplicate entries ...\n" if ($vflag);
+sub suddenly { &clean(); exit 1}
+$SIG{'INT'} = 'suddenly';
+$SIG{'QUIT'} = 'suddenly';
+$SIG{'TERM'} = 'suddenly';
+&cache'open(100000);
+$func_total = &makedupindex($func_total);
+print STDERR "Total $func_total functions.\n" if ($vflag);
+#
+# (5) make file index (files.html and $FILES/*)
+# PRODUCE @files
+#
+print STDERR "[", &date, "] ", "(5) making file index ...\n" if ($vflag);
+$file_total = &makefileindex("$html/files.html");
+print STDERR "Total $file_total files.\n" if ($vflag);
+#
+# [#] make a common part for mains.html and index.html
+# USING @funcs @files
+#
+print STDERR "[", &date, "] ", "(#) making a common part ...\n" if ($vflag);
+$index = &makecommonpart($title);
+#
+# (6)make index file (index.html)
+#
+print STDERR "[", &date, "] ", "(6) making index file ...\n" if ($vflag);
+&makeindex("$html/index.html", $title, $index);
+#
+# (7) make main index (mains.html)
+#
+print STDERR "[", &date, "] ", "(7) making main index ...\n" if ($vflag);
+&makemainindex("$html/mains.html", $index);
+#
+# (#) make anchor database
+#
+print STDERR "[", &date, "] ", "(#) making temporary database ...\n" if ($vflag);
+&anchor'create();
+#
+# (8) make HTML files ($SRCS/*)
+# USING TAG CACHE
+#
+print STDERR "[", &date, "] ", "(8) making hypertext from source code ...\n" if ($vflag);
+&makehtml($file_total);
+&clean();
+print STDERR "[", &date, "] ", "Done.\n" if ($vflag);
+exit 0;
+#-------------------------------------------------------------------------
+# SUBROUTINES
+#-------------------------------------------------------------------------
+#
+# makehelp: make help file
+#
+sub makehelp {
+ local($file) = @_;
+
+ open(HELP, ">$file") || &error("cannot make help file.\n");
+ print HELP "<HTML>\n<HEAD><TITLE>HELP</TITLE></HEAD>\n<BODY>\n";
+ print HELP "<H2>Usage of Links</H2>\n";
+ print HELP "<PRE>/* [&lt;][&gt;][^][v] [top][bottom][index][help] */</PRE>\n";
+ print HELP "<DL>\n";
+ print HELP "<DT>[&lt;]<DD>Previous function.\n";
+ print HELP "<DT>[&gt;]<DD>Next function.\n";
+ print HELP "<DT>[^]<DD>First function in this file.\n";
+ print HELP "<DT>[v]<DD>Last function in this file.\n";
+ print HELP "<DT>[top]<DD>Top of this file.\n";
+ print HELP "<DT>[bottom]<DD>Bottom of this file.\n";
+ print HELP "<DT>[index]<DD>Return to index page (mains.html).\n";
+ print HELP "<DT>[help]<DD>You are seeing now.\n";
+ print HELP "</DL>\n";
+ print HELP "</BODY>\n</HTML>\n";
+ close(HELP);
+}
+#
+# makefuncindex: make function index (including alphabetic index)
+#
+# i) file function index file
+# go) @funcs
+#
+sub makefuncindex {
+ local($file) = @_;
+ local($count) = 0;
+
+ open(FUNCTIONS, ">$file") || &error("cannot make function index <$file>.\n");
+ print FUNCTIONS "<HTML>\n<HEAD><TITLE>FUNCTION INDEX</TITLE>\n";
+ print FUNCTIONS "$begin_script$defaultview$end_script</HEAD>\n<BODY>\n";
+ print FUNCTIONS "<H2>FUNCTION INDEX</H2>\n";
+ print FUNCTIONS "<OL>\n" if (!$aflag);
+ local($old) = select(FUNCTIONS);
+ open(TAGS, "btreeop $dbpath/GTAGS | awk '{print \$1}' | sort | uniq |") || &error("btreeop $dbpath/GTAGS failed.\n");
+ local($alpha) = '';
+ @funcs = (); # [A][B][C]...
+ while (<TAGS>) {
+ $count++;
+ chop;
+ local($tag) = $_;
+ print STDERR " [$count] adding $tag\n" if ($vflag);
+ if ($aflag && $alpha ne substr($tag, 0, 1)) {
+ if ($alpha) {
+ print ALPHA "</OL>\n";
+ print ALPHA "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print ALPHA "$begin_script$rewrite_href_funcs$end_script";
+ print ALPHA "</BODY>\n</HTML>\n";
+ close(ALPHA);
+ }
+ $alpha = substr($tag, 0, 1);
+ push(@funcs, "<A HREF=$FUNCS/$alpha.html TARGET=_self>[$alpha]</A>\n");
+ open(ALPHA, ">$html/$FUNCS/$alpha.html") || &error("cannot make alphabetical function index.\n");
+ print ALPHA "<HTML>\n<HEAD><TITLE>$alpha</TITLE>\n";
+ print ALPHA "$begin_script$defaultview$end_script";
+ print ALPHA "</HEAD>\n<BODY>\n<H2>[$alpha]</H2>\n";
+ print ALPHA "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print ALPHA "<OL>\n";
+ select(ALPHA);
+ }
+ open(LIST, "btreeop -K $tag $dbpath/GTAGS |") || &error("btreeop -K $tag $dbpath/GTAGS failed.\n");;
+ local($line1, $line2);
+ if ($line1 = <LIST>) {
+ $line2 = <LIST>;
+ }
+ close(LIST);
+ if ($line2) {
+ print "<LI><A HREF=", ($aflag) ? "../" : "", "D/$tag.html>$tag</A>\n";
+ } else {
+ local($nouse, $lno, $filename) = split(/[ \t]+/, $line1);
+ $nouse = ''; # to make perl quiet
+ $filename =~ s/^\.\///;
+ $filename =~ s/\//$ESCSEP/g;
+ print "<LI><A HREF=", ($aflag) ? "../" : "", "$SRCS/$filename.html#$lno>$tag</A>\n";
+ }
+ close(LIST);
+ }
+ close(TAGS);
+ select($old);
+ if ($aflag) {
+ print ALPHA "</OL>\n";
+ print ALPHA "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print ALPHA "$begin_script$rewrite_href_funcs$end_script";
+ print ALPHA "</BODY>\n</HTML>\n";
+ close(ALPHA);
+
+ print FUNCTIONS @funcs;
+ }
+ print FUNCTIONS "</OL>\n" if (!$aflag);
+ print FUNCTIONS "</BODY>\n</HTML>\n";
+ close(FUNCTIONS);
+ $count;
+}
+#
+# makedupindex: make duplicate entries index ($DEFS/* and $REFS/*)
+#
+# i) $total functions total
+# r) $count
+#
+sub makedupindex {
+ local($total) = @_;
+ local($count) = 0;
+
+ open(TAGS, "btreeop $dbpath/GTAGS | awk '{print \$1}' | sort | uniq |") || &error("btreeop $dbpath/GTAGS failed.\n");
+ while (<TAGS>) {
+ $count++;
+ chop;
+ local($tag) = $_;
+ print STDERR " [$count/$total] adding $tag\n" if ($vflag);
+ foreach $db ('GTAGS', 'GRTAGS') {
+ open(LIST, "btreeop -K $tag $dbpath/$db | sort +0b -1 +2b -3 +1n -2|") || &error("btreeop -K $tag $dbpath/$db failed.\n");;
+ local($line1, $line2);
+ if ($line1 = <LIST>) {
+ $line2 = <LIST>;
+ }
+ &cache'put($db, $tag, ($line2) ? '' : $line1) if ($line1);
+ if ($line2) { # two or more entries exist
+ local($type) = ($db eq 'GTAGS') ? $'DEFS : $'REFS;
+ open(FILE, ">$html/$type/$tag.html") || &error("cannot make file <$html/$type/$tag.html>.\n");
+ print FILE "<HTML>\n<HEAD><TITLE>$tag</TITLE></HEAD>\n<BODY>\n";
+ print FILE "<PRE>\n";
+ for (;;) {
+ if ($line1) {
+ $_ = $line1;
+ $line1 = '';
+ } elsif ($line2) {
+ $_ = $line2;
+ $line2 = '';
+ } elsif (!($_ = <LIST>)) {
+ last;
+ }
+ s/\.\///;
+ s/&/&amp;/g;
+ s/</&lt;/g;
+ s/>/&gt;/g;
+ local($nouse, $lno, $filename) = split;
+ $nouse = ''; # to make perl quiet
+ $filename =~ s/\//$ESCSEP/g;
+ s/^$tag/<A HREF=..\/$SRCS\/$filename.html#$lno>$tag<\/A>/;
+ print FILE;
+ }
+ print FILE "</PRE>\n</BODY>\n</HTML>\n";
+ close(FILE);
+ }
+ close(LIST);
+ }
+ }
+ close(TAGS);
+ $count;
+}
+#
+# makefileindex: make file index
+#
+# i) file name
+# go) @files
+#
+sub makefileindex {
+ local($file) = @_;
+ local($count) = 0;
+
+ open(FILES, ">$file") || &error("cannot make file <$file>.\n");
+ print FILES "<HTML>\n<HEAD><TITLE>FILES</TITLE>\n";
+ print FILES "$begin_script$defaultview$end_script";
+ print FILES "</HEAD>\n<BODY>\n<H2>FILE INDEX</H2>\n";
+ print FILES "<OL>\n";
+ local($old) = select(FILES);
+ open(FIND, "find . -name '*.[chysS]' -print | sort |") || &error("cannot exec find.\n");
+ local($lastdir) = '';
+ @files = ();
+ while (<FIND>) {
+ $count++;
+ chop;
+ s/^\.\///;
+ next if /(y\.tab\.c|y\.tab\.h)$/;
+ next if (!$'sflag && /\.[sS]$/);
+ local($filename) = $_;
+ print STDERR " [$count] adding $filename\n" if ($vflag);
+ local($dir);
+ if (index($filename, '/') >= 0) {
+ @split = split('/');
+ $dir = $split[0];
+ } else {
+ $dir = '';
+ }
+ #if ($dir && $dir ne $lastdir) {
+ if ($dir ne $lastdir) {
+ if ($lastdir) {
+ print DIR "</OL>\n";
+ print DIR "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print DIR "$begin_script$rewrite_href_files$end_script";
+ print DIR "</BODY>\n</HTML>\n";
+ close(DIR);
+ }
+ if ($dir) {
+ push(@files, "<LI><A HREF=$FILES/$dir.html TARGET=_self>$dir/</A>\n");
+ open(DIR, ">$html/$FILES/$dir.html") || &error("cannot make directory index.\n");
+ print DIR "<HTML>\n<HEAD><TITLE>$dir/</TITLE>\n";
+ print DIR "$begin_script$defaultview$end_script";
+ print DIR "</HEAD>\n<BODY>\n<H2>$dir/</H2>\n";
+ print DIR "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print DIR "<OL>\n";
+ }
+ $lastdir = $dir;
+ }
+ local($path) = $filename;
+ $path =~ s/\//$ESCSEP/g;
+ if ($dir eq '') {
+ push(@files, "<LI><A HREF=", ($dir) ? "../" : "", "$SRCS/$path.html>$filename</A>\n");
+ } else {
+ print DIR "<LI><A HREF=../$SRCS/$path.html>$filename</A>\n";
+ }
+ }
+ close(FIND);
+ select($old);
+ if ($lastdir) {
+ print DIR "</OL>\n";
+ print DIR "<A HREF=../mains.html TARGET=_self>[index]</A>\n";
+ print DIR "$begin_script$rewrite_href_files$end_script";
+ print DIR "</BODY>\n</HTML>\n";
+ close(DIR);
+ }
+ print FILES @files;
+ print FILES "</OL>\n";
+ print FILES "</BODY>\n</HTML>\n";
+ close(FILES);
+
+ $count;
+}
+#
+# makecommonpart: make a common part for mains.html and index.html
+#
+# gi) @files
+# gi) @funcs
+#
+sub makecommonpart {
+ local($title) = @_;
+ local($index) = '';
+
+ $index .= "<H1><FONT COLOR=#cc0000>$title</FONT></H1>\n";
+ $index .= "<P ALIGN=right>";
+ $index .= "Last updated " . &date . "<BR>\n";
+ $index .= "This hypertext was generated by <A HREF=http://wafu.netgate.net/tama/unix/indexe.html#global TARGET=_top>GLOBAL</A>.<BR>\n";
+ $index .= "$begin_script";
+ $index .= "if (parent.frames.length && parent.$f_mains == self)\n";
+ $index .= " document.write($langle+'A HREF=mains.html TARGET=_top'+$rangle+'[No frame version is here.]'+$langle+'/A'+$rangle)\n";
+ $index .= "$end_script";
+ $index .= "</P>\n<HR>\n";
+ $index .= "<H2>MAINS</H2>\n";
+ $index .= "<PRE>\n";
+ open(PIPE, "btreeop -K main $dbpath/GTAGS | sort +0b -1 +2b -3 +1n -2 |") || &error("btreeop -K main $dbpath/GTAGS failed.\n");
+ while (<PIPE>) {
+ local($nouse, $lno, $filename) = split;
+ $nouse = ''; # to make perl quiet
+ $filename =~ s/^\.\///;
+ $filename =~ s/\//$ESCSEP/g;
+ s/(main)/<A HREF=$SRCS\/$filename.html#$lno>$1<\/A>/;
+ $index .= $_;
+ }
+ close(PIPE);
+ $index .= "</PRE>\n<HR>\n<H2>FUNCTIONS</H2>\n";
+ if ($aflag) {
+ foreach $f (@funcs) {
+ $index .= $f;
+ }
+ } else {
+ $index .= "<PRE><A HREF=funcs.html>function index</A></PRE>\n";
+ }
+ $index .= "<HR>\n<H2>FILES</H2>\n";
+ $index .= "<OL>\n";
+ foreach $f (@files) {
+ $index .= $f;
+ }
+ $index .= "</OL>\n<HR>\n";
+ $index;
+}
+#
+# makeindex: make index file
+#
+# i) $file file name
+# i) $title title of index file
+# i) $index common part
+#
+sub makeindex {
+ local($file, $title, $index) = @_;
+
+ open(FRAME, ">$file") || &error("cannot open file <$file>.\n");
+ print FRAME "<HTML>\n<HEAD><TITLE>$title</TITLE></HEAD>\n";
+ print FRAME "<FRAMESET COLS='200,*'>\n";
+ print FRAME "<NOFRAME>\n$index</NOFRAME>\n";
+ print FRAME "<FRAMESET ROWS='50%,50%'>\n";
+ print FRAME "<FRAME NAME=$f_funcs SRC=funcs.html>\n";
+ print FRAME "<FRAME NAME=$f_files SRC=files.html>\n";
+ print FRAME "</FRAMESET>\n";
+ print FRAME "<FRAME NAME=$f_mains SRC=mains.html>\n";
+ print FRAME "</FRAMESET>\n";
+ print FRAME "</HTML>\n";
+ close(FRAME);
+}
+#
+# makemainindex: make main index
+#
+# i) $file file name
+# i) $index common part
+#
+sub makemainindex {
+ local($file, $index) = @_;
+
+ open(INDEX, ">$file") || &error("cannot create file <$file>.\n");
+ print INDEX "<HTML>\n<HEAD><TITLE>MAINS</TITLE></HEAD>\n";
+ print INDEX "<BODY>\n$index</BODY>\n</HTML>\n";
+ close(INDEX);
+}
+#
+# makehtml: make html files
+#
+sub makehtml {
+ local($total) = @_;
+ local($count) = 0;
+
+ open(FIND, "find . -name '*.[chysS]' -print|") || &error("cannot exec find.\n");
+ while (<FIND>) {
+ $count++;
+ chop;
+ s/^\.\///;
+ next if /y\.tab\.c|y\.tab\.h/;
+ next if (!$'sflag && /\.[sS]$/);
+ local($path) = $_;
+ $path =~ s/\//$SEP/g;
+ print STDERR " [$count/$total] converting $_\n" if ($vflag);
+ &convert'src2html($_, "$html/$SRCS/$path.html");
+ }
+ close(FIND);
+}
+#=========================================================================
+# CONVERT PACKAGE
+#=========================================================================
+package convert;
+#
+# src2html: convert source code into HTML
+#
+# i) $file source file - Read from
+# i) $html HTML file - Write to
+#
+sub src2html {
+ local($file, $html) = @_;
+ local($ncol) = $'ncol;
+ local($expand) = &'usable('expand') ? 'expand' : 'cat';
+
+ open(HTML, ">$html") || &'error("cannot create file <$html>.\n");
+ local($old) = select(HTML);
+ #
+ # load tags belonging to this file.
+ #
+ $file =~ s/^\.\///;
+ &anchor'load($file);
+ open(C, "$expand '$file' |") || &'error("cannot open file <$file>.\n");
+ #
+ # print the header
+ #
+ print "<HTML>\n<HEAD><TITLE>$file</TITLE></HEAD>\n";
+ print "<BODY><A NAME=TOP><H2>$file</H2>\n";
+ print &link_format(&anchor'getlinks(0));
+ print "\n<HR>\n";
+ print "<H2>FUNCTIONS</H2>\n";
+ print "This source file includes following functions.\n";
+ print "<OL>\n";
+ local($lno, $tag, $type);
+ for (($lno, $tag, $type) = &anchor'first(); $lno; ($lno, $tag, $type) = &anchor'next()) {
+ print "<LI><A HREF=#$lno>$tag</A>\n" if ($type eq 'D');
+ }
+ print "</OL>\n";
+ print "<HR>\n";
+ #
+ # print source code
+ #
+ print "<PRE>\n";
+ $INCOMMENT = 0; # initial status is out of comment
+ local($LNO, $TAG, $TYPE) = &anchor'first();
+ while (<C>) {
+ s/\r$//;
+ s/&/&amp;/g; # '<', '>' and '&' are used for HTML tag
+ s/</&lt;/g;
+ s/>/&gt;/g;
+ &protect_line(); # protect quoted char, strings and comments
+ # painting source code
+ s/({|})/$'brace_begin$1$'brace_end/g;
+ $sharp = s/^(#\w+)// ? $1 : ''; # protect macro
+ s/\b($'reserved_words)\b/$'reserved_begin$1$'reserved_end/go if ($sharp ne '#include');
+ s/^/$'sharp_begin$sharp$'sharp_end/ if ($sharp); # recover macro
+
+ local($define_line) = 0;
+ local(@links) = ();
+ local($count) = 0;
+ local($lno_printed) = 0;
+
+ if ($'lflag) {
+ print "<A NAME=$.>";
+ $lno_printed = 1;
+ }
+ for (; int($LNO) == $.; ($LNO, $TAG, $TYPE) = &anchor'next()) {
+ if (!$lno_printed) {
+ print "<A NAME=$.>";
+ $lno_printed = 1;
+ }
+ $define_line = $LNO if ($TYPE eq 'D');
+ $db = ($TYPE eq 'D') ? 'GRTAGS' : 'GTAGS';
+ local($line) = &cache'get($db, $TAG);
+ if (defined($line)) {
+ local($href, $dir);
+ if ($line) {
+ local($nouse, $lno, $filename) = split(/[ \t]+/, $line);
+ $nouse = ''; # to make perl quiet
+ $filename =~ s/^\.\///;
+ $filename =~ s/\//$'ESCSEP/g;
+ $href = "<A HREF=../$'SRCS/$filename.html#$lno>$TAG</A>";
+ } else {
+ $dir = ($TYPE eq 'D') ? $'REFS : $'DEFS;
+ $href = "<A HREF=../$dir/$TAG.html>$TAG</A>";
+ }
+ # set tag marks and push hyperlink into @links
+ if (s/\b$TAG\b/\005$count\005/) {
+ $count++;
+ push(@links, $href);
+ } else {
+ print STDERR "Error: $file $LNO $TAG($TYPE) tag must exist.\n" if ($'wflag);
+ }
+ } else {
+ print STDERR "Warning: $file $LNO $TAG($TYPE) found but not referred.\n" if ($'wflag);
+ }
+ }
+ # implant links
+ local($s);
+ for ($count = 0; @links; $count++) {
+ $s = shift @links;
+ unless (s/\005$count\005/$s/) {
+ print STDERR "Error: $file $LNO $TAG($TYPE) tag must exist.\n" if ($'wflag);
+ }
+ }
+ &unprotect_line();
+ # print a line
+ printf "%${ncol}d ", $.;
+ print;
+ # print hyperlinks
+ if ($define_line && $file !~ /\.h$/) {
+ print ' ' x ($ncol + 1);
+ print &link_format(&anchor'getlinks($define_line));
+ print "\n";
+ }
+ }
+ print "</PRE>\n";
+ print "<HR>\n";
+ print "<A NAME=BOTTOM>\n";
+ print &link_format(&anchor'getlinks(-1));
+ print "\n";
+ print "</BODY>\n</HTML>\n";
+ close(C);
+ close(HTML);
+ select($old);
+
+}
+#
+# protect_line: protect quoted strings
+#
+# io) $_ source line
+#
+# \001 quoted(\) char
+# \002 quoted('') char
+# \003 quoted string
+# \004 comment
+# \032 temporary mark
+#
+sub protect_line {
+ @quoted_char1 = ();
+ while (/(\\.)/) {
+ push(@quoted_char1, $1);
+ s/\\./\001/;
+ }
+ @quoted_char2 = ();
+ while (/('[^']')/) {
+ push(@quoted_char2, $1);
+ s/'[^']'/\002/;
+ }
+ @quoted_strings = ();
+ while (/("[^"]*")/) {
+ push(@quoted_strings, $1);
+ s/"[^"]*"/\003/;
+ }
+ @comments = ();
+ s/^/\032/ if ($INCOMMENT);
+ while (1) {
+ if ($INCOMMENT == 0) {
+ if (/\/\*/) { # start comment
+ s/\/\*/\032\/\*/;
+ $INCOMMENT = 1;
+ } else {
+ last;
+ }
+ } else {
+ # Thanks to Jeffrey Friedl for his code.
+ if (m!\032(/\*)?[^*]*\*+([^/*][^*]*\*+)*/!) {
+ $INCOMMENT = 0;
+ # minimum matching
+ s!\032((/\*)?[^*]*\*+([^/*][^*]*\*+)*/)!\004!;
+ push(@comments, $1);
+ } else {
+ s/\032(.*)$/\004/; # mark comment
+ push(@comments, $1);
+ }
+ last if ($INCOMMENT);
+ }
+ }
+}
+#
+# unprotect_line: recover quoted strings
+#
+# i) $_ source line
+#
+sub unprotect_line {
+ local($s);
+
+ while (@comments) {
+ $s = shift @comments;
+ s/\004/$'comment_begin$s$'comment_end/;
+ }
+ while (@quoted_strings) {
+ $s = shift @quoted_strings;
+ s/\003/$s/;
+ }
+ while (@quoted_char2) {
+ $s = shift @quoted_char2;
+ s/\002/$s/;
+ }
+ while (@quoted_char1) {
+ $s = shift @quoted_char1;
+ s/\001/$s/;
+ }
+}
+#
+# link_format: format hyperlinks.
+#
+# i) (previous, next, first, last, top, bottom)
+#
+sub link_format {
+ local(@tag) = @_;
+ local(@label) = ('&lt;', '&gt;', '^', 'v', 'top', 'bottom');
+
+ local($line) = "$'comment_begin/* ";
+ while ($label = shift @label) {
+ local($tag) = shift @tag;
+ $line .= "<A HREF=#$tag>" if ($tag);
+ $line .= "[$label]";
+ $line .= "</A>" if ($tag);
+ }
+ $line .= "<A HREF=../mains.html>[index]</A>";
+ $line .= "<A HREF=../help.html>[help]</A>";
+ $line .= " */$'comment_end";
+
+ $line;
+}
+
+#=========================================================================
+# ANCHOR PACKAGE
+#=========================================================================
+package anchor;
+#
+# create: create anchors temporary database
+#
+sub create {
+ $ANCH = "$'tmp/ANCH$$";
+ open(ANCH, "| btreeop -C $ANCH") || &'error("btreeop -C $ANCH failed.\n");
+ foreach $db ('GTAGS', 'GRTAGS') {
+ local($type) = ($db eq 'GTAGS') ? 'D' : 'R';
+ open(PIPE, "btreeop $'dbpath/$db |") || &'error("btreeop $'dbpath/$db failed.\n");
+ while (<PIPE>) {
+ local($tag, $lno, $filename) = split;
+ print ANCH "$filename $lno $tag $type\n";
+ }
+ close(PIPE);
+ }
+ close(ANCH);
+}
+#
+# finish: remove anchors database
+#
+sub finish {
+ unlink("$ANCH") if (defined($ANCH));
+}
+#
+# load: load anchors in a file from database
+#
+# i) $file source file
+#
+sub load {
+ local($file) = @_;
+
+ $file = './' . $file if ($file !~ /^\.\//);
+
+ @ANCHORS = ();
+ open(ANCH, "btreeop -K $file $ANCH|") || &'error("btreeop -K $file $ANCH failed.\n");
+$n = 0;
+ while (<ANCH>) {
+ local($filename, $lno, $tag, $type) = split;
+ local($line);
+ # START for DTFLAG
+ # don't refer to macros which is defined in other C source.
+ if ($type eq 'R' && ($line = &cache'get('GTAGS', $tag))) {
+ local($nouse1, $nouse2, $f, $def) = split(/[ \t]+/, $line);
+ if ($f !~ /\.h$/ && $f !~ $filename && $def =~ /^#/) {
+ print STDERR "Information: $filename $lno $tag($type) skipped, because this is a macro which is defined in other C source.\n" if ($'wflag);
+ next;
+ }
+ }
+ # END for DTFLAG
+ push(@ANCHORS, "$lno,$tag,$type");
+ }
+ close(ANCH);
+ local(@keys);
+ foreach (@ANCHORS) {
+ push(@keys, (split(/,/))[0]);
+ }
+ sub compare { $keys[$a] <=> $keys[$b]; }
+ @ANCHORS = @ANCHORS[sort compare 0 .. $#keys];
+ local($c);
+ for ($c = 0; $c < @ANCHORS; $c++) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$c]);
+ if ($type eq 'D') {
+ $FIRST = $lno;
+ last;
+ }
+ }
+ for ($c = $#ANCHORS; $c >= 0; $c--) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$c]);
+ if ($type eq 'D') {
+ $LAST = $lno;
+ last;
+ }
+ }
+}
+#
+# first: get first anchor
+#
+sub first {
+ $CURRENT = 0;
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$CURRENT]);
+ $CURRENTDEF = $CURRENT if ($type eq 'D');
+
+ ($lno, $tag, $type);
+}
+#
+# next: get next anchor
+#
+sub next {
+ if (++$CURRENT > $#ANCHORS) {
+ return ('', '', '');
+ }
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$CURRENT]);
+ $CURRENTDEF = $CURRENT if ($type eq 'D');
+
+ ($lno, $tag, $type);
+}
+#
+# getlinks: get links
+#
+# i) linenumber >= 1: line number
+# 0: header, -1: tailer
+# gi) @ANCHORS tag table in current file
+# r) (previous, next, first, last, top, bottom)
+#
+sub getlinks {
+ local($linenumber) = @_;
+ local($prev, $next, $first, $last, $top, $bottom);
+
+ $prev = $next = $first = $last = $top = $bottom = 0;
+ if ($linenumber >= 1) {
+ local($c, $p, $n);
+ if ($CURRENTDEF == 0) {
+ for ($c = 0; $c <= $#ANCHORS; $c++) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$c]);
+ if ($lno == $linenumber && $type eq 'D') {
+ last;
+ }
+ }
+ $CURRENTDEF = $c;
+ } else {
+ for ($c = $CURRENTDEF; $c >= 0; $c--) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$c]);
+ if ($lno == $linenumber && $type eq 'D') {
+ last;
+ }
+ }
+ }
+ $p = $n = $c;
+ while (--$p >= 0) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$p]);
+ if ($type eq 'D') {
+ $prev = $lno;
+ last;
+ }
+ }
+ while (++$n <= $#ANCHORS) {
+ local($lno, $tag, $type) = split(/,/, $ANCHORS[$n]);
+ if ($type eq 'D') {
+ $next = $lno;
+ last;
+ }
+ }
+ }
+ $first = $FIRST if ($linenumber != $FIRST);
+ $last = $LAST if ($linenumber != $LAST);
+ $top = 'TOP' if ($linenumber != 0);
+ $bottom = 'BOTTOM' if ($linenumber != -1);
+ if ($FIRST == $LAST) {
+ $last = '' if ($linenumber == 0);
+ $first = '' if ($linenumber == -1);
+ }
+
+ ($prev, $next, $first, $last, $top, $bottom);
+}
+
+#=========================================================================
+# CACHE PACKAGE
+#=========================================================================
+package cache;
+#
+# open: open tag cache
+#
+# i) size cache size
+# -1: all cache
+# 0: no cache
+# other: sized cache
+#
+sub open {
+ ($cachesize) = @_;
+
+ if ($cachesize == -1) {
+ return;
+ }
+ undef %CACH if defined(%CACH);
+ $cachecount = 0;
+}
+#
+# put: put tag into cache
+#
+# i) $db database name
+# i) $tag tag name
+# i) $line tag line
+#
+sub put {
+ local($db, $tag, $line) = @_;
+ local($label) = ($db eq 'GTAGS') ? 'D' : 'R';
+
+ $cachecount++;
+ if ($cachesize >= 0 && $cachecount > $cachesize) {
+ $CACH = "$'tmp/CACH$$";
+ dbmopen(%CACH, $CACH, 0600) || &'error("make cache database.\n");
+ $cachesize = -1;
+ }
+ $CACH{$label.$tag} = $line;
+}
+#
+# get: get tag from cache
+#
+# i) $db database name
+# i) $tag tag name
+# r) tag line
+#
+sub get {
+ local($db, $tag) = @_;
+ local($label) = ($db eq 'GTAGS') ? 'D' : 'R';
+
+ defined($CACH{$label.$tag}) ? $CACH{$label.$tag} : undef;
+}
+#
+# close: close cache
+#
+sub close {
+ #dbmclose(%CACH);
+ unlink("$CACH.db") if (defined($CACH));
+}
diff --git a/usr.bin/global/systags/Makefile b/usr.bin/global/systags/Makefile
new file mode 100644
index 0000000..49c9806
--- /dev/null
+++ b/usr.bin/global/systags/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 1.0 (Berkeley) 4/21/96
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/systags.sh ${DESTDIR}/usr/bin/systags
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/global/systags/systags.sh b/usr.bin/global/systags/systags.sh
new file mode 100755
index 0000000..e6e85bf
--- /dev/null
+++ b/usr.bin/global/systags/systags.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# Copyright (c) 1997 Shigio Yamaguchi. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Shigio Yamaguchi.
+# 4. Neither the name of the author nor the names of any co-contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# systags.sh 17-Feb-97
+#
+# script to make hypertext of kernel source.
+# supporting FreeBSD and Linux.
+#
+case $1 in
+-n) nflag=1; shift;;
+esac
+case $1 in
+"") dir=.;;
+*) dir=$1;;
+esac
+#
+# get release number from source tree.
+#
+if [ -f conf/newvers.sh ]; then
+ os=FreeBSD
+ release=`awk -F= '/^RELEASE=/ {print $2}' < conf/newvers.sh`
+elif [ -f Makefile ] && grep '^vmlinux:' Makefile >/dev/null; then
+ os=Linux
+ version=`awk -F= '/^VERSION *=/ {print $2}' < Makefile`
+ patchlevel=`awk -F= '/^PATCHLEVEL *=/ {print $2}' < Makefile`
+ sublevel=`awk -F= '/^SUBLEVEL *=/ {print $2}' < Makefile`
+ release=`echo "$version.$patchlevel.$sublevel" | tr -d ' '`
+fi
+#
+# remove old files
+#
+case $nflag in
+1) echo "rm -rf $dir/htags.log $dir/GTAGS $dir/GRTAGS $dir/HTML";;
+*) rm -rf $dir/htags.log $dir/GTAGS $dir/GRTAGS $dir/HTML;;
+esac
+#
+# make global database(GTAGS, GRTAGS).
+#
+case $nflag in
+1) echo "gtags -se $dir";;
+*) gtags -se $dir;;
+esac
+#
+# make hypertext.
+# (please replace this title with a suitable one.)
+#
+case $os$release in
+"") program=`/bin/pwd | sed 's/.*\///'`
+ title="Welcome to $program source tour!";;
+*) title="Welcome to $os $release kernel source tour!";;
+esac
+case $nflag in
+1) echo "htags -vwat '$title' -d $dir $dir > $dir/htags.log 2>&1";;
+*) htags -vwat "$title" -d $dir $dir> $dir/htags.log 2>&1;;
+esac
diff --git a/usr.bin/gprof/Makefile b/usr.bin/gprof/Makefile
index 0762b78..f8aa1f2 100644
--- a/usr.bin/gprof/Makefile
+++ b/usr.bin/gprof/Makefile
@@ -5,7 +5,7 @@ SRCS= gprof.c arcs.c dfn.c lookup.c ${MACHINE}.c hertz.c \
printgprof.c printlist.c
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \
${.CURDIR}/gprof.flat ${.CURDIR}/gprof.callg \
${DESTDIR}/usr/share/misc
diff --git a/usr.bin/gprof/amd64.c b/usr.bin/gprof/amd64.c
new file mode 100644
index 0000000..6a47408
--- /dev/null
+++ b/usr.bin/gprof/amd64.c
@@ -0,0 +1,11 @@
+#include "gprof.h"
+
+/*
+ * gprof -c isn't currently supported...
+ */
+findcall( parentp , p_lowpc , p_highpc )
+ nltype *parentp;
+ unsigned long p_lowpc;
+ unsigned long p_highpc;
+{
+}
diff --git a/usr.bin/gprof/amd64.h b/usr.bin/gprof/amd64.h
new file mode 100644
index 0000000..067e019
--- /dev/null
+++ b/usr.bin/gprof/amd64.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)i386.h 8.1 (Berkeley) 6/6/93
+ */
+
+ /*
+ * offset (in bytes) of the code from the entry address of a routine.
+ * (see asgnsamples for use and explanation.)
+ */
+#define OFFSET_OF_CODE 0
+#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT))
+
+enum opermodes { dummy };
+typedef enum opermodes operandenum;
diff --git a/usr.bin/gprof/arcs.c b/usr.bin/gprof/arcs.c
index e5bbc24..2c22469 100644
--- a/usr.bin/gprof/arcs.c
+++ b/usr.bin/gprof/arcs.c
@@ -224,7 +224,7 @@ doarcs()
*/
doflags();
/*
- * starting from the topological bottom,
+ * starting from the topological bottom,
* propogate children times up to parents.
*/
dotime();
@@ -416,7 +416,7 @@ cyclelink()
/*
* link members to cycle header
*/
- for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
+ for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
memberp -> cycleno = cycle;
memberp -> cyclehead = cyclenlp;
}
@@ -847,7 +847,7 @@ doflags()
}
} else {
/*
- * it has parents to pass time to,
+ * it has parents to pass time to,
* but maybe someone wants to shut it up
* by puttting it on -E list. (but favor -F over -E)
*/
@@ -874,7 +874,7 @@ doflags()
/*
* check if any parent of this child
* (or outside parents of this cycle)
- * have their print flags on and set the
+ * have their print flags on and set the
* print flag of the child (cycle) appropriately.
* similarly, deal with propagation fractions from parents.
*/
@@ -915,7 +915,7 @@ inheritflags( childp )
}
} else {
/*
- * its a member of a cycle, look at all parents from
+ * its a member of a cycle, look at all parents from
* outside the cycle
*/
headp -> printflag = FALSE;
diff --git a/usr.bin/gprof/dfn.c b/usr.bin/gprof/dfn.c
index 987929f..169a47f 100644
--- a/usr.bin/gprof/dfn.c
+++ b/usr.bin/gprof/dfn.c
@@ -134,7 +134,7 @@ bool
dfn_numbered( childp )
nltype *childp;
{
-
+
return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY );
}
@@ -212,7 +212,7 @@ dfn_findcycle( childp )
* if what we think is the top of the cycle
* has a cyclehead field, then it's not really the
* head of the cycle, which is really what we want
- */
+ */
if ( cycleheadp -> cyclehead != cycleheadp ) {
cycleheadp = cycleheadp -> cyclehead;
# ifdef DEBUG
diff --git a/usr.bin/gprof/gprof.1 b/usr.bin/gprof/gprof.1
index dfb0f21..76b5543 100644
--- a/usr.bin/gprof/gprof.1
+++ b/usr.bin/gprof/gprof.1
@@ -91,8 +91,8 @@ Second, a flat profile is given,
similar to that provided by
.Xr prof 1 .
This listing gives the total execution times, the call counts,
-the time in milleseconds the call spent in the routine itself, and
-the time in milleseconds the call spent in the routine itself including
+the time in msec or usec the call spent in the routine itself, and
+the time in msec or usec the call spent in the routine itself including
its descendents.
.Pp
Finally, an index of the function names is provided.
@@ -194,6 +194,10 @@ option may be given.
Only one pair of routine names may be given with each
.Fl k
option.
+.It Fl l
+Suppresses the printing of the call-graph profile.
+.It Fl L
+Suppresses the printing of the flat profile.
.It Fl s
A profile file
.Pa gmon.sum
@@ -205,6 +209,13 @@ executions of gprof (probably also with a
to accumulate profile data across several runs of an
.Pa a.out
file.
+.It Fl u
+Suppresses the printing of functions whose name does not begin with
+an underscore.
+All relevant information about such functions belongs to the
+(non-suppressed) function with the next lowest address.
+This is useful for eliminating "functions" that are just labels
+inside other functions.
.It Fl z
Displays routines that have zero usage (as shown by call counts
and accumulated time).
@@ -222,10 +233,11 @@ Dynamic call graph and profile.
Summarized dynamic call graph and profile.
.El
.Sh SEE ALSO
-.Xr monitor 3 ,
-.Xr profil 2 ,
.Xr cc 1 ,
-.Xr prof 1
+.Xr profil 2 ,
+.Xr clocks 7
+.\" .Xr monitor 3 ,
+.\" .Xr prof 1
.Rs
.%T "An Execution Profiler for Modular Programs"
.%A S. Graham
@@ -274,7 +286,7 @@ propagated properly, unless the signal catcher was invoked during
the execution of the profiling routine, in which case all is lost.
.Pp
The profiled program must call
-.Xr exit 2
+.Xr exit 3
or return normally for the profiling information to be saved
in the
.Pa gmon.out
diff --git a/usr.bin/gprof/gprof.c b/usr.bin/gprof/gprof.c
index 5057e32..0dbb187 100644
--- a/usr.bin/gprof/gprof.c
+++ b/usr.bin/gprof/gprof.c
@@ -51,6 +51,9 @@ char *whoami = "gprof";
char *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
static struct gmonhdr gmonhdr;
+static bool uflag;
+static int lflag;
+static int Lflag;
main(argc, argv)
int argc;
@@ -122,9 +125,20 @@ main(argc, argv)
addlist( ktolist , *++argv );
kflag = TRUE;
break;
- case 's':
+ case 'l':
+ lflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ lflag = 0;
+ break;
+ case 's':
sflag = TRUE;
break;
+ case 'u':
+ uflag = TRUE;
+ break;
case 'z':
zflag = TRUE;
break;
@@ -190,15 +204,19 @@ main(argc, argv)
/*
* print the dynamic profile
*/
- printgprof( timesortnlp );
+ if(!lflag) {
+ printgprof( timesortnlp );
+ }
/*
* print the flat profile
*/
- printprof();
+ if(!Lflag) {
+ printprof();
+ }
/*
* print the index
*/
- printindex();
+ printindex();
done();
}
@@ -534,11 +552,11 @@ readsamples(pfile)
{
register i;
UNIT sample;
-
+
if (samples == 0) {
samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
if (samples == 0) {
- fprintf( stderr , "%s: No room for %d sample pc's\n",
+ fprintf( stderr , "%s: No room for %d sample pc's\n",
whoami , sampbytes / sizeof (UNIT));
done();
}
@@ -621,7 +639,7 @@ asgnsamples()
svalue0 = nl[j].svalue;
svalue1 = nl[j+1].svalue;
/*
- * if high end of tick is below entry address,
+ * if high end of tick is below entry address,
* go for next tick.
*/
if (pch < svalue0)
@@ -638,7 +656,7 @@ asgnsamples()
if (debug & SAMPLEDEBUG) {
printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
nl[j].value/sizeof(UNIT), svalue0, svalue1,
- nl[j].name,
+ nl[j].name,
overlap * time / scale, overlap);
}
# endif DEBUG
@@ -704,8 +722,6 @@ bool
funcsymbol( nlistp )
struct nlist *nlistp;
{
- extern char *strtab; /* string table from a.out */
- extern int aflag; /* if static functions aren't desired */
char *name, c;
/*
@@ -717,6 +733,7 @@ funcsymbol( nlistp )
return FALSE;
}
/*
+ * name must start with an underscore if uflag is set.
* can't have any `funny' characters in name,
* where `funny' includes `.', .o file names
* and `$', pascal labels.
@@ -724,6 +741,8 @@ funcsymbol( nlistp )
* perhaps we should just drop this code entirely...
*/
name = strtab + nlistp -> n_un.n_strx;
+ if ( uflag && *name != '_' )
+ return FALSE;
#ifdef sparc
if ( *name == '.' ) {
char *p = name + 1;
diff --git a/usr.bin/gprof/gprof.h b/usr.bin/gprof/gprof.h
index ef1cc19..27808d2 100644
--- a/usr.bin/gprof/gprof.h
+++ b/usr.bin/gprof/gprof.h
@@ -81,7 +81,11 @@ typedef int bool;
*/
long hz;
+#ifdef GPROF4
+typedef int32_t UNIT;
+#else
typedef u_short UNIT; /* unit of profiling */
+#endif
char *a_outname;
#define A_OUTNAME "a.out"
@@ -179,7 +183,7 @@ int cyclecnt; /* the number of cycles found */
#define DFN_BUSY -1
#define DFN_NAN 0
- /*
+ /*
* namelist entries for cycle headers.
* the number of discovered cycles.
*/
diff --git a/usr.bin/gprof/lookup.c b/usr.bin/gprof/lookup.c
index d63c13bf..c276346 100644
--- a/usr.bin/gprof/lookup.c
+++ b/usr.bin/gprof/lookup.c
@@ -39,7 +39,7 @@ static char sccsid[] = "@(#)lookup.c 8.1 (Berkeley) 6/6/93";
/*
* look up an address in a sorted-by-address namelist
- * this deals with misses by mapping them to the next lower
+ * this deals with misses by mapping them to the next lower
* entry point.
*/
nltype *
diff --git a/usr.bin/gprof/printgprof.c b/usr.bin/gprof/printgprof.c
index 5ede772..0b039df 100644
--- a/usr.bin/gprof/printgprof.c
+++ b/usr.bin/gprof/printgprof.c
@@ -90,7 +90,7 @@ timecmp( npp1 , npp2 )
*/
flatprofheader()
{
-
+
if ( bflag ) {
printblurb( _PATH_FLAT_BLURB );
}
@@ -110,7 +110,9 @@ flatprofheader()
"% " , "cumulative" , "self " , "" , "self " , "total " , "" );
printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" ,
"time" , "seconds " , "seconds" , "calls" ,
- "ms/call" , "ms/call" , "name" );
+ hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
+ hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
+ "name" );
}
flatprofline( np )
@@ -121,12 +123,25 @@ flatprofline( np )
return;
}
actime += np -> time;
- printf( "%5.1f %10.2f %8.2f" ,
- 100 * np -> time / totime , actime / hz , np -> time / hz );
+ if (hz >= 10000)
+ printf( "%5.1f %10.3f %8.3f" ,
+ 100 * np -> time / totime , actime / hz , np -> time / hz );
+ else
+ printf( "%5.1f %10.2f %8.2f" ,
+ 100 * np -> time / totime , actime / hz , np -> time / hz );
if ( np -> ncall != 0 ) {
- printf( " %8d %8.2f %8.2f " , np -> ncall ,
- 1000 * np -> time / hz / np -> ncall ,
- 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
+ if (hz >= 10000000)
+ printf( " %8d %8.0f %8.0f " , np -> ncall ,
+ 1e9 * np -> time / hz / np -> ncall ,
+ 1e9 * ( np -> time + np -> childtime ) / hz / np -> ncall );
+ else if (hz >= 10000)
+ printf( " %8d %8.0f %8.0f " , np -> ncall ,
+ 1e6 * np -> time / hz / np -> ncall ,
+ 1e6 * ( np -> time + np -> childtime ) / hz / np -> ncall );
+ else
+ printf( " %8d %8.2f %8.2f " , np -> ncall ,
+ 1000 * np -> time / hz / np -> ncall ,
+ 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
} else {
printf( " %8.8s %8.8s %8.8s " , "" , "" , "" );
}
@@ -250,7 +265,7 @@ totalcmp( npp1 , npp2 )
return 1;
if ( diff > 0.0 )
return -1;
- if ( np1 -> name == 0 && np1 -> cycleno != 0 )
+ if ( np1 -> name == 0 && np1 -> cycleno != 0 )
return -1;
if ( np2 -> name == 0 && np2 -> cycleno != 0 )
return 1;
@@ -264,7 +279,7 @@ totalcmp( npp1 , npp2 )
return 1;
if ( np1 -> ncall > np2 -> ncall )
return -1;
- if ( np1 -> ncall < np2 -> ncall )
+ if ( np1 -> ncall < np2 -> ncall )
return 1;
return strcmp( np1 -> name , np2 -> name );
}
@@ -487,7 +502,7 @@ printmembers( cyclep )
sortmembers( cyclep );
for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
- printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
+ printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
"" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
memberp -> npropcall );
if ( memberp -> selfcalls != 0 ) {
diff --git a/usr.bin/gprof/tahoe.c b/usr.bin/gprof/tahoe.c
index ac027f9..839ee29 100644
--- a/usr.bin/gprof/tahoe.c
+++ b/usr.bin/gprof/tahoe.c
@@ -66,7 +66,7 @@ operandmode( modep )
unsigned char *modep;
{
long usesreg = ((long)*modep) & 0xf;
-
+
switch ( ((long)*modep) >> 4 ) {
case 0:
case 1:
@@ -105,7 +105,7 @@ char *
operandname( mode )
operandenum mode;
{
-
+
switch ( mode ) {
case literal:
return "literal";
@@ -157,7 +157,7 @@ long
operandlength( modep )
unsigned char *modep;
{
-
+
switch ( operandmode( modep ) ) {
case literal:
case reg:
@@ -300,7 +300,7 @@ findcall( parentp , p_lowpc , p_highpc )
case longrel:
/*
* regular pc relative addressing
- * check that this is the address of
+ * check that this is the address of
* a function.
*/
destpc = reladdr( instructp+length )
diff --git a/usr.bin/gprof/tahoe.h b/usr.bin/gprof/tahoe.h
index 7fd0d04..d82359a 100644
--- a/usr.bin/gprof/tahoe.h
+++ b/usr.bin/gprof/tahoe.h
@@ -51,7 +51,7 @@
#define PC 0xf
enum opermodes {
- literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
+ literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
longrel, longreldef
diff --git a/usr.bin/gprof/vax.c b/usr.bin/gprof/vax.c
index ec3232a..03e3495 100644
--- a/usr.bin/gprof/vax.c
+++ b/usr.bin/gprof/vax.c
@@ -66,7 +66,7 @@ operandmode( modep )
struct modebyte *modep;
{
long usesreg = modep -> regfield;
-
+
switch ( modep -> modefield ) {
case 0:
case 1:
@@ -105,7 +105,7 @@ char *
operandname( mode )
operandenum mode;
{
-
+
switch ( mode ) {
case literal:
return "literal";
@@ -157,7 +157,7 @@ long
operandlength( modep )
struct modebyte *modep;
{
-
+
switch ( operandmode( modep ) ) {
case literal:
case reg:
@@ -297,7 +297,7 @@ findcall( parentp , p_lowpc , p_highpc )
case longrel:
/*
* regular pc relative addressing
- * check that this is the address of
+ * check that this is the address of
* a function.
*/
destpc = reladdr( (struct modebyte *) (instructp+length) )
diff --git a/usr.bin/gprof/vax.h b/usr.bin/gprof/vax.h
index b5fbf35..33c5822 100644
--- a/usr.bin/gprof/vax.h
+++ b/usr.bin/gprof/vax.h
@@ -51,7 +51,7 @@
#define PC 0xf
enum opermodes {
- literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
+ literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
longrel, longreldef
diff --git a/usr.bin/gprof4/Makefile b/usr.bin/gprof4/Makefile
new file mode 100644
index 0000000..f5c2c83
--- /dev/null
+++ b/usr.bin/gprof4/Makefile
@@ -0,0 +1,14 @@
+# This was cloned from the Makefile for gprof by changing PROG from gprof
+# to gprof4, adding NOMAN and PATH, adding -DGPROF4 to CFLAGS and deleting
+# beforeinstall.
+
+# @(#)Makefile 5.17 (Berkeley) 5/11/90
+
+PROG= gprof4
+NOMAN= noman
+SRCS= gprof.c arcs.c dfn.c lookup.c ${MACHINE}.c hertz.c \
+ printgprof.c printlist.c
+CFLAGS+=-DGPROF4
+.PATH: ${.CURDIR}/../../usr.bin/gprof
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/grep/egrep/Makefile b/usr.bin/grep/egrep/Makefile
deleted file mode 100644
index 556ebfe..0000000
--- a/usr.bin/grep/egrep/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/27/93
-
-# -DSLOWSYS invoke xread() for system time quirk on PDP, others?
-# -DNOKANJI default is for Japanese Unix. undef only for raw
-# parity-marked search capability, not standard w/grep.
-# -DCHINESE for systems using EUC Chinese2 codes
-# -Dstrrchr=rindex, -Dstrchr=index as necessary
-
-PROG= egrep
-CFLAGS+=-Dstrrchr=rindex -Dstrchr=index -DNOKANJI
-LDADD= -lcompat # must search compat to get spencers early regexp package
-MAN1= grep.0
-LINKS= ${BINDIR}/egrep ${BINDIR}/grep ${BINDIR}/egrep ${BINDIR}/fgrep
-MLINKS= grep.1 egrep.1 grep.1 fgrep.1
-
-.include "../../Makefile.inc"
-.include <bsd.prog.mk>
diff --git a/usr.bin/head/head.1 b/usr.bin/head/head.1
index 2e47515..a85c93f 100644
--- a/usr.bin/head/head.1
+++ b/usr.bin/head/head.1
@@ -40,11 +40,14 @@
.Sh SYNOPSIS
.Nm head
.Op Fl n Ar count
+.Op Fl c Ar bytes
.Op Ar file ...
.Sh DESCRIPTION
This filter displays the first
.Ar count
-lines of each of the specified files, or of the standard input if no
+lines or
+.Ar bytes
+of each of the specified files, or of the standard input if no
files are specified.
If
.Ar count
diff --git a/usr.bin/head/head.c b/usr.bin/head/head.c
index a3ad1de..e4a7a58 100644
--- a/usr.bin/head/head.c
+++ b/usr.bin/head/head.c
@@ -58,6 +58,7 @@ static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 5/4/95";
void err __P((int, const char *, ...));
void head __P((FILE *, int));
+void head_bytes __P((FILE *, int));
void obsolete __P((char *[]));
void usage __P((void));
@@ -70,13 +71,17 @@ main(argc, argv)
{
register int ch;
FILE *fp;
- int first, linecnt;
+ int first, linecnt = -1, bytecnt = -1;
char *ep;
obsolete(argv);
- linecnt = 10;
- while ((ch = getopt(argc, argv, "n:")) != EOF)
+ while ((ch = getopt(argc, argv, "n:c:")) != -1)
switch(ch) {
+ case 'c':
+ bytecnt = strtol(optarg, &ep, 10);
+ if (*ep || bytecnt <= 0)
+ err(1, "illegal byte count -- %s", optarg);
+ break;
case 'n':
linecnt = strtol(optarg, &ep, 10);
if (*ep || linecnt <= 0)
@@ -89,7 +94,11 @@ main(argc, argv)
argc -= optind;
argv += optind;
- if (*argv)
+ if (linecnt != -1 && bytecnt != -1)
+ err(1, "can't combine line and byte counts");
+ if (linecnt == -1 )
+ linecnt = 10;
+ if (*argv) {
for (first = 1; *argv; ++argv) {
if ((fp = fopen(*argv, "r")) == NULL) {
err(0, "%s: %s", *argv, strerror(errno));
@@ -100,11 +109,18 @@ main(argc, argv)
first ? "" : "\n", *argv);
first = 0;
}
- head(fp, linecnt);
+ if (bytecnt == -1)
+ head(fp, linecnt);
+ else
+ head_bytes(fp, bytecnt);
(void)fclose(fp);
}
- else
+ }
+ else if (bytecnt == -1)
head(stdin, linecnt);
+ else
+ head_bytes(stdin, bytecnt);
+
exit(eval);
}
@@ -115,22 +131,43 @@ head(fp, cnt)
{
register int ch;
- while (cnt--)
- while ((ch = getc(fp)) != EOF) {
+ while (cnt && (ch = getc(fp)) != EOF) {
if (putchar(ch) == EOF)
err(1, "stdout: %s", strerror(errno));
if (ch == '\n')
- break;
+ cnt--;
}
}
void
+head_bytes(fp, cnt)
+ FILE *fp;
+ register int cnt;
+{
+ char buf[4096];
+ register int readlen;
+
+ while (cnt) {
+ if (cnt < sizeof(buf))
+ readlen = cnt;
+ else
+ readlen = sizeof(buf);
+ readlen = fread(buf, sizeof(char), readlen, fp);
+ if (readlen == EOF)
+ break;
+ if (fwrite(buf, sizeof(char), readlen, stdout) != readlen)
+ err(1, "stdout: %s", strerror(errno));
+ cnt -= readlen;
+ }
+}
+
+void
obsolete(argv)
char *argv[];
{
char *ap;
- while (ap = *++argv) {
+ while ((ap = *++argv)) {
/* Return if "--" or not "-[0-9]*". */
if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1]))
return;
diff --git a/usr.bin/hexdump/Makefile b/usr.bin/hexdump/Makefile
index 5a9e87a..24ad198 100644
--- a/usr.bin/hexdump/Makefile
+++ b/usr.bin/hexdump/Makefile
@@ -2,7 +2,9 @@
PROG= hexdump
SRCS= conv.c display.c hexdump.c hexsyntax.c odsyntax.c parse.c
-MAN1= hexdump.0 od.0
+MAN1= hexdump.1 od.1
+MLINKS= hexdump.1 hd.1
LINKS= ${BINDIR}/hexdump ${BINDIR}/od
+LINKS+= ${BINDIR}/hexdump ${BINDIR}/hd
.include <bsd.prog.mk>
diff --git a/usr.bin/hexdump/hexdump.1 b/usr.bin/hexdump/hexdump.1
index 7161beb..1fd6d07 100644
--- a/usr.bin/hexdump/hexdump.1
+++ b/usr.bin/hexdump/hexdump.1
@@ -30,15 +30,25 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)hexdump.1 8.2 (Berkeley) 4/18/94
+.\" $Id$
.\"
.Dd April 18, 1994
.Dt HEXDUMP 1
.Os
.Sh NAME
-.Nm hexdump
+.Nm hexdump, hd
.Nd ascii, decimal, hexadecimal, octal dump
.Sh SYNOPSIS
.Nm hexdump
+.Op Fl bcCdovx
+.Op Fl e Ar format_string
+.Op Fl f Ar format_file
+.Op Fl n Ar length
+.Bk -words
+.Op Fl s Ar skip
+.Ek
+.Ar file ...
+.Nm hd
.Op Fl bcdovx
.Op Fl e Ar format_string
.Op Fl f Ar format_file
@@ -64,6 +74,15 @@ in octal, per line.
Display the input offset in hexadecimal, followed by sixteen
space-separated, three column, space-filled, characters of input
data per line.
+.It Fl C
+.Em Canonical hex+ASCII display.
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, two column, hexadecimal bytes, followed by the
+same sixteen bytes in %_p format enclosed in ``|'' characters.
+.Pp
+Calling the command
+.Nm hd
+implies this option.
.It Fl d
.Em Two-byte decimal display.
Display the input offset in hexadecimal, followed by eight
@@ -195,7 +214,7 @@ described in the C standard are supported:
.Ed
.El
.Pp
-Hexdump also supports the the following additional conversion strings:
+Hexdump also supports the following additional conversion strings:
.Bl -tag -width Fl
.It Cm \&_a Ns Op Cm dox
Display the input offset, cumulative across input files, of the
@@ -321,4 +340,4 @@ Implement the \-x option:
"%07.7_ax " 8/2 "%04x " "\en"
.Ed
.Sh SEE ALSO
-.Xr adb 1
+.Xr gdb 1
diff --git a/usr.bin/hexdump/hexsyntax.c b/usr.bin/hexdump/hexsyntax.c
index 300d43e..279a68c 100644
--- a/usr.bin/hexdump/hexsyntax.c
+++ b/usr.bin/hexdump/hexsyntax.c
@@ -58,7 +58,14 @@ newsyntax(argc, argvp)
char *p, **argv;
argv = *argvp;
- while ((ch = getopt(argc, argv, "bcde:f:n:os:vx")) != EOF)
+ if ((p = rindex(argv[0], 'h')) != NULL &&
+ strcmp(p, "hd") == 0) {
+ /* "Canonical" format, implies -C. */
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ }
+ while ((ch = getopt(argc, argv, "bcCde:f:n:os:vx")) != -1)
switch (ch) {
case 'b':
add("\"%07.7_Ax\n\"");
@@ -68,6 +75,11 @@ newsyntax(argc, argvp)
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"");
break;
+ case 'C':
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ break;
case 'd':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"");
@@ -124,6 +136,6 @@ void
usage()
{
(void)fprintf(stderr,
-"hexdump: [-bcdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n");
+"hexdump: [-bcCdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n");
exit(1);
}
diff --git a/usr.bin/hexdump/od.1 b/usr.bin/hexdump/od.1
index dab6da7..001b900 100644
--- a/usr.bin/hexdump/od.1
+++ b/usr.bin/hexdump/od.1
@@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)od.1 8.1 (Berkeley) 6/6/93
+.\" $Id: od.1,v 1.5 1997/02/22 19:55:07 peter Exp $
.\"
-.Dd %Q
+.Dd May 27, 1994
.Os
.Dt OD 1
.Sh NAME
@@ -53,7 +54,7 @@
has been deprecated in favor of
.Xr hexdump 1 .
.Pp
-.Xr Hexdump ,
+.Nm Hexdump ,
if called as
.Nm od ,
provides compatibility for the options listed above.
@@ -74,3 +75,8 @@ of the offset syntax.
.Xr strings 1
.Sh BUGS
Quite a few.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/hexdump/odsyntax.c b/usr.bin/hexdump/odsyntax.c
index 46f308b..e4c4e72 100644
--- a/usr.bin/hexdump/odsyntax.c
+++ b/usr.bin/hexdump/odsyntax.c
@@ -61,7 +61,7 @@ oldsyntax(argc, argvp)
deprecated = 1;
argv = *argvp;
- while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != EOF)
+ while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != -1)
switch (ch) {
case 'a':
odprecede();
@@ -93,7 +93,7 @@ oldsyntax(argc, argvp)
odprecede();
add("2/8 \" %21.14e \" \"\\n\"");
break;
-
+
case 'f':
odprecede();
add("4/4 \" %14.7e \" \"\\n\"");
diff --git a/usr.bin/host/Makefile b/usr.bin/host/Makefile
new file mode 100644
index 0000000..ebccefa
--- /dev/null
+++ b/usr.bin/host/Makefile
@@ -0,0 +1,10 @@
+# $Id$
+
+.include "${.CURDIR}/../../usr.sbin/named/Makefile.inc"
+
+.PATH: ${BIND_DIR}/tools
+.PATH: ${BIND_DIR}/man
+
+PROG= host
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/id/Makefile b/usr.bin/id/Makefile
index 44eaa4a..5b90f29 100644
--- a/usr.bin/id/Makefile
+++ b/usr.bin/id/Makefile
@@ -1,14 +1,13 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= id
-MAN1= id.0 groups.0 whoami.0
+MAN1= id.1 groups.1 whoami.1
+# XXX BROKEN: afterinstall:
afterinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/groups.sh ${DESTDIR}/usr/bin/groups
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/whoami.sh ${DESTDIR}/usr/bin/whoami
- ${MINSTALL} groups.0 ${DESTDIR}${MANDIR}1/groups.0
- ${MINSTALL} whoami.0 ${DESTDIR}${MANDIR}1/whoami.0
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/groups.sh ${DESTDIR}${BINDIR}/groups
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/whoami.sh ${DESTDIR}${BINDIR}/whoami
.include <bsd.prog.mk>
diff --git a/usr.bin/id/groups.1 b/usr.bin/id/groups.1
index 35653dc..58204af 100644
--- a/usr.bin/id/groups.1
+++ b/usr.bin/id/groups.1
@@ -31,7 +31,7 @@
.\"
.\" @(#)groups.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd "June 6, 1993"
+.Dd June 6, 1993
.Dt GROUPS 1
.UC
.Sh NAME
diff --git a/usr.bin/id/groups.sh b/usr.bin/id/groups.sh
index e29ed90..904f200 100644
--- a/usr.bin/id/groups.sh
+++ b/usr.bin/id/groups.sh
@@ -32,6 +32,8 @@
# SUCH DAMAGE.
#
# @(#)groups.sh 8.1 (Berkeley) 6/6/93
-#
+# $Id$
+
+PATH=/bin:/usr/bin; export PATH
-id -Gn $*
+exec id -Gn -- "$@"
diff --git a/usr.bin/id/id.1 b/usr.bin/id/id.1
index 3bc454e..1d194e9 100644
--- a/usr.bin/id/id.1
+++ b/usr.bin/id/id.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1991, 1993, 1994
+.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
@@ -32,31 +32,32 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)id.1 8.2 (Berkeley) 5/5/94
+.\" @(#)id.1 8.1 (Berkeley) 6/6/93
+.\" $Id: id.1,v 1.2 1997/04/27 08:45:44 jmg Exp $
.\"
-.Dd "May 5, 1994"
+.Dd June 6, 1993
.Dt ID 1
.Os BSD 4.4
.Sh NAME
.Nm id
.Nd return user identity
.Sh SYNOPSIS
-.Nm id
+.Nm
.Op Ar user
-.Nm id
+.Nm
.Fl G Op Fl n
.Op Ar user
-.Nm id
+.Nm
.Fl g Op Fl nr
.Op Ar user
-.Nm id
+.Nm
.Fl p
-.Nm id
+.Nm
.Fl u Op Fl nr
.Op Ar user
.Sh DESCRIPTION
The
-.Nm id
+.Nm
utility displays the user and group names and numeric IDs, of the
calling process, to the standard output.
If the real and effective IDs are different, both are displayed,
@@ -91,14 +92,19 @@ If the user name returned by
is different from the login name referenced by the user ID, the name
returned by
.Xr getlogin 2
-is displayed, preceded by the keyword ``login''.
-The user ID as a name is displayed, preceded by the keyword ``uid''.
+is displayed, preceded by the keyword
+.Dq login .
+The user ID as a name is displayed, preceded by the keyword
+.Dq uid .
If the effective user ID is different from the real user ID, the real user
-ID is displayed as a name, preceded by the keyword ``euid''.
+ID is displayed as a name, preceded by the keyword
+.Dq euid .
If the effective group ID is different from the real group ID, the real group
-ID is displayed as a name, preceded by the keyword ``rgid''.
+ID is displayed as a name, preceded by the keyword
+.Dq rgid .
The list of groups to which the user belongs is then displayed as names,
-preceded by the keyword ``groups''.
+preceded by the keyword
+.Dq groups .
Each display is on a separate line.
.It Fl r
Display the real ID for the
@@ -111,13 +117,13 @@ Display the effective user ID as a number.
.El
.Pp
The
-.Nm id
+.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
.Xr who 1
.Sh STANDARDS
The
-.Nm id
+.Nm
function is expected to conform to
.St -p1003.2 .
.Sh HISTORY
@@ -134,6 +140,6 @@ command is equivalent to
.Dq Nm id Fl un .
.Pp
The
-.Nm id
-command first appeared in
+.Nm
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/id/id.c b/usr.bin/id/id.c
index bf9218e..05face7 100644
--- a/usr.bin/id/id.c
+++ b/usr.bin/id/id.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)id.c 8.3 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)id.c 8.2 (Berkeley) 2/16/94";
#endif /* not lint */
#include <sys/param.h>
@@ -70,7 +70,7 @@ main(argc, argv)
int Gflag, ch, gflag, id, nflag, pflag, rflag, uflag;
Gflag = gflag = nflag = pflag = rflag = uflag = 0;
- while ((ch = getopt(argc, argv, "Ggnpru")) != EOF)
+ while ((ch = getopt(argc, argv, "Ggnpru")) != -1)
switch(ch) {
case 'G':
Gflag = 1;
@@ -168,7 +168,7 @@ pretty(pw)
(void)printf("uid\t%s\n", pw->pw_name);
else
(void)printf("uid\t%u\n", rid);
-
+
if ((eid = geteuid()) != rid)
if (pw = getpwuid(eid))
(void)printf("euid\t%s", pw->pw_name);
@@ -231,24 +231,24 @@ user(pw)
{
register struct group *gr;
register char *fmt, **p;
- int cnt, id, lastid, ngroups, groups[NGROUPS + 1];
+ int cnt, gid, lastgid, ngroups, groups[NGROUPS + 1];
- id = pw->pw_uid;
- (void)printf("uid=%u(%s)", id, pw->pw_name);
- (void)printf(" gid=%u", pw->pw_gid);
- if (gr = getgrgid(pw->pw_gid))
+ (void)printf("uid=%u(%s)", pw->pw_uid, pw->pw_name);
+ gid = pw->pw_gid;
+ (void)printf(" gid=%u", gid);
+ if (gr = getgrgid(gid))
(void)printf("(%s)", gr->gr_name);
ngroups = NGROUPS + 1;
- (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+ (void) getgrouplist(pw->pw_name, gid, groups, &ngroups);
fmt = " groups=%u";
- for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
- if (lastid == (id = groups[cnt]))
+ for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) {
+ if (lastgid == (gid = groups[cnt]))
continue;
- (void)printf(fmt, id);
+ (void)printf(fmt, gid);
fmt = " %u";
- if (gr = getgrgid(id))
+ if (gr = getgrgid(gid))
(void)printf("(%s)", gr->gr_name);
- lastid = id;
+ lastgid = gid;
}
(void)printf("\n");
}
diff --git a/usr.bin/id/whoami.1 b/usr.bin/id/whoami.1
index 7cf7b43..738e346 100644
--- a/usr.bin/id/whoami.1
+++ b/usr.bin/id/whoami.1
@@ -31,7 +31,7 @@
.\"
.\" @(#)whoami.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd "June 6, 1993"
+.Dd June 6, 1993
.Dt WHOAMI 1
.UC
.Sh NAME
diff --git a/usr.bin/id/whoami.sh b/usr.bin/id/whoami.sh
index 372b7da..1c24bcc 100644
--- a/usr.bin/id/whoami.sh
+++ b/usr.bin/id/whoami.sh
@@ -32,6 +32,8 @@
# SUCH DAMAGE.
#
# @(#)whoami.sh 8.1 (Berkeley) 6/6/93
-#
+# $Id$
+
+PATH=/bin:/usr/bin; export PATH
-id -un
+exec id -un
diff --git a/usr.bin/indent/indent.1 b/usr.bin/indent/indent.1
index c44964a..7f92a23 100644
--- a/usr.bin/indent/indent.1
+++ b/usr.bin/indent/indent.1
@@ -160,9 +160,9 @@ if (...) {
}
.Ed
.Pp
-.It Fl c n
+.It Fl c Ns Ar n
The column in which comments on code start. The default is 33.
-.It Fl cd n
+.It Fl cd Ns Ar n
The column in which comments on declarations start. The default
is for these comments to start in the same column as those on code.
.It Fl cdb , ncdb
@@ -171,8 +171,8 @@ this option enabled, comments look like this:
.Bd -literal -offset indent
.ne 3
/*
- * this is a comment
- */
+ * this is a comment
+ */
.Ed
.Pp
Rather than like this:
@@ -205,7 +205,7 @@ Causes case labels to be indented
tab stops to the right of the containing
.Ic switch
statement.
-.Fl cli0 .5
+.Fl cli0.5
causes case labels to be indented half a tab stop. The
default is
.Fl cli0 .
@@ -264,7 +264,7 @@ in effect:
.ne 2
.Bd -literal -offset indent
p1 = first_procedure(second_procedure(p2, p3),
-\ \ third_procedure(p4,p5));
+\ \ third_procedure(p4, p5));
.Ed
.Pp
.ne 5
@@ -273,7 +273,7 @@ With
in effect (the default) the code looks somewhat clearer:
.Bd -literal -offset indent
p1\ =\ first_procedure(second_procedure(p2,\ p3),
-\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,p5));
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,\ p5));
.Ed
.Pp
.ne 5
@@ -281,7 +281,7 @@ Inserting two more newlines we get:
.Bd -literal -offset indent
p1\ =\ first_procedure(second_procedure(p2,
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p3),
-\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p5));
.Ed
.It Fl npro
diff --git a/usr.bin/indent/io.c b/usr.bin/indent/io.c
index 4615db2..ae98242 100644
--- a/usr.bin/indent/io.c
+++ b/usr.bin/indent/io.c
@@ -314,18 +314,18 @@ compute_label_target()
/*
* Copyright (C) 1976 by the Board of Trustees of the University of Illinois
- *
+ *
* All rights reserved
- *
- *
+ *
+ *
* NAME: fill_buffer
- *
+ *
* FUNCTION: Reads one block of input into input_buffer
- *
+ *
* HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A
* Willcox of CAC Added check for switch back to partly full input
* buffer from temporary buffer
- *
+ *
*/
int
fill_buffer()
@@ -416,31 +416,31 @@ fill_buffer()
/*
* Copyright (C) 1976 by the Board of Trustees of the University of Illinois
- *
+ *
* All rights reserved
- *
- *
+ *
+ *
* NAME: pad_output
- *
+ *
* FUNCTION: Writes tabs and spaces to move the current column up to the desired
* position.
- *
+ *
* ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
- *
+ *
* PARAMETERS: current integer The current column target
* nteger The desired column
- *
+ *
* RETURNS: Integer value of the new column. (If current >= target, no action is
* taken, and current is returned.
- *
+ *
* GLOBALS: None
- *
+ *
* CALLS: write (sys)
- *
+ *
* CALLED BY: dump_line
- *
+ *
* HISTORY: initial coding November 1976 D A Willcox of CAC
- *
+ *
*/
pad_output(current, target) /* writes tabs and blanks (if necessary) to
* get the current output position up to the
@@ -469,23 +469,23 @@ pad_output(current, target) /* writes tabs and blanks (if necessary) to
/*
* Copyright (C) 1976 by the Board of Trustees of the University of Illinois
- *
+ *
* All rights reserved
- *
- *
+ *
+ *
* NAME: count_spaces
- *
+ *
* FUNCTION: Find out where printing of a given string will leave the current
* character position on output.
- *
+ *
* ALGORITHM: Run thru input string and add appropriate values to current
* position.
- *
+ *
* RETURNS: Integer value of position after printing "buffer" starting in column
* "current".
- *
+ *
* HISTORY: initial coding November 1976 D A Willcox of CAC
- *
+ *
*/
int
count_spaces(current, buffer)
diff --git a/usr.bin/indent/lexi.c b/usr.bin/indent/lexi.c
index 8da9d2c..69f2431 100644
--- a/usr.bin/indent/lexi.c
+++ b/usr.bin/indent/lexi.c
@@ -120,7 +120,7 @@ int
lexi()
{
int unary_delim; /* this is set to 1 if the current token
- *
+ *
* forces a following operator to be unary */
static int last_code; /* the last token type returned */
static int l_struct; /* set to 1 if the last token was 'struct' */
@@ -146,7 +146,7 @@ lexi()
* we have a character or number
*/
register char *j; /* used for searching thru list of
- *
+ *
* reserved words */
register struct templ *p;
diff --git a/usr.bin/indent/parse.c b/usr.bin/indent/parse.c
index fef22cf..f3a4b44 100644
--- a/usr.bin/indent/parse.c
+++ b/usr.bin/indent/parse.c
@@ -205,12 +205,12 @@ parse(tk)
/*
* NAME: reduce
- *
+ *
* FUNCTION: Implements the reduce part of the parsing algorithm
- *
+ *
* ALGORITHM: The following reductions are done. Reductions are repeated
* until no more are possible.
- *
+ *
* Old TOS New TOS
* <stmt> <stmt> <stmtl>
* <stmtl> <stmt> <stmtl>
@@ -222,22 +222,22 @@ parse(tk)
* for <stmt> <stmt>
* while <stmt> <stmt>
* "dostmt" while <stmt>
- *
+ *
* On each reduction, ps.i_l_follow (the indentation for the following line)
* is set to the indentation level associated with the old TOS.
- *
+ *
* PARAMETERS: None
- *
+ *
* RETURNS: Nothing
- *
+ *
* GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
- *
+ *
* CALLS: None
- *
+ *
* CALLED BY: parse
- *
+ *
* HISTORY: initial coding November 1976 D A Willcox of CAC
- *
+ *
*/
/*----------------------------------------------*\
| REDUCTION PHASE |
diff --git a/usr.bin/ipcrm/Makefile b/usr.bin/ipcrm/Makefile
new file mode 100644
index 0000000..6cc7bda
--- /dev/null
+++ b/usr.bin/ipcrm/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+PROG= ipcrm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ipcrm/ipcrm.1 b/usr.bin/ipcrm/ipcrm.1
new file mode 100644
index 0000000..8a3a532
--- /dev/null
+++ b/usr.bin/ipcrm/ipcrm.1
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1994 Adam Glass
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. The name of the Author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ipcrm.1,v 1.3 1997/02/22 19:55:11 peter Exp $
+.\""
+.Dd August 8, 1994
+.Dt ipcrm 1
+.Os
+.Sh NAME
+.Nm ipcrm
+.Nd remove the specified message queues, semaphore sets, and shared memory
+segments
+.Sh SYNOPSIS
+.Nm ipcrm
+.Op Fl q Ar msqid
+.Op Fl m Ar shmid
+.Op Fl s Ar semid
+.Op Fl Q Ar msgkey
+.Op Fl M Ar shmkey
+.Op Fl S Ar semkey
+.Ar ...
+.Sh DESCRIPTION
+.Nm ipcrm
+removes the specified message queues, semaphores and shared memory
+segments. These System V IPC objects can be specified by their
+creation id or any associated key.
+.Pp
+The following options are used to specify which IPC objects will be removed. Any number and combination of these options can be used:
+.Bl -tag -width indent
+.It Fl q Ar msqid
+Remove the message queue associated with the id
+.Nm msqid
+from the system.
+.It Fl m Ar shmid
+Mark the shared memory segment associated with id
+.Nm shmid
+for removal.
+This marked segment will be destroyed after the last detach.
+.It Fl s Ar semid
+Removes the semaphore set associated with id
+.Nm semid
+from the system.
+.It Fl Q Ar msgkey
+Remove the message queue associated with key
+.Nm msgkey
+from the system.
+.It Fl M Ar shmkey
+Mark the shared memory segment associated with key
+.Nm shmkey
+for removal.
+This marked segment will be destroyed after the last detach.
+.It Fl S Ar semkey
+Remove the semaphore set associated with key
+.Nm semkey
+from the system.
+.El
+.Pp
+The identifiers and keys associated with these System V IPC objects can be
+determined by using
+.Xr ipcs 1
+.
+.Sh SEE ALSO
+.Xr ipcs 1
diff --git a/usr.bin/ipcrm/ipcrm.c b/usr.bin/ipcrm/ipcrm.c
new file mode 100644
index 0000000..717c826
--- /dev/null
+++ b/usr.bin/ipcrm/ipcrm.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1994 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Glass.
+ * 4. The name of the Author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#define IPC_TO_STR(x) (x == 'Q' ? "msq" : (x == 'M' ? "shm" : "sem"))
+#define IPC_TO_STRING(x) (x == 'Q' ? "message queue" : \
+ (x == 'M' ? "shared memory segment" : "semaphore"))
+
+int signaled;
+
+void usage()
+{
+ fprintf(stderr, "usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]\n");
+ fprintf(stderr, " [-Q msgkey] [-M shmkey] [-S semkey] ...]\n");
+ exit(1);
+}
+
+int msgrm(key, id)
+ key_t key;
+ int id;
+{
+ if (key) {
+ id = msgget(key, 0);
+ if (id == -1)
+ return -1;
+ }
+ return msgctl(id, IPC_RMID, NULL);
+}
+
+int shmrm(key, id)
+ key_t key;
+ int id;
+{
+ if (key) {
+ id = shmget(key, 0, 0);
+ if (id == -1)
+ return -1;
+ }
+ return shmctl(id, IPC_RMID, NULL);
+}
+
+int semrm(key, id)
+ key_t key;
+ int id;
+{
+ union semun arg;
+
+ if (key) {
+ id = semget(key, 0, 0);
+ if (id == -1)
+ return -1;
+ }
+ return semctl(id, 0, IPC_RMID, arg);
+}
+
+void not_configured()
+{
+ signaled++;
+}
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+
+{
+ int c, result, errflg, target_id;
+ key_t target_key;
+
+ errflg = 0;
+ signal(SIGSYS, not_configured);
+ while ((c = getopt(argc, argv, ":q:m:s:Q:M:S:")) != -1) {
+
+ signaled = 0;
+ switch (c) {
+ case 'q':
+ case 'm':
+ case 's':
+ target_id = atoi(optarg);
+ if (c == 'q')
+ result = msgrm(0, target_id);
+ else if (c == 'm')
+ result = shmrm(0, target_id);
+ else
+ result = semrm(0, target_id);
+ if (result < 0) {
+ errflg++;
+ if (!signaled)
+ warn("%sid(%d): ", IPC_TO_STR(toupper(c)), target_id);
+ else
+ warnx("%ss are not configured in the running kernel",
+ IPC_TO_STRING(toupper(c)));
+ }
+ break;
+ case 'Q':
+ case 'M':
+ case 'S':
+ target_key = atol(optarg);
+ if (target_key == IPC_PRIVATE) {
+ warnx("can't remove private %ss", IPC_TO_STRING(c));
+ continue;
+ }
+ if (c == 'Q')
+ result = msgrm(target_key, 0);
+ else if (c == 'M')
+ result = shmrm(target_key, 0);
+ else
+ result = semrm(target_key, 0);
+ if (result < 0) {
+ errflg++;
+ if (!signaled)
+ warn("%key(%ld): ", IPC_TO_STR(c), target_key);
+ else
+ warnx("%ss are not configured in the running kernel",
+ IPC_TO_STRING(c));
+ }
+ break;
+ case ':':
+ fprintf(stderr, "option -%c requires an argument\n", optopt);
+ usage();
+ case '?':
+ fprintf(stderr, "unrecognized option: -%c\n", optopt);
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "unknown argument: %s\n", argv[optind]);
+ usage();
+ }
+ exit(errflg);
+}
+
diff --git a/usr.bin/ipcs/Makefile b/usr.bin/ipcs/Makefile
new file mode 100644
index 0000000..5e4afcc
--- /dev/null
+++ b/usr.bin/ipcs/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG= ipcs
+BINGRP= kmem
+BINMODE= 2555
+DPADD+= ${LIBKVM}
+LDADD+= -lkvm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ipcs/ipcs.1 b/usr.bin/ipcs/ipcs.1
new file mode 100644
index 0000000..c0e53cb
--- /dev/null
+++ b/usr.bin/ipcs/ipcs.1
@@ -0,0 +1,151 @@
+.\"
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by SigmaSoft, Th. Lockert.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: ipcs.1,v 1.5 1997/02/22 19:55:15 peter Exp $
+.\"
+.Dd June 18, 1994
+.Dt "IPCS" 1
+.Os FreeBSD 2.0
+.Sh NAME
+.Nm ipcs
+.Nd report System V interprocess communication facilities status
+.Sh SYNOPSIS
+.Nm ipcs
+.Op Fl abcmopqstMQST
+.Op Fl C Ar system
+.Op Fl N Ar core
+.Sh DESCRIPTION
+The
+.Nm ipcs
+program provides information on System V interprocess communication
+(IPC) facilities on the system.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Show the maximum amount of information possible when
+displaying active semaphores, message queues,
+and shared memory segments.
+(This is shorthand for specifying the
+.Fl b ,
+.Fl c ,
+.Fl o ,
+.Fl p ,
+and
+.Fl t
+options.)
+.It Fl b
+Show the maximum allowed sizes for active semaphores, message queues,
+and shared memory segments. The
+.Dq maximum allowed size
+is the maximum number of bytes in a message on a message queue,
+the size of a shared memory segment,
+or the number of semaphores in a set of semaphores.
+.It Fl c
+Show the creator's name and group for active semaphores, message queues,
+and shared memory segments.
+.It Fl m
+Display information about active shared memory segments.
+.It Fl o
+Show outstanding usage for active message queues,
+and shared memory segments. The
+.Dq outstanding usage
+is the number of messages in a message queue, or the number
+of processes attached to a shared memory segment.
+.It Fl p
+Show the process ID information for active semaphores, message queues,
+and shared memory segments. The
+.Dq process ID information
+is the last process to send a message to or receive a message from
+a message queue,
+the process that created a semaphore, or the last process to attach
+or detach a shared memory segment.
+.It Fl q
+Display information about active message queues.
+.It Fl s
+Display information about active semaphores.
+.It Fl t
+Show access times for active semaphores, message queues,
+and shared memory segments. The access times is the time
+of the last control operation on an IPC object,
+the last send or receive of a message,
+the last attach or detach of a shared memory segment,
+or the last operation on a semaphore.
+.It Fl C Ar system
+Extract the name list from the specified system instead of the
+default
+.Dq Pa /kernel .
+.It Fl M
+Display system information about shared memory.
+.It Fl N Ar core
+Extract values associated with the name list from the specified
+core instead of the default
+.Dq Pa /dev/kmem .
+.It Fl Q
+Display system information about messages queues.
+.It Fl S
+Display system information about semaphores.
+.It Fl T
+Display system information about shared memory, message queues
+and semaphores.
+.El
+.Pp
+If none of the
+.Fl M ,
+.Fl m ,
+.Fl Q ,
+.Fl q ,
+.Fl S ,
+or
+.Fl s
+options are specified, information about all active IPC facilities is
+listed.
+.Sh RESTRICTIONS
+System data structures may change while
+.Nm ipcs
+is running; the output of
+.Nm ipcs
+is not guaranteed to be consistent.
+.Sh BUGS
+This manual page is woefully incomplete, because it does not
+at all attempt to explain the information printed by
+.Nm ipcs .
+.Sh FILES
+.Bl -tag -width /etc/passwd -compact
+.It Pa /dev/kmem
+default kernel memory
+.It Pa /kernel
+default system name list
+.El
+.Sh SEE ALSO
+.Xr ipcrm 1
+.Sh AUTHOR
+.Bl -tag
+Thorsten Lockert <tholo@sigmasoft.com>
+.El
diff --git a/usr.bin/ipcs/ipcs.c b/usr.bin/ipcs/ipcs.c
new file mode 100644
index 0000000..28db9b0
--- /dev/null
+++ b/usr.bin/ipcs/ipcs.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ipcs.c,v 1.8 1997/02/22 19:55:18 peter Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <err.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#define KERNEL
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/msg.h>
+
+struct semid_ds *sema;
+struct seminfo seminfo;
+struct msginfo msginfo;
+struct msqid_ds *msqids;
+struct shminfo shminfo;
+struct shmid_ds *shmsegs;
+
+int semconfig __P((int,...));
+void usage __P((void));
+
+static struct nlist symbols[] = {
+ {"_sema"},
+#define X_SEMA 0
+ {"_seminfo"},
+#define X_SEMINFO 1
+ {"_semu"},
+#define X_SEMU 2
+ {"_msginfo"},
+#define X_MSGINFO 3
+ {"_msqids"},
+#define X_MSQIDS 4
+ {"_shminfo"},
+#define X_SHMINFO 5
+ {"_shmsegs"},
+#define X_SHMSEGS 6
+ {NULL}
+};
+
+static kvm_t *kd;
+
+char *
+fmt_perm(mode)
+ u_short mode;
+{
+ static char buffer[100];
+
+ buffer[0] = '-';
+ buffer[1] = '-';
+ buffer[2] = ((mode & 0400) ? 'r' : '-');
+ buffer[3] = ((mode & 0200) ? 'w' : '-');
+ buffer[4] = ((mode & 0100) ? 'a' : '-');
+ buffer[5] = ((mode & 0040) ? 'r' : '-');
+ buffer[6] = ((mode & 0020) ? 'w' : '-');
+ buffer[7] = ((mode & 0010) ? 'a' : '-');
+ buffer[8] = ((mode & 0004) ? 'r' : '-');
+ buffer[9] = ((mode & 0002) ? 'w' : '-');
+ buffer[10] = ((mode & 0001) ? 'a' : '-');
+ buffer[11] = '\0';
+ return (&buffer[0]);
+}
+
+void
+cvt_time(t, buf)
+ time_t t;
+ char *buf;
+{
+ struct tm *tm;
+
+ if (t == 0) {
+ strcpy(buf, "no-entry");
+ } else {
+ tm = localtime(&t);
+ sprintf(buf, "%2d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ }
+}
+#define SHMINFO 1
+#define SHMTOTAL 2
+#define MSGINFO 4
+#define MSGTOTAL 8
+#define SEMINFO 16
+#define SEMTOTAL 32
+
+#define BIGGEST 1
+#define CREATOR 2
+#define OUTSTANDING 4
+#define PID 8
+#define TIME 16
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int display = SHMINFO | MSGINFO | SEMINFO;
+ int option = 0;
+ char *core = NULL, *namelist = NULL;
+ int i;
+
+ while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
+ switch (i) {
+ case 'M':
+ display = SHMTOTAL;
+ break;
+ case 'm':
+ display = SHMINFO;
+ break;
+ case 'Q':
+ display = MSGTOTAL;
+ break;
+ case 'q':
+ display = MSGINFO;
+ break;
+ case 'S':
+ display = SEMTOTAL;
+ break;
+ case 's':
+ display = SEMINFO;
+ break;
+ case 'T':
+ display = SHMTOTAL | MSGTOTAL | SEMTOTAL;
+ break;
+ case 'a':
+ option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
+ break;
+ case 'b':
+ option |= BIGGEST;
+ break;
+ case 'C':
+ core = optarg;
+ break;
+ case 'c':
+ option |= CREATOR;
+ break;
+ case 'N':
+ namelist = optarg;
+ break;
+ case 'o':
+ option |= OUTSTANDING;
+ break;
+ case 'p':
+ option |= PID;
+ break;
+ case 't':
+ option |= TIME;
+ break;
+ default:
+ usage();
+ }
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (namelist != NULL || core != NULL)
+ setgid(getgid());
+
+ if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL)
+ exit(1);
+
+ switch (kvm_nlist(kd, symbols)) {
+ case 0:
+ break;
+ case -1:
+ errx(1, "unable to read kernel symbol table.");
+ default:
+#ifdef notdef /* they'll be told more civilly later */
+ warnx("nlist failed");
+ for (i = 0; symbols[i].n_name != NULL; i++)
+ if (symbols[i].n_value == 0)
+ warnx("symbol %s not found",
+ symbols[i].n_name);
+ break;
+#endif
+ }
+
+ if ((display & (MSGINFO | MSGTOTAL)) &&
+ kvm_read(kd, symbols[X_MSGINFO].n_value, &msginfo, sizeof(msginfo))) {
+
+ if (display & MSGTOTAL) {
+ printf("msginfo:\n");
+ printf("\tmsgmax: %6d\t(max characters in a message)\n",
+ msginfo.msgmax);
+ printf("\tmsgmni: %6d\t(# of message queues)\n",
+ msginfo.msgmni);
+ printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
+ msginfo.msgmnb);
+ printf("\tmsgtql: %6d\t(max # of messages in system)\n",
+ msginfo.msgtql);
+ printf("\tmsgssz: %6d\t(size of a message segment)\n",
+ msginfo.msgssz);
+ printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
+ msginfo.msgseg);
+ }
+ if (display & MSGINFO) {
+ struct msqid_ds *xmsqids;
+
+ kvm_read(kd, symbols[X_MSQIDS].n_value, &msqids, sizeof(msqids));
+ xmsqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni);
+ kvm_read(kd, (u_long) msqids, xmsqids, sizeof(struct msqid_ds) * msginfo.msgmni);
+
+ printf("Message Queues:\n");
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & OUTSTANDING)
+ printf(" CBYTES QNUM");
+ if (option & BIGGEST)
+ printf(" QBYTES");
+ if (option & PID)
+ printf(" LSPID LRPID");
+ if (option & TIME)
+ printf(" STIME RTIME CTIME");
+ printf("\n");
+ for (i = 0; i < msginfo.msgmni; i += 1) {
+ if (xmsqids[i].msg_qbytes != 0) {
+ char stime_buf[100], rtime_buf[100],
+ ctime_buf[100];
+ struct msqid_ds *msqptr = &xmsqids[i];
+
+ cvt_time(msqptr->msg_stime, stime_buf);
+ cvt_time(msqptr->msg_rtime, rtime_buf);
+ cvt_time(msqptr->msg_ctime, ctime_buf);
+
+ printf("q %6d %10d %s %8s %8s",
+ IXSEQ_TO_IPCID(i, msqptr->msg_perm),
+ msqptr->msg_perm.key,
+ fmt_perm(msqptr->msg_perm.mode),
+ user_from_uid(msqptr->msg_perm.uid, 0),
+ group_from_gid(msqptr->msg_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(msqptr->msg_perm.cuid, 0),
+ group_from_gid(msqptr->msg_perm.cgid, 0));
+
+ if (option & OUTSTANDING)
+ printf(" %6d %6d",
+ msqptr->msg_cbytes,
+ msqptr->msg_qnum);
+
+ if (option & BIGGEST)
+ printf(" %6d",
+ msqptr->msg_qbytes);
+
+ if (option & PID)
+ printf(" %6d %6d",
+ msqptr->msg_lspid,
+ msqptr->msg_lrpid);
+
+ if (option & TIME)
+ printf("%s %s %s",
+ stime_buf,
+ rtime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+ } else
+ if (display & (MSGINFO | MSGTOTAL)) {
+ fprintf(stderr,
+ "SVID messages facility not configured in the system\n");
+ }
+ if ((display & (SHMINFO | SHMTOTAL)) &&
+ kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo, sizeof(shminfo))) {
+ if (display & SHMTOTAL) {
+ printf("shminfo:\n");
+ printf("\tshmmax: %7d\t(max shared memory segment size)\n",
+ shminfo.shmmax);
+ printf("\tshmmin: %7d\t(min shared memory segment size)\n",
+ shminfo.shmmin);
+ printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n",
+ shminfo.shmmni);
+ printf("\tshmseg: %7d\t(max shared memory segments per process)\n",
+ shminfo.shmseg);
+ printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n",
+ shminfo.shmall);
+ }
+ if (display & SHMINFO) {
+ struct shmid_ds *xshmids;
+
+ kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs, sizeof(shmsegs));
+ xshmids = malloc(sizeof(struct shmid_ds) * shminfo.shmmni);
+ kvm_read(kd, (u_long) shmsegs, xshmids, sizeof(struct shmid_ds) *
+ shminfo.shmmni);
+
+ printf("Shared Memory:\n");
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & OUTSTANDING)
+ printf(" NATTCH");
+ if (option & BIGGEST)
+ printf(" SEGSZ");
+ if (option & PID)
+ printf(" CPID LPID");
+ if (option & TIME)
+ printf(" ATIME DTIME CTIME");
+ printf("\n");
+ for (i = 0; i < shminfo.shmmni; i += 1) {
+ if (xshmids[i].shm_perm.mode & 0x0800) {
+ char atime_buf[100], dtime_buf[100],
+ ctime_buf[100];
+ struct shmid_ds *shmptr = &xshmids[i];
+
+ cvt_time(shmptr->shm_atime, atime_buf);
+ cvt_time(shmptr->shm_dtime, dtime_buf);
+ cvt_time(shmptr->shm_ctime, ctime_buf);
+
+ printf("m %6d %10d %s %8s %8s",
+ IXSEQ_TO_IPCID(i, shmptr->shm_perm),
+ shmptr->shm_perm.key,
+ fmt_perm(shmptr->shm_perm.mode),
+ user_from_uid(shmptr->shm_perm.uid, 0),
+ group_from_gid(shmptr->shm_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(shmptr->shm_perm.cuid, 0),
+ group_from_gid(shmptr->shm_perm.cgid, 0));
+
+ if (option & OUTSTANDING)
+ printf(" %6d",
+ shmptr->shm_nattch);
+
+ if (option & BIGGEST)
+ printf(" %6d",
+ shmptr->shm_segsz);
+
+ if (option & PID)
+ printf(" %6d %6d",
+ shmptr->shm_cpid,
+ shmptr->shm_lpid);
+
+ if (option & TIME)
+ printf("%s %s %s",
+ atime_buf,
+ dtime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+ } else
+ if (display & (SHMINFO | SHMTOTAL)) {
+ fprintf(stderr,
+ "SVID shared memory facility not configured in the system\n");
+ }
+ if ((display & (SEMINFO | SEMTOTAL)) &&
+ kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo, sizeof(seminfo))) {
+ struct semid_ds *xsema;
+
+ if (display & SEMTOTAL) {
+ printf("seminfo:\n");
+ printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
+ seminfo.semmap);
+ printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
+ seminfo.semmni);
+ printf("\tsemmns: %6d\t(# of semaphores in system)\n",
+ seminfo.semmns);
+ printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
+ seminfo.semmnu);
+ printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
+ seminfo.semmsl);
+ printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
+ seminfo.semopm);
+ printf("\tsemume: %6d\t(max # of undo entries per process)\n",
+ seminfo.semume);
+ printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
+ seminfo.semusz);
+ printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
+ seminfo.semvmx);
+ printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
+ seminfo.semaem);
+ }
+ if (display & SEMINFO) {
+ if (semconfig(SEM_CONFIG_FREEZE) != 0) {
+ perror("semconfig");
+ fprintf(stderr,
+ "Can't lock semaphore facility - winging it...\n");
+ }
+ kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema));
+ xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni);
+ kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * seminfo.semmni);
+
+ printf("Semaphores:\n");
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & BIGGEST)
+ printf(" NSEMS");
+ if (option & TIME)
+ printf(" OTIME CTIME");
+ printf("\n");
+ for (i = 0; i < seminfo.semmni; i += 1) {
+ if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) {
+ char ctime_buf[100], otime_buf[100];
+ struct semid_ds *semaptr = &xsema[i];
+ int j, value;
+ union semun junk;
+
+ cvt_time(semaptr->sem_otime, otime_buf);
+ cvt_time(semaptr->sem_ctime, ctime_buf);
+
+ printf("s %6d %10d %s %8s %8s",
+ IXSEQ_TO_IPCID(i, semaptr->sem_perm),
+ semaptr->sem_perm.key,
+ fmt_perm(semaptr->sem_perm.mode),
+ user_from_uid(semaptr->sem_perm.uid, 0),
+ group_from_gid(semaptr->sem_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(semaptr->sem_perm.cuid, 0),
+ group_from_gid(semaptr->sem_perm.cgid, 0));
+
+ if (option & BIGGEST)
+ printf(" %6d",
+ semaptr->sem_nsems);
+
+ if (option & TIME)
+ printf("%s %s",
+ otime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ }
+
+ (void) semconfig(SEM_CONFIG_THAW);
+
+ printf("\n");
+ }
+ } else
+ if (display & (SEMINFO | SEMTOTAL)) {
+ fprintf(stderr, "SVID semaphores facility not configured in the system\n");
+ }
+ kvm_close(kd);
+
+ exit(0);
+}
+
+void
+usage()
+{
+
+ fprintf(stderr,
+ "usage: ipcs [-abcmopqst] [-C corefile] [-N namelist]\n");
+ exit(1);
+}
diff --git a/usr.bin/join/join.c b/usr.bin/join/join.c
index 122c62f..7b1e779 100644
--- a/usr.bin/join/join.c
+++ b/usr.bin/join/join.c
@@ -122,7 +122,7 @@ main(argc, argv)
aflag = vflag = 0;
obsolete(argv);
- while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != EOF) {
+ while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != -1) {
switch (ch) {
case '\01': /* See comment in obsolete(). */
aflag = 1;
@@ -276,7 +276,7 @@ slurp(F)
* join field.
*/
F->setcnt = 0;
- for (lastlp = NULL;; ++F->setcnt, lastlp = lp) {
+ for (lastlp = NULL;; ++F->setcnt) {
/*
* If we're out of space to hold line structures, allocate
* more. Initialize the structure so that we know that this
@@ -294,16 +294,17 @@ slurp(F)
if (lastlp != NULL)
lastlp = &F->set[F->setcnt - 1];
}
-
+
/*
* Get any pushed back line, else get the next line. Allocate
* space as necessary. If taking the line from the stack swap
* the two structures so that we don't lose space allocated to
* either structure. This could be avoided by doing another
* level of indirection, but it's probably okay as is.
- * but it's probably okay as is.
*/
lp = &F->set[F->setcnt];
+ if (F->setcnt)
+ lastlp = &F->set[F->setcnt - 1];
if (F->pushbool) {
tmp = F->set[F->setcnt];
F->set[F->setcnt] = F->set[F->pushback];
@@ -454,7 +455,7 @@ outfield(lp, fieldno, out_empty)
if (needsep++)
(void)printf("%c", *tabchar);
if (!ferror(stdout))
- if (lp->fieldcnt < fieldno || out_empty) {
+ if (lp->fieldcnt <= fieldno || out_empty) {
if (empty != NULL)
(void)printf("%s", empty);
} else {
@@ -512,7 +513,7 @@ obsolete(argv)
return;
switch (ap[1]) {
case 'a':
- /*
+ /*
* The original join allowed "-a", which meant the
* same as -a1 plus -a2. POSIX 1003.2, Draft 11.2
* only specifies this as "-a 1" and "a -2", so we
diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c
index 442d083..39b6d55 100644
--- a/usr.bin/jot/jot.c
+++ b/usr.bin/jot/jot.c
@@ -53,6 +53,7 @@ static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>
#define REPS_DEF 100
#define BEGIN_DEF 1
@@ -95,9 +96,12 @@ main(argc, argv)
getargs(argc, argv);
if (randomize) {
*x = (ender - begin) * (ender > begin ? 1 : -1);
- srandom((int) s);
+ if (s == -1.0)
+ srandomdev();
+ else
+ srandom((unsigned long) s);
for (*i = 1; *i <= reps || infinity; (*i)++) {
- *y = (double) random() / INT_MAX;
+ *y = (double) random() / LONG_MAX;
putdata(*y * *x + begin, reps - *i);
}
}
@@ -140,11 +144,11 @@ getargs(ac, av)
break;
case 's':
if ((*av)[2])
- strcpy(sepstring, *av + 2);
+ sepstring = *av + 2;
else if (!--ac)
error("Need string after -s", "");
else
- strcpy(sepstring, *++av);
+ sepstring = *++av;
break;
case 'p':
if ((*av)[2])
@@ -249,7 +253,7 @@ getargs(ac, av)
mask = 015;
break;
case 012:
- s = (randomize ? time(0) : STEP_DEF);
+ s = (randomize ? -1.0 : STEP_DEF);
mask = 013;
break;
case 013:
@@ -257,11 +261,12 @@ getargs(ac, av)
begin = BEGIN_DEF;
else if (reps == 0)
error("Must specify begin if reps == 0", "");
- begin = ender - reps * s + s;
+ else
+ begin = ender - reps * s + s;
mask = 0;
break;
case 014:
- s = (randomize ? time(0) : STEP_DEF);
+ s = (randomize ? -1.0 : STEP_DEF);
mask = 015;
break;
case 015:
@@ -273,7 +278,7 @@ getargs(ac, av)
break;
case 016:
if (randomize)
- s = time(0);
+ s = -1.0;
else if (reps == 0)
error("Infinite sequences cannot be bounded",
"");
diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile
index 0f8add8..5cc1042 100644
--- a/usr.bin/kdump/Makefile
+++ b/usr.bin/kdump/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= kdump
-CFLAGS+=-I${.CURDIR}/../ktrace
+CFLAGS+=-I${.CURDIR}/../ktrace -I${.CURDIR}/../..
SRCS= kdump.c ioctl.c subr.c
.PATH: ${.CURDIR}/../ktrace
CLEANFILES+=ioctl.c
diff --git a/usr.bin/kdump/kdump.1 b/usr.bin/kdump/kdump.1
index 5db704f..99a1471 100644
--- a/usr.bin/kdump/kdump.1
+++ b/usr.bin/kdump/kdump.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)kdump.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt KDUMP 1
@@ -38,14 +39,15 @@
.Nm kdump
.Nd display kernel trace data
.Sh SYNOPSIS
-.Nm kdump
+.Nm
.Op Fl dnlRT
.Op Fl f Ar file
.Op Fl m Ar maxdata
-.Op Fl t Op cnis
+.Op Fl t Op cnisu
.Sh DESCRIPTION
-.Nm Kdump
-displays the kernel trace files produced with
+The
+.Nm
+command displays the kernel trace files produced with
.Xr ktrace 1
in human readable format.
By default, the file
@@ -70,7 +72,7 @@ bytes when decoding
.It Fl n
Suppress ad hoc translations.
Normally
-.Nm kdump
+.Nm
tries to decode many system calls into a more human readable format.
For example,
.Xr ioctl 2
@@ -85,7 +87,7 @@ easily amenable to further processing.
Display relative timestamps (time since previous entry).
.It Fl T
Display absolute timestamps for each entry (seconds since epoch).
-.It Fl t Ar cnis
+.It Fl t Ar cnisuw
See the
.Fl t
option of
@@ -95,6 +97,6 @@ option of
.Xr ktrace 1
.Sh HISTORY
The
-.Nm kdump
-command appears in
+.Nm
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 5a1f279..debf08a 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -38,9 +38,13 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#define KERNEL
+extern int errno;
+#include <sys/errno.h>
+#undef KERNEL
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/time.h>
@@ -48,18 +52,11 @@ static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
#include <sys/ktrace.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
-#define KERNEL
-#include <sys/errno.h>
-#undef KERNEL
-
-#include <err.h>
-#include <signal.h>
+#include <vis.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <vis.h>
-
+#include <locale.h>
#include "ktrace.h"
int timestamp, decimal, fancy = 1, tail, maxdata;
@@ -68,17 +65,20 @@ struct ktr_header ktr_header;
#define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
-int
main(argc, argv)
int argc;
char *argv[];
{
+ extern int optind;
+ extern char *optarg;
int ch, ktrlen, size;
register void *m;
int trpoints = ALL_POINTS;
- while ((ch = getopt(argc, argv, "f:dlm:nRTt:")) != -1)
- switch (ch) {
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1)
+ switch((char)ch) {
case 'f':
tracefile = optarg;
break;
@@ -102,36 +102,51 @@ main(argc, argv)
break;
case 't':
trpoints = getpoints(optarg);
- if (trpoints < 0)
- errx(1, "unknown trace point in %s", optarg);
+ if (trpoints < 0) {
+ (void)fprintf(stderr,
+ "kdump: unknown trace point in %s\n",
+ optarg);
+ exit(1);
+ }
break;
default:
usage();
}
- argv += optind;
- argc -= optind;
- if (argc > 1)
+ if (argc > optind)
usage();
m = (void *)malloc(size = 1025);
- if (m == NULL)
- errx(1, "%s", strerror(ENOMEM));
- if (!freopen(tracefile, "r", stdin))
- err(1, "%s", tracefile);
+ if (m == NULL) {
+ (void)fprintf(stderr, "kdump: %s.\n", strerror(ENOMEM));
+ exit(1);
+ }
+ if (!freopen(tracefile, "r", stdin)) {
+ (void)fprintf(stderr,
+ "kdump: %s: %s.\n", tracefile, strerror(errno));
+ exit(1);
+ }
while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
if (trpoints & (1<<ktr_header.ktr_type))
dumpheader(&ktr_header);
- if ((ktrlen = ktr_header.ktr_len) < 0)
- errx(1, "bogus length 0x%x", ktrlen);
+ if ((ktrlen = ktr_header.ktr_len) < 0) {
+ (void)fprintf(stderr,
+ "kdump: bogus length 0x%x\n", ktrlen);
+ exit(1);
+ }
if (ktrlen > size) {
m = (void *)realloc(m, ktrlen+1);
- if (m == NULL)
- errx(1, "%s", strerror(ENOMEM));
+ if (m == NULL) {
+ (void)fprintf(stderr,
+ "kdump: %s.\n", strerror(ENOMEM));
+ exit(1);
+ }
size = ktrlen;
}
- if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
- errx(1, "data too short");
+ if (ktrlen && fread_tail(m, ktrlen, 1) == 0) {
+ (void)fprintf(stderr, "kdump: data too short.\n");
+ exit(1);
+ }
if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
continue;
switch (ktr_header.ktr_type) {
@@ -153,6 +168,9 @@ main(argc, argv)
case KTR_CSW:
ktrcsw((struct ktr_csw *)m);
break;
+ case KTR_USER:
+ ktruser(ktrlen, m);
+ break;
}
if (tail)
(void)fflush(stdout);
@@ -198,6 +216,9 @@ dumpheader(kth)
case KTR_CSW:
type = "CSW";
break;
+ case KTR_USER:
+ type = "USER";
+ break;
default:
(void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
type = unknown;
@@ -218,7 +239,7 @@ dumpheader(kth)
#include <sys/syscall.h>
#define KTRACE
-#include "/sys/kern/syscalls.c"
+#include <sys/kern/syscalls.c>
#undef KTRACE
int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
@@ -231,58 +252,55 @@ static char *ptrace_ops[] = {
ktrsyscall(ktr)
register struct ktr_syscall *ktr;
{
- register argsize = ktr->ktr_argsize;
- register register_t *ap;
+ register narg = ktr->ktr_narg;
+ register int *ip;
char *ioctlname();
if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
(void)printf("[%d]", ktr->ktr_code);
else
(void)printf("%s", syscallnames[ktr->ktr_code]);
- ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
- if (argsize) {
+ ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
+ if (narg) {
char c = '(';
if (fancy) {
if (ktr->ktr_code == SYS_ioctl) {
char *cp;
if (decimal)
- (void)printf("(%ld", (long)*ap);
+ (void)printf("(%d", *ip);
else
- (void)printf("(%#lx", (long)*ap);
- ap++;
- argsize -= sizeof(register_t);
- if ((cp = ioctlname(*ap)) != NULL)
+ (void)printf("(%#x", *ip);
+ ip++;
+ narg--;
+ if ((cp = ioctlname(*ip)) != NULL)
(void)printf(",%s", cp);
else {
if (decimal)
- (void)printf(",%ld",
- (long)*ap);
+ (void)printf(",%d", *ip);
else
- (void)printf(",%#lx ",
- (long)*ap);
+ (void)printf(",%#x ", *ip);
}
c = ',';
- ap++;
- argsize -= sizeof(register_t);
+ ip++;
+ narg--;
} else if (ktr->ktr_code == SYS_ptrace) {
- if (*ap >= 0 && *ap <=
- sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
- (void)printf("(%s", ptrace_ops[*ap]);
+ if (*ip <= PT_STEP && *ip >= 0)
+ (void)printf("(%s", ptrace_ops[*ip]);
else
- (void)printf("(%ld", (long)*ap);
+ (void)printf("(%d", *ip);
c = ',';
- ap++;
- argsize -= sizeof(register_t);
+ ip++;
+ narg--;
}
}
- while (argsize) {
+ while (narg) {
if (decimal)
- (void)printf("%c%ld", c, (long)*ap);
+ (void)printf("%c%d", c, *ip);
else
- (void)printf("%c%#lx", c, (long)*ap);
+ (void)printf("%c%#x", c, *ip);
c = ',';
- ap++;
- argsize -= sizeof(register_t);
+ ip++;
+ narg--;
}
(void)putchar(')');
}
@@ -324,7 +342,7 @@ ktrsysret(ktr)
(void)putchar('\n');
}
-ktrnamei(cp, len)
+ktrnamei(cp, len)
char *cp;
{
(void)printf("\"%.*s\"\n", len, cp);
@@ -350,13 +368,14 @@ ktrgenio(ktr, len)
else
screenwidth = 80;
}
- printf("fd %d %s %d bytes\n", ktr->ktr_fd,
- ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
+ printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
+ ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
+ datalen == 1 ? "" : "s");
if (maxdata && datalen > maxdata)
datalen = maxdata;
(void)printf(" \"");
col = 8;
- for (; datalen > 0; datalen--, dp++) {
+ for (;datalen > 0; datalen--, dp++) {
(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
cp = visbuf;
/*
@@ -392,27 +411,47 @@ ktrgenio(ktr, len)
(void)printf("\"\n");
}
+char *signames[] = {
+ "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */
+ "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */
+ "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */
+ "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */
+ "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */
+ "USR2", NULL, /* 31 - 32 */
+};
+
ktrpsig(psig)
struct ktr_psig *psig;
{
- (void)printf("SIG%s ", sys_signame[psig->signo]);
+ (void)printf("SIG%s ", signames[psig->signo]);
if (psig->action == SIG_DFL)
(void)printf("SIG_DFL\n");
else
- (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
- (u_long)psig->action, psig->mask, psig->code);
+ (void)printf("caught handler=0x%x mask=0x%x code=0x%x\n",
+ (u_int)psig->action, psig->mask, psig->code);
}
ktrcsw(cs)
struct ktr_csw *cs;
{
(void)printf("%s %s\n", cs->out ? "stop" : "resume",
- cs->user ? "user" : "kernel");
+ cs->user ? "user" : "kernel");
+}
+
+ktruser(len, p)
+ int len;
+ unsigned char *p;
+{
+ (void)printf("%d ", len);
+ while (len--)
+ (void)printf(" %02x", *p++);
+ (void)printf("\n");
+
}
usage()
{
(void)fprintf(stderr,
- "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n");
+ "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
exit(1);
}
diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls
index b165d05..8ff0cd6 100644
--- a/usr.bin/kdump/mkioctls
+++ b/usr.bin/kdump/mkioctls
@@ -1,45 +1,18 @@
-#!/bin/sh -
-#
-# Copyright (c) 1994
-# The Regents of the University of California. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-# must display the following acknowledgement:
-# This product includes software developed by the University of
-# California, Berkeley and its contributors.
-# 4. Neither the name of the University nor the names of its contributors
-# may be used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# @(#)mkioctls 8.2 (Berkeley) 4/28/95
-#
-awk '
+# XXX should we use an ANSI cpp?
+# XXX does -I$DESTDIR/usr/include actually work?
+(echo "#include <sys/ioctl.h>"
+ echo "#include <sys/ioctl_compat.h>"
+) | cpp -I$DESTDIR/usr/include -dM | awk '
BEGIN {
print "#include <sys/param.h>"
+ print "#include <sys/queue.h>"
print "#include <sys/socket.h>"
print "#include <sys/socketvar.h>"
+ print "#include <sys/time.h>"
print "#include <net/route.h>"
print "#include <net/if.h>"
+ print "#include <netinet/in.h>"
+ print "#include <netinet/ip_mroute.h>"
print "#include <sys/termios.h>"
print "#define COMPAT_43"
print "#include <sys/ioctl.h>"
@@ -65,4 +38,4 @@ END {
print "\n\treturn(NULL);"
print "}"
}
-' /usr/include/sys/ioctl.h /usr/include/sys/ioctl_compat.h
+'
diff --git a/usr.bin/key/Makefile b/usr.bin/key/Makefile
new file mode 100644
index 0000000..c150e63
--- /dev/null
+++ b/usr.bin/key/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 5.6 (Berkeley) 3/5/91
+#
+
+PROG= key
+SRCS= skey.c
+MAN1= key.1
+
+CFLAGS+= -D_SKEY_INTERNAL
+
+DPADD= ${LIBSKEY} ${LIBMD}
+LDADD= -lskey -lmd
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/key/key.1 b/usr.bin/key/key.1
new file mode 100644
index 0000000..7399233
--- /dev/null
+++ b/usr.bin/key/key.1
@@ -0,0 +1,49 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)key.1 1.0 (Bellcore) 12/2/91
+.\"
+.lt 6.0i
+.TH KEY 1 "2 December 1991"
+.AT 3
+.SH NAME
+key \- Stand\-alone program for computing responses to S/Key challenges.
+.SH SYNOPSIS
+.B key [\-n <count>] <Sequence> <key>
+.SH DESCRIPTION
+.I key
+Takes the optional count of the number of one time access
+passwords to print
+along with a (maximum) sequence number and key as command line args,
+it prompts for the user's secret password, and produces both word
+and hex format responses.
+.SH EXAMPLE
+.sh
+ Usage example:
+.sp 0
+ >key \-n 5 99 th91334
+.sp 0
+ Enter password: <your secret password is entered here>
+.sp 0
+ OMEN US HORN OMIT BACK AHOY
+.sp 0
+ .... 4 more passwords.
+.sp 0
+ >
+.LP
+.SH OPTIONS
+.LP
+.B \-n <count>
+the number of one time access passwords to print.
+The default is one.
+.SH DIAGNOSTICS
+.SH BUGS
+.LP
+.SH SEE ALSO
+.BR skey(1),
+.BR keyinit(1),
+.\" .BR keysu(1),
+.BR keyinfo(1)
+.SH AUTHOR
+Command by Phil Karn, Neil M. Haller, John S. Walden
+.SH CONTACT
+staff@thumper.bellcore.com
diff --git a/usr.bin/key/skey.c b/usr.bin/key/skey.c
new file mode 100644
index 0000000..0196ebe
--- /dev/null
+++ b/usr.bin/key/skey.c
@@ -0,0 +1,129 @@
+/* Stand-alone program for computing responses to S/Key challenges.
+ * Takes the iteration count and seed as command line args, prompts
+ * for the user's key, and produces both word and hex format responses.
+ *
+ * Usage example:
+ * >skey 88 ka9q2
+ * Enter password:
+ * OMEN US HORN OMIT BACK AHOY
+ * C848 666B 6435 0A93
+ * >
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __MSDOS__
+#include <dos.h>
+#else /* Assume BSD unix */
+#include <fcntl.h>
+#endif
+
+#include <skey.h>
+
+char *readpass();
+void usage();
+int getopt();
+extern int optind;
+extern char *optarg;
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int n,cnt,i;
+ char passwd[256],passwd2[256];
+ char key[8];
+ char *seed;
+ char buf[33];
+ char *slash;
+
+ cnt = 1;
+ while((i = getopt(argc,argv,"n:")) != -1){
+ switch(i){
+ case 'n':
+ cnt = atoi(optarg);
+ break;
+ }
+ }
+ /* could be in the form <number>/<seed> */
+ if(argc <= optind + 1){
+ /*look for / in it */
+ if(argc <= optind){
+ usage(argv[0]);
+ return 1;
+ }
+
+ slash = strchr(argv[optind], '/');
+ if(slash == NULL){
+ usage(argv[0]);
+ return 1;
+ }
+ *slash++ = '\0';
+ seed = slash;
+
+ if((n = atoi(argv[optind])) < 0){
+ fprintf(stderr,"%s not positive\n",argv[optind]);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ else {
+
+ if((n = atoi(argv[optind])) < 0){
+ fprintf(stderr,"%s not positive\n",argv[optind]);
+ usage(argv[0]);
+ return 1;
+ }
+ seed = argv[++optind];
+ }
+ fprintf(stderr,"Reminder - Do not use this program while logged in via telnet or rlogin.\n");
+
+ /* Get user's secret password */
+ for(;;){
+ fprintf(stderr,"Enter secret password: ");
+ readpass(passwd,sizeof(passwd));
+ break;
+ /************
+ fprintf(stderr,"Again secret password: ");
+ readpass(passwd2,sizeof(passwd));
+ if(strcmp(passwd,passwd2) == 0) break;
+ fprintf(stderr, "Sorry no match\n");
+ **************/
+
+ }
+
+ /* Crunch seed and password into starting key */
+ if(keycrunch(key,seed,passwd) != 0){
+ fprintf(stderr,"%s: key crunch failed\n",argv[0]);
+ return 1;
+ }
+ if(cnt == 1){
+ while(n-- != 0)
+ f(key);
+ printf("%s\n",btoe(buf,key));
+#ifdef HEXIN
+ printf("%s\n",put8(buf,key));
+#endif
+ } else {
+ for(i=0;i<=n-cnt;i++)
+ f(key);
+ for(;i<=n;i++){
+#ifdef HEXIN
+ printf("%d: %-29s %s\n",i,btoe(buf,key),put8(buf,key));
+#else
+ printf("%d: %-29s\n",i,btoe(buf,key));
+#endif
+ f(key);
+ }
+ }
+ return 0;
+}
+
+void
+usage(s)
+char *s;
+{
+ fprintf(stderr,"Usage: %s [-n count] <sequence #>[/] <key> \n",s);
+}
diff --git a/usr.bin/keyinfo/Makefile b/usr.bin/keyinfo/Makefile
new file mode 100644
index 0000000..93bfb8a
--- /dev/null
+++ b/usr.bin/keyinfo/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 5.5 (Berkeley) 7/1/90
+
+BINOWN= root
+BINMODE=4555
+
+MAN1= keyinfo.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/keyinfo.pl ${DESTDIR}${BINDIR}/keyinfo
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keyinfo/keyinfo.1 b/usr.bin/keyinfo/keyinfo.1
new file mode 100644
index 0000000..9ddea83
--- /dev/null
+++ b/usr.bin/keyinfo/keyinfo.1
@@ -0,0 +1,50 @@
+.ll 6i
+.pl 10.5i
+.\" from: @(#)keyinfo.1 1.1 (Bellcore) 7/20/93
+.\" $Id$
+.\"
+.lt 6.0i
+.TH KEYINFO 1 "26 April 1996"
+.AT 3
+.SH NAME
+keyinfo \- display current S/Key sequence number and seed
+.SH SYNOPSIS
+.B keyinfo [username]
+.SH DESCRIPTION
+.I keyinfo
+takes an optional user name and displays the user\'s current sequence
+number and seed found in the S/Key database /etc/skeykeys.
+.sp 1
+The command can be useful when generating a list of passwords for use
+on a field trip, by combining with the command
+.I key
+in the form:
+.sp
+ > key \-n <number of passwords> `keyinfo`|lpr
+.SH EXAMPLE
+.sh
+Usage example:
+.sp 0
+ > keyinfo
+.sp 0
+ 0098 ws91340
+.LP
+.SH ARGUMENTS
+.TP
+.B username
+The S/key user to display the information for. The default is
+to display S/Key information on the user who invokes the command.
+.SH DIAGNOSTICS
+.I keyinfo
+exits with status 0 if a key for the requested user has been found,
+else with status 1.
+.SH SEE ALSO
+.BR keyinit(1),
+.BR key(1)
+.SH AUTHOR
+Original command by Phil Karn, Neil M. Haller, John S. Walden.
+Rewritten in Perl by
+.ie t J\(:org \%Wunsch
+.el Joerg Wunsch
+so it can be made setuid, and the S/Key keys file can be read-protected
+from the users.
diff --git a/usr.bin/keyinfo/keyinfo.pl b/usr.bin/keyinfo/keyinfo.pl
new file mode 100644
index 0000000..260a724
--- /dev/null
+++ b/usr.bin/keyinfo/keyinfo.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/suidperl
+#
+# Search /etc/skeykeys for the skey string for this user OR user specified
+# in 1st parameter.
+#
+# $Id$
+#
+
+die "usage: keyinfo [user]\n" unless $#ARGV < 1;
+
+open(K, "/etc/skeykeys") || exit 1;
+
+if ($#ARGV == 0) {
+ $user = $ARGV[0];
+} else {
+ $user = (getpwuid($<))[0];
+}
+
+while (<K>) {
+ ($id, $seq, $serial) = split;
+ if ($id eq $user) {
+ printf "%d %s\n", $seq - 1, $serial;
+ exit 0;
+ }
+}
+exit 1;
+
diff --git a/usr.bin/keyinit/Makefile b/usr.bin/keyinit/Makefile
new file mode 100644
index 0000000..2796a3d
--- /dev/null
+++ b/usr.bin/keyinit/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 5.6 (Berkeley) 3/5/91
+#
+PROG= keyinit
+MAN1= keyinit.1
+SRCS= skeyinit.c
+
+CFLAGS+= -D_SKEY_INTERNAL
+
+BINOWN= root
+BINMODE=4555
+
+DPADD= ${LIBSKEY} ${LIBMD}
+LDADD= -lskey -lmd
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keyinit/keyinit.1 b/usr.bin/keyinit/keyinit.1
new file mode 100644
index 0000000..aba9cee
--- /dev/null
+++ b/usr.bin/keyinit/keyinit.1
@@ -0,0 +1,64 @@
+.ll 6i
+.pl 10.5i
+.\" @(#)keyinit.1 1.0 (Bellcore) 7/20/93
+.\"
+.lt 6.0i
+.TH KEYINIT 1 "20 July 1993"
+.AT 3
+.SH NAME
+keyinit \- Change password or add user to S/Key authentication system.
+.SH SYNOPSIS
+.B keyinit [\-s] [<user ID >]
+.SH DESCRIPTION
+.I keyinit
+initializes the system so you can use S/Key one-time passwords to
+login. The program will ask you to enter a secret pass phrase; enter a
+phrase of several words in response. After the S/Key database has been
+updated you can login using either your regular UNIX password or using
+S/Key one-time passwords.
+.PP
+When logging in from another machine you can avoid typing a real
+password over the network, by typing your S/Key pass phrase to the
+\fIkey\fR command on the local machine: the program will respond with
+the one-time password that you should use to log into the remote
+machine. This is most conveniently done with cut-and-paste operations
+using a mouse. Alternatively, you can pre-compute one-time passwords
+using the \fIkey\fR command and carry them with you on a piece of paper.
+.PP
+\fIkeyinit\fR requires you to type your secret password, so it should
+be used only on a secure terminal. For example, on the console of a
+workstation. If you are using \fIkeyinit\fR while logged in over an
+untrusted network, follow the instructions given below with the \-s
+option.
+.SH OPTIONS
+.IP \-s
+Set secure mode where the user is expected to have used a secure
+machine to generate the first one time password. Without the \-s the
+system will assume you are direct connected over secure communications
+and prompt you for your secret password.
+The \-s option also allows one to set the seed and count for complete
+control of the parameters. You can use keyinit -s in combination with
+the
+.I key
+command to set the seed and count if you do not like the defaults.
+To do this run keyinit in one window and put in your count and seed
+then run key in another window to generate the correct 6 English words
+for that count and seed. You can then
+"cut" and "paste" them or copy them into the keyinit window.
+.sp
+.LP
+.B <user ID>
+the ID for the user to be changed/added
+.SH DIAGNOSTICS
+.SH FILES
+.TP
+/etc/skeykeys data base of information for S/Key system.
+.SH BUGS
+.LP
+.SH SEE ALSO
+.BR skey(1),
+.BR key(1),
+.BR su(1),
+.BR keyinfo(1)
+.SH AUTHOR
+Command by Phil Karn, Neil M. Haller, John S. Walden
diff --git a/usr.bin/keyinit/skeyinit.c b/usr.bin/keyinit/skeyinit.c
new file mode 100644
index 0000000..0a739b3
--- /dev/null
+++ b/usr.bin/keyinit/skeyinit.c
@@ -0,0 +1,191 @@
+/* change password or add user to S/KEY authentication system.
+ * S/KEY is a tradmark of Bellcore */
+
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <time.h>
+
+#include <skey.h>
+
+extern int optind;
+extern char *optarg;
+
+#define NAMELEN 2
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ struct skey skey;
+ int rval,n,nn,i,defaultsetup;
+ char seed[18],tmp[80],key[8];
+ struct passwd *ppuser,*pp;
+ char defaultseed[17], passwd[256],passwd2[256] ;
+
+
+ time_t now;
+ struct tm *tm;
+ char tbuf[27],buf[60];
+ char lastc, me[80];
+ int l;
+
+ time(&now);
+#if 0 /* Choose a more random seed */
+ tm = localtime(&now);
+ strftime(tbuf, sizeof(tbuf), "%M%j", tm);
+#else
+ sprintf(tbuf, "%05ld", (long) (now % 100000));
+#endif
+ gethostname(defaultseed,NAMELEN);
+ strcpy(&defaultseed[NAMELEN],tbuf);
+
+ pp = ppuser = getpwuid(getuid());
+ strcpy(me,pp->pw_name);
+ defaultsetup = 1;
+ if( argc > 1){
+ if(strcmp("-s", argv[1]) == 0)
+ defaultsetup = 0;
+ else
+ pp = getpwnam(argv[1]);
+ if(argc > 2)
+ pp = getpwnam(argv[2]);
+
+ }
+ if(pp == NULL){
+ printf("User unknown\n");
+ return 1;
+ }
+ if(strcmp( pp->pw_name,me) != 0){
+ if(getuid() != 0){
+ /* Only root can change other's passwds */
+ printf("Permission denied.\n");
+ return(1);
+ }
+ }
+
+
+
+ rval = skeylookup(&skey,pp->pw_name);
+ switch(rval){
+ case -1:
+ perror("error in opening database");
+ return 1;
+ case 0:
+ printf("Updating %s:\n",pp->pw_name);
+ printf("Old key: %s\n",skey.seed);
+ /* lets be nice if they have a skey.seed that ends in 0-8 just add one*/
+ l = strlen(skey.seed);
+ if( l > 0){
+ lastc = skey.seed[l-1];
+ if( isdigit(lastc) && lastc != '9' ){
+ strcpy(defaultseed, skey.seed);
+ defaultseed[l-1] = lastc + 1;
+ }
+ if( isdigit(lastc) && lastc == '9' && l < 16){
+ strcpy(defaultseed, skey.seed);
+ defaultseed[l-1] = '0';
+ defaultseed[l] = '0';
+ defaultseed[l+1] = '\0';
+ }
+ }
+ break;
+ case 1:
+ skey.val = 0; /* XXX */
+ printf("Adding %s:\n",pp->pw_name);
+ break;
+ }
+ n = 99;
+ if( ! defaultsetup){
+ printf("Reminder you need the 6 english words from the key command.\n");
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ printf("Enter sequence count from 1 to 9999: ");
+ fgets(tmp,sizeof(tmp),stdin);
+ n = atoi(tmp);
+ if(n > 0 && n < 10000)
+ break; /* Valid range */
+ printf("Count must be > 0 and < 10000\n");
+ }
+ }
+ if( !defaultsetup){
+ printf("Enter new key [default %s]: ", defaultseed);
+ fflush(stdout);
+ fgets(seed,sizeof(seed),stdin);
+ rip(seed);
+ if(strlen(seed) > 16){
+ printf("Seed truncated to 16 chars\n");
+ seed[16] = '\0';
+ }
+ if( seed[0] == '\0') strcpy(seed,defaultseed);
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ printf("s/key %d %s\ns/key access password: ",n,seed);
+ fgets(tmp,sizeof(tmp),stdin);
+ rip(tmp);
+ if(tmp[0] == '?'){
+ printf("Enter 6 English words from secure S/Key calculation.\n");
+ continue;
+ }
+ if(tmp[0] == '\0'){
+ exit(1);
+ }
+ if(etob(key,tmp) == 1 || atob8(key,tmp) == 0)
+ break; /* Valid format */
+ printf("Invalid format, try again with 6 English words.\n");
+ }
+ } else {
+ /* Get user's secret password */
+ fprintf(stderr,"Reminder - Only use this method if you are directly connected.\n");
+ fprintf(stderr,"If you are using telnet or rlogin exit with no password and use keyinit -s.\n");
+ for(i=0;;i++){
+ if(i >= 2) exit(1);
+ fprintf(stderr,"Enter secret password: ");
+ readpass(passwd,sizeof(passwd));
+ if(passwd[0] == '\0'){
+ exit(1);
+ }
+ fprintf(stderr,"Again secret password: ");
+ readpass(passwd2,sizeof(passwd));
+ if(passwd2[0] == '\0'){
+ exit(1);
+ }
+ if(strlen(passwd) < 4 && strlen(passwd2) < 4) {
+ fprintf(stderr, "Sorry your password must be longer\n\r");
+ exit(1);
+ }
+ if(strcmp(passwd,passwd2) == 0) break;
+ fprintf(stderr, "Sorry no match\n");
+
+
+ }
+ strcpy(seed,defaultseed);
+
+ /* Crunch seed and password into starting key */
+ if(keycrunch(key,seed,passwd) != 0){
+ fprintf(stderr,"%s: key crunch failed\n",argv[0]);
+ return 1;
+ }
+ nn = n;
+ while(nn-- != 0)
+ f(key);
+ }
+ time(&now);
+ tm = localtime(&now);
+ strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
+ if (skey.val == NULL)
+ skey.val = (char *) malloc(16+1);
+
+
+ btoa8(skey.val,key);
+ fprintf(skey.keyfile,"%s %04d %-16s %s %-21s\n",pp->pw_name,n,
+ seed,skey.val, tbuf);
+ fclose(skey.keyfile);
+ printf("\nID %s s/key is %d %s\n",pp->pw_name,n,seed);
+ printf("%s\n",btoe(buf,key));
+#ifdef HEXIN
+ printf("%s\n",put8(buf,key));
+#endif
+ return 0;
+}
diff --git a/usr.bin/keylogin/Makefile b/usr.bin/keylogin/Makefile
new file mode 100644
index 0000000..971a746
--- /dev/null
+++ b/usr.bin/keylogin/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= keylogin
+SRCS= keylogin.c
+
+MAN1= keylogin.1
+
+LDADD+= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keylogin/keylogin.1 b/usr.bin/keylogin/keylogin.1
new file mode 100644
index 0000000..424454982
--- /dev/null
+++ b/usr.bin/keylogin/keylogin.1
@@ -0,0 +1,25 @@
+.\" @(#)keylogin.1 1.5 91/03/11 TIRPC 1.0;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\"
+.TH KEYLOGIN 1 "9 September 1987"
+.SH NAME
+keylogin \- decrypt and store secret key
+.SH SYNOPSIS
+.B keylogin
+.SH DESCRIPTION
+.LP
+.B keylogin
+prompts the user for their login password, and uses it to decrypt
+the user's secret key stored in the
+.BR publickey (5)
+database. Once decrypted, the user's key is stored by the local
+key server process
+.BR keyserv (8C)
+to be used by any secure network services, such as
+.SM NFS\s0.
+.SH "SEE ALSO"
+.BR chkey (1),
+.BR login (1),
+.BR publickey (5),
+.BR keyserv (8C),
+.BR newkey (8)
diff --git a/usr.bin/keylogin/keylogin.c b/usr.bin/keylogin/keylogin.c
new file mode 100644
index 0000000..55529c8
--- /dev/null
+++ b/usr.bin/keylogin/keylogin.c
@@ -0,0 +1,80 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)keylogin.c 1.4 91/03/11 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Set secret key on local machine
+ */
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+
+int
+main()
+{
+ char fullname[MAXNETNAMELEN + 1];
+ struct netstarg netst;
+
+ if (!getnetname(fullname)) {
+ fprintf(stderr, "netname lookup failed -- make sure the ");
+ fprintf(stderr, "system domain name is set.\n");
+ exit(1);
+ }
+
+ if (! getsecretkey(fullname, (char *)&(netst.st_priv_key),
+ getpass("Password:"))) {
+ fprintf(stderr, "Can't find %s's secret key\n", fullname);
+ exit(1);
+ }
+ if (netst.st_priv_key[0] == 0) {
+ fprintf(stderr, "Password incorrect for %s\n", fullname);
+ exit(1);
+ }
+
+ netst.st_pub_key[0] = 0;
+ netst.st_netname = strdup(fullname);
+
+ if (key_setnet(&netst) < 0) {
+ fprintf(stderr, "Could not set %s's secret key\n", fullname);
+ fprintf(stderr, "Maybe the keyserver is down?\n");
+ exit(1);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
diff --git a/usr.bin/keylogout/Makefile b/usr.bin/keylogout/Makefile
new file mode 100644
index 0000000..c5bd6f5
--- /dev/null
+++ b/usr.bin/keylogout/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= keylogout
+SRCS= keylogout.c
+
+MAN1= keylogout.1
+
+LDADD+= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/keylogout/keylogout.1 b/usr.bin/keylogout/keylogout.1
new file mode 100644
index 0000000..cbc5613
--- /dev/null
+++ b/usr.bin/keylogout/keylogout.1
@@ -0,0 +1,44 @@
+.\" @(#)keylogout.1 1.4 91/03/11 TIRPC 1.0; from 1.3 89/07/26 SMI;
+.TH KEYLOGOUT 1 "15 April 1989"
+.SH NAME
+keylogout \- delete stored secret key
+.SH SYNOPSIS
+.B keylogout
+[
+.B \-f
+]
+.SH DESCRIPTION
+.IX "keylogout command" "" "\fLkeylogout\fR command"
+.LP
+.B keylogout
+deletes the key stored by the key server process
+.BR keyserv (8C)
+to be used by any secure network services, such as
+.SM NFS\s0.
+Further access to the key is revoked,
+however current session keys may remain valid till they expire,
+or are refreshed.
+This option will cause any background jobs that need secure
+.SM RPC
+services to fail, and any scheduled
+.B at
+jobs that need the key to fail.
+Also since only one copy is kept on a machine of the key,
+it is a bad idea to place this in your
+.B .logout
+file since it will affect other sessions on the same machine.
+.SH OPTIONS
+.TP
+.B \-f
+Forget the rootkey.
+This will break secure
+.SM NFS\s0
+if it is done on a server.
+.LP
+.SH "SEE ALSO"
+.BR chkey (1),
+.BR login (1),
+.BR keylogin (1),
+.BR publickey (5),
+.BR keyserv (8C),
+.BR newkey (8)
diff --git a/usr.bin/keylogout/keylogout.c b/usr.bin/keylogout/keylogout.c
new file mode 100644
index 0000000..51c03b1
--- /dev/null
+++ b/usr.bin/keylogout/keylogout.c
@@ -0,0 +1,68 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * unset the secret key on local machine
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+
+int
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ static char secret[HEXKEYBYTES + 1];
+
+ if (geteuid() == 0) {
+ if ((argc != 2 ) || (strcmp(argv[1], "-f") != 0)) {
+ fprintf(stderr,
+"keylogout by root would break all servers that use secure rpc!\n");
+ fprintf(stderr,
+"root may use keylogout -f to do this (at your own risk)!\n");
+ exit(-1);
+ }
+ }
+
+ if (key_setsecret(secret) < 0) {
+ fprintf(stderr, "Could not unset your secret key.\n");
+ fprintf(stderr, "Maybe the keyserver is down?\n");
+ exit(1);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
diff --git a/usr.bin/killall/Makefile b/usr.bin/killall/Makefile
new file mode 100644
index 0000000..17cfc53
--- /dev/null
+++ b/usr.bin/killall/Makefile
@@ -0,0 +1,7 @@
+MAN1= killall.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/killall.pl ${DESTDIR}${BINDIR}/killall
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/killall/killall.1 b/usr.bin/killall/killall.1
new file mode 100644
index 0000000..a05c529
--- /dev/null
+++ b/usr.bin/killall/killall.1
@@ -0,0 +1,134 @@
+.\" Copyright (C) 1995 by Joerg Wunsch, Dresden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 25, 1995
+.Os FreeBSD 2.2
+.Dt KILLALL 1
+.Sh NAME
+.Nm killall
+.Nd kill processes by name
+.Sh SYNOPSIS
+.Nm killall
+.Op Fl d \&| Ns Fl v
+.Op Fl h \&| Ns Fl \&?
+.Op Fl help
+.Op Fl l
+.Op Fl m
+.Op Fl s
+.Op Fl SIGNAL
+.Ar procname ...
+.Sh DESCRIPTION
+.Nm Killall
+kills processes selected by name, as opposed to the selection by pid
+as done by
+.Xr kill 1 .
+By default, it will send a
+.Dv TERM
+signal to all processes with an effective UID identical to the
+caller of
+.Nm
+that match the name
+.Ar procname .
+The super-user is allowed to kill any process.
+.Pp
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl d \&| Ns Fl v
+Be more verbose about what will be done. For a single
+.Fl d
+option, a list of the processes that will be sent the signal will be
+printed, or a message indicating that no matching processes have been
+found. If the option
+.Fl d
+has been specified at least twice, the effective UID, PID, and name
+of all processes found in
+.Xr procfs 5
+will be listed in addition.
+.It Fl h \&| Ns Fl \&?
+.It Fl help
+Give a help on the command usage and exit.
+.It Fl l
+List the names of the available signals and exit, like in
+.Xr kill 1 .
+.It Fl m
+Match the argument
+.Ar procname
+as a (case insensitive) regular expression against the names
+of processes found in
+.Xr procfs 5 .
+CAUTION! This is dangerous, a single dot will match any process
+running under the effective UID of the caller. The regular expression
+syntax in effect is that used by
+.Xr perl 1 .
+.It Fl s
+Show only what would be done, but do net send any signal.
+.It Fl SIGNAL
+Send a different signal instead of the default
+.Dv TERM .
+The signal may be specified either as a name
+.Pq with \&or without a leading Dv SIG ,
+or numerically.
+.El
+
+.Sh ALL PROCESSES
+Sending a signal to all processes with uid
+.Nm XYZ
+is already supported by
+.Xr kill 1 .
+So use
+.Xr kill 1
+for this job (e.g. $ kill -TERM -1 or
+as root $ echo kill -TERM -1 | su -m <user>)
+
+
+.Sh DIAGNOSTICS
+The
+.Nm
+command will respond with a short usage message and exit with a status
+of 2 in case of a command error. A status of 1 will be returned if
+either no matching process has been found or not all processes have
+been signalled successfully. Otherwise, a status of 0 will be
+returned.
+.Pp
+Diagnostic messages will only be printed if requested by
+.Fl d
+options.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr procfs 5 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.1 .
+It has been modeled after the
+.Nm
+command as available on other platforms.
+.Sh AUTHOR
+The program has been contributed by Wolfram Schneider, this manual
+page has been written by
+.if n Joerg Wunsch.
+.if t J\(:org Wunsch.
diff --git a/usr.bin/killall/killall.pl b/usr.bin/killall/killall.pl
new file mode 100755
index 0000000..2e8dc66
--- /dev/null
+++ b/usr.bin/killall/killall.pl
@@ -0,0 +1,117 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1995-1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# killall - kill processes by name
+#
+# $Id$
+
+
+$ENV{'PATH'} = '/bin:/usr/bin'; # security
+$procfs = '/proc';
+$signal = 'SIGTERM'; # default signal for kill
+$debug = 0;
+$match = 0; # 0 match exactly program name
+$show = 0; # do nothings
+
+# see /sys/miscfs/procfs/procfs_status.c
+$PROC_NAME = 0;
+$PROC_EUID = 11;
+$PROC_RUID = 12;
+
+sub usage {
+ $! = 2;
+ die "killall [-?|-help] [-d] [-l] [-m] [-s] [-SIGNAL] procname ...\n";
+}
+
+$id = $<; # real uid of this process / your id
+while ($_ = $ARGV[0], /^-/) {
+ shift @ARGV;
+ if (/^--$/) { $_ = $ARGV[0]; last }
+ elsif (/^-(h|help|\?)$/) { &usage }
+ elsif (/^-[dv]$/) { $debug++ }
+ elsif (/^-l$/) { exec 'kill', '-l' }
+ elsif (/^-m$/) { $match = 1 }
+ elsif (/^-s$/) { $show = 1 }
+ elsif (/^-([a-z][a-z0-9]+|[0-9]+)$/i) { $signal = $1 }
+ elsif (/^-/) { &usage }
+}
+
+&usage if $#ARGV < 0; # no arguments
+die "Maybe $procfs is not mounted\n" unless -e "$procfs/0/status";
+
+while ($program = $ARGV[0]) {
+ shift @ARGV;
+ $thiskill = 0;
+
+ opendir(PROCFS, "$procfs") || die "$procfs $!\n";
+ print " PID EUID RUID COMMAND\n" if $debug > 1;
+
+ # quote meta characters
+ ($programMatch = $program) =~ s/(\W)/\\$1/g;
+
+ foreach (sort{$a <=> $b} grep(/^[0-9]/, readdir(PROCFS))) {
+ $status = "$procfs/$_/status";
+ $pid = $_;
+ next if $pid == $$; # don't kill yourself
+
+ open(STATUS, "$status") || next; # process maybe already terminated
+ while(<STATUS>) {
+ @proc = split;
+
+ printf "%5d %5d %5d %s\n", $pid, $proc[$PROC_EUID],
+ $proc[$PROC_RUID], $proc[$PROC_NAME] if $debug > 1;
+
+ if ( # match program name
+ ($proc[$PROC_NAME] eq $program ||
+ ($match && $proc[$PROC_NAME] =~ /$programMatch/oi)
+ ) &&
+ # id test
+ ($proc[$PROC_EUID] eq $id || # effective uid
+ $proc[$PROC_RUID] eq $id || # real uid
+ !$id)) # root
+ {
+ push(@kill, $pid);
+ $thiskill++;
+ }
+ }
+ close STATUS;
+ }
+ closedir PROCFS;
+
+ # nothing found
+ warn "No matching processes ``$program''\n" unless $thiskill;
+}
+
+# nothing found
+exit(1) if $#kill < 0;
+
+$signal =~ y/a-z/A-Z/; # signal name in upper case
+$signal =~ s/^SIG//; # strip a leading SIG if present
+print "kill -$signal @kill\n" if $debug || $show;
+
+$cnt = kill ($signal, @kill) unless $show; # kill processes
+exit(0) if $show || $cnt == $#kill + 1;
+exit(1);
diff --git a/usr.bin/ktrace/Makefile b/usr.bin/ktrace/Makefile
index 53a253f..7cfae99 100644
--- a/usr.bin/ktrace/Makefile
+++ b/usr.bin/ktrace/Makefile
@@ -1,6 +1,8 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# @(#)Makefile 1.1 (Berkeley) 6/6/93
+# $Id$
PROG= ktrace
SRCS= ktrace.c subr.c
+MLINKS= ktrace.1 trace.1 ktrace.1 truss.1
.include <bsd.prog.mk>
diff --git a/usr.bin/ktrace/ktrace.1 b/usr.bin/ktrace/ktrace.1
index d080b4e..af9e14c 100644
--- a/usr.bin/ktrace/ktrace.1
+++ b/usr.bin/ktrace/ktrace.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ktrace.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt KTRACE 1
@@ -38,20 +39,21 @@
.Nm ktrace
.Nd enable kernel process tracing
.Sh SYNOPSIS
-.Nm ktrace
+.Nm
.Op Fl aCcdi
.Op Fl f Ar trfile
.Op Fl g Ar pgrp
.Op Fl p Ar pid
.Op Fl t Ar trstr
-.Nm ktrace
+.Nm
.Op Fl adi
.Op Fl f Ar trfile
.Op Fl t Ar trstr
command
.Sh DESCRIPTION
-.Nm Ktrace
-enables kernel trace logging for the specified processes.
+The
+.Nm
+command enables kernel trace logging for the specified processes.
Kernel trace data is logged to the file
.Pa ktrace.out .
The kernel operations that are traced include system calls, namei
@@ -66,7 +68,7 @@ attempting to trace a process.
The following command is sufficient to disable tracing on all user owned
processes, and, if executed by root, all processes:
.Pp
-.Dl \&$ trace -C
+.Dl \&$ ktrace -C
.Pp
The trace file is not human readable; use
.Xr kdump 1
@@ -75,7 +77,7 @@ to decode it.
The options are as follows:
.Bl -tag -width indent
.It Fl a
-Append to the trace file instead of truncating it.
+Append to the trace file instead of recreating it.
.It Fl C
Disable tracing on all user owned processes, and, if executed by root, all
processes in the system.
@@ -114,6 +116,10 @@ trace
.Tn I/O
.It Cm s
trace signal processing
+.It Cm u
+userland traces
+.It Cm w
+context switches
.El
.It Ar command
Execute
@@ -156,8 +162,12 @@ on process 67
.Dl $ ktrace -C
.Sh SEE ALSO
.Xr kdump 1
+.Sh BUGS
+Only works if
+.Ar file
+is a regular file.
.Sh HISTORY
The
-.Nm ktrace
-command appears in
+.Nm
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/ktrace/ktrace.c b/usr.bin/ktrace/ktrace.c
index f40dbaf..534b09a 100644
--- a/usr.bin/ktrace/ktrace.c
+++ b/usr.bin/ktrace/ktrace.c
@@ -38,7 +38,11 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)ktrace.c 8.2 (Berkeley) 4/28/95";
+#if 0
+static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$Id: ktrace.c,v 1.9 1997/03/15 10:39:12 joerg Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -62,15 +66,19 @@ main(argc, argv)
int argc;
char **argv;
{
+ extern int optind;
+ extern char *optarg;
enum { NOTSET, CLEAR, CLEARALL } clear;
int append, ch, fd, inherit, ops, pid, pidset, trpoints;
char *tracefile;
+ mode_t omask;
+ struct stat sb;
clear = NOTSET;
append = ops = pidset = inherit = 0;
trpoints = DEF_POINTS;
tracefile = DEF_TRACEFILE;
- while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != EOF)
+ while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != -1)
switch((char)ch) {
case 'a':
append = 1;
@@ -132,9 +140,21 @@ main(argc, argv)
exit(0);
}
- if ((fd = open(tracefile, O_CREAT | O_WRONLY | (append ? 0 : O_TRUNC),
- DEFFILEMODE)) < 0)
- err(1, tracefile);
+ omask = umask(S_IRWXG|S_IRWXO);
+ if (append) {
+ if ((fd = open(tracefile, O_CREAT | O_WRONLY, DEFFILEMODE)) < 0)
+ err(1, tracefile);
+ if (fstat(fd, &sb) != 0 || sb.st_uid != getuid())
+ errx(1, "Refuse to append to %s not owned by you.",
+ tracefile);
+ } else {
+ if (unlink(tracefile) == -1 && errno != ENOENT)
+ err(1, "unlink %s", tracefile);
+ if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY,
+ DEFFILEMODE)) < 0)
+ err(1, tracefile);
+ }
+ (void)umask(omask);
(void)close(fd);
if (*argv) {
@@ -168,7 +188,7 @@ void
usage()
{
(void)fprintf(stderr,
-"usage:\tktrace [-aCcid] [-f trfile] [-g pgid] [-p pid] [-t [acgn]\n\tktrace [-aCcid] [-f trfile] [-t [acgn] command\n");
+"usage:\tktrace [-aCcid] [-f trfile] [-g pgid] [-p pid] [-t [cnisuv]\n\tktrace [-aCcid] [-f trfile] [-t [cnisuw] command\n");
exit(1);
}
diff --git a/usr.bin/ktrace/ktrace.h b/usr.bin/ktrace/ktrace.h
index 595b8bc..9f6431a 100644
--- a/usr.bin/ktrace/ktrace.h
+++ b/usr.bin/ktrace/ktrace.h
@@ -34,7 +34,7 @@
*/
#define DEF_POINTS (KTRFAC_SYSCALL | KTRFAC_SYSRET | KTRFAC_NAMEI | \
- KTRFAC_GENIO | KTRFAC_PSIG)
+ KTRFAC_GENIO | KTRFAC_PSIG | KTRFAC_USER)
#define ALL_POINTS (DEF_POINTS | KTRFAC_CSW)
diff --git a/usr.bin/ktrace/subr.c b/usr.bin/ktrace/subr.c
index 015801d..8af26ba 100644
--- a/usr.bin/ktrace/subr.c
+++ b/usr.bin/ktrace/subr.c
@@ -32,7 +32,11 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)subr.c 8.2 (Berkeley) 4/28/95";
+#if 0
+static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <sys/param.h>
@@ -65,6 +69,9 @@ getpoints(s)
case 's':
facs |= KTRFAC_PSIG;
break;
+ case 'u':
+ facs |= KTRFAC_USER;
+ break;
case 'w':
facs |= KTRFAC_CSW;
break;
diff --git a/usr.bin/kzip/Makefile b/usr.bin/kzip/Makefile
new file mode 100644
index 0000000..7c9f8c3
--- /dev/null
+++ b/usr.bin/kzip/Makefile
@@ -0,0 +1,6 @@
+# $Id$
+
+PROG= kzip
+MAN8= kzip.8
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/kzip/kzip.8 b/usr.bin/kzip/kzip.8
new file mode 100644
index 0000000..9989f1e
--- /dev/null
+++ b/usr.bin/kzip/kzip.8
@@ -0,0 +1,73 @@
+.\"
+.\" Copyright (c) 1996 David E. O'Brien
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd August 15, 1996
+.Os
+.Dt KZIP 8
+.Sh NAME
+.Nm kzip
+.Nd compresses kernels
+.Sh SYNOPSIS
+.Nm kzip
+.Op Fl v
+.Op Fl l Ar loadaddr
+.Sh DESCRIPTION
+This program compresses a kernel using
+.Xr gzip 1
+to reduce its disk storage requirements.
+It does not reduce the memory footprint once loaded into memory.
+You lose all the symbols, so usability is limited.
+Its main usage is making kernels for install and fixit floppies, etc.
+.Pp
+The following options are available:
+.Bl -tag -width flag
+.It Fl v
+Verbose mode, reports how much memory is being used by the kernel
+after compression. Also allows you to check to make sure your kernel
+is not going past the 4MB boundary.
+.It Fl l Ar loadaddr
+Specify the address to load the kernel into memory at.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility returns with exit code 1 if given invalid arguments.
+Exit code two means
+.Nm
+was unable to read or process the kernel file.
+.Sh SEE ALSO
+.Xr gzip 1
+.\" .Sh STANDARDS
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.0.5 .
+Obtained from Linux via 386BSD -- based on tools/build.c by Linus Torvalds,
+and ported to 386BSD by Serge Vakulenko.
+.Sh AUTHORS
+This man page was written by David E. O'Brien.
+.\" .Sh BUGS
diff --git a/usr.bin/kzip/kzip.c b/usr.bin/kzip/kzip.c
new file mode 100644
index 0000000..f4b9782
--- /dev/null
+++ b/usr.bin/kzip/kzip.c
@@ -0,0 +1,348 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 1993 Hannu Savolainen
+ * Ported to 386bsd by Serge Vakulenko
+ * based on tools/build.c by Linus Torvalds
+ * $Id: kzip.c,v 1.8 1997/03/29 04:30:19 imp Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <a.out.h>
+#include <string.h>
+
+#define MAXIMAGE (2*1024*1024)
+ /* This is the limit because a kzip'ed kernel loads at 3Mb and
+ * ends up at 1Mb
+ */
+void
+Usage(char *prog)
+{
+ fprintf(stderr,"usage:\n\t%s [-v] [ -l loadaddr] kernel\n", prog);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ pid_t Pext, Pgzip, Ppiggy, Pld;
+ int pipe1[2], pipe2[2];
+ int status, fdi, fdo, fdn, c, verbose;
+ int size;
+ struct exec hdr;
+ int zip_size, offset;
+ struct stat st;
+ u_long forceaddr = 0, addr, entry;
+ char *kernname;
+ char obj[BUFSIZ];
+ char out[BUFSIZ];
+ char base[32];
+
+ while ((c = getopt(argc, argv, "l:v")) != -1) {
+ switch (c) {
+ case 'l':
+ forceaddr = strtoul(optarg, NULL, 0);
+ if (forceaddr == 0) {
+ fprintf(stderr, "Invalid load address!\n");
+ exit(1);
+ }
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ Usage(argv[0]);
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1)
+ Usage(argv[0]);
+
+ argc -= optind;
+ argv += optind;
+
+ kernname = argv[0];
+
+ strcpy(obj, kernname); strcat(obj,".o");
+ strcpy(out, kernname); strcat(out,".kz");
+
+ fdi = open(kernname ,O_RDONLY);
+ if(fdi<0) {
+ perror(kernname);
+ return 2;
+ }
+
+ /* figure out how big the uncompressed image will be */
+ if (read (fdi, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
+ perror(argv[1]);
+ exit(2);
+ }
+
+ size = hdr.a_text + hdr.a_data + hdr.a_bss;
+ entry = hdr.a_entry & 0x00FFFFFF;
+
+ lseek (fdi, 0, SEEK_SET);
+
+ if (verbose) {
+ printf("real kernel start address will be: 0x%x\n", entry);
+ printf("real kernel end address will be: 0x%x\n", entry+size);
+ }
+
+
+ fdo = open(obj,O_WRONLY|O_TRUNC|O_CREAT,0666);
+ if(fdo<0) {
+ perror(obj);
+ return 2;
+ }
+
+ if (pipe(pipe1) < 0) { perror("pipe()"); return 1; }
+
+ if (pipe(pipe2) < 0) { perror("pipe()"); return 1; }
+
+ Pext = fork();
+ if (Pext < 0) { perror("fork()"); return 1; }
+ if (!Pext) {
+ dup2(fdi,0);
+ dup2(pipe1[1],1);
+ close(pipe1[0]); close(pipe1[1]);
+ close(pipe2[0]); close(pipe2[1]);
+ close(fdi); close(fdo);
+ extract(kernname);
+ exit(0);
+ }
+
+ Pgzip = fork();
+ if (Pgzip < 0) { perror("fork()"); return 1; }
+ if (!Pgzip) {
+ dup2(pipe1[0],0);
+ dup2(pipe2[1],1);
+ close(pipe1[0]); close(pipe1[1]);
+ close(pipe2[0]); close(pipe2[1]);
+ close(fdi); close(fdo);
+ execlp("gzip", "gzip", "-9", "-n", 0);
+ exit (0);
+ }
+
+ Ppiggy = fork();
+ if (Ppiggy < 0) { perror("fork()"); return 1; }
+ if (!Ppiggy) {
+ dup2(pipe2[0],0);
+ dup2(fdo,1);
+ close(pipe1[0]); close(pipe1[1]);
+ close(pipe2[0]); close(pipe2[1]);
+ close(fdi); close(fdo);
+ piggyback(obj);
+ exit(0);
+ }
+
+ close(pipe1[0]); close(pipe1[1]);
+ close(pipe2[0]); close(pipe2[1]);
+ close(fdi); close(fdo);
+
+ if (waitpid(Pext, &status,0) < 0)
+ { perror("waitpid(Pextract)"); return 1; }
+
+ if(status) {
+ fprintf(stderr,"extract returned %x\n",status);
+ return 3;
+ }
+
+ if (waitpid(Pgzip, &status,0) < 0)
+ { perror("waitpid(Pgzip)"); return 1; }
+
+ if(status) {
+ fprintf(stderr,"gzip returned %x\n",status);
+ return 3;
+ }
+
+ if (waitpid(Ppiggy, &status,0) < 0)
+ { perror("waitpid(Ppiggy)"); return 1; }
+
+ if(status) {
+ fprintf(stderr,"piggyback returned %x\n",status);
+ return 3;
+ }
+
+ if (forceaddr)
+ offset = forceaddr;
+ else {
+ /* a kludge to dynamically figure out where to start it */
+ if (stat (obj, &st) < 0) {
+ perror("cannot get size of compressed data");
+ return 3;
+ }
+ zip_size = (int)st.st_size;
+ offset = entry + size - zip_size + 0x8000; /* fudge factor */
+ }
+ sprintf(base, "0x%x", roundup(offset, 4096));
+
+ Pld = fork();
+ if (Pld < 0) { perror("fork()"); return 1; }
+ if (!Pld) {
+ execlp("ld",
+ "ld",
+ "-Bstatic",
+ "-Z",
+ "-T",
+ base,
+ "-o",
+ out,
+ "/usr/lib/kzhead.o",
+ obj,
+ "/usr/lib/kztail.o",
+ 0);
+ exit(2);
+ }
+
+ if (waitpid(Pld, &status,0) < 0)
+ { perror("waitpid(Pld)"); return 1; }
+
+ if(status) {
+ fprintf(stderr,"ld returned %x\n",status);
+ return 3;
+ }
+
+ if (verbose) {
+
+ fdn = open(obj ,O_RDONLY);
+ if(fdn<0) {
+ perror(obj);
+ return 3;
+ }
+
+ /* figure out how big the compressed image is */
+ if (read (fdn, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
+ perror(obj);
+ return 3;
+ }
+ close(fdn);
+
+ size = hdr.a_text + hdr.a_data + hdr.a_bss;
+
+ printf("kzip data start address will be: 0x%x\n",offset);
+ printf("kzip data end address will be: 0x%x\n",offset+size);
+ }
+
+ unlink(obj);
+ exit(0);
+}
+
+int
+extract (char *file)
+{
+ int sz;
+ char buf[BUFSIZ];
+ struct exec hdr;
+
+ if (read (0, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
+ perror(file);
+ exit(2);
+ }
+ if (hdr.a_magic != ZMAGIC) {
+ fprintf(stderr,"Bad magic in file %s, probably not a kernel\n",
+ file);
+ exit(2);
+ }
+ if (lseek (0, N_TXTOFF(hdr), 0) < 0) {
+ perror(file);
+ exit(2);
+ }
+
+ sz = N_SYMOFF (hdr) - N_TXTOFF (hdr);
+
+ while (sz) {
+ int l, n;
+
+ l = sz;
+ if (l > sizeof(buf))
+ l = sizeof(buf);
+
+ n = read (0, buf, l);
+ if (n != l) {
+ if (n == -1)
+ perror (file);
+ else
+ fprintf (stderr, "Unexpected EOF\n");
+
+ exit(1);
+ }
+
+ write (1, buf, l);
+ sz -= l;
+ }
+ exit(0);
+}
+
+
+char string_names[] = {"_input_data\0_input_len\0"};
+
+struct nlist var_names[2] = { /* Symbol table */
+ { { (char*) 4 }, N_EXT|N_TEXT, 0, 0, 0 }, /* _input_data */
+ { { (char*) 16 }, N_EXT|N_TEXT, 0, 0, 0 }, /* _input_len */
+};
+
+int
+piggyback(char *file)
+{
+ int n, len;
+ struct exec hdr; /* object header */
+ char image[MAXIMAGE]; /* kernel image buffer */
+
+ len = 0;
+ while ((n = read (0, &image[len], sizeof(image)-len+1)) > 0)
+ len += n;
+
+ if (n < 0) {
+ perror ("stdin");
+ exit (1);
+ }
+
+ if (len >= sizeof(image)) {
+ fprintf (stderr,"Input too large\n");
+ exit (1);
+ }
+
+ /*
+ * Output object header
+ */
+ memset(&hdr,0,sizeof hdr);
+ hdr.a_magic = OMAGIC;
+ hdr.a_text = len + sizeof(long);
+ hdr.a_syms = sizeof(var_names);
+ write (1, (char *)&hdr, sizeof(hdr));
+
+ /*
+ * Output text segment (compressed system & len)
+ */
+ write (1, image, len);
+ write (1, (char *)&len, sizeof(len));
+
+ /*
+ * Output symbol table
+ */
+ var_names[1].n_value = len;
+ write (1, (char *)&var_names, sizeof(var_names));
+
+ /*
+ * Output string table
+ */
+ len = sizeof(string_names) + sizeof(len);
+ write (1, (char *)&len, sizeof(len));
+ write (1, string_names, sizeof(string_names));
+
+ return (0);
+}
diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1
index 27a214d..c746d5b 100644
--- a/usr.bin/last/last.1
+++ b/usr.bin/last/last.1
@@ -117,6 +117,11 @@ login data base
.Xr lastcomm 1 ,
.Xr utmp 5 ,
.Xr ac 8
+.Sh BUGS
+If a login shell should terminate abnormally for some reason, it is likely
+that a logout record won't be written to the wtmp file. In this case,
+.Nm last
+will indicate the logout time as "shutdown".
.Sh HISTORY
.Nm Last
appeared in
diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c
index 662a663..9dea466 100644
--- a/usr.bin/last/last.c
+++ b/usr.bin/last/last.c
@@ -46,15 +46,16 @@ static char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94";
#include <err.h>
#include <fcntl.h>
+#include <locale.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
#include <utmp.h>
+#include <sys/queue.h>
#define NO 0 /* false/no */
#define YES 1 /* true/yes */
@@ -71,23 +72,23 @@ typedef struct arg {
} ARG;
ARG *arglist; /* head of linked list */
-typedef struct ttytab {
+LIST_HEAD(ttylisthead, ttytab) ttylist;
+
+struct ttytab {
long logout; /* log out time */
char tty[UT_LINESIZE + 1]; /* terminal name */
- struct ttytab *next; /* linked list pointer */
-} TTY;
-TTY *ttylist; /* head of linked list */
+ LIST_ENTRY(ttytab) list;
+};
static long currentout, /* current logout value */
maxrec; /* records to display */
static char *file = _PATH_WTMP; /* wtmp file */
void addarg __P((int, char *));
-TTY *addtty __P((char *));
void hostconv __P((char *));
void onintr __P((int));
char *ttyconv __P((char *));
-int want __P((struct utmp *, int));
+int want __P((struct utmp *));
void wtmp __P((void));
int
@@ -100,8 +101,10 @@ main(argc, argv)
int ch;
char *p;
+ (void) setlocale(LC_TIME, "");
+
maxrec = -1;
- while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
+ while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != -1)
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@@ -159,11 +162,15 @@ void
wtmp()
{
struct utmp *bp; /* current structure */
- TTY *T; /* tty list entry */
+ struct ttytab *tt, *ttx; /* ttylist entry */
struct stat stb; /* stat of file for size */
long bl, delta; /* time difference */
int bytes, wfd;
- char *ct, *crmsg;
+ char *crmsg;
+ char ct[80];
+ struct tm *tm;
+
+ LIST_INIT(&ttylist);
if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
err(1, "%s", file);
@@ -184,14 +191,19 @@ wtmp()
*/
if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
/* everybody just logged out */
- for (T = ttylist; T; T = T->next)
- T->logout = -bp->ut_time;
+ for (tt = ttylist.lh_first; tt;) {
+ LIST_REMOVE(tt, list);
+ ttx = tt;
+ tt = tt->list.le_next;
+ free(ttx);
+ }
currentout = -bp->ut_time;
crmsg = strncmp(bp->ut_name, "shutdown",
UT_NAMESIZE) ? "crash" : "shutdown";
- if (want(bp, NO)) {
- ct = ctime(&bp->ut_time);
- printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n",
+ if (want(bp)) {
+ tm = localtime(&bp->ut_time);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
+ printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n",
UT_NAMESIZE, UT_NAMESIZE,
bp->ut_name, UT_LINESIZE,
UT_LINESIZE, bp->ut_line,
@@ -208,61 +220,85 @@ wtmp()
*/
if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
&& !bp->ut_line[1]) {
- if (want(bp, NO)) {
- ct = ctime(&bp->ut_time);
- printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n",
- UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
- UT_LINESIZE, UT_LINESIZE, bp->ut_line,
- UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
- ct, ct + 11);
+ if (want(bp)) {
+ tm = localtime(&bp->ut_time);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
+ printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n",
+ UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
+ UT_LINESIZE, UT_LINESIZE, bp->ut_line,
+ UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
if (maxrec && !--maxrec)
return;
}
continue;
}
- /* find associated tty */
- for (T = ttylist;; T = T->next) {
- if (!T) {
- /* add new one */
- T = addtty(bp->ut_line);
- break;
+ if (bp->ut_name[0] == '\0' || want(bp)) {
+ /* find associated tty */
+ for (tt = ttylist.lh_first; ; tt = tt->list.le_next) {
+ if (tt == NULL) {
+ /* add new one */
+ tt = malloc(sizeof(struct ttytab));
+ if (tt == NULL)
+ err(1, "malloc failure");
+ tt->logout = currentout;
+ strncpy(tt->tty, bp->ut_line, UT_LINESIZE);
+ LIST_INSERT_HEAD(&ttylist, tt, list);
+ break;
+ }
+ if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE))
+ break;
}
- if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE))
- break;
- }
- if (bp->ut_name[0] && want(bp, YES)) {
- ct = ctime(&bp->ut_time);
- printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",
- UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
- UT_LINESIZE, UT_LINESIZE, bp->ut_line,
- UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
- ct, ct + 11);
- if (!T->logout)
- puts(" still logged in");
- else {
- if (T->logout < 0) {
- T->logout = -T->logout;
- printf("- %s", crmsg);
+ if (bp->ut_name[0]) {
+ /*
+ * when uucp and ftp log in over a network, the entry in
+ * the utmp file is the name plus their process id. See
+ * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
+ */
+ if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
+ bp->ut_line[3] = '\0';
+ else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
+ bp->ut_line[4] = '\0';
+ tm = localtime(&bp->ut_time);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
+ printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",
+ UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
+ UT_LINESIZE, UT_LINESIZE, bp->ut_line,
+ UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
+ if (!tt->logout)
+ puts(" still logged in");
+ else {
+ if (tt->logout < 0) {
+ tt->logout = -tt->logout;
+ printf("- %s", crmsg);
+ }
+ else {
+ tm = localtime(&tt->logout);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
+ printf("- %5.5s", ct + 11);
+ }
+ delta = tt->logout - bp->ut_time;
+ tm = gmtime(&delta);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
+ if (delta < 86400)
+ printf(" (%5.5s)\n", ct + 11);
+ else
+ printf(" (%ld+%5.5s)\n",
+ delta / 86400, ct + 11);
}
- else
- printf("- %5.5s",
- ctime(&T->logout)+11);
- delta = T->logout - bp->ut_time;
- if (delta < SECSPERDAY)
- printf(" (%5.5s)\n",
- asctime(gmtime(&delta))+11);
- else
- printf(" (%ld+%5.5s)\n",
- delta / SECSPERDAY,
- asctime(gmtime(&delta))+11);
+ LIST_REMOVE(tt, list);
+ free(tt);
+ if (maxrec != -1 && !--maxrec)
+ return;
+ } else {
+ tt->logout = bp->ut_time;
}
- if (maxrec != -1 && !--maxrec)
- return;
}
- T->logout = bp->ut_time;
}
}
- ct = ctime(&buf[0].ut_time);
+ tm = localtime(&buf[0].ut_time);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
}
@@ -271,22 +307,11 @@ wtmp()
* see if want this entry
*/
int
-want(bp, check)
+want(bp)
struct utmp *bp;
- int check;
{
ARG *step;
- if (check)
- /*
- * when uucp and ftp log in over a network, the entry in
- * the utmp file is the name plus their process id. See
- * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
- */
- if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
- bp->ut_line[3] = '\0';
- else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
- bp->ut_line[4] = '\0';
if (!arglist)
return (YES);
@@ -328,24 +353,6 @@ addarg(type, arg)
}
/*
- * addtty --
- * add an entry to a linked list of ttys
- */
-TTY *
-addtty(ttyname)
- char *ttyname;
-{
- TTY *cur;
-
- if (!(cur = (TTY *)malloc((u_int)sizeof(TTY))))
- err(1, "malloc failure");
- cur->next = ttylist;
- cur->logout = currentout;
- memmove(cur->tty, ttyname, UT_LINESIZE);
- return (ttylist = cur);
-}
-
-/*
* hostconv --
* convert the hostname to search pattern; if the supplied host name
* has a domain attached that is the same as the current domain, rip
@@ -410,9 +417,11 @@ void
onintr(signo)
int signo;
{
- char *ct;
+ char ct[80];
+ struct tm *tm;
- ct = ctime(&buf[0].ut_time);
+ tm = localtime(&buf[0].ut_time);
+ (void) strftime(ct, sizeof(ct), "%c", tm);
printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
if (signo == SIGINT)
exit(1);
diff --git a/usr.bin/lastcomm/lastcomm.1 b/usr.bin/lastcomm/lastcomm.1
index 1542b0d..05455cf 100644
--- a/usr.bin/lastcomm/lastcomm.1
+++ b/usr.bin/lastcomm/lastcomm.1
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)lastcomm.1 8.1 (Berkeley) 6/6/93
+.\" From: @(#)lastcomm.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
-.Dd June 6, 1993
+.Dd September 18, 1996
.Dt LASTCOMM 1
.Os BSD 3
.Sh NAME
@@ -39,6 +40,7 @@
.Nd show last commands executed in reverse order
.Sh SYNOPSIS
.Nm lastcomm
+.Op Fl EScesu
.Op Fl f Ar file
.Op Ar command ...
.Op Ar user ...
@@ -51,17 +53,35 @@ With no arguments,
prints information about all the commands recorded
during the current accounting file's lifetime.
.Pp
-Option:
+The following options are available:
.Pp
-.Bl -tag -width Fl
+.Bl -tag -width XXfXfileX -compact
+.Pp
+.It Fl E
+Print the time the process exited.
+.It Fl S
+Print the time the process started.
+.It Fl c
+Print the amount of cpu time used by the process.
+.It Fl e
+Print the amount of elapsed time used by the process.
+.It Fl s
+Print the amount of system time used by the process.
+.It Fl u
+Print the amount of user time used by the process.
.It Fl f Ar file
Read from
.Ar file
rather than the default
-accounting file.
+.Pa /var/account/acct .
.El
.Pp
-If called with arguments, only accounting entries with a
+If no options are specified,
+.Fl cS
+is assumed.
+If
+.Nm
+is invoked with arguments, only accounting entries with a
matching
.Ar command
name,
@@ -71,7 +91,7 @@ or
.Ar terminal
name
are printed.
-So, for example:
+For example:
.Pp
.Dl lastcomm a.out root ttyd0
.Pp
@@ -93,17 +113,29 @@ Flags, as accumulated by the accounting facilities in the system.
.It
The command name under which the process was called.
.It
-The amount of cpu time used by the process (in seconds).
+The amount of
+CPU
+.Pq Fl c ,
+wall
+.Pq Fl e ,
+system
+.Pq Fl s ,
+or user
+.Pq Fl u
+time used by the process (in seconds).
.It
-The time the process exited.
+The time the process started
+.Pq Fl S
+or exited
+.Pq Fl E .
.El
.Pp
The flags are encoded as follows: ``S'' indicates the command was
executed by the super-user, ``F'' indicates the command ran after
a fork, but without a following
.Xr exec ,
-``C'' indicates the command was run in PDP-11 compatibility mode
-(VAX only),
+.\" ``C'' indicates the command was run in PDP-11 compatibility mode
+.\" (VAX only),
``D'' indicates the command terminated with the generation of a
.Pa core
file, and ``X'' indicates the command was terminated with a signal.
diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c
index 749d8cf..6d7b034 100644
--- a/usr.bin/lastcomm/lastcomm.c
+++ b/usr.bin/lastcomm/lastcomm.c
@@ -29,6 +29,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: lastcomm.c,v 1.7 1997/03/29 04:30:24 imp Exp $
*/
#ifndef lint
@@ -38,7 +40,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95";
+static char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
@@ -63,6 +65,16 @@ int requested __P((char *[], struct acct *));
void usage __P((void));
char *user_from_uid();
+#define AC_UTIME 1 /* user */
+#define AC_STIME 2 /* system */
+#define AC_ETIME 4 /* elapsed */
+#define AC_CTIME 8 /* user + system time, default */
+
+#define AC_BTIME 16 /* starting time */
+#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
+
+#define AC_HZ ((double)AHZ)
+
int
main(argc, argv)
int argc;
@@ -76,17 +88,46 @@ main(argc, argv)
time_t t;
int ch;
char *acctfile;
+ int time = 0;
acctfile = _PATH_ACCT;
- while ((ch = getopt(argc, argv, "f:")) != EOF)
+ while ((ch = getopt(argc, argv, "f:usecSE")) != -1)
switch((char)ch) {
case 'f':
acctfile = optarg;
break;
+
+ case 'u':
+ time |= AC_UTIME; /* user time */
+ break;
+ case 's':
+ time |= AC_STIME; /* system time */
+ break;
+ case 'e':
+ time |= AC_ETIME; /* elapsed time */
+ break;
+ case 'c':
+ time |= AC_CTIME; /* user + system time */
+ break;
+
+ case 'S':
+ time |= AC_BTIME; /* starting time */
+ break;
+ case 'E':
+ /* exit time (starting time + elapsed time )*/
+ time |= AC_FTIME;
+ break;
+
case '?':
default:
usage();
}
+
+ /* default user + system time and starting time */
+ if (!time) {
+ time = AC_CTIME | AC_BTIME;
+ }
+
argc -= optind;
argv += optind;
@@ -134,14 +175,51 @@ main(argc, argv)
if (*argv && !requested(argv, &ab))
continue;
- t = expand(ab.ac_utime) + expand(ab.ac_stime);
- (void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n",
- fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag),
- UT_NAMESIZE, user_from_uid(ab.ac_uid, 0),
- UT_LINESIZE, getdev(ab.ac_tty),
- t / (double)AHZ, ctime(&ab.ac_btime));
- }
- exit(0);
+ (void)printf("%-*.*s %-7s %-*s %-*s ",
+ fldsiz(acct, ac_comm),
+ fldsiz(acct, ac_comm), ab.ac_comm,
+ flagbits(ab.ac_flag),
+ UT_NAMESIZE, user_from_uid(ab.ac_uid, 0),
+ UT_LINESIZE, getdev(ab.ac_tty));
+
+
+ /* user + system time */
+ if (time & AC_CTIME) {
+ (void)printf("%6.2f secs ",
+ (expand(ab.ac_utime) +
+ expand(ab.ac_stime))/AC_HZ);
+ }
+
+ /* usr time */
+ if (time & AC_UTIME) {
+ (void)printf("%6.2f us ", expand(ab.ac_utime)/AC_HZ);
+ }
+
+ /* system time */
+ if (time & AC_STIME) {
+ (void)printf("%6.2f sy ", expand(ab.ac_stime)/AC_HZ);
+ }
+
+ /* elapsed time */
+ if (time & AC_ETIME) {
+ (void)printf("%8.2f es ", expand(ab.ac_etime)/AC_HZ);
+ }
+
+ /* starting time */
+ if (time & AC_BTIME) {
+ (void)printf("%.16s ", ctime(&ab.ac_btime));
+ }
+
+ /* exit time (starting time + elapsed time )*/
+ if (time & AC_FTIME) {
+ t = ab.ac_btime;
+ t += (time_t)(expand(ab.ac_etime)/AC_HZ);
+ (void)printf("%.16s ",
+ ctime(&t));
+ }
+ printf("\n");
+ }
+ exit(0);
}
time_t
@@ -183,10 +261,13 @@ requested(argv, acp)
register char *argv[];
register struct acct *acp;
{
+ register char *p;
+
do {
- if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv))
+ p = user_from_uid(acp->ac_uid, 0);
+ if (!strcmp(p, *argv))
return (1);
- if (!strcmp(getdev(acp->ac_tty), *argv))
+ if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
return (1);
if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
return (1);
@@ -206,8 +287,7 @@ getdev(dev)
if (dev == lastdev) /* One-element cache. */
return (lastname);
lastdev = dev;
- if ((lastname = devname(dev, S_IFCHR)) == NULL)
- lastname = "??";
+ lastname = devname(dev, S_IFCHR);
return (lastname);
}
@@ -215,6 +295,6 @@ void
usage()
{
(void)fprintf(stderr,
- "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n");
+ "lastcomm [-EScesu] [ -f file ] [command ...] [user ...] [tty ...]\n");
exit(1);
}
diff --git a/usr.bin/ldd/Makefile b/usr.bin/ldd/Makefile
new file mode 100644
index 0000000..61c95a8
--- /dev/null
+++ b/usr.bin/ldd/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= ldd
+SRCS= ldd.c sods.c
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ldd/ldd.1 b/usr.bin/ldd/ldd.1
new file mode 100644
index 0000000..4b499fe
--- /dev/null
+++ b/usr.bin/ldd/ldd.1
@@ -0,0 +1,47 @@
+.Dd October 22, 1993
+.Dt LDD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ldd
+.Nd list dynamic object dependencies
+.Sh SYNOPSIS
+.Nm ldd
+.Op Fl v
+.Op Fl f Ar format
+.Ar program ...
+.Sh DESCRIPTION
+.Nm ldd
+displays all shared objects that are needed to run the given program.
+Contrary to nm(1), the list includes
+.Dq indirect
+depedencies that are the result of needed shared objects which themselves
+depend on yet other shared objects.
+.Pp
+Zero, one or two
+.Fl f
+options may be given. The argument is a format string passed to
+.Xr rtld 1
+and allows customization of
+.Nm ldd Ns 's
+output. See
+.Xr rtld 1
+for a list of recognised conversion characters.
+.Pp
+The
+.Fl v
+option displays an verbose listing of the dynamic linking headers
+encoded in the executable. See the source code and include
+files for the definitive meaning of all the fields.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ld.so 1 ,
+.Xr nm 1
+.Sh HISTORY
+A
+.Nm ldd
+utility first appeared in SunOS 4.0, it appeared in its current form
+in FreeBSD 1.1.
+.Pp
+The
+.Fl v
+support is based on code written by John Polstra <jdp@polstra.com>
diff --git a/usr.bin/ldd/ldd.c b/usr.bin/ldd/ldd.c
new file mode 100644
index 0000000..331d3c7
--- /dev/null
+++ b/usr.bin/ldd/ldd.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <a.out.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern void dump_filename __P((const char *));
+extern int error_count;
+
+void
+usage()
+{
+ fprintf(stderr, "usage: ldd [-v] [-f format] program ...\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *fmt1 = NULL, *fmt2 = NULL;
+ int rval;
+ int c;
+ int vflag = 0;
+
+ while ((c = getopt(argc, argv, "vf:")) != EOF) {
+ switch (c) {
+ case 'v':
+ vflag++;
+ break;
+ case 'f':
+ if (fmt1) {
+ if (fmt2)
+ errx(1, "Too many formats");
+ fmt2 = optarg;
+ } else
+ fmt1 = optarg;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (vflag && fmt1)
+ errx(1, "-v may not be used with -f");
+
+ if (argc <= 0) {
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (vflag) {
+ for (c = 0; c < argc; c++)
+ dump_file(argv[c]);
+ exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
+ /* ld.so magic */
+ setenv("LD_TRACE_LOADED_OBJECTS", "1", 1);
+ if (fmt1)
+ setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
+ if (fmt2)
+ setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
+
+ rval = 0;
+ while (argc--) {
+ int fd;
+ struct exec hdr;
+ int status;
+
+ if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+ warn("%s", *argv);
+ rval |= 1;
+ argv++;
+ continue;
+ }
+ if (read(fd, &hdr, sizeof hdr) != sizeof hdr
+ || (N_GETFLAG(hdr) & EX_DPMASK) != EX_DYNAMIC
+#if 1 /* Compatibility */
+ || hdr.a_entry < __LDPGSZ
+#endif
+ ) {
+
+ warnx("%s: not a dynamic executable", *argv);
+ (void)close(fd);
+ rval |= 1;
+ argv++;
+ continue;
+ }
+ (void)close(fd);
+
+ setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
+ if (fmt1 == NULL && fmt2 == NULL)
+ /* Default formats */
+ printf("%s:\n", *argv);
+
+ fflush(stdout);
+
+ switch (fork()) {
+ case -1:
+ err(1, "fork");
+ break;
+ default:
+ if (wait(&status) <= 0) {
+ warn("wait");
+ rval |= 1;
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr, "%s: signal %d\n",
+ *argv, WTERMSIG(status));
+ rval |= 1;
+ } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ fprintf(stderr, "%s: exit status %d\n",
+ *argv, WEXITSTATUS(status));
+ rval |= 1;
+ }
+ break;
+ case 0:
+ rval |= execl(*argv, *argv, NULL) != 0;
+ perror(*argv);
+ _exit(1);
+ }
+ argv++;
+ }
+
+ return rval;
+}
diff --git a/usr.bin/ldd/sods.c b/usr.bin/ldd/sods.c
new file mode 100644
index 0000000..b3732c1
--- /dev/null
+++ b/usr.bin/ldd/sods.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 1996 John D. Polstra. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <a.out.h>
+#include <link.h>
+#include <stab.h>
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+#ifdef STANDALONE
+static
+#endif
+void dump_file(const char *);
+
+static void dump_rels(const char *, const struct relocation_info *,
+ unsigned long, const char *(*)(unsigned long), unsigned char *);
+static void dump_segs();
+static void dump_sods();
+static void dump_sym(const struct nlist *);
+static void dump_syms();
+
+static void dump_rtrels();
+static void dump_rtsyms();
+
+static void error(const char *, ...);
+static const char *rtsym_name(unsigned long);
+static const char *sym_name(unsigned long);
+
+#ifdef STANDALONE
+static
+#endif
+int error_count;
+
+/*
+ * Variables ending in _base are pointers to things in our address space,
+ * i.e., in the file itself.
+ *
+ * Variables ending in _addr are adjusted according to where things would
+ * actually appear in memory if the file were loaded.
+ */
+static const char *file_base;
+static const char *text_base;
+static const char *data_base;
+static const struct relocation_info *rel_base;
+static const struct nlist *sym_base;
+static const char *str_base;
+
+static const struct relocation_info *rtrel_base;
+static const struct nzlist *rtsym_base;
+static const char *rtstr_base;
+
+static const struct exec *ex;
+static const struct _dynamic *dyn;
+static const struct section_dispatch_table *sdt;
+
+static const char *text_addr;
+static const char *data_addr;
+
+static unsigned long rel_count;
+static unsigned long sym_count;
+
+static unsigned long rtrel_count;
+static unsigned long rtsym_count;
+
+/* Dynamically allocated flags, 1 byte per symbol, to record whether each
+ symbol was referenced by a relocation entry. */
+static unsigned char *sym_used;
+static unsigned char *rtsym_used;
+
+static unsigned long origin; /* What values are relocated relative to */
+
+#ifdef STANDALONE
+main(int argc, char *argv[])
+{
+ int i;
+
+ for(i = 1; i < argc; ++i)
+ dump_file(argv[i]);
+
+ return error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+#endif
+
+#ifdef STANDALONE
+static
+#endif
+void
+dump_file(const char *fname)
+{
+ int fd;
+ struct stat sb;
+ caddr_t objbase;
+ long load_offset;
+
+ if(stat(fname, &sb) == -1) {
+ error("Cannot stat \"%s\"", fname);
+ return;
+ }
+
+ if((sb.st_mode & S_IFMT) != S_IFREG) {
+ error("\"%s\" is not a regular file", fname);
+ return;
+ }
+
+ if((fd = open(fname, O_RDONLY, 0)) == -1) {
+ error("Cannot open \"%s\"", fname);
+ return;
+ }
+
+ objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if(objbase == (caddr_t) -1) {
+ error("Cannot mmap \"%s\"", fname);
+ close(fd);
+ return;
+ }
+
+ close(fd);
+
+ file_base = (const char *) objbase; /* Makes address arithmetic easier */
+
+ ex = (const struct exec *) file_base;
+
+ printf("%s: a_midmag = 0x%lx\n", fname, ex->a_midmag);
+ printf(" magic = 0x%x = 0%o, netmagic = 0x%x = 0%o\n",
+ N_GETMAGIC(*ex), N_GETMAGIC(*ex),
+ N_GETMAGIC_NET(*ex), N_GETMAGIC_NET(*ex));
+
+ if(N_BADMAG(*ex)) {
+ error("%s: Bad magic number", fname);
+ munmap(objbase, sb.st_size);
+ return;
+ }
+
+ printf(" a_text = 0x%lx\n", ex->a_text);
+ printf(" a_data = 0x%lx\n", ex->a_data);
+ printf(" a_bss = 0x%lx\n", ex->a_bss);
+ printf(" a_syms = 0x%lx\n", ex->a_syms);
+ printf(" a_entry = 0x%lx\n", ex->a_entry);
+ printf(" a_trsize = 0x%lx\n", ex->a_trsize);
+ printf(" a_drsize = 0x%lx\n", ex->a_drsize);
+
+ load_offset = N_TXTADDR(*ex) - N_TXTOFF(*ex);
+
+ text_base = file_base + N_TXTOFF(*ex);
+ data_base = file_base + N_DATOFF(*ex);
+ rel_base = (const struct relocation_info *) (file_base + N_RELOFF(*ex));
+ sym_base = (const struct nlist *) (file_base + N_SYMOFF(*ex));
+ str_base = file_base + N_STROFF(*ex);
+
+ rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0];
+ assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize);
+ sym_count = ex->a_syms / sizeof sym_base[0];
+ assert(sym_count * sizeof sym_base[0] == ex->a_syms);
+
+ if(sym_count != 0) {
+ sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char));
+ assert(sym_used != NULL);
+ }
+
+ printf(" Entry = 0x%x, load offset = 0x%lx\n",
+ ex->a_entry, load_offset);
+ printf(" Text offset = %lx, address = %lx\n", N_TXTOFF(*ex),
+ N_TXTADDR(*ex));
+ printf(" Data offset = %lx, address = %lx\n", N_DATOFF(*ex),
+ N_DATADDR(*ex));
+
+ /*
+ * DEBUG
+ *
+ * In an executable program file, everything is relocated relative to
+ * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000.
+ *
+ * In a shared library file, everything is relocated relative to the
+ * start of the file, i.e., N_TXTOFF(*ex), i.e., 0.
+ *
+ * The way to tell the difference is by looking at ex->a_entry. If it
+ * is >= 0x1000, then we have an executable program. Otherwise, we
+ * have a shared library.
+ *
+ * When a program is executed, the entire file is mapped into memory,
+ * including the a.out header and so forth. But it is not mapped at
+ * address 0; rather it is mapped at address 0x1000. The first page
+ * of the user's address space is left unmapped in order to catch null
+ * pointer dereferences.
+ *
+ * In this program, when we map in an executable program, we have to
+ * simulate the empty page by decrementing our assumed base address by
+ * a pagesize.
+ */
+
+ text_addr = text_base;
+ data_addr = data_base;
+ origin = 0;
+
+ if(ex->a_entry >= load_offset) { /* Executable, not a shared library */
+ /*
+ * The fields in the object have already been relocated on the
+ * assumption that the object will be loaded at N_TXTADDR(*ex).
+ * We have to compensate for that.
+ */
+ text_addr -= load_offset;
+ data_addr -= load_offset;
+ origin = load_offset;
+ printf(" Program, origin = %lx\n", origin);
+ } else
+ printf(" Library, origin = %lx\n", origin);
+
+ if(N_GETFLAG(*ex) & EX_DYNAMIC) {
+ dyn = (const struct _dynamic *) data_base;
+ sdt = (const struct section_dispatch_table *)
+ (text_addr + (unsigned long) dyn->d_un.d_sdt);
+
+ rtrel_base =
+ (const struct relocation_info *) (text_addr + sdt->sdt_rel);
+ rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0];
+ assert(rtrel_count * sizeof rtrel_base[0] ==
+ sdt->sdt_hash - sdt->sdt_rel);
+
+ rtsym_base = (const struct nzlist *) (text_addr + sdt->sdt_nzlist);
+ rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) /
+ sizeof rtsym_base[0];
+ assert(rtsym_count * sizeof rtsym_base[0] ==
+ sdt->sdt_strings - sdt->sdt_nzlist);
+
+ if(rtsym_count != 0) {
+ rtsym_used = (unsigned char *) calloc(rtsym_count,
+ sizeof(unsigned char));
+ assert(rtsym_used != NULL);
+ }
+
+ rtstr_base = text_addr + sdt->sdt_strings;
+ }
+
+ dump_segs();
+ dump_sods();
+ dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used);
+ dump_syms();
+
+ dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name,
+ rtsym_used);
+ dump_rtsyms();
+
+ if(rtsym_used != NULL) {
+ free(rtsym_used);
+ rtsym_used = NULL;
+ }
+ if(sym_used != NULL) {
+ free(sym_used);
+ sym_used = NULL;
+ }
+ munmap(objbase, sb.st_size);
+}
+
+static void
+dump_rels(const char *label, const struct relocation_info *base,
+ unsigned long count, const char *(*name)(unsigned long),
+ unsigned char *sym_used_flags)
+{
+ unsigned long i;
+
+ printf(" %s:\n", label);
+ for(i = 0; i < count; ++i) {
+ const struct relocation_info *r = &base[i];
+
+ printf(" %6lu %8x/%u %c%c%c%c%c%c", i,
+ r->r_address, 1u << r->r_length,
+ r->r_extern ? 'e' : '-',
+ r->r_jmptable ? 'j' : '-',
+ r->r_relative ? 'r' : '-',
+ r->r_baserel ? 'b' : '-',
+ r->r_pcrel ? 'p' : '-',
+ r->r_copy ? 'c' : '-');
+
+ if(r->r_extern || r->r_baserel || r->r_jmptable || r->r_copy) {
+ printf(" %4u %s", r->r_symbolnum, name(r->r_symbolnum));
+ sym_used_flags[r->r_symbolnum] = 1;
+ }
+
+ printf("\n");
+ }
+}
+
+static void
+dump_rtsyms()
+{
+ unsigned long i;
+
+ printf(" Run-time symbols:\n");
+ for(i = 0; i < rtsym_count; ++i) {
+ printf(" %6lu%c ", i, rtsym_used[i] ? '*' : ' ');
+ dump_sym(&rtsym_base[i].nlist);
+ printf("/%-5ld %s\n", rtsym_base[i].nz_size, rtsym_name(i));
+ }
+}
+
+static void
+dump_segs()
+{
+ printf(" Text segment starts at address %lx\n", origin + N_TXTOFF(*ex));
+ if(N_GETFLAG(*ex) & EX_DYNAMIC) {
+ printf(" rel starts at %lx\n", sdt->sdt_rel);
+ printf(" hash starts at %lx\n", sdt->sdt_hash);
+ printf(" nzlist starts at %lx\n", sdt->sdt_nzlist);
+ printf(" strings starts at %lx\n", sdt->sdt_strings);
+ }
+
+ printf(" Data segment starts at address %lx\n", origin + N_DATOFF(*ex));
+ if(N_GETFLAG(*ex) & EX_DYNAMIC) {
+ printf(" _dynamic starts at %lx\n", origin + N_DATOFF(*ex));
+ printf(" so_debug starts at %lx\n", (unsigned long) dyn->d_debug);
+ printf(" sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt);
+ printf(" got starts at %lx\n", sdt->sdt_got);
+ printf(" plt starts at %lx\n", sdt->sdt_plt);
+ printf(" rest of stuff starts at %lx\n",
+ sdt->sdt_plt + sdt->sdt_plt_sz);
+ }
+}
+
+static void
+dump_sods()
+{
+ long sod_offset;
+ long paths_offset;
+
+ if(dyn == NULL) /* Not a shared object */
+ return;
+
+ sod_offset = sdt->sdt_sods;
+ printf(" Shared object dependencies:\n");
+ while(sod_offset != 0) {
+ const struct sod *sodp = (const struct sod *) (text_addr + sod_offset);
+ const char *name = (const char *) (text_addr + sodp->sod_name);
+
+ if (sodp->sod_library)
+ printf(" -l%-16s version %d.%d\n", name, sodp->sod_major,
+ sodp->sod_minor);
+ else
+ printf(" %s\n", name);
+ sod_offset = sodp->sod_next;
+ }
+ paths_offset = sdt->sdt_paths;
+ printf(" Shared object additional paths:\n");
+ if (paths_offset != 0) {
+ char *path = (char *)(text_addr + paths_offset);
+ printf(" %s\n", path);
+ } else {
+ printf(" NULL\n");
+ }
+}
+
+static void
+dump_sym(const struct nlist *np)
+{
+ char type[8];
+ char *p;
+
+ switch(np->n_type & ~N_EXT) {
+ case N_UNDF: strcpy(type, "undf"); break;
+ case N_ABS: strcpy(type, "abs"); break;
+ case N_TEXT: strcpy(type, "text"); break;
+ case N_DATA: strcpy(type, "data"); break;
+ case N_BSS: strcpy(type, "bss"); break;
+ case N_INDR: strcpy(type, "indr"); break;
+ case N_SIZE: strcpy(type, "size"); break;
+ case N_COMM: strcpy(type, "comm"); break;
+ case N_SETA: strcpy(type, "seta"); break;
+ case N_SETT: strcpy(type, "sett"); break;
+ case N_SETD: strcpy(type, "setd"); break;
+ case N_SETB: strcpy(type, "setb"); break;
+ case N_SETV: strcpy(type, "setv"); break;
+ case N_FN: strcpy(type, np->n_type&N_EXT ? "fn" : "warn"); break;
+ case N_GSYM: strcpy(type, "gsym"); break;
+ case N_FNAME: strcpy(type, "fname"); break;
+ case N_FUN: strcpy(type, "fun"); break;
+ case N_STSYM: strcpy(type, "stsym"); break;
+ case N_LCSYM: strcpy(type, "lcsym"); break;
+ case N_MAIN: strcpy(type, "main"); break;
+ case N_PC: strcpy(type, "pc"); break;
+ case N_RSYM: strcpy(type, "rsym"); break;
+ case N_SLINE: strcpy(type, "sline"); break;
+ case N_DSLINE: strcpy(type, "dsline"); break;
+ case N_BSLINE: strcpy(type, "bsline"); break;
+ case N_SSYM: strcpy(type, "ssym"); break;
+ case N_SO: strcpy(type, "so"); break;
+ case N_LSYM: strcpy(type, "lsym"); break;
+ case N_BINCL: strcpy(type, "bincl"); break;
+ case N_SOL: strcpy(type, "sol"); break;
+ case N_PSYM: strcpy(type, "psym"); break;
+ case N_EINCL: strcpy(type, "eincl"); break;
+ case N_ENTRY: strcpy(type, "entry"); break;
+ case N_LBRAC: strcpy(type, "lbrac"); break;
+ case N_EXCL: strcpy(type, "excl"); break;
+ case N_RBRAC: strcpy(type, "rbrac"); break;
+ case N_BCOMM: strcpy(type, "bcomm"); break;
+ case N_ECOMM: strcpy(type, "ecomm"); break;
+ case N_ECOML: strcpy(type, "ecoml"); break;
+ case N_LENG: strcpy(type, "leng"); break;
+ default: sprintf(type, "0x%02x", np->n_type);
+ }
+
+ if(np->n_type & N_EXT && type[0] != '0')
+ for(p = type; *p != '\0'; ++p)
+ *p = toupper(*p);
+
+ printf("%-5s %8lx", type, np->n_value);
+}
+
+static void
+dump_syms()
+{
+ unsigned long i;
+
+ printf(" Symbols:\n");
+ for(i = 0; i < sym_count; ++i) {
+ printf(" %6lu%c ", i, sym_used[i] ? '*' : ' ');
+ dump_sym(&sym_base[i]);
+ printf(" %s\n", sym_name(i));
+ }
+}
+
+static void
+error(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ putc('\n', stderr);
+
+ ++error_count;
+}
+
+static const char *
+rtsym_name(unsigned long n)
+{
+ assert(n < rtsym_count);
+ if(rtsym_base[n].nz_strx == 0)
+ return "";
+ return rtstr_base + rtsym_base[n].nz_strx;
+}
+
+static const char *
+sym_name(unsigned long n)
+{
+ assert(n < sym_count);
+ if(sym_base[n].n_un.n_strx == 0)
+ return "";
+ return str_base + sym_base[n].n_un.n_strx;
+}
diff --git a/usr.bin/lex/COPYING b/usr.bin/lex/COPYING
new file mode 100644
index 0000000..dcb775e
--- /dev/null
+++ b/usr.bin/lex/COPYING
@@ -0,0 +1,38 @@
+Flex carries the copyright used for BSD software, slightly modified
+because it originated at the Lawrence Berkeley (not Livermore!) Laboratory,
+which operates under a contract with the Department of Energy:
+
+ Copyright (c) 1990 The Regents of the University of California.
+ All rights reserved.
+
+ This code is derived from software contributed to Berkeley by
+ Vern Paxson.
+
+ The United States Government has rights in this work pursuant
+ to contract no. DE-AC03-76SF00098 between the United States
+ Department of Energy and the University of California.
+
+ Redistribution and use in source and binary forms are permitted
+ provided that: (1) source distributions retain this entire
+ copyright notice and comment, and (2) distributions including
+ binaries display the following acknowledgement: ``This product
+ includes software developed by the University of California,
+ Berkeley and its contributors'' in the documentation or other
+ materials provided with the distribution and in all advertising
+ materials mentioning features or use of this software. Neither the
+ name of the University nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+This basically says "do whatever you please with this software except
+remove this notice or take advantage of the University's (or the flex
+authors') name".
+
+Note that the "flex.skl" scanner skeleton carries no copyright notice.
+You are free to do whatever you please with scanners generated using flex;
+for them, you are not even bound by the above copyright.
diff --git a/usr.bin/lex/FlexLexer.h b/usr.bin/lex/FlexLexer.h
new file mode 100644
index 0000000..6c9a950
--- /dev/null
+++ b/usr.bin/lex/FlexLexer.h
@@ -0,0 +1,185 @@
+// $Header: /home/daffy/u0/vern/flex/RCS/FlexLexer.h,v 1.19 96/05/25 20:43:02 vern Exp $
+
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+// by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms are permitted provided
+// that: (1) source distributions retain this entire copyright notice and
+// comment, and (2) distributions including binaries display the following
+// acknowledgement: ``This product includes software developed by the
+// University of California, Berkeley and its contributors'' in the
+// documentation or other materials provided with the distribution and in
+// all advertising materials mentioning features or use of this software.
+// Neither the name of the University nor the names of its contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer. You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer xxFlexLexer
+// #include <FlexLexer.h>
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer zzFlexLexer
+// #include <FlexLexer.h>
+// ...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+#include <iostream.h>
+
+extern "C++" {
+
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+ virtual ~FlexLexer() { }
+
+ const char* YYText() { return yytext; }
+ int YYLeng() { return yyleng; }
+
+ virtual void
+ yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+ virtual struct yy_buffer_state*
+ yy_create_buffer( istream* s, int size ) = 0;
+ virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+ virtual void yyrestart( istream* s ) = 0;
+
+ virtual int yylex() = 0;
+
+ // Call yylex with new input/output sources.
+ int yylex( istream* new_in, ostream* new_out = 0 )
+ {
+ switch_streams( new_in, new_out );
+ return yylex();
+ }
+
+ // Switch to new input/output streams. A nil stream pointer
+ // indicates "keep the current one".
+ virtual void switch_streams( istream* new_in = 0,
+ ostream* new_out = 0 ) = 0;
+
+ int lineno() const { return yylineno; }
+
+ int debug() const { return yy_flex_debug; }
+ void set_debug( int flag ) { yy_flex_debug = flag; }
+
+protected:
+ char* yytext;
+ int yyleng;
+ int yylineno; // only maintained if you use %option yylineno
+ int yy_flex_debug; // only has effect with -d or "%option debug"
+};
+
+}
+#endif
+
+#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex man page.
+#define yyFlexLexerOnce
+
+class yyFlexLexer : public FlexLexer {
+public:
+ // arg_yyin and arg_yyout default to the cin and cout, but we
+ // only make that assignment when initializing in yylex().
+ yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 );
+
+ virtual ~yyFlexLexer();
+
+ void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+ struct yy_buffer_state* yy_create_buffer( istream* s, int size );
+ void yy_delete_buffer( struct yy_buffer_state* b );
+ void yyrestart( istream* s );
+
+ virtual int yylex();
+ virtual void switch_streams( istream* new_in, ostream* new_out );
+
+protected:
+ virtual int LexerInput( char* buf, int max_size );
+ virtual void LexerOutput( const char* buf, int size );
+ virtual void LexerError( const char* msg );
+
+ void yyunput( int c, char* buf_ptr );
+ int yyinput();
+
+ void yy_load_buffer_state();
+ void yy_init_buffer( struct yy_buffer_state* b, istream* s );
+ void yy_flush_buffer( struct yy_buffer_state* b );
+
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int* yy_start_stack;
+
+ void yy_push_state( int new_state );
+ void yy_pop_state();
+ int yy_top_state();
+
+ yy_state_type yy_get_previous_state();
+ yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+ int yy_get_next_buffer();
+
+ istream* yyin; // input source for default LexerInput
+ ostream* yyout; // output sink for default LexerOutput
+
+ struct yy_buffer_state* yy_current_buffer;
+
+ // yy_hold_char holds the character lost when yytext is formed.
+ char yy_hold_char;
+
+ // Number of characters read into yy_ch_buf.
+ int yy_n_chars;
+
+ // Points to current character in buffer.
+ char* yy_c_buf_p;
+
+ int yy_init; // whether we need to initialize
+ int yy_start; // start state number
+
+ // Flag which is used to allow yywrap()'s to do buffer switches
+ // instead of setting up a fresh yyin. A bit of a hack ...
+ int yy_did_buffer_switch_on_eof;
+
+ // The following are not always needed, but may be depending
+ // on use of certain flex features (like REJECT or yymore()).
+
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ yy_state_type* yy_state_buf;
+ yy_state_type* yy_state_ptr;
+
+ char* yy_full_match;
+ int* yy_full_state;
+ int yy_full_lp;
+
+ int yy_lp;
+ int yy_looking_for_trail_begin;
+
+ int yy_more_flag;
+ int yy_more_len;
+ int yy_more_offset;
+ int yy_prev_more_offset;
+};
+
+#endif
diff --git a/usr.bin/lex/Makefile b/usr.bin/lex/Makefile
new file mode 100644
index 0000000..63f36e9
--- /dev/null
+++ b/usr.bin/lex/Makefile
@@ -0,0 +1,59 @@
+# $Id$
+#
+# By default, flex will be configured to generate 8-bit scanners only if the
+# -8 flag is given. If you want it to always generate 8-bit scanners, add
+# "-DDEFAULT_CSIZE=256" to CFLAGS. Note that doing so will double the size
+# of all uncompressed scanners.
+#
+# Bootstrapping of lex is handled automatically.
+# Also note that flex.skel no longer gets installed.
+#
+
+PROG= lex
+LINKS+= ${BINDIR}/lex ${BINDIR}/lex++
+LINKS+= ${BINDIR}/lex ${BINDIR}/flex
+LINKS+= ${BINDIR}/lex ${BINDIR}/flex++
+
+SRCS= scan.c ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ skel.c sym.c tblcmp.c yylex.c
+LFLAGS+= -is
+CFLAGS+= -I. -I${.CURDIR}
+MAN1= lex.1
+MLINKS+= lex.1 flex.1
+MLINKS+= lex.1 flex++.1
+MLINKS+= lex.1 lex++.1
+
+CLEANFILES+= parse.c parse.h scan.c y.tab.h y.tab.c
+
+.if !defined(NOLIB)
+SUBDIR= lib
+.endif
+
+beforeinstall:
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${.CURDIR}/FlexLexer.h ${DESTDIR}/usr/include/g++
+
+
+parse.c parse.h: parse.y
+ $(YACC) -d $(.CURDIR)/parse.y
+ mv -f y.tab.c parse.c
+ mv -f y.tab.h parse.h
+
+bootstrap: initscan.c
+ @cmp -s ${.CURDIR}/initscan.c scan.c || { \
+ echo "Bootstrapping flex" ; \
+ rm -f scan.c ; \
+ cp -f ${.CURDIR}/initscan.c scan.c ; \
+ }
+
+beforedepend: parse.h
+scan.o: parse.h
+
+test: check
+check: $(PROG)
+ ./$(PROG) $(LFLAGS) -t $(COMPRESSION) $(.CURDIR)/scan.l \
+ | sed s,\"$(.CURDIR)/scan.l",\"scan.l", \
+ | diff $(.CURDIR)/initscan.c -
+ @echo "Check successful"
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/lex/NEWS b/usr.bin/lex/NEWS
new file mode 100644
index 0000000..3e23e7d
--- /dev/null
+++ b/usr.bin/lex/NEWS
@@ -0,0 +1,1233 @@
+Changes between release 2.5.4 (11Sep96) and release 2.5.3:
+
+ - Fixed a bug introduced in 2.5.3 that blew it when a call
+ to input() occurred at the end of an input file.
+
+ - Fixed scanner skeleton so the example in the man page of
+ scanning strings using exclusive start conditions works.
+
+ - Minor Makefile tweaks.
+
+
+Changes between release 2.5.3 (29May96) and release 2.5.2:
+
+ - Some serious bugs in yymore() have been fixed. In particular,
+ when using AT&T-lex-compatibility or %array, you can intermix
+ calls to input(), unput(), and yymore(). (This still doesn't
+ work for %pointer, and isn't likely to in the future.)
+
+ - A bug in handling NUL's in the input stream of scanners using
+ REJECT has been fixed.
+
+ - The default main() in libfl.a now repeatedly calls yylex() until
+ it returns 0, rather than just calling it once.
+
+ - Minor tweak for Windows NT Makefile, MISC/NT/Makefile.
+
+
+Changes between release 2.5.2 (25Apr95) and release 2.5.1:
+
+ - The --prefix configuration option now works.
+
+ - A bug that completely broke the "-Cf" table compression
+ option has been fixed.
+
+ - A major headache involving "const" declarators and Solaris
+ systems has been fixed.
+
+ - An octal escape sequence in a flex regular expression must
+ now contain only the digits 0-7.
+
+ - You can now use "--" on the flex command line to mark the
+ end of flex options.
+
+ - You can now specify the filename '-' as a synonym for stdin.
+
+ - By default, the scanners generated by flex no longer
+ statically initialize yyin and yyout to stdin and stdout.
+ This change is necessary because in some ANSI environments,
+ stdin and stdout are not compile-time constant. You can
+ force the initialization using "%option stdinit" in the first
+ section of your flex input.
+
+ - "%option nounput" now correctly omits the unput() routine
+ from the output.
+
+ - "make clean" now removes config.log, config.cache, and the
+ flex binary. The fact that it removes the flex binary means
+ you should take care if making changes to scan.l, to make
+ sure you don't wind up in a bootstrap problem.
+
+ - In general, the Makefile has been reworked somewhat (thanks
+ to Francois Pinard) for added flexibility - more changes will
+ follow in subsequent releases.
+
+ - The .texi and .info files in MISC/texinfo/ have been updated,
+ thanks also to Francois Pinard.
+
+ - The FlexLexer::yylex(istream* new_in, ostream* new_out) method
+ now does not have a default for the first argument, to disambiguate
+ it from FlexLexer::yylex().
+
+ - A bug in destructing a FlexLexer object before doing any scanning
+ with it has been fixed.
+
+ - A problem with including FlexLexer.h multiple times has been fixed.
+
+ - The alloca() chud necessary to accommodate bison has grown
+ even uglier, but hopefully more correct.
+
+ - A portability tweak has been added to accommodate compilers that
+ use char* generic pointers.
+
+ - EBCDIC contact information in the file MISC/EBCDIC has been updated.
+
+ - An OS/2 Makefile and config.h for flex 2.5 is now available in
+ MISC/OS2/, contributed by Kai Uwe Rommel.
+
+ - The descrip.mms file for building flex under VMS has been updated,
+ thanks to Pat Rankin.
+
+ - The notes on building flex for the Amiga have been updated for
+ flex 2.5, contributed by Andreas Scherer.
+
+
+Changes between release 2.5.1 (28Mar95) and release 2.4.7:
+
+ - A new concept of "start condition" scope has been introduced.
+ A start condition scope is begun with:
+
+ <SCs>{
+
+ where SCs is a list of one or more start conditions. Inside
+ the start condition scope, every rule automatically has the
+ prefix <SCs> applied to it, until a '}' which matches the
+ initial '{'. So, for example:
+
+ <ESC>{
+ "\\n" return '\n';
+ "\\r" return '\r';
+ "\\f" return '\f';
+ "\\0" return '\0';
+ }
+
+ is equivalent to:
+
+ <ESC>"\\n" return '\n';
+ <ESC>"\\r" return '\r';
+ <ESC>"\\f" return '\f';
+ <ESC>"\\0" return '\0';
+
+ As indicated in this example, rules inside start condition scopes
+ (and any rule, actually, other than the first) can be indented,
+ to better show the extent of the scope.
+
+ Start condition scopes may be nested.
+
+ - The new %option directive can be used in the first section of
+ a flex scanner to control scanner-generation options. Most
+ options are given simply as names, optionally preceded by the
+ word "no" (with no intervening whitespace) to negate their
+ meaning. Some are equivalent to flex flags, so putting them
+ in your scanner source is equivalent to always specifying
+ the flag (%option's take precedence over flags):
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+ caseful opposite of -i option (caseful is the default);
+ case-sensitive same as above
+ caseless -i option;
+ case-insensitive same as above
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option (so use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+ Some provide new features:
+
+ always-interactive generate a scanner which always
+ considers its input "interactive" (no call to isatty()
+ will be made when the scanner runs)
+ main supply a main program for the scanner, which
+ simply calls yylex(). Implies %option noyywrap.
+ never-interactive generate a scanner which never
+ considers its input "interactive" (no call to isatty()
+ will be made when the scanner runs)
+ stack if set, enable start condition stacks (see below)
+ stdinit if unset ("%option nostdinit"), initialize yyin
+ and yyout statically to nil FILE* pointers, instead
+ of stdin and stdout
+ yylineno if set, keep track of the current line
+ number in global yylineno (this option is expensive
+ in terms of performance). The line number is available
+ to C++ scanning objects via the new member function
+ lineno().
+ yywrap if unset ("%option noyywrap"), scanner does not
+ call yywrap() upon EOF but simply assumes there
+ are no more files to scan
+
+ Flex scans your rule actions to determine whether you use the
+ REJECT or yymore features (this is not new). Two %options can be
+ used to override its decision, either by setting them to indicate
+ the feature is indeed used, or unsetting them to indicate it
+ actually is not used:
+
+ reject
+ yymore
+
+ Three %option's take string-delimited values, offset with '=':
+
+ outfile="<name>" equivalent to -o<name>
+ prefix="<name>" equivalent to -P<name>
+ yyclass="<name>" set the name of the C++ scanning class
+ (see below)
+
+ A number of %option's are available for lint purists who
+ want to suppress the appearance of unneeded routines in
+ the generated scanner. Each of the following, if unset,
+ results in the corresponding routine not appearing in the
+ generated scanner:
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+ You can specify multiple options with a single %option directive,
+ and multiple directives in the first section of your flex input file.
+
+ - The new function:
+
+ YY_BUFFER_STATE yy_scan_string( const char *str )
+
+ returns a YY_BUFFER_STATE (which also becomes the current input
+ buffer) for scanning the given string, which occurs starting
+ with the next call to yylex(). The string must be NUL-terminated.
+ A related function:
+
+ YY_BUFFER_STATE yy_scan_bytes( const char *bytes, int len )
+
+ creates a buffer for scanning "len" bytes (including possibly NUL's)
+ starting at location "bytes".
+
+ Note that both of these functions create and scan a *copy* of
+ the string/bytes. (This may be desirable, since yylex() modifies
+ the contents of the buffer it is scanning.) You can avoid the
+ copy by using:
+
+ YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+
+ which scans in place the buffer starting at "base", consisting
+ of "size" bytes, the last two bytes of which *must* be
+ YY_END_OF_BUFFER_CHAR (these bytes are not scanned; thus, scanning
+ consists of base[0] through base[size-2], inclusive). If you
+ fail to set up "base" in this manner, yy_scan_buffer returns a
+ nil pointer instead of creating a new input buffer.
+
+ The type yy_size_t is an integral type to which you can cast
+ an integer expression reflecting the size of the buffer.
+
+ - Three new routines are available for manipulating stacks of
+ start conditions:
+
+ void yy_push_state( int new_state )
+
+ pushes the current start condition onto the top of the stack
+ and BEGIN's "new_state" (recall that start condition names are
+ also integers).
+
+ void yy_pop_state()
+
+ pops the top of the stack and BEGIN's to it, and
+
+ int yy_top_state()
+
+ returns the top of the stack without altering the stack's
+ contents.
+
+ The start condition stack grows dynamically and so has no built-in
+ size limitation. If memory is exhausted, program execution
+ is aborted.
+
+ To use start condition stacks, your scanner must include
+ a "%option stack" directive.
+
+ - flex now supports POSIX character class expressions. These
+ are expressions enclosed inside "[:" and ":]" delimiters (which
+ themselves must appear between the '[' and ']' of a character
+ class; other elements may occur inside the character class, too).
+ The expressions flex recognizes are:
+
+ [:alnum:] [:alpha:] [:blank:] [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:] [:space:] [:upper:] [:xdigit:]
+
+ These expressions all designate a set of characters equivalent to
+ the corresponding isXXX function (for example, [:alnum:] designates
+ those characters for which isalnum() returns true - i.e., any
+ alphabetic or numeric). Some systems don't provide isblank(),
+ so flex defines [:blank:] as a blank or a tab.
+
+ For example, the following character classes are all equivalent:
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+ If your scanner is case-insensitive (-i flag), then [:upper:]
+ and [:lower:] are equivalent to [:alpha:].
+
+ - The promised rewrite of the C++ FlexLexer class has not yet
+ been done. Support for FlexLexer is limited at the moment to
+ fixing show-stopper bugs, so, for example, the new functions
+ yy_scan_string() & friends are not available to FlexLexer
+ objects.
+
+ - The new macro
+
+ yy_set_interactive(is_interactive)
+
+ can be used to control whether the current buffer is considered
+ "interactive". An interactive buffer is processed more slowly,
+ but must be used when the scanner's input source is indeed
+ interactive to avoid problems due to waiting to fill buffers
+ (see the discussion of the -I flag in flex.1). A non-zero value
+ in the macro invocation marks the buffer as interactive, a zero
+ value as non-interactive. Note that use of this macro overrides
+ "%option always-interactive" or "%option never-interactive".
+
+ yy_set_interactive() must be invoked prior to beginning to
+ scan the buffer.
+
+ - The new macro
+
+ yy_set_bol(at_bol)
+
+ can be used to control whether the current buffer's scanning
+ context for the next token match is done as though at the
+ beginning of a line (non-zero macro argument; makes '^' anchored
+ rules active) or not at the beginning of a line (zero argument,
+ '^' rules inactive).
+
+ - Related to this change, the mechanism for determining when a scan is
+ starting at the beginning of a line has changed. It used to be
+ that '^' was active iff the character prior to that at which the
+ scan started was a newline. The mechanism now is that '^' is
+ active iff the last token ended in a newline (or the last call to
+ input() returned a newline). For most users, the difference in
+ mechanisms is negligible. Where it will make a difference,
+ however, is if unput() or yyless() is used to alter the input
+ stream. When in doubt, use yy_set_bol().
+
+ - The new beginning-of-line mechanism involved changing some fairly
+ twisted code, so it may have introduced bugs - beware ...
+
+ - The macro YY_AT_BOL() returns true if the next token scanned from
+ the current buffer will have '^' rules active, false otherwise.
+
+ - The new function
+
+ void yy_flush_buffer( struct yy_buffer_state* b )
+
+ flushes the contents of the current buffer (i.e., next time
+ the scanner attempts to match a token using b as the current
+ buffer, it will begin by invoking YY_INPUT to fill the buffer).
+ This routine is also available to C++ scanners (unlike some
+ of the other new routines).
+
+ The related macro
+
+ YY_FLUSH_BUFFER
+
+ flushes the contents of the current buffer.
+
+ - A new "-ooutput" option writes the generated scanner to "output".
+ If used with -t, the scanner is still written to stdout, but
+ its internal #line directives (see previous item) use "output".
+
+ - Flex now generates #line directives relating the code it
+ produces to the output file; this means that error messages
+ in the flex-generated code should be correctly pinpointed.
+
+ - When generating #line directives, filenames with embedded '\'s
+ have those characters escaped (i.e., turned into '\\'). This
+ feature helps with reporting filenames for some MS-DOS and OS/2
+ systems.
+
+ - The FlexLexer class includes two new public member functions:
+
+ virtual void switch_streams( istream* new_in = 0,
+ ostream* new_out = 0 )
+
+ reassigns yyin to new_in (if non-nil) and yyout to new_out
+ (ditto), deleting the previous input buffer if yyin is
+ reassigned. It is used by:
+
+ int yylex( istream* new_in = 0, ostream* new_out = 0 )
+
+ which first calls switch_streams() and then returns the value
+ of calling yylex().
+
+ - C++ scanners now have yy_flex_debug as a member variable of
+ FlexLexer rather than a global, and member functions for testing
+ and setting it.
+
+ - When generating a C++ scanning class, you can now use
+
+ %option yyclass="foo"
+
+ to inform flex that you have derived "foo" as a subclass of
+ yyFlexLexer, so flex will place your actions in the member
+ function foo::yylex() instead of yyFlexLexer::yylex(). It also
+ generates a yyFlexLexer::yylex() member function that generates a
+ run-time error if called (by invoking yyFlexLexer::LexerError()).
+ This feature is necessary if your subclass "foo" introduces some
+ additional member functions or variables that you need to access
+ from yylex().
+
+ - Current texinfo files in MISC/texinfo, contributed by Francois
+ Pinard.
+
+ - You can now change the name "flex" to something else (e.g., "lex")
+ by redefining $(FLEX) in the Makefile.
+
+ - Two bugs (one serious) that could cause "bigcheck" to fail have
+ been fixed.
+
+ - A number of portability/configuration changes have been made
+ for easier portability.
+
+ - You can use "YYSTATE" in your scanner as an alias for YY_START
+ (for AT&T lex compatibility).
+
+ - input() now maintains yylineno.
+
+ - input() no longer trashes yytext.
+
+ - interactive scanners now read characters in YY_INPUT up to a
+ newline, a large performance gain.
+
+ - C++ scanner objects now work with the -P option. You include
+ <FlexLexer.h> once per scanner - see comments in <FlexLexer.h>
+ (or flex.1) for details.
+
+ - C++ FlexLexer objects now use the "cerr" stream to report -d output
+ instead of stdio.
+
+ - The -c flag now has its full glorious POSIX interpretation (do
+ nothing), rather than being interpreted as an old-style -C flag.
+
+ - Scanners generated by flex now include two #define's giving
+ the major and minor version numbers (YY_FLEX_MAJOR_VERSION,
+ YY_FLEX_MINOR_VERSION). These can then be tested to see
+ whether certain flex features are available.
+
+ - Scanners generated using -l lex compatibility now have the symbol
+ YY_FLEX_LEX_COMPAT #define'd.
+
+ - When initializing (i.e., yy_init is non-zero on entry to yylex()),
+ generated scanners now set yy_init to zero before executing
+ YY_USER_INIT. This means that you can set yy_init back to a
+ non-zero value in YY_USER_INIT if you need the scanner to be
+ reinitialized on the next call.
+
+ - You can now use "#line" directives in the first section of your
+ scanner specification.
+
+ - When generating full-table scanners (-Cf), flex now puts braces
+ around each row of the 2-d array initialization, to silence warnings
+ on over-zealous compilers.
+
+ - Improved support for MS-DOS. The flex sources have been successfully
+ built, unmodified, for Borland 4.02 (all that's required is a
+ Borland Makefile and config.h file, which are supplied in
+ MISC/Borland - contributed by Terrence O Kane).
+
+ - Improved support for Macintosh using Think C - the sources should
+ build for this platform "out of the box". Contributed by Scott
+ Hofmann.
+
+ - Improved support for VMS, in MISC/VMS/, contributed by Pat Rankin.
+
+ - Support for the Amiga, in MISC/Amiga/, contributed by Andreas
+ Scherer. Note that the contributed files were developed for
+ flex 2.4 and have not been tested with flex 2.5.
+
+ - Some notes on support for the NeXT, in MISC/NeXT, contributed
+ by Raf Schietekat.
+
+ - The MISC/ directory now includes a preformatted version of flex.1
+ in flex.man, and pre-yacc'd versions of parse.y in parse.{c,h}.
+
+ - The flex.1 and flexdoc.1 manual pages have been merged. There
+ is now just one document, flex.1, which includes an overview
+ at the beginning to help you find the section you need.
+
+ - Documentation now clarifies that start conditions persist across
+ switches to new input files or different input buffers. If you
+ want to e.g., return to INITIAL, you must explicitly do so.
+
+ - The "Performance Considerations" section of the manual has been
+ updated.
+
+ - Documented the "yy_act" variable, which when YY_USER_ACTION is
+ invoked holds the number of the matched rule, and added an
+ example of using yy_act to profile how often each rule is matched.
+
+ - Added YY_NUM_RULES, a definition that gives the total number
+ of rules in the file, including the default rule (even if you
+ use -s).
+
+ - Documentation now clarifies that you can pass a nil FILE* pointer
+ to yy_create_buffer() or yyrestart() if you've arrange YY_INPUT
+ to not need yyin.
+
+ - Documentation now clarifies that YY_BUFFER_STATE is a pointer to
+ an opaque "struct yy_buffer_state".
+
+ - Documentation now stresses that you gain the benefits of removing
+ backing-up states only if you remove *all* of them.
+
+ - Documentation now points out that traditional lex allows you
+ to put the action on a separate line from the rule pattern if
+ the pattern has trailing whitespace (ugh!), but flex doesn't
+ support this.
+
+ - A broken example in documentation of the difference between
+ inclusive and exclusive start conditions is now fixed.
+
+ - Usage (-h) report now goes to stdout.
+
+ - Version (-V) info now goes to stdout.
+
+ - More #ifdef chud has been added to the parser in attempt to
+ deal with bison's use of alloca().
+
+ - "make clean" no longer deletes emacs backup files (*~).
+
+ - Some memory leaks have been fixed.
+
+ - A bug was fixed in which dynamically-expanded buffers were
+ reallocated a couple of bytes too small.
+
+ - A bug was fixed which could cause flex to read and write beyond
+ the end of the input buffer.
+
+ - -S will not be going away.
+
+
+Changes between release 2.4.7 (03Aug94) and release 2.4.6:
+
+ - Fixed serious bug in reading multiple files.
+
+ - Fixed bug in scanning NUL's.
+
+ - Fixed bug in input() returning 8-bit characters.
+
+ - Fixed bug in matching text with embedded NUL's when
+ using %array or lex compatibility.
+
+ - Fixed multiple invocations of YY_USER_ACTION when using '|'
+ continuation action.
+
+ - Minor prototyping fixes.
+
+Changes between release 2.4.6 (04Jan94) and release 2.4.5:
+
+ - Linking with -lfl no longer required if your program includes
+ its own yywrap() and main() functions. (This change will cause
+ problems if you have a non-ANSI compiler on a system for which
+ sizeof(int) != sizeof(void*) or sizeof(int) != sizeof(size_t).)
+
+ - The use of 'extern "C++"' in FlexLexer.h has been modified to
+ get around an incompatibility with g++'s header files.
+
+Changes between release 2.4.5 (11Dec93) and release 2.4.4:
+
+ - Fixed bug breaking C++ scanners that use REJECT or variable
+ trailing context.
+
+ - Fixed serious input problem for interactive scanners on
+ systems for which char is unsigned.
+
+ - Fixed bug in incorrectly treating '$' operator as variable
+ trailing context.
+
+ - Fixed bug in -CF table representation that could lead to
+ corrupt tables.
+
+ - Fixed fairly benign memory leak.
+
+ - Added `extern "C++"' wrapper to FlexLexer.h header. This
+ should overcome the g++ 2.5.X problems mentioned in the
+ NEWS for release 2.4.3.
+
+ - Changed #include of FlexLexer.h to use <> instead of "".
+
+ - Added feature to control whether the scanner attempts to
+ refill the input buffer once it's exhausted. This feature
+ will be documented in the 2.5 release.
+
+
+Changes between release 2.4.4 (07Dec93) and release 2.4.3:
+
+ - Fixed two serious bugs in scanning 8-bit characters.
+
+ - Fixed bug in YY_USER_ACTION that caused it to be executed
+ inappropriately (on the scanner's own internal actions, and
+ with incorrect yytext/yyleng values).
+
+ - Fixed bug in pointing yyin at a new file and resuming scanning.
+
+ - Portability fix regarding min/max/abs macros conflicting with
+ function definitions in standard header files.
+
+ - Added a virtual LexerError() method to the C++ yyFlexLexer class
+ for reporting error messages instead of always using cerr.
+
+ - Added warning in flexdoc that the C++ scanning class is presently
+ experimental and subject to considerable change between major
+ releases.
+
+
+Changes between release 2.4.3 (03Dec93) and release 2.4.2:
+
+ - Fixed bug causing fatal scanner messages to fail to print.
+
+ - Fixed things so FlexLexer.h can be included in other C++
+ sources. One side-effect of this change is that -+ and -CF
+ are now incompatible.
+
+ - libfl.a now supplies private versions of the the <string.h>/
+ <strings.h> string routines needed by flex and the scanners
+ it generates, to enhance portability to some BSD systems.
+
+ - More robust solution to 2.4.2's flexfatal() bug fix.
+
+ - Added ranlib of installed libfl.a.
+
+ - Some lint tweaks.
+
+ - NOTE: problems have been encountered attempting to build flex
+ C++ scanners using g++ version 2.5.X. The problem is due to an
+ unfortunate heuristic in g++ 2.5.X that attempts to discern between
+ C and C++ headers. Because FlexLexer.h is installed (by default)
+ in /usr/local/include and not /usr/local/lib/g++-include, g++ 2.5.X
+ decides that it's a C header :-(. So if you have problems, install
+ the header in /usr/local/lib/g++-include instead.
+
+
+Changes between release 2.4.2 (01Dec93) and release 2.4.1:
+
+ - Fixed bug in libfl.a referring to non-existent "flexfatal" function.
+
+ - Modified to produce both compress'd and gzip'd tar files for
+ distributions (you probably don't care about this change!).
+
+
+Changes between release 2.4.1 (30Nov93) and release 2.3.8:
+
+ - The new '-+' flag instructs flex to generate a C++ scanner class
+ (thanks to Kent Williams). flex writes an implementation of the
+ class defined in FlexLexer.h to lex.yy.cc. You may include
+ multiple scanner classes in your program using the -P flag. Note
+ that the scanner class also provides a mechanism for creating
+ reentrant scanners. The scanner class uses C++ streams for I/O
+ instead of FILE*'s (thanks to Tom Epperly). If the flex executable's
+ name ends in '+' then the '-+' flag is automatically on, so creating
+ a symlink or copy of "flex" to "flex++" results in a version of
+ flex that can be used exclusively for C++ scanners.
+
+ Note that without the '-+' flag, flex-generated scanners can still
+ be compiled using C++ compilers, though they use FILE*'s for I/O
+ instead of streams.
+
+ See the "GENERATING C++ SCANNERS" section of flexdoc for details.
+
+ - The new '-l' flag turns on maximum AT&T lex compatibility. In
+ particular, -l includes support for "yylineno" and makes yytext
+ be an array instead of a pointer. It does not, however, do away
+ with all incompatibilities. See the "INCOMPATIBILITIES WITH LEX
+ AND POSIX" section of flexdoc for details.
+
+ - The new '-P' option specifies a prefix to use other than "yy"
+ for the scanner's globally-visible variables, and for the
+ "lex.yy.c" filename. Using -P you can link together multiple
+ flex scanners in the same executable.
+
+ - The distribution includes a "texinfo" version of flexdoc.1,
+ contributed by Roland Pesch (thanks also to Marq Kole, who
+ contributed another version). It has not been brought up to
+ date, but reflects version 2.3. See MISC/flex.texinfo.
+
+ The flex distribution will soon include G.T. Nicol's flex
+ manual; he is presently bringing it up-to-date for version 2.4.
+
+ - yywrap() is now a function, and you now *must* link flex scanners
+ with libfl.a.
+
+ - Site-configuration is now done via an autoconf-generated
+ "configure" script contributed by Francois Pinard.
+
+ - Scanners now use fread() (or getc(), if interactive) and not
+ read() for input. A new "table compression" option, -Cr,
+ overrides this change and causes the scanner to use read()
+ (because read() is a bit faster than fread()). -f and -F
+ are now equivalent to -Cfr and -CFr; i.e., they imply the
+ -Cr option.
+
+ - In the blessed name of POSIX compliance, flex supports "%array"
+ and "%pointer" directives in the definitions (first) section of
+ the scanner specification. The former specifies that yytext
+ should be an array (of size YYLMAX), the latter, that it should
+ be a pointer. The array version of yytext is universally slower
+ than the pointer version, but has the advantage that its contents
+ remain unmodified across calls to input() and unput() (the pointer
+ version of yytext is, still, trashed by such calls).
+
+ "%array" cannot be used with the '-+' C++ scanner class option.
+
+ - The new '-Ca' option directs flex to trade off memory for
+ natural alignment when generating a scanner's tables. In
+ particular, table entries that would otherwise be "short"
+ become "long".
+
+ - The new '-h' option produces a summary of the flex flags.
+
+ - The new '-V' option reports the flex version number and exits.
+
+ - The new scanner macro YY_START returns an integer value
+ corresponding to the current start condition. You can return
+ to that start condition by passing the value to a subsequent
+ "BEGIN" action. You also can implement "start condition stacks"
+ by storing the values in an integer stack.
+
+ - You can now redefine macros such as YY_INPUT by just #define'ing
+ them to some other value in the first section of the flex input;
+ no need to first #undef them.
+
+ - flex now generates warnings for rules that can't be matched.
+ These warnings can be turned off using the new '-w' flag. If
+ your scanner uses REJECT then you will not get these warnings.
+
+ - If you specify the '-s' flag but the default rule can be matched,
+ flex now generates a warning.
+
+ - "yyleng" is now a global, and may be modified by the user (though
+ doing so and then using yymore() will yield weird results).
+
+ - Name definitions in the first section of a scanner specification
+ can now include a leading '^' or trailing '$' operator. In this
+ case, the definition is *not* pushed back inside of parentheses.
+
+ - Scanners with compressed tables are now "interactive" (-I option)
+ by default. You can suppress this attribute (which makes them
+ run slightly slower) using the new '-B' flag.
+
+ - Flex now generates 8-bit scanners by default, unless you use the
+ -Cf or -CF compression options (-Cfe and -CFe result in 8-bit
+ scanners). You can force it to generate a 7-bit scanner using
+ the new '-7' flag. You can build flex to generate 8-bit scanners
+ for -Cf and -CF, too, by adding -DDEFAULT_CSIZE=256 to CFLAGS
+ in the Makefile.
+
+ - You no longer need to call the scanner routine yyrestart() to
+ inform the scanner that you have switched to a new file after
+ having seen an EOF on the current input file. Instead, just
+ point yyin at the new file and continue scanning.
+
+ - You no longer need to invoke YY_NEW_FILE in an <<EOF>> action
+ to indicate you wish to continue scanning. Simply point yyin
+ at a new file.
+
+ - A leading '#' no longer introduces a comment in a flex input.
+
+ - flex no longer considers formfeed ('\f') a whitespace character.
+
+ - %t, I'm happy to report, has been nuked.
+
+ - The '-p' option may be given twice ('-pp') to instruct flex to
+ report minor performance problems as well as major ones.
+
+ - The '-v' verbose output no longer includes start/finish time
+ information.
+
+ - Newlines in flex inputs can optionally include leading or
+ trailing carriage-returns ('\r'), in support of several PC/Mac
+ run-time libraries that automatically include these.
+
+ - A start condition of the form "<*>" makes the following rule
+ active in every start condition, whether exclusive or inclusive.
+
+ - The following items have been corrected in the flex documentation:
+
+ - '-C' table compression options *are* cumulative.
+
+ - You may modify yytext but not lengthen it by appending
+ characters to the end. Modifying its final character
+ will affect '^' anchoring for the next rule matched
+ if the character is changed to or from a newline.
+
+ - The term "backtracking" has been renamed "backing up",
+ since it is a one-time repositioning and not a repeated
+ search. What used to be the "lex.backtrack" file is now
+ "lex.backup".
+
+ - Unindented "/* ... */" comments are allowed in the first
+ flex input section, but not in the second.
+
+ - yyless() can only be used in the flex input source, not
+ externally.
+
+ - You can use "yyrestart(yyin)" to throw away the
+ current contents of the input buffer.
+
+ - To write high-speed scanners, attempt to match as much
+ text as possible with each rule. See MISC/fastwc/README
+ for more information.
+
+ - Using the beginning-of-line operator ('^') is fairly
+ cheap. Using unput() is expensive. Using yyless() is
+ cheap.
+
+ - An example of scanning strings with embedded escape
+ sequences has been added.
+
+ - The example of backing-up in flexdoc was erroneous; it
+ has been corrected.
+
+ - A flex scanner's internal buffer now dynamically grows if needed
+ to match large tokens. Note that growing the buffer presently
+ requires rescanning the (large) token, so consuming a lot of
+ text this way is a slow process. Also note that presently the
+ buffer does *not* grow if you unput() more text than can fit
+ into the buffer.
+
+ - The MISC/ directory has been reorganized; see MISC/README for
+ details.
+
+ - yyless() can now be used in the third (user action) section
+ of a scanner specification, thanks to Ceriel Jacobs. yyless()
+ remains a macro and cannot be used outside of the scanner source.
+
+ - The skeleton file is no longer opened at run-time, but instead
+ compiled into a large string array (thanks to John Gilmore and
+ friends at Cygnus). You can still use the -S flag to point flex
+ at a different skeleton file.
+
+ - flex no longer uses a temporary file to store the scanner's
+ actions.
+
+ - A number of changes have been made to decrease porting headaches.
+ In particular, flex no longer uses memset() or ctime(), and
+ provides a single simple mechanism for dealing with C compilers
+ that still define malloc() as returning char* instead of void*.
+
+ - Flex now detects if the scanner specification requires the -8 flag
+ but the flag was not given or on by default.
+
+ - A number of table-expansion fencepost bugs have been fixed,
+ making flex more robust for generating large scanners.
+
+ - flex more consistently identifies the location of errors in
+ its input.
+
+ - YY_USER_ACTION is now invoked only for "real" actions, not for
+ internal actions used by the scanner for things like filling
+ the buffer or handling EOF.
+
+ - The rule "[^]]" now matches any character other than a ']';
+ formerly it matched any character at all followed by a ']'.
+ This change was made for compatibility with AT&T lex.
+
+ - A large number of miscellaneous bugs have been found and fixed
+ thanks to Gerhard Wilhelms.
+
+ - The source code has been heavily reformatted, making patches
+ relative to previous flex releases no longer accurate.
+
+
+Changes between 2.3 Patch #8 (21Feb93) and 2.3 Patch #7:
+
+ - Fixed bugs in dynamic memory allocation leading to grievous
+ fencepost problems when generating large scanners.
+ - Fixed bug causing infinite loops on character classes with 8-bit
+ characters in them.
+ - Fixed bug in matching repetitions with a lower bound of 0.
+ - Fixed bug in scanning NUL characters using an "interactive" scanner.
+ - Fixed bug in using yymore() at the end of a file.
+ - Fixed bug in misrecognizing rules with variable trailing context.
+ - Fixed bug compiling flex on Suns using gcc 2.
+ - Fixed bug in not recognizing that input files with the character
+ ASCII 128 in them require the -8 flag.
+ - Fixed bug that could cause an infinite loop writing out
+ error messages.
+ - Fixed bug in not recognizing old-style lex % declarations if
+ followed by a tab instead of a space.
+ - Fixed potential crash when flex terminated early (usually due
+ to a bad flag) and the -v flag had been given.
+ - Added some missing declarations of void functions.
+ - Changed to only use '\a' for __STDC__ compilers.
+ - Updated mailing addresses.
+
+
+Changes between 2.3 Patch #7 (28Mar91) and 2.3 Patch #6:
+
+ - Fixed out-of-bounds array access that caused bad tables
+ to be produced on machines where the bad reference happened
+ to yield a 1. This caused problems installing or running
+ flex on some Suns, in particular.
+
+
+Changes between 2.3 Patch #6 (29Aug90) and 2.3 Patch #5:
+
+ - Fixed a serious bug in yymore() which basically made it
+ completely broken. Thanks goes to Jean Christophe of
+ the Nethack development team for finding the problem
+ and passing along the fix.
+
+
+Changes between 2.3 Patch #5 (16Aug90) and 2.3 Patch #4:
+
+ - An up-to-date version of initscan.c so "make test" will
+ work after applying the previous patches
+
+
+Changes between 2.3 Patch #4 (14Aug90) and 2.3 Patch #3:
+
+ - Fixed bug in hexadecimal escapes which allowed only digits,
+ not letters, in escapes
+ - Fixed bug in previous "Changes" file!
+
+
+Changes between 2.3 Patch #3 (03Aug90) and 2.3 Patch #2:
+
+ - Correction to patch #2 for gcc compilation; thanks goes to
+ Paul Eggert for catching this.
+
+
+Changes between 2.3 Patch #2 (02Aug90) and original 2.3 release:
+
+ - Fixed (hopefully) headaches involving declaring malloc()
+ and free() for gcc, which defines __STDC__ but (often) doesn't
+ come with the standard include files such as <stdlib.h>.
+ Reordered #ifdef maze in the scanner skeleton in the hope of
+ getting the declarations right for cfront and g++, too.
+
+ - Note that this patch supercedes patch #1 for release 2.3,
+ which was never announced but was available briefly for
+ anonymous ftp.
+
+
+Changes between 2.3 (full) release of 28Jun90 and 2.2 (alpha) release:
+
+ User-visible:
+
+ - A lone <<EOF>> rule (that is, one which is not qualified with
+ a list of start conditions) now specifies the EOF action for
+ *all* start conditions which haven't already had <<EOF>> actions
+ given. To specify an end-of-file action for just the initial
+ state, use <INITIAL><<EOF>>.
+
+ - -d debug output is now contigent on the global yy_flex_debug
+ being set to a non-zero value, which it is by default.
+
+ - A new macro, YY_USER_INIT, is provided for the user to specify
+ initialization action to be taken on the first call to the
+ scanner. This action is done before the scanner does its
+ own initialization.
+
+ - yy_new_buffer() has been added as an alias for yy_create_buffer()
+
+ - Comments beginning with '#' and extending to the end of the line
+ now work, but have been deprecated (in anticipation of making
+ flex recognize #line directives).
+
+ - The funky restrictions on when semi-colons could follow the
+ YY_NEW_FILE and yyless macros have been removed. They now
+ behave identically to functions.
+
+ - A bug in the sample redefinition of YY_INPUT in the documentation
+ has been corrected.
+
+ - A bug in the sample simple tokener in the documentation has
+ been corrected.
+
+ - The documentation on the incompatibilities between flex and
+ lex has been reordered so that the discussion of yylineno
+ and input() come first, as it's anticipated that these will
+ be the most common source of headaches.
+
+
+ Things which didn't used to be documented but now are:
+
+ - flex interprets "^foo|bar" differently from lex. flex interprets
+ it as "match either a 'foo' or a 'bar', providing it comes at the
+ beginning of a line", whereas lex interprets it as "match either
+ a 'foo' at the beginning of a line, or a 'bar' anywhere".
+
+ - flex initializes the global "yyin" on the first call to the
+ scanner, while lex initializes it at compile-time.
+
+ - yy_switch_to_buffer() can be used in the yywrap() macro/routine.
+
+ - flex scanners do not use stdio for their input, and hence when
+ writing an interactive scanner one must explictly call fflush()
+ after writing out a prompt.
+
+ - flex scanner can be made reentrant (after a fashion) by using
+ "yyrestart( yyin );". This is useful for interactive scanners
+ which have interrupt handlers that long-jump out of the scanner.
+
+ - a defense of why yylineno is not supported is included, along
+ with a suggestion on how to convert scanners which rely on it.
+
+
+ Other changes:
+
+ - Prototypes and proper declarations of void routines have
+ been added to the flex source code, courtesy of Kevin B. Kenny.
+
+ - Routines dealing with memory allocation now use void* pointers
+ instead of char* - see Makefile for porting implications.
+
+ - Error-checking is now done when flex closes a file.
+
+ - Various lint tweaks were added to reduce the number of gripes.
+
+ - Makefile has been further parameterized to aid in porting.
+
+ - Support for SCO Unix added.
+
+ - Flex now sports the latest & greatest UC copyright notice
+ (which is only slightly different from the previous one).
+
+ - A note has been added to flexdoc.1 mentioning work in progress
+ on modifying flex to generate straight C code rather than a
+ table-driven automaton, with an email address of whom to contact
+ if you are working along similar lines.
+
+
+Changes between 2.2 Patch #3 (30Mar90) and 2.2 Patch #2:
+
+ - fixed bug which caused -I scanners to bomb
+
+
+Changes between 2.2 Patch #2 (27Mar90) and 2.2 Patch #1:
+
+ - fixed bug writing past end of input buffer in yyunput()
+ - fixed bug detecting NUL's at the end of a buffer
+
+
+Changes between 2.2 Patch #1 (23Mar90) and 2.2 (alpha) release:
+
+ - Makefile fixes: definition of MAKE variable for systems
+ which don't have it; installation of flexdoc.1 along with
+ flex.1; fixed two bugs which could cause "bigtest" to fail.
+
+ - flex.skel fix for compiling with g++.
+
+ - README and flexdoc.1 no longer list an out-of-date BITNET address
+ for contacting me.
+
+ - minor typos and formatting changes to flex.1 and flexdoc.1.
+
+
+Changes between 2.2 (alpha) release of March '90 and previous release:
+
+ User-visible:
+
+ - Full user documentation now available.
+
+ - Support for 8-bit scanners.
+
+ - Scanners now accept NUL's.
+
+ - A facility has been added for dealing with multiple
+ input buffers.
+
+ - Two manual entries now. One which fully describes flex
+ (rather than just its differences from lex), and the
+ other for quick(er) reference.
+
+ - A number of changes to bring flex closer into compliance
+ with the latest POSIX lex draft:
+
+ %t support
+ flex now accepts multiple input files and concatenates
+ them together to form its input
+ previous -c (compress) flag renamed -C
+ do-nothing -c and -n flags added
+ Any indented code or code within %{}'s in section 2 is
+ now copied to the output
+
+ - yyleng is now a bona fide global integer.
+
+ - -d debug information now gives the line number of the
+ matched rule instead of which number rule it was from
+ the beginning of the file.
+
+ - -v output now includes a summary of the flags used to generate
+ the scanner.
+
+ - unput() and yyrestart() are now globally callable.
+
+ - yyrestart() no longer closes the previous value of yyin.
+
+ - C++ support; generated scanners can be compiled with C++ compiler.
+
+ - Primitive -lfl library added, containing default main()
+ which calls yylex(). A number of routines currently living
+ in the scanner skeleton will probably migrate to here
+ in the future (in particular, yywrap() will probably cease
+ to be a macro and instead be a function in the -lfl library).
+
+ - Hexadecimal (\x) escape sequences added.
+
+ - Support for MS-DOS, VMS, and Turbo-C integrated.
+
+ - The %used/%unused operators have been deprecated. They
+ may go away soon.
+
+
+ Other changes:
+
+ - Makefile enhanced for easier testing and installation.
+ - The parser has been tweaked to detect some erroneous
+ constructions which previously were missed.
+ - Scanner input buffer overflow is now detected.
+ - Bugs with missing "const" declarations fixed.
+ - Out-of-date Minix/Atari patches provided.
+ - Scanners no longer require printf() unless FLEX_DEBUG is being used.
+ - A subtle input() bug has been fixed.
+ - Line numbers for "continued action" rules (those following
+ the special '|' action) are now correct.
+ - unput() bug fixed; had been causing problems porting flex to VMS.
+ - yymore() handling rewritten to fix bug with interaction
+ between yymore() and trailing context.
+ - EOF in actions now generates an error message.
+ - Bug involving -CFe and generating equivalence classes fixed.
+ - Bug which made -CF be treated as -Cf fixed.
+ - Support for SysV tmpnam() added.
+ - Unused #define's for scanner no longer generated.
+ - Error messages which are associated with a particular input
+ line are now all identified with their input line in standard
+ format.
+ - % directives which are valid to lex but not to flex are
+ now ignored instead of generating warnings.
+ - -DSYS_V flag can now also be specified -DUSG for System V
+ compilation.
+
+
+Changes between 2.1 beta-test release of June '89 and previous release:
+
+ User-visible:
+
+ - -p flag generates a performance report to stderr. The report
+ consists of comments regarding features of the scanner rules
+ which result in slower scanners.
+
+ - -b flag generates backtracking information to lex.backtrack.
+ This is a list of scanner states which require backtracking
+ and the characters on which they do so. By adding rules
+ one can remove backtracking states. If all backtracking states
+ are eliminated, the generated scanner will run faster.
+ Backtracking is not yet documented in the manual entry.
+
+ - Variable trailing context now works, i.e., one can have
+ rules like "(foo)*/[ \t]*bletch". Some trailing context
+ patterns still cannot be properly matched and generate
+ error messages. These are patterns where the ending of the
+ first part of the rule matches the beginning of the second
+ part, such as "zx*/xy*", where the 'x*' matches the 'x' at
+ the beginning of the trailing context. Lex won't get these
+ patterns right either.
+
+ - Faster scanners.
+
+ - End-of-file rules. The special rule "<<EOF>>" indicates
+ actions which are to be taken when an end-of-file is
+ encountered and yywrap() returns non-zero (i.e., indicates
+ no further files to process). See manual entry for example.
+
+ - The -r (reject used) flag is gone. flex now scans the input
+ for occurrences of the string "REJECT" to determine if the
+ action is needed. It tries to be intelligent about this but
+ can be fooled. One can force the presence or absence of
+ REJECT by adding a line in the first section of the form
+ "%used REJECT" or "%unused REJECT".
+
+ - yymore() has been implemented. Similarly to REJECT, flex
+ detects the use of yymore(), which can be overridden using
+ "%used" or "%unused".
+
+ - Patterns like "x{0,3}" now work (i.e., with lower-limit == 0).
+
+ - Removed '\^x' for ctrl-x misfeature.
+
+ - Added '\a' and '\v' escape sequences.
+
+ - \<digits> now works for octal escape sequences; previously
+ \0<digits> was required.
+
+ - Better error reporting; line numbers are associated with rules.
+
+ - yyleng is a macro; it cannot be accessed outside of the
+ scanner source file.
+
+ - yytext and yyleng should not be modified within a flex action.
+
+ - Generated scanners #define the name FLEX_SCANNER.
+
+ - Rules are internally separated by YY_BREAK in lex.yy.c rather
+ than break, to allow redefinition.
+
+ - The macro YY_USER_ACTION can be redefined to provide an action
+ which is always executed prior to the matched rule's action.
+
+ - yyrestart() is a new action which can be used to restart
+ the scanner after it has seen an end-of-file (a "real" one,
+ that is, one for which yywrap() returned non-zero). It takes
+ a FILE* argument indicating a new file to scan and sets
+ things up so that a subsequent call to yylex() will start
+ scanning that file.
+
+ - Internal scanner names all preceded by "yy_"
+
+ - lex.yy.c is deleted if errors are encountered during processing.
+
+ - Comments may be put in the first section of the input by preceding
+ them with '#'.
+
+
+
+ Other changes:
+
+ - Some portability-related bugs fixed, in particular for machines
+ with unsigned characters or sizeof( int* ) != sizeof( int ).
+ Also, tweaks for VMS and Microsoft C (MS-DOS), and identifiers all
+ trimmed to be 31 or fewer characters. Shortened file names
+ for dinosaur OS's. Checks for allocating > 64K memory
+ on 16 bit'ers. Amiga tweaks. Compiles using gcc on a Sun-3.
+ - Compressed and fast scanner skeletons merged.
+ - Skeleton header files done away with.
+ - Generated scanner uses prototypes and "const" for __STDC__.
+ - -DSV flag is now -DSYS_V for System V compilation.
+ - Removed all references to FTL language.
+ - Software now covered by BSD Copyright.
+ - flex will replace lex in subsequent BSD releases.
diff --git a/usr.bin/lex/README b/usr.bin/lex/README
new file mode 100644
index 0000000..7a4224d
--- /dev/null
+++ b/usr.bin/lex/README
@@ -0,0 +1,60 @@
+This is release 2.5 of flex. See "version.h" for the exact patch-level.
+
+See the file "NEWS" to find out what is new in this Flex release.
+
+Read the file "INSTALL" for general installation directives. Peek near
+the beginning of the file "Makefile.in" for special DEFS values. On most
+systems, you can just run the "configure" script and type "make" to build
+flex; then "make check" to test whether it built correctly; and if it did,
+then "make install" to install it.
+
+If you're feeling adventurous, you can also issue "make bigcheck" (be
+prepared to wait a while).
+
+Note that flex is distributed under a copyright very similar to that of
+BSD Unix, and not under the GNU General Public License (GPL), except for
+the "configure" script, which is covered by the GPL.
+
+Many thanks to the 2.5 beta-testers for finding bugs and helping test and
+increase portability: Stan Adermann, Scott David Daniels, Charles Elliott,
+Joe Gayda, Chris Meier, James Nordby, Terrence O'Kane, Karsten Pahnke,
+Francois Pinard, Pat Rankin, Andreas Scherer, Marc Wiese, Nathan Zelle.
+
+Please send bug reports and feedback to: Vern Paxson (vern@ee.lbl.gov).
+
+
+The flex distribution consists of the following files:
+
+ README This message
+
+ NEWS Differences between the various releases
+
+ INSTALL General installation information
+
+ COPYING flex's copyright
+
+ conf.in, configure.in, configure, Makefile.in, install.sh,
+ mkinstalldirs
+ elements of the "autoconf" auto-configuration process
+
+ flexdef.h, parse.y, scan.l, ccl.c, dfa.c, ecs.c, gen.c, main.c,
+ misc.c, nfa.c, sym.c, tblcmp.c, yylex.c
+ source files
+
+ version.h version of this flex release
+
+ flex.skl flex scanner skeleton
+ mkskel.sh script for converting flex.skl to C source file skel.c
+ skel.c pre-converted C version of flex.skl
+
+ libmain.c flex library (-lfl) sources
+ libyywrap.c
+
+ initscan.c pre-flex'd version of scan.l
+
+ FlexLexer.h header file for C++ lexer class
+
+ flex.1 user documentation
+
+ MISC/ a directory containing miscellaneous contributions.
+ See MISC/README for details.
diff --git a/usr.bin/lex/ccl.c b/usr.bin/lex/ccl.c
new file mode 100644
index 0000000..fe28463
--- /dev/null
+++ b/usr.bin/lex/ccl.c
@@ -0,0 +1,149 @@
+/* ccl - routines for character classes */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/ccl.c,v 2.9 93/09/16 20:32:14 vern Exp $ */
+
+#include "flexdef.h"
+
+/* ccladd - add a single character to a ccl */
+
+void ccladd( cclp, ch )
+int cclp;
+int ch;
+ {
+ int ind, len, newpos, i;
+
+ check_char( ch );
+
+ len = ccllen[cclp];
+ ind = cclmap[cclp];
+
+ /* check to see if the character is already in the ccl */
+
+ for ( i = 0; i < len; ++i )
+ if ( ccltbl[ind + i] == ch )
+ return;
+
+ newpos = ind + len;
+
+ if ( newpos >= current_max_ccl_tbl_size )
+ {
+ current_max_ccl_tbl_size += MAX_CCL_TBL_SIZE_INCREMENT;
+
+ ++num_reallocs;
+
+ ccltbl = reallocate_Character_array( ccltbl,
+ current_max_ccl_tbl_size );
+ }
+
+ ccllen[cclp] = len + 1;
+ ccltbl[newpos] = ch;
+ }
+
+
+/* cclinit - return an empty ccl */
+
+int cclinit()
+ {
+ if ( ++lastccl >= current_maxccls )
+ {
+ current_maxccls += MAX_CCLS_INCREMENT;
+
+ ++num_reallocs;
+
+ cclmap = reallocate_integer_array( cclmap, current_maxccls );
+ ccllen = reallocate_integer_array( ccllen, current_maxccls );
+ cclng = reallocate_integer_array( cclng, current_maxccls );
+ }
+
+ if ( lastccl == 1 )
+ /* we're making the first ccl */
+ cclmap[lastccl] = 0;
+
+ else
+ /* The new pointer is just past the end of the last ccl.
+ * Since the cclmap points to the \first/ character of a
+ * ccl, adding the length of the ccl to the cclmap pointer
+ * will produce a cursor to the first free space.
+ */
+ cclmap[lastccl] = cclmap[lastccl - 1] + ccllen[lastccl - 1];
+
+ ccllen[lastccl] = 0;
+ cclng[lastccl] = 0; /* ccl's start out life un-negated */
+
+ return lastccl;
+ }
+
+
+/* cclnegate - negate the given ccl */
+
+void cclnegate( cclp )
+int cclp;
+ {
+ cclng[cclp] = 1;
+ }
+
+
+/* list_character_set - list the members of a set of characters in CCL form
+ *
+ * Writes to the given file a character-class representation of those
+ * characters present in the given CCL. A character is present if it
+ * has a non-zero value in the cset array.
+ */
+
+void list_character_set( file, cset )
+FILE *file;
+int cset[];
+ {
+ register int i;
+
+ putc( '[', file );
+
+ for ( i = 0; i < csize; ++i )
+ {
+ if ( cset[i] )
+ {
+ register int start_char = i;
+
+ putc( ' ', file );
+
+ fputs( readable_form( i ), file );
+
+ while ( ++i < csize && cset[i] )
+ ;
+
+ if ( i - 1 > start_char )
+ /* this was a run */
+ fprintf( file, "-%s", readable_form( i - 1 ) );
+
+ putc( ' ', file );
+ }
+ }
+
+ putc( ']', file );
+ }
diff --git a/usr.bin/lex/config.h b/usr.bin/lex/config.h
new file mode 100644
index 0000000..dc4481c
--- /dev/null
+++ b/usr.bin/lex/config.h
@@ -0,0 +1,26 @@
+/* config.h. Generated automatically by configure. */
+/* $Header: /home/daffy/u0/vern/flex/RCS/conf.in,v 1.2 95/01/09 12:11:51 vern Exp $ */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the <malloc.h> header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if platform-specific command line handling is necessary. */
+/* #undef NEED_ARGV_FIXUP */
diff --git a/usr.bin/lex/dfa.c b/usr.bin/lex/dfa.c
new file mode 100644
index 0000000..3647c2c
--- /dev/null
+++ b/usr.bin/lex/dfa.c
@@ -0,0 +1,1095 @@
+/* dfa - DFA construction routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/dfa.c,v 1.1.1.2 1996/06/19 20:26:04 nate Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+void dump_associated_rules PROTO((FILE*, int));
+void dump_transitions PROTO((FILE*, int[]));
+void sympartition PROTO((int[], int, int[], int[]));
+int symfollowset PROTO((int[], int, int, int[]));
+
+
+/* check_for_backing_up - check a DFA state for backing up
+ *
+ * synopsis
+ * void check_for_backing_up( int ds, int state[numecs] );
+ *
+ * ds is the number of the state to check and state[] is its out-transitions,
+ * indexed by equivalence class.
+ */
+
+void check_for_backing_up( ds, state )
+int ds;
+int state[];
+ {
+ if ( (reject && ! dfaacc[ds].dfaacc_set) ||
+ (! reject && ! dfaacc[ds].dfaacc_state) )
+ { /* state is non-accepting */
+ ++num_backing_up;
+
+ if ( backing_up_report )
+ {
+ fprintf( backing_up_file,
+ _( "State #%d is non-accepting -\n" ), ds );
+
+ /* identify the state */
+ dump_associated_rules( backing_up_file, ds );
+
+ /* Now identify it further using the out- and
+ * jam-transitions.
+ */
+ dump_transitions( backing_up_file, state );
+
+ putc( '\n', backing_up_file );
+ }
+ }
+ }
+
+
+/* check_trailing_context - check to see if NFA state set constitutes
+ * "dangerous" trailing context
+ *
+ * synopsis
+ * void check_trailing_context( int nfa_states[num_states+1], int num_states,
+ * int accset[nacc+1], int nacc );
+ *
+ * NOTES
+ * Trailing context is "dangerous" if both the head and the trailing
+ * part are of variable size \and/ there's a DFA state which contains
+ * both an accepting state for the head part of the rule and NFA states
+ * which occur after the beginning of the trailing context.
+ *
+ * When such a rule is matched, it's impossible to tell if having been
+ * in the DFA state indicates the beginning of the trailing context or
+ * further-along scanning of the pattern. In these cases, a warning
+ * message is issued.
+ *
+ * nfa_states[1 .. num_states] is the list of NFA states in the DFA.
+ * accset[1 .. nacc] is the list of accepting numbers for the DFA state.
+ */
+
+void check_trailing_context( nfa_states, num_states, accset, nacc )
+int *nfa_states, num_states;
+int *accset;
+int nacc;
+ {
+ register int i, j;
+
+ for ( i = 1; i <= num_states; ++i )
+ {
+ int ns = nfa_states[i];
+ register int type = state_type[ns];
+ register int ar = assoc_rule[ns];
+
+ if ( type == STATE_NORMAL || rule_type[ar] != RULE_VARIABLE )
+ { /* do nothing */
+ }
+
+ else if ( type == STATE_TRAILING_CONTEXT )
+ {
+ /* Potential trouble. Scan set of accepting numbers
+ * for the one marking the end of the "head". We
+ * assume that this looping will be fairly cheap
+ * since it's rare that an accepting number set
+ * is large.
+ */
+ for ( j = 1; j <= nacc; ++j )
+ if ( accset[j] & YY_TRAILING_HEAD_MASK )
+ {
+ line_warning(
+ _( "dangerous trailing context" ),
+ rule_linenum[ar] );
+ return;
+ }
+ }
+ }
+ }
+
+
+/* dump_associated_rules - list the rules associated with a DFA state
+ *
+ * Goes through the set of NFA states associated with the DFA and
+ * extracts the first MAX_ASSOC_RULES unique rules, sorts them,
+ * and writes a report to the given file.
+ */
+
+void dump_associated_rules( file, ds )
+FILE *file;
+int ds;
+ {
+ register int i, j;
+ register int num_associated_rules = 0;
+ int rule_set[MAX_ASSOC_RULES + 1];
+ int *dset = dss[ds];
+ int size = dfasiz[ds];
+
+ for ( i = 1; i <= size; ++i )
+ {
+ register int rule_num = rule_linenum[assoc_rule[dset[i]]];
+
+ for ( j = 1; j <= num_associated_rules; ++j )
+ if ( rule_num == rule_set[j] )
+ break;
+
+ if ( j > num_associated_rules )
+ { /* new rule */
+ if ( num_associated_rules < MAX_ASSOC_RULES )
+ rule_set[++num_associated_rules] = rule_num;
+ }
+ }
+
+ bubble( rule_set, num_associated_rules );
+
+ fprintf( file, _( " associated rule line numbers:" ) );
+
+ for ( i = 1; i <= num_associated_rules; ++i )
+ {
+ if ( i % 8 == 1 )
+ putc( '\n', file );
+
+ fprintf( file, "\t%d", rule_set[i] );
+ }
+
+ putc( '\n', file );
+ }
+
+
+/* dump_transitions - list the transitions associated with a DFA state
+ *
+ * synopsis
+ * dump_transitions( FILE *file, int state[numecs] );
+ *
+ * Goes through the set of out-transitions and lists them in human-readable
+ * form (i.e., not as equivalence classes); also lists jam transitions
+ * (i.e., all those which are not out-transitions, plus EOF). The dump
+ * is done to the given file.
+ */
+
+void dump_transitions( file, state )
+FILE *file;
+int state[];
+ {
+ register int i, ec;
+ int out_char_set[CSIZE];
+
+ for ( i = 0; i < csize; ++i )
+ {
+ ec = ABS( ecgroup[i] );
+ out_char_set[i] = state[ec];
+ }
+
+ fprintf( file, _( " out-transitions: " ) );
+
+ list_character_set( file, out_char_set );
+
+ /* now invert the members of the set to get the jam transitions */
+ for ( i = 0; i < csize; ++i )
+ out_char_set[i] = ! out_char_set[i];
+
+ fprintf( file, _( "\n jam-transitions: EOF " ) );
+
+ list_character_set( file, out_char_set );
+
+ putc( '\n', file );
+ }
+
+
+/* epsclosure - construct the epsilon closure of a set of ndfa states
+ *
+ * synopsis
+ * int *epsclosure( int t[num_states], int *numstates_addr,
+ * int accset[num_rules+1], int *nacc_addr,
+ * int *hashval_addr );
+ *
+ * NOTES
+ * The epsilon closure is the set of all states reachable by an arbitrary
+ * number of epsilon transitions, which themselves do not have epsilon
+ * transitions going out, unioned with the set of states which have non-null
+ * accepting numbers. t is an array of size numstates of nfa state numbers.
+ * Upon return, t holds the epsilon closure and *numstates_addr is updated.
+ * accset holds a list of the accepting numbers, and the size of accset is
+ * given by *nacc_addr. t may be subjected to reallocation if it is not
+ * large enough to hold the epsilon closure.
+ *
+ * hashval is the hash value for the dfa corresponding to the state set.
+ */
+
+int *epsclosure( t, ns_addr, accset, nacc_addr, hv_addr )
+int *t, *ns_addr, accset[], *nacc_addr, *hv_addr;
+ {
+ register int stkpos, ns, tsp;
+ int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum;
+ int stkend, nstate;
+ static int did_stk_init = false, *stk;
+
+#define MARK_STATE(state) \
+trans1[state] = trans1[state] - MARKER_DIFFERENCE;
+
+#define IS_MARKED(state) (trans1[state] < 0)
+
+#define UNMARK_STATE(state) \
+trans1[state] = trans1[state] + MARKER_DIFFERENCE;
+
+#define CHECK_ACCEPT(state) \
+{ \
+nfaccnum = accptnum[state]; \
+if ( nfaccnum != NIL ) \
+accset[++nacc] = nfaccnum; \
+}
+
+#define DO_REALLOCATION \
+{ \
+current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \
+++num_reallocs; \
+t = reallocate_integer_array( t, current_max_dfa_size ); \
+stk = reallocate_integer_array( stk, current_max_dfa_size ); \
+} \
+
+#define PUT_ON_STACK(state) \
+{ \
+if ( ++stkend >= current_max_dfa_size ) \
+DO_REALLOCATION \
+stk[stkend] = state; \
+MARK_STATE(state) \
+}
+
+#define ADD_STATE(state) \
+{ \
+if ( ++numstates >= current_max_dfa_size ) \
+DO_REALLOCATION \
+t[numstates] = state; \
+hashval += state; \
+}
+
+#define STACK_STATE(state) \
+{ \
+PUT_ON_STACK(state) \
+CHECK_ACCEPT(state) \
+if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \
+ADD_STATE(state) \
+}
+
+
+ if ( ! did_stk_init )
+ {
+ stk = allocate_integer_array( current_max_dfa_size );
+ did_stk_init = true;
+ }
+
+ nacc = stkend = hashval = 0;
+
+ for ( nstate = 1; nstate <= numstates; ++nstate )
+ {
+ ns = t[nstate];
+
+ /* The state could be marked if we've already pushed it onto
+ * the stack.
+ */
+ if ( ! IS_MARKED(ns) )
+ {
+ PUT_ON_STACK(ns)
+ CHECK_ACCEPT(ns)
+ hashval += ns;
+ }
+ }
+
+ for ( stkpos = 1; stkpos <= stkend; ++stkpos )
+ {
+ ns = stk[stkpos];
+ transsym = transchar[ns];
+
+ if ( transsym == SYM_EPSILON )
+ {
+ tsp = trans1[ns] + MARKER_DIFFERENCE;
+
+ if ( tsp != NO_TRANSITION )
+ {
+ if ( ! IS_MARKED(tsp) )
+ STACK_STATE(tsp)
+
+ tsp = trans2[ns];
+
+ if ( tsp != NO_TRANSITION && ! IS_MARKED(tsp) )
+ STACK_STATE(tsp)
+ }
+ }
+ }
+
+ /* Clear out "visit" markers. */
+
+ for ( stkpos = 1; stkpos <= stkend; ++stkpos )
+ {
+ if ( IS_MARKED(stk[stkpos]) )
+ UNMARK_STATE(stk[stkpos])
+ else
+ flexfatal(
+ _( "consistency check failed in epsclosure()" ) );
+ }
+
+ *ns_addr = numstates;
+ *hv_addr = hashval;
+ *nacc_addr = nacc;
+
+ return t;
+ }
+
+
+/* increase_max_dfas - increase the maximum number of DFAs */
+
+void increase_max_dfas()
+ {
+ current_max_dfas += MAX_DFAS_INCREMENT;
+
+ ++num_reallocs;
+
+ base = reallocate_integer_array( base, current_max_dfas );
+ def = reallocate_integer_array( def, current_max_dfas );
+ dfasiz = reallocate_integer_array( dfasiz, current_max_dfas );
+ accsiz = reallocate_integer_array( accsiz, current_max_dfas );
+ dhash = reallocate_integer_array( dhash, current_max_dfas );
+ dss = reallocate_int_ptr_array( dss, current_max_dfas );
+ dfaacc = reallocate_dfaacc_union( dfaacc, current_max_dfas );
+
+ if ( nultrans )
+ nultrans =
+ reallocate_integer_array( nultrans, current_max_dfas );
+ }
+
+
+/* ntod - convert an ndfa to a dfa
+ *
+ * Creates the dfa corresponding to the ndfa we've constructed. The
+ * dfa starts out in state #1.
+ */
+
+void ntod()
+ {
+ int *accset, ds, nacc, newds;
+ int sym, hashval, numstates, dsize;
+ int num_full_table_rows; /* used only for -f */
+ int *nset, *dset;
+ int targptr, totaltrans, i, comstate, comfreq, targ;
+ int symlist[CSIZE + 1];
+ int num_start_states;
+ int todo_head, todo_next;
+
+ /* Note that the following are indexed by *equivalence classes*
+ * and not by characters. Since equivalence classes are indexed
+ * beginning with 1, even if the scanner accepts NUL's, this
+ * means that (since every character is potentially in its own
+ * equivalence class) these arrays must have room for indices
+ * from 1 to CSIZE, so their size must be CSIZE + 1.
+ */
+ int duplist[CSIZE + 1], state[CSIZE + 1];
+ int targfreq[CSIZE + 1], targstate[CSIZE + 1];
+
+ accset = allocate_integer_array( num_rules + 1 );
+ nset = allocate_integer_array( current_max_dfa_size );
+
+ /* The "todo" queue is represented by the head, which is the DFA
+ * state currently being processed, and the "next", which is the
+ * next DFA state number available (not in use). We depend on the
+ * fact that snstods() returns DFA's \in increasing order/, and thus
+ * need only know the bounds of the dfas to be processed.
+ */
+ todo_head = todo_next = 0;
+
+ for ( i = 0; i <= csize; ++i )
+ {
+ duplist[i] = NIL;
+ symlist[i] = false;
+ }
+
+ for ( i = 0; i <= num_rules; ++i )
+ accset[i] = NIL;
+
+ if ( trace )
+ {
+ dumpnfa( scset[1] );
+ fputs( _( "\n\nDFA Dump:\n\n" ), stderr );
+ }
+
+ inittbl();
+
+ /* Check to see whether we should build a separate table for
+ * transitions on NUL characters. We don't do this for full-speed
+ * (-F) scanners, since for them we don't have a simple state
+ * number lying around with which to index the table. We also
+ * don't bother doing it for scanners unless (1) NUL is in its own
+ * equivalence class (indicated by a positive value of
+ * ecgroup[NUL]), (2) NUL's equivalence class is the last
+ * equivalence class, and (3) the number of equivalence classes is
+ * the same as the number of characters. This latter case comes
+ * about when useecs is false or when it's true but every character
+ * still manages to land in its own class (unlikely, but it's
+ * cheap to check for). If all these things are true then the
+ * character code needed to represent NUL's equivalence class for
+ * indexing the tables is going to take one more bit than the
+ * number of characters, and therefore we won't be assured of
+ * being able to fit it into a YY_CHAR variable. This rules out
+ * storing the transitions in a compressed table, since the code
+ * for interpreting them uses a YY_CHAR variable (perhaps it
+ * should just use an integer, though; this is worth pondering ...
+ * ###).
+ *
+ * Finally, for full tables, we want the number of entries in the
+ * table to be a power of two so the array references go fast (it
+ * will just take a shift to compute the major index). If
+ * encoding NUL's transitions in the table will spoil this, we
+ * give it its own table (note that this will be the case if we're
+ * not using equivalence classes).
+ */
+
+ /* Note that the test for ecgroup[0] == numecs below accomplishes
+ * both (1) and (2) above
+ */
+ if ( ! fullspd && ecgroup[0] == numecs )
+ {
+ /* NUL is alone in its equivalence class, which is the
+ * last one.
+ */
+ int use_NUL_table = (numecs == csize);
+
+ if ( fulltbl && ! use_NUL_table )
+ {
+ /* We still may want to use the table if numecs
+ * is a power of 2.
+ */
+ int power_of_two;
+
+ for ( power_of_two = 1; power_of_two <= csize;
+ power_of_two *= 2 )
+ if ( numecs == power_of_two )
+ {
+ use_NUL_table = true;
+ break;
+ }
+ }
+
+ if ( use_NUL_table )
+ nultrans = allocate_integer_array( current_max_dfas );
+
+ /* From now on, nultrans != nil indicates that we're
+ * saving null transitions for later, separate encoding.
+ */
+ }
+
+
+ if ( fullspd )
+ {
+ for ( i = 0; i <= numecs; ++i )
+ state[i] = 0;
+
+ place_state( state, 0, 0 );
+ dfaacc[0].dfaacc_state = 0;
+ }
+
+ else if ( fulltbl )
+ {
+ if ( nultrans )
+ /* We won't be including NUL's transitions in the
+ * table, so build it for entries from 0 .. numecs - 1.
+ */
+ num_full_table_rows = numecs;
+
+ else
+ /* Take into account the fact that we'll be including
+ * the NUL entries in the transition table. Build it
+ * from 0 .. numecs.
+ */
+ num_full_table_rows = numecs + 1;
+
+ /* Unless -Ca, declare it "short" because it's a real
+ * long-shot that that won't be large enough.
+ */
+ out_str_dec( "static yyconst %s yy_nxt[][%d] =\n {\n",
+ /* '}' so vi doesn't get too confused */
+ long_align ? "long" : "short", num_full_table_rows );
+
+ outn( " {" );
+
+ /* Generate 0 entries for state #0. */
+ for ( i = 0; i < num_full_table_rows; ++i )
+ mk2data( 0 );
+
+ dataflush();
+ outn( " },\n" );
+ }
+
+ /* Create the first states. */
+
+ num_start_states = lastsc * 2;
+
+ for ( i = 1; i <= num_start_states; ++i )
+ {
+ numstates = 1;
+
+ /* For each start condition, make one state for the case when
+ * we're at the beginning of the line (the '^' operator) and
+ * one for the case when we're not.
+ */
+ if ( i % 2 == 1 )
+ nset[numstates] = scset[(i / 2) + 1];
+ else
+ nset[numstates] =
+ mkbranch( scbol[i / 2], scset[i / 2] );
+
+ nset = epsclosure( nset, &numstates, accset, &nacc, &hashval );
+
+ if ( snstods( nset, numstates, accset, nacc, hashval, &ds ) )
+ {
+ numas += nacc;
+ totnst += numstates;
+ ++todo_next;
+
+ if ( variable_trailing_context_rules && nacc > 0 )
+ check_trailing_context( nset, numstates,
+ accset, nacc );
+ }
+ }
+
+ if ( ! fullspd )
+ {
+ if ( ! snstods( nset, 0, accset, 0, 0, &end_of_buffer_state ) )
+ flexfatal(
+ _( "could not create unique end-of-buffer state" ) );
+
+ ++numas;
+ ++num_start_states;
+ ++todo_next;
+ }
+
+ while ( todo_head < todo_next )
+ {
+ targptr = 0;
+ totaltrans = 0;
+
+ for ( i = 1; i <= numecs; ++i )
+ state[i] = 0;
+
+ ds = ++todo_head;
+
+ dset = dss[ds];
+ dsize = dfasiz[ds];
+
+ if ( trace )
+ fprintf( stderr, _( "state # %d:\n" ), ds );
+
+ sympartition( dset, dsize, symlist, duplist );
+
+ for ( sym = 1; sym <= numecs; ++sym )
+ {
+ if ( symlist[sym] )
+ {
+ symlist[sym] = 0;
+
+ if ( duplist[sym] == NIL )
+ {
+ /* Symbol has unique out-transitions. */
+ numstates = symfollowset( dset, dsize,
+ sym, nset );
+ nset = epsclosure( nset, &numstates,
+ accset, &nacc, &hashval );
+
+ if ( snstods( nset, numstates, accset,
+ nacc, hashval, &newds ) )
+ {
+ totnst = totnst + numstates;
+ ++todo_next;
+ numas += nacc;
+
+ if (
+ variable_trailing_context_rules &&
+ nacc > 0 )
+ check_trailing_context(
+ nset, numstates,
+ accset, nacc );
+ }
+
+ state[sym] = newds;
+
+ if ( trace )
+ fprintf( stderr, "\t%d\t%d\n",
+ sym, newds );
+
+ targfreq[++targptr] = 1;
+ targstate[targptr] = newds;
+ ++numuniq;
+ }
+
+ else
+ {
+ /* sym's equivalence class has the same
+ * transitions as duplist(sym)'s
+ * equivalence class.
+ */
+ targ = state[duplist[sym]];
+ state[sym] = targ;
+
+ if ( trace )
+ fprintf( stderr, "\t%d\t%d\n",
+ sym, targ );
+
+ /* Update frequency count for
+ * destination state.
+ */
+
+ i = 0;
+ while ( targstate[++i] != targ )
+ ;
+
+ ++targfreq[i];
+ ++numdup;
+ }
+
+ ++totaltrans;
+ duplist[sym] = NIL;
+ }
+ }
+
+ if ( caseins && ! useecs )
+ {
+ register int j;
+
+ for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j )
+ {
+ if ( state[i] == 0 && state[j] != 0 )
+ /* We're adding a transition. */
+ ++totaltrans;
+
+ else if ( state[i] != 0 && state[j] == 0 )
+ /* We're taking away a transition. */
+ --totaltrans;
+
+ state[i] = state[j];
+ }
+ }
+
+ numsnpairs += totaltrans;
+
+ if ( ds > num_start_states )
+ check_for_backing_up( ds, state );
+
+ if ( nultrans )
+ {
+ nultrans[ds] = state[NUL_ec];
+ state[NUL_ec] = 0; /* remove transition */
+ }
+
+ if ( fulltbl )
+ {
+ outn( " {" );
+
+ /* Supply array's 0-element. */
+ if ( ds == end_of_buffer_state )
+ mk2data( -end_of_buffer_state );
+ else
+ mk2data( end_of_buffer_state );
+
+ for ( i = 1; i < num_full_table_rows; ++i )
+ /* Jams are marked by negative of state
+ * number.
+ */
+ mk2data( state[i] ? state[i] : -ds );
+
+ dataflush();
+ outn( " },\n" );
+ }
+
+ else if ( fullspd )
+ place_state( state, ds, totaltrans );
+
+ else if ( ds == end_of_buffer_state )
+ /* Special case this state to make sure it does what
+ * it's supposed to, i.e., jam on end-of-buffer.
+ */
+ stack1( ds, 0, 0, JAMSTATE );
+
+ else /* normal, compressed state */
+ {
+ /* Determine which destination state is the most
+ * common, and how many transitions to it there are.
+ */
+
+ comfreq = 0;
+ comstate = 0;
+
+ for ( i = 1; i <= targptr; ++i )
+ if ( targfreq[i] > comfreq )
+ {
+ comfreq = targfreq[i];
+ comstate = targstate[i];
+ }
+
+ bldtbl( state, ds, totaltrans, comstate, comfreq );
+ }
+ }
+
+ if ( fulltbl )
+ dataend();
+
+ else if ( ! fullspd )
+ {
+ cmptmps(); /* create compressed template entries */
+
+ /* Create tables for all the states with only one
+ * out-transition.
+ */
+ while ( onesp > 0 )
+ {
+ mk1tbl( onestate[onesp], onesym[onesp], onenext[onesp],
+ onedef[onesp] );
+ --onesp;
+ }
+
+ mkdeftbl();
+ }
+
+ flex_free( (void *) accset );
+ flex_free( (void *) nset );
+ }
+
+
+/* snstods - converts a set of ndfa states into a dfa state
+ *
+ * synopsis
+ * is_new_state = snstods( int sns[numstates], int numstates,
+ * int accset[num_rules+1], int nacc,
+ * int hashval, int *newds_addr );
+ *
+ * On return, the dfa state number is in newds.
+ */
+
+int snstods( sns, numstates, accset, nacc, hashval, newds_addr )
+int sns[], numstates, accset[], nacc, hashval, *newds_addr;
+ {
+ int didsort = 0;
+ register int i, j;
+ int newds, *oldsns;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ if ( hashval == dhash[i] )
+ {
+ if ( numstates == dfasiz[i] )
+ {
+ oldsns = dss[i];
+
+ if ( ! didsort )
+ {
+ /* We sort the states in sns so we
+ * can compare it to oldsns quickly.
+ * We use bubble because there probably
+ * aren't very many states.
+ */
+ bubble( sns, numstates );
+ didsort = 1;
+ }
+
+ for ( j = 1; j <= numstates; ++j )
+ if ( sns[j] != oldsns[j] )
+ break;
+
+ if ( j > numstates )
+ {
+ ++dfaeql;
+ *newds_addr = i;
+ return 0;
+ }
+
+ ++hshcol;
+ }
+
+ else
+ ++hshsave;
+ }
+
+ /* Make a new dfa. */
+
+ if ( ++lastdfa >= current_max_dfas )
+ increase_max_dfas();
+
+ newds = lastdfa;
+
+ dss[newds] = allocate_integer_array( numstates + 1 );
+
+ /* If we haven't already sorted the states in sns, we do so now,
+ * so that future comparisons with it can be made quickly.
+ */
+
+ if ( ! didsort )
+ bubble( sns, numstates );
+
+ for ( i = 1; i <= numstates; ++i )
+ dss[newds][i] = sns[i];
+
+ dfasiz[newds] = numstates;
+ dhash[newds] = hashval;
+
+ if ( nacc == 0 )
+ {
+ if ( reject )
+ dfaacc[newds].dfaacc_set = (int *) 0;
+ else
+ dfaacc[newds].dfaacc_state = 0;
+
+ accsiz[newds] = 0;
+ }
+
+ else if ( reject )
+ {
+ /* We sort the accepting set in increasing order so the
+ * disambiguating rule that the first rule listed is considered
+ * match in the event of ties will work. We use a bubble
+ * sort since the list is probably quite small.
+ */
+
+ bubble( accset, nacc );
+
+ dfaacc[newds].dfaacc_set = allocate_integer_array( nacc + 1 );
+
+ /* Save the accepting set for later */
+ for ( i = 1; i <= nacc; ++i )
+ {
+ dfaacc[newds].dfaacc_set[i] = accset[i];
+
+ if ( accset[i] <= num_rules )
+ /* Who knows, perhaps a REJECT can yield
+ * this rule.
+ */
+ rule_useful[accset[i]] = true;
+ }
+
+ accsiz[newds] = nacc;
+ }
+
+ else
+ {
+ /* Find lowest numbered rule so the disambiguating rule
+ * will work.
+ */
+ j = num_rules + 1;
+
+ for ( i = 1; i <= nacc; ++i )
+ if ( accset[i] < j )
+ j = accset[i];
+
+ dfaacc[newds].dfaacc_state = j;
+
+ if ( j <= num_rules )
+ rule_useful[j] = true;
+ }
+
+ *newds_addr = newds;
+
+ return 1;
+ }
+
+
+/* symfollowset - follow the symbol transitions one step
+ *
+ * synopsis
+ * numstates = symfollowset( int ds[current_max_dfa_size], int dsize,
+ * int transsym, int nset[current_max_dfa_size] );
+ */
+
+int symfollowset( ds, dsize, transsym, nset )
+int ds[], dsize, transsym, nset[];
+ {
+ int ns, tsp, sym, i, j, lenccl, ch, numstates, ccllist;
+
+ numstates = 0;
+
+ for ( i = 1; i <= dsize; ++i )
+ { /* for each nfa state ns in the state set of ds */
+ ns = ds[i];
+ sym = transchar[ns];
+ tsp = trans1[ns];
+
+ if ( sym < 0 )
+ { /* it's a character class */
+ sym = -sym;
+ ccllist = cclmap[sym];
+ lenccl = ccllen[sym];
+
+ if ( cclng[sym] )
+ {
+ for ( j = 0; j < lenccl; ++j )
+ {
+ /* Loop through negated character
+ * class.
+ */
+ ch = ccltbl[ccllist + j];
+
+ if ( ch == 0 )
+ ch = NUL_ec;
+
+ if ( ch > transsym )
+ /* Transsym isn't in negated
+ * ccl.
+ */
+ break;
+
+ else if ( ch == transsym )
+ /* next 2 */ goto bottom;
+ }
+
+ /* Didn't find transsym in ccl. */
+ nset[++numstates] = tsp;
+ }
+
+ else
+ for ( j = 0; j < lenccl; ++j )
+ {
+ ch = ccltbl[ccllist + j];
+
+ if ( ch == 0 )
+ ch = NUL_ec;
+
+ if ( ch > transsym )
+ break;
+ else if ( ch == transsym )
+ {
+ nset[++numstates] = tsp;
+ break;
+ }
+ }
+ }
+
+ else if ( sym >= 'A' && sym <= 'Z' && caseins )
+ flexfatal(
+ _( "consistency check failed in symfollowset" ) );
+
+ else if ( sym == SYM_EPSILON )
+ { /* do nothing */
+ }
+
+ else if ( ABS( ecgroup[sym] ) == transsym )
+ nset[++numstates] = tsp;
+
+ bottom: ;
+ }
+
+ return numstates;
+ }
+
+
+/* sympartition - partition characters with same out-transitions
+ *
+ * synopsis
+ * sympartition( int ds[current_max_dfa_size], int numstates,
+ * int symlist[numecs], int duplist[numecs] );
+ */
+
+void sympartition( ds, numstates, symlist, duplist )
+int ds[], numstates;
+int symlist[], duplist[];
+ {
+ int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich;
+
+ /* Partitioning is done by creating equivalence classes for those
+ * characters which have out-transitions from the given state. Thus
+ * we are really creating equivalence classes of equivalence classes.
+ */
+
+ for ( i = 1; i <= numecs; ++i )
+ { /* initialize equivalence class list */
+ duplist[i] = i - 1;
+ dupfwd[i] = i + 1;
+ }
+
+ duplist[1] = NIL;
+ dupfwd[numecs] = NIL;
+
+ for ( i = 1; i <= numstates; ++i )
+ {
+ ns = ds[i];
+ tch = transchar[ns];
+
+ if ( tch != SYM_EPSILON )
+ {
+ if ( tch < -lastccl || tch >= csize )
+ {
+ flexfatal(
+ _( "bad transition character detected in sympartition()" ) );
+ }
+
+ if ( tch >= 0 )
+ { /* character transition */
+ int ec = ecgroup[tch];
+
+ mkechar( ec, dupfwd, duplist );
+ symlist[ec] = 1;
+ }
+
+ else
+ { /* character class */
+ tch = -tch;
+
+ lenccl = ccllen[tch];
+ cclp = cclmap[tch];
+ mkeccl( ccltbl + cclp, lenccl, dupfwd,
+ duplist, numecs, NUL_ec );
+
+ if ( cclng[tch] )
+ {
+ j = 0;
+
+ for ( k = 0; k < lenccl; ++k )
+ {
+ ich = ccltbl[cclp + k];
+
+ if ( ich == 0 )
+ ich = NUL_ec;
+
+ for ( ++j; j < ich; ++j )
+ symlist[j] = 1;
+ }
+
+ for ( ++j; j <= numecs; ++j )
+ symlist[j] = 1;
+ }
+
+ else
+ for ( k = 0; k < lenccl; ++k )
+ {
+ ich = ccltbl[cclp + k];
+
+ if ( ich == 0 )
+ ich = NUL_ec;
+
+ symlist[ich] = 1;
+ }
+ }
+ }
+ }
+ }
diff --git a/usr.bin/lex/ecs.c b/usr.bin/lex/ecs.c
new file mode 100644
index 0000000..10b167c
--- /dev/null
+++ b/usr.bin/lex/ecs.c
@@ -0,0 +1,225 @@
+/* ecs - equivalence class routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/ecs.c,v 2.9 93/12/07 10:18:20 vern Exp $ */
+
+#include "flexdef.h"
+
+/* ccl2ecl - convert character classes to set of equivalence classes */
+
+void ccl2ecl()
+ {
+ int i, ich, newlen, cclp, ccls, cclmec;
+
+ for ( i = 1; i <= lastccl; ++i )
+ {
+ /* We loop through each character class, and for each character
+ * in the class, add the character's equivalence class to the
+ * new "character" class we are creating. Thus when we are all
+ * done, character classes will really consist of collections
+ * of equivalence classes
+ */
+
+ newlen = 0;
+ cclp = cclmap[i];
+
+ for ( ccls = 0; ccls < ccllen[i]; ++ccls )
+ {
+ ich = ccltbl[cclp + ccls];
+ cclmec = ecgroup[ich];
+
+ if ( cclmec > 0 )
+ {
+ ccltbl[cclp + newlen] = cclmec;
+ ++newlen;
+ }
+ }
+
+ ccllen[i] = newlen;
+ }
+ }
+
+
+/* cre8ecs - associate equivalence class numbers with class members
+ *
+ * fwd is the forward linked-list of equivalence class members. bck
+ * is the backward linked-list, and num is the number of class members.
+ *
+ * Returned is the number of classes.
+ */
+
+int cre8ecs( fwd, bck, num )
+int fwd[], bck[], num;
+ {
+ int i, j, numcl;
+
+ numcl = 0;
+
+ /* Create equivalence class numbers. From now on, ABS( bck(x) )
+ * is the equivalence class number for object x. If bck(x)
+ * is positive, then x is the representative of its equivalence
+ * class.
+ */
+ for ( i = 1; i <= num; ++i )
+ if ( bck[i] == NIL )
+ {
+ bck[i] = ++numcl;
+ for ( j = fwd[i]; j != NIL; j = fwd[j] )
+ bck[j] = -numcl;
+ }
+
+ return numcl;
+ }
+
+
+/* mkeccl - update equivalence classes based on character class xtions
+ *
+ * synopsis
+ * Char ccls[];
+ * int lenccl, fwd[llsiz], bck[llsiz], llsiz, NUL_mapping;
+ * void mkeccl( Char ccls[], int lenccl, int fwd[llsiz], int bck[llsiz],
+ * int llsiz, int NUL_mapping );
+ *
+ * ccls contains the elements of the character class, lenccl is the
+ * number of elements in the ccl, fwd is the forward link-list of equivalent
+ * characters, bck is the backward link-list, and llsiz size of the link-list.
+ *
+ * NUL_mapping is the value which NUL (0) should be mapped to.
+ */
+
+void mkeccl( ccls, lenccl, fwd, bck, llsiz, NUL_mapping )
+Char ccls[];
+int lenccl, fwd[], bck[], llsiz, NUL_mapping;
+ {
+ int cclp, oldec, newec;
+ int cclm, i, j;
+ static unsigned char cclflags[CSIZE]; /* initialized to all '\0' */
+
+ /* Note that it doesn't matter whether or not the character class is
+ * negated. The same results will be obtained in either case.
+ */
+
+ cclp = 0;
+
+ while ( cclp < lenccl )
+ {
+ cclm = ccls[cclp];
+
+ if ( NUL_mapping && cclm == 0 )
+ cclm = NUL_mapping;
+
+ oldec = bck[cclm];
+ newec = cclm;
+
+ j = cclp + 1;
+
+ for ( i = fwd[cclm]; i != NIL && i <= llsiz; i = fwd[i] )
+ { /* look for the symbol in the character class */
+ for ( ; j < lenccl; ++j )
+ {
+ register int ccl_char;
+
+ if ( NUL_mapping && ccls[j] == 0 )
+ ccl_char = NUL_mapping;
+ else
+ ccl_char = ccls[j];
+
+ if ( ccl_char > i )
+ break;
+
+ if ( ccl_char == i && ! cclflags[j] )
+ {
+ /* We found an old companion of cclm
+ * in the ccl. Link it into the new
+ * equivalence class and flag it as
+ * having been processed.
+ */
+
+ bck[i] = newec;
+ fwd[newec] = i;
+ newec = i;
+ /* Set flag so we don't reprocess. */
+ cclflags[j] = 1;
+
+ /* Get next equivalence class member. */
+ /* continue 2 */
+ goto next_pt;
+ }
+ }
+
+ /* Symbol isn't in character class. Put it in the old
+ * equivalence class.
+ */
+
+ bck[i] = oldec;
+
+ if ( oldec != NIL )
+ fwd[oldec] = i;
+
+ oldec = i;
+
+ next_pt: ;
+ }
+
+ if ( bck[cclm] != NIL || oldec != bck[cclm] )
+ {
+ bck[cclm] = NIL;
+ fwd[oldec] = NIL;
+ }
+
+ fwd[newec] = NIL;
+
+ /* Find next ccl member to process. */
+
+ for ( ++cclp; cclflags[cclp] && cclp < lenccl; ++cclp )
+ {
+ /* Reset "doesn't need processing" flag. */
+ cclflags[cclp] = 0;
+ }
+ }
+ }
+
+
+/* mkechar - create equivalence class for single character */
+
+void mkechar( tch, fwd, bck )
+int tch, fwd[], bck[];
+ {
+ /* If until now the character has been a proper subset of
+ * an equivalence class, break it away to create a new ec
+ */
+
+ if ( fwd[tch] != NIL )
+ bck[fwd[tch]] = bck[tch];
+
+ if ( bck[tch] != NIL )
+ fwd[bck[tch]] = fwd[tch];
+
+ fwd[tch] = NIL;
+ bck[tch] = NIL;
+ }
diff --git a/usr.bin/lex/flex.skl b/usr.bin/lex/flex.skl
new file mode 100644
index 0000000..8dee386
--- /dev/null
+++ b/usr.bin/lex/flex.skl
@@ -0,0 +1,1541 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/ncvs/src/usr.bin/lex/flex.skl,v 1.1.1.2 1996/06/19 20:26:06 nate Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+%-
+#include <stdio.h>
+%*
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+%+
+class istream;
+%*
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+%-
+extern FILE *yyin, *yyout;
+%*
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+%-
+ FILE *yy_input_file;
+%+
+ istream* yy_input_file;
+%*
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+%- Standard (non-C++) definition
+static YY_BUFFER_STATE yy_current_buffer = 0;
+%*
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+%- Standard (non-C++) definition
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+%*
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here
+
+%- Standard (non-C++) definition
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+%*
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+%% code to fiddle yytext and yyleng for yymore() goes here
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+%% code to copy yytext_ptr to yytext[] goes here, if %array
+ yy_c_buf_p = yy_cp;
+
+%% data tables for the DFA and the user's section 1 definitions go here
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+%-
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+%*
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+%- Standard (non-C++) definition
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+%*
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+%- Standard (non-C++) definition
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+%+ C++ definition
+#define ECHO LexerOutput( yytext, yyleng )
+%*
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+%% fread()/read() definition of YY_INPUT goes here unless we're doing C++
+%+ C++ definition
+ if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+%*
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+%-
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+%+
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+%*
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+%- Standard (non-C++) definition
+#define YY_DECL int yylex YY_PROTO(( void ))
+%+ C++ definition
+#define YY_DECL int yyFlexLexer::yylex()
+%*
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+%% YY_RULE_SETUP definition goes here
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+%% user's declarations go here
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+%-
+ yyin = stdin;
+%+
+ yyin = &cin;
+%*
+
+ if ( ! yyout )
+%-
+ yyout = stdout;
+%+
+ yyout = &cout;
+%*
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+%% yymore()-related code goes here
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+%% code to set up and find next match goes here
+
+yy_find_action:
+%% code to find the action number goes here
+
+ YY_DO_BEFORE_ACTION;
+
+%% code for yylineno update goes here
+
+do_action: /* This label is used only to access EOF actions. */
+
+%% debug code goes here
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+%% actions go here
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+%% code to do back-up for compressed tables and set up yy_cp goes here
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+%+
+yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )
+ {
+ yyin = arg_yyin;
+ yyout = arg_yyout;
+ yy_c_buf_p = 0;
+ yy_init = 1;
+ yy_start = 0;
+ yy_flex_debug = 0;
+ yylineno = 1; // this will only get updated if %option yylineno
+
+ yy_did_buffer_switch_on_eof = 0;
+
+ yy_looking_for_trail_begin = 0;
+ yy_more_flag = 0;
+ yy_more_len = 0;
+ yy_more_offset = yy_prev_more_offset = 0;
+
+ yy_start_stack_ptr = yy_start_stack_depth = 0;
+ yy_start_stack = 0;
+
+ yy_current_buffer = 0;
+
+#ifdef YY_USES_REJECT
+ yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];
+#else
+ yy_state_buf = 0;
+#endif
+ }
+
+yyFlexLexer::~yyFlexLexer()
+ {
+ delete yy_state_buf;
+ yy_delete_buffer( yy_current_buffer );
+ }
+
+void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )
+ {
+ if ( new_in )
+ {
+ yy_delete_buffer( yy_current_buffer );
+ yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+ }
+
+ if ( new_out )
+ yyout = new_out;
+ }
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+ {
+ if ( yyin->eof() || yyin->fail() )
+ return 0;
+
+#ifdef YY_INTERACTIVE
+ yyin->get( buf[0] );
+
+ if ( yyin->eof() )
+ return 0;
+
+ if ( yyin->bad() )
+ return -1;
+
+ return 1;
+
+#else
+ (void) yyin->read( buf, max_size );
+
+ if ( yyin->bad() )
+ return -1;
+ else
+ return yyin->gcount();
+#endif
+ }
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+ {
+ (void) yyout->write( buf, size );
+ }
+%*
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+%-
+static int yy_get_next_buffer()
+%+
+int yyFlexLexer::yy_get_next_buffer()
+%*
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+%-
+static yy_state_type yy_get_previous_state()
+%+
+yy_state_type yyFlexLexer::yy_get_previous_state()
+%*
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+%% code to get the start state into yy_current_state goes here
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+%% code to find the next state goes here
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+%-
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+%+
+yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+%*
+ {
+ register int yy_is_jam;
+%% code to find the next state, and perhaps do backing up, goes here
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+%-
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+%+
+void yyFlexLexer::yyunput( int c, register char* yy_bp )
+%*
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+%% update yylineno here
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+%-
+#endif /* ifndef YY_NO_UNPUT */
+%*
+
+
+%-
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+%+
+int yyFlexLexer::yyinput()
+%*
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+%% update BOL and yylineno
+
+ return c;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+%+
+void yyFlexLexer::yyrestart( istream* input_file )
+%*
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+%+
+void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+%*
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+%+
+void yyFlexLexer::yy_load_buffer_state()
+%*
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+%+
+YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )
+%*
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+%+
+void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+%*
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+%-
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+%+
+extern "C" int isatty YY_PROTO(( int ));
+void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )
+%*
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+%-
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+%+
+ b->yy_is_interactive = 0;
+%*
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+%+
+void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+%*
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+%*
+
+
+#ifndef YY_NO_SCAN_BUFFER
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+%-
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+%+
+void yyFlexLexer::yy_push_state( int new_state )
+%*
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+%-
+static void yy_pop_state()
+%+
+void yyFlexLexer::yy_pop_state()
+%*
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+%-
+static int yy_top_state()
+%+
+int yyFlexLexer::yy_top_state()
+%*
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+%-
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+%+
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+ {
+ cerr << msg << '\n';
+ exit( YY_EXIT_FAILURE );
+ }
+%*
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
diff --git a/usr.bin/lex/flexdef.h b/usr.bin/lex/flexdef.h
new file mode 100644
index 0000000..3969fdf
--- /dev/null
+++ b/usr.bin/lex/flexdef.h
@@ -0,0 +1,1048 @@
+/* flexdef - definitions file for flex */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* @(#) $Header: /home/ncvs/src/usr.bin/lex/flexdef.h,v 1.1.1.2 1996/06/19 20:26:08 nate Exp $ (LBL) */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "config.h"
+
+#ifdef __TURBOC__
+#define HAVE_STRING_H 1
+#define MS_DOS 1
+#ifndef __STDC__
+#define __STDC__ 1
+#endif
+ #pragma warn -pro
+ #pragma warn -rch
+ #pragma warn -use
+ #pragma warn -aus
+ #pragma warn -par
+ #pragma warn -pia
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+/* As an aid for the internationalization patch to flex, which
+ * is maintained outside this distribution for copyright reasons.
+ */
+#define _(String) (String)
+
+/* Always be prepared to generate an 8-bit scanner. */
+#define CSIZE 256
+#define Char unsigned char
+
+/* Size of input alphabet - should be size of ASCII set. */
+#ifndef DEFAULT_CSIZE
+#define DEFAULT_CSIZE 128
+#endif
+
+#ifndef PROTO
+#if __STDC__
+#define PROTO(proto) proto
+#else
+#define PROTO(proto) ()
+#endif
+#endif
+
+#ifdef VMS
+#ifndef __VMS_POSIX
+#define unlink remove
+#define SHORT_FILE_NAMES
+#endif
+#endif
+
+#ifdef MS_DOS
+#define SHORT_FILE_NAMES
+#endif
+
+
+/* Maximum line length we'll have to deal with. */
+#define MAXLINE 2048
+
+#ifndef MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+#ifndef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+
+/* ANSI C does not guarantee that isascii() is defined */
+#ifndef isascii
+#define isascii(c) ((c) <= 0177)
+#endif
+
+
+#define true 1
+#define false 0
+#define unspecified -1
+
+
+/* Special chk[] values marking the slots taking by end-of-buffer and action
+ * numbers.
+ */
+#define EOB_POSITION -1
+#define ACTION_POSITION -2
+
+/* Number of data items per line for -f output. */
+#define NUMDATAITEMS 10
+
+/* Number of lines of data in -f output before inserting a blank line for
+ * readability.
+ */
+#define NUMDATALINES 10
+
+/* transition_struct_out() definitions. */
+#define TRANS_STRUCT_PRINT_LENGTH 14
+
+/* Returns true if an nfa state has an epsilon out-transition slot
+ * that can be used. This definition is currently not used.
+ */
+#define FREE_EPSILON(state) \
+ (transchar[state] == SYM_EPSILON && \
+ trans2[state] == NO_TRANSITION && \
+ finalst[state] != state)
+
+/* Returns true if an nfa state has an epsilon out-transition character
+ * and both slots are free
+ */
+#define SUPER_FREE_EPSILON(state) \
+ (transchar[state] == SYM_EPSILON && \
+ trans1[state] == NO_TRANSITION) \
+
+/* Maximum number of NFA states that can comprise a DFA state. It's real
+ * big because if there's a lot of rules, the initial state will have a
+ * huge epsilon closure.
+ */
+#define INITIAL_MAX_DFA_SIZE 750
+#define MAX_DFA_SIZE_INCREMENT 750
+
+
+/* A note on the following masks. They are used to mark accepting numbers
+ * as being special. As such, they implicitly limit the number of accepting
+ * numbers (i.e., rules) because if there are too many rules the rule numbers
+ * will overload the mask bits. Fortunately, this limit is \large/ (0x2000 ==
+ * 8192) so unlikely to actually cause any problems. A check is made in
+ * new_rule() to ensure that this limit is not reached.
+ */
+
+/* Mask to mark a trailing context accepting number. */
+#define YY_TRAILING_MASK 0x2000
+
+/* Mask to mark the accepting number of the "head" of a trailing context
+ * rule.
+ */
+#define YY_TRAILING_HEAD_MASK 0x4000
+
+/* Maximum number of rules, as outlined in the above note. */
+#define MAX_RULE (YY_TRAILING_MASK - 1)
+
+
+/* NIL must be 0. If not, its special meaning when making equivalence classes
+ * (it marks the representative of a given e.c.) will be unidentifiable.
+ */
+#define NIL 0
+
+#define JAM -1 /* to mark a missing DFA transition */
+#define NO_TRANSITION NIL
+#define UNIQUE -1 /* marks a symbol as an e.c. representative */
+#define INFINITY -1 /* for x{5,} constructions */
+
+#define INITIAL_MAX_CCLS 100 /* max number of unique character classes */
+#define MAX_CCLS_INCREMENT 100
+
+/* Size of table holding members of character classes. */
+#define INITIAL_MAX_CCL_TBL_SIZE 500
+#define MAX_CCL_TBL_SIZE_INCREMENT 250
+
+#define INITIAL_MAX_RULES 100 /* default maximum number of rules */
+#define MAX_RULES_INCREMENT 100
+
+#define INITIAL_MNS 2000 /* default maximum number of nfa states */
+#define MNS_INCREMENT 1000 /* amount to bump above by if it's not enough */
+
+#define INITIAL_MAX_DFAS 1000 /* default maximum number of dfa states */
+#define MAX_DFAS_INCREMENT 1000
+
+#define JAMSTATE -32766 /* marks a reference to the state that always jams */
+
+/* Maximum number of NFA states. */
+#define MAXIMUM_MNS 31999
+
+/* Enough so that if it's subtracted from an NFA state number, the result
+ * is guaranteed to be negative.
+ */
+#define MARKER_DIFFERENCE (MAXIMUM_MNS+2)
+
+/* Maximum number of nxt/chk pairs for non-templates. */
+#define INITIAL_MAX_XPAIRS 2000
+#define MAX_XPAIRS_INCREMENT 2000
+
+/* Maximum number of nxt/chk pairs needed for templates. */
+#define INITIAL_MAX_TEMPLATE_XPAIRS 2500
+#define MAX_TEMPLATE_XPAIRS_INCREMENT 2500
+
+#define SYM_EPSILON (CSIZE + 1) /* to mark transitions on the symbol epsilon */
+
+#define INITIAL_MAX_SCS 40 /* maximum number of start conditions */
+#define MAX_SCS_INCREMENT 40 /* amount to bump by if it's not enough */
+
+#define ONE_STACK_SIZE 500 /* stack of states with only one out-transition */
+#define SAME_TRANS -1 /* transition is the same as "default" entry for state */
+
+/* The following percentages are used to tune table compression:
+
+ * The percentage the number of out-transitions a state must be of the
+ * number of equivalence classes in order to be considered for table
+ * compaction by using protos.
+ */
+#define PROTO_SIZE_PERCENTAGE 15
+
+/* The percentage the number of homogeneous out-transitions of a state
+ * must be of the number of total out-transitions of the state in order
+ * that the state's transition table is first compared with a potential
+ * template of the most common out-transition instead of with the first
+ * proto in the proto queue.
+ */
+#define CHECK_COM_PERCENTAGE 50
+
+/* The percentage the number of differences between a state's transition
+ * table and the proto it was first compared with must be of the total
+ * number of out-transitions of the state in order to keep the first
+ * proto as a good match and not search any further.
+ */
+#define FIRST_MATCH_DIFF_PERCENTAGE 10
+
+/* The percentage the number of differences between a state's transition
+ * table and the most similar proto must be of the state's total number
+ * of out-transitions to use the proto as an acceptable close match.
+ */
+#define ACCEPTABLE_DIFF_PERCENTAGE 50
+
+/* The percentage the number of homogeneous out-transitions of a state
+ * must be of the number of total out-transitions of the state in order
+ * to consider making a template from the state.
+ */
+#define TEMPLATE_SAME_PERCENTAGE 60
+
+/* The percentage the number of differences between a state's transition
+ * table and the most similar proto must be of the state's total number
+ * of out-transitions to create a new proto from the state.
+ */
+#define NEW_PROTO_DIFF_PERCENTAGE 20
+
+/* The percentage the total number of out-transitions of a state must be
+ * of the number of equivalence classes in order to consider trying to
+ * fit the transition table into "holes" inside the nxt/chk table.
+ */
+#define INTERIOR_FIT_PERCENTAGE 15
+
+/* Size of region set aside to cache the complete transition table of
+ * protos on the proto queue to enable quick comparisons.
+ */
+#define PROT_SAVE_SIZE 2000
+
+#define MSP 50 /* maximum number of saved protos (protos on the proto queue) */
+
+/* Maximum number of out-transitions a state can have that we'll rummage
+ * around through the interior of the internal fast table looking for a
+ * spot for it.
+ */
+#define MAX_XTIONS_FULL_INTERIOR_FIT 4
+
+/* Maximum number of rules which will be reported as being associated
+ * with a DFA state.
+ */
+#define MAX_ASSOC_RULES 100
+
+/* Number that, if used to subscript an array, has a good chance of producing
+ * an error; should be small enough to fit into a short.
+ */
+#define BAD_SUBSCRIPT -32767
+
+/* Absolute value of largest number that can be stored in a short, with a
+ * bit of slop thrown in for general paranoia.
+ */
+#define MAX_SHORT 32700
+
+
+/* Declarations for global variables. */
+
+/* Variables for symbol tables:
+ * sctbl - start-condition symbol table
+ * ndtbl - name-definition symbol table
+ * ccltab - character class text symbol table
+ */
+
+struct hash_entry
+ {
+ struct hash_entry *prev, *next;
+ char *name;
+ char *str_val;
+ int int_val;
+ } ;
+
+typedef struct hash_entry **hash_table;
+
+#define NAME_TABLE_HASH_SIZE 101
+#define START_COND_HASH_SIZE 101
+#define CCL_HASH_SIZE 101
+
+extern struct hash_entry *ndtbl[NAME_TABLE_HASH_SIZE];
+extern struct hash_entry *sctbl[START_COND_HASH_SIZE];
+extern struct hash_entry *ccltab[CCL_HASH_SIZE];
+
+
+/* Variables for flags:
+ * printstats - if true (-v), dump statistics
+ * syntaxerror - true if a syntax error has been found
+ * eofseen - true if we've seen an eof in the input file
+ * ddebug - if true (-d), make a "debug" scanner
+ * trace - if true (-T), trace processing
+ * nowarn - if true (-w), do not generate warnings
+ * spprdflt - if true (-s), suppress the default rule
+ * interactive - if true (-I), generate an interactive scanner
+ * caseins - if true (-i), generate a case-insensitive scanner
+ * lex_compat - if true (-l), maximize compatibility with AT&T lex
+ * do_yylineno - if true, generate code to maintain yylineno
+ * useecs - if true (-Ce flag), use equivalence classes
+ * fulltbl - if true (-Cf flag), don't compress the DFA state table
+ * usemecs - if true (-Cm flag), use meta-equivalence classes
+ * fullspd - if true (-F flag), use Jacobson method of table representation
+ * gen_line_dirs - if true (i.e., no -L flag), generate #line directives
+ * performance_report - if > 0 (i.e., -p flag), generate a report relating
+ * to scanner performance; if > 1 (-p -p), report on minor performance
+ * problems, too
+ * backing_up_report - if true (i.e., -b flag), generate "lex.backup" file
+ * listing backing-up states
+ * C_plus_plus - if true (i.e., -+ flag), generate a C++ scanner class;
+ * otherwise, a standard C scanner
+ * long_align - if true (-Ca flag), favor long-word alignment.
+ * use_read - if true (-f, -F, or -Cr) then use read() for scanner input;
+ * otherwise, use fread().
+ * yytext_is_array - if true (i.e., %array directive), then declare
+ * yytext as a array instead of a character pointer. Nice and inefficient.
+ * do_yywrap - do yywrap() processing on EOF. If false, EOF treated as
+ * "no more files".
+ * csize - size of character set for the scanner we're generating;
+ * 128 for 7-bit chars and 256 for 8-bit
+ * yymore_used - if true, yymore() is used in input rules
+ * reject - if true, generate back-up tables for REJECT macro
+ * real_reject - if true, scanner really uses REJECT (as opposed to just
+ * having "reject" set for variable trailing context)
+ * continued_action - true if this rule's action is to "fall through" to
+ * the next rule's action (i.e., the '|' action)
+ * in_rule - true if we're inside an individual rule, false if not.
+ * yymore_really_used - whether to treat yymore() as really used, regardless
+ * of what we think based on references to it in the user's actions.
+ * reject_really_used - same for REJECT
+ */
+
+extern int printstats, syntaxerror, eofseen, ddebug, trace, nowarn, spprdflt;
+extern int interactive, caseins, lex_compat, do_yylineno;
+extern int useecs, fulltbl, usemecs, fullspd;
+extern int gen_line_dirs, performance_report, backing_up_report;
+extern int C_plus_plus, long_align, use_read, yytext_is_array, do_yywrap;
+extern int csize;
+extern int yymore_used, reject, real_reject, continued_action, in_rule;
+
+extern int yymore_really_used, reject_really_used;
+
+
+/* Variables used in the flex input routines:
+ * datapos - characters on current output line
+ * dataline - number of contiguous lines of data in current data
+ * statement. Used to generate readable -f output
+ * linenum - current input line number
+ * out_linenum - current output line number
+ * skelfile - the skeleton file
+ * skel - compiled-in skeleton array
+ * skel_ind - index into "skel" array, if skelfile is nil
+ * yyin - input file
+ * backing_up_file - file to summarize backing-up states to
+ * infilename - name of input file
+ * outfilename - name of output file
+ * did_outfilename - whether outfilename was explicitly set
+ * prefix - the prefix used for externally visible names ("yy" by default)
+ * yyclass - yyFlexLexer subclass to use for YY_DECL
+ * do_stdinit - whether to initialize yyin/yyout to stdin/stdout
+ * use_stdout - the -t flag
+ * input_files - array holding names of input files
+ * num_input_files - size of input_files array
+ * program_name - name with which program was invoked
+ *
+ * action_array - array to hold the rule actions
+ * action_size - size of action_array
+ * defs1_offset - index where the user's section 1 definitions start
+ * in action_array
+ * prolog_offset - index where the prolog starts in action_array
+ * action_offset - index where the non-prolog starts in action_array
+ * action_index - index where the next action should go, with respect
+ * to "action_array"
+ */
+
+extern int datapos, dataline, linenum, out_linenum;
+extern FILE *skelfile, *yyin, *backing_up_file;
+extern const char *skel[];
+extern int skel_ind;
+extern char *infilename, *outfilename;
+extern int did_outfilename;
+extern char *prefix, *yyclass;
+extern int do_stdinit, use_stdout;
+extern char **input_files;
+extern int num_input_files;
+extern char *program_name;
+
+extern char *action_array;
+extern int action_size;
+extern int defs1_offset, prolog_offset, action_offset, action_index;
+
+
+/* Variables for stack of states having only one out-transition:
+ * onestate - state number
+ * onesym - transition symbol
+ * onenext - target state
+ * onedef - default base entry
+ * onesp - stack pointer
+ */
+
+extern int onestate[ONE_STACK_SIZE], onesym[ONE_STACK_SIZE];
+extern int onenext[ONE_STACK_SIZE], onedef[ONE_STACK_SIZE], onesp;
+
+
+/* Variables for nfa machine data:
+ * current_mns - current maximum on number of NFA states
+ * num_rules - number of the last accepting state; also is number of
+ * rules created so far
+ * num_eof_rules - number of <<EOF>> rules
+ * default_rule - number of the default rule
+ * current_max_rules - current maximum number of rules
+ * lastnfa - last nfa state number created
+ * firstst - physically the first state of a fragment
+ * lastst - last physical state of fragment
+ * finalst - last logical state of fragment
+ * transchar - transition character
+ * trans1 - transition state
+ * trans2 - 2nd transition state for epsilons
+ * accptnum - accepting number
+ * assoc_rule - rule associated with this NFA state (or 0 if none)
+ * state_type - a STATE_xxx type identifying whether the state is part
+ * of a normal rule, the leading state in a trailing context
+ * rule (i.e., the state which marks the transition from
+ * recognizing the text-to-be-matched to the beginning of
+ * the trailing context), or a subsequent state in a trailing
+ * context rule
+ * rule_type - a RULE_xxx type identifying whether this a ho-hum
+ * normal rule or one which has variable head & trailing
+ * context
+ * rule_linenum - line number associated with rule
+ * rule_useful - true if we've determined that the rule can be matched
+ */
+
+extern int current_mns, current_max_rules;
+extern int num_rules, num_eof_rules, default_rule, lastnfa;
+extern int *firstst, *lastst, *finalst, *transchar, *trans1, *trans2;
+extern int *accptnum, *assoc_rule, *state_type;
+extern int *rule_type, *rule_linenum, *rule_useful;
+
+/* Different types of states; values are useful as masks, as well, for
+ * routines like check_trailing_context().
+ */
+#define STATE_NORMAL 0x1
+#define STATE_TRAILING_CONTEXT 0x2
+
+/* Global holding current type of state we're making. */
+
+extern int current_state_type;
+
+/* Different types of rules. */
+#define RULE_NORMAL 0
+#define RULE_VARIABLE 1
+
+/* True if the input rules include a rule with both variable-length head
+ * and trailing context, false otherwise.
+ */
+extern int variable_trailing_context_rules;
+
+
+/* Variables for protos:
+ * numtemps - number of templates created
+ * numprots - number of protos created
+ * protprev - backlink to a more-recently used proto
+ * protnext - forward link to a less-recently used proto
+ * prottbl - base/def table entry for proto
+ * protcomst - common state of proto
+ * firstprot - number of the most recently used proto
+ * lastprot - number of the least recently used proto
+ * protsave contains the entire state array for protos
+ */
+
+extern int numtemps, numprots, protprev[MSP], protnext[MSP], prottbl[MSP];
+extern int protcomst[MSP], firstprot, lastprot, protsave[PROT_SAVE_SIZE];
+
+
+/* Variables for managing equivalence classes:
+ * numecs - number of equivalence classes
+ * nextecm - forward link of Equivalence Class members
+ * ecgroup - class number or backward link of EC members
+ * nummecs - number of meta-equivalence classes (used to compress
+ * templates)
+ * tecfwd - forward link of meta-equivalence classes members
+ * tecbck - backward link of MEC's
+ */
+
+/* Reserve enough room in the equivalence class arrays so that we
+ * can use the CSIZE'th element to hold equivalence class information
+ * for the NUL character. Later we'll move this information into
+ * the 0th element.
+ */
+extern int numecs, nextecm[CSIZE + 1], ecgroup[CSIZE + 1], nummecs;
+
+/* Meta-equivalence classes are indexed starting at 1, so it's possible
+ * that they will require positions from 1 .. CSIZE, i.e., CSIZE + 1
+ * slots total (since the arrays are 0-based). nextecm[] and ecgroup[]
+ * don't require the extra position since they're indexed from 1 .. CSIZE - 1.
+ */
+extern int tecfwd[CSIZE + 1], tecbck[CSIZE + 1];
+
+
+/* Variables for start conditions:
+ * lastsc - last start condition created
+ * current_max_scs - current limit on number of start conditions
+ * scset - set of rules active in start condition
+ * scbol - set of rules active only at the beginning of line in a s.c.
+ * scxclu - true if start condition is exclusive
+ * sceof - true if start condition has EOF rule
+ * scname - start condition name
+ */
+
+extern int lastsc, *scset, *scbol, *scxclu, *sceof;
+extern int current_max_scs;
+extern char **scname;
+
+
+/* Variables for dfa machine data:
+ * current_max_dfa_size - current maximum number of NFA states in DFA
+ * current_max_xpairs - current maximum number of non-template xtion pairs
+ * current_max_template_xpairs - current maximum number of template pairs
+ * current_max_dfas - current maximum number DFA states
+ * lastdfa - last dfa state number created
+ * nxt - state to enter upon reading character
+ * chk - check value to see if "nxt" applies
+ * tnxt - internal nxt table for templates
+ * base - offset into "nxt" for given state
+ * def - where to go if "chk" disallows "nxt" entry
+ * nultrans - NUL transition for each state
+ * NUL_ec - equivalence class of the NUL character
+ * tblend - last "nxt/chk" table entry being used
+ * firstfree - first empty entry in "nxt/chk" table
+ * dss - nfa state set for each dfa
+ * dfasiz - size of nfa state set for each dfa
+ * dfaacc - accepting set for each dfa state (if using REJECT), or accepting
+ * number, if not
+ * accsiz - size of accepting set for each dfa state
+ * dhash - dfa state hash value
+ * numas - number of DFA accepting states created; note that this
+ * is not necessarily the same value as num_rules, which is the analogous
+ * value for the NFA
+ * numsnpairs - number of state/nextstate transition pairs
+ * jambase - position in base/def where the default jam table starts
+ * jamstate - state number corresponding to "jam" state
+ * end_of_buffer_state - end-of-buffer dfa state number
+ */
+
+extern int current_max_dfa_size, current_max_xpairs;
+extern int current_max_template_xpairs, current_max_dfas;
+extern int lastdfa, *nxt, *chk, *tnxt;
+extern int *base, *def, *nultrans, NUL_ec, tblend, firstfree, **dss, *dfasiz;
+extern union dfaacc_union
+ {
+ int *dfaacc_set;
+ int dfaacc_state;
+ } *dfaacc;
+extern int *accsiz, *dhash, numas;
+extern int numsnpairs, jambase, jamstate;
+extern int end_of_buffer_state;
+
+/* Variables for ccl information:
+ * lastccl - ccl index of the last created ccl
+ * current_maxccls - current limit on the maximum number of unique ccl's
+ * cclmap - maps a ccl index to its set pointer
+ * ccllen - gives the length of a ccl
+ * cclng - true for a given ccl if the ccl is negated
+ * cclreuse - counts how many times a ccl is re-used
+ * current_max_ccl_tbl_size - current limit on number of characters needed
+ * to represent the unique ccl's
+ * ccltbl - holds the characters in each ccl - indexed by cclmap
+ */
+
+extern int lastccl, *cclmap, *ccllen, *cclng, cclreuse;
+extern int current_maxccls, current_max_ccl_tbl_size;
+extern Char *ccltbl;
+
+
+/* Variables for miscellaneous information:
+ * nmstr - last NAME scanned by the scanner
+ * sectnum - section number currently being parsed
+ * nummt - number of empty nxt/chk table entries
+ * hshcol - number of hash collisions detected by snstods
+ * dfaeql - number of times a newly created dfa was equal to an old one
+ * numeps - number of epsilon NFA states created
+ * eps2 - number of epsilon states which have 2 out-transitions
+ * num_reallocs - number of times it was necessary to realloc() a group
+ * of arrays
+ * tmpuses - number of DFA states that chain to templates
+ * totnst - total number of NFA states used to make DFA states
+ * peakpairs - peak number of transition pairs we had to store internally
+ * numuniq - number of unique transitions
+ * numdup - number of duplicate transitions
+ * hshsave - number of hash collisions saved by checking number of states
+ * num_backing_up - number of DFA states requiring backing up
+ * bol_needed - whether scanner needs beginning-of-line recognition
+ */
+
+extern char nmstr[MAXLINE];
+extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
+extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
+extern int num_backing_up, bol_needed;
+
+void *allocate_array PROTO((int, size_t));
+void *reallocate_array PROTO((void*, int, size_t));
+
+void *flex_alloc PROTO((size_t));
+void *flex_realloc PROTO((void*, size_t));
+void flex_free PROTO((void*));
+
+#define allocate_integer_array(size) \
+ (int *) allocate_array( size, sizeof( int ) )
+
+#define reallocate_integer_array(array,size) \
+ (int *) reallocate_array( (void *) array, size, sizeof( int ) )
+
+#define allocate_int_ptr_array(size) \
+ (int **) allocate_array( size, sizeof( int * ) )
+
+#define allocate_char_ptr_array(size) \
+ (char **) allocate_array( size, sizeof( char * ) )
+
+#define allocate_dfaacc_union(size) \
+ (union dfaacc_union *) \
+ allocate_array( size, sizeof( union dfaacc_union ) )
+
+#define reallocate_int_ptr_array(array,size) \
+ (int **) reallocate_array( (void *) array, size, sizeof( int * ) )
+
+#define reallocate_char_ptr_array(array,size) \
+ (char **) reallocate_array( (void *) array, size, sizeof( char * ) )
+
+#define reallocate_dfaacc_union(array, size) \
+ (union dfaacc_union *) \
+ reallocate_array( (void *) array, size, sizeof( union dfaacc_union ) )
+
+#define allocate_character_array(size) \
+ (char *) allocate_array( size, sizeof( char ) )
+
+#define reallocate_character_array(array,size) \
+ (char *) reallocate_array( (void *) array, size, sizeof( char ) )
+
+#define allocate_Character_array(size) \
+ (Char *) allocate_array( size, sizeof( Char ) )
+
+#define reallocate_Character_array(array,size) \
+ (Char *) reallocate_array( (void *) array, size, sizeof( Char ) )
+
+
+/* Used to communicate between scanner and parser. The type should really
+ * be YYSTYPE, but we can't easily get our hands on it.
+ */
+extern int yylval;
+
+
+/* External functions that are cross-referenced among the flex source files. */
+
+
+/* from file ccl.c */
+
+extern void ccladd PROTO((int, int)); /* add a single character to a ccl */
+extern int cclinit PROTO((void)); /* make an empty ccl */
+extern void cclnegate PROTO((int)); /* negate a ccl */
+
+/* List the members of a set of characters in CCL form. */
+extern void list_character_set PROTO((FILE*, int[]));
+
+
+/* from file dfa.c */
+
+/* Check a DFA state for backing up. */
+extern void check_for_backing_up PROTO((int, int[]));
+
+/* Check to see if NFA state set constitutes "dangerous" trailing context. */
+extern void check_trailing_context PROTO((int*, int, int*, int));
+
+/* Construct the epsilon closure of a set of ndfa states. */
+extern int *epsclosure PROTO((int*, int*, int[], int*, int*));
+
+/* Increase the maximum number of dfas. */
+extern void increase_max_dfas PROTO((void));
+
+extern void ntod PROTO((void)); /* convert a ndfa to a dfa */
+
+/* Converts a set of ndfa states into a dfa state. */
+extern int snstods PROTO((int[], int, int[], int, int, int*));
+
+
+/* from file ecs.c */
+
+/* Convert character classes to set of equivalence classes. */
+extern void ccl2ecl PROTO((void));
+
+/* Associate equivalence class numbers with class members. */
+extern int cre8ecs PROTO((int[], int[], int));
+
+/* Update equivalence classes based on character class transitions. */
+extern void mkeccl PROTO((Char[], int, int[], int[], int, int));
+
+/* Create equivalence class for single character. */
+extern void mkechar PROTO((int, int[], int[]));
+
+
+/* from file gen.c */
+
+extern void do_indent PROTO((void)); /* indent to the current level */
+
+/* Generate the code to keep backing-up information. */
+extern void gen_backing_up PROTO((void));
+
+/* Generate the code to perform the backing up. */
+extern void gen_bu_action PROTO((void));
+
+/* Generate full speed compressed transition table. */
+extern void genctbl PROTO((void));
+
+/* Generate the code to find the action number. */
+extern void gen_find_action PROTO((void));
+
+extern void genftbl PROTO((void)); /* generate full transition table */
+
+/* Generate the code to find the next compressed-table state. */
+extern void gen_next_compressed_state PROTO((char*));
+
+/* Generate the code to find the next match. */
+extern void gen_next_match PROTO((void));
+
+/* Generate the code to find the next state. */
+extern void gen_next_state PROTO((int));
+
+/* Generate the code to make a NUL transition. */
+extern void gen_NUL_trans PROTO((void));
+
+/* Generate the code to find the start state. */
+extern void gen_start_state PROTO((void));
+
+/* Generate data statements for the transition tables. */
+extern void gentabs PROTO((void));
+
+/* Write out a formatted string at the current indentation level. */
+extern void indent_put2s PROTO((char[], char[]));
+
+/* Write out a string + newline at the current indentation level. */
+extern void indent_puts PROTO((char[]));
+
+extern void make_tables PROTO((void)); /* generate transition tables */
+
+
+/* from file main.c */
+
+extern void check_options PROTO((void));
+extern void flexend PROTO((int));
+extern void usage PROTO((void));
+
+
+/* from file misc.c */
+
+/* Add a #define to the action file. */
+extern void action_define PROTO(( char *defname, int value ));
+
+/* Add the given text to the stored actions. */
+extern void add_action PROTO(( char *new_text ));
+
+/* True if a string is all lower case. */
+extern int all_lower PROTO((register char *));
+
+/* True if a string is all upper case. */
+extern int all_upper PROTO((register char *));
+
+/* Bubble sort an integer array. */
+extern void bubble PROTO((int [], int));
+
+/* Check a character to make sure it's in the expected range. */
+extern void check_char PROTO((int c));
+
+/* Replace upper-case letter to lower-case. */
+extern Char clower PROTO((int));
+
+/* Returns a dynamically allocated copy of a string. */
+extern char *copy_string PROTO((register const char *));
+
+/* Returns a dynamically allocated copy of a (potentially) unsigned string. */
+extern Char *copy_unsigned_string PROTO((register Char *));
+
+/* Shell sort a character array. */
+extern void cshell PROTO((Char [], int, int));
+
+/* Finish up a block of data declarations. */
+extern void dataend PROTO((void));
+
+/* Flush generated data statements. */
+extern void dataflush PROTO((void));
+
+/* Report an error message and terminate. */
+extern void flexerror PROTO((const char[]));
+
+/* Report a fatal error message and terminate. */
+extern void flexfatal PROTO((const char[]));
+
+/* Convert a hexadecimal digit string to an integer value. */
+extern int htoi PROTO((Char[]));
+
+/* Report an error message formatted with one integer argument. */
+extern void lerrif PROTO((const char[], int));
+
+/* Report an error message formatted with one string argument. */
+extern void lerrsf PROTO((const char[], const char[]));
+
+/* Spit out a "#line" statement. */
+extern void line_directive_out PROTO((FILE*, int));
+
+/* Mark the current position in the action array as the end of the section 1
+ * user defs.
+ */
+extern void mark_defs1 PROTO((void));
+
+/* Mark the current position in the action array as the end of the prolog. */
+extern void mark_prolog PROTO((void));
+
+/* Generate a data statment for a two-dimensional array. */
+extern void mk2data PROTO((int));
+
+extern void mkdata PROTO((int)); /* generate a data statement */
+
+/* Return the integer represented by a string of digits. */
+extern int myctoi PROTO((char []));
+
+/* Return character corresponding to escape sequence. */
+extern Char myesc PROTO((Char[]));
+
+/* Convert an octal digit string to an integer value. */
+extern int otoi PROTO((Char [] ));
+
+/* Output a (possibly-formatted) string to the generated scanner. */
+extern void out PROTO((const char []));
+extern void out_dec PROTO((const char [], int));
+extern void out_dec2 PROTO((const char [], int, int));
+extern void out_hex PROTO((const char [], unsigned int));
+extern void out_line_count PROTO((const char []));
+extern void out_str PROTO((const char [], const char []));
+extern void out_str3
+ PROTO((const char [], const char [], const char [], const char []));
+extern void out_str_dec PROTO((const char [], const char [], int));
+extern void outc PROTO((int));
+extern void outn PROTO((const char []));
+
+/* Return a printable version of the given character, which might be
+ * 8-bit.
+ */
+extern char *readable_form PROTO((int));
+
+/* Write out one section of the skeleton file. */
+extern void skelout PROTO((void));
+
+/* Output a yy_trans_info structure. */
+extern void transition_struct_out PROTO((int, int));
+
+/* Only needed when using certain broken versions of bison to build parse.c. */
+extern void *yy_flex_xmalloc PROTO(( int ));
+
+/* Set a region of memory to 0. */
+extern void zero_out PROTO((char *, size_t));
+
+
+/* from file nfa.c */
+
+/* Add an accepting state to a machine. */
+extern void add_accept PROTO((int, int));
+
+/* Make a given number of copies of a singleton machine. */
+extern int copysingl PROTO((int, int));
+
+/* Debugging routine to write out an nfa. */
+extern void dumpnfa PROTO((int));
+
+/* Finish up the processing for a rule. */
+extern void finish_rule PROTO((int, int, int, int));
+
+/* Connect two machines together. */
+extern int link_machines PROTO((int, int));
+
+/* Mark each "beginning" state in a machine as being a "normal" (i.e.,
+ * not trailing context associated) state.
+ */
+extern void mark_beginning_as_normal PROTO((register int));
+
+/* Make a machine that branches to two machines. */
+extern int mkbranch PROTO((int, int));
+
+extern int mkclos PROTO((int)); /* convert a machine into a closure */
+extern int mkopt PROTO((int)); /* make a machine optional */
+
+/* Make a machine that matches either one of two machines. */
+extern int mkor PROTO((int, int));
+
+/* Convert a machine into a positive closure. */
+extern int mkposcl PROTO((int));
+
+extern int mkrep PROTO((int, int, int)); /* make a replicated machine */
+
+/* Create a state with a transition on a given symbol. */
+extern int mkstate PROTO((int));
+
+extern void new_rule PROTO((void)); /* initialize for a new rule */
+
+
+/* from file parse.y */
+
+/* Build the "<<EOF>>" action for the active start conditions. */
+extern void build_eof_action PROTO((void));
+
+/* Write out a message formatted with one string, pinpointing its location. */
+extern void format_pinpoint_message PROTO((char[], char[]));
+
+/* Write out a message, pinpointing its location. */
+extern void pinpoint_message PROTO((char[]));
+
+/* Write out a warning, pinpointing it at the given line. */
+extern void line_warning PROTO(( char[], int ));
+
+/* Write out a message, pinpointing it at the given line. */
+extern void line_pinpoint PROTO(( char[], int ));
+
+/* Report a formatted syntax error. */
+extern void format_synerr PROTO((char [], char[]));
+extern void synerr PROTO((char [])); /* report a syntax error */
+extern void format_warn PROTO((char [], char[]));
+extern void warn PROTO((char [])); /* report a warning */
+extern void yyerror PROTO((char [])); /* report a parse error */
+extern int yyparse PROTO((void)); /* the YACC parser */
+
+
+/* from file scan.l */
+
+/* The Flex-generated scanner for flex. */
+extern int flexscan PROTO((void));
+
+/* Open the given file (if NULL, stdin) for scanning. */
+extern void set_input_file PROTO((char*));
+
+/* Wrapup a file in the lexical analyzer. */
+extern int yywrap PROTO((void));
+
+
+/* from file sym.c */
+
+/* Add symbol and definitions to symbol table. */
+extern int addsym PROTO((register char[], char*, int, hash_table, int));
+
+/* Save the text of a character class. */
+extern void cclinstal PROTO ((Char [], int));
+
+/* Lookup the number associated with character class. */
+extern int ccllookup PROTO((Char []));
+
+/* Find symbol in symbol table. */
+extern struct hash_entry *findsym PROTO((register char[], hash_table, int ));
+
+extern void ndinstal PROTO((char[], Char[])); /* install a name definition */
+extern Char *ndlookup PROTO((char[])); /* lookup a name definition */
+
+/* Increase maximum number of SC's. */
+extern void scextend PROTO((void));
+extern void scinstal PROTO((char[], int)); /* make a start condition */
+
+/* Lookup the number associated with a start condition. */
+extern int sclookup PROTO((char[]));
+
+
+/* from file tblcmp.c */
+
+/* Build table entries for dfa state. */
+extern void bldtbl PROTO((int[], int, int, int, int));
+
+extern void cmptmps PROTO((void)); /* compress template table entries */
+extern void expand_nxt_chk PROTO((void)); /* increase nxt/chk arrays */
+/* Finds a space in the table for a state to be placed. */
+extern int find_table_space PROTO((int*, int));
+extern void inittbl PROTO((void)); /* initialize transition tables */
+/* Make the default, "jam" table entries. */
+extern void mkdeftbl PROTO((void));
+
+/* Create table entries for a state (or state fragment) which has
+ * only one out-transition.
+ */
+extern void mk1tbl PROTO((int, int, int, int));
+
+/* Place a state into full speed transition table. */
+extern void place_state PROTO((int*, int, int));
+
+/* Save states with only one out-transition to be processed later. */
+extern void stack1 PROTO((int, int, int, int));
+
+
+/* from file yylex.c */
+
+extern int yylex PROTO((void));
diff --git a/usr.bin/lex/gen.c b/usr.bin/lex/gen.c
new file mode 100644
index 0000000..08f400a
--- /dev/null
+++ b/usr.bin/lex/gen.c
@@ -0,0 +1,1625 @@
+/* gen - actual generation (writing) of flex scanners */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/gen.c,v 1.1.1.2 1996/06/19 20:26:10 nate Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+void gen_next_state PROTO((int));
+void genecs PROTO((void));
+void indent_put2s PROTO((char [], char []));
+void indent_puts PROTO((char []));
+
+
+static int indent_level = 0; /* each level is 8 spaces */
+
+#define indent_up() (++indent_level)
+#define indent_down() (--indent_level)
+#define set_indent(indent_val) indent_level = indent_val
+
+/* Almost everything is done in terms of arrays starting at 1, so provide
+ * a null entry for the zero element of all C arrays. (The exception
+ * to this is that the fast table representation generally uses the
+ * 0 elements of its arrays, too.)
+ */
+static char C_int_decl[] = "static yyconst int %s[%d] =\n { 0,\n";
+static char C_short_decl[] = "static yyconst short int %s[%d] =\n { 0,\n";
+static char C_long_decl[] = "static yyconst long int %s[%d] =\n { 0,\n";
+static char C_state_decl[] =
+ "static yyconst yy_state_type %s[%d] =\n { 0,\n";
+
+
+/* Indent to the current level. */
+
+void do_indent()
+ {
+ register int i = indent_level * 8;
+
+ while ( i >= 8 )
+ {
+ outc( '\t' );
+ i -= 8;
+ }
+
+ while ( i > 0 )
+ {
+ outc( ' ' );
+ --i;
+ }
+ }
+
+
+/* Generate the code to keep backing-up information. */
+
+void gen_backing_up()
+ {
+ if ( reject || num_backing_up == 0 )
+ return;
+
+ if ( fullspd )
+ indent_puts( "if ( yy_current_state[-1].yy_nxt )" );
+ else
+ indent_puts( "if ( yy_accept[yy_current_state] )" );
+
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_last_accepting_state = yy_current_state;" );
+ indent_puts( "yy_last_accepting_cpos = yy_cp;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+
+/* Generate the code to perform the backing up. */
+
+void gen_bu_action()
+ {
+ if ( reject || num_backing_up == 0 )
+ return;
+
+ set_indent( 3 );
+
+ indent_puts( "case 0: /* must back up */" );
+ indent_puts( "/* undo the effects of YY_DO_BEFORE_ACTION */" );
+ indent_puts( "*yy_cp = yy_hold_char;" );
+
+ if ( fullspd || fulltbl )
+ indent_puts( "yy_cp = yy_last_accepting_cpos + 1;" );
+ else
+ /* Backing-up info for compressed tables is taken \after/
+ * yy_cp has been incremented for the next state.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+
+ indent_puts( "yy_current_state = yy_last_accepting_state;" );
+ indent_puts( "goto yy_find_action;" );
+ outc( '\n' );
+
+ set_indent( 0 );
+ }
+
+
+/* genctbl - generates full speed compressed transition table */
+
+void genctbl()
+ {
+ register int i;
+ int end_of_buffer_action = num_rules + 1;
+
+ /* Table of verify for transition and offset to next state. */
+ out_dec( "static yyconst struct yy_trans_info yy_transition[%d] =\n",
+ tblend + numecs + 1 );
+ outn( " {" );
+
+ /* We want the transition to be represented as the offset to the
+ * next state, not the actual state number, which is what it currently
+ * is. The offset is base[nxt[i]] - (base of current state)]. That's
+ * just the difference between the starting points of the two involved
+ * states (to - from).
+ *
+ * First, though, we need to find some way to put in our end-of-buffer
+ * flags and states. We do this by making a state with absolutely no
+ * transitions. We put it at the end of the table.
+ */
+
+ /* We need to have room in nxt/chk for two more slots: One for the
+ * action and one for the end-of-buffer transition. We now *assume*
+ * that we're guaranteed the only character we'll try to index this
+ * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure
+ * there's room for jam entries for other characters.
+ */
+
+ while ( tblend + 2 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ while ( lastdfa + 1 >= current_max_dfas )
+ increase_max_dfas();
+
+ base[lastdfa + 1] = tblend + 2;
+ nxt[tblend + 1] = end_of_buffer_action;
+ chk[tblend + 1] = numecs + 1;
+ chk[tblend + 2] = 1; /* anything but EOB */
+
+ /* So that "make test" won't show arb. differences. */
+ nxt[tblend + 2] = 0;
+
+ /* Make sure every state has an end-of-buffer transition and an
+ * action #.
+ */
+ for ( i = 0; i <= lastdfa; ++i )
+ {
+ int anum = dfaacc[i].dfaacc_state;
+ int offset = base[i];
+
+ chk[offset] = EOB_POSITION;
+ chk[offset - 1] = ACTION_POSITION;
+ nxt[offset - 1] = anum; /* action number */
+ }
+
+ for ( i = 0; i <= tblend; ++i )
+ {
+ if ( chk[i] == EOB_POSITION )
+ transition_struct_out( 0, base[lastdfa + 1] - i );
+
+ else if ( chk[i] == ACTION_POSITION )
+ transition_struct_out( 0, nxt[i] );
+
+ else if ( chk[i] > numecs || chk[i] == 0 )
+ transition_struct_out( 0, 0 ); /* unused slot */
+
+ else /* verify, transition */
+ transition_struct_out( chk[i],
+ base[nxt[i]] - (i - chk[i]) );
+ }
+
+
+ /* Here's the final, end-of-buffer state. */
+ transition_struct_out( chk[tblend + 1], nxt[tblend + 1] );
+ transition_struct_out( chk[tblend + 2], nxt[tblend + 2] );
+
+ outn( " };\n" );
+
+ /* Table of pointers to start states. */
+ out_dec(
+ "static yyconst struct yy_trans_info *yy_start_state_list[%d] =\n",
+ lastsc * 2 + 1 );
+ outn( " {" ); /* } so vi doesn't get confused */
+
+ for ( i = 0; i <= lastsc * 2; ++i )
+ out_dec( " &yy_transition[%d],\n", base[i] );
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+ }
+
+
+/* Generate equivalence-class tables. */
+
+void genecs()
+ {
+ register int i, j;
+ int numrows;
+
+ out_str_dec( C_int_decl, "yy_ec", csize );
+
+ for ( i = 1; i < csize; ++i )
+ {
+ if ( caseins && (i >= 'A') && (i <= 'Z') )
+ ecgroup[i] = ecgroup[clower( i )];
+
+ ecgroup[i] = ABS( ecgroup[i] );
+ mkdata( ecgroup[i] );
+ }
+
+ dataend();
+
+ if ( trace )
+ {
+ fputs( _( "\n\nEquivalence Classes:\n\n" ), stderr );
+
+ numrows = csize / 8;
+
+ for ( j = 0; j < numrows; ++j )
+ {
+ for ( i = j; i < csize; i = i + numrows )
+ {
+ fprintf( stderr, "%4s = %-2d",
+ readable_form( i ), ecgroup[i] );
+
+ putc( ' ', stderr );
+ }
+
+ putc( '\n', stderr );
+ }
+ }
+ }
+
+
+/* Generate the code to find the action number. */
+
+void gen_find_action()
+ {
+ if ( fullspd )
+ indent_puts( "yy_act = yy_current_state[-1].yy_nxt;" );
+
+ else if ( fulltbl )
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+
+ else if ( reject )
+ {
+ indent_puts( "yy_current_state = *--yy_state_ptr;" );
+ indent_puts( "yy_lp = yy_accept[yy_current_state];" );
+
+ outn(
+ "find_rule: /* we branch to this label when backing up */" );
+
+ indent_puts(
+ "for ( ; ; ) /* until we find what rule we matched */" );
+
+ indent_up();
+
+ indent_puts( "{" );
+
+ indent_puts(
+ "if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_act = yy_acclist[yy_lp];" );
+
+ if ( variable_trailing_context_rules )
+ {
+ indent_puts( "if ( yy_act & YY_TRAILING_HEAD_MASK ||" );
+ indent_puts( " yy_looking_for_trail_begin )" );
+ indent_up();
+ indent_puts( "{" );
+
+ indent_puts(
+ "if ( yy_act == yy_looking_for_trail_begin )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_looking_for_trail_begin = 0;" );
+ indent_puts( "yy_act &= ~YY_TRAILING_HEAD_MASK;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "else if ( yy_act & YY_TRAILING_MASK )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts(
+ "yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;" );
+ indent_puts(
+ "yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;" );
+
+ if ( real_reject )
+ {
+ /* Remember matched text in case we back up
+ * due to REJECT.
+ */
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "yy_full_state = yy_state_ptr;" );
+ indent_puts( "yy_full_lp = yy_lp;" );
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "else" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "yy_full_state = yy_state_ptr;" );
+ indent_puts( "yy_full_lp = yy_lp;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "++yy_lp;" );
+ indent_puts( "goto find_rule;" );
+ }
+
+ else
+ {
+ /* Remember matched text in case we back up due to
+ * trailing context plus REJECT.
+ */
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "--yy_cp;" );
+
+ /* We could consolidate the following two lines with those at
+ * the beginning, but at the cost of complaints that we're
+ * branching inside a loop.
+ */
+ indent_puts( "yy_current_state = *--yy_state_ptr;" );
+ indent_puts( "yy_lp = yy_accept[yy_current_state];" );
+
+ indent_puts( "}" );
+
+ indent_down();
+ }
+
+ else
+ { /* compressed */
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+
+ if ( interactive && ! reject )
+ {
+ /* Do the guaranteed-needed backing up to figure out
+ * the match.
+ */
+ indent_puts( "if ( yy_act == 0 )" );
+ indent_up();
+ indent_puts( "{ /* have to back up */" );
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+ indent_puts( "}" );
+ indent_down();
+ }
+ }
+ }
+
+
+/* genftbl - generate full transition table */
+
+void genftbl()
+ {
+ register int i;
+ int end_of_buffer_action = num_rules + 1;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_accept", lastdfa + 1 );
+
+ dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ register int anum = dfaacc[i].dfaacc_state;
+
+ mkdata( anum );
+
+ if ( trace && anum )
+ fprintf( stderr, _( "state # %d accepts: [%d]\n" ),
+ i, anum );
+ }
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+
+ /* Don't have to dump the actual full table entries - they were
+ * created on-the-fly.
+ */
+ }
+
+
+/* Generate the code to find the next compressed-table state. */
+
+void gen_next_compressed_state( char_map )
+char *char_map;
+ {
+ indent_put2s( "register YY_CHAR yy_c = %s;", char_map );
+
+ /* Save the backing-up info \before/ computing the next state
+ * because we always compute one more state than needed - we
+ * always proceed until we reach a jam state
+ */
+ gen_backing_up();
+
+ indent_puts(
+"while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_current_state = (int) yy_def[yy_current_state];" );
+
+ if ( usemecs )
+ {
+ /* We've arrange it so that templates are never chained
+ * to one another. This means we can afford to make a
+ * very simple test to see if we need to convert to
+ * yy_c's meta-equivalence class without worrying
+ * about erroneously looking up the meta-equivalence
+ * class twice
+ */
+ do_indent();
+
+ /* lastdfa + 2 is the beginning of the templates */
+ out_dec( "if ( yy_current_state >= %d )\n", lastdfa + 2 );
+
+ indent_up();
+ indent_puts( "yy_c = yy_meta[(unsigned int) yy_c];" );
+ indent_down();
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts(
+"yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];" );
+ }
+
+
+/* Generate the code to find the next match. */
+
+void gen_next_match()
+ {
+ /* NOTE - changes in here should be reflected in gen_next_state() and
+ * gen_NUL_trans().
+ */
+ char *char_map = useecs ?
+ "yy_ec[YY_SC_TO_UI(*yy_cp)]" :
+ "YY_SC_TO_UI(*yy_cp)";
+
+ char *char_map_2 = useecs ?
+ "yy_ec[YY_SC_TO_UI(*++yy_cp)]" :
+ "YY_SC_TO_UI(*++yy_cp)";
+
+ if ( fulltbl )
+ {
+ indent_put2s(
+ "while ( (yy_current_state = yy_nxt[yy_current_state][%s]) > 0 )",
+ char_map );
+
+ indent_up();
+
+ if ( num_backing_up > 0 )
+ {
+ indent_puts( "{" ); /* } for vi */
+ gen_backing_up();
+ outc( '\n' );
+ }
+
+ indent_puts( "++yy_cp;" );
+
+ if ( num_backing_up > 0 )
+ /* { for vi */
+ indent_puts( "}" );
+
+ indent_down();
+
+ outc( '\n' );
+ indent_puts( "yy_current_state = -yy_current_state;" );
+ }
+
+ else if ( fullspd )
+ {
+ indent_puts( "{" ); /* } for vi */
+ indent_puts(
+ "register yyconst struct yy_trans_info *yy_trans_info;\n" );
+ indent_puts( "register YY_CHAR yy_c;\n" );
+ indent_put2s( "for ( yy_c = %s;", char_map );
+ indent_puts(
+ " (yy_trans_info = &yy_current_state[(unsigned int) yy_c])->" );
+ indent_puts( "yy_verify == yy_c;" );
+ indent_put2s( " yy_c = %s )", char_map_2 );
+
+ indent_up();
+
+ if ( num_backing_up > 0 )
+ indent_puts( "{" ); /* } for vi */
+
+ indent_puts( "yy_current_state += yy_trans_info->yy_nxt;" );
+
+ if ( num_backing_up > 0 )
+ {
+ outc( '\n' );
+ gen_backing_up(); /* { for vi */
+ indent_puts( "}" );
+ }
+
+ indent_down(); /* { for vi */
+ indent_puts( "}" );
+ }
+
+ else
+ { /* compressed */
+ indent_puts( "do" );
+
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+
+ gen_next_state( false );
+
+ indent_puts( "++yy_cp;" );
+
+ /* { for vi */
+ indent_puts( "}" );
+ indent_down();
+
+ do_indent();
+
+ if ( interactive )
+ out_dec( "while ( yy_base[yy_current_state] != %d );\n",
+ jambase );
+ else
+ out_dec( "while ( yy_current_state != %d );\n",
+ jamstate );
+
+ if ( ! reject && ! interactive )
+ {
+ /* Do the guaranteed-needed backing up to figure out
+ * the match.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ }
+ }
+ }
+
+
+/* Generate the code to find the next state. */
+
+void gen_next_state( worry_about_NULs )
+int worry_about_NULs;
+ { /* NOTE - changes in here should be reflected in gen_next_match() */
+ char char_map[256];
+
+ if ( worry_about_NULs && ! nultrans )
+ {
+ if ( useecs )
+ (void) sprintf( char_map,
+ "(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : %d)",
+ NUL_ec );
+ else
+ (void) sprintf( char_map,
+ "(*yy_cp ? YY_SC_TO_UI(*yy_cp) : %d)", NUL_ec );
+ }
+
+ else
+ strcpy( char_map, useecs ?
+ "yy_ec[YY_SC_TO_UI(*yy_cp)]" : "YY_SC_TO_UI(*yy_cp)" );
+
+ if ( worry_about_NULs && nultrans )
+ {
+ if ( ! fulltbl && ! fullspd )
+ /* Compressed tables back up *before* they match. */
+ gen_backing_up();
+
+ indent_puts( "if ( *yy_cp )" );
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+ }
+
+ if ( fulltbl )
+ indent_put2s(
+ "yy_current_state = yy_nxt[yy_current_state][%s];",
+ char_map );
+
+ else if ( fullspd )
+ indent_put2s(
+ "yy_current_state += yy_current_state[%s].yy_nxt;",
+ char_map );
+
+ else
+ gen_next_compressed_state( char_map );
+
+ if ( worry_about_NULs && nultrans )
+ {
+ /* { for vi */
+ indent_puts( "}" );
+ indent_down();
+ indent_puts( "else" );
+ indent_up();
+ indent_puts(
+ "yy_current_state = yy_NUL_trans[yy_current_state];" );
+ indent_down();
+ }
+
+ if ( fullspd || fulltbl )
+ gen_backing_up();
+
+ if ( reject )
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ }
+
+
+/* Generate the code to make a NUL transition. */
+
+void gen_NUL_trans()
+ { /* NOTE - changes in here should be reflected in gen_next_match() */
+ /* Only generate a definition for "yy_cp" if we'll generate code
+ * that uses it. Otherwise lint and the like complain.
+ */
+ int need_backing_up = (num_backing_up > 0 && ! reject);
+
+ if ( need_backing_up && (! nultrans || fullspd || fulltbl) )
+ /* We're going to need yy_cp lying around for the call
+ * below to gen_backing_up().
+ */
+ indent_puts( "register char *yy_cp = yy_c_buf_p;" );
+
+ outc( '\n' );
+
+ if ( nultrans )
+ {
+ indent_puts(
+ "yy_current_state = yy_NUL_trans[yy_current_state];" );
+ indent_puts( "yy_is_jam = (yy_current_state == 0);" );
+ }
+
+ else if ( fulltbl )
+ {
+ do_indent();
+ out_dec( "yy_current_state = yy_nxt[yy_current_state][%d];\n",
+ NUL_ec );
+ indent_puts( "yy_is_jam = (yy_current_state <= 0);" );
+ }
+
+ else if ( fullspd )
+ {
+ do_indent();
+ out_dec( "register int yy_c = %d;\n", NUL_ec );
+
+ indent_puts(
+ "register yyconst struct yy_trans_info *yy_trans_info;\n" );
+ indent_puts(
+ "yy_trans_info = &yy_current_state[(unsigned int) yy_c];" );
+ indent_puts( "yy_current_state += yy_trans_info->yy_nxt;" );
+
+ indent_puts(
+ "yy_is_jam = (yy_trans_info->yy_verify != yy_c);" );
+ }
+
+ else
+ {
+ char NUL_ec_str[20];
+
+ (void) sprintf( NUL_ec_str, "%d", NUL_ec );
+ gen_next_compressed_state( NUL_ec_str );
+
+ do_indent();
+ out_dec( "yy_is_jam = (yy_current_state == %d);\n", jamstate );
+
+ if ( reject )
+ {
+ /* Only stack this state if it's a transition we
+ * actually make. If we stack it on a jam, then
+ * the state stack and yy_c_buf_p get out of sync.
+ */
+ indent_puts( "if ( ! yy_is_jam )" );
+ indent_up();
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ indent_down();
+ }
+ }
+
+ /* If we've entered an accepting state, back up; note that
+ * compressed tables have *already* done such backing up, so
+ * we needn't bother with it again.
+ */
+ if ( need_backing_up && (fullspd || fulltbl) )
+ {
+ outc( '\n' );
+ indent_puts( "if ( ! yy_is_jam )" );
+ indent_up();
+ indent_puts( "{" );
+ gen_backing_up();
+ indent_puts( "}" );
+ indent_down();
+ }
+ }
+
+
+/* Generate the code to find the start state. */
+
+void gen_start_state()
+ {
+ if ( fullspd )
+ {
+ if ( bol_needed )
+ {
+ indent_puts(
+ "yy_current_state = yy_start_state_list[yy_start + YY_AT_BOL()];" );
+ }
+ else
+ indent_puts(
+ "yy_current_state = yy_start_state_list[yy_start];" );
+ }
+
+ else
+ {
+ indent_puts( "yy_current_state = yy_start;" );
+
+ if ( bol_needed )
+ indent_puts( "yy_current_state += YY_AT_BOL();" );
+
+ if ( reject )
+ {
+ /* Set up for storing up states. */
+ indent_puts( "yy_state_ptr = yy_state_buf;" );
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ }
+ }
+ }
+
+
+/* gentabs - generate data statements for the transition tables */
+
+void gentabs()
+ {
+ int i, j, k, *accset, nacc, *acc_array, total_states;
+ int end_of_buffer_action = num_rules + 1;
+
+ acc_array = allocate_integer_array( current_max_dfas );
+ nummt = 0;
+
+ /* The compressed table format jams by entering the "jam state",
+ * losing information about the previous state in the process.
+ * In order to recover the previous state, we effectively need
+ * to keep backing-up information.
+ */
+ ++num_backing_up;
+
+ if ( reject )
+ {
+ /* Write out accepting list and pointer list.
+ *
+ * First we generate the "yy_acclist" array. In the process,
+ * we compute the indices that will go into the "yy_accept"
+ * array, and save the indices in the dfaacc array.
+ */
+ int EOB_accepting_list[2];
+
+ /* Set up accepting structures for the End Of Buffer state. */
+ EOB_accepting_list[0] = 0;
+ EOB_accepting_list[1] = end_of_buffer_action;
+ accsiz[end_of_buffer_state] = 1;
+ dfaacc[end_of_buffer_state].dfaacc_set = EOB_accepting_list;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_acclist", MAX( numas, 1 ) + 1 );
+
+ j = 1; /* index into "yy_acclist" array */
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ acc_array[i] = j;
+
+ if ( accsiz[i] != 0 )
+ {
+ accset = dfaacc[i].dfaacc_set;
+ nacc = accsiz[i];
+
+ if ( trace )
+ fprintf( stderr,
+ _( "state # %d accepts: " ),
+ i );
+
+ for ( k = 1; k <= nacc; ++k )
+ {
+ int accnum = accset[k];
+
+ ++j;
+
+ if ( variable_trailing_context_rules &&
+ ! (accnum & YY_TRAILING_HEAD_MASK) &&
+ accnum > 0 && accnum <= num_rules &&
+ rule_type[accnum] == RULE_VARIABLE )
+ {
+ /* Special hack to flag
+ * accepting number as part
+ * of trailing context rule.
+ */
+ accnum |= YY_TRAILING_MASK;
+ }
+
+ mkdata( accnum );
+
+ if ( trace )
+ {
+ fprintf( stderr, "[%d]",
+ accset[k] );
+
+ if ( k < nacc )
+ fputs( ", ", stderr );
+ else
+ putc( '\n', stderr );
+ }
+ }
+ }
+ }
+
+ /* add accepting number for the "jam" state */
+ acc_array[i] = j;
+
+ dataend();
+ }
+
+ else
+ {
+ dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ acc_array[i] = dfaacc[i].dfaacc_state;
+
+ /* add accepting number for jam state */
+ acc_array[i] = 0;
+ }
+
+ /* Spit out "yy_accept" array. If we're doing "reject", it'll be
+ * pointers into the "yy_acclist" array. Otherwise it's actual
+ * accepting numbers. In either case, we just dump the numbers.
+ */
+
+ /* "lastdfa + 2" is the size of "yy_accept"; includes room for C arrays
+ * beginning at 0 and for "jam" state.
+ */
+ k = lastdfa + 2;
+
+ if ( reject )
+ /* We put a "cap" on the table associating lists of accepting
+ * numbers with state numbers. This is needed because we tell
+ * where the end of an accepting list is by looking at where
+ * the list for the next state starts.
+ */
+ ++k;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl, "yy_accept", k );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ mkdata( acc_array[i] );
+
+ if ( ! reject && trace && acc_array[i] )
+ fprintf( stderr, _( "state # %d accepts: [%d]\n" ),
+ i, acc_array[i] );
+ }
+
+ /* Add entry for "jam" state. */
+ mkdata( acc_array[i] );
+
+ if ( reject )
+ /* Add "cap" for the list. */
+ mkdata( acc_array[i] );
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+
+ if ( usemecs )
+ {
+ /* Write out meta-equivalence classes (used to index
+ * templates with).
+ */
+
+ if ( trace )
+ fputs( _( "\n\nMeta-Equivalence Classes:\n" ),
+ stderr );
+
+ out_str_dec( C_int_decl, "yy_meta", numecs + 1 );
+
+ for ( i = 1; i <= numecs; ++i )
+ {
+ if ( trace )
+ fprintf( stderr, "%d = %d\n",
+ i, ABS( tecbck[i] ) );
+
+ mkdata( ABS( tecbck[i] ) );
+ }
+
+ dataend();
+ }
+
+ total_states = lastdfa + numtemps;
+
+ out_str_dec( (tblend >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_base", total_states + 1 );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ register int d = def[i];
+
+ if ( base[i] == JAMSTATE )
+ base[i] = jambase;
+
+ if ( d == JAMSTATE )
+ def[i] = jamstate;
+
+ else if ( d < 0 )
+ {
+ /* Template reference. */
+ ++tmpuses;
+ def[i] = lastdfa - d + 1;
+ }
+
+ mkdata( base[i] );
+ }
+
+ /* Generate jam state's base index. */
+ mkdata( base[i] );
+
+ for ( ++i /* skip jam state */; i <= total_states; ++i )
+ {
+ mkdata( base[i] );
+ def[i] = jamstate;
+ }
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_def", total_states + 1 );
+
+ for ( i = 1; i <= total_states; ++i )
+ mkdata( def[i] );
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_nxt", tblend + 1 );
+
+ for ( i = 1; i <= tblend; ++i )
+ {
+ /* Note, the order of the following test is important.
+ * If chk[i] is 0, then nxt[i] is undefined.
+ */
+ if ( chk[i] == 0 || nxt[i] == 0 )
+ nxt[i] = jamstate; /* new state is the JAM state */
+
+ mkdata( nxt[i] );
+ }
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_chk", tblend + 1 );
+
+ for ( i = 1; i <= tblend; ++i )
+ {
+ if ( chk[i] == 0 )
+ ++nummt;
+
+ mkdata( chk[i] );
+ }
+
+ dataend();
+ }
+
+
+/* Write out a formatted string (with a secondary string argument) at the
+ * current indentation level, adding a final newline.
+ */
+
+void indent_put2s( fmt, arg )
+char fmt[], arg[];
+ {
+ do_indent();
+ out_str( fmt, arg );
+ outn( "" );
+ }
+
+
+/* Write out a string at the current indentation level, adding a final
+ * newline.
+ */
+
+void indent_puts( str )
+char str[];
+ {
+ do_indent();
+ outn( str );
+ }
+
+
+/* make_tables - generate transition tables and finishes generating output file
+ */
+
+void make_tables()
+ {
+ register int i;
+ int did_eof_rule = false;
+
+ skelout();
+
+ /* First, take care of YY_DO_BEFORE_ACTION depending on yymore
+ * being used.
+ */
+ set_indent( 1 );
+
+ if ( yymore_used && ! yytext_is_array )
+ {
+ indent_puts( "yytext_ptr -= yy_more_len; \\" );
+ indent_puts( "yyleng = (int) (yy_cp - yytext_ptr); \\" );
+ }
+
+ else
+ indent_puts( "yyleng = (int) (yy_cp - yy_bp); \\" );
+
+ /* Now also deal with copying yytext_ptr to yytext if needed. */
+ skelout();
+ if ( yytext_is_array )
+ {
+ if ( yymore_used )
+ indent_puts(
+ "if ( yyleng + yy_more_offset >= YYLMAX ) \\" );
+ else
+ indent_puts( "if ( yyleng >= YYLMAX ) \\" );
+
+ indent_up();
+ indent_puts(
+ "YY_FATAL_ERROR( \"token too large, exceeds YYLMAX\" ); \\" );
+ indent_down();
+
+ if ( yymore_used )
+ {
+ indent_puts(
+"yy_flex_strncpy( &yytext[yy_more_offset], yytext_ptr, yyleng + 1 ); \\" );
+ indent_puts( "yyleng += yy_more_offset; \\" );
+ indent_puts(
+ "yy_prev_more_offset = yy_more_offset; \\" );
+ indent_puts( "yy_more_offset = 0; \\" );
+ }
+ else
+ {
+ indent_puts(
+ "yy_flex_strncpy( yytext, yytext_ptr, yyleng + 1 ); \\" );
+ }
+ }
+
+ set_indent( 0 );
+
+ skelout();
+
+
+ out_dec( "#define YY_NUM_RULES %d\n", num_rules );
+ out_dec( "#define YY_END_OF_BUFFER %d\n", num_rules + 1 );
+
+ if ( fullspd )
+ {
+ /* Need to define the transet type as a size large
+ * enough to hold the biggest offset.
+ */
+ int total_table_size = tblend + numecs + 1;
+ char *trans_offset_type =
+ (total_table_size >= MAX_SHORT || long_align) ?
+ "long" : "short";
+
+ set_indent( 0 );
+ indent_puts( "struct yy_trans_info" );
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+
+ if ( long_align )
+ indent_puts( "long yy_verify;" );
+ else
+ indent_puts( "short yy_verify;" );
+
+ /* In cases where its sister yy_verify *is* a "yes, there is
+ * a transition", yy_nxt is the offset (in records) to the
+ * next state. In most cases where there is no transition,
+ * the value of yy_nxt is irrelevant. If yy_nxt is the -1th
+ * record of a state, though, then yy_nxt is the action number
+ * for that state.
+ */
+
+ indent_put2s( "%s yy_nxt;", trans_offset_type );
+ indent_puts( "};" );
+ indent_down();
+ }
+
+ if ( fullspd )
+ genctbl();
+ else if ( fulltbl )
+ genftbl();
+ else
+ gentabs();
+
+ /* Definitions for backing up. We don't need them if REJECT
+ * is being used because then we use an alternative backin-up
+ * technique instead.
+ */
+ if ( num_backing_up > 0 && ! reject )
+ {
+ if ( ! C_plus_plus )
+ {
+ indent_puts(
+ "static yy_state_type yy_last_accepting_state;" );
+ indent_puts(
+ "static char *yy_last_accepting_cpos;\n" );
+ }
+ }
+
+ if ( nultrans )
+ {
+ out_str_dec( C_state_decl, "yy_NUL_trans", lastdfa + 1 );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ if ( fullspd )
+ out_dec( " &yy_transition[%d],\n", base[i] );
+ else
+ mkdata( nultrans[i] );
+ }
+
+ dataend();
+ }
+
+ if ( ddebug )
+ { /* Spit out table mapping rules to line numbers. */
+ if ( ! C_plus_plus )
+ {
+ indent_puts( "extern int yy_flex_debug;" );
+ indent_puts( "int yy_flex_debug = 1;\n" );
+ }
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_rule_linenum", num_rules );
+ for ( i = 1; i < num_rules; ++i )
+ mkdata( rule_linenum[i] );
+ dataend();
+ }
+
+ if ( reject )
+ {
+ /* Declare state buffer variables. */
+ if ( ! C_plus_plus )
+ {
+ outn(
+ "static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;" );
+ outn( "static char *yy_full_match;" );
+ outn( "static int yy_lp;" );
+ }
+
+ if ( variable_trailing_context_rules )
+ {
+ if ( ! C_plus_plus )
+ {
+ outn(
+ "static int yy_looking_for_trail_begin = 0;" );
+ outn( "static int yy_full_lp;" );
+ outn( "static int *yy_full_state;" );
+ }
+
+ out_hex( "#define YY_TRAILING_MASK 0x%x\n",
+ (unsigned int) YY_TRAILING_MASK );
+ out_hex( "#define YY_TRAILING_HEAD_MASK 0x%x\n",
+ (unsigned int) YY_TRAILING_HEAD_MASK );
+ }
+
+ outn( "#define REJECT \\" );
+ outn( "{ \\" ); /* } for vi */
+ outn(
+ "*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \\" );
+ outn(
+ "yy_cp = yy_full_match; /* restore poss. backed-over text */ \\" );
+
+ if ( variable_trailing_context_rules )
+ {
+ outn(
+ "yy_lp = yy_full_lp; /* restore orig. accepting pos. */ \\" );
+ outn(
+ "yy_state_ptr = yy_full_state; /* restore orig. state */ \\" );
+ outn(
+ "yy_current_state = *yy_state_ptr; /* restore curr. state */ \\" );
+ }
+
+ outn( "++yy_lp; \\" );
+ outn( "goto find_rule; \\" );
+ /* { for vi */
+ outn( "}" );
+ }
+
+ else
+ {
+ outn(
+ "/* The intent behind this definition is that it'll catch" );
+ outn( " * any uses of REJECT which flex missed." );
+ outn( " */" );
+ outn( "#define REJECT reject_used_but_not_detected" );
+ }
+
+ if ( yymore_used )
+ {
+ if ( ! C_plus_plus )
+ {
+ if ( yytext_is_array )
+ {
+ indent_puts( "static int yy_more_offset = 0;" );
+ indent_puts(
+ "static int yy_prev_more_offset = 0;" );
+ }
+ else
+ {
+ indent_puts( "static int yy_more_flag = 0;" );
+ indent_puts( "static int yy_more_len = 0;" );
+ }
+ }
+
+ if ( yytext_is_array )
+ {
+ indent_puts(
+ "#define yymore() (yy_more_offset = yy_flex_strlen( yytext ))" );
+ indent_puts( "#define YY_NEED_STRLEN" );
+ indent_puts( "#define YY_MORE_ADJ 0" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET \\" );
+ indent_up();
+ indent_puts( "{ \\" );
+ indent_puts( "yy_more_offset = yy_prev_more_offset; \\" );
+ indent_puts( "yyleng -= yy_more_offset; \\" );
+ indent_puts( "}" );
+ indent_down();
+ }
+ else
+ {
+ indent_puts( "#define yymore() (yy_more_flag = 1)" );
+ indent_puts( "#define YY_MORE_ADJ yy_more_len" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET" );
+ }
+ }
+
+ else
+ {
+ indent_puts( "#define yymore() yymore_used_but_not_detected" );
+ indent_puts( "#define YY_MORE_ADJ 0" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET" );
+ }
+
+ if ( ! C_plus_plus )
+ {
+ if ( yytext_is_array )
+ {
+ outn( "#ifndef YYLMAX" );
+ outn( "#define YYLMAX 8192" );
+ outn( "#endif\n" );
+ outn( "char yytext[YYLMAX];" );
+ outn( "char *yytext_ptr;" );
+ }
+
+ else
+ outn( "char *yytext;" );
+ }
+
+ out( &action_array[defs1_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ skelout();
+
+ if ( ! C_plus_plus )
+ {
+ if ( use_read )
+ {
+ outn(
+"\tif ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \\" );
+ outn(
+ "\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );" );
+ }
+
+ else
+ {
+ outn(
+ "\tif ( yy_current_buffer->yy_is_interactive ) \\" );
+ outn( "\t\t{ \\" );
+ outn( "\t\tint c = '*', n; \\" );
+ outn( "\t\tfor ( n = 0; n < max_size && \\" );
+ outn( "\t\t\t (c = getc( yyin )) != EOF && c != '\\n'; ++n ) \\" );
+ outn( "\t\t\tbuf[n] = (char) c; \\" );
+ outn( "\t\tif ( c == '\\n' ) \\" );
+ outn( "\t\t\tbuf[n++] = (char) c; \\" );
+ outn( "\t\tif ( c == EOF && ferror( yyin ) ) \\" );
+ outn(
+ "\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\" );
+ outn( "\t\tresult = n; \\" );
+ outn( "\t\t} \\" );
+ outn(
+ "\telse if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \\" );
+ outn( "\t\t && ferror( yyin ) ) \\" );
+ outn(
+ "\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );" );
+ }
+ }
+
+ skelout();
+
+ indent_puts( "#define YY_RULE_SETUP \\" );
+ indent_up();
+ if ( bol_needed )
+ {
+ indent_puts( "if ( yyleng > 0 ) \\" );
+ indent_up();
+ indent_puts( "yy_current_buffer->yy_at_bol = \\" );
+ indent_puts( "\t\t(yytext[yyleng - 1] == '\\n'); \\" );
+ indent_down();
+ }
+ indent_puts( "YY_USER_ACTION" );
+ indent_down();
+
+ skelout();
+
+ /* Copy prolog to output file. */
+ out( &action_array[prolog_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ skelout();
+
+ set_indent( 2 );
+
+ if ( yymore_used && ! yytext_is_array )
+ {
+ indent_puts( "yy_more_len = 0;" );
+ indent_puts( "if ( yy_more_flag )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_more_len = yy_c_buf_p - yytext_ptr;" );
+ indent_puts( "yy_more_flag = 0;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ skelout();
+
+ gen_start_state();
+
+ /* Note, don't use any indentation. */
+ outn( "yy_match:" );
+ gen_next_match();
+
+ skelout();
+ set_indent( 2 );
+ gen_find_action();
+
+ skelout();
+ if ( do_yylineno )
+ {
+ indent_puts( "if ( yy_act != YY_END_OF_BUFFER )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "int yyl;" );
+ indent_puts( "for ( yyl = 0; yyl < yyleng; ++yyl )" );
+ indent_up();
+ indent_puts( "if ( yytext[yyl] == '\\n' )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ indent_down();
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ skelout();
+ if ( ddebug )
+ {
+ indent_puts( "if ( yy_flex_debug )" );
+ indent_up();
+
+ indent_puts( "{" );
+ indent_puts( "if ( yy_act == 0 )" );
+ indent_up();
+ indent_puts( C_plus_plus ?
+ "cerr << \"--scanner backing up\\n\";" :
+ "fprintf( stderr, \"--scanner backing up\\n\" );" );
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act < %d )\n", num_rules );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+ "cerr << \"--accepting rule at line \" << yy_rule_linenum[yy_act] <<" );
+ indent_puts(
+ " \"(\\\"\" << yytext << \"\\\")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--accepting rule at line %d (\\\"%s\\\")\\n\"," );
+
+ indent_puts(
+ " yy_rule_linenum[yy_act], yytext );" );
+ }
+
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act == %d )\n", num_rules );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+"cerr << \"--accepting default rule (\\\"\" << yytext << \"\\\")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--accepting default rule (\\\"%s\\\")\\n\"," );
+ indent_puts( " yytext );" );
+ }
+
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act == %d )\n", num_rules + 1 );
+ indent_up();
+
+ indent_puts( C_plus_plus ?
+ "cerr << \"--(end of buffer or a NUL)\\n\";" :
+ "fprintf( stderr, \"--(end of buffer or a NUL)\\n\" );" );
+
+ indent_down();
+
+ do_indent();
+ outn( "else" );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+ "cerr << \"--EOF (start condition \" << YY_START << \")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--EOF (start condition %d)\\n\", YY_START );" );
+ }
+
+ indent_down();
+
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ /* Copy actions to output file. */
+ skelout();
+ indent_up();
+ gen_bu_action();
+ out( &action_array[action_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ /* generate cases for any missing EOF rules */
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! sceof[i] )
+ {
+ do_indent();
+ out_str( "case YY_STATE_EOF(%s):\n", scname[i] );
+ did_eof_rule = true;
+ }
+
+ if ( did_eof_rule )
+ {
+ indent_up();
+ indent_puts( "yyterminate();" );
+ indent_down();
+ }
+
+
+ /* Generate code for handling NUL's, if needed. */
+
+ /* First, deal with backing up and setting up yy_cp if the scanner
+ * finds that it should JAM on the NUL.
+ */
+ skelout();
+ set_indent( 4 );
+
+ if ( fullspd || fulltbl )
+ indent_puts( "yy_cp = yy_c_buf_p;" );
+
+ else
+ { /* compressed table */
+ if ( ! reject && ! interactive )
+ {
+ /* Do the guaranteed-needed backing up to figure
+ * out the match.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ }
+
+ else
+ /* Still need to initialize yy_cp, though
+ * yy_current_state was set up by
+ * yy_get_previous_state().
+ */
+ indent_puts( "yy_cp = yy_c_buf_p;" );
+ }
+
+
+ /* Generate code for yy_get_previous_state(). */
+ set_indent( 1 );
+ skelout();
+
+ gen_start_state();
+
+ set_indent( 2 );
+ skelout();
+ gen_next_state( true );
+
+ set_indent( 1 );
+ skelout();
+ gen_NUL_trans();
+
+ skelout();
+ if ( do_yylineno )
+ { /* update yylineno inside of unput() */
+ indent_puts( "if ( c == '\\n' )" );
+ indent_up();
+ indent_puts( "--yylineno;" );
+ indent_down();
+ }
+
+ skelout();
+ /* Update BOL and yylineno inside of input(). */
+ if ( bol_needed )
+ {
+ indent_puts( "yy_current_buffer->yy_at_bol = (c == '\\n');" );
+ if ( do_yylineno )
+ {
+ indent_puts( "if ( yy_current_buffer->yy_at_bol )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ }
+ }
+
+ else if ( do_yylineno )
+ {
+ indent_puts( "if ( c == '\\n' )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ }
+
+ skelout();
+
+ /* Copy remainder of input to output. */
+
+ line_directive_out( stdout, 1 );
+
+ if ( sectnum == 3 )
+ (void) flexscan(); /* copy remainder of input to output */
+ }
diff --git a/usr.bin/lex/initscan.c b/usr.bin/lex/initscan.c
new file mode 100644
index 0000000..f5e9dd1
--- /dev/null
+++ b/usr.bin/lex/initscan.c
@@ -0,0 +1,3697 @@
+#line 2 "scan.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/ncvs/src/usr.bin/lex/initscan.c,v 1.3 1996/06/19 20:47:13 nate Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 165
+#define YY_END_OF_BUFFER 166
+static yyconst short int yy_accept[769] =
+ { 0,
+ 0, 0, 0, 0, 87, 87, 163, 163, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 166, 164,
+ 7, 18, 164, 16, 1, 17, 164, 164, 164, 164,
+ 15, 108, 100, 101, 108, 93, 108, 107, 108, 108,
+ 108, 107, 99, 89, 108, 108, 91, 92, 87, 88,
+ 87, 86, 85, 86, 86, 163, 163, 28, 29, 28,
+ 28, 28, 28, 28, 28, 31, 30, 32, 31, 113,
+ 109, 110, 112, 114, 141, 142, 141, 139, 138, 140,
+
+ 115, 117, 115, 116, 115, 120, 120, 120, 120, 122,
+ 124, 122, 122, 122, 122, 123, 151, 155, 151, 154,
+ 156, 156, 152, 152, 152, 149, 150, 164, 82, 164,
+ 21, 22, 21, 20, 157, 159, 157, 160, 161, 147,
+ 147, 148, 147, 147, 147, 147, 147, 147, 147, 81,
+ 34, 33, 81, 81, 81, 81, 35, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 26, 23, 26, 24,
+ 7, 18, 0, 16, 1, 17, 0, 0, 0, 14,
+ 8, 0, 0, 0, 0, 4, 5, 0, 2, 15,
+
+ 100, 101, 0, 0, 0, 95, 0, 0, 105, 105,
+ 0, 162, 162, 162, 94, 0, 99, 89, 0, 0,
+ 0, 91, 92, 104, 90, 0, 87, 88, 86, 85,
+ 85, 83, 84, 163, 163, 28, 29, 28, 28, 28,
+ 28, 31, 30, 32, 111, 112, 142, 138, 117, 0,
+ 118, 119, 124, 121, 151, 155, 0, 153, 0, 144,
+ 152, 152, 152, 0, 82, 0, 21, 22, 21, 19,
+ 157, 159, 158, 147, 147, 147, 148, 143, 147, 147,
+ 147, 34, 33, 0, 80, 0, 0, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 81, 81, 36, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 0, 25, 24, 0, 14, 8,
+ 0, 12, 0, 0, 0, 0, 0, 4, 5, 0,
+ 6, 0, 96, 0, 97, 0, 0, 105, 105, 0,
+ 105, 105, 105, 162, 162, 0, 106, 90, 98, 0,
+ 104, 0, 83, 84, 28, 28, 28, 27, 28, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 152, 152, 143, 143, 147, 147, 0, 0, 81,
+ 81, 81, 81, 81, 44, 81, 81, 81, 49, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 81, 81, 81, 81, 81, 81, 81, 0, 81,
+ 81, 81, 81, 0, 0, 0, 12, 0, 0, 0,
+ 0, 0, 0, 4, 5, 0, 105, 105, 105, 105,
+ 105, 105, 162, 0, 0, 28, 28, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 152, 152, 147, 147, 37, 38, 81, 81, 81, 81,
+ 81, 81, 81, 81, 50, 51, 81, 81, 81, 55,
+ 81, 81, 81, 81, 81, 81, 60, 81, 81, 81,
+ 81, 81, 81, 67, 0, 0, 0, 81, 81, 81,
+ 81, 0, 13, 0, 0, 0, 0, 0, 0, 105,
+
+ 105, 105, 105, 105, 105, 0, 0, 28, 28, 137,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 152, 152, 147, 147, 39, 81, 41, 81,
+ 43, 81, 81, 81, 47, 81, 52, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 62, 81, 81, 65,
+ 81, 0, 0, 0, 0, 81, 81, 81, 81, 3,
+ 0, 0, 0, 0, 105, 105, 105, 0, 0, 28,
+ 28, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 145, 146, 145, 146, 81, 42, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 78, 61, 81, 64, 81, 0, 0, 0, 0,
+ 81, 81, 69, 70, 0, 10, 0, 11, 0, 103,
+ 0, 102, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 81, 81, 81, 45, 81, 48,
+ 81, 81, 81, 81, 77, 81, 59, 63, 66, 0,
+ 0, 0, 0, 79, 81, 0, 102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 81,
+ 81, 81, 46, 81, 81, 56, 81, 81, 0, 0,
+ 0, 0, 68, 0, 9, 0, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, 134, 135, 0, 81, 81,
+
+ 81, 81, 81, 81, 81, 0, 0, 0, 0, 0,
+ 136, 81, 81, 81, 81, 54, 81, 81, 0, 0,
+ 0, 0, 0, 0, 81, 81, 81, 53, 81, 58,
+ 0, 0, 0, 0, 0, 0, 81, 81, 81, 81,
+ 72, 0, 0, 0, 0, 73, 81, 81, 81, 81,
+ 71, 0, 75, 0, 81, 81, 81, 74, 76, 81,
+ 81, 81, 81, 81, 81, 57, 40, 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 7, 8, 1, 9, 10,
+ 10, 11, 12, 13, 14, 10, 15, 16, 16, 16,
+ 16, 16, 16, 16, 17, 18, 19, 20, 1, 21,
+ 22, 23, 10, 1, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 47,
+ 26, 27, 28, 29, 30, 1, 31, 32, 33, 34,
+
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 47, 56, 57, 58, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[59] =
+ { 0,
+ 1, 1, 2, 1, 3, 1, 1, 1, 4, 1,
+ 5, 6, 1, 7, 4, 8, 8, 8, 8, 1,
+ 1, 1, 1, 9, 10, 1, 11, 12, 1, 13,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 4, 1, 16
+ } ;
+
+static yyconst short int yy_base[858] =
+ { 0,
+ 0, 58, 115, 172, 120, 129, 2712, 2711, 230, 2705,
+ 136, 141, 288, 0, 2683, 2682, 144, 151, 185, 191,
+ 178, 188, 344, 347, 375, 0, 125, 131, 147, 216,
+ 431, 434, 461, 0, 519, 0, 205, 349, 2710, 2716,
+ 353, 2716, 2706, 0, 360, 2716, 2705, 144, 570, 2696,
+ 0, 2716, 577, 2716, 2703, 2716, 438, 2716, 2684, 126,
+ 149, 427, 591, 2716, 2701, 141, 2682, 2716, 0, 2716,
+ 2699, 0, 2699, 2697, 155, 2696, 2716, 0, 2716, 2695,
+ 2716, 0, 2662, 2641, 2637, 0, 2692, 2716, 2690, 2716,
+ 2716, 2663, 0, 2716, 2716, 2716, 2688, 2716, 431, 2716,
+
+ 2716, 2716, 2687, 2716, 567, 2716, 2669, 571, 164, 2716,
+ 2716, 2685, 0, 2667, 573, 2716, 0, 2716, 2683, 2716,
+ 573, 2674, 0, 2649, 2628, 2716, 2716, 222, 2716, 356,
+ 448, 2716, 450, 2667, 0, 2716, 2678, 2716, 0, 0,
+ 198, 2716, 2677, 2621, 2716, 2667, 0, 2642, 2621, 2716,
+ 2673, 2716, 2671, 2668, 2640, 2639, 2716, 544, 2639, 579,
+ 2634, 2635, 318, 0, 2623, 2631, 424, 562, 2614, 587,
+ 2629, 2613, 2618, 2626, 2629, 2604, 2716, 2716, 2653, 612,
+ 634, 2716, 2654, 0, 637, 2716, 2653, 600, 2616, 0,
+ 0, 641, 647, 651, 669, 0, 0, 453, 2716, 0,
+
+ 672, 2716, 2651, 2597, 605, 2716, 2649, 2616, 620, 657,
+ 645, 2716, 662, 0, 2716, 2592, 688, 2716, 2646, 2592,
+ 2636, 2625, 2716, 0, 2716, 2610, 0, 2716, 0, 0,
+ 2642, 0, 0, 2640, 2716, 0, 2716, 0, 2602, 2598,
+ 745, 0, 2638, 2716, 2716, 0, 2716, 688, 2716, 773,
+ 2716, 2716, 2716, 2716, 0, 2716, 673, 2716, 0, 2716,
+ 0, 2599, 2595, 690, 2716, 698, 707, 2716, 709, 2716,
+ 0, 2716, 2716, 0, 596, 2579, 2716, 827, 0, 2596,
+ 2592, 2632, 2716, 2628, 2716, 2593, 2592, 0, 642, 2582,
+ 563, 2617, 2579, 620, 2578, 2577, 2583, 669, 2570, 2584,
+
+ 2572, 0, 2569, 2716, 2570, 2571, 2579, 2582, 685, 125,
+ 2570, 2567, 2566, 688, 2608, 2716, 716, 2568, 0, 0,
+ 720, 2716, 2608, 884, 2562, 2559, 2569, 0, 0, 723,
+ 2716, 739, 2716, 805, 2716, 808, 2562, 787, 869, 876,
+ 930, 881, 973, 800, 0, 2548, 2716, 2716, 2716, 2570,
+ 0, 2559, 0, 0, 2568, 2557, 0, 2716, 0, 1009,
+ 2581, 678, 870, 871, 874, 879, 913, 992, 974, 1013,
+ 885, 2565, 2554, 0, 1067, 2563, 2552, 2546, 2545, 2557,
+ 2562, 2561, 2550, 2557, 0, 2554, 2537, 2556, 0, 2536,
+ 2543, 2533, 2548, 2568, 2537, 2549, 2544, 2542, 2541, 2532,
+
+ 2539, 2540, 2538, 2539, 578, 2520, 2538, 2525, 860, 2526,
+ 2528, 2521, 2517, 2529, 817, 1044, 2716, 822, 1095, 914,
+ 2532, 2523, 2517, 0, 0, 2524, 1102, 1025, 1142, 2539,
+ 1028, 1163, 2716, 2513, 2521, 2523, 2507, 0, 2526, 1058,
+ 891, 1014, 1019, 894, 1038, 1080, 1072, 1086, 1083, 1081,
+ 2520, 2504, 2518, 2502, 2716, 2716, 2505, 2493, 2492, 2495,
+ 2507, 1148, 2507, 2492, 0, 0, 2492, 2493, 2507, 0,
+ 2525, 2490, 2498, 2522, 2485, 2495, 0, 2500, 2491, 2487,
+ 2479, 2479, 2483, 0, 875, 2494, 2481, 2494, 2480, 2475,
+ 2491, 2519, 2716, 920, 999, 2465, 2474, 2468, 2494, 2496,
+
+ 1105, 1184, 1081, 902, 969, 2479, 2491, 2463, 2477, 2716,
+ 165, 1090, 1144, 1143, 1147, 1163, 1095, 1145, 1037, 1085,
+ 1150, 1173, 2461, 2475, 2459, 2473, 0, 2458, 0, 2460,
+ 0, 1165, 2454, 2469, 0, 2461, 0, 2471, 2410, 2414,
+ 2434, 2400, 2393, 2405, 2385, 2382, 0, 2383, 2335, 0,
+ 2335, 2330, 2326, 2309, 2278, 2259, 2269, 2268, 2256, 2297,
+ 1046, 2238, 2242, 2253, 1179, 1142, 1145, 2247, 2246, 0,
+ 0, 1191, 1192, 1172, 1201, 1202, 1204, 1205, 1206, 1207,
+ 1209, 1210, 1208, 0, 0, 0, 0, 2254, 0, 2221,
+ 2229, 2218, 2208, 2200, 2209, 2198, 2195, 2165, 2168, 2149,
+
+ 2132, 0, 0, 2129, 0, 2139, 2143, 2134, 2124, 2137,
+ 2117, 2116, 0, 0, 1228, 2716, 1232, 2716, 2111, 2716,
+ 2117, 2716, 2115, 2114, 2108, 2107, 2106, 2103, 2102, 2098,
+ 2095, 2063, 2047, 1213, 2012, 1986, 1975, 0, 1954, 0,
+ 1947, 1950, 1941, 1945, 0, 1942, 0, 0, 0, 1938,
+ 1940, 1934, 1905, 0, 1872, 1234, 2716, 1888, 1882, 1881,
+ 1864, 1848, 1832, 1828, 1827, 1826, 1823, 1806, 1809, 1784,
+ 1787, 1772, 0, 1781, 1786, 0, 1766, 1767, 1759, 1744,
+ 1213, 1736, 0, 1236, 2716, 1245, 2716, 2716, 2716, 2716,
+ 2716, 2716, 2716, 2716, 2716, 2716, 2716, 1750, 1727, 1720,
+
+ 1701, 1687, 1670, 1681, 1667, 1679, 1659, 689, 1658, 1671,
+ 2716, 1657, 1627, 1621, 1635, 0, 1603, 1596, 1595, 1608,
+ 1602, 1587, 1586, 1583, 1581, 1587, 1555, 0, 1547, 0,
+ 1527, 1507, 1520, 1503, 1483, 1482, 1485, 1443, 1440, 1228,
+ 2716, 1225, 1224, 1206, 1210, 2716, 1213, 1202, 1018, 948,
+ 2716, 945, 2716, 884, 780, 771, 779, 2716, 2716, 689,
+ 673, 581, 408, 318, 86, 0, 0, 2716, 1263, 1279,
+ 1295, 1311, 1327, 1343, 1359, 1375, 1391, 1407, 1423, 1439,
+ 1455, 1471, 1481, 1496, 1505, 1520, 1536, 1545, 1560, 1576,
+ 1592, 1608, 1624, 1634, 1649, 1659, 1674, 1690, 1706, 1718,
+
+ 1728, 1743, 1759, 1775, 1791, 1807, 1817, 1832, 1843, 1236,
+ 1858, 1874, 1890, 1898, 1905, 1920, 1936, 1952, 1968, 1977,
+ 1985, 2001, 2017, 2033, 2049, 2065, 2081, 2097, 2113, 2123,
+ 2138, 2148, 2155, 2170, 2182, 2192, 2207, 2223, 2239, 2255,
+ 2265, 2280, 2291, 2306, 2322, 2338, 2354, 2364, 2373, 2388,
+ 2404, 2420, 2429, 2437, 2453, 2469, 2485
+ } ;
+
+static yyconst short int yy_def[858] =
+ { 0,
+ 768, 768, 769, 769, 770, 771, 772, 772, 768, 9,
+ 773, 773, 768, 13, 774, 774, 775, 775, 776, 776,
+ 777, 777, 778, 778, 768, 25, 779, 779, 780, 780,
+ 781, 781, 768, 33, 768, 35, 782, 782, 768, 768,
+ 768, 768, 768, 783, 768, 768, 768, 768, 784, 768,
+ 785, 768, 768, 768, 768, 768, 768, 768, 768, 786,
+ 787, 788, 768, 768, 768, 768, 768, 768, 789, 768,
+ 789, 790, 791, 790, 790, 792, 768, 793, 768, 793,
+ 768, 794, 794, 794, 793, 795, 768, 768, 795, 768,
+ 768, 768, 796, 768, 768, 768, 768, 768, 768, 768,
+
+ 768, 768, 768, 768, 787, 768, 768, 787, 797, 768,
+ 768, 768, 798, 768, 787, 768, 799, 768, 799, 768,
+ 800, 768, 801, 801, 801, 768, 768, 802, 768, 802,
+ 803, 768, 803, 768, 804, 768, 804, 768, 805, 806,
+ 806, 768, 806, 806, 768, 806, 807, 807, 807, 768,
+ 768, 768, 768, 808, 768, 768, 768, 809, 809, 809,
+ 809, 809, 809, 809, 809, 809, 809, 810, 809, 809,
+ 809, 809, 809, 809, 809, 809, 768, 768, 811, 768,
+ 768, 768, 768, 783, 768, 768, 768, 768, 768, 812,
+ 813, 768, 768, 768, 768, 814, 815, 816, 768, 785,
+
+ 768, 768, 768, 768, 817, 768, 768, 768, 818, 818,
+ 819, 768, 768, 820, 768, 821, 768, 768, 768, 768,
+ 768, 768, 768, 822, 768, 768, 823, 768, 824, 825,
+ 825, 826, 827, 828, 768, 829, 768, 830, 830, 830,
+ 768, 831, 768, 768, 768, 832, 768, 768, 768, 833,
+ 768, 768, 768, 768, 834, 768, 835, 768, 835, 768,
+ 836, 836, 836, 837, 768, 837, 838, 768, 838, 768,
+ 839, 768, 768, 840, 840, 840, 768, 768, 841, 841,
+ 841, 768, 768, 842, 768, 768, 768, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 768, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 844, 768, 768, 768, 845, 846,
+ 847, 768, 768, 768, 768, 768, 768, 848, 849, 850,
+ 768, 850, 768, 851, 768, 851, 768, 852, 852, 852,
+ 768, 852, 852, 768, 853, 854, 768, 768, 768, 768,
+ 855, 768, 826, 827, 830, 830, 241, 768, 241, 241,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 836, 836, 278, 278, 841, 841, 768, 768, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 843, 843, 843, 843, 843, 768, 843,
+ 843, 843, 843, 768, 847, 847, 768, 847, 847, 768,
+ 768, 768, 768, 848, 849, 768, 341, 852, 343, 341,
+ 852, 343, 768, 768, 768, 830, 830, 360, 768, 833,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 836, 836, 841, 841, 768, 768, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 768, 768, 768, 843, 843, 843,
+ 843, 768, 768, 847, 847, 768, 768, 768, 768, 427,
+
+ 852, 343, 852, 852, 852, 768, 768, 830, 830, 768,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 836, 836, 841, 841, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 768, 768, 768, 768, 843, 843, 843, 843, 768,
+ 856, 768, 768, 768, 852, 852, 852, 768, 768, 830,
+ 830, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 833, 836, 836, 841, 841, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 843, 843, 843, 768, 768, 768, 768,
+ 843, 843, 843, 843, 856, 768, 856, 768, 768, 768,
+ 768, 768, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 833, 833, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 768,
+ 768, 768, 768, 843, 843, 857, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 833, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 768, 768,
+ 768, 768, 843, 857, 768, 857, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 843, 843,
+
+ 843, 843, 843, 843, 843, 768, 768, 768, 768, 768,
+ 768, 843, 843, 843, 843, 843, 843, 843, 768, 768,
+ 768, 768, 768, 768, 843, 843, 843, 843, 843, 843,
+ 768, 768, 768, 768, 768, 768, 843, 843, 843, 843,
+ 768, 768, 768, 768, 768, 768, 843, 843, 843, 843,
+ 768, 768, 768, 768, 843, 843, 843, 768, 768, 843,
+ 843, 843, 843, 843, 843, 843, 843, 0, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768
+ } ;
+
+static yyconst short int yy_nxt[2775] =
+ { 0,
+ 40, 41, 42, 43, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 44, 44, 40, 40, 40, 40, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 40, 40, 40, 40, 45,
+ 46, 47, 40, 48, 40, 49, 40, 40, 40, 40,
+ 40, 40, 50, 40, 40, 40, 40, 40, 40, 40,
+ 40, 51, 51, 40, 40, 40, 40, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 40, 40, 40, 53, 54, 55, 56,
+ 767, 57, 70, 71, 58, 58, 58, 129, 130, 58,
+ 73, 70, 74, 129, 130, 59, 75, 87, 88, 89,
+ 60, 61, 87, 88, 89, 188, 96, 97, 224, 132,
+ 133, 210, 211, 96, 97, 404, 98, 134, 405, 99,
+ 99, 99, 99, 98, 213, 213, 99, 99, 99, 99,
+ 62, 58, 58, 63, 64, 65, 56, 252, 57, 66,
+ 40, 58, 58, 58, 439, 189, 58, 102, 103, 104,
+ 40, 252, 67, 102, 103, 104, 225, 60, 61, 275,
+
+ 68, 100, 214, 107, 108, 276, 109, 178, 100, 179,
+ 232, 105, 233, 107, 108, 572, 109, 105, 132, 133,
+ 180, 180, 180, 180, 265, 266, 134, 62, 58, 58,
+ 78, 78, 79, 80, 78, 78, 78, 78, 78, 78,
+ 81, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 82, 82, 78, 78, 78, 78, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 82, 82, 82, 82, 82, 83, 82, 82,
+ 82, 82, 82, 82, 84, 78, 78, 78, 90, 90,
+ 40, 90, 90, 90, 90, 90, 90, 90, 91, 90,
+
+ 91, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 92, 93, 93, 90, 90, 90, 90, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 90, 90, 90, 111, 112, 296, 111,
+ 112, 178, 766, 179, 181, 182, 183, 113, 265, 266,
+ 113, 185, 186, 187, 180, 180, 180, 180, 297, 114,
+ 115, 116, 114, 115, 116, 117, 117, 118, 119, 120,
+ 117, 117, 117, 121, 117, 117, 117, 117, 117, 122,
+ 117, 117, 117, 117, 117, 117, 117, 117, 123, 123,
+
+ 117, 117, 117, 117, 123, 123, 123, 123, 123, 123,
+ 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 123, 124, 123, 123, 123, 123, 123, 123, 125,
+ 126, 117, 127, 136, 137, 138, 136, 137, 138, 206,
+ 206, 207, 215, 215, 215, 215, 248, 248, 248, 248,
+ 268, 269, 268, 269, 300, 331, 332, 139, 301, 765,
+ 139, 140, 141, 142, 143, 140, 140, 140, 144, 140,
+ 140, 145, 140, 140, 140, 146, 140, 140, 140, 140,
+ 140, 140, 140, 140, 147, 147, 140, 140, 140, 140,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+
+ 147, 147, 147, 147, 147, 147, 147, 147, 148, 147,
+ 147, 147, 147, 147, 147, 149, 140, 140, 140, 150,
+ 151, 152, 153, 154, 150, 150, 150, 150, 150, 150,
+ 150, 150, 150, 150, 150, 155, 156, 150, 150, 150,
+ 157, 150, 150, 150, 150, 150, 150, 150, 150, 158,
+ 159, 160, 161, 162, 163, 164, 164, 165, 164, 164,
+ 166, 167, 168, 169, 170, 164, 171, 172, 164, 173,
+ 174, 175, 164, 176, 150, 150, 150, 191, 201, 202,
+ 203, 258, 213, 213, 204, 289, 213, 213, 213, 213,
+ 292, 290, 217, 218, 219, 383, 303, 275, 220, 259,
+
+ 192, 188, 193, 276, 193, 221, 304, 335, 336, 293,
+ 193, 222, 384, 193, 194, 195, 480, 193, 196, 223,
+ 214, 306, 481, 197, 214, 198, 214, 317, 317, 317,
+ 317, 307, 764, 205, 308, 181, 182, 183, 185, 186,
+ 187, 189, 321, 322, 323, 339, 340, 205, 321, 322,
+ 323, 387, 321, 322, 323, 388, 324, 324, 324, 324,
+ 342, 342, 324, 324, 324, 324, 324, 324, 324, 324,
+ 321, 322, 323, 201, 202, 203, 341, 344, 344, 204,
+ 380, 258, 339, 340, 324, 324, 324, 324, 325, 217,
+ 218, 219, 265, 266, 381, 220, 326, 439, 343, 259,
+
+ 265, 266, 221, 248, 248, 248, 248, 673, 222, 268,
+ 269, 268, 269, 327, 392, 402, 223, 409, 393, 440,
+ 410, 416, 417, 418, 403, 331, 332, 763, 205, 411,
+ 412, 317, 317, 317, 317, 419, 419, 419, 419, 721,
+ 413, 331, 332, 722, 205, 357, 357, 358, 359, 357,
+ 357, 357, 357, 357, 357, 360, 357, 357, 357, 357,
+ 357, 357, 357, 357, 357, 357, 357, 357, 360, 360,
+ 357, 357, 357, 357, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+
+ 357, 357, 357, 362, 363, 364, 365, 335, 336, 366,
+ 335, 336, 339, 340, 367, 212, 212, 762, 368, 493,
+ 494, 369, 761, 370, 417, 494, 371, 374, 374, 760,
+ 374, 374, 374, 374, 374, 374, 374, 375, 374, 374,
+ 374, 374, 374, 374, 374, 374, 374, 374, 374, 374,
+ 375, 375, 374, 374, 374, 374, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 374, 374, 374, 420, 322, 323, 427, 439,
+ 439, 428, 428, 439, 339, 340, 431, 431, 439, 324,
+
+ 324, 324, 324, 338, 439, 485, 339, 340, 486, 487,
+ 439, 441, 443, 439, 442, 420, 322, 323, 450, 552,
+ 759, 513, 493, 494, 516, 553, 444, 339, 340, 429,
+ 338, 338, 439, 338, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 338, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 430, 430, 339, 340, 445, 338, 338,
+ 430, 430, 430, 430, 430, 430, 430, 430, 430, 430,
+ 430, 430, 430, 430, 430, 430, 430, 430, 430, 430,
+ 430, 430, 430, 430, 430, 338, 338, 338, 432, 432,
+ 432, 432, 758, 439, 339, 340, 432, 757, 339, 340,
+
+ 495, 417, 418, 432, 432, 432, 432, 432, 432, 360,
+ 360, 439, 438, 360, 360, 360, 360, 360, 360, 448,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 439, 439, 360, 360, 360, 360, 439, 446,
+ 501, 501, 447, 504, 504, 416, 417, 418, 616, 617,
+ 339, 340, 638, 339, 340, 515, 439, 439, 449, 419,
+ 419, 419, 419, 514, 360, 360, 360, 375, 375, 580,
+ 375, 375, 375, 375, 375, 375, 375, 439, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 517, 439, 375, 375, 375, 375, 495, 417, 418, 439,
+
+ 439, 511, 439, 512, 439, 439, 339, 340, 209, 439,
+ 419, 419, 419, 419, 439, 519, 520, 581, 518, 522,
+ 566, 566, 375, 375, 375, 500, 500, 573, 521, 578,
+ 339, 340, 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 500, 500, 500, 500, 500, 502, 502, 502,
+ 502, 532, 439, 439, 439, 502, 439, 339, 340, 439,
+ 339, 340, 502, 502, 502, 502, 502, 502, 505, 505,
+ 505, 505, 439, 533, 582, 576, 505, 574, 579, 534,
+ 575, 439, 439, 505, 505, 505, 505, 505, 505, 567,
+
+ 567, 567, 567, 590, 339, 340, 338, 567, 577, 583,
+ 439, 439, 625, 591, 567, 567, 567, 567, 567, 567,
+ 439, 439, 624, 439, 439, 439, 439, 439, 439, 439,
+ 616, 617, 439, 623, 616, 617, 685, 686, 685, 686,
+ 756, 628, 626, 632, 708, 755, 634, 685, 686, 302,
+ 302, 627, 629, 754, 753, 630, 631, 633, 752, 751,
+ 750, 709, 669, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 72, 72, 72, 72, 72,
+
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+
+ 106, 106, 106, 106, 106, 106, 106, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 131,
+ 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+ 131, 131, 131, 131, 131, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 184, 184, 184,
+ 184, 749, 748, 184, 184, 184, 190, 190, 190, 190,
+
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 200, 200, 200, 200, 747, 746, 200, 200, 200,
+ 209, 745, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 212, 744, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 216, 216, 216, 743, 742, 216, 216, 216,
+ 227, 741, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 227, 227, 227, 229, 740, 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229, 229, 229,
+ 229, 229, 230, 739, 230, 230, 230, 230, 230, 230,
+
+ 230, 230, 230, 230, 230, 230, 230, 230, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 236, 738, 236, 236, 737, 236,
+ 236, 236, 736, 735, 236, 236, 734, 733, 732, 236,
+ 238, 238, 238, 238, 731, 730, 238, 238, 238, 242,
+ 729, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 246, 246, 246, 246, 728,
+ 727, 246, 246, 246, 251, 726, 251, 251, 251, 251,
+ 251, 251, 251, 251, 251, 251, 251, 251, 251, 251,
+ 254, 725, 254, 254, 254, 254, 254, 254, 254, 254,
+
+ 254, 724, 254, 254, 254, 254, 255, 723, 720, 719,
+ 255, 255, 255, 255, 718, 717, 255, 255, 257, 716,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 261, 261, 261, 261, 715, 714,
+ 261, 261, 261, 264, 264, 264, 264, 264, 264, 264,
+ 264, 264, 264, 264, 264, 264, 264, 264, 264, 267,
+ 267, 267, 267, 713, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 271, 712, 711, 271, 271,
+ 271, 271, 271, 271, 271, 710, 271, 271, 271, 271,
+ 271, 273, 707, 273, 273, 273, 273, 273, 273, 273,
+
+ 273, 273, 273, 273, 273, 273, 273, 274, 706, 274,
+ 274, 705, 274, 274, 274, 704, 703, 274, 274, 702,
+ 701, 700, 274, 279, 279, 279, 279, 699, 698, 279,
+ 279, 279, 284, 697, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 284, 284, 288, 288,
+ 696, 288, 288, 695, 694, 693, 288, 288, 315, 692,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 319, 691, 319, 319, 319, 319,
+ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
+ 320, 690, 320, 320, 320, 320, 320, 320, 320, 320,
+
+ 320, 320, 320, 320, 320, 320, 328, 328, 689, 688,
+ 328, 328, 328, 329, 329, 687, 683, 329, 329, 329,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 334, 334, 334, 334,
+ 334, 334, 334, 334, 334, 334, 334, 334, 334, 334,
+ 334, 334, 338, 682, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 681, 338, 338, 338, 338, 209, 680,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 345, 345, 679, 678, 677, 676,
+ 345, 346, 346, 346, 346, 675, 674, 346, 346, 346,
+
+ 346, 351, 673, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 227, 672, 227,
+ 227, 227, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 229, 671, 229, 229, 229, 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229, 229, 230,
+ 670, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 353, 668, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 354, 667, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 354, 354, 234, 234, 234,
+
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 236, 666, 236, 236, 665, 236, 236,
+ 236, 664, 663, 236, 236, 662, 661, 660, 236, 238,
+ 238, 238, 238, 659, 658, 238, 238, 238, 242, 657,
+ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 246, 246, 246, 246, 656, 655,
+ 246, 246, 246, 361, 361, 654, 653, 652, 361, 361,
+ 255, 651, 650, 649, 255, 255, 255, 255, 648, 647,
+ 255, 255, 257, 646, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 261, 261,
+
+ 261, 261, 645, 644, 261, 261, 261, 264, 264, 264,
+ 264, 264, 264, 264, 264, 264, 264, 264, 264, 264,
+ 264, 264, 264, 267, 267, 267, 267, 643, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 267, 271,
+ 642, 641, 271, 271, 271, 271, 271, 271, 271, 640,
+ 271, 271, 271, 271, 271, 274, 639, 274, 274, 638,
+ 274, 274, 274, 637, 636, 274, 274, 635, 622, 621,
+ 274, 279, 279, 279, 279, 620, 619, 279, 279, 279,
+ 284, 618, 284, 284, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 288, 288, 560, 288,
+
+ 288, 614, 613, 612, 288, 288, 315, 611, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 319, 610, 319, 319, 319, 319, 319, 319,
+ 319, 319, 319, 319, 319, 319, 319, 319, 320, 609,
+ 320, 320, 320, 320, 320, 320, 320, 320, 320, 320,
+ 320, 320, 320, 320, 415, 415, 415, 415, 415, 415,
+ 415, 415, 415, 415, 415, 415, 415, 415, 415, 415,
+ 424, 424, 424, 424, 608, 607, 424, 424, 424, 425,
+ 425, 425, 425, 606, 605, 425, 425, 425, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 334, 334, 334, 334, 334, 334,
+ 334, 334, 334, 334, 334, 334, 334, 334, 334, 334,
+ 338, 604, 338, 338, 338, 338, 338, 338, 338, 338,
+ 338, 603, 338, 338, 338, 338, 433, 433, 602, 601,
+ 600, 599, 433, 346, 346, 346, 346, 598, 597, 346,
+ 346, 346, 346, 351, 596, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 351, 351, 615,
+ 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+ 615, 615, 615, 615, 615, 684, 684, 684, 684, 684,
+ 684, 684, 684, 684, 684, 684, 684, 684, 684, 684,
+
+ 684, 595, 594, 593, 592, 589, 588, 587, 586, 585,
+ 584, 571, 570, 569, 568, 565, 564, 563, 562, 561,
+ 560, 559, 558, 557, 556, 555, 554, 551, 550, 549,
+ 548, 547, 546, 545, 544, 543, 542, 541, 540, 539,
+ 538, 537, 536, 535, 531, 530, 529, 528, 527, 526,
+ 525, 524, 523, 510, 509, 508, 507, 506, 503, 499,
+ 498, 497, 496, 492, 491, 490, 489, 488, 484, 483,
+ 482, 479, 478, 477, 476, 475, 474, 473, 472, 471,
+ 470, 469, 468, 467, 466, 465, 464, 463, 462, 461,
+ 460, 459, 458, 457, 456, 455, 454, 453, 452, 451,
+
+ 439, 437, 436, 435, 434, 347, 426, 423, 422, 421,
+ 322, 414, 316, 408, 407, 406, 401, 400, 399, 398,
+ 397, 396, 395, 394, 391, 390, 389, 386, 385, 382,
+ 379, 378, 285, 282, 377, 376, 278, 373, 372, 243,
+ 356, 355, 235, 231, 352, 350, 349, 348, 218, 347,
+ 337, 206, 333, 202, 318, 186, 182, 316, 314, 313,
+ 312, 311, 310, 309, 305, 299, 298, 295, 294, 291,
+ 287, 286, 285, 283, 282, 281, 280, 260, 278, 277,
+ 272, 270, 263, 262, 260, 256, 250, 253, 250, 249,
+ 247, 245, 244, 243, 241, 240, 239, 237, 235, 228,
+
+ 231, 228, 226, 218, 208, 202, 199, 186, 182, 768,
+ 94, 94, 85, 77, 77, 39, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768
+ } ;
+
+static yyconst short int yy_chk[2775] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 765, 3, 5, 5, 3, 3, 3, 27, 27, 3,
+ 6, 6, 6, 28, 28, 3, 6, 11, 11, 11,
+ 3, 3, 12, 12, 12, 48, 17, 17, 66, 29,
+ 29, 60, 60, 18, 18, 310, 17, 29, 310, 17,
+ 17, 17, 17, 18, 61, 61, 18, 18, 18, 18,
+ 3, 3, 3, 4, 4, 4, 4, 109, 4, 4,
+ 21, 4, 4, 4, 511, 48, 4, 19, 19, 19,
+ 22, 109, 4, 20, 20, 20, 66, 4, 4, 141,
+
+ 4, 17, 61, 21, 21, 141, 21, 37, 18, 37,
+ 75, 19, 75, 22, 22, 511, 22, 20, 30, 30,
+ 37, 37, 37, 37, 128, 128, 30, 4, 4, 4,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 23, 23, 163, 24,
+ 24, 38, 764, 38, 41, 41, 41, 23, 130, 130,
+ 24, 45, 45, 45, 38, 38, 38, 38, 163, 23,
+ 23, 23, 24, 24, 24, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 31, 31, 31, 32, 32, 32, 57,
+ 57, 57, 62, 62, 62, 62, 99, 99, 99, 99,
+ 131, 131, 133, 133, 167, 198, 198, 31, 167, 763,
+ 32, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 49, 53, 53,
+ 53, 121, 105, 105, 53, 158, 108, 108, 115, 115,
+ 160, 158, 63, 63, 63, 291, 168, 275, 63, 121,
+
+ 49, 188, 49, 275, 49, 63, 168, 205, 205, 160,
+ 49, 63, 291, 49, 49, 49, 405, 49, 49, 63,
+ 105, 170, 405, 49, 108, 49, 115, 180, 180, 180,
+ 180, 170, 762, 53, 170, 181, 181, 181, 185, 185,
+ 185, 188, 192, 192, 192, 209, 209, 63, 193, 193,
+ 193, 294, 194, 194, 194, 294, 192, 192, 192, 192,
+ 211, 211, 193, 193, 193, 193, 194, 194, 194, 194,
+ 195, 195, 195, 201, 201, 201, 210, 213, 213, 201,
+ 289, 257, 210, 210, 195, 195, 195, 195, 192, 217,
+ 217, 217, 264, 264, 289, 217, 194, 362, 211, 257,
+
+ 266, 266, 217, 248, 248, 248, 248, 761, 217, 267,
+ 267, 269, 269, 195, 298, 309, 217, 314, 298, 362,
+ 314, 321, 321, 321, 309, 330, 330, 760, 201, 314,
+ 314, 317, 317, 317, 317, 321, 321, 321, 321, 708,
+ 314, 332, 332, 708, 217, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+
+ 241, 241, 241, 250, 250, 250, 250, 334, 334, 250,
+ 336, 336, 338, 338, 250, 344, 344, 757, 250, 415,
+ 415, 250, 756, 250, 418, 418, 250, 278, 278, 755,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 324, 324, 324, 339, 363,
+ 364, 340, 340, 365, 339, 339, 342, 342, 366, 324,
+
+ 324, 324, 324, 340, 371, 409, 342, 342, 409, 409,
+ 441, 363, 365, 444, 364, 420, 420, 420, 371, 485,
+ 754, 441, 494, 494, 444, 485, 366, 504, 504, 340,
+ 341, 341, 367, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 367, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 343, 343,
+ 343, 343, 752, 369, 505, 505, 343, 750, 343, 343,
+
+ 495, 495, 495, 343, 343, 343, 343, 343, 343, 360,
+ 360, 368, 360, 360, 360, 360, 360, 360, 360, 369,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 370, 442, 360, 360, 360, 360, 443, 368,
+ 428, 428, 368, 431, 431, 416, 416, 416, 561, 561,
+ 428, 428, 749, 431, 431, 443, 519, 445, 370, 416,
+ 416, 416, 416, 442, 360, 360, 360, 375, 375, 519,
+ 375, 375, 375, 375, 375, 375, 375, 440, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 445, 447, 375, 375, 375, 375, 419, 419, 419, 446,
+
+ 450, 440, 449, 440, 520, 448, 503, 503, 503, 512,
+ 419, 419, 419, 419, 517, 447, 448, 520, 446, 450,
+ 501, 501, 375, 375, 375, 427, 427, 512, 449, 517,
+ 501, 501, 427, 427, 427, 427, 427, 427, 427, 427,
+ 427, 427, 427, 427, 427, 427, 427, 427, 427, 427,
+ 427, 427, 427, 427, 427, 427, 427, 429, 429, 429,
+ 429, 462, 514, 513, 518, 429, 515, 566, 566, 521,
+ 567, 567, 429, 429, 429, 429, 429, 429, 432, 432,
+ 432, 432, 516, 462, 521, 515, 432, 513, 518, 462,
+ 514, 574, 522, 432, 432, 432, 432, 432, 432, 502,
+
+ 502, 502, 502, 532, 565, 565, 565, 502, 516, 522,
+ 572, 573, 574, 532, 502, 502, 502, 502, 502, 502,
+ 575, 576, 573, 577, 578, 579, 580, 583, 581, 582,
+ 615, 615, 634, 572, 617, 617, 656, 656, 684, 684,
+ 748, 577, 575, 581, 681, 747, 583, 686, 686, 810,
+ 810, 576, 578, 745, 744, 579, 580, 582, 743, 742,
+ 740, 681, 634, 769, 769, 769, 769, 769, 769, 769,
+ 769, 769, 769, 769, 769, 769, 769, 769, 769, 770,
+ 770, 770, 770, 770, 770, 770, 770, 770, 770, 770,
+ 770, 770, 770, 770, 770, 771, 771, 771, 771, 771,
+
+ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771,
+ 771, 772, 772, 772, 772, 772, 772, 772, 772, 772,
+ 772, 772, 772, 772, 772, 772, 772, 773, 773, 773,
+ 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
+ 773, 773, 773, 774, 774, 774, 774, 774, 774, 774,
+ 774, 774, 774, 774, 774, 774, 774, 774, 774, 775,
+ 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
+ 775, 775, 775, 775, 775, 776, 776, 776, 776, 776,
+ 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 777, 777, 777, 777, 777, 777, 777, 777, 777,
+
+ 777, 777, 777, 777, 777, 777, 777, 778, 778, 778,
+ 778, 778, 778, 778, 778, 778, 778, 778, 778, 778,
+ 778, 778, 778, 779, 779, 779, 779, 779, 779, 779,
+ 779, 779, 779, 779, 779, 779, 779, 779, 779, 780,
+ 780, 780, 780, 780, 780, 780, 780, 780, 780, 780,
+ 780, 780, 780, 780, 780, 781, 781, 781, 781, 781,
+ 781, 781, 781, 781, 781, 781, 781, 781, 781, 781,
+ 781, 782, 782, 782, 782, 782, 782, 782, 782, 782,
+ 782, 782, 782, 782, 782, 782, 782, 783, 783, 783,
+ 783, 739, 738, 783, 783, 783, 784, 784, 784, 784,
+
+ 784, 784, 784, 784, 784, 784, 784, 784, 784, 784,
+ 784, 785, 785, 785, 785, 737, 736, 785, 785, 785,
+ 786, 735, 786, 786, 786, 786, 786, 786, 786, 786,
+ 786, 786, 786, 786, 786, 786, 787, 734, 787, 787,
+ 787, 787, 787, 787, 787, 787, 787, 787, 787, 787,
+ 787, 787, 788, 788, 788, 733, 732, 788, 788, 788,
+ 789, 731, 789, 789, 789, 789, 789, 789, 789, 789,
+ 789, 789, 789, 789, 789, 789, 790, 729, 790, 790,
+ 790, 790, 790, 790, 790, 790, 790, 790, 790, 790,
+ 790, 790, 791, 727, 791, 791, 791, 791, 791, 791,
+
+ 791, 791, 791, 791, 791, 791, 791, 791, 792, 792,
+ 792, 792, 792, 792, 792, 792, 792, 792, 792, 792,
+ 792, 792, 792, 792, 793, 726, 793, 793, 725, 793,
+ 793, 793, 724, 723, 793, 793, 722, 721, 720, 793,
+ 794, 794, 794, 794, 719, 718, 794, 794, 794, 795,
+ 717, 795, 795, 795, 795, 795, 795, 795, 795, 795,
+ 795, 795, 795, 795, 795, 796, 796, 796, 796, 715,
+ 714, 796, 796, 796, 797, 713, 797, 797, 797, 797,
+ 797, 797, 797, 797, 797, 797, 797, 797, 797, 797,
+ 798, 712, 798, 798, 798, 798, 798, 798, 798, 798,
+
+ 798, 710, 798, 798, 798, 798, 799, 709, 707, 706,
+ 799, 799, 799, 799, 705, 704, 799, 799, 800, 703,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 801, 801, 801, 801, 702, 701,
+ 801, 801, 801, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 803,
+ 803, 803, 803, 700, 803, 803, 803, 803, 803, 803,
+ 803, 803, 803, 803, 803, 804, 699, 698, 804, 804,
+ 804, 804, 804, 804, 804, 682, 804, 804, 804, 804,
+ 804, 805, 680, 805, 805, 805, 805, 805, 805, 805,
+
+ 805, 805, 805, 805, 805, 805, 805, 806, 679, 806,
+ 806, 678, 806, 806, 806, 677, 675, 806, 806, 674,
+ 672, 671, 806, 807, 807, 807, 807, 670, 669, 807,
+ 807, 807, 808, 668, 808, 808, 808, 808, 808, 808,
+ 808, 808, 808, 808, 808, 808, 808, 808, 809, 809,
+ 667, 809, 809, 666, 665, 664, 809, 809, 811, 663,
+ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+ 811, 811, 811, 811, 812, 662, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 813, 661, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 814, 814, 660, 659,
+ 814, 814, 814, 815, 815, 658, 655, 815, 815, 815,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 817, 817, 817, 817,
+ 817, 817, 817, 817, 817, 817, 817, 817, 817, 817,
+ 817, 817, 818, 653, 818, 818, 818, 818, 818, 818,
+ 818, 818, 818, 652, 818, 818, 818, 818, 819, 651,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 820, 820, 650, 646, 644, 643,
+ 820, 821, 821, 821, 821, 642, 641, 821, 821, 821,
+
+ 821, 822, 639, 822, 822, 822, 822, 822, 822, 822,
+ 822, 822, 822, 822, 822, 822, 822, 823, 637, 823,
+ 823, 823, 823, 823, 823, 823, 823, 823, 823, 823,
+ 823, 823, 823, 824, 636, 824, 824, 824, 824, 824,
+ 824, 824, 824, 824, 824, 824, 824, 824, 824, 825,
+ 635, 825, 825, 825, 825, 825, 825, 825, 825, 825,
+ 825, 825, 825, 825, 825, 826, 633, 826, 826, 826,
+ 826, 826, 826, 826, 826, 826, 826, 826, 826, 826,
+ 826, 827, 632, 827, 827, 827, 827, 827, 827, 827,
+ 827, 827, 827, 827, 827, 827, 827, 828, 828, 828,
+
+ 828, 828, 828, 828, 828, 828, 828, 828, 828, 828,
+ 828, 828, 828, 829, 631, 829, 829, 630, 829, 829,
+ 829, 629, 628, 829, 829, 627, 626, 625, 829, 830,
+ 830, 830, 830, 624, 623, 830, 830, 830, 831, 621,
+ 831, 831, 831, 831, 831, 831, 831, 831, 831, 831,
+ 831, 831, 831, 831, 832, 832, 832, 832, 619, 612,
+ 832, 832, 832, 833, 833, 611, 610, 609, 833, 833,
+ 834, 608, 607, 606, 834, 834, 834, 834, 604, 601,
+ 834, 834, 835, 600, 835, 835, 835, 835, 835, 835,
+ 835, 835, 835, 835, 835, 835, 835, 835, 836, 836,
+
+ 836, 836, 599, 598, 836, 836, 836, 837, 837, 837,
+ 837, 837, 837, 837, 837, 837, 837, 837, 837, 837,
+ 837, 837, 837, 838, 838, 838, 838, 597, 838, 838,
+ 838, 838, 838, 838, 838, 838, 838, 838, 838, 839,
+ 596, 595, 839, 839, 839, 839, 839, 839, 839, 594,
+ 839, 839, 839, 839, 839, 840, 593, 840, 840, 592,
+ 840, 840, 840, 591, 590, 840, 840, 588, 569, 568,
+ 840, 841, 841, 841, 841, 564, 563, 841, 841, 841,
+ 842, 562, 842, 842, 842, 842, 842, 842, 842, 842,
+ 842, 842, 842, 842, 842, 842, 843, 843, 560, 843,
+
+ 843, 559, 558, 557, 843, 843, 844, 556, 844, 844,
+ 844, 844, 844, 844, 844, 844, 844, 844, 844, 844,
+ 844, 844, 845, 555, 845, 845, 845, 845, 845, 845,
+ 845, 845, 845, 845, 845, 845, 845, 845, 846, 554,
+ 846, 846, 846, 846, 846, 846, 846, 846, 846, 846,
+ 846, 846, 846, 846, 847, 847, 847, 847, 847, 847,
+ 847, 847, 847, 847, 847, 847, 847, 847, 847, 847,
+ 848, 848, 848, 848, 553, 552, 848, 848, 848, 849,
+ 849, 849, 849, 551, 549, 849, 849, 849, 850, 850,
+ 850, 850, 850, 850, 850, 850, 850, 850, 850, 850,
+
+ 850, 850, 850, 850, 851, 851, 851, 851, 851, 851,
+ 851, 851, 851, 851, 851, 851, 851, 851, 851, 851,
+ 852, 548, 852, 852, 852, 852, 852, 852, 852, 852,
+ 852, 546, 852, 852, 852, 852, 853, 853, 545, 544,
+ 543, 542, 853, 854, 854, 854, 854, 541, 540, 854,
+ 854, 854, 854, 855, 539, 855, 855, 855, 855, 855,
+ 855, 855, 855, 855, 855, 855, 855, 855, 855, 856,
+ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856,
+ 856, 856, 856, 856, 856, 857, 857, 857, 857, 857,
+ 857, 857, 857, 857, 857, 857, 857, 857, 857, 857,
+
+ 857, 538, 536, 534, 533, 530, 528, 526, 525, 524,
+ 523, 509, 508, 507, 506, 500, 499, 498, 497, 496,
+ 492, 491, 490, 489, 488, 487, 486, 483, 482, 481,
+ 480, 479, 478, 476, 475, 474, 473, 472, 471, 469,
+ 468, 467, 464, 463, 461, 460, 459, 458, 457, 454,
+ 453, 452, 451, 439, 437, 436, 435, 434, 430, 426,
+ 423, 422, 421, 414, 413, 412, 411, 410, 408, 407,
+ 406, 404, 403, 402, 401, 400, 399, 398, 397, 396,
+ 395, 394, 393, 392, 391, 390, 388, 387, 386, 384,
+ 383, 382, 381, 380, 379, 378, 377, 376, 373, 372,
+
+ 361, 356, 355, 352, 350, 346, 337, 327, 326, 325,
+ 323, 318, 315, 313, 312, 311, 308, 307, 306, 305,
+ 303, 301, 300, 299, 297, 296, 295, 293, 292, 290,
+ 287, 286, 284, 282, 281, 280, 276, 263, 262, 243,
+ 240, 239, 234, 231, 226, 222, 221, 220, 219, 216,
+ 208, 207, 204, 203, 189, 187, 183, 179, 176, 175,
+ 174, 173, 172, 171, 169, 166, 165, 162, 161, 159,
+ 156, 155, 154, 153, 151, 149, 148, 146, 144, 143,
+ 137, 134, 125, 124, 122, 119, 114, 112, 107, 103,
+ 97, 92, 89, 87, 85, 84, 83, 80, 76, 74,
+
+ 73, 71, 67, 65, 59, 55, 50, 47, 43, 39,
+ 16, 15, 10, 8, 7, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "scan.l"
+#define INITIAL 0
+/* scan.l - scanner for flex input */
+#line 4 "scan.l"
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/initscan.c,v 1.3 1996/06/19 20:47:13 nate Exp $ */
+
+#include "flexdef.h"
+#include "parse.h"
+
+#define ACTION_ECHO add_action( yytext )
+#define ACTION_IFDEF(def, should_define) \
+ { \
+ if ( should_define ) \
+ action_define( def, 1 ); \
+ }
+
+#define MARK_END_OF_PROLOG mark_prolog();
+
+#define YY_DECL \
+ int flexscan()
+
+#define RETURNCHAR \
+ yylval = (unsigned char) yytext[0]; \
+ return CHAR;
+
+#define RETURNNAME \
+ strcpy( nmstr, yytext ); \
+ return NAME;
+
+#define PUT_BACK_STRING(str, start) \
+ for ( i = strlen( str ) - 1; i >= start; --i ) \
+ unput((str)[i])
+
+#define CHECK_REJECT(str) \
+ if ( all_upper( str ) ) \
+ reject = true;
+
+#define CHECK_YYMORE(str) \
+ if ( all_lower( str ) ) \
+ yymore_used = true;
+#define YY_STACK_USED 1
+#define YY_NO_TOP_STATE 1
+#define SECT2 1
+#define SECT2PROLOG 2
+#define SECT3 3
+#define CODEBLOCK 4
+#define PICKUPDEF 5
+#define SC 6
+#define CARETISBOL 7
+#define NUM 8
+#define QUOTE 9
+
+#define FIRSTCCL 10
+#define CCL 11
+#define ACTION 12
+#define RECOVER 13
+#define COMMENT 14
+#define ACTION_STRING 15
+#define PERCENT_BRACE_ACTION 16
+
+#define OPTION 17
+#define LINEDIR 18
+
+#line 1333 "scan.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ yy_current_buffer->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 94 "scan.l"
+
+ static int bracelevel, didadef, indented_code;
+ static int doing_rule_action = false;
+ static int option_sense;
+
+ int doing_codeblock = false;
+ int i;
+ Char nmdef[MAXLINE], myesc();
+
+
+#line 1498 "scan.c"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 2716 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+
+case 1:
+YY_RULE_SETUP
+#line 105 "scan.l"
+indented_code = true; BEGIN(CODEBLOCK);
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 106 "scan.l"
+ACTION_ECHO; yy_push_state( COMMENT );
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 107 "scan.l"
+yy_push_state( LINEDIR );
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 108 "scan.l"
+return SCDECL;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 109 "scan.l"
+return XSCDECL;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 110 "scan.l"
+{
+ ++linenum;
+ line_directive_out( (FILE *) 0, 1 );
+ indented_code = false;
+ BEGIN(CODEBLOCK);
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 117 "scan.l"
+/* discard */
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 119 "scan.l"
+{
+ sectnum = 2;
+ bracelevel = 0;
+ mark_defs1();
+ line_directive_out( (FILE *) 0, 1 );
+ BEGIN(SECT2PROLOG);
+ return SECTEND;
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 128 "scan.l"
+yytext_is_array = false; ++linenum;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 129 "scan.l"
+yytext_is_array = true; ++linenum;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 131 "scan.l"
+BEGIN(OPTION); return OPTION_OP;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 133 "scan.l"
+++linenum; /* ignore */
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 134 "scan.l"
+++linenum; /* ignore */
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 136 "scan.l"
+synerr( _( "unrecognized '%' directive" ) );
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 138 "scan.l"
+{
+ strcpy( nmstr, yytext );
+ didadef = false;
+ BEGIN(PICKUPDEF);
+ }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 144 "scan.l"
+RETURNNAME;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 145 "scan.l"
+++linenum; /* allows blank lines in section 1 */
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 146 "scan.l"
+ACTION_ECHO; ++linenum; /* maybe end of comment line */
+ YY_BREAK
+
+
+case 19:
+YY_RULE_SETUP
+#line 151 "scan.l"
+ACTION_ECHO; yy_pop_state();
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 152 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 153 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 154 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+
+
+case 23:
+YY_RULE_SETUP
+#line 158 "scan.l"
+yy_pop_state();
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 159 "scan.l"
+linenum = myctoi( yytext );
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 161 "scan.l"
+{
+ flex_free( (void *) infilename );
+ infilename = copy_string( yytext + 1 );
+ infilename[strlen( infilename ) - 1] = '\0';
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 166 "scan.l"
+/* ignore spurious characters */
+ YY_BREAK
+
+
+case 27:
+YY_RULE_SETUP
+#line 170 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 172 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 174 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( indented_code )
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+
+case 30:
+YY_RULE_SETUP
+#line 184 "scan.l"
+/* separates name and definition */
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 186 "scan.l"
+{
+ strcpy( (char *) nmdef, yytext );
+
+ /* Skip trailing whitespace. */
+ for ( i = strlen( (char *) nmdef ) - 1;
+ i >= 0 && (nmdef[i] == ' ' || nmdef[i] == '\t');
+ --i )
+ ;
+
+ nmdef[i + 1] = '\0';
+
+ ndinstal( nmstr, nmdef );
+ didadef = true;
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 201 "scan.l"
+{
+ if ( ! didadef )
+ synerr( _( "incomplete name definition" ) );
+ BEGIN(INITIAL);
+ ++linenum;
+ }
+ YY_BREAK
+
+
+case 33:
+YY_RULE_SETUP
+#line 211 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 212 "scan.l"
+option_sense = true;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 214 "scan.l"
+return '=';
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 216 "scan.l"
+option_sense = ! option_sense;
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 218 "scan.l"
+csize = option_sense ? 128 : 256;
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 219 "scan.l"
+csize = option_sense ? 256 : 128;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 221 "scan.l"
+long_align = option_sense;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 222 "scan.l"
+{
+ action_define( "YY_ALWAYS_INTERACTIVE", option_sense );
+ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 225 "scan.l"
+yytext_is_array = option_sense;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 226 "scan.l"
+backing_up_report = option_sense;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 227 "scan.l"
+interactive = ! option_sense;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 228 "scan.l"
+C_plus_plus = option_sense;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 229 "scan.l"
+caseins = ! option_sense;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 230 "scan.l"
+caseins = option_sense;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 231 "scan.l"
+ddebug = option_sense;
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 232 "scan.l"
+spprdflt = ! option_sense;
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 233 "scan.l"
+useecs = option_sense;
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 234 "scan.l"
+{
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 238 "scan.l"
+{
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 242 "scan.l"
+ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 243 "scan.l"
+interactive = option_sense;
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 244 "scan.l"
+lex_compat = option_sense;
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 245 "scan.l"
+{
+ action_define( "YY_MAIN", option_sense );
+ do_yywrap = ! option_sense;
+ }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 249 "scan.l"
+usemecs = option_sense;
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 250 "scan.l"
+{
+ action_define( "YY_NEVER_INTERACTIVE", option_sense );
+ }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 253 "scan.l"
+performance_report += option_sense ? 1 : -1;
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 254 "scan.l"
+yytext_is_array = ! option_sense;
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 255 "scan.l"
+use_read = option_sense;
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 256 "scan.l"
+reject_really_used = option_sense;
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 257 "scan.l"
+action_define( "YY_STACK_USED", option_sense );
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 258 "scan.l"
+do_stdinit = option_sense;
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 259 "scan.l"
+use_stdout = option_sense;
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 260 "scan.l"
+ACTION_IFDEF("YY_NO_UNPUT", ! option_sense);
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 261 "scan.l"
+printstats = option_sense;
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 262 "scan.l"
+nowarn = ! option_sense;
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 263 "scan.l"
+do_yylineno = option_sense;
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 264 "scan.l"
+yymore_really_used = option_sense;
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 265 "scan.l"
+do_yywrap = option_sense;
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 267 "scan.l"
+ACTION_IFDEF("YY_NO_PUSH_STATE", ! option_sense);
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 268 "scan.l"
+ACTION_IFDEF("YY_NO_POP_STATE", ! option_sense);
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 269 "scan.l"
+ACTION_IFDEF("YY_NO_TOP_STATE", ! option_sense);
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 271 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_BUFFER", ! option_sense);
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 272 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_BYTES", ! option_sense);
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 273 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_STRING", ! option_sense);
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 275 "scan.l"
+return OPT_OUTFILE;
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 276 "scan.l"
+return OPT_PREFIX;
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 277 "scan.l"
+return OPT_YYCLASS;
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 279 "scan.l"
+{
+ strcpy( nmstr, yytext + 1 );
+ nmstr[strlen( nmstr ) - 1] = '\0';
+ return NAME;
+ }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 285 "scan.l"
+{
+ format_synerr( _( "unrecognized %%option: %s" ),
+ yytext );
+ BEGIN(RECOVER);
+ }
+ YY_BREAK
+
+case 82:
+YY_RULE_SETUP
+#line 292 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+
+case 83:
+YY_RULE_SETUP
+#line 296 "scan.l"
+++bracelevel; yyless( 2 ); /* eat only %{ */
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 297 "scan.l"
+--bracelevel; yyless( 2 ); /* eat only %} */
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 299 "scan.l"
+ACTION_ECHO; /* indented code in prolog */
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 301 "scan.l"
+{ /* non-indented code */
+ if ( bracelevel <= 0 )
+ { /* not in %{ ... %} */
+ yyless( 0 ); /* put it all back */
+ yy_set_bol( 1 );
+ mark_prolog();
+ BEGIN(SECT2);
+ }
+ else
+ ACTION_ECHO;
+ }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 313 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 314 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case YY_STATE_EOF(SECT2PROLOG):
+#line 316 "scan.l"
+{
+ mark_prolog();
+ sectnum = 0;
+ yyterminate(); /* to stop the parser */
+ }
+ YY_BREAK
+
+
+case 89:
+YY_RULE_SETUP
+#line 324 "scan.l"
+++linenum; /* allow blank lines in section 2 */
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 326 "scan.l"
+{
+ indented_code = false;
+ doing_codeblock = true;
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+ }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 333 "scan.l"
+BEGIN(SC); return '<';
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 334 "scan.l"
+return '^';
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 335 "scan.l"
+BEGIN(QUOTE); return '"';
+ YY_BREAK
+case 94:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 336 "scan.l"
+BEGIN(NUM); return '{';
+ YY_BREAK
+case 95:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 337 "scan.l"
+return '$';
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 339 "scan.l"
+{
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 350 "scan.l"
+continued_action = true; ++linenum; return '\n';
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 352 "scan.l"
+{
+ yyless( yyleng - 2 ); /* put back '/', '*' */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 359 "scan.l"
+/* allow indented rules */
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 361 "scan.l"
+{
+ /* This rule is separate from the one below because
+ * otherwise we get variable trailing context, so
+ * we can't build the scanner using -{f,F}.
+ */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 378 "scan.l"
+{
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ unput( '\n' ); /* so <ACTION> sees it */
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 102:
+#line 393 "scan.l"
+case 103:
+YY_RULE_SETUP
+#line 393 "scan.l"
+return EOF_OP;
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 395 "scan.l"
+{
+ sectnum = 3;
+ BEGIN(SECT3);
+ yyterminate(); /* to stop the parser */
+ }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 401 "scan.l"
+{
+ int cclval;
+
+ strcpy( nmstr, yytext );
+
+ /* Check to see if we've already encountered this
+ * ccl.
+ */
+ if ( (cclval = ccllookup( (Char *) nmstr )) != 0 )
+ {
+ if ( input() != ']' )
+ synerr( _( "bad character class" ) );
+
+ yylval = cclval;
+ ++cclreuse;
+ return PREVCCL;
+ }
+ else
+ {
+ /* We fudge a bit. We know that this ccl will
+ * soon be numbered as lastccl + 1 by cclinit.
+ */
+ cclinstal( (Char *) nmstr, lastccl + 1 );
+
+ /* Push back everything but the leading bracket
+ * so the ccl can be rescanned.
+ */
+ yyless( 1 );
+
+ BEGIN(FIRSTCCL);
+ return '[';
+ }
+ }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 435 "scan.l"
+{
+ register Char *nmdefptr;
+ Char *ndlookup();
+
+ strcpy( nmstr, yytext + 1 );
+ nmstr[yyleng - 2] = '\0'; /* chop trailing brace */
+
+ if ( (nmdefptr = ndlookup( nmstr )) == 0 )
+ format_synerr(
+ _( "undefined definition {%s}" ),
+ nmstr );
+
+ else
+ { /* push back name surrounded by ()'s */
+ int len = strlen( (char *) nmdefptr );
+
+ if ( lex_compat || nmdefptr[0] == '^' ||
+ (len > 0 && nmdefptr[len - 1] == '$') )
+ { /* don't use ()'s after all */
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+
+ if ( nmdefptr[0] == '^' )
+ BEGIN(CARETISBOL);
+ }
+
+ else
+ {
+ unput(')');
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+ unput('(');
+ }
+ }
+ }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 469 "scan.l"
+return (unsigned char) yytext[0];
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 470 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+
+
+case 109:
+YY_RULE_SETUP
+#line 475 "scan.l"
+return (unsigned char) yytext[0];
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 476 "scan.l"
+BEGIN(SECT2); return '>';
+ YY_BREAK
+case 111:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 477 "scan.l"
+BEGIN(CARETISBOL); return '>';
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 478 "scan.l"
+RETURNNAME;
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 479 "scan.l"
+{
+ format_synerr( _( "bad <start condition>: %s" ),
+ yytext );
+ }
+ YY_BREAK
+
+case 114:
+YY_RULE_SETUP
+#line 485 "scan.l"
+BEGIN(SECT2); return '^';
+ YY_BREAK
+
+case 115:
+YY_RULE_SETUP
+#line 489 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 490 "scan.l"
+BEGIN(SECT2); return '"';
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 492 "scan.l"
+{
+ synerr( _( "missing quote" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '"';
+ }
+ YY_BREAK
+
+
+case 118:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 502 "scan.l"
+BEGIN(CCL); return '^';
+ YY_BREAK
+case 119:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 503 "scan.l"
+return '^';
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 504 "scan.l"
+BEGIN(CCL); RETURNCHAR;
+ YY_BREAK
+
+
+case 121:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 508 "scan.l"
+return '-';
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 509 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 510 "scan.l"
+BEGIN(SECT2); return ']';
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 511 "scan.l"
+{
+ synerr( _( "bad character class" ) );
+ BEGIN(SECT2);
+ return ']';
+ }
+ YY_BREAK
+
+
+case 125:
+YY_RULE_SETUP
+#line 519 "scan.l"
+BEGIN(CCL); return CCE_ALNUM;
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 520 "scan.l"
+BEGIN(CCL); return CCE_ALPHA;
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 521 "scan.l"
+BEGIN(CCL); return CCE_BLANK;
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 522 "scan.l"
+BEGIN(CCL); return CCE_CNTRL;
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 523 "scan.l"
+BEGIN(CCL); return CCE_DIGIT;
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 524 "scan.l"
+BEGIN(CCL); return CCE_GRAPH;
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 525 "scan.l"
+BEGIN(CCL); return CCE_LOWER;
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 526 "scan.l"
+BEGIN(CCL); return CCE_PRINT;
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 527 "scan.l"
+BEGIN(CCL); return CCE_PUNCT;
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 528 "scan.l"
+BEGIN(CCL); return CCE_SPACE;
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 529 "scan.l"
+BEGIN(CCL); return CCE_UPPER;
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 530 "scan.l"
+BEGIN(CCL); return CCE_XDIGIT;
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 531 "scan.l"
+{
+ format_synerr(
+ _( "bad character class expression: %s" ),
+ yytext );
+ BEGIN(CCL); return CCE_ALNUM;
+ }
+ YY_BREAK
+
+
+case 138:
+YY_RULE_SETUP
+#line 540 "scan.l"
+{
+ yylval = myctoi( yytext );
+ return NUMBER;
+ }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 545 "scan.l"
+return ',';
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 546 "scan.l"
+BEGIN(SECT2); return '}';
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 548 "scan.l"
+{
+ synerr( _( "bad character inside {}'s" ) );
+ BEGIN(SECT2);
+ return '}';
+ }
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+#line 554 "scan.l"
+{
+ synerr( _( "missing }" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '}';
+ }
+ YY_BREAK
+
+
+case 143:
+YY_RULE_SETUP
+#line 564 "scan.l"
+bracelevel = 0;
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 566 "scan.l"
+ACTION_ECHO; yy_push_state( COMMENT );
+ YY_BREAK
+
+case 145:
+YY_RULE_SETUP
+#line 569 "scan.l"
+{
+ ACTION_ECHO;
+ CHECK_REJECT(yytext);
+ }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 573 "scan.l"
+{
+ ACTION_ECHO;
+ CHECK_YYMORE(yytext);
+ }
+ YY_BREAK
+
+case 147:
+YY_RULE_SETUP
+#line 579 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 580 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 ||
+ (doing_codeblock && indented_code) )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = doing_codeblock = false;
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+
+/* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
+
+case 149:
+YY_RULE_SETUP
+#line 598 "scan.l"
+ACTION_ECHO; ++bracelevel;
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 599 "scan.l"
+ACTION_ECHO; --bracelevel;
+ YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 600 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 152:
+YY_RULE_SETUP
+#line 601 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 602 "scan.l"
+ACTION_ECHO; /* character constant */
+ YY_BREAK
+case 154:
+YY_RULE_SETUP
+#line 603 "scan.l"
+ACTION_ECHO; BEGIN(ACTION_STRING);
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 604 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = false;
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 616 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+
+
+case 157:
+YY_RULE_SETUP
+#line 620 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 158:
+YY_RULE_SETUP
+#line 621 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 159:
+YY_RULE_SETUP
+#line 622 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case 160:
+YY_RULE_SETUP
+#line 623 "scan.l"
+ACTION_ECHO; BEGIN(ACTION);
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 624 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+
+case YY_STATE_EOF(COMMENT):
+case YY_STATE_EOF(ACTION):
+case YY_STATE_EOF(ACTION_STRING):
+#line 627 "scan.l"
+{
+ synerr( _( "EOF encountered inside an action" ) );
+ yyterminate();
+ }
+ YY_BREAK
+case 162:
+YY_RULE_SETUP
+#line 633 "scan.l"
+{
+ yylval = myesc( (Char *) yytext );
+
+ if ( YY_START == FIRSTCCL )
+ BEGIN(CCL);
+
+ return CHAR;
+ }
+ YY_BREAK
+
+case 163:
+YY_RULE_SETUP
+#line 644 "scan.l"
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(SECT3):
+#line 645 "scan.l"
+sectnum = 0; yyterminate();
+ YY_BREAK
+
+case 164:
+YY_RULE_SETUP
+#line 648 "scan.l"
+format_synerr( _( "bad character: %s" ), yytext );
+ YY_BREAK
+case 165:
+YY_RULE_SETUP
+#line 650 "scan.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 2736 "scan.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(SECT2):
+case YY_STATE_EOF(CODEBLOCK):
+case YY_STATE_EOF(PICKUPDEF):
+case YY_STATE_EOF(SC):
+case YY_STATE_EOF(CARETISBOL):
+case YY_STATE_EOF(NUM):
+case YY_STATE_EOF(QUOTE):
+case YY_STATE_EOF(FIRSTCCL):
+case YY_STATE_EOF(CCL):
+case YY_STATE_EOF(RECOVER):
+case YY_STATE_EOF(PERCENT_BRACE_ACTION):
+case YY_STATE_EOF(OPTION):
+case YY_STATE_EOF(LINEDIR):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 768);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ yy_current_buffer->yy_at_bol = (c == '\n');
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 650 "scan.l"
+
+
+
+int yywrap()
+ {
+ if ( --num_input_files > 0 )
+ {
+ set_input_file( *++input_files );
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+
+/* set_input_file - open the given file (if NULL, stdin) for scanning */
+
+void set_input_file( file )
+char *file;
+ {
+ if ( file && strcmp( file, "-" ) )
+ {
+ infilename = copy_string( file );
+ yyin = fopen( infilename, "r" );
+
+ if ( yyin == NULL )
+ lerrsf( _( "can't open %s" ), file );
+ }
+
+ else
+ {
+ yyin = stdin;
+ infilename = copy_string( "<stdin>" );
+ }
+
+ linenum = 1;
+ }
+
+
+/* Wrapper routines for accessing the scanner's malloc routines. */
+
+void *flex_alloc( size )
+size_t size;
+ {
+ return (void *) malloc( size );
+ }
+
+void *flex_realloc( ptr, size )
+void *ptr;
+size_t size;
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+void flex_free( ptr )
+void *ptr;
+ {
+ if ( ptr )
+ free( ptr );
+ }
diff --git a/usr.bin/lex/lex.1 b/usr.bin/lex/lex.1
new file mode 100644
index 0000000..16025e9
--- /dev/null
+++ b/usr.bin/lex/lex.1
@@ -0,0 +1,4062 @@
+.TH FLEX 1 "April 1995" "Version 2.5"
+.SH NAME
+flex \- fast lexical analyzer generator
+.SH SYNOPSIS
+.B flex
+.B [\-bcdfhilnpstvwBFILTV78+? \-C[aefFmr] \-ooutput \-Pprefix \-Sskeleton]
+.B [\-\-help \-\-version]
+.I [filename ...]
+.SH OVERVIEW
+This manual describes
+.I flex,
+a tool for generating programs that perform pattern-matching on text. The
+manual includes both tutorial and reference sections:
+.nf
+
+ Description
+ a brief overview of the tool
+
+ Some Simple Examples
+
+ Format Of The Input File
+
+ Patterns
+ the extended regular expressions used by flex
+
+ How The Input Is Matched
+ the rules for determining what has been matched
+
+ Actions
+ how to specify what to do when a pattern is matched
+
+ The Generated Scanner
+ details regarding the scanner that flex produces;
+ how to control the input source
+
+ Start Conditions
+ introducing context into your scanners, and
+ managing "mini-scanners"
+
+ Multiple Input Buffers
+ how to manipulate multiple input sources; how to
+ scan from strings instead of files
+
+ End-of-file Rules
+ special rules for matching the end of the input
+
+ Miscellaneous Macros
+ a summary of macros available to the actions
+
+ Values Available To The User
+ a summary of values available to the actions
+
+ Interfacing With Yacc
+ connecting flex scanners together with yacc parsers
+
+ Options
+ flex command-line options, and the "%option"
+ directive
+
+ Performance Considerations
+ how to make your scanner go as fast as possible
+
+ Generating C++ Scanners
+ the (experimental) facility for generating C++
+ scanner classes
+
+ Incompatibilities With Lex And POSIX
+ how flex differs from AT&T lex and the POSIX lex
+ standard
+
+ Diagnostics
+ those error messages produced by flex (or scanners
+ it generates) whose meanings might not be apparent
+
+ Files
+ files used by flex
+
+ Deficiencies / Bugs
+ known problems with flex
+
+ See Also
+ other documentation, related tools
+
+ Author
+ includes contact information
+
+.fi
+.SH DESCRIPTION
+.I flex
+is a tool for generating
+.I scanners:
+programs which recognized lexical patterns in text.
+.I flex
+reads
+the given input files, or its standard input if no file names are given,
+for a description of a scanner to generate. The description is in
+the form of pairs
+of regular expressions and C code, called
+.I rules. flex
+generates as output a C source file,
+.B lex.yy.c,
+which defines a routine
+.B yylex().
+This file is compiled and linked with the
+.B \-ll
+library to produce an executable. When the executable is run,
+it analyzes its input for occurrences
+of the regular expressions. Whenever it finds one, it executes
+the corresponding C code.
+.SH SOME SIMPLE EXAMPLES
+.PP
+First some simple examples to get the flavor of how one uses
+.I flex.
+The following
+.I flex
+input specifies a scanner which whenever it encounters the string
+"username" will replace it with the user's login name:
+.nf
+
+ %%
+ username printf( "%s", getlogin() );
+
+.fi
+By default, any text not matched by a
+.I flex
+scanner
+is copied to the output, so the net effect of this scanner is
+to copy its input file to its output with each occurrence
+of "username" expanded.
+In this input, there is just one rule. "username" is the
+.I pattern
+and the "printf" is the
+.I action.
+The "%%" marks the beginning of the rules.
+.PP
+Here's another simple example:
+.nf
+
+ %{
+ int num_lines = 0, num_chars = 0;
+ %}
+
+ %%
+ \\n ++num_lines; ++num_chars;
+ . ++num_chars;
+
+ %%
+ main()
+ {
+ yylex();
+ printf( "# of lines = %d, # of chars = %d\\n",
+ num_lines, num_chars );
+ }
+
+.fi
+This scanner counts the number of characters and the number
+of lines in its input (it produces no output other than the
+final report on the counts). The first line
+declares two globals, "num_lines" and "num_chars", which are accessible
+both inside
+.B yylex()
+and in the
+.B main()
+routine declared after the second "%%". There are two rules, one
+which matches a newline ("\\n") and increments both the line count and
+the character count, and one which matches any character other than
+a newline (indicated by the "." regular expression).
+.PP
+A somewhat more complicated example:
+.nf
+
+ /* scanner for a toy Pascal-like language */
+
+ %{
+ /* need this for the call to atof() below */
+ #include <math.h>
+ %}
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+ %%
+
+ {DIGIT}+ {
+ printf( "An integer: %s (%d)\\n", yytext,
+ atoi( yytext ) );
+ }
+
+ {DIGIT}+"."{DIGIT}* {
+ printf( "A float: %s (%g)\\n", yytext,
+ atof( yytext ) );
+ }
+
+ if|then|begin|end|procedure|function {
+ printf( "A keyword: %s\\n", yytext );
+ }
+
+ {ID} printf( "An identifier: %s\\n", yytext );
+
+ "+"|"-"|"*"|"/" printf( "An operator: %s\\n", yytext );
+
+ "{"[^}\\n]*"}" /* eat up one-line comments */
+
+ [ \\t\\n]+ /* eat up whitespace */
+
+ . printf( "Unrecognized character: %s\\n", yytext );
+
+ %%
+
+ main( argc, argv )
+ int argc;
+ char **argv;
+ {
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yylex();
+ }
+
+.fi
+This is the beginnings of a simple scanner for a language like
+Pascal. It identifies different types of
+.I tokens
+and reports on what it has seen.
+.PP
+The details of this example will be explained in the following
+sections.
+.SH FORMAT OF THE INPUT FILE
+The
+.I flex
+input file consists of three sections, separated by a line with just
+.B %%
+in it:
+.nf
+
+ definitions
+ %%
+ rules
+ %%
+ user code
+
+.fi
+The
+.I definitions
+section contains declarations of simple
+.I name
+definitions to simplify the scanner specification, and declarations of
+.I start conditions,
+which are explained in a later section.
+.PP
+Name definitions have the form:
+.nf
+
+ name definition
+
+.fi
+The "name" is a word beginning with a letter or an underscore ('_')
+followed by zero or more letters, digits, '_', or '-' (dash).
+The definition is taken to begin at the first non-white-space character
+following the name and continuing to the end of the line.
+The definition can subsequently be referred to using "{name}", which
+will expand to "(definition)". For example,
+.nf
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+.fi
+defines "DIGIT" to be a regular expression which matches a
+single digit, and
+"ID" to be a regular expression which matches a letter
+followed by zero-or-more letters-or-digits.
+A subsequent reference to
+.nf
+
+ {DIGIT}+"."{DIGIT}*
+
+.fi
+is identical to
+.nf
+
+ ([0-9])+"."([0-9])*
+
+.fi
+and matches one-or-more digits followed by a '.' followed
+by zero-or-more digits.
+.PP
+The
+.I rules
+section of the
+.I flex
+input contains a series of rules of the form:
+.nf
+
+ pattern action
+
+.fi
+where the pattern must be unindented and the action must begin
+on the same line.
+.PP
+See below for a further description of patterns and actions.
+.PP
+Finally, the user code section is simply copied to
+.B lex.yy.c
+verbatim.
+It is used for companion routines which call or are called
+by the scanner. The presence of this section is optional;
+if it is missing, the second
+.B %%
+in the input file may be skipped, too.
+.PP
+In the definitions and rules sections, any
+.I indented
+text or text enclosed in
+.B %{
+and
+.B %}
+is copied verbatim to the output (with the %{}'s removed).
+The %{}'s must appear unindented on lines by themselves.
+.PP
+In the rules section,
+any indented or %{} text appearing before the
+first rule may be used to declare variables
+which are local to the scanning routine and (after the declarations)
+code which is to be executed whenever the scanning routine is entered.
+Other indented or %{} text in the rule section is still copied to the output,
+but its meaning is not well-defined and it may well cause compile-time
+errors (this feature is present for
+.I POSIX
+compliance; see below for other such features).
+.PP
+In the definitions section (but not in the rules section),
+an unindented comment (i.e., a line
+beginning with "/*") is also copied verbatim to the output up
+to the next "*/".
+.SH PATTERNS
+The patterns in the input are written using an extended set of regular
+expressions. These are:
+.nf
+
+ x match the character 'x'
+ . any character (byte) except newline
+ [xyz] a "character class"; in this case, the pattern
+ matches either an 'x', a 'y', or a 'z'
+ [abj-oZ] a "character class" with a range in it; matches
+ an 'a', a 'b', any letter from 'j' through 'o',
+ or a 'Z'
+ [^A-Z] a "negated character class", i.e., any character
+ but those in the class. In this case, any
+ character EXCEPT an uppercase letter.
+ [^A-Z\\n] any character EXCEPT an uppercase letter or
+ a newline
+ r* zero or more r's, where r is any regular expression
+ r+ one or more r's
+ r? zero or one r's (that is, "an optional r")
+ r{2,5} anywhere from two to five r's
+ r{2,} two or more r's
+ r{4} exactly 4 r's
+ {name} the expansion of the "name" definition
+ (see above)
+ "[xyz]\\"foo"
+ the literal string: [xyz]"foo
+ \\X if X is an 'a', 'b', 'f', 'n', 'r', 't', or 'v',
+ then the ANSI-C interpretation of \\x.
+ Otherwise, a literal 'X' (used to escape
+ operators such as '*')
+ \\0 a NUL character (ASCII code 0)
+ \\123 the character with octal value 123
+ \\x2a the character with hexadecimal value 2a
+ (r) match an r; parentheses are used to override
+ precedence (see below)
+
+
+ rs the regular expression r followed by the
+ regular expression s; called "concatenation"
+
+
+ r|s either an r or an s
+
+
+ r/s an r but only if it is followed by an s. The
+ text matched by s is included when determining
+ whether this rule is the "longest match",
+ but is then returned to the input before
+ the action is executed. So the action only
+ sees the text matched by r. This type
+ of pattern is called trailing context".
+ (There are some combinations of r/s that flex
+ cannot match correctly; see notes in the
+ Deficiencies / Bugs section below regarding
+ "dangerous trailing context".)
+ ^r an r, but only at the beginning of a line (i.e.,
+ which just starting to scan, or right after a
+ newline has been scanned).
+ r$ an r, but only at the end of a line (i.e., just
+ before a newline). Equivalent to "r/\\n".
+
+ Note that flex's notion of "newline" is exactly
+ whatever the C compiler used to compile flex
+ interprets '\\n' as; in particular, on some DOS
+ systems you must either filter out \\r's in the
+ input yourself, or explicitly use r/\\r\\n for "r$".
+
+
+ <s>r an r, but only in start condition s (see
+ below for discussion of start conditions)
+ <s1,s2,s3>r
+ same, but in any of start conditions s1,
+ s2, or s3
+ <*>r an r in any start condition, even an exclusive one.
+
+
+ <<EOF>> an end-of-file
+ <s1,s2><<EOF>>
+ an end-of-file when in start condition s1 or s2
+
+.fi
+Note that inside of a character class, all regular expression operators
+lose their special meaning except escape ('\\') and the character class
+operators, '-', ']', and, at the beginning of the class, '^'.
+.PP
+The regular expressions listed above are grouped according to
+precedence, from highest precedence at the top to lowest at the bottom.
+Those grouped together have equal precedence. For example,
+.nf
+
+ foo|bar*
+
+.fi
+is the same as
+.nf
+
+ (foo)|(ba(r*))
+
+.fi
+since the '*' operator has higher precedence than concatenation,
+and concatenation higher than alternation ('|'). This pattern
+therefore matches
+.I either
+the string "foo"
+.I or
+the string "ba" followed by zero-or-more r's.
+To match "foo" or zero-or-more "bar"'s, use:
+.nf
+
+ foo|(bar)*
+
+.fi
+and to match zero-or-more "foo"'s-or-"bar"'s:
+.nf
+
+ (foo|bar)*
+
+.fi
+.PP
+In addition to characters and ranges of characters, character classes
+can also contain character class
+.I expressions.
+These are expressions enclosed inside
+.B [:
+and
+.B :]
+delimiters (which themselves must appear between the '[' and ']' of the
+character class; other elements may occur inside the character class, too).
+The valid expressions are:
+.nf
+
+ [:alnum:] [:alpha:] [:blank:]
+ [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:]
+ [:space:] [:upper:] [:xdigit:]
+
+.fi
+These expressions all designate a set of characters equivalent to
+the corresponding standard C
+.B isXXX
+function. For example,
+.B [:alnum:]
+designates those characters for which
+.B isalnum()
+returns true - i.e., any alphabetic or numeric.
+Some systems don't provide
+.B isblank(),
+so flex defines
+.B [:blank:]
+as a blank or a tab.
+.PP
+For example, the following character classes are all equivalent:
+.nf
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+.fi
+If your scanner is case-insensitive (the
+.B \-i
+flag), then
+.B [:upper:]
+and
+.B [:lower:]
+are equivalent to
+.B [:alpha:].
+.PP
+Some notes on patterns:
+.IP -
+A negated character class such as the example "[^A-Z]"
+above
+.I will match a newline
+unless "\\n" (or an equivalent escape sequence) is one of the
+characters explicitly present in the negated character class
+(e.g., "[^A-Z\\n]"). This is unlike how many other regular
+expression tools treat negated character classes, but unfortunately
+the inconsistency is historically entrenched.
+Matching newlines means that a pattern like [^"]* can match the entire
+input unless there's another quote in the input.
+.IP -
+A rule can have at most one instance of trailing context (the '/' operator
+or the '$' operator). The start condition, '^', and "<<EOF>>" patterns
+can only occur at the beginning of a pattern, and, as well as with '/' and '$',
+cannot be grouped inside parentheses. A '^' which does not occur at
+the beginning of a rule or a '$' which does not occur at the end of
+a rule loses its special properties and is treated as a normal character.
+.IP
+The following are illegal:
+.nf
+
+ foo/bar$
+ <sc1>foo<sc2>bar
+
+.fi
+Note that the first of these, can be written "foo/bar\\n".
+.IP
+The following will result in '$' or '^' being treated as a normal character:
+.nf
+
+ foo|(bar$)
+ foo|^bar
+
+.fi
+If what's wanted is a "foo" or a bar-followed-by-a-newline, the following
+could be used (the special '|' action is explained below):
+.nf
+
+ foo |
+ bar$ /* action goes here */
+
+.fi
+A similar trick will work for matching a foo or a
+bar-at-the-beginning-of-a-line.
+.SH HOW THE INPUT IS MATCHED
+When the generated scanner is run, it analyzes its input looking
+for strings which match any of its patterns. If it finds more than
+one match, it takes the one matching the most text (for trailing
+context rules, this includes the length of the trailing part, even
+though it will then be returned to the input). If it finds two
+or more matches of the same length, the
+rule listed first in the
+.I flex
+input file is chosen.
+.PP
+Once the match is determined, the text corresponding to the match
+(called the
+.I token)
+is made available in the global character pointer
+.B yytext,
+and its length in the global integer
+.B yyleng.
+The
+.I action
+corresponding to the matched pattern is then executed (a more
+detailed description of actions follows), and then the remaining
+input is scanned for another match.
+.PP
+If no match is found, then the
+.I default rule
+is executed: the next character in the input is considered matched and
+copied to the standard output. Thus, the simplest legal
+.I flex
+input is:
+.nf
+
+ %%
+
+.fi
+which generates a scanner that simply copies its input (one character
+at a time) to its output.
+.PP
+Note that
+.B yytext
+can be defined in two different ways: either as a character
+.I pointer
+or as a character
+.I array.
+You can control which definition
+.I flex
+uses by including one of the special directives
+.B %pointer
+or
+.B %array
+in the first (definitions) section of your flex input. The default is
+.B %pointer,
+unless you use the
+.B -l
+lex compatibility option, in which case
+.B yytext
+will be an array.
+The advantage of using
+.B %pointer
+is substantially faster scanning and no buffer overflow when matching
+very large tokens (unless you run out of dynamic memory). The disadvantage
+is that you are restricted in how your actions can modify
+.B yytext
+(see the next section), and calls to the
+.B unput()
+function destroys the present contents of
+.B yytext,
+which can be a considerable porting headache when moving between different
+.I lex
+versions.
+.PP
+The advantage of
+.B %array
+is that you can then modify
+.B yytext
+to your heart's content, and calls to
+.B unput()
+do not destroy
+.B yytext
+(see below). Furthermore, existing
+.I lex
+programs sometimes access
+.B yytext
+externally using declarations of the form:
+.nf
+ extern char yytext[];
+.fi
+This definition is erroneous when used with
+.B %pointer,
+but correct for
+.B %array.
+.PP
+.B %array
+defines
+.B yytext
+to be an array of
+.B YYLMAX
+characters, which defaults to a fairly large value. You can change
+the size by simply #define'ing
+.B YYLMAX
+to a different value in the first section of your
+.I flex
+input. As mentioned above, with
+.B %pointer
+yytext grows dynamically to accommodate large tokens. While this means your
+.B %pointer
+scanner can accommodate very large tokens (such as matching entire blocks
+of comments), bear in mind that each time the scanner must resize
+.B yytext
+it also must rescan the entire token from the beginning, so matching such
+tokens can prove slow.
+.B yytext
+presently does
+.I not
+dynamically grow if a call to
+.B unput()
+results in too much text being pushed back; instead, a run-time error results.
+.PP
+Also note that you cannot use
+.B %array
+with C++ scanner classes
+(the
+.B c++
+option; see below).
+.SH ACTIONS
+Each pattern in a rule has a corresponding action, which can be any
+arbitrary C statement. The pattern ends at the first non-escaped
+whitespace character; the remainder of the line is its action. If the
+action is empty, then when the pattern is matched the input token
+is simply discarded. For example, here is the specification for a program
+which deletes all occurrences of "zap me" from its input:
+.nf
+
+ %%
+ "zap me"
+
+.fi
+(It will copy all other characters in the input to the output since
+they will be matched by the default rule.)
+.PP
+Here is a program which compresses multiple blanks and tabs down to
+a single blank, and throws away whitespace found at the end of a line:
+.nf
+
+ %%
+ [ \\t]+ putchar( ' ' );
+ [ \\t]+$ /* ignore this token */
+
+.fi
+.PP
+If the action contains a '{', then the action spans till the balancing '}'
+is found, and the action may cross multiple lines.
+.I flex
+knows about C strings and comments and won't be fooled by braces found
+within them, but also allows actions to begin with
+.B %{
+and will consider the action to be all the text up to the next
+.B %}
+(regardless of ordinary braces inside the action).
+.PP
+An action consisting solely of a vertical bar ('|') means "same as
+the action for the next rule." See below for an illustration.
+.PP
+Actions can include arbitrary C code, including
+.B return
+statements to return a value to whatever routine called
+.B yylex().
+Each time
+.B yylex()
+is called it continues processing tokens from where it last left
+off until it either reaches
+the end of the file or executes a return.
+.PP
+Actions are free to modify
+.B yytext
+except for lengthening it (adding
+characters to its end--these will overwrite later characters in the
+input stream). This however does not apply when using
+.B %array
+(see above); in that case,
+.B yytext
+may be freely modified in any way.
+.PP
+Actions are free to modify
+.B yyleng
+except they should not do so if the action also includes use of
+.B yymore()
+(see below).
+.PP
+There are a number of special directives which can be included within
+an action:
+.IP -
+.B ECHO
+copies yytext to the scanner's output.
+.IP -
+.B BEGIN
+followed by the name of a start condition places the scanner in the
+corresponding start condition (see below).
+.IP -
+.B REJECT
+directs the scanner to proceed on to the "second best" rule which matched the
+input (or a prefix of the input). The rule is chosen as described
+above in "How the Input is Matched", and
+.B yytext
+and
+.B yyleng
+set up appropriately.
+It may either be one which matched as much text
+as the originally chosen rule but came later in the
+.I flex
+input file, or one which matched less text.
+For example, the following will both count the
+words in the input and call the routine special() whenever "frob" is seen:
+.nf
+
+ int word_count = 0;
+ %%
+
+ frob special(); REJECT;
+ [^ \\t\\n]+ ++word_count;
+
+.fi
+Without the
+.B REJECT,
+any "frob"'s in the input would not be counted as words, since the
+scanner normally executes only one action per token.
+Multiple
+.B REJECT's
+are allowed, each one finding the next best choice to the currently
+active rule. For example, when the following scanner scans the token
+"abcd", it will write "abcdabcaba" to the output:
+.nf
+
+ %%
+ a |
+ ab |
+ abc |
+ abcd ECHO; REJECT;
+ .|\\n /* eat up any unmatched character */
+
+.fi
+(The first three rules share the fourth's action since they use
+the special '|' action.)
+.B REJECT
+is a particularly expensive feature in terms of scanner performance;
+if it is used in
+.I any
+of the scanner's actions it will slow down
+.I all
+of the scanner's matching. Furthermore,
+.B REJECT
+cannot be used with the
+.I -Cf
+or
+.I -CF
+options (see below).
+.IP
+Note also that unlike the other special actions,
+.B REJECT
+is a
+.I branch;
+code immediately following it in the action will
+.I not
+be executed.
+.IP -
+.B yymore()
+tells the scanner that the next time it matches a rule, the corresponding
+token should be
+.I appended
+onto the current value of
+.B yytext
+rather than replacing it. For example, given the input "mega-kludge"
+the following will write "mega-mega-kludge" to the output:
+.nf
+
+ %%
+ mega- ECHO; yymore();
+ kludge ECHO;
+
+.fi
+First "mega-" is matched and echoed to the output. Then "kludge"
+is matched, but the previous "mega-" is still hanging around at the
+beginning of
+.B yytext
+so the
+.B ECHO
+for the "kludge" rule will actually write "mega-kludge".
+.PP
+Two notes regarding use of
+.B yymore().
+First,
+.B yymore()
+depends on the value of
+.I yyleng
+correctly reflecting the size of the current token, so you must not
+modify
+.I yyleng
+if you are using
+.B yymore().
+Second, the presence of
+.B yymore()
+in the scanner's action entails a minor performance penalty in the
+scanner's matching speed.
+.IP -
+.B yyless(n)
+returns all but the first
+.I n
+characters of the current token back to the input stream, where they
+will be rescanned when the scanner looks for the next match.
+.B yytext
+and
+.B yyleng
+are adjusted appropriately (e.g.,
+.B yyleng
+will now be equal to
+.I n
+). For example, on the input "foobar" the following will write out
+"foobarbar":
+.nf
+
+ %%
+ foobar ECHO; yyless(3);
+ [a-z]+ ECHO;
+
+.fi
+An argument of 0 to
+.B yyless
+will cause the entire current input string to be scanned again. Unless you've
+changed how the scanner will subsequently process its input (using
+.B BEGIN,
+for example), this will result in an endless loop.
+.PP
+Note that
+.B yyless
+is a macro and can only be used in the flex input file, not from
+other source files.
+.IP -
+.B unput(c)
+puts the character
+.I c
+back onto the input stream. It will be the next character scanned.
+The following action will take the current token and cause it
+to be rescanned enclosed in parentheses.
+.nf
+
+ {
+ int i;
+ /* Copy yytext because unput() trashes yytext */
+ char *yycopy = strdup( yytext );
+ unput( ')' );
+ for ( i = yyleng - 1; i >= 0; --i )
+ unput( yycopy[i] );
+ unput( '(' );
+ free( yycopy );
+ }
+
+.fi
+Note that since each
+.B unput()
+puts the given character back at the
+.I beginning
+of the input stream, pushing back strings must be done back-to-front.
+.PP
+An important potential problem when using
+.B unput()
+is that if you are using
+.B %pointer
+(the default), a call to
+.B unput()
+.I destroys
+the contents of
+.I yytext,
+starting with its rightmost character and devouring one character to
+the left with each call. If you need the value of yytext preserved
+after a call to
+.B unput()
+(as in the above example),
+you must either first copy it elsewhere, or build your scanner using
+.B %array
+instead (see How The Input Is Matched).
+.PP
+Finally, note that you cannot put back
+.B EOF
+to attempt to mark the input stream with an end-of-file.
+.IP -
+.B input()
+reads the next character from the input stream. For example,
+the following is one way to eat up C comments:
+.nf
+
+ %%
+ "/*" {
+ register int c;
+
+ for ( ; ; )
+ {
+ while ( (c = input()) != '*' &&
+ c != EOF )
+ ; /* eat up text of comment */
+
+ if ( c == '*' )
+ {
+ while ( (c = input()) == '*' )
+ ;
+ if ( c == '/' )
+ break; /* found the end */
+ }
+
+ if ( c == EOF )
+ {
+ error( "EOF in comment" );
+ break;
+ }
+ }
+ }
+
+.fi
+(Note that if the scanner is compiled using
+.B C++,
+then
+.B input()
+is instead referred to as
+.B yyinput(),
+in order to avoid a name clash with the
+.B C++
+stream by the name of
+.I input.)
+.IP -
+.B YY_FLUSH_BUFFER
+flushes the scanner's internal buffer
+so that the next time the scanner attempts to match a token, it will
+first refill the buffer using
+.B YY_INPUT
+(see The Generated Scanner, below). This action is a special case
+of the more general
+.B yy_flush_buffer()
+function, described below in the section Multiple Input Buffers.
+.IP -
+.B yyterminate()
+can be used in lieu of a return statement in an action. It terminates
+the scanner and returns a 0 to the scanner's caller, indicating "all done".
+By default,
+.B yyterminate()
+is also called when an end-of-file is encountered. It is a macro and
+may be redefined.
+.SH THE GENERATED SCANNER
+The output of
+.I flex
+is the file
+.B lex.yy.c,
+which contains the scanning routine
+.B yylex(),
+a number of tables used by it for matching tokens, and a number
+of auxiliary routines and macros. By default,
+.B yylex()
+is declared as follows:
+.nf
+
+ int yylex()
+ {
+ ... various definitions and the actions in here ...
+ }
+
+.fi
+(If your environment supports function prototypes, then it will
+be "int yylex( void )".) This definition may be changed by defining
+the "YY_DECL" macro. For example, you could use:
+.nf
+
+ #define YY_DECL float lexscan( a, b ) float a, b;
+
+.fi
+to give the scanning routine the name
+.I lexscan,
+returning a float, and taking two floats as arguments. Note that
+if you give arguments to the scanning routine using a
+K&R-style/non-prototyped function declaration, you must terminate
+the definition with a semi-colon (;).
+.PP
+Whenever
+.B yylex()
+is called, it scans tokens from the global input file
+.I yyin
+(which defaults to stdin). It continues until it either reaches
+an end-of-file (at which point it returns the value 0) or
+one of its actions executes a
+.I return
+statement.
+.PP
+If the scanner reaches an end-of-file, subsequent calls are undefined
+unless either
+.I yyin
+is pointed at a new input file (in which case scanning continues from
+that file), or
+.B yyrestart()
+is called.
+.B yyrestart()
+takes one argument, a
+.B FILE *
+pointer (which can be nil, if you've set up
+.B YY_INPUT
+to scan from a source other than
+.I yyin),
+and initializes
+.I yyin
+for scanning from that file. Essentially there is no difference between
+just assigning
+.I yyin
+to a new input file or using
+.B yyrestart()
+to do so; the latter is available for compatibility with previous versions
+of
+.I flex,
+and because it can be used to switch input files in the middle of scanning.
+It can also be used to throw away the current input buffer, by calling
+it with an argument of
+.I yyin;
+but better is to use
+.B YY_FLUSH_BUFFER
+(see above).
+Note that
+.B yyrestart()
+does
+.I not
+reset the start condition to
+.B INITIAL
+(see Start Conditions, below).
+.PP
+If
+.B yylex()
+stops scanning due to executing a
+.I return
+statement in one of the actions, the scanner may then be called again and it
+will resume scanning where it left off.
+.PP
+By default (and for purposes of efficiency), the scanner uses
+block-reads rather than simple
+.I getc()
+calls to read characters from
+.I yyin.
+The nature of how it gets its input can be controlled by defining the
+.B YY_INPUT
+macro.
+YY_INPUT's calling sequence is "YY_INPUT(buf,result,max_size)". Its
+action is to place up to
+.I max_size
+characters in the character array
+.I buf
+and return in the integer variable
+.I result
+either the
+number of characters read or the constant YY_NULL (0 on Unix systems)
+to indicate EOF. The default YY_INPUT reads from the
+global file-pointer "yyin".
+.PP
+A sample definition of YY_INPUT (in the definitions
+section of the input file):
+.nf
+
+ %{
+ #define YY_INPUT(buf,result,max_size) \\
+ { \\
+ int c = getchar(); \\
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \\
+ }
+ %}
+
+.fi
+This definition will change the input processing to occur
+one character at a time.
+.PP
+When the scanner receives an end-of-file indication from YY_INPUT,
+it then checks the
+.B yywrap()
+function. If
+.B yywrap()
+returns false (zero), then it is assumed that the
+function has gone ahead and set up
+.I yyin
+to point to another input file, and scanning continues. If it returns
+true (non-zero), then the scanner terminates, returning 0 to its
+caller. Note that in either case, the start condition remains unchanged;
+it does
+.I not
+revert to
+.B INITIAL.
+.PP
+If you do not supply your own version of
+.B yywrap(),
+then you must either use
+.B %option noyywrap
+(in which case the scanner behaves as though
+.B yywrap()
+returned 1), or you must link with
+.B \-ll
+to obtain the default version of the routine, which always returns 1.
+.PP
+Three routines are available for scanning from in-memory buffers rather
+than files:
+.B yy_scan_string(), yy_scan_bytes(),
+and
+.B yy_scan_buffer().
+See the discussion of them below in the section Multiple Input Buffers.
+.PP
+The scanner writes its
+.B ECHO
+output to the
+.I yyout
+global (default, stdout), which may be redefined by the user simply
+by assigning it to some other
+.B FILE
+pointer.
+.SH START CONDITIONS
+.I flex
+provides a mechanism for conditionally activating rules. Any rule
+whose pattern is prefixed with "<sc>" will only be active when
+the scanner is in the start condition named "sc". For example,
+.nf
+
+ <STRING>[^"]* { /* eat up the string body ... */
+ ...
+ }
+
+.fi
+will be active only when the scanner is in the "STRING" start
+condition, and
+.nf
+
+ <INITIAL,STRING,QUOTE>\\. { /* handle an escape ... */
+ ...
+ }
+
+.fi
+will be active only when the current start condition is
+either "INITIAL", "STRING", or "QUOTE".
+.PP
+Start conditions
+are declared in the definitions (first) section of the input
+using unindented lines beginning with either
+.B %s
+or
+.B %x
+followed by a list of names.
+The former declares
+.I inclusive
+start conditions, the latter
+.I exclusive
+start conditions. A start condition is activated using the
+.B BEGIN
+action. Until the next
+.B BEGIN
+action is executed, rules with the given start
+condition will be active and
+rules with other start conditions will be inactive.
+If the start condition is
+.I inclusive,
+then rules with no start conditions at all will also be active.
+If it is
+.I exclusive,
+then
+.I only
+rules qualified with the start condition will be active.
+A set of rules contingent on the same exclusive start condition
+describe a scanner which is independent of any of the other rules in the
+.I flex
+input. Because of this,
+exclusive start conditions make it easy to specify "mini-scanners"
+which scan portions of the input that are syntactically different
+from the rest (e.g., comments).
+.PP
+If the distinction between inclusive and exclusive start conditions
+is still a little vague, here's a simple example illustrating the
+connection between the two. The set of rules:
+.nf
+
+ %s example
+ %%
+
+ <example>foo do_something();
+
+ bar something_else();
+
+.fi
+is equivalent to
+.nf
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <INITIAL,example>bar something_else();
+
+.fi
+Without the
+.B <INITIAL,example>
+qualifier, the
+.I bar
+pattern in the second example wouldn't be active (i.e., couldn't match)
+when in start condition
+.B example.
+If we just used
+.B <example>
+to qualify
+.I bar,
+though, then it would only be active in
+.B example
+and not in
+.B INITIAL,
+while in the first example it's active in both, because in the first
+example the
+.B example
+startion condition is an
+.I inclusive
+.B (%s)
+start condition.
+.PP
+Also note that the special start-condition specifier
+.B <*>
+matches every start condition. Thus, the above example could also
+have been written;
+.nf
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <*>bar something_else();
+
+.fi
+.PP
+The default rule (to
+.B ECHO
+any unmatched character) remains active in start conditions. It
+is equivalent to:
+.nf
+
+ <*>.|\\n ECHO;
+
+.fi
+.PP
+.B BEGIN(0)
+returns to the original state where only the rules with
+no start conditions are active. This state can also be
+referred to as the start-condition "INITIAL", so
+.B BEGIN(INITIAL)
+is equivalent to
+.B BEGIN(0).
+(The parentheses around the start condition name are not required but
+are considered good style.)
+.PP
+.B BEGIN
+actions can also be given as indented code at the beginning
+of the rules section. For example, the following will cause
+the scanner to enter the "SPECIAL" start condition whenever
+.B yylex()
+is called and the global variable
+.I enter_special
+is true:
+.nf
+
+ int enter_special;
+
+ %x SPECIAL
+ %%
+ if ( enter_special )
+ BEGIN(SPECIAL);
+
+ <SPECIAL>blahblahblah
+ ...more rules follow...
+
+.fi
+.PP
+To illustrate the uses of start conditions,
+here is a scanner which provides two different interpretations
+of a string like "123.456". By default it will treat it as
+three tokens, the integer "123", a dot ('.'), and the integer "456".
+But if the string is preceded earlier in the line by the string
+"expect-floats"
+it will treat it as a single token, the floating-point number
+123.456:
+.nf
+
+ %{
+ #include <math.h>
+ %}
+ %s expect
+
+ %%
+ expect-floats BEGIN(expect);
+
+ <expect>[0-9]+"."[0-9]+ {
+ printf( "found a float, = %f\\n",
+ atof( yytext ) );
+ }
+ <expect>\\n {
+ /* that's the end of the line, so
+ * we need another "expect-number"
+ * before we'll recognize any more
+ * numbers
+ */
+ BEGIN(INITIAL);
+ }
+
+ [0-9]+ {
+ printf( "found an integer, = %d\\n",
+ atoi( yytext ) );
+ }
+
+ "." printf( "found a dot\\n" );
+
+.fi
+Here is a scanner which recognizes (and discards) C comments while
+maintaining a count of the current input line.
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+This scanner goes to a bit of trouble to match as much
+text as possible with each rule. In general, when attempting to write
+a high-speed scanner try to match as much possible in each rule, as
+it's a big win.
+.PP
+Note that start-conditions names are really integer values and
+can be stored as such. Thus, the above could be extended in the
+following fashion:
+.nf
+
+ %x comment foo
+ %%
+ int line_num = 1;
+ int comment_caller;
+
+ "/*" {
+ comment_caller = INITIAL;
+ BEGIN(comment);
+ }
+
+ ...
+
+ <foo>"/*" {
+ comment_caller = foo;
+ BEGIN(comment);
+ }
+
+ <comment>[^*\\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(comment_caller);
+
+.fi
+Furthermore, you can access the current start condition using
+the integer-valued
+.B YY_START
+macro. For example, the above assignments to
+.I comment_caller
+could instead be written
+.nf
+
+ comment_caller = YY_START;
+
+.fi
+Flex provides
+.B YYSTATE
+as an alias for
+.B YY_START
+(since that is what's used by AT&T
+.I lex).
+.PP
+Note that start conditions do not have their own name-space; %s's and %x's
+declare names in the same fashion as #define's.
+.PP
+Finally, here's an example of how to match C-style quoted strings using
+exclusive start conditions, including expanded escape sequences (but
+not including checking for a string that's too long):
+.nf
+
+ %x str
+
+ %%
+ char string_buf[MAX_STR_CONST];
+ char *string_buf_ptr;
+
+
+ \\" string_buf_ptr = string_buf; BEGIN(str);
+
+ <str>\\" { /* saw closing quote - all done */
+ BEGIN(INITIAL);
+ *string_buf_ptr = '\\0';
+ /* return string constant token type and
+ * value to parser
+ */
+ }
+
+ <str>\\n {
+ /* error - unterminated string constant */
+ /* generate error message */
+ }
+
+ <str>\\\\[0-7]{1,3} {
+ /* octal escape sequence */
+ int result;
+
+ (void) sscanf( yytext + 1, "%o", &result );
+
+ if ( result > 0xff )
+ /* error, constant is out-of-bounds */
+
+ *string_buf_ptr++ = result;
+ }
+
+ <str>\\\\[0-9]+ {
+ /* generate error - bad escape sequence; something
+ * like '\\48' or '\\0777777'
+ */
+ }
+
+ <str>\\\\n *string_buf_ptr++ = '\\n';
+ <str>\\\\t *string_buf_ptr++ = '\\t';
+ <str>\\\\r *string_buf_ptr++ = '\\r';
+ <str>\\\\b *string_buf_ptr++ = '\\b';
+ <str>\\\\f *string_buf_ptr++ = '\\f';
+
+ <str>\\\\(.|\\n) *string_buf_ptr++ = yytext[1];
+
+ <str>[^\\\\\\n\\"]+ {
+ char *yptr = yytext;
+
+ while ( *yptr )
+ *string_buf_ptr++ = *yptr++;
+ }
+
+.fi
+.PP
+Often, such as in some of the examples above, you wind up writing a
+whole bunch of rules all preceded by the same start condition(s). Flex
+makes this a little easier and cleaner by introducing a notion of
+start condition
+.I scope.
+A start condition scope is begun with:
+.nf
+
+ <SCs>{
+
+.fi
+where
+.I SCs
+is a list of one or more start conditions. Inside the start condition
+scope, every rule automatically has the prefix
+.I <SCs>
+applied to it, until a
+.I '}'
+which matches the initial
+.I '{'.
+So, for example,
+.nf
+
+ <ESC>{
+ "\\\\n" return '\\n';
+ "\\\\r" return '\\r';
+ "\\\\f" return '\\f';
+ "\\\\0" return '\\0';
+ }
+
+.fi
+is equivalent to:
+.nf
+
+ <ESC>"\\\\n" return '\\n';
+ <ESC>"\\\\r" return '\\r';
+ <ESC>"\\\\f" return '\\f';
+ <ESC>"\\\\0" return '\\0';
+
+.fi
+Start condition scopes may be nested.
+.PP
+Three routines are available for manipulating stacks of start conditions:
+.TP
+.B void yy_push_state(int new_state)
+pushes the current start condition onto the top of the start condition
+stack and switches to
+.I new_state
+as though you had used
+.B BEGIN new_state
+(recall that start condition names are also integers).
+.TP
+.B void yy_pop_state()
+pops the top of the stack and switches to it via
+.B BEGIN.
+.TP
+.B int yy_top_state()
+returns the top of the stack without altering the stack's contents.
+.PP
+The start condition stack grows dynamically and so has no built-in
+size limitation. If memory is exhausted, program execution aborts.
+.PP
+To use start condition stacks, your scanner must include a
+.B %option stack
+directive (see Options below).
+.SH MULTIPLE INPUT BUFFERS
+Some scanners (such as those which support "include" files)
+require reading from several input streams. As
+.I flex
+scanners do a large amount of buffering, one cannot control
+where the next input will be read from by simply writing a
+.B YY_INPUT
+which is sensitive to the scanning context.
+.B YY_INPUT
+is only called when the scanner reaches the end of its buffer, which
+may be a long time after scanning a statement such as an "include"
+which requires switching the input source.
+.PP
+To negotiate these sorts of problems,
+.I flex
+provides a mechanism for creating and switching between multiple
+input buffers. An input buffer is created by using:
+.nf
+
+ YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+
+.fi
+which takes a
+.I FILE
+pointer and a size and creates a buffer associated with the given
+file and large enough to hold
+.I size
+characters (when in doubt, use
+.B YY_BUF_SIZE
+for the size). It returns a
+.B YY_BUFFER_STATE
+handle, which may then be passed to other routines (see below). The
+.B YY_BUFFER_STATE
+type is a pointer to an opaque
+.B struct yy_buffer_state
+structure, so you may safely initialize YY_BUFFER_STATE variables to
+.B ((YY_BUFFER_STATE) 0)
+if you wish, and also refer to the opaque structure in order to
+correctly declare input buffers in source files other than that
+of your scanner. Note that the
+.I FILE
+pointer in the call to
+.B yy_create_buffer
+is only used as the value of
+.I yyin
+seen by
+.B YY_INPUT;
+if you redefine
+.B YY_INPUT
+so it no longer uses
+.I yyin,
+then you can safely pass a nil
+.I FILE
+pointer to
+.B yy_create_buffer.
+You select a particular buffer to scan from using:
+.nf
+
+ void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+
+.fi
+switches the scanner's input buffer so subsequent tokens will
+come from
+.I new_buffer.
+Note that
+.B yy_switch_to_buffer()
+may be used by yywrap() to set things up for continued scanning, instead
+of opening a new file and pointing
+.I yyin
+at it. Note also that switching input sources via either
+.B yy_switch_to_buffer()
+or
+.B yywrap()
+does
+.I not
+change the start condition.
+.nf
+
+ void yy_delete_buffer( YY_BUFFER_STATE buffer )
+
+.fi
+is used to reclaim the storage associated with a buffer. (
+.B buffer
+can be nil, in which case the routine does nothing.)
+You can also clear the current contents of a buffer using:
+.nf
+
+ void yy_flush_buffer( YY_BUFFER_STATE buffer )
+
+.fi
+This function discards the buffer's contents,
+so the next time the scanner attempts to match a token from the
+buffer, it will first fill the buffer anew using
+.B YY_INPUT.
+.PP
+.B yy_new_buffer()
+is an alias for
+.B yy_create_buffer(),
+provided for compatibility with the C++ use of
+.I new
+and
+.I delete
+for creating and destroying dynamic objects.
+.PP
+Finally, the
+.B YY_CURRENT_BUFFER
+macro returns a
+.B YY_BUFFER_STATE
+handle to the current buffer.
+.PP
+Here is an example of using these features for writing a scanner
+which expands include files (the
+.B <<EOF>>
+feature is discussed below):
+.nf
+
+ /* the "incl" state is used for picking up the name
+ * of an include file
+ */
+ %x incl
+
+ %{
+ #define MAX_INCLUDE_DEPTH 10
+ YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+ int include_stack_ptr = 0;
+ %}
+
+ %%
+ include BEGIN(incl);
+
+ [a-z]+ ECHO;
+ [^a-z\\n]*\\n? ECHO;
+
+ <incl>[ \\t]* /* eat the whitespace */
+ <incl>[^ \\t\\n]+ { /* got the include file name */
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply" );
+ exit( 1 );
+ }
+
+ include_stack[include_stack_ptr++] =
+ YY_CURRENT_BUFFER;
+
+ yyin = fopen( yytext, "r" );
+
+ if ( ! yyin )
+ error( ... );
+
+ yy_switch_to_buffer(
+ yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+ BEGIN(INITIAL);
+ }
+
+ <<EOF>> {
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer(
+ include_stack[include_stack_ptr] );
+ }
+ }
+
+.fi
+Three routines are available for setting up input buffers for
+scanning in-memory strings instead of files. All of them create
+a new input buffer for scanning the string, and return a corresponding
+.B YY_BUFFER_STATE
+handle (which you should delete with
+.B yy_delete_buffer()
+when done with it). They also switch to the new buffer using
+.B yy_switch_to_buffer(),
+so the next call to
+.B yylex()
+will start scanning the string.
+.TP
+.B yy_scan_string(const char *str)
+scans a NUL-terminated string.
+.TP
+.B yy_scan_bytes(const char *bytes, int len)
+scans
+.I len
+bytes (including possibly NUL's)
+starting at location
+.I bytes.
+.PP
+Note that both of these functions create and scan a
+.I copy
+of the string or bytes. (This may be desirable, since
+.B yylex()
+modifies the contents of the buffer it is scanning.) You can avoid the
+copy by using:
+.TP
+.B yy_scan_buffer(char *base, yy_size_t size)
+which scans in place the buffer starting at
+.I base,
+consisting of
+.I size
+bytes, the last two bytes of which
+.I must
+be
+.B YY_END_OF_BUFFER_CHAR
+(ASCII NUL).
+These last two bytes are not scanned; thus, scanning
+consists of
+.B base[0]
+through
+.B base[size-2],
+inclusive.
+.IP
+If you fail to set up
+.I base
+in this manner (i.e., forget the final two
+.B YY_END_OF_BUFFER_CHAR
+bytes), then
+.B yy_scan_buffer()
+returns a nil pointer instead of creating a new input buffer.
+.IP
+The type
+.B yy_size_t
+is an integral type to which you can cast an integer expression
+reflecting the size of the buffer.
+.SH END-OF-FILE RULES
+The special rule "<<EOF>>" indicates
+actions which are to be taken when an end-of-file is
+encountered and yywrap() returns non-zero (i.e., indicates
+no further files to process). The action must finish
+by doing one of four things:
+.IP -
+assigning
+.I yyin
+to a new input file (in previous versions of flex, after doing the
+assignment you had to call the special action
+.B YY_NEW_FILE;
+this is no longer necessary);
+.IP -
+executing a
+.I return
+statement;
+.IP -
+executing the special
+.B yyterminate()
+action;
+.IP -
+or, switching to a new buffer using
+.B yy_switch_to_buffer()
+as shown in the example above.
+.PP
+<<EOF>> rules may not be used with other
+patterns; they may only be qualified with a list of start
+conditions. If an unqualified <<EOF>> rule is given, it
+applies to
+.I all
+start conditions which do not already have <<EOF>> actions. To
+specify an <<EOF>> rule for only the initial start condition, use
+.nf
+
+ <INITIAL><<EOF>>
+
+.fi
+.PP
+These rules are useful for catching things like unclosed comments.
+An example:
+.nf
+
+ %x quote
+ %%
+
+ ...other rules for dealing with quotes...
+
+ <quote><<EOF>> {
+ error( "unterminated quote" );
+ yyterminate();
+ }
+ <<EOF>> {
+ if ( *++filelist )
+ yyin = fopen( *filelist, "r" );
+ else
+ yyterminate();
+ }
+
+.fi
+.SH MISCELLANEOUS MACROS
+The macro
+.B YY_USER_ACTION
+can be defined to provide an action
+which is always executed prior to the matched rule's action. For example,
+it could be #define'd to call a routine to convert yytext to lower-case.
+When
+.B YY_USER_ACTION
+is invoked, the variable
+.I yy_act
+gives the number of the matched rule (rules are numbered starting with 1).
+Suppose you want to profile how often each of your rules is matched. The
+following would do the trick:
+.nf
+
+ #define YY_USER_ACTION ++ctr[yy_act]
+
+.fi
+where
+.I ctr
+is an array to hold the counts for the different rules. Note that
+the macro
+.B YY_NUM_RULES
+gives the total number of rules (including the default rule, even if
+you use
+.B \-s),
+so a correct declaration for
+.I ctr
+is:
+.nf
+
+ int ctr[YY_NUM_RULES];
+
+.fi
+.PP
+The macro
+.B YY_USER_INIT
+may be defined to provide an action which is always executed before
+the first scan (and before the scanner's internal initializations are done).
+For example, it could be used to call a routine to read
+in a data table or open a logging file.
+.PP
+The macro
+.B yy_set_interactive(is_interactive)
+can be used to control whether the current buffer is considered
+.I interactive.
+An interactive buffer is processed more slowly,
+but must be used when the scanner's input source is indeed
+interactive to avoid problems due to waiting to fill buffers
+(see the discussion of the
+.B \-I
+flag below). A non-zero value
+in the macro invocation marks the buffer as interactive, a zero
+value as non-interactive. Note that use of this macro overrides
+.B %option always-interactive
+or
+.B %option never-interactive
+(see Options below).
+.B yy_set_interactive()
+must be invoked prior to beginning to scan the buffer that is
+(or is not) to be considered interactive.
+.PP
+The macro
+.B yy_set_bol(at_bol)
+can be used to control whether the current buffer's scanning
+context for the next token match is done as though at the
+beginning of a line. A non-zero macro argument makes rules anchored with
+'^' active, while a zero argument makes '^' rules inactive.
+.PP
+The macro
+.B YY_AT_BOL()
+returns true if the next token scanned from the current buffer
+will have '^' rules active, false otherwise.
+.PP
+In the generated scanner, the actions are all gathered in one large
+switch statement and separated using
+.B YY_BREAK,
+which may be redefined. By default, it is simply a "break", to separate
+each rule's action from the following rule's.
+Redefining
+.B YY_BREAK
+allows, for example, C++ users to
+#define YY_BREAK to do nothing (while being very careful that every
+rule ends with a "break" or a "return"!) to avoid suffering from
+unreachable statement warnings where because a rule's action ends with
+"return", the
+.B YY_BREAK
+is inaccessible.
+.SH VALUES AVAILABLE TO THE USER
+This section summarizes the various values available to the user
+in the rule actions.
+.IP -
+.B char *yytext
+holds the text of the current token. It may be modified but not lengthened
+(you cannot append characters to the end).
+.IP
+If the special directive
+.B %array
+appears in the first section of the scanner description, then
+.B yytext
+is instead declared
+.B char yytext[YYLMAX],
+where
+.B YYLMAX
+is a macro definition that you can redefine in the first section
+if you don't like the default value (generally 8KB). Using
+.B %array
+results in somewhat slower scanners, but the value of
+.B yytext
+becomes immune to calls to
+.I input()
+and
+.I unput(),
+which potentially destroy its value when
+.B yytext
+is a character pointer. The opposite of
+.B %array
+is
+.B %pointer,
+which is the default.
+.IP
+You cannot use
+.B %array
+when generating C++ scanner classes
+(the
+.B \-+
+flag).
+.IP -
+.B int yyleng
+holds the length of the current token.
+.IP -
+.B FILE *yyin
+is the file which by default
+.I flex
+reads from. It may be redefined but doing so only makes sense before
+scanning begins or after an EOF has been encountered. Changing it in
+the midst of scanning will have unexpected results since
+.I flex
+buffers its input; use
+.B yyrestart()
+instead.
+Once scanning terminates because an end-of-file
+has been seen, you can assign
+.I yyin
+at the new input file and then call the scanner again to continue scanning.
+.IP -
+.B void yyrestart( FILE *new_file )
+may be called to point
+.I yyin
+at the new input file. The switch-over to the new file is immediate
+(any previously buffered-up input is lost). Note that calling
+.B yyrestart()
+with
+.I yyin
+as an argument thus throws away the current input buffer and continues
+scanning the same input file.
+.IP -
+.B FILE *yyout
+is the file to which
+.B ECHO
+actions are done. It can be reassigned by the user.
+.IP -
+.B YY_CURRENT_BUFFER
+returns a
+.B YY_BUFFER_STATE
+handle to the current buffer.
+.IP -
+.B YY_START
+returns an integer value corresponding to the current start
+condition. You can subsequently use this value with
+.B BEGIN
+to return to that start condition.
+.SH INTERFACING WITH YACC
+One of the main uses of
+.I flex
+is as a companion to the
+.I yacc
+parser-generator.
+.I yacc
+parsers expect to call a routine named
+.B yylex()
+to find the next input token. The routine is supposed to
+return the type of the next token as well as putting any associated
+value in the global
+.B yylval.
+To use
+.I flex
+with
+.I yacc,
+one specifies the
+.B \-d
+option to
+.I yacc
+to instruct it to generate the file
+.B y.tab.h
+containing definitions of all the
+.B %tokens
+appearing in the
+.I yacc
+input. This file is then included in the
+.I flex
+scanner. For example, if one of the tokens is "TOK_NUMBER",
+part of the scanner might look like:
+.nf
+
+ %{
+ #include "y.tab.h"
+ %}
+
+ %%
+
+ [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
+
+.fi
+.SH OPTIONS
+.I flex
+has the following options:
+.TP
+.B \-b
+Generate backing-up information to
+.I lex.backup.
+This is a list of scanner states which require backing up
+and the input characters on which they do so. By adding rules one
+can remove backing-up states. If
+.I all
+backing-up states are eliminated and
+.B \-Cf
+or
+.B \-CF
+is used, the generated scanner will run faster (see the
+.B \-p
+flag). Only users who wish to squeeze every last cycle out of their
+scanners need worry about this option. (See the section on Performance
+Considerations below.)
+.TP
+.B \-c
+is a do-nothing, deprecated option included for POSIX compliance.
+.TP
+.B \-d
+makes the generated scanner run in
+.I debug
+mode. Whenever a pattern is recognized and the global
+.B yy_flex_debug
+is non-zero (which is the default),
+the scanner will write to
+.I stderr
+a line of the form:
+.nf
+
+ --accepting rule at line 53 ("the matched text")
+
+.fi
+The line number refers to the location of the rule in the file
+defining the scanner (i.e., the file that was fed to flex). Messages
+are also generated when the scanner backs up, accepts the
+default rule, reaches the end of its input buffer (or encounters
+a NUL; at this point, the two look the same as far as the scanner's concerned),
+or reaches an end-of-file.
+.TP
+.B \-f
+specifies
+.I fast scanner.
+No table compression is done and stdio is bypassed.
+The result is large but fast. This option is equivalent to
+.B \-Cfr
+(see below).
+.TP
+.B \-h
+generates a "help" summary of
+.I flex's
+options to
+.I stdout
+and then exits.
+.B \-?
+and
+.B \-\-help
+are synonyms for
+.B \-h.
+.TP
+.B \-i
+instructs
+.I flex
+to generate a
+.I case-insensitive
+scanner. The case of letters given in the
+.I flex
+input patterns will
+be ignored, and tokens in the input will be matched regardless of case. The
+matched text given in
+.I yytext
+will have the preserved case (i.e., it will not be folded).
+.TP
+.B \-l
+turns on maximum compatibility with the original AT&T
+.I lex
+implementation. Note that this does not mean
+.I full
+compatibility. Use of this option costs a considerable amount of
+performance, and it cannot be used with the
+.B \-+, -f, -F, -Cf,
+or
+.B -CF
+options. For details on the compatibilities it provides, see the section
+"Incompatibilities With Lex And POSIX" below. This option also results
+in the name
+.B YY_FLEX_LEX_COMPAT
+being #define'd in the generated scanner.
+.TP
+.B \-n
+is another do-nothing, deprecated option included only for
+POSIX compliance.
+.TP
+.B \-p
+generates a performance report to stderr. The report
+consists of comments regarding features of the
+.I flex
+input file which will cause a serious loss of performance in the resulting
+scanner. If you give the flag twice, you will also get comments regarding
+features that lead to minor performance losses.
+.IP
+Note that the use of
+.B REJECT,
+.B %option yylineno,
+and variable trailing context (see the Deficiencies / Bugs section below)
+entails a substantial performance penalty; use of
+.I yymore(),
+the
+.B ^
+operator,
+and the
+.B \-I
+flag entail minor performance penalties.
+.TP
+.B \-s
+causes the
+.I default rule
+(that unmatched scanner input is echoed to
+.I stdout)
+to be suppressed. If the scanner encounters input that does not
+match any of its rules, it aborts with an error. This option is
+useful for finding holes in a scanner's rule set.
+.TP
+.B \-t
+instructs
+.I flex
+to write the scanner it generates to standard output instead
+of
+.B lex.yy.c.
+.TP
+.B \-v
+specifies that
+.I flex
+should write to
+.I stderr
+a summary of statistics regarding the scanner it generates.
+Most of the statistics are meaningless to the casual
+.I flex
+user, but the first line identifies the version of
+.I flex
+(same as reported by
+.B \-V),
+and the next line the flags used when generating the scanner, including
+those that are on by default.
+.TP
+.B \-w
+suppresses warning messages.
+.TP
+.B \-B
+instructs
+.I flex
+to generate a
+.I batch
+scanner, the opposite of
+.I interactive
+scanners generated by
+.B \-I
+(see below). In general, you use
+.B \-B
+when you are
+.I certain
+that your scanner will never be used interactively, and you want to
+squeeze a
+.I little
+more performance out of it. If your goal is instead to squeeze out a
+.I lot
+more performance, you should be using the
+.B \-Cf
+or
+.B \-CF
+options (discussed below), which turn on
+.B \-B
+automatically anyway.
+.TP
+.B \-F
+specifies that the
+.ul
+fast
+scanner table representation should be used (and stdio
+bypassed). This representation is
+about as fast as the full table representation
+.B (-f),
+and for some sets of patterns will be considerably smaller (and for
+others, larger). In general, if the pattern set contains both "keywords"
+and a catch-all, "identifier" rule, such as in the set:
+.nf
+
+ "case" return TOK_CASE;
+ "switch" return TOK_SWITCH;
+ ...
+ "default" return TOK_DEFAULT;
+ [a-z]+ return TOK_ID;
+
+.fi
+then you're better off using the full table representation. If only
+the "identifier" rule is present and you then use a hash table or some such
+to detect the keywords, you're better off using
+.B -F.
+.IP
+This option is equivalent to
+.B \-CFr
+(see below). It cannot be used with
+.B \-+.
+.TP
+.B \-I
+instructs
+.I flex
+to generate an
+.I interactive
+scanner. An interactive scanner is one that only looks ahead to decide
+what token has been matched if it absolutely must. It turns out that
+always looking one extra character ahead, even if the scanner has already
+seen enough text to disambiguate the current token, is a bit faster than
+only looking ahead when necessary. But scanners that always look ahead
+give dreadful interactive performance; for example, when a user types
+a newline, it is not recognized as a newline token until they enter
+.I another
+token, which often means typing in another whole line.
+.IP
+.I Flex
+scanners default to
+.I interactive
+unless you use the
+.B \-Cf
+or
+.B \-CF
+table-compression options (see below). That's because if you're looking
+for high-performance you should be using one of these options, so if you
+didn't,
+.I flex
+assumes you'd rather trade off a bit of run-time performance for intuitive
+interactive behavior. Note also that you
+.I cannot
+use
+.B \-I
+in conjunction with
+.B \-Cf
+or
+.B \-CF.
+Thus, this option is not really needed; it is on by default for all those
+cases in which it is allowed.
+.IP
+You can force a scanner to
+.I not
+be interactive by using
+.B \-B
+(see above).
+.TP
+.B \-L
+instructs
+.I flex
+not to generate
+.B #line
+directives. Without this option,
+.I flex
+peppers the generated scanner
+with #line directives so error messages in the actions will be correctly
+located with respect to either the original
+.I flex
+input file (if the errors are due to code in the input file), or
+.B lex.yy.c
+(if the errors are
+.I flex's
+fault -- you should report these sorts of errors to the email address
+given below).
+.TP
+.B \-T
+makes
+.I flex
+run in
+.I trace
+mode. It will generate a lot of messages to
+.I stderr
+concerning
+the form of the input and the resultant non-deterministic and deterministic
+finite automata. This option is mostly for use in maintaining
+.I flex.
+.TP
+.B \-V
+prints the version number to
+.I stdout
+and exits.
+.B \-\-version
+is a synonym for
+.B \-V.
+.TP
+.B \-7
+instructs
+.I flex
+to generate a 7-bit scanner, i.e., one which can only recognized 7-bit
+characters in its input. The advantage of using
+.B \-7
+is that the scanner's tables can be up to half the size of those generated
+using the
+.B \-8
+option (see below). The disadvantage is that such scanners often hang
+or crash if their input contains an 8-bit character.
+.IP
+Note, however, that unless you generate your scanner using the
+.B \-Cf
+or
+.B \-CF
+table compression options, use of
+.B \-7
+will save only a small amount of table space, and make your scanner
+considerably less portable.
+.I Flex's
+default behavior is to generate an 8-bit scanner unless you use the
+.B \-Cf
+or
+.B \-CF,
+in which case
+.I flex
+defaults to generating 7-bit scanners unless your site was always
+configured to generate 8-bit scanners (as will often be the case
+with non-USA sites). You can tell whether flex generated a 7-bit
+or an 8-bit scanner by inspecting the flag summary in the
+.B \-v
+output as described above.
+.IP
+Note that if you use
+.B \-Cfe
+or
+.B \-CFe
+(those table compression options, but also using equivalence classes as
+discussed see below), flex still defaults to generating an 8-bit
+scanner, since usually with these compression options full 8-bit tables
+are not much more expensive than 7-bit tables.
+.TP
+.B \-8
+instructs
+.I flex
+to generate an 8-bit scanner, i.e., one which can recognize 8-bit
+characters. This flag is only needed for scanners generated using
+.B \-Cf
+or
+.B \-CF,
+as otherwise flex defaults to generating an 8-bit scanner anyway.
+.IP
+See the discussion of
+.B \-7
+above for flex's default behavior and the tradeoffs between 7-bit
+and 8-bit scanners.
+.TP
+.B \-+
+specifies that you want flex to generate a C++
+scanner class. See the section on Generating C++ Scanners below for
+details.
+.TP
+.B \-C[aefFmr]
+controls the degree of table compression and, more generally, trade-offs
+between small scanners and fast scanners.
+.IP
+.B \-Ca
+("align") instructs flex to trade off larger tables in the
+generated scanner for faster performance because the elements of
+the tables are better aligned for memory access and computation. On some
+RISC architectures, fetching and manipulating longwords is more efficient
+than with smaller-sized units such as shortwords. This option can
+double the size of the tables used by your scanner.
+.IP
+.B \-Ce
+directs
+.I flex
+to construct
+.I equivalence classes,
+i.e., sets of characters
+which have identical lexical properties (for example, if the only
+appearance of digits in the
+.I flex
+input is in the character class
+"[0-9]" then the digits '0', '1', ..., '9' will all be put
+in the same equivalence class). Equivalence classes usually give
+dramatic reductions in the final table/object file sizes (typically
+a factor of 2-5) and are pretty cheap performance-wise (one array
+look-up per character scanned).
+.IP
+.B \-Cf
+specifies that the
+.I full
+scanner tables should be generated -
+.I flex
+should not compress the
+tables by taking advantages of similar transition functions for
+different states.
+.IP
+.B \-CF
+specifies that the alternate fast scanner representation (described
+above under the
+.B \-F
+flag)
+should be used. This option cannot be used with
+.B \-+.
+.IP
+.B \-Cm
+directs
+.I flex
+to construct
+.I meta-equivalence classes,
+which are sets of equivalence classes (or characters, if equivalence
+classes are not being used) that are commonly used together. Meta-equivalence
+classes are often a big win when using compressed tables, but they
+have a moderate performance impact (one or two "if" tests and one
+array look-up per character scanned).
+.IP
+.B \-Cr
+causes the generated scanner to
+.I bypass
+use of the standard I/O library (stdio) for input. Instead of calling
+.B fread()
+or
+.B getc(),
+the scanner will use the
+.B read()
+system call, resulting in a performance gain which varies from system
+to system, but in general is probably negligible unless you are also using
+.B \-Cf
+or
+.B \-CF.
+Using
+.B \-Cr
+can cause strange behavior if, for example, you read from
+.I yyin
+using stdio prior to calling the scanner (because the scanner will miss
+whatever text your previous reads left in the stdio input buffer).
+.IP
+.B \-Cr
+has no effect if you define
+.B YY_INPUT
+(see The Generated Scanner above).
+.IP
+A lone
+.B \-C
+specifies that the scanner tables should be compressed but neither
+equivalence classes nor meta-equivalence classes should be used.
+.IP
+The options
+.B \-Cf
+or
+.B \-CF
+and
+.B \-Cm
+do not make sense together - there is no opportunity for meta-equivalence
+classes if the table is not being compressed. Otherwise the options
+may be freely mixed, and are cumulative.
+.IP
+The default setting is
+.B \-Cem,
+which specifies that
+.I flex
+should generate equivalence classes
+and meta-equivalence classes. This setting provides the highest
+degree of table compression. You can trade off
+faster-executing scanners at the cost of larger tables with
+the following generally being true:
+.nf
+
+ slowest & smallest
+ -Cem
+ -Cm
+ -Ce
+ -C
+ -C{f,F}e
+ -C{f,F}
+ -C{f,F}a
+ fastest & largest
+
+.fi
+Note that scanners with the smallest tables are usually generated and
+compiled the quickest, so
+during development you will usually want to use the default, maximal
+compression.
+.IP
+.B \-Cfe
+is often a good compromise between speed and size for production
+scanners.
+.TP
+.B \-ooutput
+directs flex to write the scanner to the file
+.B output
+instead of
+.B lex.yy.c.
+If you combine
+.B \-o
+with the
+.B \-t
+option, then the scanner is written to
+.I stdout
+but its
+.B #line
+directives (see the
+.B \\-L
+option above) refer to the file
+.B output.
+.TP
+.B \-Pprefix
+changes the default
+.I "yy"
+prefix used by
+.I flex
+for all globally-visible variable and function names to instead be
+.I prefix.
+For example,
+.B \-Pfoo
+changes the name of
+.B yytext
+to
+.B footext.
+It also changes the name of the default output file from
+.B lex.yy.c
+to
+.B lex.foo.c.
+Here are all of the names affected:
+.nf
+
+ yy_create_buffer
+ yy_delete_buffer
+ yy_flex_debug
+ yy_init_buffer
+ yy_flush_buffer
+ yy_load_buffer_state
+ yy_switch_to_buffer
+ yyin
+ yyleng
+ yylex
+ yylineno
+ yyout
+ yyrestart
+ yytext
+ yywrap
+
+.fi
+(If you are using a C++ scanner, then only
+.B yywrap
+and
+.B yyFlexLexer
+are affected.)
+Within your scanner itself, you can still refer to the global variables
+and functions using either version of their name; but externally, they
+have the modified name.
+.IP
+This option lets you easily link together multiple
+.I flex
+programs into the same executable. Note, though, that using this
+option also renames
+.B yywrap(),
+so you now
+.I must
+either
+provide your own (appropriately-named) version of the routine for your
+scanner, or use
+.B %option noyywrap,
+as linking with
+.B \-ll
+no longer provides one for you by default.
+.TP
+.B \-Sskeleton_file
+overrides the default skeleton file from which
+.I flex
+constructs its scanners. You'll never need this option unless you are doing
+.I flex
+maintenance or development.
+.PP
+.I flex
+also provides a mechanism for controlling options within the
+scanner specification itself, rather than from the flex command-line.
+This is done by including
+.B %option
+directives in the first section of the scanner specification.
+You can specify multiple options with a single
+.B %option
+directive, and multiple directives in the first section of your flex input
+file.
+.PP
+Most options are given simply as names, optionally preceded by the
+word "no" (with no intervening whitespace) to negate their meaning.
+A number are equivalent to flex flags or their negation:
+.nf
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+
+ caseful or
+ case-sensitive opposite of -i (default)
+
+ case-insensitive or
+ caseless -i option
+
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option
+ (use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+.fi
+Some
+.B %option's
+provide features otherwise not available:
+.TP
+.B always-interactive
+instructs flex to generate a scanner which always considers its input
+"interactive". Normally, on each new input file the scanner calls
+.B isatty()
+in an attempt to determine whether
+the scanner's input source is interactive and thus should be read a
+character at a time. When this option is used, however, then no
+such call is made.
+.TP
+.B main
+directs flex to provide a default
+.B main()
+program for the scanner, which simply calls
+.B yylex().
+This option implies
+.B noyywrap
+(see below).
+.TP
+.B never-interactive
+instructs flex to generate a scanner which never considers its input
+"interactive" (again, no call made to
+.B isatty()).
+This is the opposite of
+.B always-interactive.
+.TP
+.B stack
+enables the use of start condition stacks (see Start Conditions above).
+.TP
+.B stdinit
+if set (i.e.,
+.B %option stdinit)
+initializes
+.I yyin
+and
+.I yyout
+to
+.I stdin
+and
+.I stdout,
+instead of the default of
+.I nil.
+Some existing
+.I lex
+programs depend on this behavior, even though it is not compliant with
+ANSI C, which does not require
+.I stdin
+and
+.I stdout
+to be compile-time constant.
+.TP
+.B yylineno
+directs
+.I flex
+to generate a scanner that maintains the number of the current line
+read from its input in the global variable
+.B yylineno.
+This option is implied by
+.B %option lex-compat.
+.TP
+.B yywrap
+if unset (i.e.,
+.B %option noyywrap),
+makes the scanner not call
+.B yywrap()
+upon an end-of-file, but simply assume that there are no more
+files to scan (until the user points
+.I yyin
+at a new file and calls
+.B yylex()
+again).
+.PP
+.I flex
+scans your rule actions to determine whether you use the
+.B REJECT
+or
+.B yymore()
+features. The
+.B reject
+and
+.B yymore
+options are available to override its decision as to whether you use the
+options, either by setting them (e.g.,
+.B %option reject)
+to indicate the feature is indeed used, or
+unsetting them to indicate it actually is not used
+(e.g.,
+.B %option noyymore).
+.PP
+Three options take string-delimited values, offset with '=':
+.nf
+
+ %option outfile="ABC"
+
+.fi
+is equivalent to
+.B -oABC,
+and
+.nf
+
+ %option prefix="XYZ"
+
+.fi
+is equivalent to
+.B -PXYZ.
+Finally,
+.nf
+
+ %option yyclass="foo"
+
+.fi
+only applies when generating a C++ scanner (
+.B \-+
+option). It informs
+.I flex
+that you have derived
+.B foo
+as a subclass of
+.B yyFlexLexer,
+so
+.I flex
+will place your actions in the member function
+.B foo::yylex()
+instead of
+.B yyFlexLexer::yylex().
+It also generates a
+.B yyFlexLexer::yylex()
+member function that emits a run-time error (by invoking
+.B yyFlexLexer::LexerError())
+if called.
+See Generating C++ Scanners, below, for additional information.
+.PP
+A number of options are available for lint purists who want to suppress
+the appearance of unneeded routines in the generated scanner. Each of the
+following, if unset
+(e.g.,
+.B %option nounput
+), results in the corresponding routine not appearing in
+the generated scanner:
+.nf
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+.fi
+(though
+.B yy_push_state()
+and friends won't appear anyway unless you use
+.B %option stack).
+.SH PERFORMANCE CONSIDERATIONS
+The main design goal of
+.I flex
+is that it generate high-performance scanners. It has been optimized
+for dealing well with large sets of rules. Aside from the effects on
+scanner speed of the table compression
+.B \-C
+options outlined above,
+there are a number of options/actions which degrade performance. These
+are, from most expensive to least:
+.nf
+
+ REJECT
+ %option yylineno
+ arbitrary trailing context
+
+ pattern sets that require backing up
+ %array
+ %option interactive
+ %option always-interactive
+
+ '^' beginning-of-line operator
+ yymore()
+
+.fi
+with the first three all being quite expensive and the last two
+being quite cheap. Note also that
+.B unput()
+is implemented as a routine call that potentially does quite a bit of
+work, while
+.B yyless()
+is a quite-cheap macro; so if just putting back some excess text you
+scanned, use
+.B yyless().
+.PP
+.B REJECT
+should be avoided at all costs when performance is important.
+It is a particularly expensive option.
+.PP
+Getting rid of backing up is messy and often may be an enormous
+amount of work for a complicated scanner. In principal, one begins
+by using the
+.B \-b
+flag to generate a
+.I lex.backup
+file. For example, on the input
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+.fi
+the file looks like:
+.nf
+
+ State #6 is non-accepting -
+ associated rule line numbers:
+ 2 3
+ out-transitions: [ o ]
+ jam-transitions: EOF [ \\001-n p-\\177 ]
+
+ State #8 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ a ]
+ jam-transitions: EOF [ \\001-` b-\\177 ]
+
+ State #9 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ r ]
+ jam-transitions: EOF [ \\001-q s-\\177 ]
+
+ Compressed tables always back up.
+
+.fi
+The first few lines tell us that there's a scanner state in
+which it can make a transition on an 'o' but not on any other
+character, and that in that state the currently scanned text does not match
+any rule. The state occurs when trying to match the rules found
+at lines 2 and 3 in the input file.
+If the scanner is in that state and then reads
+something other than an 'o', it will have to back up to find
+a rule which is matched. With
+a bit of headscratching one can see that this must be the
+state it's in when it has seen "fo". When this has happened,
+if anything other than another 'o' is seen, the scanner will
+have to back up to simply match the 'f' (by the default rule).
+.PP
+The comment regarding State #8 indicates there's a problem
+when "foob" has been scanned. Indeed, on any character other
+than an 'a', the scanner will have to back up to accept "foo".
+Similarly, the comment for State #9 concerns when "fooba" has
+been scanned and an 'r' does not follow.
+.PP
+The final comment reminds us that there's no point going to
+all the trouble of removing backing up from the rules unless
+we're using
+.B \-Cf
+or
+.B \-CF,
+since there's no performance gain doing so with compressed scanners.
+.PP
+The way to remove the backing up is to add "error" rules:
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ fooba |
+ foob |
+ fo {
+ /* false alarm, not really a keyword */
+ return TOK_ID;
+ }
+
+.fi
+.PP
+Eliminating backing up among a list of keywords can also be
+done using a "catch-all" rule:
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ [a-z]+ return TOK_ID;
+
+.fi
+This is usually the best solution when appropriate.
+.PP
+Backing up messages tend to cascade.
+With a complicated set of rules it's not uncommon to get hundreds
+of messages. If one can decipher them, though, it often
+only takes a dozen or so rules to eliminate the backing up (though
+it's easy to make a mistake and have an error rule accidentally match
+a valid token. A possible future
+.I flex
+feature will be to automatically add rules to eliminate backing up).
+.PP
+It's important to keep in mind that you gain the benefits of eliminating
+backing up only if you eliminate
+.I every
+instance of backing up. Leaving just one means you gain nothing.
+.PP
+.I Variable
+trailing context (where both the leading and trailing parts do not have
+a fixed length) entails almost the same performance loss as
+.B REJECT
+(i.e., substantial). So when possible a rule like:
+.nf
+
+ %%
+ mouse|rat/(cat|dog) run();
+
+.fi
+is better written:
+.nf
+
+ %%
+ mouse/cat|dog run();
+ rat/cat|dog run();
+
+.fi
+or as
+.nf
+
+ %%
+ mouse|rat/cat run();
+ mouse|rat/dog run();
+
+.fi
+Note that here the special '|' action does
+.I not
+provide any savings, and can even make things worse (see
+Deficiencies / Bugs below).
+.LP
+Another area where the user can increase a scanner's performance
+(and one that's easier to implement) arises from the fact that
+the longer the tokens matched, the faster the scanner will run.
+This is because with long tokens the processing of most input
+characters takes place in the (short) inner scanning loop, and
+does not often have to go through the additional work of setting up
+the scanning environment (e.g.,
+.B yytext)
+for the action. Recall the scanner for C comments:
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]*
+ <comment>"*"+[^*/\\n]*
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+This could be sped up by writing it as:
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]*
+ <comment>[^*\\n]*\\n ++line_num;
+ <comment>"*"+[^*/\\n]*
+ <comment>"*"+[^*/\\n]*\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+Now instead of each newline requiring the processing of another
+action, recognizing the newlines is "distributed" over the other rules
+to keep the matched text as long as possible. Note that
+.I adding
+rules does
+.I not
+slow down the scanner! The speed of the scanner is independent
+of the number of rules or (modulo the considerations given at the
+beginning of this section) how complicated the rules are with
+regard to operators such as '*' and '|'.
+.PP
+A final example in speeding up a scanner: suppose you want to scan
+through a file containing identifiers and keywords, one per line
+and with no other extraneous characters, and recognize all the
+keywords. A natural first approach is:
+.nf
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ .|\\n /* it's not a keyword */
+
+.fi
+To eliminate the back-tracking, introduce a catch-all rule:
+.nf
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ [a-z]+ |
+ .|\\n /* it's not a keyword */
+
+.fi
+Now, if it's guaranteed that there's exactly one word per line,
+then we can reduce the total number of matches by a half by
+merging in the recognition of newlines with that of the other
+tokens:
+.nf
+
+ %%
+ asm\\n |
+ auto\\n |
+ break\\n |
+ ... etc ...
+ volatile\\n |
+ while\\n /* it's a keyword */
+
+ [a-z]+\\n |
+ .|\\n /* it's not a keyword */
+
+.fi
+One has to be careful here, as we have now reintroduced backing up
+into the scanner. In particular, while
+.I we
+know that there will never be any characters in the input stream
+other than letters or newlines,
+.I flex
+can't figure this out, and it will plan for possibly needing to back up
+when it has scanned a token like "auto" and then the next character
+is something other than a newline or a letter. Previously it would
+then just match the "auto" rule and be done, but now it has no "auto"
+rule, only a "auto\\n" rule. To eliminate the possibility of backing up,
+we could either duplicate all rules but without final newlines, or,
+since we never expect to encounter such an input and therefore don't
+how it's classified, we can introduce one more catch-all rule, this
+one which doesn't include a newline:
+.nf
+
+ %%
+ asm\\n |
+ auto\\n |
+ break\\n |
+ ... etc ...
+ volatile\\n |
+ while\\n /* it's a keyword */
+
+ [a-z]+\\n |
+ [a-z]+ |
+ .|\\n /* it's not a keyword */
+
+.fi
+Compiled with
+.B \-Cf,
+this is about as fast as one can get a
+.I flex
+scanner to go for this particular problem.
+.PP
+A final note:
+.I flex
+is slow when matching NUL's, particularly when a token contains
+multiple NUL's.
+It's best to write rules which match
+.I short
+amounts of text if it's anticipated that the text will often include NUL's.
+.PP
+Another final note regarding performance: as mentioned above in the section
+How the Input is Matched, dynamically resizing
+.B yytext
+to accommodate huge tokens is a slow process because it presently requires that
+the (huge) token be rescanned from the beginning. Thus if performance is
+vital, you should attempt to match "large" quantities of text but not
+"huge" quantities, where the cutoff between the two is at about 8K
+characters/token.
+.SH GENERATING C++ SCANNERS
+.I flex
+provides two different ways to generate scanners for use with C++. The
+first way is to simply compile a scanner generated by
+.I flex
+using a C++ compiler instead of a C compiler. You should not encounter
+any compilations errors (please report any you find to the email address
+given in the Author section below). You can then use C++ code in your
+rule actions instead of C code. Note that the default input source for
+your scanner remains
+.I yyin,
+and default echoing is still done to
+.I yyout.
+Both of these remain
+.I FILE *
+variables and not C++
+.I streams.
+.PP
+You can also use
+.I flex
+to generate a C++ scanner class, using the
+.B \-+
+option (or, equivalently,
+.B %option c++),
+which is automatically specified if the name of the flex
+executable ends in a '+', such as
+.I flex++.
+When using this option, flex defaults to generating the scanner to the file
+.B lex.yy.cc
+instead of
+.B lex.yy.c.
+The generated scanner includes the header file
+.I FlexLexer.h,
+which defines the interface to two C++ classes.
+.PP
+The first class,
+.B FlexLexer,
+provides an abstract base class defining the general scanner class
+interface. It provides the following member functions:
+.TP
+.B const char* YYText()
+returns the text of the most recently matched token, the equivalent of
+.B yytext.
+.TP
+.B int YYLeng()
+returns the length of the most recently matched token, the equivalent of
+.B yyleng.
+.TP
+.B int lineno() const
+returns the current input line number
+(see
+.B %option yylineno),
+or
+.B 1
+if
+.B %option yylineno
+was not used.
+.TP
+.B void set_debug( int flag )
+sets the debugging flag for the scanner, equivalent to assigning to
+.B yy_flex_debug
+(see the Options section above). Note that you must build the scanner
+using
+.B %option debug
+to include debugging information in it.
+.TP
+.B int debug() const
+returns the current setting of the debugging flag.
+.PP
+Also provided are member functions equivalent to
+.B yy_switch_to_buffer(),
+.B yy_create_buffer()
+(though the first argument is an
+.B istream*
+object pointer and not a
+.B FILE*),
+.B yy_flush_buffer(),
+.B yy_delete_buffer(),
+and
+.B yyrestart()
+(again, the first argument is a
+.B istream*
+object pointer).
+.PP
+The second class defined in
+.I FlexLexer.h
+is
+.B yyFlexLexer,
+which is derived from
+.B FlexLexer.
+It defines the following additional member functions:
+.TP
+.B
+yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
+constructs a
+.B yyFlexLexer
+object using the given streams for input and output. If not specified,
+the streams default to
+.B cin
+and
+.B cout,
+respectively.
+.TP
+.B virtual int yylex()
+performs the same role is
+.B yylex()
+does for ordinary flex scanners: it scans the input stream, consuming
+tokens, until a rule's action returns a value. If you derive a subclass
+.B S
+from
+.B yyFlexLexer
+and want to access the member functions and variables of
+.B S
+inside
+.B yylex(),
+then you need to use
+.B %option yyclass="S"
+to inform
+.I flex
+that you will be using that subclass instead of
+.B yyFlexLexer.
+In this case, rather than generating
+.B yyFlexLexer::yylex(),
+.I flex
+generates
+.B S::yylex()
+(and also generates a dummy
+.B yyFlexLexer::yylex()
+that calls
+.B yyFlexLexer::LexerError()
+if called).
+.TP
+.B
+virtual void switch_streams(istream* new_in = 0,
+.B
+ostream* new_out = 0)
+reassigns
+.B yyin
+to
+.B new_in
+(if non-nil)
+and
+.B yyout
+to
+.B new_out
+(ditto), deleting the previous input buffer if
+.B yyin
+is reassigned.
+.TP
+.B
+int yylex( istream* new_in, ostream* new_out = 0 )
+first switches the input streams via
+.B switch_streams( new_in, new_out )
+and then returns the value of
+.B yylex().
+.PP
+In addition,
+.B yyFlexLexer
+defines the following protected virtual functions which you can redefine
+in derived classes to tailor the scanner:
+.TP
+.B
+virtual int LexerInput( char* buf, int max_size )
+reads up to
+.B max_size
+characters into
+.B buf
+and returns the number of characters read. To indicate end-of-input,
+return 0 characters. Note that "interactive" scanners (see the
+.B \-B
+and
+.B \-I
+flags) define the macro
+.B YY_INTERACTIVE.
+If you redefine
+.B LexerInput()
+and need to take different actions depending on whether or not
+the scanner might be scanning an interactive input source, you can
+test for the presence of this name via
+.B #ifdef.
+.TP
+.B
+virtual void LexerOutput( const char* buf, int size )
+writes out
+.B size
+characters from the buffer
+.B buf,
+which, while NUL-terminated, may also contain "internal" NUL's if
+the scanner's rules can match text with NUL's in them.
+.TP
+.B
+virtual void LexerError( const char* msg )
+reports a fatal error message. The default version of this function
+writes the message to the stream
+.B cerr
+and exits.
+.PP
+Note that a
+.B yyFlexLexer
+object contains its
+.I entire
+scanning state. Thus you can use such objects to create reentrant
+scanners. You can instantiate multiple instances of the same
+.B yyFlexLexer
+class, and you can also combine multiple C++ scanner classes together
+in the same program using the
+.B \-P
+option discussed above.
+.PP
+Finally, note that the
+.B %array
+feature is not available to C++ scanner classes; you must use
+.B %pointer
+(the default).
+.PP
+Here is an example of a simple C++ scanner:
+.nf
+
+ // An example of using the flex C++ scanner class.
+
+ %{
+ int mylineno = 0;
+ %}
+
+ string \\"[^\\n"]+\\"
+
+ ws [ \\t]+
+
+ alpha [A-Za-z]
+ dig [0-9]
+ name ({alpha}|{dig}|\\$)({alpha}|{dig}|[_.\\-/$])*
+ num1 [-+]?{dig}+\\.?([eE][-+]?{dig}+)?
+ num2 [-+]?{dig}*\\.{dig}+([eE][-+]?{dig}+)?
+ number {num1}|{num2}
+
+ %%
+
+ {ws} /* skip blanks and tabs */
+
+ "/*" {
+ int c;
+
+ while((c = yyinput()) != 0)
+ {
+ if(c == '\\n')
+ ++mylineno;
+
+ else if(c == '*')
+ {
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+ {number} cout << "number " << YYText() << '\\n';
+
+ \\n mylineno++;
+
+ {name} cout << "name " << YYText() << '\\n';
+
+ {string} cout << "string " << YYText() << '\\n';
+
+ %%
+
+ int main( int /* argc */, char** /* argv */ )
+ {
+ FlexLexer* lexer = new yyFlexLexer;
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ }
+.fi
+If you want to create multiple (different) lexer classes, you use the
+.B \-P
+flag (or the
+.B prefix=
+option) to rename each
+.B yyFlexLexer
+to some other
+.B xxFlexLexer.
+You then can include
+.B <FlexLexer.h>
+in your other sources once per lexer class, first renaming
+.B yyFlexLexer
+as follows:
+.nf
+
+ #undef yyFlexLexer
+ #define yyFlexLexer xxFlexLexer
+ #include <FlexLexer.h>
+
+ #undef yyFlexLexer
+ #define yyFlexLexer zzFlexLexer
+ #include <FlexLexer.h>
+
+.fi
+if, for example, you used
+.B %option prefix="xx"
+for one of your scanners and
+.B %option prefix="zz"
+for the other.
+.PP
+IMPORTANT: the present form of the scanning class is
+.I experimental
+and may change considerably between major releases.
+.SH INCOMPATIBILITIES WITH LEX AND POSIX
+.I flex
+is a rewrite of the AT&T Unix
+.I lex
+tool (the two implementations do not share any code, though),
+with some extensions and incompatibilities, both of which
+are of concern to those who wish to write scanners acceptable
+to either implementation. Flex is fully compliant with the POSIX
+.I lex
+specification, except that when using
+.B %pointer
+(the default), a call to
+.B unput()
+destroys the contents of
+.B yytext,
+which is counter to the POSIX specification.
+.PP
+In this section we discuss all of the known areas of incompatibility
+between flex, AT&T lex, and the POSIX specification.
+.PP
+.I flex's
+.B \-l
+option turns on maximum compatibility with the original AT&T
+.I lex
+implementation, at the cost of a major loss in the generated scanner's
+performance. We note below which incompatibilities can be overcome
+using the
+.B \-l
+option.
+.PP
+.I flex
+is fully compatible with
+.I lex
+with the following exceptions:
+.IP -
+The undocumented
+.I lex
+scanner internal variable
+.B yylineno
+is not supported unless
+.B \-l
+or
+.B %option yylineno
+is used.
+.IP
+.B yylineno
+should be maintained on a per-buffer basis, rather than a per-scanner
+(single global variable) basis.
+.IP
+.B yylineno
+is not part of the POSIX specification.
+.IP -
+The
+.B input()
+routine is not redefinable, though it may be called to read characters
+following whatever has been matched by a rule. If
+.B input()
+encounters an end-of-file the normal
+.B yywrap()
+processing is done. A ``real'' end-of-file is returned by
+.B input()
+as
+.I EOF.
+.IP
+Input is instead controlled by defining the
+.B YY_INPUT
+macro.
+.IP
+The
+.I flex
+restriction that
+.B input()
+cannot be redefined is in accordance with the POSIX specification,
+which simply does not specify any way of controlling the
+scanner's input other than by making an initial assignment to
+.I yyin.
+.IP -
+The
+.B unput()
+routine is not redefinable. This restriction is in accordance with POSIX.
+.IP -
+.I flex
+scanners are not as reentrant as
+.I lex
+scanners. In particular, if you have an interactive scanner and
+an interrupt handler which long-jumps out of the scanner, and
+the scanner is subsequently called again, you may get the following
+message:
+.nf
+
+ fatal flex scanner internal error--end of buffer missed
+
+.fi
+To reenter the scanner, first use
+.nf
+
+ yyrestart( yyin );
+
+.fi
+Note that this call will throw away any buffered input; usually this
+isn't a problem with an interactive scanner.
+.IP
+Also note that flex C++ scanner classes
+.I are
+reentrant, so if using C++ is an option for you, you should use
+them instead. See "Generating C++ Scanners" above for details.
+.IP -
+.B output()
+is not supported.
+Output from the
+.B ECHO
+macro is done to the file-pointer
+.I yyout
+(default
+.I stdout).
+.IP
+.B output()
+is not part of the POSIX specification.
+.IP -
+.I lex
+does not support exclusive start conditions (%x), though they
+are in the POSIX specification.
+.IP -
+When definitions are expanded,
+.I flex
+encloses them in parentheses.
+With lex, the following:
+.nf
+
+ NAME [A-Z][A-Z0-9]*
+ %%
+ foo{NAME}? printf( "Found it\\n" );
+ %%
+
+.fi
+will not match the string "foo" because when the macro
+is expanded the rule is equivalent to "foo[A-Z][A-Z0-9]*?"
+and the precedence is such that the '?' is associated with
+"[A-Z0-9]*". With
+.I flex,
+the rule will be expanded to
+"foo([A-Z][A-Z0-9]*)?" and so the string "foo" will match.
+.IP
+Note that if the definition begins with
+.B ^
+or ends with
+.B $
+then it is
+.I not
+expanded with parentheses, to allow these operators to appear in
+definitions without losing their special meanings. But the
+.B <s>, /,
+and
+.B <<EOF>>
+operators cannot be used in a
+.I flex
+definition.
+.IP
+Using
+.B \-l
+results in the
+.I lex
+behavior of no parentheses around the definition.
+.IP
+The POSIX specification is that the definition be enclosed in parentheses.
+.IP -
+Some implementations of
+.I lex
+allow a rule's action to begin on a separate line, if the rule's pattern
+has trailing whitespace:
+.nf
+
+ %%
+ foo|bar<space here>
+ { foobar_action(); }
+
+.fi
+.I flex
+does not support this feature.
+.IP -
+The
+.I lex
+.B %r
+(generate a Ratfor scanner) option is not supported. It is not part
+of the POSIX specification.
+.IP -
+After a call to
+.B unput(),
+.I yytext
+is undefined until the next token is matched, unless the scanner
+was built using
+.B %array.
+This is not the case with
+.I lex
+or the POSIX specification. The
+.B \-l
+option does away with this incompatibility.
+.IP -
+The precedence of the
+.B {}
+(numeric range) operator is different.
+.I lex
+interprets "abc{1,3}" as "match one, two, or
+three occurrences of 'abc'", whereas
+.I flex
+interprets it as "match 'ab'
+followed by one, two, or three occurrences of 'c'". The latter is
+in agreement with the POSIX specification.
+.IP -
+The precedence of the
+.B ^
+operator is different.
+.I lex
+interprets "^foo|bar" as "match either 'foo' at the beginning of a line,
+or 'bar' anywhere", whereas
+.I flex
+interprets it as "match either 'foo' or 'bar' if they come at the beginning
+of a line". The latter is in agreement with the POSIX specification.
+.IP -
+The special table-size declarations such as
+.B %a
+supported by
+.I lex
+are not required by
+.I flex
+scanners;
+.I flex
+ignores them.
+.IP -
+The name
+.bd
+FLEX_SCANNER
+is #define'd so scanners may be written for use with either
+.I flex
+or
+.I lex.
+Scanners also include
+.B YY_FLEX_MAJOR_VERSION
+and
+.B YY_FLEX_MINOR_VERSION
+indicating which version of
+.I flex
+generated the scanner
+(for example, for the 2.5 release, these defines would be 2 and 5
+respectively).
+.PP
+The following
+.I flex
+features are not included in
+.I lex
+or the POSIX specification:
+.nf
+
+ C++ scanners
+ %option
+ start condition scopes
+ start condition stacks
+ interactive/non-interactive scanners
+ yy_scan_string() and friends
+ yyterminate()
+ yy_set_interactive()
+ yy_set_bol()
+ YY_AT_BOL()
+ <<EOF>>
+ <*>
+ YY_DECL
+ YY_START
+ YY_USER_ACTION
+ YY_USER_INIT
+ #line directives
+ %{}'s around actions
+ multiple actions on a line
+
+.fi
+plus almost all of the flex flags.
+The last feature in the list refers to the fact that with
+.I flex
+you can put multiple actions on the same line, separated with
+semi-colons, while with
+.I lex,
+the following
+.nf
+
+ foo handle_foo(); ++num_foos_seen;
+
+.fi
+is (rather surprisingly) truncated to
+.nf
+
+ foo handle_foo();
+
+.fi
+.I flex
+does not truncate the action. Actions that are not enclosed in
+braces are simply terminated at the end of the line.
+.SH DIAGNOSTICS
+.PP
+.I warning, rule cannot be matched
+indicates that the given rule
+cannot be matched because it follows other rules that will
+always match the same text as it. For
+example, in the following "foo" cannot be matched because it comes after
+an identifier "catch-all" rule:
+.nf
+
+ [a-z]+ got_identifier();
+ foo got_foo();
+
+.fi
+Using
+.B REJECT
+in a scanner suppresses this warning.
+.PP
+.I warning,
+.B \-s
+.I
+option given but default rule can be matched
+means that it is possible (perhaps only in a particular start condition)
+that the default rule (match any single character) is the only one
+that will match a particular input. Since
+.B \-s
+was given, presumably this is not intended.
+.PP
+.I reject_used_but_not_detected undefined
+or
+.I yymore_used_but_not_detected undefined -
+These errors can occur at compile time. They indicate that the
+scanner uses
+.B REJECT
+or
+.B yymore()
+but that
+.I flex
+failed to notice the fact, meaning that
+.I flex
+scanned the first two sections looking for occurrences of these actions
+and failed to find any, but somehow you snuck some in (via a #include
+file, for example). Use
+.B %option reject
+or
+.B %option yymore
+to indicate to flex that you really do use these features.
+.PP
+.I flex scanner jammed -
+a scanner compiled with
+.B \-s
+has encountered an input string which wasn't matched by
+any of its rules. This error can also occur due to internal problems.
+.PP
+.I token too large, exceeds YYLMAX -
+your scanner uses
+.B %array
+and one of its rules matched a string longer than the
+.B YYLMAX
+constant (8K bytes by default). You can increase the value by
+#define'ing
+.B YYLMAX
+in the definitions section of your
+.I flex
+input.
+.PP
+.I scanner requires \-8 flag to
+.I use the character 'x' -
+Your scanner specification includes recognizing the 8-bit character
+.I 'x'
+and you did not specify the \-8 flag, and your scanner defaulted to 7-bit
+because you used the
+.B \-Cf
+or
+.B \-CF
+table compression options. See the discussion of the
+.B \-7
+flag for details.
+.PP
+.I flex scanner push-back overflow -
+you used
+.B unput()
+to push back so much text that the scanner's buffer could not hold
+both the pushed-back text and the current token in
+.B yytext.
+Ideally the scanner should dynamically resize the buffer in this case, but at
+present it does not.
+.PP
+.I
+input buffer overflow, can't enlarge buffer because scanner uses REJECT -
+the scanner was working on matching an extremely large token and needed
+to expand the input buffer. This doesn't work with scanners that use
+.B
+REJECT.
+.PP
+.I
+fatal flex scanner internal error--end of buffer missed -
+This can occur in an scanner which is reentered after a long-jump
+has jumped out (or over) the scanner's activation frame. Before
+reentering the scanner, use:
+.nf
+
+ yyrestart( yyin );
+
+.fi
+or, as noted above, switch to using the C++ scanner class.
+.PP
+.I too many start conditions in <> construct! -
+you listed more start conditions in a <> construct than exist (so
+you must have listed at least one of them twice).
+.SH FILES
+.TP
+.B \-ll
+library with which scanners must be linked.
+.TP
+.I lex.yy.c
+generated scanner (called
+.I lexyy.c
+on some systems).
+.TP
+.I lex.yy.cc
+generated C++ scanner class, when using
+.B -+.
+.TP
+.I <FlexLexer.h>
+header file defining the C++ scanner base class,
+.B FlexLexer,
+and its derived class,
+.B yyFlexLexer.
+.TP
+.I flex.skl
+skeleton scanner. This file is only used when building flex, not when
+flex executes.
+.TP
+.I lex.backup
+backing-up information for
+.B \-b
+flag (called
+.I lex.bck
+on some systems).
+.SH DEFICIENCIES / BUGS
+.PP
+Some trailing context
+patterns cannot be properly matched and generate
+warning messages ("dangerous trailing context"). These are
+patterns where the ending of the
+first part of the rule matches the beginning of the second
+part, such as "zx*/xy*", where the 'x*' matches the 'x' at
+the beginning of the trailing context. (Note that the POSIX draft
+states that the text matched by such patterns is undefined.)
+.PP
+For some trailing context rules, parts which are actually fixed-length are
+not recognized as such, leading to the abovementioned performance loss.
+In particular, parts using '|' or {n} (such as "foo{3}") are always
+considered variable-length.
+.PP
+Combining trailing context with the special '|' action can result in
+.I fixed
+trailing context being turned into the more expensive
+.I variable
+trailing context. For example, in the following:
+.nf
+
+ %%
+ abc |
+ xyz/def
+
+.fi
+.PP
+Use of
+.B unput()
+invalidates yytext and yyleng, unless the
+.B %array
+directive
+or the
+.B \-l
+option has been used.
+.PP
+Pattern-matching of NUL's is substantially slower than matching other
+characters.
+.PP
+Dynamic resizing of the input buffer is slow, as it entails rescanning
+all the text matched so far by the current (generally huge) token.
+.PP
+Due to both buffering of input and read-ahead, you cannot intermix
+calls to <stdio.h> routines, such as, for example,
+.B getchar(),
+with
+.I flex
+rules and expect it to work. Call
+.B input()
+instead.
+.PP
+The total table entries listed by the
+.B \-v
+flag excludes the number of table entries needed to determine
+what rule has been matched. The number of entries is equal
+to the number of DFA states if the scanner does not use
+.B REJECT,
+and somewhat greater than the number of states if it does.
+.PP
+.B REJECT
+cannot be used with the
+.B \-f
+or
+.B \-F
+options.
+.PP
+The
+.I flex
+internal algorithms need documentation.
+.SH SEE ALSO
+.PP
+lex(1), yacc(1), sed(1), awk(1).
+.PP
+John Levine, Tony Mason, and Doug Brown,
+.I Lex & Yacc,
+O'Reilly and Associates. Be sure to get the 2nd edition.
+.PP
+M. E. Lesk and E. Schmidt,
+.I LEX \- Lexical Analyzer Generator
+.PP
+Alfred Aho, Ravi Sethi and Jeffrey Ullman,
+.I Compilers: Principles, Techniques and Tools,
+Addison-Wesley (1986). Describes the pattern-matching techniques used by
+.I flex
+(deterministic finite automata).
+.SH AUTHOR
+Vern Paxson, with the help of many ideas and much inspiration from
+Van Jacobson. Original version by Jef Poskanzer. The fast table
+representation is a partial implementation of a design done by Van
+Jacobson. The implementation was done by Kevin Gong and Vern Paxson.
+.PP
+Thanks to the many
+.I flex
+beta-testers, feedbackers, and contributors, especially Francois Pinard,
+Casey Leedom,
+Robert Abramovitz,
+Stan Adermann, Terry Allen, David Barker-Plummer, John Basrai,
+Neal Becker, Nelson H.F. Beebe, benson@odi.com,
+Karl Berry, Peter A. Bigot, Simon Blanchard,
+Keith Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher,
+Brian Clapper, J.T. Conklin,
+Jason Coughlin, Bill Cox, Nick Cropper, Dave Curtis, Scott David
+Daniels, Chris G. Demetriou, Theo Deraadt,
+Mike Donahue, Chuck Doucette, Tom Epperly, Leo Eskin,
+Chris Faylor, Chris Flatters, Jon Forrest, Jeffrey Friedl,
+Joe Gayda, Kaveh R. Ghazi, Wolfgang Glunz,
+Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer Griebel,
+Jan Hajic, Charles Hemphill, NORO Hideo,
+Jarkko Hietaniemi, Scott Hofmann,
+Jeff Honig, Dana Hudes, Eric Hughes, John Interrante,
+Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,
+Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane,
+Amir Katz, ken@ken.hilco.com, Kevin B. Kenny,
+Steve Kirsch, Winfried Koenig, Marq Kole, Ronald Lamprecht,
+Greg Lee, Rohan Lenard, Craig Leres, John Levine, Steve Liddle,
+David Loffredo, Mike Long,
+Mohamed el Lozy, Brian Madsen, Malte, Joe Marshall,
+Bengt Martensson, Chris Metcalf,
+Luke Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum,
+G.T. Nicol, Landon Noll, James Nordby, Marc Nozell,
+Richard Ohnemus, Karsten Pahnke,
+Sven Panne, Roland Pesch, Walter Pelissero, Gaumond
+Pierre, Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha,
+Frederic Raimbault, Pat Rankin, Rick Richardson,
+Kevin Rodgers, Kai Uwe Rommel, Jim Roskind, Alberto Santini,
+Andreas Scherer, Darrell Schiebel, Raf Schietekat,
+Doug Schmidt, Philippe Schnoebelen, Andreas Schwab,
+Larry Schwimmer, Alex Siegel, Eckehard Stolz, Jan-Erik Strvmquist,
+Mike Stump, Paul Stuart, Dave Tallman, Ian Lance Taylor,
+Chris Thewalt, Richard M. Timoney, Jodi Tsai,
+Paul Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms, Kent Williams, Ken
+Yap, Ron Zellar, Nathan Zelle, David Zuhn,
+and those whose names have slipped my marginal
+mail-archiving skills but whose contributions are appreciated all the
+same.
+.PP
+Thanks to Keith Bostic, Jon Forrest, Noah Friedman,
+John Gilmore, Craig Leres, John Levine, Bob Mulcahy, G.T.
+Nicol, Francois Pinard, Rich Salz, and Richard Stallman for help with various
+distribution headaches.
+.PP
+Thanks to Esmond Pitt and Earle Horton for 8-bit character support; to
+Benson Margulies and Fred Burke for C++ support; to Kent Williams and Tom
+Epperly for C++ class support; to Ove Ewerlid for support of NUL's; and to
+Eric Hughes for support of multiple buffers.
+.PP
+This work was primarily done when I was with the Real Time Systems Group
+at the Lawrence Berkeley Laboratory in Berkeley, CA. Many thanks to all there
+for the support I received.
+.PP
+Send comments to vern@ee.lbl.gov.
diff --git a/usr.bin/lex/lib/Makefile b/usr.bin/lex/lib/Makefile
new file mode 100644
index 0000000..8fd744f
--- /dev/null
+++ b/usr.bin/lex/lib/Makefile
@@ -0,0 +1,16 @@
+# $Id: Makefile,v 1.5 1997/02/22 19:55:36 peter Exp $
+
+LIB= ln
+SRCS= libmain.c libyywrap.c
+NOPIC= yes
+
+LINKS= ${LIBDIR}/libln.a ${LIBDIR}/libl.a
+LINKS+= ${LIBDIR}/libln.a ${LIBDIR}/libfl.a
+
+.if !defined(NOPROFILE)
+LINKS+= ${LIBDIR}/libln_p.a ${LIBDIR}/libl_p.a
+LINKS+= ${LIBDIR}/libln_p.a ${LIBDIR}/libfl_p.a
+.endif
+
+.include <bsd.lib.mk>
+
diff --git a/usr.bin/lex/lib/libmain.c b/usr.bin/lex/lib/libmain.c
new file mode 100644
index 0000000..6c43b08
--- /dev/null
+++ b/usr.bin/lex/lib/libmain.c
@@ -0,0 +1,15 @@
+/* libmain - flex run-time support library "main" function */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/libmain.c,v 1.4 95/09/27 12:47:55 vern Exp $ */
+
+extern int yylex();
+
+int main( argc, argv )
+int argc;
+char *argv[];
+ {
+ while ( yylex() != 0 )
+ ;
+
+ return 0;
+ }
diff --git a/usr.bin/lex/lib/libyywrap.c b/usr.bin/lex/lib/libyywrap.c
new file mode 100644
index 0000000..b18f54e
--- /dev/null
+++ b/usr.bin/lex/lib/libyywrap.c
@@ -0,0 +1,8 @@
+/* libyywrap - flex run-time support library "yywrap" function */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/libyywrap.c,v 1.1 93/10/02 15:23:09 vern Exp $ */
+
+int yywrap()
+ {
+ return 1;
+ }
diff --git a/usr.bin/lex/main.c b/usr.bin/lex/main.c
new file mode 100644
index 0000000..bc1e8c9
--- /dev/null
+++ b/usr.bin/lex/main.c
@@ -0,0 +1,1177 @@
+/* flex - tool to generate fast lexical analyzers */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/main.c,v 1.1.1.2 1996/06/19 20:26:16 nate Exp $ */
+
+
+#include "flexdef.h"
+#include "version.h"
+
+static char flex_version[] = FLEX_VERSION;
+
+
+/* declare functions that have forward references */
+
+void flexinit PROTO((int, char**));
+void readin PROTO((void));
+void set_up_initial_allocations PROTO((void));
+
+#ifdef NEED_ARGV_FIXUP
+extern void argv_fixup PROTO((int *, char ***));
+#endif
+
+
+/* these globals are all defined and commented in flexdef.h */
+int printstats, syntaxerror, eofseen, ddebug, trace, nowarn, spprdflt;
+int interactive, caseins, lex_compat, do_yylineno, useecs, fulltbl, usemecs;
+int fullspd, gen_line_dirs, performance_report, backing_up_report;
+int C_plus_plus, long_align, use_read, yytext_is_array, do_yywrap, csize;
+int yymore_used, reject, real_reject, continued_action, in_rule;
+int yymore_really_used, reject_really_used;
+int datapos, dataline, linenum, out_linenum;
+FILE *skelfile = NULL;
+int skel_ind = 0;
+char *action_array;
+int action_size, defs1_offset, prolog_offset, action_offset, action_index;
+char *infilename = NULL, *outfilename = NULL;
+int did_outfilename;
+char *prefix, *yyclass;
+int do_stdinit, use_stdout;
+int onestate[ONE_STACK_SIZE], onesym[ONE_STACK_SIZE];
+int onenext[ONE_STACK_SIZE], onedef[ONE_STACK_SIZE], onesp;
+int current_mns, current_max_rules;
+int num_rules, num_eof_rules, default_rule, lastnfa;
+int *firstst, *lastst, *finalst, *transchar, *trans1, *trans2;
+int *accptnum, *assoc_rule, *state_type;
+int *rule_type, *rule_linenum, *rule_useful;
+int current_state_type;
+int variable_trailing_context_rules;
+int numtemps, numprots, protprev[MSP], protnext[MSP], prottbl[MSP];
+int protcomst[MSP], firstprot, lastprot, protsave[PROT_SAVE_SIZE];
+int numecs, nextecm[CSIZE + 1], ecgroup[CSIZE + 1], nummecs, tecfwd[CSIZE + 1];
+int tecbck[CSIZE + 1];
+int lastsc, *scset, *scbol, *scxclu, *sceof;
+int current_max_scs;
+char **scname;
+int current_max_dfa_size, current_max_xpairs;
+int current_max_template_xpairs, current_max_dfas;
+int lastdfa, *nxt, *chk, *tnxt;
+int *base, *def, *nultrans, NUL_ec, tblend, firstfree, **dss, *dfasiz;
+union dfaacc_union *dfaacc;
+int *accsiz, *dhash, numas;
+int numsnpairs, jambase, jamstate;
+int lastccl, *cclmap, *ccllen, *cclng, cclreuse;
+int current_maxccls, current_max_ccl_tbl_size;
+Char *ccltbl;
+char nmstr[MAXLINE];
+int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
+int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
+int num_backing_up, bol_needed;
+FILE *backing_up_file;
+int end_of_buffer_state;
+char **input_files;
+int num_input_files;
+
+/* Make sure program_name is initialized so we don't crash if writing
+ * out an error message before getting the program name from argv[0].
+ */
+char *program_name = "flex";
+
+#ifndef SHORT_FILE_NAMES
+static char *outfile_template = "lex.%s.%s";
+static char *backing_name = "lex.backup";
+#else
+static char *outfile_template = "lex%s.%s";
+static char *backing_name = "lex.bck";
+#endif
+
+#ifdef THINK_C
+#include <console.h>
+#endif
+
+#ifdef MS_DOS
+extern unsigned _stklen = 16384;
+#endif
+
+static char outfile_path[MAXLINE];
+static int outfile_created = 0;
+static char *skelname = NULL;
+
+
+int main( argc, argv )
+int argc;
+char **argv;
+ {
+ int i;
+
+#ifdef THINK_C
+ argc = ccommand( &argv );
+#endif
+#ifdef NEED_ARGV_FIXUP
+ argv_fixup( &argc, &argv );
+#endif
+
+ flexinit( argc, argv );
+
+ readin();
+
+ ntod();
+
+ for ( i = 1; i <= num_rules; ++i )
+ if ( ! rule_useful[i] && i != default_rule )
+ line_warning( _( "rule cannot be matched" ),
+ rule_linenum[i] );
+
+ if ( spprdflt && ! reject && rule_useful[default_rule] )
+ line_warning(
+ _( "-s option given but default rule can be matched" ),
+ rule_linenum[default_rule] );
+
+ /* Generate the C state transition tables from the DFA. */
+ make_tables();
+
+ /* Note, flexend does not return. It exits with its argument
+ * as status.
+ */
+ flexend( 0 );
+
+ return 0; /* keep compilers/lint happy */
+ }
+
+
+/* check_options - check user-specified options */
+
+void check_options()
+ {
+ int i;
+
+ if ( lex_compat )
+ {
+ if ( C_plus_plus )
+ flexerror( _( "Can't use -+ with -l option" ) );
+
+ if ( fulltbl || fullspd )
+ flexerror( _( "Can't use -f or -F with -l option" ) );
+
+ /* Don't rely on detecting use of yymore() and REJECT,
+ * just assume they'll be used.
+ */
+ yymore_really_used = reject_really_used = true;
+
+ yytext_is_array = true;
+ do_yylineno = true;
+ use_read = false;
+ }
+
+ if ( do_yylineno )
+ /* This should really be "maintain_backup_tables = true" */
+ reject_really_used = true;
+
+ if ( csize == unspecified )
+ {
+ if ( (fulltbl || fullspd) && ! useecs )
+ csize = DEFAULT_CSIZE;
+ else
+ csize = CSIZE;
+ }
+
+ if ( interactive == unspecified )
+ {
+ if ( fulltbl || fullspd )
+ interactive = false;
+ else
+ interactive = true;
+ }
+
+ if ( fulltbl || fullspd )
+ {
+ if ( usemecs )
+ flexerror(
+ _( "-Cf/-CF and -Cm don't make sense together" ) );
+
+ if ( interactive )
+ flexerror( _( "-Cf/-CF and -I are incompatible" ) );
+
+ if ( lex_compat )
+ flexerror(
+ _( "-Cf/-CF are incompatible with lex-compatibility mode" ) );
+
+ if ( do_yylineno )
+ flexerror(
+ _( "-Cf/-CF and %option yylineno are incompatible" ) );
+
+ if ( fulltbl && fullspd )
+ flexerror( _( "-Cf and -CF are mutually exclusive" ) );
+ }
+
+ if ( C_plus_plus && fullspd )
+ flexerror( _( "Can't use -+ with -CF option" ) );
+
+ if ( C_plus_plus && yytext_is_array )
+ {
+ warn( _( "%array incompatible with -+ option" ) );
+ yytext_is_array = false;
+ }
+
+ if ( useecs )
+ { /* Set up doubly-linked equivalence classes. */
+
+ /* We loop all the way up to csize, since ecgroup[csize] is
+ * the position used for NUL characters.
+ */
+ ecgroup[1] = NIL;
+
+ for ( i = 2; i <= csize; ++i )
+ {
+ ecgroup[i] = i - 1;
+ nextecm[i - 1] = i;
+ }
+
+ nextecm[csize] = NIL;
+ }
+
+ else
+ {
+ /* Put everything in its own equivalence class. */
+ for ( i = 1; i <= csize; ++i )
+ {
+ ecgroup[i] = i;
+ nextecm[i] = BAD_SUBSCRIPT; /* to catch errors */
+ }
+ }
+
+ if ( ! use_stdout )
+ {
+ FILE *prev_stdout;
+
+ if ( ! did_outfilename )
+ {
+ char *suffix;
+
+ if ( C_plus_plus )
+ suffix = "cc";
+ else
+ suffix = "c";
+
+ sprintf( outfile_path, outfile_template,
+ prefix, suffix );
+
+ outfilename = outfile_path;
+ }
+
+ prev_stdout = freopen( outfilename, "w", stdout );
+
+ if ( prev_stdout == NULL )
+ lerrsf( _( "could not create %s" ), outfilename );
+
+ outfile_created = 1;
+ }
+
+ if ( skelname && (skelfile = fopen( skelname, "r" )) == NULL )
+ lerrsf( _( "can't open skeleton file %s" ), skelname );
+
+ if ( strcmp( prefix, "yy" ) )
+ {
+#define GEN_PREFIX(name) out_str3( "#define yy%s %s%s\n", name, prefix, name )
+ if ( C_plus_plus )
+ GEN_PREFIX( "FlexLexer" );
+ else
+ {
+ GEN_PREFIX( "_create_buffer" );
+ GEN_PREFIX( "_delete_buffer" );
+ GEN_PREFIX( "_scan_buffer" );
+ GEN_PREFIX( "_scan_string" );
+ GEN_PREFIX( "_scan_bytes" );
+ GEN_PREFIX( "_flex_debug" );
+ GEN_PREFIX( "_init_buffer" );
+ GEN_PREFIX( "_flush_buffer" );
+ GEN_PREFIX( "_load_buffer_state" );
+ GEN_PREFIX( "_switch_to_buffer" );
+ GEN_PREFIX( "in" );
+ GEN_PREFIX( "leng" );
+ GEN_PREFIX( "lex" );
+ GEN_PREFIX( "out" );
+ GEN_PREFIX( "restart" );
+ GEN_PREFIX( "text" );
+
+ if ( do_yylineno )
+ GEN_PREFIX( "lineno" );
+ }
+
+ if ( do_yywrap )
+ GEN_PREFIX( "wrap" );
+
+ outn( "" );
+ }
+
+ if ( did_outfilename )
+ line_directive_out( stdout, 0 );
+
+ skelout();
+ }
+
+
+/* flexend - terminate flex
+ *
+ * note
+ * This routine does not return.
+ */
+
+void flexend( exit_status )
+int exit_status;
+
+ {
+ int tblsiz;
+ int unlink();
+
+ if ( skelfile != NULL )
+ {
+ if ( ferror( skelfile ) )
+ lerrsf( _( "input error reading skeleton file %s" ),
+ skelname );
+
+ else if ( fclose( skelfile ) )
+ lerrsf( _( "error closing skeleton file %s" ),
+ skelname );
+ }
+
+ if ( exit_status != 0 && outfile_created )
+ {
+ if ( ferror( stdout ) )
+ lerrsf( _( "error writing output file %s" ),
+ outfilename );
+
+ else if ( fclose( stdout ) )
+ lerrsf( _( "error closing output file %s" ),
+ outfilename );
+
+ else if ( unlink( outfilename ) )
+ lerrsf( _( "error deleting output file %s" ),
+ outfilename );
+ }
+
+ if ( backing_up_report && backing_up_file )
+ {
+ if ( num_backing_up == 0 )
+ fprintf( backing_up_file, _( "No backing up.\n" ) );
+ else if ( fullspd || fulltbl )
+ fprintf( backing_up_file,
+ _( "%d backing up (non-accepting) states.\n" ),
+ num_backing_up );
+ else
+ fprintf( backing_up_file,
+ _( "Compressed tables always back up.\n" ) );
+
+ if ( ferror( backing_up_file ) )
+ lerrsf( _( "error writing backup file %s" ),
+ backing_name );
+
+ else if ( fclose( backing_up_file ) )
+ lerrsf( _( "error closing backup file %s" ),
+ backing_name );
+ }
+
+ if ( printstats )
+ {
+ fprintf( stderr, _( "%s version %s usage statistics:\n" ),
+ program_name, flex_version );
+
+ fprintf( stderr, _( " scanner options: -" ) );
+
+ if ( C_plus_plus )
+ putc( '+', stderr );
+ if ( backing_up_report )
+ putc( 'b', stderr );
+ if ( ddebug )
+ putc( 'd', stderr );
+ if ( caseins )
+ putc( 'i', stderr );
+ if ( lex_compat )
+ putc( 'l', stderr );
+ if ( performance_report > 0 )
+ putc( 'p', stderr );
+ if ( performance_report > 1 )
+ putc( 'p', stderr );
+ if ( spprdflt )
+ putc( 's', stderr );
+ if ( use_stdout )
+ putc( 't', stderr );
+ if ( printstats )
+ putc( 'v', stderr ); /* always true! */
+ if ( nowarn )
+ putc( 'w', stderr );
+ if ( interactive == false )
+ putc( 'B', stderr );
+ if ( interactive == true )
+ putc( 'I', stderr );
+ if ( ! gen_line_dirs )
+ putc( 'L', stderr );
+ if ( trace )
+ putc( 'T', stderr );
+
+ if ( csize == unspecified )
+ /* We encountered an error fairly early on, so csize
+ * never got specified. Define it now, to prevent
+ * bogus table sizes being written out below.
+ */
+ csize = 256;
+
+ if ( csize == 128 )
+ putc( '7', stderr );
+ else
+ putc( '8', stderr );
+
+ fprintf( stderr, " -C" );
+
+ if ( long_align )
+ putc( 'a', stderr );
+ if ( fulltbl )
+ putc( 'f', stderr );
+ if ( fullspd )
+ putc( 'F', stderr );
+ if ( useecs )
+ putc( 'e', stderr );
+ if ( usemecs )
+ putc( 'm', stderr );
+ if ( use_read )
+ putc( 'r', stderr );
+
+ if ( did_outfilename )
+ fprintf( stderr, " -o%s", outfilename );
+
+ if ( skelname )
+ fprintf( stderr, " -S%s", skelname );
+
+ if ( strcmp( prefix, "yy" ) )
+ fprintf( stderr, " -P%s", prefix );
+
+ putc( '\n', stderr );
+
+ fprintf( stderr, _( " %d/%d NFA states\n" ),
+ lastnfa, current_mns );
+ fprintf( stderr, _( " %d/%d DFA states (%d words)\n" ),
+ lastdfa, current_max_dfas, totnst );
+ fprintf( stderr, _( " %d rules\n" ),
+ num_rules + num_eof_rules - 1 /* - 1 for def. rule */ );
+
+ if ( num_backing_up == 0 )
+ fprintf( stderr, _( " No backing up\n" ) );
+ else if ( fullspd || fulltbl )
+ fprintf( stderr,
+ _( " %d backing-up (non-accepting) states\n" ),
+ num_backing_up );
+ else
+ fprintf( stderr,
+ _( " Compressed tables always back-up\n" ) );
+
+ if ( bol_needed )
+ fprintf( stderr,
+ _( " Beginning-of-line patterns used\n" ) );
+
+ fprintf( stderr, _( " %d/%d start conditions\n" ), lastsc,
+ current_max_scs );
+ fprintf( stderr,
+ _( " %d epsilon states, %d double epsilon states\n" ),
+ numeps, eps2 );
+
+ if ( lastccl == 0 )
+ fprintf( stderr, _( " no character classes\n" ) );
+ else
+ fprintf( stderr,
+_( " %d/%d character classes needed %d/%d words of storage, %d reused\n" ),
+ lastccl, current_maxccls,
+ cclmap[lastccl] + ccllen[lastccl],
+ current_max_ccl_tbl_size, cclreuse );
+
+ fprintf( stderr, _( " %d state/nextstate pairs created\n" ),
+ numsnpairs );
+ fprintf( stderr, _( " %d/%d unique/duplicate transitions\n" ),
+ numuniq, numdup );
+
+ if ( fulltbl )
+ {
+ tblsiz = lastdfa * numecs;
+ fprintf( stderr, _( " %d table entries\n" ), tblsiz );
+ }
+
+ else
+ {
+ tblsiz = 2 * (lastdfa + numtemps) + 2 * tblend;
+
+ fprintf( stderr,
+ _( " %d/%d base-def entries created\n" ),
+ lastdfa + numtemps, current_max_dfas );
+ fprintf( stderr,
+ _( " %d/%d (peak %d) nxt-chk entries created\n" ),
+ tblend, current_max_xpairs, peakpairs );
+ fprintf( stderr,
+ _( " %d/%d (peak %d) template nxt-chk entries created\n" ),
+ numtemps * nummecs,
+ current_max_template_xpairs,
+ numtemps * numecs );
+ fprintf( stderr, _( " %d empty table entries\n" ),
+ nummt );
+ fprintf( stderr, _( " %d protos created\n" ),
+ numprots );
+ fprintf( stderr,
+ _( " %d templates created, %d uses\n" ),
+ numtemps, tmpuses );
+ }
+
+ if ( useecs )
+ {
+ tblsiz = tblsiz + csize;
+ fprintf( stderr,
+ _( " %d/%d equivalence classes created\n" ),
+ numecs, csize );
+ }
+
+ if ( usemecs )
+ {
+ tblsiz = tblsiz + numecs;
+ fprintf( stderr,
+ _( " %d/%d meta-equivalence classes created\n" ),
+ nummecs, csize );
+ }
+
+ fprintf( stderr,
+ _( " %d (%d saved) hash collisions, %d DFAs equal\n" ),
+ hshcol, hshsave, dfaeql );
+ fprintf( stderr, _( " %d sets of reallocations needed\n" ),
+ num_reallocs );
+ fprintf( stderr, _( " %d total table entries needed\n" ),
+ tblsiz );
+ }
+
+ exit( exit_status );
+ }
+
+
+/* flexinit - initialize flex */
+
+void flexinit( argc, argv )
+int argc;
+char **argv;
+ {
+ int i, sawcmpflag;
+ char *arg;
+
+ printstats = syntaxerror = trace = spprdflt = caseins = false;
+ lex_compat = C_plus_plus = backing_up_report = ddebug = fulltbl = false;
+ fullspd = long_align = nowarn = yymore_used = continued_action = false;
+ do_yylineno = yytext_is_array = in_rule = reject = do_stdinit = false;
+ yymore_really_used = reject_really_used = unspecified;
+ interactive = csize = unspecified;
+ do_yywrap = gen_line_dirs = usemecs = useecs = true;
+ performance_report = 0;
+ did_outfilename = 0;
+ prefix = "yy";
+ yyclass = 0;
+ use_read = use_stdout = false;
+
+ sawcmpflag = false;
+
+ /* Initialize dynamic array for holding the rule actions. */
+ action_size = 2048; /* default size of action array in bytes */
+ action_array = allocate_character_array( action_size );
+ defs1_offset = prolog_offset = action_offset = action_index = 0;
+ action_array[0] = '\0';
+
+ program_name = argv[0];
+
+ if ( program_name[0] != '\0' &&
+ program_name[strlen( program_name ) - 1] == '+' )
+ C_plus_plus = true;
+
+ /* read flags */
+ for ( --argc, ++argv; argc ; --argc, ++argv )
+ {
+ arg = argv[0];
+
+ if ( arg[0] != '-' || arg[1] == '\0' )
+ break;
+
+ if ( arg[1] == '-' )
+ { /* --option */
+ if ( ! strcmp( arg, "--help" ) )
+ arg = "-h";
+
+ else if ( ! strcmp( arg, "--version" ) )
+ arg = "-V";
+
+ else if ( ! strcmp( arg, "--" ) )
+ { /* end of options */
+ --argc;
+ ++argv;
+ break;
+ }
+ }
+
+ for ( i = 1; arg[i] != '\0'; ++i )
+ switch ( arg[i] )
+ {
+ case '+':
+ C_plus_plus = true;
+ break;
+
+ case 'B':
+ interactive = false;
+ break;
+
+ case 'b':
+ backing_up_report = true;
+ break;
+
+ case 'c':
+ break;
+
+ case 'C':
+ if ( i != 1 )
+ flexerror(
+ _( "-C flag must be given separately" ) );
+
+ if ( ! sawcmpflag )
+ {
+ useecs = false;
+ usemecs = false;
+ fulltbl = false;
+ sawcmpflag = true;
+ }
+
+ for ( ++i; arg[i] != '\0'; ++i )
+ switch ( arg[i] )
+ {
+ case 'a':
+ long_align =
+ true;
+ break;
+
+ case 'e':
+ useecs = true;
+ break;
+
+ case 'F':
+ fullspd = true;
+ break;
+
+ case 'f':
+ fulltbl = true;
+ break;
+
+ case 'm':
+ usemecs = true;
+ break;
+
+ case 'r':
+ use_read = true;
+ break;
+
+ default:
+ lerrif(
+ _( "unknown -C option '%c'" ),
+ (int) arg[i] );
+ break;
+ }
+
+ goto get_next_arg;
+
+ case 'd':
+ ddebug = true;
+ break;
+
+ case 'f':
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ break;
+
+ case 'F':
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ break;
+
+ case '?':
+ case 'h':
+ usage();
+ exit( 0 );
+
+ case 'I':
+ interactive = true;
+ break;
+
+ case 'i':
+ caseins = true;
+ break;
+
+ case 'l':
+ lex_compat = true;
+ break;
+
+ case 'L':
+ gen_line_dirs = false;
+ break;
+
+ case 'n':
+ /* Stupid do-nothing deprecated
+ * option.
+ */
+ break;
+
+ case 'o':
+ if ( i != 1 )
+ flexerror(
+ _( "-o flag must be given separately" ) );
+
+ outfilename = arg + i + 1;
+ did_outfilename = 1;
+ goto get_next_arg;
+
+ case 'P':
+ if ( i != 1 )
+ flexerror(
+ _( "-P flag must be given separately" ) );
+
+ prefix = arg + i + 1;
+ goto get_next_arg;
+
+ case 'p':
+ ++performance_report;
+ break;
+
+ case 'S':
+ if ( i != 1 )
+ flexerror(
+ _( "-S flag must be given separately" ) );
+
+ skelname = arg + i + 1;
+ goto get_next_arg;
+
+ case 's':
+ spprdflt = true;
+ break;
+
+ case 't':
+ use_stdout = true;
+ break;
+
+ case 'T':
+ trace = true;
+ break;
+
+ case 'v':
+ printstats = true;
+ break;
+
+ case 'V':
+ printf( _( "%s version %s\n" ),
+ program_name, flex_version );
+ exit( 0 );
+
+ case 'w':
+ nowarn = true;
+ break;
+
+ case '7':
+ csize = 128;
+ break;
+
+ case '8':
+ csize = CSIZE;
+ break;
+
+ default:
+ fprintf( stderr,
+ _( "%s: unknown flag '%c'. For usage, try\n\t%s --help\n" ),
+ program_name, (int) arg[i],
+ program_name );
+ exit( 1 );
+ }
+
+ /* Used by -C, -S, -o, and -P flags in lieu of a "continue 2"
+ * control.
+ */
+ get_next_arg: ;
+ }
+
+ num_input_files = argc;
+ input_files = argv;
+ set_input_file( num_input_files > 0 ? input_files[0] : NULL );
+
+ lastccl = lastsc = lastdfa = lastnfa = 0;
+ num_rules = num_eof_rules = default_rule = 0;
+ numas = numsnpairs = tmpuses = 0;
+ numecs = numeps = eps2 = num_reallocs = hshcol = dfaeql = totnst = 0;
+ numuniq = numdup = hshsave = eofseen = datapos = dataline = 0;
+ num_backing_up = onesp = numprots = 0;
+ variable_trailing_context_rules = bol_needed = false;
+
+ out_linenum = linenum = sectnum = 1;
+ firstprot = NIL;
+
+ /* Used in mkprot() so that the first proto goes in slot 1
+ * of the proto queue.
+ */
+ lastprot = 1;
+
+ set_up_initial_allocations();
+ }
+
+
+/* readin - read in the rules section of the input file(s) */
+
+void readin()
+ {
+ static char yy_stdinit[] = "FILE *yyin = stdin, *yyout = stdout;";
+ static char yy_nostdinit[] =
+ "FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;";
+
+ line_directive_out( (FILE *) 0, 1 );
+
+ if ( yyparse() )
+ {
+ pinpoint_message( _( "fatal parse error" ) );
+ flexend( 1 );
+ }
+
+ if ( syntaxerror )
+ flexend( 1 );
+
+ if ( backing_up_report )
+ {
+ backing_up_file = fopen( backing_name, "w" );
+ if ( backing_up_file == NULL )
+ lerrsf(
+ _( "could not create backing-up info file %s" ),
+ backing_name );
+ }
+
+ else
+ backing_up_file = NULL;
+
+ if ( yymore_really_used == true )
+ yymore_used = true;
+ else if ( yymore_really_used == false )
+ yymore_used = false;
+
+ if ( reject_really_used == true )
+ reject = true;
+ else if ( reject_really_used == false )
+ reject = false;
+
+ if ( performance_report > 0 )
+ {
+ if ( lex_compat )
+ {
+ fprintf( stderr,
+_( "-l AT&T lex compatibility option entails a large performance penalty\n" ) );
+ fprintf( stderr,
+_( " and may be the actual source of other reported performance penalties\n" ) );
+ }
+
+ else if ( do_yylineno )
+ {
+ fprintf( stderr,
+ _( "%%option yylineno entails a large performance penalty\n" ) );
+ }
+
+ if ( performance_report > 1 )
+ {
+ if ( interactive )
+ fprintf( stderr,
+ _( "-I (interactive) entails a minor performance penalty\n" ) );
+
+ if ( yymore_used )
+ fprintf( stderr,
+ _( "yymore() entails a minor performance penalty\n" ) );
+ }
+
+ if ( reject )
+ fprintf( stderr,
+ _( "REJECT entails a large performance penalty\n" ) );
+
+ if ( variable_trailing_context_rules )
+ fprintf( stderr,
+_( "Variable trailing context rules entail a large performance penalty\n" ) );
+ }
+
+ if ( reject )
+ real_reject = true;
+
+ if ( variable_trailing_context_rules )
+ reject = true;
+
+ if ( (fulltbl || fullspd) && reject )
+ {
+ if ( real_reject )
+ flexerror(
+ _( "REJECT cannot be used with -f or -F" ) );
+ else if ( do_yylineno )
+ flexerror(
+ _( "%option yylineno cannot be used with -f or -F" ) );
+ else
+ flexerror(
+ _( "variable trailing context rules cannot be used with -f or -F" ) );
+ }
+
+ if ( reject )
+ outn( "\n#define YY_USES_REJECT" );
+
+ if ( ! do_yywrap )
+ {
+ outn( "\n#define yywrap() 1" );
+ outn( "#define YY_SKIP_YYWRAP" );
+ }
+
+ if ( ddebug )
+ outn( "\n#define FLEX_DEBUG" );
+
+ if ( csize == 256 )
+ outn( "typedef unsigned char YY_CHAR;" );
+ else
+ outn( "typedef char YY_CHAR;" );
+
+ if ( C_plus_plus )
+ {
+ outn( "#define yytext_ptr yytext" );
+
+ if ( interactive )
+ outn( "#define YY_INTERACTIVE" );
+ }
+
+ else
+ {
+ if ( do_stdinit )
+ {
+ outn( "#ifdef VMS" );
+ outn( "#ifndef __VMS_POSIX" );
+ outn( yy_nostdinit );
+ outn( "#else" );
+ outn( yy_stdinit );
+ outn( "#endif" );
+ outn( "#else" );
+ outn( yy_stdinit );
+ outn( "#endif" );
+ }
+
+ else
+ outn( yy_nostdinit );
+ }
+
+ if ( fullspd )
+ outn( "typedef yyconst struct yy_trans_info *yy_state_type;" );
+ else if ( ! C_plus_plus )
+ outn( "typedef int yy_state_type;" );
+
+ if ( ddebug )
+ outn( "\n#define FLEX_DEBUG" );
+
+ if ( lex_compat )
+ outn( "#define YY_FLEX_LEX_COMPAT" );
+
+ if ( do_yylineno && ! C_plus_plus )
+ {
+ outn( "extern int yylineno;" );
+ outn( "int yylineno = 1;" );
+ }
+
+ if ( C_plus_plus )
+ {
+ outn( "\n#include <FlexLexer.h>" );
+
+ if ( yyclass )
+ {
+ outn( "int yyFlexLexer::yylex()" );
+ outn( "\t{" );
+ outn(
+"\tLexerError( \"yyFlexLexer::yylex invoked but %option yyclass used\" );" );
+ outn( "\treturn 0;" );
+ outn( "\t}" );
+
+ out_str( "\n#define YY_DECL int %s::yylex()\n",
+ yyclass );
+ }
+ }
+
+ else
+ {
+ if ( yytext_is_array )
+ outn( "extern char yytext[];\n" );
+
+ else
+ {
+ outn( "extern char *yytext;" );
+ outn( "#define yytext_ptr yytext" );
+ }
+
+ if ( yyclass )
+ flexerror(
+ _( "%option yyclass only meaningful for C++ scanners" ) );
+ }
+
+ if ( useecs )
+ numecs = cre8ecs( nextecm, ecgroup, csize );
+ else
+ numecs = csize;
+
+ /* Now map the equivalence class for NUL to its expected place. */
+ ecgroup[0] = ecgroup[csize];
+ NUL_ec = ABS( ecgroup[0] );
+
+ if ( useecs )
+ ccl2ecl();
+ }
+
+
+/* set_up_initial_allocations - allocate memory for internal tables */
+
+void set_up_initial_allocations()
+ {
+ current_mns = INITIAL_MNS;
+ firstst = allocate_integer_array( current_mns );
+ lastst = allocate_integer_array( current_mns );
+ finalst = allocate_integer_array( current_mns );
+ transchar = allocate_integer_array( current_mns );
+ trans1 = allocate_integer_array( current_mns );
+ trans2 = allocate_integer_array( current_mns );
+ accptnum = allocate_integer_array( current_mns );
+ assoc_rule = allocate_integer_array( current_mns );
+ state_type = allocate_integer_array( current_mns );
+
+ current_max_rules = INITIAL_MAX_RULES;
+ rule_type = allocate_integer_array( current_max_rules );
+ rule_linenum = allocate_integer_array( current_max_rules );
+ rule_useful = allocate_integer_array( current_max_rules );
+
+ current_max_scs = INITIAL_MAX_SCS;
+ scset = allocate_integer_array( current_max_scs );
+ scbol = allocate_integer_array( current_max_scs );
+ scxclu = allocate_integer_array( current_max_scs );
+ sceof = allocate_integer_array( current_max_scs );
+ scname = allocate_char_ptr_array( current_max_scs );
+
+ current_maxccls = INITIAL_MAX_CCLS;
+ cclmap = allocate_integer_array( current_maxccls );
+ ccllen = allocate_integer_array( current_maxccls );
+ cclng = allocate_integer_array( current_maxccls );
+
+ current_max_ccl_tbl_size = INITIAL_MAX_CCL_TBL_SIZE;
+ ccltbl = allocate_Character_array( current_max_ccl_tbl_size );
+
+ current_max_dfa_size = INITIAL_MAX_DFA_SIZE;
+
+ current_max_xpairs = INITIAL_MAX_XPAIRS;
+ nxt = allocate_integer_array( current_max_xpairs );
+ chk = allocate_integer_array( current_max_xpairs );
+
+ current_max_template_xpairs = INITIAL_MAX_TEMPLATE_XPAIRS;
+ tnxt = allocate_integer_array( current_max_template_xpairs );
+
+ current_max_dfas = INITIAL_MAX_DFAS;
+ base = allocate_integer_array( current_max_dfas );
+ def = allocate_integer_array( current_max_dfas );
+ dfasiz = allocate_integer_array( current_max_dfas );
+ accsiz = allocate_integer_array( current_max_dfas );
+ dhash = allocate_integer_array( current_max_dfas );
+ dss = allocate_int_ptr_array( current_max_dfas );
+ dfaacc = allocate_dfaacc_union( current_max_dfas );
+
+ nultrans = (int *) 0;
+ }
+
+
+void usage()
+ {
+ FILE *f = stdout;
+
+ fprintf( f,
+_( "%s [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]\n" ),
+ program_name );
+ fprintf( f, _( "\t[--help --version] [file ...]\n" ) );
+
+ fprintf( f, _( "\t-b generate backing-up information to %s\n" ),
+ backing_name );
+ fprintf( f, _( "\t-c do-nothing POSIX option\n" ) );
+ fprintf( f, _( "\t-d turn on debug mode in generated scanner\n" ) );
+ fprintf( f, _( "\t-f generate fast, large scanner\n" ) );
+ fprintf( f, _( "\t-h produce this help message\n" ) );
+ fprintf( f, _( "\t-i generate case-insensitive scanner\n" ) );
+ fprintf( f, _( "\t-l maximal compatibility with original lex\n" ) );
+ fprintf( f, _( "\t-n do-nothing POSIX option\n" ) );
+ fprintf( f, _( "\t-p generate performance report to stderr\n" ) );
+ fprintf( f,
+ _( "\t-s suppress default rule to ECHO unmatched text\n" ) );
+
+ if ( ! did_outfilename )
+ {
+ sprintf( outfile_path, outfile_template,
+ prefix, C_plus_plus ? "cc" : "c" );
+ outfilename = outfile_path;
+ }
+
+ fprintf( f,
+ _( "\t-t write generated scanner on stdout instead of %s\n" ),
+ outfilename );
+
+ fprintf( f,
+ _( "\t-v write summary of scanner statistics to f\n" ) );
+ fprintf( f, _( "\t-w do not generate warnings\n" ) );
+ fprintf( f, _( "\t-B generate batch scanner (opposite of -I)\n" ) );
+ fprintf( f,
+ _( "\t-F use alternative fast scanner representation\n" ) );
+ fprintf( f,
+ _( "\t-I generate interactive scanner (opposite of -B)\n" ) );
+ fprintf( f, _( "\t-L suppress #line directives in scanner\n" ) );
+ fprintf( f, _( "\t-T %s should run in trace mode\n" ), program_name );
+ fprintf( f, _( "\t-V report %s version\n" ), program_name );
+ fprintf( f, _( "\t-7 generate 7-bit scanner\n" ) );
+ fprintf( f, _( "\t-8 generate 8-bit scanner\n" ) );
+ fprintf( f, _( "\t-+ generate C++ scanner class\n" ) );
+ fprintf( f, _( "\t-? produce this help message\n" ) );
+ fprintf( f,
+_( "\t-C specify degree of table compression (default is -Cem):\n" ) );
+ fprintf( f,
+_( "\t\t-Ca trade off larger tables for better memory alignment\n" ) );
+ fprintf( f, _( "\t\t-Ce construct equivalence classes\n" ) );
+ fprintf( f,
+_( "\t\t-Cf do not compress scanner tables; use -f representation\n" ) );
+ fprintf( f,
+_( "\t\t-CF do not compress scanner tables; use -F representation\n" ) );
+ fprintf( f, _( "\t\t-Cm construct meta-equivalence classes\n" ) );
+ fprintf( f,
+ _( "\t\t-Cr use read() instead of stdio for scanner input\n" ) );
+ fprintf( f, _( "\t-o specify output filename\n" ) );
+ fprintf( f, _( "\t-P specify scanner prefix other than \"yy\"\n" ) );
+ fprintf( f, _( "\t-S specify skeleton file\n" ) );
+ fprintf( f, _( "\t--help produce this help message\n" ) );
+ fprintf( f, _( "\t--version report %s version\n" ), program_name );
+ }
diff --git a/usr.bin/lex/misc.c b/usr.bin/lex/misc.c
new file mode 100644
index 0000000..34c67c5
--- /dev/null
+++ b/usr.bin/lex/misc.c
@@ -0,0 +1,886 @@
+/* misc - miscellaneous flex routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/misc.c,v 1.1.1.2 1996/06/19 20:26:19 nate Exp $ */
+
+#include "flexdef.h"
+
+
+void action_define( defname, value )
+char *defname;
+int value;
+ {
+ char buf[MAXLINE];
+
+ if ( (int) strlen( defname ) > MAXLINE / 2 )
+ {
+ format_pinpoint_message( _( "name \"%s\" ridiculously long" ),
+ defname );
+ return;
+ }
+
+ sprintf( buf, "#define %s %d\n", defname, value );
+ add_action( buf );
+ }
+
+
+void add_action( new_text )
+char *new_text;
+ {
+ int len = strlen( new_text );
+
+ while ( len + action_index >= action_size - 10 /* slop */ )
+ {
+ int new_size = action_size * 2;
+
+ if ( new_size <= 0 )
+ /* Increase just a little, to try to avoid overflow
+ * on 16-bit machines.
+ */
+ action_size += action_size / 8;
+ else
+ action_size = new_size;
+
+ action_array =
+ reallocate_character_array( action_array, action_size );
+ }
+
+ strcpy( &action_array[action_index], new_text );
+
+ action_index += len;
+ }
+
+
+/* allocate_array - allocate memory for an integer array of the given size */
+
+void *allocate_array( size, element_size )
+int size;
+size_t element_size;
+ {
+ register void *mem;
+ size_t num_bytes = element_size * size;
+
+ mem = flex_alloc( num_bytes );
+ if ( ! mem )
+ flexfatal(
+ _( "memory allocation failed in allocate_array()" ) );
+
+ return mem;
+ }
+
+
+/* all_lower - true if a string is all lower-case */
+
+int all_lower( str )
+register char *str;
+ {
+ while ( *str )
+ {
+ if ( ! isascii( (Char) *str ) || ! islower( *str ) )
+ return 0;
+ ++str;
+ }
+
+ return 1;
+ }
+
+
+/* all_upper - true if a string is all upper-case */
+
+int all_upper( str )
+register char *str;
+ {
+ while ( *str )
+ {
+ if ( ! isascii( (Char) *str ) || ! isupper( *str ) )
+ return 0;
+ ++str;
+ }
+
+ return 1;
+ }
+
+
+/* bubble - bubble sort an integer array in increasing order
+ *
+ * synopsis
+ * int v[n], n;
+ * void bubble( v, n );
+ *
+ * description
+ * sorts the first n elements of array v and replaces them in
+ * increasing order.
+ *
+ * passed
+ * v - the array to be sorted
+ * n - the number of elements of 'v' to be sorted
+ */
+
+void bubble( v, n )
+int v[], n;
+ {
+ register int i, j, k;
+
+ for ( i = n; i > 1; --i )
+ for ( j = 1; j < i; ++j )
+ if ( v[j] > v[j + 1] ) /* compare */
+ {
+ k = v[j]; /* exchange */
+ v[j] = v[j + 1];
+ v[j + 1] = k;
+ }
+ }
+
+
+/* check_char - checks a character to make sure it's within the range
+ * we're expecting. If not, generates fatal error message
+ * and exits.
+ */
+
+void check_char( c )
+int c;
+ {
+ if ( c >= CSIZE )
+ lerrsf( _( "bad character '%s' detected in check_char()" ),
+ readable_form( c ) );
+
+ if ( c >= csize )
+ lerrsf(
+ _( "scanner requires -8 flag to use the character %s" ),
+ readable_form( c ) );
+ }
+
+
+
+/* clower - replace upper-case letter to lower-case */
+
+Char clower( c )
+register int c;
+ {
+ return (Char) ((isascii( c ) && isupper( c )) ? tolower( c ) : c);
+ }
+
+
+/* copy_string - returns a dynamically allocated copy of a string */
+
+char *copy_string( str )
+register const char *str;
+ {
+ register const char *c1;
+ register char *c2;
+ char *copy;
+ unsigned int size;
+
+ /* find length */
+ for ( c1 = str; *c1; ++c1 )
+ ;
+
+ size = (c1 - str + 1) * sizeof( char );
+ copy = (char *) flex_alloc( size );
+
+ if ( copy == NULL )
+ flexfatal( _( "dynamic memory failure in copy_string()" ) );
+
+ for ( c2 = copy; (*c2++ = *str++) != 0; )
+ ;
+
+ return copy;
+ }
+
+
+/* copy_unsigned_string -
+ * returns a dynamically allocated copy of a (potentially) unsigned string
+ */
+
+Char *copy_unsigned_string( str )
+register Char *str;
+ {
+ register Char *c;
+ Char *copy;
+
+ /* find length */
+ for ( c = str; *c; ++c )
+ ;
+
+ copy = allocate_Character_array( c - str + 1 );
+
+ for ( c = copy; (*c++ = *str++) != 0; )
+ ;
+
+ return copy;
+ }
+
+
+/* cshell - shell sort a character array in increasing order
+ *
+ * synopsis
+ *
+ * Char v[n];
+ * int n, special_case_0;
+ * cshell( v, n, special_case_0 );
+ *
+ * description
+ * Does a shell sort of the first n elements of array v.
+ * If special_case_0 is true, then any element equal to 0
+ * is instead assumed to have infinite weight.
+ *
+ * passed
+ * v - array to be sorted
+ * n - number of elements of v to be sorted
+ */
+
+void cshell( v, n, special_case_0 )
+Char v[];
+int n, special_case_0;
+ {
+ int gap, i, j, jg;
+ Char k;
+
+ for ( gap = n / 2; gap > 0; gap = gap / 2 )
+ for ( i = gap; i < n; ++i )
+ for ( j = i - gap; j >= 0; j = j - gap )
+ {
+ jg = j + gap;
+
+ if ( special_case_0 )
+ {
+ if ( v[jg] == 0 )
+ break;
+
+ else if ( v[j] != 0 && v[j] <= v[jg] )
+ break;
+ }
+
+ else if ( v[j] <= v[jg] )
+ break;
+
+ k = v[j];
+ v[j] = v[jg];
+ v[jg] = k;
+ }
+ }
+
+
+/* dataend - finish up a block of data declarations */
+
+void dataend()
+ {
+ if ( datapos > 0 )
+ dataflush();
+
+ /* add terminator for initialization; { for vi */
+ outn( " } ;\n" );
+
+ dataline = 0;
+ datapos = 0;
+ }
+
+
+/* dataflush - flush generated data statements */
+
+void dataflush()
+ {
+ outc( '\n' );
+
+ if ( ++dataline >= NUMDATALINES )
+ {
+ /* Put out a blank line so that the table is grouped into
+ * large blocks that enable the user to find elements easily.
+ */
+ outc( '\n' );
+ dataline = 0;
+ }
+
+ /* Reset the number of characters written on the current line. */
+ datapos = 0;
+ }
+
+
+/* flexerror - report an error message and terminate */
+
+void flexerror( msg )
+const char msg[];
+ {
+ fprintf( stderr, "%s: %s\n", program_name, msg );
+ flexend( 1 );
+ }
+
+
+/* flexfatal - report a fatal error message and terminate */
+
+void flexfatal( msg )
+const char msg[];
+ {
+ fprintf( stderr, _( "%s: fatal internal error, %s\n" ),
+ program_name, msg );
+ exit( 1 );
+ }
+
+
+/* htoi - convert a hexadecimal digit string to an integer value */
+
+int htoi( str )
+Char str[];
+ {
+ unsigned int result;
+
+ (void) sscanf( (char *) str, "%x", &result );
+
+ return result;
+ }
+
+
+/* lerrif - report an error message formatted with one integer argument */
+
+void lerrif( msg, arg )
+const char msg[];
+int arg;
+ {
+ char errmsg[MAXLINE];
+ (void) sprintf( errmsg, msg, arg );
+ flexerror( errmsg );
+ }
+
+
+/* lerrsf - report an error message formatted with one string argument */
+
+void lerrsf( msg, arg )
+const char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ flexerror( errmsg );
+ }
+
+
+/* line_directive_out - spit out a "#line" statement */
+
+void line_directive_out( output_file, do_infile )
+FILE *output_file;
+int do_infile;
+ {
+ char directive[MAXLINE], filename[MAXLINE];
+ char *s1, *s2, *s3;
+ static char line_fmt[] = "#line %d \"%s\"\n";
+
+ if ( ! gen_line_dirs )
+ return;
+
+ if ( (do_infile && ! infilename) || (! do_infile && ! outfilename) )
+ /* don't know the filename to use, skip */
+ return;
+
+ s1 = do_infile ? infilename : outfilename;
+ s2 = filename;
+ s3 = &filename[sizeof( filename ) - 2];
+
+ while ( s2 < s3 && *s1 )
+ {
+ if ( *s1 == '\\' )
+ /* Escape the '\' */
+ *s2++ = '\\';
+
+ *s2++ = *s1++;
+ }
+
+ *s2 = '\0';
+
+ if ( do_infile )
+ sprintf( directive, line_fmt, linenum, filename );
+ else
+ {
+ if ( output_file == stdout )
+ /* Account for the line directive itself. */
+ ++out_linenum;
+
+ sprintf( directive, line_fmt, out_linenum, filename );
+ }
+
+ /* If output_file is nil then we should put the directive in
+ * the accumulated actions.
+ */
+ if ( output_file )
+ {
+ fputs( directive, output_file );
+ }
+ else
+ add_action( directive );
+ }
+
+
+/* mark_defs1 - mark the current position in the action array as
+ * representing where the user's section 1 definitions end
+ * and the prolog begins
+ */
+void mark_defs1()
+ {
+ defs1_offset = 0;
+ action_array[action_index++] = '\0';
+ action_offset = prolog_offset = action_index;
+ action_array[action_index] = '\0';
+ }
+
+
+/* mark_prolog - mark the current position in the action array as
+ * representing the end of the action prolog
+ */
+void mark_prolog()
+ {
+ action_array[action_index++] = '\0';
+ action_offset = action_index;
+ action_array[action_index] = '\0';
+ }
+
+
+/* mk2data - generate a data statement for a two-dimensional array
+ *
+ * Generates a data statement initializing the current 2-D array to "value".
+ */
+void mk2data( value )
+int value;
+ {
+ if ( datapos >= NUMDATAITEMS )
+ {
+ outc( ',' );
+ dataflush();
+ }
+
+ if ( datapos == 0 )
+ /* Indent. */
+ out( " " );
+
+ else
+ outc( ',' );
+
+ ++datapos;
+
+ out_dec( "%5d", value );
+ }
+
+
+/* mkdata - generate a data statement
+ *
+ * Generates a data statement initializing the current array element to
+ * "value".
+ */
+void mkdata( value )
+int value;
+ {
+ if ( datapos >= NUMDATAITEMS )
+ {
+ outc( ',' );
+ dataflush();
+ }
+
+ if ( datapos == 0 )
+ /* Indent. */
+ out( " " );
+ else
+ outc( ',' );
+
+ ++datapos;
+
+ out_dec( "%5d", value );
+ }
+
+
+/* myctoi - return the integer represented by a string of digits */
+
+int myctoi( array )
+char array[];
+ {
+ int val = 0;
+
+ (void) sscanf( array, "%d", &val );
+
+ return val;
+ }
+
+
+/* myesc - return character corresponding to escape sequence */
+
+Char myesc( array )
+Char array[];
+ {
+ Char c, esc_char;
+
+ switch ( array[1] )
+ {
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+
+#if __STDC__
+ case 'a': return '\a';
+ case 'v': return '\v';
+#else
+ case 'a': return '\007';
+ case 'v': return '\013';
+#endif
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ { /* \<octal> */
+ int sptr = 1;
+
+ while ( isascii( array[sptr] ) &&
+ isdigit( array[sptr] ) )
+ /* Don't increment inside loop control
+ * because if isdigit() is a macro it might
+ * expand into multiple increments ...
+ */
+ ++sptr;
+
+ c = array[sptr];
+ array[sptr] = '\0';
+
+ esc_char = otoi( array + 1 );
+
+ array[sptr] = c;
+
+ return esc_char;
+ }
+
+ case 'x':
+ { /* \x<hex> */
+ int sptr = 2;
+
+ while ( isascii( array[sptr] ) &&
+ isxdigit( (char) array[sptr] ) )
+ /* Don't increment inside loop control
+ * because if isdigit() is a macro it might
+ * expand into multiple increments ...
+ */
+ ++sptr;
+
+ c = array[sptr];
+ array[sptr] = '\0';
+
+ esc_char = htoi( array + 2 );
+
+ array[sptr] = c;
+
+ return esc_char;
+ }
+
+ default:
+ return array[1];
+ }
+ }
+
+
+/* otoi - convert an octal digit string to an integer value */
+
+int otoi( str )
+Char str[];
+ {
+ unsigned int result;
+
+ (void) sscanf( (char *) str, "%o", &result );
+ return result;
+ }
+
+
+/* out - various flavors of outputing a (possibly formatted) string for the
+ * generated scanner, keeping track of the line count.
+ */
+
+void out( str )
+const char str[];
+ {
+ fputs( str, stdout );
+ out_line_count( str );
+ }
+
+void out_dec( fmt, n )
+const char fmt[];
+int n;
+ {
+ printf( fmt, n );
+ out_line_count( fmt );
+ }
+
+void out_dec2( fmt, n1, n2 )
+const char fmt[];
+int n1, n2;
+ {
+ printf( fmt, n1, n2 );
+ out_line_count( fmt );
+ }
+
+void out_hex( fmt, x )
+const char fmt[];
+unsigned int x;
+ {
+ printf( fmt, x );
+ out_line_count( fmt );
+ }
+
+void out_line_count( str )
+const char str[];
+ {
+ register int i;
+
+ for ( i = 0; str[i]; ++i )
+ if ( str[i] == '\n' )
+ ++out_linenum;
+ }
+
+void out_str( fmt, str )
+const char fmt[], str[];
+ {
+ printf( fmt, str );
+ out_line_count( fmt );
+ out_line_count( str );
+ }
+
+void out_str3( fmt, s1, s2, s3 )
+const char fmt[], s1[], s2[], s3[];
+ {
+ printf( fmt, s1, s2, s3 );
+ out_line_count( fmt );
+ out_line_count( s1 );
+ out_line_count( s2 );
+ out_line_count( s3 );
+ }
+
+void out_str_dec( fmt, str, n )
+const char fmt[], str[];
+int n;
+ {
+ printf( fmt, str, n );
+ out_line_count( fmt );
+ out_line_count( str );
+ }
+
+void outc( c )
+int c;
+ {
+ putc( c, stdout );
+
+ if ( c == '\n' )
+ ++out_linenum;
+ }
+
+void outn( str )
+const char str[];
+ {
+ puts( str );
+ out_line_count( str );
+ ++out_linenum;
+ }
+
+
+/* readable_form - return the the human-readable form of a character
+ *
+ * The returned string is in static storage.
+ */
+
+char *readable_form( c )
+register int c;
+ {
+ static char rform[10];
+
+ if ( (c >= 0 && c < 32) || c >= 127 )
+ {
+ switch ( c )
+ {
+ case '\b': return "\\b";
+ case '\f': return "\\f";
+ case '\n': return "\\n";
+ case '\r': return "\\r";
+ case '\t': return "\\t";
+
+#if __STDC__
+ case '\a': return "\\a";
+ case '\v': return "\\v";
+#endif
+
+ default:
+ (void) sprintf( rform, "\\%.3o",
+ (unsigned int) c );
+ return rform;
+ }
+ }
+
+ else if ( c == ' ' )
+ return "' '";
+
+ else
+ {
+ rform[0] = c;
+ rform[1] = '\0';
+
+ return rform;
+ }
+ }
+
+
+/* reallocate_array - increase the size of a dynamic array */
+
+void *reallocate_array( array, size, element_size )
+void *array;
+int size;
+size_t element_size;
+ {
+ register void *new_array;
+ size_t num_bytes = element_size * size;
+
+ new_array = flex_realloc( array, num_bytes );
+ if ( ! new_array )
+ flexfatal( _( "attempt to increase array size failed" ) );
+
+ return new_array;
+ }
+
+
+/* skelout - write out one section of the skeleton file
+ *
+ * Description
+ * Copies skelfile or skel array to stdout until a line beginning with
+ * "%%" or EOF is found.
+ */
+void skelout()
+ {
+ char buf_storage[MAXLINE];
+ char *buf = buf_storage;
+ int do_copy = 1;
+
+ /* Loop pulling lines either from the skelfile, if we're using
+ * one, or from the skel[] array.
+ */
+ while ( skelfile ?
+ (fgets( buf, MAXLINE, skelfile ) != NULL) :
+ ((buf = (char *) skel[skel_ind++]) != 0) )
+ { /* copy from skel array */
+ if ( buf[0] == '%' )
+ { /* control line */
+ switch ( buf[1] )
+ {
+ case '%':
+ return;
+
+ case '+':
+ do_copy = C_plus_plus;
+ break;
+
+ case '-':
+ do_copy = ! C_plus_plus;
+ break;
+
+ case '*':
+ do_copy = 1;
+ break;
+
+ default:
+ flexfatal(
+ _( "bad line in skeleton file" ) );
+ }
+ }
+
+ else if ( do_copy )
+ {
+ if ( skelfile )
+ /* Skeleton file reads include final
+ * newline, skel[] array does not.
+ */
+ out( buf );
+ else
+ outn( buf );
+ }
+ }
+ }
+
+
+/* transition_struct_out - output a yy_trans_info structure
+ *
+ * outputs the yy_trans_info structure with the two elements, element_v and
+ * element_n. Formats the output with spaces and carriage returns.
+ */
+
+void transition_struct_out( element_v, element_n )
+int element_v, element_n;
+ {
+ out_dec2( " {%4d,%4d },", element_v, element_n );
+
+ datapos += TRANS_STRUCT_PRINT_LENGTH;
+
+ if ( datapos >= 79 - TRANS_STRUCT_PRINT_LENGTH )
+ {
+ outc( '\n' );
+
+ if ( ++dataline % 10 == 0 )
+ outc( '\n' );
+
+ datapos = 0;
+ }
+ }
+
+
+/* The following is only needed when building flex's parser using certain
+ * broken versions of bison.
+ */
+void *yy_flex_xmalloc( size )
+int size;
+ {
+ void *result = flex_alloc( (size_t) size );
+
+ if ( ! result )
+ flexfatal(
+ _( "memory allocation failed in yy_flex_xmalloc()" ) );
+
+ return result;
+ }
+
+
+/* zero_out - set a region of memory to 0
+ *
+ * Sets region_ptr[0] through region_ptr[size_in_bytes - 1] to zero.
+ */
+
+void zero_out( region_ptr, size_in_bytes )
+char *region_ptr;
+size_t size_in_bytes;
+ {
+ register char *rp, *rp_end;
+
+ rp = region_ptr;
+ rp_end = region_ptr + size_in_bytes;
+
+ while ( rp < rp_end )
+ *rp++ = 0;
+ }
diff --git a/usr.bin/lex/mkskel.sh b/usr.bin/lex/mkskel.sh
new file mode 100755
index 0000000..a03a11a
--- /dev/null
+++ b/usr.bin/lex/mkskel.sh
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+cat <<!
+/* File created from flex.skl via mkskel.sh */
+
+#include "flexdef.h"
+
+const char *skel[] = {
+!
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
+
+cat <<!
+ 0
+};
+!
diff --git a/usr.bin/lex/nfa.c b/usr.bin/lex/nfa.c
new file mode 100644
index 0000000..5fbec9a
--- /dev/null
+++ b/usr.bin/lex/nfa.c
@@ -0,0 +1,709 @@
+/* nfa - NFA construction routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/nfa.c,v 1.1.1.2 1996/06/19 20:26:24 nate Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+int dupmachine PROTO((int));
+void mkxtion PROTO((int, int));
+
+
+/* add_accept - add an accepting state to a machine
+ *
+ * accepting_number becomes mach's accepting number.
+ */
+
+void add_accept( mach, accepting_number )
+int mach, accepting_number;
+ {
+ /* Hang the accepting number off an epsilon state. if it is associated
+ * with a state that has a non-epsilon out-transition, then the state
+ * will accept BEFORE it makes that transition, i.e., one character
+ * too soon.
+ */
+
+ if ( transchar[finalst[mach]] == SYM_EPSILON )
+ accptnum[finalst[mach]] = accepting_number;
+
+ else
+ {
+ int astate = mkstate( SYM_EPSILON );
+ accptnum[astate] = accepting_number;
+ (void) link_machines( mach, astate );
+ }
+ }
+
+
+/* copysingl - make a given number of copies of a singleton machine
+ *
+ * synopsis
+ *
+ * newsng = copysingl( singl, num );
+ *
+ * newsng - a new singleton composed of num copies of singl
+ * singl - a singleton machine
+ * num - the number of copies of singl to be present in newsng
+ */
+
+int copysingl( singl, num )
+int singl, num;
+ {
+ int copy, i;
+
+ copy = mkstate( SYM_EPSILON );
+
+ for ( i = 1; i <= num; ++i )
+ copy = link_machines( copy, dupmachine( singl ) );
+
+ return copy;
+ }
+
+
+/* dumpnfa - debugging routine to write out an nfa */
+
+void dumpnfa( state1 )
+int state1;
+
+ {
+ int sym, tsp1, tsp2, anum, ns;
+
+ fprintf( stderr,
+ _( "\n\n********** beginning dump of nfa with start state %d\n" ),
+ state1 );
+
+ /* We probably should loop starting at firstst[state1] and going to
+ * lastst[state1], but they're not maintained properly when we "or"
+ * all of the rules together. So we use our knowledge that the machine
+ * starts at state 1 and ends at lastnfa.
+ */
+
+ /* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */
+ for ( ns = 1; ns <= lastnfa; ++ns )
+ {
+ fprintf( stderr, _( "state # %4d\t" ), ns );
+
+ sym = transchar[ns];
+ tsp1 = trans1[ns];
+ tsp2 = trans2[ns];
+ anum = accptnum[ns];
+
+ fprintf( stderr, "%3d: %4d, %4d", sym, tsp1, tsp2 );
+
+ if ( anum != NIL )
+ fprintf( stderr, " [%d]", anum );
+
+ fprintf( stderr, "\n" );
+ }
+
+ fprintf( stderr, _( "********** end of dump\n" ) );
+ }
+
+
+/* dupmachine - make a duplicate of a given machine
+ *
+ * synopsis
+ *
+ * copy = dupmachine( mach );
+ *
+ * copy - holds duplicate of mach
+ * mach - machine to be duplicated
+ *
+ * note that the copy of mach is NOT an exact duplicate; rather, all the
+ * transition states values are adjusted so that the copy is self-contained,
+ * as the original should have been.
+ *
+ * also note that the original MUST be contiguous, with its low and high
+ * states accessible by the arrays firstst and lastst
+ */
+
+int dupmachine( mach )
+int mach;
+ {
+ int i, init, state_offset;
+ int state = 0;
+ int last = lastst[mach];
+
+ for ( i = firstst[mach]; i <= last; ++i )
+ {
+ state = mkstate( transchar[i] );
+
+ if ( trans1[i] != NO_TRANSITION )
+ {
+ mkxtion( finalst[state], trans1[i] + state - i );
+
+ if ( transchar[i] == SYM_EPSILON &&
+ trans2[i] != NO_TRANSITION )
+ mkxtion( finalst[state],
+ trans2[i] + state - i );
+ }
+
+ accptnum[state] = accptnum[i];
+ }
+
+ if ( state == 0 )
+ flexfatal( _( "empty machine in dupmachine()" ) );
+
+ state_offset = state - i + 1;
+
+ init = mach + state_offset;
+ firstst[init] = firstst[mach] + state_offset;
+ finalst[init] = finalst[mach] + state_offset;
+ lastst[init] = lastst[mach] + state_offset;
+
+ return init;
+ }
+
+
+/* finish_rule - finish up the processing for a rule
+ *
+ * An accepting number is added to the given machine. If variable_trail_rule
+ * is true then the rule has trailing context and both the head and trail
+ * are variable size. Otherwise if headcnt or trailcnt is non-zero then
+ * the machine recognizes a pattern with trailing context and headcnt is
+ * the number of characters in the matched part of the pattern, or zero
+ * if the matched part has variable length. trailcnt is the number of
+ * trailing context characters in the pattern, or zero if the trailing
+ * context has variable length.
+ */
+
+void finish_rule( mach, variable_trail_rule, headcnt, trailcnt )
+int mach, variable_trail_rule, headcnt, trailcnt;
+ {
+ char action_text[MAXLINE];
+
+ add_accept( mach, num_rules );
+
+ /* We did this in new_rule(), but it often gets the wrong
+ * number because we do it before we start parsing the current rule.
+ */
+ rule_linenum[num_rules] = linenum;
+
+ /* If this is a continued action, then the line-number has already
+ * been updated, giving us the wrong number.
+ */
+ if ( continued_action )
+ --rule_linenum[num_rules];
+
+ sprintf( action_text, "case %d:\n", num_rules );
+ add_action( action_text );
+
+ if ( variable_trail_rule )
+ {
+ rule_type[num_rules] = RULE_VARIABLE;
+
+ if ( performance_report > 0 )
+ fprintf( stderr,
+ _( "Variable trailing context rule at line %d\n" ),
+ rule_linenum[num_rules] );
+
+ variable_trailing_context_rules = true;
+ }
+
+ else
+ {
+ rule_type[num_rules] = RULE_NORMAL;
+
+ if ( headcnt > 0 || trailcnt > 0 )
+ {
+ /* Do trailing context magic to not match the trailing
+ * characters.
+ */
+ char *scanner_cp = "yy_c_buf_p = yy_cp";
+ char *scanner_bp = "yy_bp";
+
+ add_action(
+ "*yy_cp = yy_hold_char; /* undo effects of setting up yytext */\n" );
+
+ if ( headcnt > 0 )
+ {
+ sprintf( action_text, "%s = %s + %d;\n",
+ scanner_cp, scanner_bp, headcnt );
+ add_action( action_text );
+ }
+
+ else
+ {
+ sprintf( action_text, "%s -= %d;\n",
+ scanner_cp, trailcnt );
+ add_action( action_text );
+ }
+
+ add_action(
+ "YY_DO_BEFORE_ACTION; /* set up yytext again */\n" );
+ }
+ }
+
+ /* Okay, in the action code at this point yytext and yyleng have
+ * their proper final values for this rule, so here's the point
+ * to do any user action. But don't do it for continued actions,
+ * as that'll result in multiple YY_RULE_SETUP's.
+ */
+ if ( ! continued_action )
+ add_action( "YY_RULE_SETUP\n" );
+
+ line_directive_out( (FILE *) 0, 1 );
+ }
+
+
+/* link_machines - connect two machines together
+ *
+ * synopsis
+ *
+ * new = link_machines( first, last );
+ *
+ * new - a machine constructed by connecting first to last
+ * first - the machine whose successor is to be last
+ * last - the machine whose predecessor is to be first
+ *
+ * note: this routine concatenates the machine first with the machine
+ * last to produce a machine new which will pattern-match first first
+ * and then last, and will fail if either of the sub-patterns fails.
+ * FIRST is set to new by the operation. last is unmolested.
+ */
+
+int link_machines( first, last )
+int first, last;
+ {
+ if ( first == NIL )
+ return last;
+
+ else if ( last == NIL )
+ return first;
+
+ else
+ {
+ mkxtion( finalst[first], last );
+ finalst[first] = finalst[last];
+ lastst[first] = MAX( lastst[first], lastst[last] );
+ firstst[first] = MIN( firstst[first], firstst[last] );
+
+ return first;
+ }
+ }
+
+
+/* mark_beginning_as_normal - mark each "beginning" state in a machine
+ * as being a "normal" (i.e., not trailing context-
+ * associated) states
+ *
+ * The "beginning" states are the epsilon closure of the first state
+ */
+
+void mark_beginning_as_normal( mach )
+register int mach;
+ {
+ switch ( state_type[mach] )
+ {
+ case STATE_NORMAL:
+ /* Oh, we've already visited here. */
+ return;
+
+ case STATE_TRAILING_CONTEXT:
+ state_type[mach] = STATE_NORMAL;
+
+ if ( transchar[mach] == SYM_EPSILON )
+ {
+ if ( trans1[mach] != NO_TRANSITION )
+ mark_beginning_as_normal(
+ trans1[mach] );
+
+ if ( trans2[mach] != NO_TRANSITION )
+ mark_beginning_as_normal(
+ trans2[mach] );
+ }
+ break;
+
+ default:
+ flexerror(
+ _( "bad state type in mark_beginning_as_normal()" ) );
+ break;
+ }
+ }
+
+
+/* mkbranch - make a machine that branches to two machines
+ *
+ * synopsis
+ *
+ * branch = mkbranch( first, second );
+ *
+ * branch - a machine which matches either first's pattern or second's
+ * first, second - machines whose patterns are to be or'ed (the | operator)
+ *
+ * Note that first and second are NEITHER destroyed by the operation. Also,
+ * the resulting machine CANNOT be used with any other "mk" operation except
+ * more mkbranch's. Compare with mkor()
+ */
+
+int mkbranch( first, second )
+int first, second;
+ {
+ int eps;
+
+ if ( first == NO_TRANSITION )
+ return second;
+
+ else if ( second == NO_TRANSITION )
+ return first;
+
+ eps = mkstate( SYM_EPSILON );
+
+ mkxtion( eps, first );
+ mkxtion( eps, second );
+
+ return eps;
+ }
+
+
+/* mkclos - convert a machine into a closure
+ *
+ * synopsis
+ * new = mkclos( state );
+ *
+ * new - a new state which matches the closure of "state"
+ */
+
+int mkclos( state )
+int state;
+ {
+ return mkopt( mkposcl( state ) );
+ }
+
+
+/* mkopt - make a machine optional
+ *
+ * synopsis
+ *
+ * new = mkopt( mach );
+ *
+ * new - a machine which optionally matches whatever mach matched
+ * mach - the machine to make optional
+ *
+ * notes:
+ * 1. mach must be the last machine created
+ * 2. mach is destroyed by the call
+ */
+
+int mkopt( mach )
+int mach;
+ {
+ int eps;
+
+ if ( ! SUPER_FREE_EPSILON(finalst[mach]) )
+ {
+ eps = mkstate( SYM_EPSILON );
+ mach = link_machines( mach, eps );
+ }
+
+ /* Can't skimp on the following if FREE_EPSILON(mach) is true because
+ * some state interior to "mach" might point back to the beginning
+ * for a closure.
+ */
+ eps = mkstate( SYM_EPSILON );
+ mach = link_machines( eps, mach );
+
+ mkxtion( mach, finalst[mach] );
+
+ return mach;
+ }
+
+
+/* mkor - make a machine that matches either one of two machines
+ *
+ * synopsis
+ *
+ * new = mkor( first, second );
+ *
+ * new - a machine which matches either first's pattern or second's
+ * first, second - machines whose patterns are to be or'ed (the | operator)
+ *
+ * note that first and second are both destroyed by the operation
+ * the code is rather convoluted because an attempt is made to minimize
+ * the number of epsilon states needed
+ */
+
+int mkor( first, second )
+int first, second;
+ {
+ int eps, orend;
+
+ if ( first == NIL )
+ return second;
+
+ else if ( second == NIL )
+ return first;
+
+ else
+ {
+ /* See comment in mkopt() about why we can't use the first
+ * state of "first" or "second" if they satisfy "FREE_EPSILON".
+ */
+ eps = mkstate( SYM_EPSILON );
+
+ first = link_machines( eps, first );
+
+ mkxtion( first, second );
+
+ if ( SUPER_FREE_EPSILON(finalst[first]) &&
+ accptnum[finalst[first]] == NIL )
+ {
+ orend = finalst[first];
+ mkxtion( finalst[second], orend );
+ }
+
+ else if ( SUPER_FREE_EPSILON(finalst[second]) &&
+ accptnum[finalst[second]] == NIL )
+ {
+ orend = finalst[second];
+ mkxtion( finalst[first], orend );
+ }
+
+ else
+ {
+ eps = mkstate( SYM_EPSILON );
+
+ first = link_machines( first, eps );
+ orend = finalst[first];
+
+ mkxtion( finalst[second], orend );
+ }
+ }
+
+ finalst[first] = orend;
+ return first;
+ }
+
+
+/* mkposcl - convert a machine into a positive closure
+ *
+ * synopsis
+ * new = mkposcl( state );
+ *
+ * new - a machine matching the positive closure of "state"
+ */
+
+int mkposcl( state )
+int state;
+ {
+ int eps;
+
+ if ( SUPER_FREE_EPSILON(finalst[state]) )
+ {
+ mkxtion( finalst[state], state );
+ return state;
+ }
+
+ else
+ {
+ eps = mkstate( SYM_EPSILON );
+ mkxtion( eps, state );
+ return link_machines( state, eps );
+ }
+ }
+
+
+/* mkrep - make a replicated machine
+ *
+ * synopsis
+ * new = mkrep( mach, lb, ub );
+ *
+ * new - a machine that matches whatever "mach" matched from "lb"
+ * number of times to "ub" number of times
+ *
+ * note
+ * if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"
+ */
+
+int mkrep( mach, lb, ub )
+int mach, lb, ub;
+ {
+ int base_mach, tail, copy, i;
+
+ base_mach = copysingl( mach, lb - 1 );
+
+ if ( ub == INFINITY )
+ {
+ copy = dupmachine( mach );
+ mach = link_machines( mach,
+ link_machines( base_mach, mkclos( copy ) ) );
+ }
+
+ else
+ {
+ tail = mkstate( SYM_EPSILON );
+
+ for ( i = lb; i < ub; ++i )
+ {
+ copy = dupmachine( mach );
+ tail = mkopt( link_machines( copy, tail ) );
+ }
+
+ mach = link_machines( mach, link_machines( base_mach, tail ) );
+ }
+
+ return mach;
+ }
+
+
+/* mkstate - create a state with a transition on a given symbol
+ *
+ * synopsis
+ *
+ * state = mkstate( sym );
+ *
+ * state - a new state matching sym
+ * sym - the symbol the new state is to have an out-transition on
+ *
+ * note that this routine makes new states in ascending order through the
+ * state array (and increments LASTNFA accordingly). The routine DUPMACHINE
+ * relies on machines being made in ascending order and that they are
+ * CONTIGUOUS. Change it and you will have to rewrite DUPMACHINE (kludge
+ * that it admittedly is)
+ */
+
+int mkstate( sym )
+int sym;
+ {
+ if ( ++lastnfa >= current_mns )
+ {
+ if ( (current_mns += MNS_INCREMENT) >= MAXIMUM_MNS )
+ lerrif(
+ _( "input rules are too complicated (>= %d NFA states)" ),
+ current_mns );
+
+ ++num_reallocs;
+
+ firstst = reallocate_integer_array( firstst, current_mns );
+ lastst = reallocate_integer_array( lastst, current_mns );
+ finalst = reallocate_integer_array( finalst, current_mns );
+ transchar = reallocate_integer_array( transchar, current_mns );
+ trans1 = reallocate_integer_array( trans1, current_mns );
+ trans2 = reallocate_integer_array( trans2, current_mns );
+ accptnum = reallocate_integer_array( accptnum, current_mns );
+ assoc_rule =
+ reallocate_integer_array( assoc_rule, current_mns );
+ state_type =
+ reallocate_integer_array( state_type, current_mns );
+ }
+
+ firstst[lastnfa] = lastnfa;
+ finalst[lastnfa] = lastnfa;
+ lastst[lastnfa] = lastnfa;
+ transchar[lastnfa] = sym;
+ trans1[lastnfa] = NO_TRANSITION;
+ trans2[lastnfa] = NO_TRANSITION;
+ accptnum[lastnfa] = NIL;
+ assoc_rule[lastnfa] = num_rules;
+ state_type[lastnfa] = current_state_type;
+
+ /* Fix up equivalence classes base on this transition. Note that any
+ * character which has its own transition gets its own equivalence
+ * class. Thus only characters which are only in character classes
+ * have a chance at being in the same equivalence class. E.g. "a|b"
+ * puts 'a' and 'b' into two different equivalence classes. "[ab]"
+ * puts them in the same equivalence class (barring other differences
+ * elsewhere in the input).
+ */
+
+ if ( sym < 0 )
+ {
+ /* We don't have to update the equivalence classes since
+ * that was already done when the ccl was created for the
+ * first time.
+ */
+ }
+
+ else if ( sym == SYM_EPSILON )
+ ++numeps;
+
+ else
+ {
+ check_char( sym );
+
+ if ( useecs )
+ /* Map NUL's to csize. */
+ mkechar( sym ? sym : csize, nextecm, ecgroup );
+ }
+
+ return lastnfa;
+ }
+
+
+/* mkxtion - make a transition from one state to another
+ *
+ * synopsis
+ *
+ * mkxtion( statefrom, stateto );
+ *
+ * statefrom - the state from which the transition is to be made
+ * stateto - the state to which the transition is to be made
+ */
+
+void mkxtion( statefrom, stateto )
+int statefrom, stateto;
+ {
+ if ( trans1[statefrom] == NO_TRANSITION )
+ trans1[statefrom] = stateto;
+
+ else if ( (transchar[statefrom] != SYM_EPSILON) ||
+ (trans2[statefrom] != NO_TRANSITION) )
+ flexfatal( _( "found too many transitions in mkxtion()" ) );
+
+ else
+ { /* second out-transition for an epsilon state */
+ ++eps2;
+ trans2[statefrom] = stateto;
+ }
+ }
+
+/* new_rule - initialize for a new rule */
+
+void new_rule()
+ {
+ if ( ++num_rules >= current_max_rules )
+ {
+ ++num_reallocs;
+ current_max_rules += MAX_RULES_INCREMENT;
+ rule_type = reallocate_integer_array( rule_type,
+ current_max_rules );
+ rule_linenum = reallocate_integer_array( rule_linenum,
+ current_max_rules );
+ rule_useful = reallocate_integer_array( rule_useful,
+ current_max_rules );
+ }
+
+ if ( num_rules > MAX_RULE )
+ lerrif( _( "too many rules (> %d)!" ), MAX_RULE );
+
+ rule_linenum[num_rules] = linenum;
+ rule_useful[num_rules] = false;
+ }
diff --git a/usr.bin/lex/parse.y b/usr.bin/lex/parse.y
new file mode 100644
index 0000000..8dbd125
--- /dev/null
+++ b/usr.bin/lex/parse.y
@@ -0,0 +1,913 @@
+/* parse.y - parser for flex input */
+
+%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
+%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS
+
+%token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
+%token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
+
+%{
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/parse.y,v 2.28 95/04/21 11:51:51 vern Exp $ */
+
+
+/* Some versions of bison are broken in that they use alloca() but don't
+ * declare it properly. The following is the patented (just kidding!)
+ * #ifdef chud to fix the problem, courtesy of Francois Pinard.
+ */
+#ifdef YYBISON
+/* AIX requires this to be the first thing in the file. What a piece. */
+# ifdef _AIX
+ #pragma alloca
+# endif
+#endif
+
+#include "flexdef.h"
+
+/* The remainder of the alloca() cruft has to come after including flexdef.h,
+ * so HAVE_ALLOCA_H is (possibly) defined.
+ */
+#ifdef YYBISON
+# ifdef __GNUC__
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef __hpux
+void *alloca ();
+# else
+# ifdef __TURBOC__
+# include <malloc.h>
+# else
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* Bletch, ^^^^ that was ugly! */
+
+
+int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, rulelen;
+int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
+
+int *scon_stk;
+int scon_stk_ptr;
+
+static int madeany = false; /* whether we've made the '.' character class */
+int previous_continued_action; /* whether the previous rule's action was '|' */
+
+/* Expand a POSIX character class expression. */
+#define CCL_EXPR(func) \
+ { \
+ int c; \
+ for ( c = 0; c < csize; ++c ) \
+ if ( isascii(c) && func(c) ) \
+ ccladd( currccl, c ); \
+ }
+
+/* While POSIX defines isblank(), it's not ANSI C. */
+#define IS_BLANK(c) ((c) == ' ' || (c) == '\t')
+
+/* On some over-ambitious machines, such as DEC Alpha's, the default
+ * token type is "long" instead of "int"; this leads to problems with
+ * declaring yylval in flexdef.h. But so far, all the yacc's I've seen
+ * wrap their definitions of YYSTYPE with "#ifndef YYSTYPE"'s, so the
+ * following should ensure that the default token type is "int".
+ */
+#define YYSTYPE int
+
+%}
+
+%%
+goal : initlex sect1 sect1end sect2 initforrule
+ { /* add default rule */
+ int def_rule;
+
+ pat = cclinit();
+ cclnegate( pat );
+
+ def_rule = mkstate( -pat );
+
+ /* Remember the number of the default rule so we
+ * don't generate "can't match" warnings for it.
+ */
+ default_rule = num_rules;
+
+ finish_rule( def_rule, false, 0, 0 );
+
+ for ( i = 1; i <= lastsc; ++i )
+ scset[i] = mkbranch( scset[i], def_rule );
+
+ if ( spprdflt )
+ add_action(
+ "YY_FATAL_ERROR( \"flex scanner jammed\" )" );
+ else
+ add_action( "ECHO" );
+
+ add_action( ";\n\tYY_BREAK\n" );
+ }
+ ;
+
+initlex :
+ { /* initialize for processing rules */
+
+ /* Create default DFA start condition. */
+ scinstal( "INITIAL", false );
+ }
+ ;
+
+sect1 : sect1 startconddecl namelist1
+ | sect1 options
+ |
+ | error
+ { synerr( "unknown error processing section 1" ); }
+ ;
+
+sect1end : SECTEND
+ {
+ check_options();
+ scon_stk = allocate_integer_array( lastsc + 1 );
+ scon_stk_ptr = 0;
+ }
+ ;
+
+startconddecl : SCDECL
+ { xcluflg = false; }
+
+ | XSCDECL
+ { xcluflg = true; }
+ ;
+
+namelist1 : namelist1 NAME
+ { scinstal( nmstr, xcluflg ); }
+
+ | NAME
+ { scinstal( nmstr, xcluflg ); }
+
+ | error
+ { synerr( "bad start condition list" ); }
+ ;
+
+options : OPTION_OP optionlist
+ ;
+
+optionlist : optionlist option
+ |
+ ;
+
+option : OPT_OUTFILE '=' NAME
+ {
+ outfilename = copy_string( nmstr );
+ did_outfilename = 1;
+ }
+ | OPT_PREFIX '=' NAME
+ { prefix = copy_string( nmstr ); }
+ | OPT_YYCLASS '=' NAME
+ { yyclass = copy_string( nmstr ); }
+ ;
+
+sect2 : sect2 scon initforrule flexrule '\n'
+ { scon_stk_ptr = $2; }
+ | sect2 scon '{' sect2 '}'
+ { scon_stk_ptr = $2; }
+ |
+ ;
+
+initforrule :
+ {
+ /* Initialize for a parse of one rule. */
+ trlcontxt = variable_trail_rule = varlength = false;
+ trailcnt = headcnt = rulelen = 0;
+ current_state_type = STATE_NORMAL;
+ previous_continued_action = continued_action;
+ in_rule = true;
+
+ new_rule();
+ }
+ ;
+
+flexrule : '^' rule
+ {
+ pat = $2;
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scbol[scon_stk[i]] =
+ mkbranch( scbol[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ /* Add to all non-exclusive start conditions,
+ * including the default (0) start condition.
+ */
+
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scbol[i] = mkbranch( scbol[i],
+ pat );
+ }
+
+ if ( ! bol_needed )
+ {
+ bol_needed = true;
+
+ if ( performance_report > 1 )
+ pinpoint_message(
+ "'^' operator results in sub-optimal performance" );
+ }
+ }
+
+ | rule
+ {
+ pat = $1;
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scset[scon_stk[i]] =
+ mkbranch( scset[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scset[i] =
+ mkbranch( scset[i],
+ pat );
+ }
+ }
+
+ | EOF_OP
+ {
+ if ( scon_stk_ptr > 0 )
+ build_eof_action();
+
+ else
+ {
+ /* This EOF applies to all start conditions
+ * which don't already have EOF actions.
+ */
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! sceof[i] )
+ scon_stk[++scon_stk_ptr] = i;
+
+ if ( scon_stk_ptr == 0 )
+ warn(
+ "all start conditions already have <<EOF>> rules" );
+
+ else
+ build_eof_action();
+ }
+ }
+
+ | error
+ { synerr( "unrecognized rule" ); }
+ ;
+
+scon_stk_ptr :
+ { $$ = scon_stk_ptr; }
+ ;
+
+scon : '<' scon_stk_ptr namelist2 '>'
+ { $$ = $2; }
+
+ | '<' '*' '>'
+ {
+ $$ = scon_stk_ptr;
+
+ for ( i = 1; i <= lastsc; ++i )
+ {
+ int j;
+
+ for ( j = 1; j <= scon_stk_ptr; ++j )
+ if ( scon_stk[j] == i )
+ break;
+
+ if ( j > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = i;
+ }
+ }
+
+ |
+ { $$ = scon_stk_ptr; }
+ ;
+
+namelist2 : namelist2 ',' sconname
+
+ | sconname
+
+ | error
+ { synerr( "bad start condition list" ); }
+ ;
+
+sconname : NAME
+ {
+ if ( (scnum = sclookup( nmstr )) == 0 )
+ format_pinpoint_message(
+ "undeclared start condition %s",
+ nmstr );
+ else
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ if ( scon_stk[i] == scnum )
+ {
+ format_warn(
+ "<%s> specified twice",
+ scname[scnum] );
+ break;
+ }
+
+ if ( i > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = scnum;
+ }
+ }
+ ;
+
+rule : re2 re
+ {
+ if ( transchar[lastst[$2]] != SYM_EPSILON )
+ /* Provide final transition \now/ so it
+ * will be marked as a trailing context
+ * state.
+ */
+ $2 = link_machines( $2,
+ mkstate( SYM_EPSILON ) );
+
+ mark_beginning_as_normal( $2 );
+ current_state_type = STATE_NORMAL;
+
+ if ( previous_continued_action )
+ {
+ /* We need to treat this as variable trailing
+ * context so that the backup does not happen
+ * in the action but before the action switch
+ * statement. If the backup happens in the
+ * action, then the rules "falling into" this
+ * one's action will *also* do the backup,
+ * erroneously.
+ */
+ if ( ! varlength || headcnt != 0 )
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ /* Mark as variable. */
+ varlength = true;
+ headcnt = 0;
+ }
+
+ if ( lex_compat || (varlength && headcnt == 0) )
+ { /* variable trailing context rule */
+ /* Mark the first part of the rule as the
+ * accepting "head" part of a trailing
+ * context rule.
+ *
+ * By the way, we didn't do this at the
+ * beginning of this production because back
+ * then current_state_type was set up for a
+ * trail rule, and add_accept() can create
+ * a new state ...
+ */
+ add_accept( $1,
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ else
+ trailcnt = rulelen;
+
+ $$ = link_machines( $1, $2 );
+ }
+
+ | re2 re '$'
+ { synerr( "trailing context used twice" ); }
+
+ | re '$'
+ {
+ headcnt = 0;
+ trailcnt = 1;
+ rulelen = 1;
+ varlength = false;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+
+ if ( trlcontxt )
+ {
+ synerr( "trailing context used twice" );
+ $$ = mkstate( SYM_EPSILON );
+ }
+
+ else if ( previous_continued_action )
+ {
+ /* See the comment in the rule for "re2 re"
+ * above.
+ */
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ varlength = true;
+ }
+
+ if ( lex_compat || varlength )
+ {
+ /* Again, see the comment in the rule for
+ * "re2 re" above.
+ */
+ add_accept( $1,
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ trlcontxt = true;
+
+ eps = mkstate( SYM_EPSILON );
+ $$ = link_machines( $1,
+ link_machines( eps, mkstate( '\n' ) ) );
+ }
+
+ | re
+ {
+ $$ = $1;
+
+ if ( trlcontxt )
+ {
+ if ( lex_compat || (varlength && headcnt == 0) )
+ /* Both head and trail are
+ * variable-length.
+ */
+ variable_trail_rule = true;
+ else
+ trailcnt = rulelen;
+ }
+ }
+ ;
+
+
+re : re '|' series
+ {
+ varlength = true;
+ $$ = mkor( $1, $3 );
+ }
+
+ | series
+ { $$ = $1; }
+ ;
+
+
+re2 : re '/'
+ {
+ /* This rule is written separately so the
+ * reduction will occur before the trailing
+ * series is parsed.
+ */
+
+ if ( trlcontxt )
+ synerr( "trailing context used twice" );
+ else
+ trlcontxt = true;
+
+ if ( varlength )
+ /* We hope the trailing context is
+ * fixed-length.
+ */
+ varlength = false;
+ else
+ headcnt = rulelen;
+
+ rulelen = 0;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+ $$ = $1;
+ }
+ ;
+
+series : series singleton
+ {
+ /* This is where concatenation of adjacent patterns
+ * gets done.
+ */
+ $$ = link_machines( $1, $2 );
+ }
+
+ | singleton
+ { $$ = $1; }
+ ;
+
+singleton : singleton '*'
+ {
+ varlength = true;
+
+ $$ = mkclos( $1 );
+ }
+
+ | singleton '+'
+ {
+ varlength = true;
+ $$ = mkposcl( $1 );
+ }
+
+ | singleton '?'
+ {
+ varlength = true;
+ $$ = mkopt( $1 );
+ }
+
+ | singleton '{' NUMBER ',' NUMBER '}'
+ {
+ varlength = true;
+
+ if ( $3 > $5 || $3 < 0 )
+ {
+ synerr( "bad iteration values" );
+ $$ = $1;
+ }
+ else
+ {
+ if ( $3 == 0 )
+ {
+ if ( $5 <= 0 )
+ {
+ synerr(
+ "bad iteration values" );
+ $$ = $1;
+ }
+ else
+ $$ = mkopt(
+ mkrep( $1, 1, $5 ) );
+ }
+ else
+ $$ = mkrep( $1, $3, $5 );
+ }
+ }
+
+ | singleton '{' NUMBER ',' '}'
+ {
+ varlength = true;
+
+ if ( $3 <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ $$ = $1;
+ }
+
+ else
+ $$ = mkrep( $1, $3, INFINITY );
+ }
+
+ | singleton '{' NUMBER '}'
+ {
+ /* The singleton could be something like "(foo)",
+ * in which case we have no idea what its length
+ * is, so we punt here.
+ */
+ varlength = true;
+
+ if ( $3 <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ $$ = $1;
+ }
+
+ else
+ $$ = link_machines( $1,
+ copysingl( $1, $3 - 1 ) );
+ }
+
+ | '.'
+ {
+ if ( ! madeany )
+ {
+ /* Create the '.' character class. */
+ anyccl = cclinit();
+ ccladd( anyccl, '\n' );
+ cclnegate( anyccl );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[anyccl],
+ ccllen[anyccl], nextecm,
+ ecgroup, csize, csize );
+
+ madeany = true;
+ }
+
+ ++rulelen;
+
+ $$ = mkstate( -anyccl );
+ }
+
+ | fullccl
+ {
+ if ( ! cclsorted )
+ /* Sort characters for fast searching. We
+ * use a shell sort since this list could
+ * be large.
+ */
+ cshell( ccltbl + cclmap[$1], ccllen[$1], true );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[$1], ccllen[$1],
+ nextecm, ecgroup, csize, csize );
+
+ ++rulelen;
+
+ $$ = mkstate( -$1 );
+ }
+
+ | PREVCCL
+ {
+ ++rulelen;
+
+ $$ = mkstate( -$1 );
+ }
+
+ | '"' string '"'
+ { $$ = $2; }
+
+ | '(' re ')'
+ { $$ = $2; }
+
+ | CHAR
+ {
+ ++rulelen;
+
+ if ( caseins && $1 >= 'A' && $1 <= 'Z' )
+ $1 = clower( $1 );
+
+ $$ = mkstate( $1 );
+ }
+ ;
+
+fullccl : '[' ccl ']'
+ { $$ = $2; }
+
+ | '[' '^' ccl ']'
+ {
+ cclnegate( $3 );
+ $$ = $3;
+ }
+ ;
+
+ccl : ccl CHAR '-' CHAR
+ {
+ if ( caseins )
+ {
+ if ( $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+ if ( $4 >= 'A' && $4 <= 'Z' )
+ $4 = clower( $4 );
+ }
+
+ if ( $2 > $4 )
+ synerr( "negative range in character class" );
+
+ else
+ {
+ for ( i = $2; i <= $4; ++i )
+ ccladd( $1, i );
+
+ /* Keep track if this ccl is staying in
+ * alphabetical order.
+ */
+ cclsorted = cclsorted && ($2 > lastchar);
+ lastchar = $4;
+ }
+
+ $$ = $1;
+ }
+
+ | ccl CHAR
+ {
+ if ( caseins && $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+
+ ccladd( $1, $2 );
+ cclsorted = cclsorted && ($2 > lastchar);
+ lastchar = $2;
+ $$ = $1;
+ }
+
+ | ccl ccl_expr
+ {
+ /* Too hard to properly maintain cclsorted. */
+ cclsorted = false;
+ $$ = $1;
+ }
+
+ |
+ {
+ cclsorted = true;
+ lastchar = 0;
+ currccl = $$ = cclinit();
+ }
+ ;
+
+ccl_expr: CCE_ALNUM { CCL_EXPR(isalnum) }
+ | CCE_ALPHA { CCL_EXPR(isalpha) }
+ | CCE_BLANK { CCL_EXPR(IS_BLANK) }
+ | CCE_CNTRL { CCL_EXPR(iscntrl) }
+ | CCE_DIGIT { CCL_EXPR(isdigit) }
+ | CCE_GRAPH { CCL_EXPR(isgraph) }
+ | CCE_LOWER { CCL_EXPR(islower) }
+ | CCE_PRINT { CCL_EXPR(isprint) }
+ | CCE_PUNCT { CCL_EXPR(ispunct) }
+ | CCE_SPACE { CCL_EXPR(isspace) }
+ | CCE_UPPER {
+ if ( caseins )
+ CCL_EXPR(islower)
+ else
+ CCL_EXPR(isupper)
+ }
+ | CCE_XDIGIT { CCL_EXPR(isxdigit) }
+ ;
+
+string : string CHAR
+ {
+ if ( caseins && $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+
+ ++rulelen;
+
+ $$ = link_machines( $1, mkstate( $2 ) );
+ }
+
+ |
+ { $$ = mkstate( SYM_EPSILON ); }
+ ;
+
+%%
+
+
+/* build_eof_action - build the "<<EOF>>" action for the active start
+ * conditions
+ */
+
+void build_eof_action()
+ {
+ register int i;
+ char action_text[MAXLINE];
+
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ {
+ if ( sceof[scon_stk[i]] )
+ format_pinpoint_message(
+ "multiple <<EOF>> rules for start condition %s",
+ scname[scon_stk[i]] );
+
+ else
+ {
+ sceof[scon_stk[i]] = true;
+ sprintf( action_text, "case YY_STATE_EOF(%s):\n",
+ scname[scon_stk[i]] );
+ add_action( action_text );
+ }
+ }
+
+ line_directive_out( (FILE *) 0, 1 );
+
+ /* This isn't a normal rule after all - don't count it as
+ * such, so we don't have any holes in the rule numbering
+ * (which make generating "rule can never match" warnings
+ * more difficult.
+ */
+ --num_rules;
+ ++num_eof_rules;
+ }
+
+
+/* format_synerr - write out formatted syntax error */
+
+void format_synerr( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ synerr( errmsg );
+ }
+
+
+/* synerr - report a syntax error */
+
+void synerr( str )
+char str[];
+ {
+ syntaxerror = true;
+ pinpoint_message( str );
+ }
+
+
+/* format_warn - write out formatted warning */
+
+void format_warn( msg, arg )
+char msg[], arg[];
+ {
+ char warn_msg[MAXLINE];
+
+ (void) sprintf( warn_msg, msg, arg );
+ warn( warn_msg );
+ }
+
+
+/* warn - report a warning, unless -w was given */
+
+void warn( str )
+char str[];
+ {
+ line_warning( str, linenum );
+ }
+
+/* format_pinpoint_message - write out a message formatted with one string,
+ * pinpointing its location
+ */
+
+void format_pinpoint_message( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ pinpoint_message( errmsg );
+ }
+
+
+/* pinpoint_message - write out a message, pinpointing its location */
+
+void pinpoint_message( str )
+char str[];
+ {
+ line_pinpoint( str, linenum );
+ }
+
+
+/* line_warning - report a warning at a given line, unless -w was given */
+
+void line_warning( str, line )
+char str[];
+int line;
+ {
+ char warning[MAXLINE];
+
+ if ( ! nowarn )
+ {
+ sprintf( warning, "warning, %s", str );
+ line_pinpoint( warning, line );
+ }
+ }
+
+
+/* line_pinpoint - write out a message, pinpointing it at the given line */
+
+void line_pinpoint( str, line )
+char str[];
+int line;
+ {
+ fprintf( stderr, "\"%s\", line %d: %s\n", infilename, line, str );
+ }
+
+
+/* yyerror - eat up an error message from the parser;
+ * currently, messages are ignore
+ */
+
+void yyerror( msg )
+char msg[];
+ {
+ }
diff --git a/usr.bin/lex/scan.l b/usr.bin/lex/scan.l
new file mode 100644
index 0000000..2db8d78
--- /dev/null
+++ b/usr.bin/lex/scan.l
@@ -0,0 +1,710 @@
+/* scan.l - scanner for flex input */
+
+%{
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/scan.l,v 1.2 1996/06/19 22:25:32 nate Exp $ */
+
+#include "flexdef.h"
+#include "parse.h"
+
+#define ACTION_ECHO add_action( yytext )
+#define ACTION_IFDEF(def, should_define) \
+ { \
+ if ( should_define ) \
+ action_define( def, 1 ); \
+ }
+
+#define MARK_END_OF_PROLOG mark_prolog();
+
+#define YY_DECL \
+ int flexscan()
+
+#define RETURNCHAR \
+ yylval = (unsigned char) yytext[0]; \
+ return CHAR;
+
+#define RETURNNAME \
+ strcpy( nmstr, yytext ); \
+ return NAME;
+
+#define PUT_BACK_STRING(str, start) \
+ for ( i = strlen( str ) - 1; i >= start; --i ) \
+ unput((str)[i])
+
+#define CHECK_REJECT(str) \
+ if ( all_upper( str ) ) \
+ reject = true;
+
+#define CHECK_YYMORE(str) \
+ if ( all_lower( str ) ) \
+ yymore_used = true;
+%}
+
+%option caseless nodefault outfile="scan.c" stack noyy_top_state
+%option nostdinit
+
+%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
+%x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
+%x OPTION LINEDIR
+
+WS [[:blank:]]+
+OPTWS [[:blank:]]*
+NOT_WS [^[:blank:]\n]
+
+NL \r?\n
+
+NAME ([[:alpha:]_][[:alnum:]_-]*)
+NOT_NAME [^[:alpha:]_*\n]+
+
+SCNAME {NAME}
+
+ESCSEQ (\\([^\n]|[0-7]{1,3}|x[[:xdigit:]]{1,2}))
+
+FIRST_CCL_CHAR ([^\\\n]|{ESCSEQ})
+CCL_CHAR ([^\\\n\]]|{ESCSEQ})
+CCL_EXPR ("[:"[[:alpha:]]+":]")
+
+LEXOPT [aceknopr]
+
+%%
+ static int bracelevel, didadef, indented_code;
+ static int doing_rule_action = false;
+ static int option_sense;
+
+ int doing_codeblock = false;
+ int i;
+ Char nmdef[MAXLINE], myesc();
+
+
+<INITIAL>{
+ ^{WS} indented_code = true; BEGIN(CODEBLOCK);
+ ^"/*" ACTION_ECHO; yy_push_state( COMMENT );
+ ^#{OPTWS}line{WS} yy_push_state( LINEDIR );
+ ^"%s"{NAME}? return SCDECL;
+ ^"%x"{NAME}? return XSCDECL;
+ ^"%{".*{NL} {
+ ++linenum;
+ line_directive_out( (FILE *) 0, 1 );
+ indented_code = false;
+ BEGIN(CODEBLOCK);
+ }
+
+ {WS} /* discard */
+
+ ^"%%".* {
+ sectnum = 2;
+ bracelevel = 0;
+ mark_defs1();
+ line_directive_out( (FILE *) 0, 1 );
+ BEGIN(SECT2PROLOG);
+ return SECTEND;
+ }
+
+ ^"%pointer".*{NL} yytext_is_array = false; ++linenum;
+ ^"%array".*{NL} yytext_is_array = true; ++linenum;
+
+ ^"%option" BEGIN(OPTION); return OPTION_OP;
+
+ ^"%"{LEXOPT}{OPTWS}[[:digit:]]*{OPTWS}{NL} ++linenum; /* ignore */
+ ^"%"{LEXOPT}{WS}.*{NL} ++linenum; /* ignore */
+
+ ^"%"[^sxaceknopr{}].* synerr( _( "unrecognized '%' directive" ) );
+
+ ^{NAME} {
+ strcpy( nmstr, yytext );
+ didadef = false;
+ BEGIN(PICKUPDEF);
+ }
+
+ {SCNAME} RETURNNAME;
+ ^{OPTWS}{NL} ++linenum; /* allows blank lines in section 1 */
+ {OPTWS}{NL} ACTION_ECHO; ++linenum; /* maybe end of comment line */
+}
+
+
+<COMMENT>{
+ "*/" ACTION_ECHO; yy_pop_state();
+ "*" ACTION_ECHO;
+ [^*\n]+ ACTION_ECHO;
+ [^*\n]*{NL} ++linenum; ACTION_ECHO;
+}
+
+<LINEDIR>{
+ \n yy_pop_state();
+ [[:digit:]]+ linenum = myctoi( yytext );
+
+ \"[^"\n]*\" {
+ flex_free( (void *) infilename );
+ infilename = copy_string( yytext + 1 );
+ infilename[strlen( infilename ) - 1] = '\0';
+ }
+ . /* ignore spurious characters */
+}
+
+<CODEBLOCK>{
+ ^"%}".*{NL} ++linenum; BEGIN(INITIAL);
+
+ {NAME}|{NOT_NAME}|. ACTION_ECHO;
+
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( indented_code )
+ BEGIN(INITIAL);
+ }
+}
+
+
+<PICKUPDEF>{
+ {WS} /* separates name and definition */
+
+ {NOT_WS}.* {
+ strcpy( (char *) nmdef, yytext );
+
+ /* Skip trailing whitespace. */
+ for ( i = strlen( (char *) nmdef ) - 1;
+ i >= 0 && (nmdef[i] == ' ' || nmdef[i] == '\t');
+ --i )
+ ;
+
+ nmdef[i + 1] = '\0';
+
+ ndinstal( nmstr, nmdef );
+ didadef = true;
+ }
+
+ {NL} {
+ if ( ! didadef )
+ synerr( _( "incomplete name definition" ) );
+ BEGIN(INITIAL);
+ ++linenum;
+ }
+}
+
+
+<OPTION>{
+ {NL} ++linenum; BEGIN(INITIAL);
+ {WS} option_sense = true;
+
+ "=" return '=';
+
+ no option_sense = ! option_sense;
+
+ 7bit csize = option_sense ? 128 : 256;
+ 8bit csize = option_sense ? 256 : 128;
+
+ align long_align = option_sense;
+ always-interactive {
+ action_define( "YY_ALWAYS_INTERACTIVE", option_sense );
+ }
+ array yytext_is_array = option_sense;
+ backup backing_up_report = option_sense;
+ batch interactive = ! option_sense;
+ "c++" C_plus_plus = option_sense;
+ caseful|case-sensitive caseins = ! option_sense;
+ caseless|case-insensitive caseins = option_sense;
+ debug ddebug = option_sense;
+ default spprdflt = ! option_sense;
+ ecs useecs = option_sense;
+ fast {
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ }
+ full {
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ }
+ input ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
+ interactive interactive = option_sense;
+ lex-compat lex_compat = option_sense;
+ main {
+ action_define( "YY_MAIN", option_sense );
+ do_yywrap = ! option_sense;
+ }
+ meta-ecs usemecs = option_sense;
+ never-interactive {
+ action_define( "YY_NEVER_INTERACTIVE", option_sense );
+ }
+ perf-report performance_report += option_sense ? 1 : -1;
+ pointer yytext_is_array = ! option_sense;
+ read use_read = option_sense;
+ reject reject_really_used = option_sense;
+ stack action_define( "YY_STACK_USED", option_sense );
+ stdinit do_stdinit = option_sense;
+ stdout use_stdout = option_sense;
+ unput ACTION_IFDEF("YY_NO_UNPUT", ! option_sense);
+ verbose printstats = option_sense;
+ warn nowarn = ! option_sense;
+ yylineno do_yylineno = option_sense;
+ yymore yymore_really_used = option_sense;
+ yywrap do_yywrap = option_sense;
+
+ yy_push_state ACTION_IFDEF("YY_NO_PUSH_STATE", ! option_sense);
+ yy_pop_state ACTION_IFDEF("YY_NO_POP_STATE", ! option_sense);
+ yy_top_state ACTION_IFDEF("YY_NO_TOP_STATE", ! option_sense);
+
+ yy_scan_buffer ACTION_IFDEF("YY_NO_SCAN_BUFFER", ! option_sense);
+ yy_scan_bytes ACTION_IFDEF("YY_NO_SCAN_BYTES", ! option_sense);
+ yy_scan_string ACTION_IFDEF("YY_NO_SCAN_STRING", ! option_sense);
+
+ outfile return OPT_OUTFILE;
+ prefix return OPT_PREFIX;
+ yyclass return OPT_YYCLASS;
+
+ \"[^"\n]*\" {
+ strcpy( nmstr, yytext + 1 );
+ nmstr[strlen( nmstr ) - 1] = '\0';
+ return NAME;
+ }
+
+ (([a-mo-z]|n[a-np-z])[[:alpha:]\-+]*)|. {
+ format_synerr( _( "unrecognized %%option: %s" ),
+ yytext );
+ BEGIN(RECOVER);
+ }
+}
+
+<RECOVER>.*{NL} ++linenum; BEGIN(INITIAL);
+
+
+<SECT2PROLOG>{
+ ^"%{".* ++bracelevel; yyless( 2 ); /* eat only %{ */
+ ^"%}".* --bracelevel; yyless( 2 ); /* eat only %} */
+
+ ^{WS}.* ACTION_ECHO; /* indented code in prolog */
+
+ ^{NOT_WS}.* { /* non-indented code */
+ if ( bracelevel <= 0 )
+ { /* not in %{ ... %} */
+ yyless( 0 ); /* put it all back */
+ yy_set_bol( 1 );
+ mark_prolog();
+ BEGIN(SECT2);
+ }
+ else
+ ACTION_ECHO;
+ }
+
+ .* ACTION_ECHO;
+ {NL} ++linenum; ACTION_ECHO;
+
+ <<EOF>> {
+ mark_prolog();
+ sectnum = 0;
+ yyterminate(); /* to stop the parser */
+ }
+}
+
+<SECT2>{
+ ^{OPTWS}{NL} ++linenum; /* allow blank lines in section 2 */
+
+ ^{OPTWS}"%{" {
+ indented_code = false;
+ doing_codeblock = true;
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+ }
+
+ ^{OPTWS}"<" BEGIN(SC); return '<';
+ ^{OPTWS}"^" return '^';
+ \" BEGIN(QUOTE); return '"';
+ "{"/[[:digit:]] BEGIN(NUM); return '{';
+ "$"/([[:blank:]]|{NL}) return '$';
+
+ {WS}"%{" {
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ {WS}"|".*{NL} continued_action = true; ++linenum; return '\n';
+
+ ^{WS}"/*" {
+ yyless( yyleng - 2 ); /* put back '/', '*' */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ }
+
+ ^{WS} /* allow indented rules */
+
+ {WS} {
+ /* This rule is separate from the one below because
+ * otherwise we get variable trailing context, so
+ * we can't build the scanner using -{f,F}.
+ */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+
+ {OPTWS}{NL} {
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ unput( '\n' ); /* so <ACTION> sees it */
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+
+ ^{OPTWS}"<<EOF>>" |
+ "<<EOF>>" return EOF_OP;
+
+ ^"%%".* {
+ sectnum = 3;
+ BEGIN(SECT3);
+ yyterminate(); /* to stop the parser */
+ }
+
+ "["({FIRST_CCL_CHAR}|{CCL_EXPR})({CCL_CHAR}|{CCL_EXPR})* {
+ int cclval;
+
+ strcpy( nmstr, yytext );
+
+ /* Check to see if we've already encountered this
+ * ccl.
+ */
+ if ( (cclval = ccllookup( (Char *) nmstr )) != 0 )
+ {
+ if ( input() != ']' )
+ synerr( _( "bad character class" ) );
+
+ yylval = cclval;
+ ++cclreuse;
+ return PREVCCL;
+ }
+ else
+ {
+ /* We fudge a bit. We know that this ccl will
+ * soon be numbered as lastccl + 1 by cclinit.
+ */
+ cclinstal( (Char *) nmstr, lastccl + 1 );
+
+ /* Push back everything but the leading bracket
+ * so the ccl can be rescanned.
+ */
+ yyless( 1 );
+
+ BEGIN(FIRSTCCL);
+ return '[';
+ }
+ }
+
+ "{"{NAME}"}" {
+ register Char *nmdefptr;
+ Char *ndlookup();
+
+ strcpy( nmstr, yytext + 1 );
+ nmstr[yyleng - 2] = '\0'; /* chop trailing brace */
+
+ if ( (nmdefptr = ndlookup( nmstr )) == 0 )
+ format_synerr(
+ _( "undefined definition {%s}" ),
+ nmstr );
+
+ else
+ { /* push back name surrounded by ()'s */
+ int len = strlen( (char *) nmdefptr );
+
+ if ( lex_compat || nmdefptr[0] == '^' ||
+ (len > 0 && nmdefptr[len - 1] == '$') )
+ { /* don't use ()'s after all */
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+
+ if ( nmdefptr[0] == '^' )
+ BEGIN(CARETISBOL);
+ }
+
+ else
+ {
+ unput(')');
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+ unput('(');
+ }
+ }
+ }
+
+ [/|*+?.(){}] return (unsigned char) yytext[0];
+ . RETURNCHAR;
+}
+
+
+<SC>{
+ [,*] return (unsigned char) yytext[0];
+ ">" BEGIN(SECT2); return '>';
+ ">"/^ BEGIN(CARETISBOL); return '>';
+ {SCNAME} RETURNNAME;
+ . {
+ format_synerr( _( "bad <start condition>: %s" ),
+ yytext );
+ }
+}
+
+<CARETISBOL>"^" BEGIN(SECT2); return '^';
+
+
+<QUOTE>{
+ [^"\n] RETURNCHAR;
+ \" BEGIN(SECT2); return '"';
+
+ {NL} {
+ synerr( _( "missing quote" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '"';
+ }
+}
+
+
+<FIRSTCCL>{
+ "^"/[^-\]\n] BEGIN(CCL); return '^';
+ "^"/("-"|"]") return '^';
+ . BEGIN(CCL); RETURNCHAR;
+}
+
+<CCL>{
+ -/[^\]\n] return '-';
+ [^\]\n] RETURNCHAR;
+ "]" BEGIN(SECT2); return ']';
+ .|{NL} {
+ synerr( _( "bad character class" ) );
+ BEGIN(SECT2);
+ return ']';
+ }
+}
+
+<FIRSTCCL,CCL>{
+ "[:alnum:]" BEGIN(CCL); return CCE_ALNUM;
+ "[:alpha:]" BEGIN(CCL); return CCE_ALPHA;
+ "[:blank:]" BEGIN(CCL); return CCE_BLANK;
+ "[:cntrl:]" BEGIN(CCL); return CCE_CNTRL;
+ "[:digit:]" BEGIN(CCL); return CCE_DIGIT;
+ "[:graph:]" BEGIN(CCL); return CCE_GRAPH;
+ "[:lower:]" BEGIN(CCL); return CCE_LOWER;
+ "[:print:]" BEGIN(CCL); return CCE_PRINT;
+ "[:punct:]" BEGIN(CCL); return CCE_PUNCT;
+ "[:space:]" BEGIN(CCL); return CCE_SPACE;
+ "[:upper:]" BEGIN(CCL); return CCE_UPPER;
+ "[:xdigit:]" BEGIN(CCL); return CCE_XDIGIT;
+ {CCL_EXPR} {
+ format_synerr(
+ _( "bad character class expression: %s" ),
+ yytext );
+ BEGIN(CCL); return CCE_ALNUM;
+ }
+}
+
+<NUM>{
+ [[:digit:]]+ {
+ yylval = myctoi( yytext );
+ return NUMBER;
+ }
+
+ "," return ',';
+ "}" BEGIN(SECT2); return '}';
+
+ . {
+ synerr( _( "bad character inside {}'s" ) );
+ BEGIN(SECT2);
+ return '}';
+ }
+
+ {NL} {
+ synerr( _( "missing }" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '}';
+ }
+}
+
+
+<PERCENT_BRACE_ACTION>{
+ {OPTWS}"%}".* bracelevel = 0;
+
+ <ACTION>"/*" ACTION_ECHO; yy_push_state( COMMENT );
+
+ <CODEBLOCK,ACTION>{
+ "reject" {
+ ACTION_ECHO;
+ CHECK_REJECT(yytext);
+ }
+ "yymore" {
+ ACTION_ECHO;
+ CHECK_YYMORE(yytext);
+ }
+ }
+
+ {NAME}|{NOT_NAME}|. ACTION_ECHO;
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 ||
+ (doing_codeblock && indented_code) )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = doing_codeblock = false;
+ BEGIN(SECT2);
+ }
+ }
+}
+
+
+ /* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
+<ACTION>{
+ "{" ACTION_ECHO; ++bracelevel;
+ "}" ACTION_ECHO; --bracelevel;
+ [^[:alpha:]_{}"'/\n]+ ACTION_ECHO;
+ {NAME} ACTION_ECHO;
+ "'"([^'\\\n]|\\.)*"'" ACTION_ECHO; /* character constant */
+ \" ACTION_ECHO; BEGIN(ACTION_STRING);
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = false;
+ BEGIN(SECT2);
+ }
+ }
+ . ACTION_ECHO;
+}
+
+<ACTION_STRING>{
+ [^"\\\n]+ ACTION_ECHO;
+ \\. ACTION_ECHO;
+ {NL} ++linenum; ACTION_ECHO;
+ \" ACTION_ECHO; BEGIN(ACTION);
+ . ACTION_ECHO;
+}
+
+<COMMENT,ACTION,ACTION_STRING><<EOF>> {
+ synerr( _( "EOF encountered inside an action" ) );
+ yyterminate();
+ }
+
+
+<SECT2,QUOTE,FIRSTCCL,CCL>{ESCSEQ} {
+ yylval = myesc( (Char *) yytext );
+
+ if ( YY_START == FIRSTCCL )
+ BEGIN(CCL);
+
+ return CHAR;
+ }
+
+
+<SECT3>{
+ .*(\n?) ECHO;
+ <<EOF>> sectnum = 0; yyterminate();
+}
+
+<*>.|\n format_synerr( _( "bad character: %s" ), yytext );
+
+%%
+
+
+int yywrap()
+ {
+ if ( --num_input_files > 0 )
+ {
+ set_input_file( *++input_files );
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+
+/* set_input_file - open the given file (if NULL, stdin) for scanning */
+
+void set_input_file( file )
+char *file;
+ {
+ if ( file && strcmp( file, "-" ) )
+ {
+ infilename = copy_string( file );
+ yyin = fopen( infilename, "r" );
+
+ if ( yyin == NULL )
+ lerrsf( _( "can't open %s" ), file );
+ }
+
+ else
+ {
+ yyin = stdin;
+ infilename = copy_string( "<stdin>" );
+ }
+
+ linenum = 1;
+ }
+
+
+/* Wrapper routines for accessing the scanner's malloc routines. */
+
+void *flex_alloc( size )
+size_t size;
+ {
+ return (void *) malloc( size );
+ }
+
+void *flex_realloc( ptr, size )
+void *ptr;
+size_t size;
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+void flex_free( ptr )
+void *ptr;
+ {
+ if ( ptr )
+ free( ptr );
+ }
diff --git a/usr.bin/lex/skel.c b/usr.bin/lex/skel.c
new file mode 100644
index 0000000..962c830
--- /dev/null
+++ b/usr.bin/lex/skel.c
@@ -0,0 +1,1548 @@
+/* File created from flex.skl via mkskel.sh */
+
+#include "flexdef.h"
+
+const char *skel[] = {
+ "/* A lexical scanner generated by flex */",
+ "",
+ "/* Scanner skeleton version:",
+ " * $Header: /home/ncvs/src/usr.bin/lex/skel.c,v 1.1.1.2 1996/06/19 20:26:34 nate Exp $",
+ " */",
+ "",
+ "#define FLEX_SCANNER",
+ "#define YY_FLEX_MAJOR_VERSION 2",
+ "#define YY_FLEX_MINOR_VERSION 5",
+ "",
+ "%-",
+ "#include <stdio.h>",
+ "%*",
+ "",
+ "",
+ "/* cfront 1.2 defines \"c_plusplus\" instead of \"__cplusplus\" */",
+ "#ifdef c_plusplus",
+ "#ifndef __cplusplus",
+ "#define __cplusplus",
+ "#endif",
+ "#endif",
+ "",
+ "",
+ "#ifdef __cplusplus",
+ "",
+ "#include <stdlib.h>",
+ "%+",
+ "class istream;",
+ "%*",
+ "#include <unistd.h>",
+ "",
+ "/* Use prototypes in function declarations. */",
+ "#define YY_USE_PROTOS",
+ "",
+ "/* The \"const\" storage-class-modifier is valid. */",
+ "#define YY_USE_CONST",
+ "",
+ "#else /* ! __cplusplus */",
+ "",
+ "#if __STDC__",
+ "",
+ "#define YY_USE_PROTOS",
+ "#define YY_USE_CONST",
+ "",
+ "#endif /* __STDC__ */",
+ "#endif /* ! __cplusplus */",
+ "",
+ "#ifdef __TURBOC__",
+ " #pragma warn -rch",
+ " #pragma warn -use",
+ "#include <io.h>",
+ "#include <stdlib.h>",
+ "#define YY_USE_CONST",
+ "#define YY_USE_PROTOS",
+ "#endif",
+ "",
+ "#ifdef YY_USE_CONST",
+ "#define yyconst const",
+ "#else",
+ "#define yyconst",
+ "#endif",
+ "",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "#define YY_PROTO(proto) proto",
+ "#else",
+ "#define YY_PROTO(proto) ()",
+ "#endif",
+ "",
+ "/* Returned upon end-of-file. */",
+ "#define YY_NULL 0",
+ "",
+ "/* Promotes a possibly negative, possibly signed char to an unsigned",
+ " * integer for use as an array index. If the signed char is negative,",
+ " * we want to instead treat it as an 8-bit unsigned char, hence the",
+ " * double cast.",
+ " */",
+ "#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)",
+ "",
+ "/* Enter a start condition. This macro really ought to take a parameter,",
+ " * but we do it the disgusting crufty way forced on us by the ()-less",
+ " * definition of BEGIN.",
+ " */",
+ "#define BEGIN yy_start = 1 + 2 *",
+ "",
+ "/* Translate the current start state into a value that can be later handed",
+ " * to BEGIN to return to the state. The YYSTATE alias is for lex",
+ " * compatibility.",
+ " */",
+ "#define YY_START ((yy_start - 1) / 2)",
+ "#define YYSTATE YY_START",
+ "",
+ "/* Action number for EOF rule of a given start state. */",
+ "#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)",
+ "",
+ "/* Special action meaning \"start processing a new file\". */",
+ "#define YY_NEW_FILE yyrestart( yyin )",
+ "",
+ "#define YY_END_OF_BUFFER_CHAR 0",
+ "",
+ "/* Size of default input buffer. */",
+ "#define YY_BUF_SIZE 16384",
+ "",
+ "typedef struct yy_buffer_state *YY_BUFFER_STATE;",
+ "",
+ "extern int yyleng;",
+ "%-",
+ "extern FILE *yyin, *yyout;",
+ "%*",
+ "",
+ "#define EOB_ACT_CONTINUE_SCAN 0",
+ "#define EOB_ACT_END_OF_FILE 1",
+ "#define EOB_ACT_LAST_MATCH 2",
+ "",
+ "/* The funky do-while in the following #define is used to turn the definition",
+ " * int a single C statement (which needs a semi-colon terminator). This",
+ " * avoids problems with code like:",
+ " *",
+ " * if ( condition_holds )",
+ " * yyless( 5 );",
+ " * else",
+ " * do_something_else();",
+ " *",
+ " * Prior to using the do-while the compiler would get upset at the",
+ " * \"else\" because it interpreted the \"if\" statement as being all",
+ " * done when it reached the ';' after the yyless() call.",
+ " */",
+ "",
+ "/* Return all but the first 'n' matched characters back to the input stream. */",
+ "",
+ "#define yyless(n) \\",
+ " do \\",
+ " { \\",
+ " /* Undo effects of setting up yytext. */ \\",
+ " *yy_cp = yy_hold_char; \\",
+ " YY_RESTORE_YY_MORE_OFFSET \\",
+ " yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \\",
+ " YY_DO_BEFORE_ACTION; /* set up yytext again */ \\",
+ " } \\",
+ " while ( 0 )",
+ "",
+ "#define unput(c) yyunput( c, yytext_ptr )",
+ "",
+ "/* The following is because we cannot portably get our hands on size_t",
+ " * (without autoconf's help, which isn't available because we want",
+ " * flex-generated scanners to compile on their own).",
+ " */",
+ "typedef unsigned int yy_size_t;",
+ "",
+ "",
+ "struct yy_buffer_state",
+ " {",
+ "%-",
+ " FILE *yy_input_file;",
+ "%+",
+ " istream* yy_input_file;",
+ "%*",
+ "",
+ " char *yy_ch_buf; /* input buffer */",
+ " char *yy_buf_pos; /* current position in input buffer */",
+ "",
+ " /* Size of input buffer in bytes, not including room for EOB",
+ " * characters.",
+ " */",
+ " yy_size_t yy_buf_size;",
+ "",
+ " /* Number of characters read into yy_ch_buf, not including EOB",
+ " * characters.",
+ " */",
+ " int yy_n_chars;",
+ "",
+ " /* Whether we \"own\" the buffer - i.e., we know we created it,",
+ " * and can realloc() it to grow it, and should free() it to",
+ " * delete it.",
+ " */",
+ " int yy_is_our_buffer;",
+ "",
+ " /* Whether this is an \"interactive\" input source; if so, and",
+ " * if we're using stdio for input, then we want to use getc()",
+ " * instead of fread(), to make sure we stop fetching input after",
+ " * each newline.",
+ " */",
+ " int yy_is_interactive;",
+ "",
+ " /* Whether we're considered to be at the beginning of a line.",
+ " * If so, '^' rules will be active on the next match, otherwise",
+ " * not.",
+ " */",
+ " int yy_at_bol;",
+ "",
+ " /* Whether to try to fill the input buffer when we reach the",
+ " * end of it.",
+ " */",
+ " int yy_fill_buffer;",
+ "",
+ " int yy_buffer_status;",
+ "#define YY_BUFFER_NEW 0",
+ "#define YY_BUFFER_NORMAL 1",
+ " /* When an EOF's been seen but there's still some text to process",
+ " * then we mark the buffer as YY_EOF_PENDING, to indicate that we",
+ " * shouldn't try reading from the input source any more. We might",
+ " * still have a bunch of tokens to match, though, because of",
+ " * possible backing-up.",
+ " *",
+ " * When we actually see the EOF, we change the status to \"new\"",
+ " * (via yyrestart()), so that the user can continue scanning by",
+ " * just pointing yyin at a new input file.",
+ " */",
+ "#define YY_BUFFER_EOF_PENDING 2",
+ " };",
+ "",
+ "%- Standard (non-C++) definition",
+ "static YY_BUFFER_STATE yy_current_buffer = 0;",
+ "%*",
+ "",
+ "/* We provide macros for accessing buffer states in case in the",
+ " * future we want to put the buffer states in a more general",
+ " * \"scanner state\".",
+ " */",
+ "#define YY_CURRENT_BUFFER yy_current_buffer",
+ "",
+ "",
+ "%- Standard (non-C++) definition",
+ "/* yy_hold_char holds the character lost when yytext is formed. */",
+ "static char yy_hold_char;",
+ "",
+ "static int yy_n_chars; /* number of characters read into yy_ch_buf */",
+ "",
+ "",
+ "int yyleng;",
+ "",
+ "/* Points to current character in buffer. */",
+ "static char *yy_c_buf_p = (char *) 0;",
+ "static int yy_init = 1; /* whether we need to initialize */",
+ "static int yy_start = 0; /* start state number */",
+ "",
+ "/* Flag which is used to allow yywrap()'s to do buffer switches",
+ " * instead of setting up a fresh yyin. A bit of a hack ...",
+ " */",
+ "static int yy_did_buffer_switch_on_eof;",
+ "",
+ "void yyrestart YY_PROTO(( FILE *input_file ));",
+ "",
+ "void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));",
+ "void yy_load_buffer_state YY_PROTO(( void ));",
+ "YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));",
+ "void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));",
+ "void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));",
+ "void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));",
+ "#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )",
+ "",
+ "YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));",
+ "YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));",
+ "YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));",
+ "%*",
+ "",
+ "static void *yy_flex_alloc YY_PROTO(( yy_size_t ));",
+ "static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));",
+ "static void yy_flex_free YY_PROTO(( void * ));",
+ "",
+ "#define yy_new_buffer yy_create_buffer",
+ "",
+ "#define yy_set_interactive(is_interactive) \\",
+ " { \\",
+ " if ( ! yy_current_buffer ) \\",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\",
+ " yy_current_buffer->yy_is_interactive = is_interactive; \\",
+ " }",
+ "",
+ "#define yy_set_bol(at_bol) \\",
+ " { \\",
+ " if ( ! yy_current_buffer ) \\",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\",
+ " yy_current_buffer->yy_at_bol = at_bol; \\",
+ " }",
+ "",
+ "#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)",
+ "",
+ "%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here",
+ "",
+ "%- Standard (non-C++) definition",
+ "static yy_state_type yy_get_previous_state YY_PROTO(( void ));",
+ "static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));",
+ "static int yy_get_next_buffer YY_PROTO(( void ));",
+ "static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));",
+ "%*",
+ "",
+ "/* Done after the current pattern has been matched and before the",
+ " * corresponding action - sets up yytext.",
+ " */",
+ "#define YY_DO_BEFORE_ACTION \\",
+ " yytext_ptr = yy_bp; \\",
+ "%% code to fiddle yytext and yyleng for yymore() goes here",
+ " yy_hold_char = *yy_cp; \\",
+ " *yy_cp = '\\0'; \\",
+ "%% code to copy yytext_ptr to yytext[] goes here, if %array",
+ " yy_c_buf_p = yy_cp;",
+ "",
+ "%% data tables for the DFA and the user's section 1 definitions go here",
+ "",
+ "/* Macros after this point can all be overridden by user definitions in",
+ " * section 1.",
+ " */",
+ "",
+ "#ifndef YY_SKIP_YYWRAP",
+ "#ifdef __cplusplus",
+ "extern \"C\" int yywrap YY_PROTO(( void ));",
+ "#else",
+ "extern int yywrap YY_PROTO(( void ));",
+ "#endif",
+ "#endif",
+ "",
+ "%-",
+ "#ifndef YY_NO_UNPUT",
+ "static void yyunput YY_PROTO(( int c, char *buf_ptr ));",
+ "#endif",
+ "%*",
+ "",
+ "#ifndef yytext_ptr",
+ "static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));",
+ "#endif",
+ "",
+ "#ifdef YY_NEED_STRLEN",
+ "static int yy_flex_strlen YY_PROTO(( yyconst char * ));",
+ "#endif",
+ "",
+ "#ifndef YY_NO_INPUT",
+ "%- Standard (non-C++) definition",
+ "#ifdef __cplusplus",
+ "static int yyinput YY_PROTO(( void ));",
+ "#else",
+ "static int input YY_PROTO(( void ));",
+ "#endif",
+ "%*",
+ "#endif",
+ "",
+ "#if YY_STACK_USED",
+ "static int yy_start_stack_ptr = 0;",
+ "static int yy_start_stack_depth = 0;",
+ "static int *yy_start_stack = 0;",
+ "#ifndef YY_NO_PUSH_STATE",
+ "static void yy_push_state YY_PROTO(( int new_state ));",
+ "#endif",
+ "#ifndef YY_NO_POP_STATE",
+ "static void yy_pop_state YY_PROTO(( void ));",
+ "#endif",
+ "#ifndef YY_NO_TOP_STATE",
+ "static int yy_top_state YY_PROTO(( void ));",
+ "#endif",
+ "",
+ "#else",
+ "#define YY_NO_PUSH_STATE 1",
+ "#define YY_NO_POP_STATE 1",
+ "#define YY_NO_TOP_STATE 1",
+ "#endif",
+ "",
+ "#ifdef YY_MALLOC_DECL",
+ "YY_MALLOC_DECL",
+ "#else",
+ "#if __STDC__",
+ "#ifndef __cplusplus",
+ "#include <stdlib.h>",
+ "#endif",
+ "#else",
+ "/* Just try to get by without declaring the routines. This will fail",
+ " * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)",
+ " * or sizeof(void*) != sizeof(int).",
+ " */",
+ "#endif",
+ "#endif",
+ "",
+ "/* Amount of stuff to slurp up with each read. */",
+ "#ifndef YY_READ_BUF_SIZE",
+ "#define YY_READ_BUF_SIZE 8192",
+ "#endif",
+ "",
+ "/* Copy whatever the last rule matched to the standard output. */",
+ "",
+ "#ifndef ECHO",
+ "%- Standard (non-C++) definition",
+ "/* This used to be an fputs(), but since the string might contain NUL's,",
+ " * we now use fwrite().",
+ " */",
+ "#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )",
+ "%+ C++ definition",
+ "#define ECHO LexerOutput( yytext, yyleng )",
+ "%*",
+ "#endif",
+ "",
+ "/* Gets input and stuffs it into \"buf\". number of characters read, or YY_NULL,",
+ " * is returned in \"result\".",
+ " */",
+ "#ifndef YY_INPUT",
+ "#define YY_INPUT(buf,result,max_size) \\",
+ "%% fread()/read() definition of YY_INPUT goes here unless we're doing C++",
+ "%+ C++ definition",
+ " if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \\",
+ " YY_FATAL_ERROR( \"input in flex scanner failed\" );",
+ "%*",
+ "#endif",
+ "",
+ "/* No semi-colon after return; correct usage is to write \"yyterminate();\" -",
+ " * we don't want an extra ';' after the \"return\" because that will cause",
+ " * some compilers to complain about unreachable statements.",
+ " */",
+ "#ifndef yyterminate",
+ "#define yyterminate() return YY_NULL",
+ "#endif",
+ "",
+ "/* Number of entries by which start-condition stack grows. */",
+ "#ifndef YY_START_STACK_INCR",
+ "#define YY_START_STACK_INCR 25",
+ "#endif",
+ "",
+ "/* Report a fatal error. */",
+ "#ifndef YY_FATAL_ERROR",
+ "%-",
+ "#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )",
+ "%+",
+ "#define YY_FATAL_ERROR(msg) LexerError( msg )",
+ "%*",
+ "#endif",
+ "",
+ "/* Default declaration of generated scanner - a define so the user can",
+ " * easily add parameters.",
+ " */",
+ "#ifndef YY_DECL",
+ "%- Standard (non-C++) definition",
+ "#define YY_DECL int yylex YY_PROTO(( void ))",
+ "%+ C++ definition",
+ "#define YY_DECL int yyFlexLexer::yylex()",
+ "%*",
+ "#endif",
+ "",
+ "/* Code executed at the beginning of each rule, after yytext and yyleng",
+ " * have been set up.",
+ " */",
+ "#ifndef YY_USER_ACTION",
+ "#define YY_USER_ACTION",
+ "#endif",
+ "",
+ "/* Code executed at the end of each rule. */",
+ "#ifndef YY_BREAK",
+ "#define YY_BREAK break;",
+ "#endif",
+ "",
+ "%% YY_RULE_SETUP definition goes here",
+ "",
+ "YY_DECL",
+ " {",
+ " register yy_state_type yy_current_state;",
+ " register char *yy_cp, *yy_bp;",
+ " register int yy_act;",
+ "",
+ "%% user's declarations go here",
+ "",
+ " if ( yy_init )",
+ " {",
+ " yy_init = 0;",
+ "",
+ "#ifdef YY_USER_INIT",
+ " YY_USER_INIT;",
+ "#endif",
+ "",
+ " if ( ! yy_start )",
+ " yy_start = 1; /* first start state */",
+ "",
+ " if ( ! yyin )",
+ "%-",
+ " yyin = stdin;",
+ "%+",
+ " yyin = &cin;",
+ "%*",
+ "",
+ " if ( ! yyout )",
+ "%-",
+ " yyout = stdout;",
+ "%+",
+ " yyout = &cout;",
+ "%*",
+ "",
+ " if ( ! yy_current_buffer )",
+ " yy_current_buffer =",
+ " yy_create_buffer( yyin, YY_BUF_SIZE );",
+ "",
+ " yy_load_buffer_state();",
+ " }",
+ "",
+ " while ( 1 ) /* loops until end-of-file is reached */",
+ " {",
+ "%% yymore()-related code goes here",
+ " yy_cp = yy_c_buf_p;",
+ "",
+ " /* Support of yytext. */",
+ " *yy_cp = yy_hold_char;",
+ "",
+ " /* yy_bp points to the position in yy_ch_buf of the start of",
+ " * the current run.",
+ " */",
+ " yy_bp = yy_cp;",
+ "",
+ "%% code to set up and find next match goes here",
+ "",
+ "yy_find_action:",
+ "%% code to find the action number goes here",
+ "",
+ " YY_DO_BEFORE_ACTION;",
+ "",
+ "%% code for yylineno update goes here",
+ "",
+ "do_action: /* This label is used only to access EOF actions. */",
+ "",
+ "%% debug code goes here",
+ "",
+ " switch ( yy_act )",
+ " { /* beginning of action switch */",
+ "%% actions go here",
+ "",
+ " case YY_END_OF_BUFFER:",
+ " {",
+ " /* Amount of text matched not including the EOB char. */",
+ " int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;",
+ "",
+ " /* Undo the effects of YY_DO_BEFORE_ACTION. */",
+ " *yy_cp = yy_hold_char;",
+ " YY_RESTORE_YY_MORE_OFFSET",
+ "",
+ " if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )",
+ " {",
+ " /* We're scanning a new file or input source. It's",
+ " * possible that this happened because the user",
+ " * just pointed yyin at a new source and called",
+ " * yylex(). If so, then we have to assure",
+ " * consistency between yy_current_buffer and our",
+ " * globals. Here is the right place to do so, because",
+ " * this is the first action (other than possibly a",
+ " * back-up) that will match for the new input source.",
+ " */",
+ " yy_n_chars = yy_current_buffer->yy_n_chars;",
+ " yy_current_buffer->yy_input_file = yyin;",
+ " yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;",
+ " }",
+ "",
+ " /* Note that here we test for yy_c_buf_p \"<=\" to the position",
+ " * of the first EOB in the buffer, since yy_c_buf_p will",
+ " * already have been incremented past the NUL character",
+ " * (since all states make transitions on EOB to the",
+ " * end-of-buffer state). Contrast this with the test",
+ " * in input().",
+ " */",
+ " if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )",
+ " { /* This was really a NUL. */",
+ " yy_state_type yy_next_state;",
+ "",
+ " yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " /* Okay, we're now positioned to make the NUL",
+ " * transition. We couldn't have",
+ " * yy_get_previous_state() go ahead and do it",
+ " * for us because it doesn't know how to deal",
+ " * with the possibility of jamming (and we don't",
+ " * want to build jamming into it because then it",
+ " * will run more slowly).",
+ " */",
+ "",
+ " yy_next_state = yy_try_NUL_trans( yy_current_state );",
+ "",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ "",
+ " if ( yy_next_state )",
+ " {",
+ " /* Consume the NUL. */",
+ " yy_cp = ++yy_c_buf_p;",
+ " yy_current_state = yy_next_state;",
+ " goto yy_match;",
+ " }",
+ "",
+ " else",
+ " {",
+ "%% code to do back-up for compressed tables and set up yy_cp goes here",
+ " goto yy_find_action;",
+ " }",
+ " }",
+ "",
+ " else switch ( yy_get_next_buffer() )",
+ " {",
+ " case EOB_ACT_END_OF_FILE:",
+ " {",
+ " yy_did_buffer_switch_on_eof = 0;",
+ "",
+ " if ( yywrap() )",
+ " {",
+ " /* Note: because we've taken care in",
+ " * yy_get_next_buffer() to have set up",
+ " * yytext, we can now set up",
+ " * yy_c_buf_p so that if some total",
+ " * hoser (like flex itself) wants to",
+ " * call the scanner after we return the",
+ " * YY_NULL, it'll still work - another",
+ " * YY_NULL will get returned.",
+ " */",
+ " yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;",
+ "",
+ " yy_act = YY_STATE_EOF(YY_START);",
+ " goto do_action;",
+ " }",
+ "",
+ " else",
+ " {",
+ " if ( ! yy_did_buffer_switch_on_eof )",
+ " YY_NEW_FILE;",
+ " }",
+ " break;",
+ " }",
+ "",
+ " case EOB_ACT_CONTINUE_SCAN:",
+ " yy_c_buf_p =",
+ " yytext_ptr + yy_amount_of_matched_text;",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " yy_cp = yy_c_buf_p;",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ " goto yy_match;",
+ "",
+ " case EOB_ACT_LAST_MATCH:",
+ " yy_c_buf_p =",
+ " &yy_current_buffer->yy_ch_buf[yy_n_chars];",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " yy_cp = yy_c_buf_p;",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ " goto yy_find_action;",
+ " }",
+ " break;",
+ " }",
+ "",
+ " default:",
+ " YY_FATAL_ERROR(",
+ " \"fatal flex scanner internal error--no action found\" );",
+ " } /* end of action switch */",
+ " } /* end of scanning one token */",
+ " } /* end of yylex */",
+ "",
+ "%+",
+ "yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )",
+ " {",
+ " yyin = arg_yyin;",
+ " yyout = arg_yyout;",
+ " yy_c_buf_p = 0;",
+ " yy_init = 1;",
+ " yy_start = 0;",
+ " yy_flex_debug = 0;",
+ " yylineno = 1; // this will only get updated if %option yylineno",
+ "",
+ " yy_did_buffer_switch_on_eof = 0;",
+ "",
+ " yy_looking_for_trail_begin = 0;",
+ " yy_more_flag = 0;",
+ " yy_more_len = 0;",
+ " yy_more_offset = yy_prev_more_offset = 0;",
+ "",
+ " yy_start_stack_ptr = yy_start_stack_depth = 0;",
+ " yy_start_stack = 0;",
+ "",
+ " yy_current_buffer = 0;",
+ "",
+ "#ifdef YY_USES_REJECT",
+ " yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];",
+ "#else",
+ " yy_state_buf = 0;",
+ "#endif",
+ " }",
+ "",
+ "yyFlexLexer::~yyFlexLexer()",
+ " {",
+ " delete yy_state_buf;",
+ " yy_delete_buffer( yy_current_buffer );",
+ " }",
+ "",
+ "void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )",
+ " {",
+ " if ( new_in )",
+ " {",
+ " yy_delete_buffer( yy_current_buffer );",
+ " yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );",
+ " }",
+ "",
+ " if ( new_out )",
+ " yyout = new_out;",
+ " }",
+ "",
+ "#ifdef YY_INTERACTIVE",
+ "int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )",
+ "#else",
+ "int yyFlexLexer::LexerInput( char* buf, int max_size )",
+ "#endif",
+ " {",
+ " if ( yyin->eof() || yyin->fail() )",
+ " return 0;",
+ "",
+ "#ifdef YY_INTERACTIVE",
+ " yyin->get( buf[0] );",
+ "",
+ " if ( yyin->eof() )",
+ " return 0;",
+ "",
+ " if ( yyin->bad() )",
+ " return -1;",
+ "",
+ " return 1;",
+ "",
+ "#else",
+ " (void) yyin->read( buf, max_size );",
+ "",
+ " if ( yyin->bad() )",
+ " return -1;",
+ " else",
+ " return yyin->gcount();",
+ "#endif",
+ " }",
+ "",
+ "void yyFlexLexer::LexerOutput( const char* buf, int size )",
+ " {",
+ " (void) yyout->write( buf, size );",
+ " }",
+ "%*",
+ "",
+ "/* yy_get_next_buffer - try to read in a new buffer",
+ " *",
+ " * Returns a code representing an action:",
+ " * EOB_ACT_LAST_MATCH -",
+ " * EOB_ACT_CONTINUE_SCAN - continue scanning from current position",
+ " * EOB_ACT_END_OF_FILE - end of file",
+ " */",
+ "",
+ "%-",
+ "static int yy_get_next_buffer()",
+ "%+",
+ "int yyFlexLexer::yy_get_next_buffer()",
+ "%*",
+ " {",
+ " register char *dest = yy_current_buffer->yy_ch_buf;",
+ " register char *source = yytext_ptr;",
+ " register int number_to_move, i;",
+ " int ret_val;",
+ "",
+ " if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )",
+ " YY_FATAL_ERROR(",
+ " \"fatal flex scanner internal error--end of buffer missed\" );",
+ "",
+ " if ( yy_current_buffer->yy_fill_buffer == 0 )",
+ " { /* Don't try to fill the buffer, so this is an EOF. */",
+ " if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )",
+ " {",
+ " /* We matched a single character, the EOB, so",
+ " * treat this as a final EOF.",
+ " */",
+ " return EOB_ACT_END_OF_FILE;",
+ " }",
+ "",
+ " else",
+ " {",
+ " /* We matched some text prior to the EOB, first",
+ " * process it.",
+ " */",
+ " return EOB_ACT_LAST_MATCH;",
+ " }",
+ " }",
+ "",
+ " /* Try to read more data. */",
+ "",
+ " /* First move last chars to start of buffer. */",
+ " number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;",
+ "",
+ " for ( i = 0; i < number_to_move; ++i )",
+ " *(dest++) = *(source++);",
+ "",
+ " if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )",
+ " /* don't do the read, it's not guaranteed to return an EOF,",
+ " * just force an EOF",
+ " */",
+ " yy_current_buffer->yy_n_chars = yy_n_chars = 0;",
+ "",
+ " else",
+ " {",
+ " int num_to_read =",
+ " yy_current_buffer->yy_buf_size - number_to_move - 1;",
+ "",
+ " while ( num_to_read <= 0 )",
+ " { /* Not enough room in the buffer - grow it. */",
+ "#ifdef YY_USES_REJECT",
+ " YY_FATAL_ERROR(",
+ "\"input buffer overflow, can't enlarge buffer because scanner uses REJECT\" );",
+ "#else",
+ "",
+ " /* just a shorter name for the current buffer */",
+ " YY_BUFFER_STATE b = yy_current_buffer;",
+ "",
+ " int yy_c_buf_p_offset =",
+ " (int) (yy_c_buf_p - b->yy_ch_buf);",
+ "",
+ " if ( b->yy_is_our_buffer )",
+ " {",
+ " int new_size = b->yy_buf_size * 2;",
+ "",
+ " if ( new_size <= 0 )",
+ " b->yy_buf_size += b->yy_buf_size / 8;",
+ " else",
+ " b->yy_buf_size *= 2;",
+ "",
+ " b->yy_ch_buf = (char *)",
+ " /* Include room in for 2 EOB chars. */",
+ " yy_flex_realloc( (void *) b->yy_ch_buf,",
+ " b->yy_buf_size + 2 );",
+ " }",
+ " else",
+ " /* Can't grow it, we don't own it. */",
+ " b->yy_ch_buf = 0;",
+ "",
+ " if ( ! b->yy_ch_buf )",
+ " YY_FATAL_ERROR(",
+ " \"fatal error - scanner input buffer overflow\" );",
+ "",
+ " yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];",
+ "",
+ " num_to_read = yy_current_buffer->yy_buf_size -",
+ " number_to_move - 1;",
+ "#endif",
+ " }",
+ "",
+ " if ( num_to_read > YY_READ_BUF_SIZE )",
+ " num_to_read = YY_READ_BUF_SIZE;",
+ "",
+ " /* Read in more data. */",
+ " YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),",
+ " yy_n_chars, num_to_read );",
+ "",
+ " yy_current_buffer->yy_n_chars = yy_n_chars;",
+ " }",
+ "",
+ " if ( yy_n_chars == 0 )",
+ " {",
+ " if ( number_to_move == YY_MORE_ADJ )",
+ " {",
+ " ret_val = EOB_ACT_END_OF_FILE;",
+ " yyrestart( yyin );",
+ " }",
+ "",
+ " else",
+ " {",
+ " ret_val = EOB_ACT_LAST_MATCH;",
+ " yy_current_buffer->yy_buffer_status =",
+ " YY_BUFFER_EOF_PENDING;",
+ " }",
+ " }",
+ "",
+ " else",
+ " ret_val = EOB_ACT_CONTINUE_SCAN;",
+ "",
+ " yy_n_chars += number_to_move;",
+ " yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;",
+ " yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " yytext_ptr = &yy_current_buffer->yy_ch_buf[0];",
+ "",
+ " return ret_val;",
+ " }",
+ "",
+ "",
+ "/* yy_get_previous_state - get the state just before the EOB char was reached */",
+ "",
+ "%-",
+ "static yy_state_type yy_get_previous_state()",
+ "%+",
+ "yy_state_type yyFlexLexer::yy_get_previous_state()",
+ "%*",
+ " {",
+ " register yy_state_type yy_current_state;",
+ " register char *yy_cp;",
+ "",
+ "%% code to get the start state into yy_current_state goes here",
+ "",
+ " for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )",
+ " {",
+ "%% code to find the next state goes here",
+ " }",
+ "",
+ " return yy_current_state;",
+ " }",
+ "",
+ "",
+ "/* yy_try_NUL_trans - try to make a transition on the NUL character",
+ " *",
+ " * synopsis",
+ " * next_state = yy_try_NUL_trans( current_state );",
+ " */",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )",
+ "#else",
+ "static yy_state_type yy_try_NUL_trans( yy_current_state )",
+ "yy_state_type yy_current_state;",
+ "#endif",
+ "%+",
+ "yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )",
+ "%*",
+ " {",
+ " register int yy_is_jam;",
+ "%% code to find the next state, and perhaps do backing up, goes here",
+ "",
+ " return yy_is_jam ? 0 : yy_current_state;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifndef YY_NO_UNPUT",
+ "#ifdef YY_USE_PROTOS",
+ "static void yyunput( int c, register char *yy_bp )",
+ "#else",
+ "static void yyunput( c, yy_bp )",
+ "int c;",
+ "register char *yy_bp;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yyunput( int c, register char* yy_bp )",
+ "%*",
+ " {",
+ " register char *yy_cp = yy_c_buf_p;",
+ "",
+ " /* undo effects of setting up yytext */",
+ " *yy_cp = yy_hold_char;",
+ "",
+ " if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )",
+ " { /* need to shift things up to make room */",
+ " /* +2 for EOB chars. */",
+ " register int number_to_move = yy_n_chars + 2;",
+ " register char *dest = &yy_current_buffer->yy_ch_buf[",
+ " yy_current_buffer->yy_buf_size + 2];",
+ " register char *source =",
+ " &yy_current_buffer->yy_ch_buf[number_to_move];",
+ "",
+ " while ( source > yy_current_buffer->yy_ch_buf )",
+ " *--dest = *--source;",
+ "",
+ " yy_cp += (int) (dest - source);",
+ " yy_bp += (int) (dest - source);",
+ " yy_current_buffer->yy_n_chars =",
+ " yy_n_chars = yy_current_buffer->yy_buf_size;",
+ "",
+ " if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )",
+ " YY_FATAL_ERROR( \"flex scanner push-back overflow\" );",
+ " }",
+ "",
+ " *--yy_cp = (char) c;",
+ "",
+ "%% update yylineno here",
+ "",
+ " yytext_ptr = yy_bp;",
+ " yy_hold_char = *yy_cp;",
+ " yy_c_buf_p = yy_cp;",
+ " }",
+ "%-",
+ "#endif /* ifndef YY_NO_UNPUT */",
+ "%*",
+ "",
+ "",
+ "%-",
+ "#ifdef __cplusplus",
+ "static int yyinput()",
+ "#else",
+ "static int input()",
+ "#endif",
+ "%+",
+ "int yyFlexLexer::yyinput()",
+ "%*",
+ " {",
+ " int c;",
+ "",
+ " *yy_c_buf_p = yy_hold_char;",
+ "",
+ " if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )",
+ " {",
+ " /* yy_c_buf_p now points to the character we want to return.",
+ " * If this occurs *before* the EOB characters, then it's a",
+ " * valid NUL; if not, then we've hit the end of the buffer.",
+ " */",
+ " if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )",
+ " /* This was really a NUL. */",
+ " *yy_c_buf_p = '\\0';",
+ "",
+ " else",
+ " { /* need more input */",
+ " int offset = yy_c_buf_p - yytext_ptr;",
+ " ++yy_c_buf_p;",
+ "",
+ " switch ( yy_get_next_buffer() )",
+ " {",
+ " case EOB_ACT_LAST_MATCH:",
+ " /* This happens because yy_g_n_b()",
+ " * sees that we've accumulated a",
+ " * token and flags that we need to",
+ " * try matching the token before",
+ " * proceeding. But for input(),",
+ " * there's no matching to consider.",
+ " * So convert the EOB_ACT_LAST_MATCH",
+ " * to EOB_ACT_END_OF_FILE.",
+ " */",
+ "",
+ " /* Reset buffer status. */",
+ " yyrestart( yyin );",
+ "",
+ " /* fall through */",
+ "",
+ " case EOB_ACT_END_OF_FILE:",
+ " {",
+ " if ( yywrap() )",
+ " return EOF;",
+ "",
+ " if ( ! yy_did_buffer_switch_on_eof )",
+ " YY_NEW_FILE;",
+ "#ifdef __cplusplus",
+ " return yyinput();",
+ "#else",
+ " return input();",
+ "#endif",
+ " }",
+ "",
+ " case EOB_ACT_CONTINUE_SCAN:",
+ " yy_c_buf_p = yytext_ptr + offset;",
+ " break;",
+ " }",
+ " }",
+ " }",
+ "",
+ " c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */",
+ " *yy_c_buf_p = '\\0'; /* preserve yytext */",
+ " yy_hold_char = *++yy_c_buf_p;",
+ "",
+ "%% update BOL and yylineno",
+ "",
+ " return c;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yyrestart( FILE *input_file )",
+ "#else",
+ "void yyrestart( input_file )",
+ "FILE *input_file;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yyrestart( istream* input_file )",
+ "%*",
+ " {",
+ " if ( ! yy_current_buffer )",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );",
+ "",
+ " yy_init_buffer( yy_current_buffer, input_file );",
+ " yy_load_buffer_state();",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )",
+ "#else",
+ "void yy_switch_to_buffer( new_buffer )",
+ "YY_BUFFER_STATE new_buffer;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )",
+ "%*",
+ " {",
+ " if ( yy_current_buffer == new_buffer )",
+ " return;",
+ "",
+ " if ( yy_current_buffer )",
+ " {",
+ " /* Flush out information for old buffer. */",
+ " *yy_c_buf_p = yy_hold_char;",
+ " yy_current_buffer->yy_buf_pos = yy_c_buf_p;",
+ " yy_current_buffer->yy_n_chars = yy_n_chars;",
+ " }",
+ "",
+ " yy_current_buffer = new_buffer;",
+ " yy_load_buffer_state();",
+ "",
+ " /* We don't actually know whether we did this switch during",
+ " * EOF (yywrap()) processing, but the only time this flag",
+ " * is looked at is after yywrap() is called, so it's safe",
+ " * to go ahead and always set it.",
+ " */",
+ " yy_did_buffer_switch_on_eof = 1;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_load_buffer_state( void )",
+ "#else",
+ "void yy_load_buffer_state()",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_load_buffer_state()",
+ "%*",
+ " {",
+ " yy_n_chars = yy_current_buffer->yy_n_chars;",
+ " yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;",
+ " yyin = yy_current_buffer->yy_input_file;",
+ " yy_hold_char = *yy_c_buf_p;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )",
+ "#else",
+ "YY_BUFFER_STATE yy_create_buffer( file, size )",
+ "FILE *file;",
+ "int size;",
+ "#endif",
+ "%+",
+ "YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )",
+ "%*",
+ " {",
+ " YY_BUFFER_STATE b;",
+ "",
+ " b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );",
+ "",
+ " b->yy_buf_size = size;",
+ "",
+ " /* yy_ch_buf has to be 2 characters longer than the size given because",
+ " * we need to put in 2 end-of-buffer characters.",
+ " */",
+ " b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );",
+ " if ( ! b->yy_ch_buf )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );",
+ "",
+ " b->yy_is_our_buffer = 1;",
+ "",
+ " yy_init_buffer( b, file );",
+ "",
+ " return b;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_delete_buffer( YY_BUFFER_STATE b )",
+ "#else",
+ "void yy_delete_buffer( b )",
+ "YY_BUFFER_STATE b;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )",
+ "%*",
+ " {",
+ " if ( ! b )",
+ " return;",
+ "",
+ " if ( b == yy_current_buffer )",
+ " yy_current_buffer = (YY_BUFFER_STATE) 0;",
+ "",
+ " if ( b->yy_is_our_buffer )",
+ " yy_flex_free( (void *) b->yy_ch_buf );",
+ "",
+ " yy_flex_free( (void *) b );",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifndef YY_ALWAYS_INTERACTIVE",
+ "#ifndef YY_NEVER_INTERACTIVE",
+ "extern int isatty YY_PROTO(( int ));",
+ "#endif",
+ "#endif",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )",
+ "#else",
+ "void yy_init_buffer( b, file )",
+ "YY_BUFFER_STATE b;",
+ "FILE *file;",
+ "#endif",
+ "",
+ "%+",
+ "extern \"C\" int isatty YY_PROTO(( int ));",
+ "void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )",
+ "%*",
+ "",
+ " {",
+ " yy_flush_buffer( b );",
+ "",
+ " b->yy_input_file = file;",
+ " b->yy_fill_buffer = 1;",
+ "",
+ "%-",
+ "#if YY_ALWAYS_INTERACTIVE",
+ " b->yy_is_interactive = 1;",
+ "#else",
+ "#if YY_NEVER_INTERACTIVE",
+ " b->yy_is_interactive = 0;",
+ "#else",
+ " b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;",
+ "#endif",
+ "#endif",
+ "%+",
+ " b->yy_is_interactive = 0;",
+ "%*",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_flush_buffer( YY_BUFFER_STATE b )",
+ "#else",
+ "void yy_flush_buffer( b )",
+ "YY_BUFFER_STATE b;",
+ "#endif",
+ "",
+ "%+",
+ "void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )",
+ "%*",
+ " {",
+ " if ( ! b )",
+ " return;",
+ "",
+ " b->yy_n_chars = 0;",
+ "",
+ " /* We always need two end-of-buffer characters. The first causes",
+ " * a transition to the end-of-buffer state. The second causes",
+ " * a jam in that state.",
+ " */",
+ " b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;",
+ " b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " b->yy_buf_pos = &b->yy_ch_buf[0];",
+ "",
+ " b->yy_at_bol = 1;",
+ " b->yy_buffer_status = YY_BUFFER_NEW;",
+ "",
+ " if ( b == yy_current_buffer )",
+ " yy_load_buffer_state();",
+ " }",
+ "%*",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_BUFFER",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_buffer( base, size )",
+ "char *base;",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " YY_BUFFER_STATE b;",
+ "",
+ " if ( size < 2 ||",
+ " base[size-2] != YY_END_OF_BUFFER_CHAR ||",
+ " base[size-1] != YY_END_OF_BUFFER_CHAR )",
+ " /* They forgot to leave room for the EOB's. */",
+ " return 0;",
+ "",
+ " b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_scan_buffer()\" );",
+ "",
+ " b->yy_buf_size = size - 2; /* \"- 2\" to take care of EOB's */",
+ " b->yy_buf_pos = b->yy_ch_buf = base;",
+ " b->yy_is_our_buffer = 0;",
+ " b->yy_input_file = 0;",
+ " b->yy_n_chars = b->yy_buf_size;",
+ " b->yy_is_interactive = 0;",
+ " b->yy_at_bol = 1;",
+ " b->yy_fill_buffer = 0;",
+ " b->yy_buffer_status = YY_BUFFER_NEW;",
+ "",
+ " yy_switch_to_buffer( b );",
+ "",
+ " return b;",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_STRING",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_string( yy_str )",
+ "yyconst char *yy_str;",
+ "#endif",
+ " {",
+ " int len;",
+ " for ( len = 0; yy_str[len]; ++len )",
+ " ;",
+ "",
+ " return yy_scan_bytes( yy_str, len );",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_BYTES",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_bytes( bytes, len )",
+ "yyconst char *bytes;",
+ "int len;",
+ "#endif",
+ " {",
+ " YY_BUFFER_STATE b;",
+ " char *buf;",
+ " yy_size_t n;",
+ " int i;",
+ "",
+ " /* Get memory for full buffer, including space for trailing EOB's. */",
+ " n = len + 2;",
+ " buf = (char *) yy_flex_alloc( n );",
+ " if ( ! buf )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_scan_bytes()\" );",
+ "",
+ " for ( i = 0; i < len; ++i )",
+ " buf[i] = bytes[i];",
+ "",
+ " buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " b = yy_scan_buffer( buf, n );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"bad buffer in yy_scan_bytes()\" );",
+ "",
+ " /* It's okay to grow etc. this buffer, and we should throw it",
+ " * away when we're done.",
+ " */",
+ " b->yy_is_our_buffer = 1;",
+ "",
+ " return b;",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_PUSH_STATE",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_push_state( int new_state )",
+ "#else",
+ "static void yy_push_state( new_state )",
+ "int new_state;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_push_state( int new_state )",
+ "%*",
+ " {",
+ " if ( yy_start_stack_ptr >= yy_start_stack_depth )",
+ " {",
+ " yy_size_t new_size;",
+ "",
+ " yy_start_stack_depth += YY_START_STACK_INCR;",
+ " new_size = yy_start_stack_depth * sizeof( int );",
+ "",
+ " if ( ! yy_start_stack )",
+ " yy_start_stack = (int *) yy_flex_alloc( new_size );",
+ "",
+ " else",
+ " yy_start_stack = (int *) yy_flex_realloc(",
+ " (void *) yy_start_stack, new_size );",
+ "",
+ " if ( ! yy_start_stack )",
+ " YY_FATAL_ERROR(",
+ " \"out of memory expanding start-condition stack\" );",
+ " }",
+ "",
+ " yy_start_stack[yy_start_stack_ptr++] = YY_START;",
+ "",
+ " BEGIN(new_state);",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_POP_STATE",
+ "%-",
+ "static void yy_pop_state()",
+ "%+",
+ "void yyFlexLexer::yy_pop_state()",
+ "%*",
+ " {",
+ " if ( --yy_start_stack_ptr < 0 )",
+ " YY_FATAL_ERROR( \"start-condition stack underflow\" );",
+ "",
+ " BEGIN(yy_start_stack[yy_start_stack_ptr]);",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_TOP_STATE",
+ "%-",
+ "static int yy_top_state()",
+ "%+",
+ "int yyFlexLexer::yy_top_state()",
+ "%*",
+ " {",
+ " return yy_start_stack[yy_start_stack_ptr - 1];",
+ " }",
+ "#endif",
+ "",
+ "#ifndef YY_EXIT_FAILURE",
+ "#define YY_EXIT_FAILURE 2",
+ "#endif",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_fatal_error( yyconst char msg[] )",
+ "#else",
+ "static void yy_fatal_error( msg )",
+ "char msg[];",
+ "#endif",
+ " {",
+ " (void) fprintf( stderr, \"%s\\n\", msg );",
+ " exit( YY_EXIT_FAILURE );",
+ " }",
+ "",
+ "%+",
+ "",
+ "void yyFlexLexer::LexerError( yyconst char msg[] )",
+ " {",
+ " cerr << msg << '\\n';",
+ " exit( YY_EXIT_FAILURE );",
+ " }",
+ "%*",
+ "",
+ "",
+ "/* Redefine yyless() so it works in section 3 code. */",
+ "",
+ "#undef yyless",
+ "#define yyless(n) \\",
+ " do \\",
+ " { \\",
+ " /* Undo effects of setting up yytext. */ \\",
+ " yytext[yyleng] = yy_hold_char; \\",
+ " yy_c_buf_p = yytext + n; \\",
+ " yy_hold_char = *yy_c_buf_p; \\",
+ " *yy_c_buf_p = '\\0'; \\",
+ " yyleng = n; \\",
+ " } \\",
+ " while ( 0 )",
+ "",
+ "",
+ "/* Internal utility routines. */",
+ "",
+ "#ifndef yytext_ptr",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )",
+ "#else",
+ "static void yy_flex_strncpy( s1, s2, n )",
+ "char *s1;",
+ "yyconst char *s2;",
+ "int n;",
+ "#endif",
+ " {",
+ " register int i;",
+ " for ( i = 0; i < n; ++i )",
+ " s1[i] = s2[i];",
+ " }",
+ "#endif",
+ "",
+ "#ifdef YY_NEED_STRLEN",
+ "#ifdef YY_USE_PROTOS",
+ "static int yy_flex_strlen( yyconst char *s )",
+ "#else",
+ "static int yy_flex_strlen( s )",
+ "yyconst char *s;",
+ "#endif",
+ " {",
+ " register int n;",
+ " for ( n = 0; s[n]; ++n )",
+ " ;",
+ "",
+ " return n;",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void *yy_flex_alloc( yy_size_t size )",
+ "#else",
+ "static void *yy_flex_alloc( size )",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " return (void *) malloc( size );",
+ " }",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void *yy_flex_realloc( void *ptr, yy_size_t size )",
+ "#else",
+ "static void *yy_flex_realloc( ptr, size )",
+ "void *ptr;",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " /* The cast to (char *) in the following accommodates both",
+ " * implementations that use char* generic pointers, and those",
+ " * that use void* generic pointers. It works with the latter",
+ " * because both ANSI C and C++ allow castless assignment from",
+ " * any pointer type to void*, and deal with argument conversions",
+ " * as though doing an assignment.",
+ " */",
+ " return (void *) realloc( (char *) ptr, size );",
+ " }",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_flex_free( void *ptr )",
+ "#else",
+ "static void yy_flex_free( ptr )",
+ "void *ptr;",
+ "#endif",
+ " {",
+ " free( ptr );",
+ " }",
+ "",
+ "#if YY_MAIN",
+ "int main()",
+ " {",
+ " yylex();",
+ " return 0;",
+ " }",
+ "#endif",
+ 0
+};
diff --git a/usr.bin/lex/sym.c b/usr.bin/lex/sym.c
new file mode 100644
index 0000000..7e29aca
--- /dev/null
+++ b/usr.bin/lex/sym.c
@@ -0,0 +1,262 @@
+/* sym - symbol table routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/sym.c,v 1.1.1.2 1996/06/19 20:26:39 nate Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+int hashfunct PROTO((register char[], int));
+
+
+struct hash_entry *ndtbl[NAME_TABLE_HASH_SIZE];
+struct hash_entry *sctbl[START_COND_HASH_SIZE];
+struct hash_entry *ccltab[CCL_HASH_SIZE];
+
+struct hash_entry *findsym();
+
+
+/* addsym - add symbol and definitions to symbol table
+ *
+ * -1 is returned if the symbol already exists, and the change not made.
+ */
+
+int addsym( sym, str_def, int_def, table, table_size )
+register char sym[];
+char *str_def;
+int int_def;
+hash_table table;
+int table_size;
+ {
+ int hash_val = hashfunct( sym, table_size );
+ register struct hash_entry *sym_entry = table[hash_val];
+ register struct hash_entry *new_entry;
+ register struct hash_entry *successor;
+
+ while ( sym_entry )
+ {
+ if ( ! strcmp( sym, sym_entry->name ) )
+ { /* entry already exists */
+ return -1;
+ }
+
+ sym_entry = sym_entry->next;
+ }
+
+ /* create new entry */
+ new_entry = (struct hash_entry *)
+ flex_alloc( sizeof( struct hash_entry ) );
+
+ if ( new_entry == NULL )
+ flexfatal( _( "symbol table memory allocation failed" ) );
+
+ if ( (successor = table[hash_val]) != 0 )
+ {
+ new_entry->next = successor;
+ successor->prev = new_entry;
+ }
+ else
+ new_entry->next = NULL;
+
+ new_entry->prev = NULL;
+ new_entry->name = sym;
+ new_entry->str_val = str_def;
+ new_entry->int_val = int_def;
+
+ table[hash_val] = new_entry;
+
+ return 0;
+ }
+
+
+/* cclinstal - save the text of a character class */
+
+void cclinstal( ccltxt, cclnum )
+Char ccltxt[];
+int cclnum;
+ {
+ /* We don't bother checking the return status because we are not
+ * called unless the symbol is new.
+ */
+ Char *copy_unsigned_string();
+
+ (void) addsym( (char *) copy_unsigned_string( ccltxt ),
+ (char *) 0, cclnum,
+ ccltab, CCL_HASH_SIZE );
+ }
+
+
+/* ccllookup - lookup the number associated with character class text
+ *
+ * Returns 0 if there's no CCL associated with the text.
+ */
+
+int ccllookup( ccltxt )
+Char ccltxt[];
+ {
+ return findsym( (char *) ccltxt, ccltab, CCL_HASH_SIZE )->int_val;
+ }
+
+
+/* findsym - find symbol in symbol table */
+
+struct hash_entry *findsym( sym, table, table_size )
+register char sym[];
+hash_table table;
+int table_size;
+ {
+ static struct hash_entry empty_entry =
+ {
+ (struct hash_entry *) 0, (struct hash_entry *) 0,
+ (char *) 0, (char *) 0, 0,
+ } ;
+ register struct hash_entry *sym_entry =
+ table[hashfunct( sym, table_size )];
+
+ while ( sym_entry )
+ {
+ if ( ! strcmp( sym, sym_entry->name ) )
+ return sym_entry;
+ sym_entry = sym_entry->next;
+ }
+
+ return &empty_entry;
+ }
+
+
+/* hashfunct - compute the hash value for "str" and hash size "hash_size" */
+
+int hashfunct( str, hash_size )
+register char str[];
+int hash_size;
+ {
+ register int hashval;
+ register int locstr;
+
+ hashval = 0;
+ locstr = 0;
+
+ while ( str[locstr] )
+ {
+ hashval = (hashval << 1) + (unsigned char) str[locstr++];
+ hashval %= hash_size;
+ }
+
+ return hashval;
+ }
+
+
+/* ndinstal - install a name definition */
+
+void ndinstal( name, definition )
+char name[];
+Char definition[];
+ {
+ char *copy_string();
+ Char *copy_unsigned_string();
+
+ if ( addsym( copy_string( name ),
+ (char *) copy_unsigned_string( definition ), 0,
+ ndtbl, NAME_TABLE_HASH_SIZE ) )
+ synerr( _( "name defined twice" ) );
+ }
+
+
+/* ndlookup - lookup a name definition
+ *
+ * Returns a nil pointer if the name definition does not exist.
+ */
+
+Char *ndlookup( nd )
+char nd[];
+ {
+ return (Char *) findsym( nd, ndtbl, NAME_TABLE_HASH_SIZE )->str_val;
+ }
+
+
+/* scextend - increase the maximum number of start conditions */
+
+void scextend()
+ {
+ current_max_scs += MAX_SCS_INCREMENT;
+
+ ++num_reallocs;
+
+ scset = reallocate_integer_array( scset, current_max_scs );
+ scbol = reallocate_integer_array( scbol, current_max_scs );
+ scxclu = reallocate_integer_array( scxclu, current_max_scs );
+ sceof = reallocate_integer_array( sceof, current_max_scs );
+ scname = reallocate_char_ptr_array( scname, current_max_scs );
+ }
+
+
+/* scinstal - make a start condition
+ *
+ * NOTE
+ * The start condition is "exclusive" if xcluflg is true.
+ */
+
+void scinstal( str, xcluflg )
+char str[];
+int xcluflg;
+ {
+ char *copy_string();
+
+ /* Generate start condition definition, for use in BEGIN et al. */
+ action_define( str, lastsc );
+
+ if ( ++lastsc >= current_max_scs )
+ scextend();
+
+ scname[lastsc] = copy_string( str );
+
+ if ( addsym( scname[lastsc], (char *) 0, lastsc,
+ sctbl, START_COND_HASH_SIZE ) )
+ format_pinpoint_message(
+ _( "start condition %s declared twice" ),
+ str );
+
+ scset[lastsc] = mkstate( SYM_EPSILON );
+ scbol[lastsc] = mkstate( SYM_EPSILON );
+ scxclu[lastsc] = xcluflg;
+ sceof[lastsc] = false;
+ }
+
+
+/* sclookup - lookup the number associated with a start condition
+ *
+ * Returns 0 if no such start condition.
+ */
+
+int sclookup( str )
+char str[];
+ {
+ return findsym( str, sctbl, START_COND_HASH_SIZE )->int_val;
+ }
diff --git a/usr.bin/lex/tblcmp.c b/usr.bin/lex/tblcmp.c
new file mode 100644
index 0000000..738b76d
--- /dev/null
+++ b/usr.bin/lex/tblcmp.c
@@ -0,0 +1,887 @@
+/* tblcmp - table compression routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/tblcmp.c,v 1.1.1.2 1996/06/19 20:26:43 nate Exp $ */
+
+#include "flexdef.h"
+
+
+/* declarations for functions that have forward references */
+
+void mkentry PROTO((register int*, int, int, int, int));
+void mkprot PROTO((int[], int, int));
+void mktemplate PROTO((int[], int, int));
+void mv2front PROTO((int));
+int tbldiff PROTO((int[], int, int[]));
+
+
+/* bldtbl - build table entries for dfa state
+ *
+ * synopsis
+ * int state[numecs], statenum, totaltrans, comstate, comfreq;
+ * bldtbl( state, statenum, totaltrans, comstate, comfreq );
+ *
+ * State is the statenum'th dfa state. It is indexed by equivalence class and
+ * gives the number of the state to enter for a given equivalence class.
+ * totaltrans is the total number of transitions out of the state. Comstate
+ * is that state which is the destination of the most transitions out of State.
+ * Comfreq is how many transitions there are out of State to Comstate.
+ *
+ * A note on terminology:
+ * "protos" are transition tables which have a high probability of
+ * either being redundant (a state processed later will have an identical
+ * transition table) or nearly redundant (a state processed later will have
+ * many of the same out-transitions). A "most recently used" queue of
+ * protos is kept around with the hope that most states will find a proto
+ * which is similar enough to be usable, and therefore compacting the
+ * output tables.
+ * "templates" are a special type of proto. If a transition table is
+ * homogeneous or nearly homogeneous (all transitions go to the same
+ * destination) then the odds are good that future states will also go
+ * to the same destination state on basically the same character set.
+ * These homogeneous states are so common when dealing with large rule
+ * sets that they merit special attention. If the transition table were
+ * simply made into a proto, then (typically) each subsequent, similar
+ * state will differ from the proto for two out-transitions. One of these
+ * out-transitions will be that character on which the proto does not go
+ * to the common destination, and one will be that character on which the
+ * state does not go to the common destination. Templates, on the other
+ * hand, go to the common state on EVERY transition character, and therefore
+ * cost only one difference.
+ */
+
+void bldtbl( state, statenum, totaltrans, comstate, comfreq )
+int state[], statenum, totaltrans, comstate, comfreq;
+ {
+ int extptr, extrct[2][CSIZE + 1];
+ int mindiff, minprot, i, d;
+
+ /* If extptr is 0 then the first array of extrct holds the result
+ * of the "best difference" to date, which is those transitions
+ * which occur in "state" but not in the proto which, to date,
+ * has the fewest differences between itself and "state". If
+ * extptr is 1 then the second array of extrct hold the best
+ * difference. The two arrays are toggled between so that the
+ * best difference to date can be kept around and also a difference
+ * just created by checking against a candidate "best" proto.
+ */
+
+ extptr = 0;
+
+ /* If the state has too few out-transitions, don't bother trying to
+ * compact its tables.
+ */
+
+ if ( (totaltrans * 100) < (numecs * PROTO_SIZE_PERCENTAGE) )
+ mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
+
+ else
+ {
+ /* "checkcom" is true if we should only check "state" against
+ * protos which have the same "comstate" value.
+ */
+ int checkcom =
+ comfreq * 100 > totaltrans * CHECK_COM_PERCENTAGE;
+
+ minprot = firstprot;
+ mindiff = totaltrans;
+
+ if ( checkcom )
+ {
+ /* Find first proto which has the same "comstate". */
+ for ( i = firstprot; i != NIL; i = protnext[i] )
+ if ( protcomst[i] == comstate )
+ {
+ minprot = i;
+ mindiff = tbldiff( state, minprot,
+ extrct[extptr] );
+ break;
+ }
+ }
+
+ else
+ {
+ /* Since we've decided that the most common destination
+ * out of "state" does not occur with a high enough
+ * frequency, we set the "comstate" to zero, assuring
+ * that if this state is entered into the proto list,
+ * it will not be considered a template.
+ */
+ comstate = 0;
+
+ if ( firstprot != NIL )
+ {
+ minprot = firstprot;
+ mindiff = tbldiff( state, minprot,
+ extrct[extptr] );
+ }
+ }
+
+ /* We now have the first interesting proto in "minprot". If
+ * it matches within the tolerances set for the first proto,
+ * we don't want to bother scanning the rest of the proto list
+ * to see if we have any other reasonable matches.
+ */
+
+ if ( mindiff * 100 > totaltrans * FIRST_MATCH_DIFF_PERCENTAGE )
+ {
+ /* Not a good enough match. Scan the rest of the
+ * protos.
+ */
+ for ( i = minprot; i != NIL; i = protnext[i] )
+ {
+ d = tbldiff( state, i, extrct[1 - extptr] );
+ if ( d < mindiff )
+ {
+ extptr = 1 - extptr;
+ mindiff = d;
+ minprot = i;
+ }
+ }
+ }
+
+ /* Check if the proto we've decided on as our best bet is close
+ * enough to the state we want to match to be usable.
+ */
+
+ if ( mindiff * 100 > totaltrans * ACCEPTABLE_DIFF_PERCENTAGE )
+ {
+ /* No good. If the state is homogeneous enough,
+ * we make a template out of it. Otherwise, we
+ * make a proto.
+ */
+
+ if ( comfreq * 100 >=
+ totaltrans * TEMPLATE_SAME_PERCENTAGE )
+ mktemplate( state, statenum, comstate );
+
+ else
+ {
+ mkprot( state, statenum, comstate );
+ mkentry( state, numecs, statenum,
+ JAMSTATE, totaltrans );
+ }
+ }
+
+ else
+ { /* use the proto */
+ mkentry( extrct[extptr], numecs, statenum,
+ prottbl[minprot], mindiff );
+
+ /* If this state was sufficiently different from the
+ * proto we built it from, make it, too, a proto.
+ */
+
+ if ( mindiff * 100 >=
+ totaltrans * NEW_PROTO_DIFF_PERCENTAGE )
+ mkprot( state, statenum, comstate );
+
+ /* Since mkprot added a new proto to the proto queue,
+ * it's possible that "minprot" is no longer on the
+ * proto queue (if it happened to have been the last
+ * entry, it would have been bumped off). If it's
+ * not there, then the new proto took its physical
+ * place (though logically the new proto is at the
+ * beginning of the queue), so in that case the
+ * following call will do nothing.
+ */
+
+ mv2front( minprot );
+ }
+ }
+ }
+
+
+/* cmptmps - compress template table entries
+ *
+ * Template tables are compressed by using the 'template equivalence
+ * classes', which are collections of transition character equivalence
+ * classes which always appear together in templates - really meta-equivalence
+ * classes.
+ */
+
+void cmptmps()
+ {
+ int tmpstorage[CSIZE + 1];
+ register int *tmp = tmpstorage, i, j;
+ int totaltrans, trans;
+
+ peakpairs = numtemps * numecs + tblend;
+
+ if ( usemecs )
+ {
+ /* Create equivalence classes based on data gathered on
+ * template transitions.
+ */
+ nummecs = cre8ecs( tecfwd, tecbck, numecs );
+ }
+
+ else
+ nummecs = numecs;
+
+ while ( lastdfa + numtemps + 1 >= current_max_dfas )
+ increase_max_dfas();
+
+ /* Loop through each template. */
+
+ for ( i = 1; i <= numtemps; ++i )
+ {
+ /* Number of non-jam transitions out of this template. */
+ totaltrans = 0;
+
+ for ( j = 1; j <= numecs; ++j )
+ {
+ trans = tnxt[numecs * i + j];
+
+ if ( usemecs )
+ {
+ /* The absolute value of tecbck is the
+ * meta-equivalence class of a given
+ * equivalence class, as set up by cre8ecs().
+ */
+ if ( tecbck[j] > 0 )
+ {
+ tmp[tecbck[j]] = trans;
+
+ if ( trans > 0 )
+ ++totaltrans;
+ }
+ }
+
+ else
+ {
+ tmp[j] = trans;
+
+ if ( trans > 0 )
+ ++totaltrans;
+ }
+ }
+
+ /* It is assumed (in a rather subtle way) in the skeleton
+ * that if we're using meta-equivalence classes, the def[]
+ * entry for all templates is the jam template, i.e.,
+ * templates never default to other non-jam table entries
+ * (e.g., another template)
+ */
+
+ /* Leave room for the jam-state after the last real state. */
+ mkentry( tmp, nummecs, lastdfa + i + 1, JAMSTATE, totaltrans );
+ }
+ }
+
+
+
+/* expand_nxt_chk - expand the next check arrays */
+
+void expand_nxt_chk()
+ {
+ register int old_max = current_max_xpairs;
+
+ current_max_xpairs += MAX_XPAIRS_INCREMENT;
+
+ ++num_reallocs;
+
+ nxt = reallocate_integer_array( nxt, current_max_xpairs );
+ chk = reallocate_integer_array( chk, current_max_xpairs );
+
+ zero_out( (char *) (chk + old_max),
+ (size_t) (MAX_XPAIRS_INCREMENT * sizeof( int )) );
+ }
+
+
+/* find_table_space - finds a space in the table for a state to be placed
+ *
+ * synopsis
+ * int *state, numtrans, block_start;
+ * int find_table_space();
+ *
+ * block_start = find_table_space( state, numtrans );
+ *
+ * State is the state to be added to the full speed transition table.
+ * Numtrans is the number of out-transitions for the state.
+ *
+ * find_table_space() returns the position of the start of the first block (in
+ * chk) able to accommodate the state
+ *
+ * In determining if a state will or will not fit, find_table_space() must take
+ * into account the fact that an end-of-buffer state will be added at [0],
+ * and an action number will be added in [-1].
+ */
+
+int find_table_space( state, numtrans )
+int *state, numtrans;
+ {
+ /* Firstfree is the position of the first possible occurrence of two
+ * consecutive unused records in the chk and nxt arrays.
+ */
+ register int i;
+ register int *state_ptr, *chk_ptr;
+ register int *ptr_to_last_entry_in_state;
+
+ /* If there are too many out-transitions, put the state at the end of
+ * nxt and chk.
+ */
+ if ( numtrans > MAX_XTIONS_FULL_INTERIOR_FIT )
+ {
+ /* If table is empty, return the first available spot in
+ * chk/nxt, which should be 1.
+ */
+ if ( tblend < 2 )
+ return 1;
+
+ /* Start searching for table space near the end of
+ * chk/nxt arrays.
+ */
+ i = tblend - numecs;
+ }
+
+ else
+ /* Start searching for table space from the beginning
+ * (skipping only the elements which will definitely not
+ * hold the new state).
+ */
+ i = firstfree;
+
+ while ( 1 ) /* loops until a space is found */
+ {
+ while ( i + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Loops until space for end-of-buffer and action number
+ * are found.
+ */
+ while ( 1 )
+ {
+ /* Check for action number space. */
+ if ( chk[i - 1] == 0 )
+ {
+ /* Check for end-of-buffer space. */
+ if ( chk[i] == 0 )
+ break;
+
+ else
+ /* Since i != 0, there is no use
+ * checking to see if (++i) - 1 == 0,
+ * because that's the same as i == 0,
+ * so we skip a space.
+ */
+ i += 2;
+ }
+
+ else
+ ++i;
+
+ while ( i + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+ }
+
+ /* If we started search from the beginning, store the new
+ * firstfree for the next call of find_table_space().
+ */
+ if ( numtrans <= MAX_XTIONS_FULL_INTERIOR_FIT )
+ firstfree = i + 1;
+
+ /* Check to see if all elements in chk (and therefore nxt)
+ * that are needed for the new state have not yet been taken.
+ */
+
+ state_ptr = &state[1];
+ ptr_to_last_entry_in_state = &chk[i + numecs + 1];
+
+ for ( chk_ptr = &chk[i + 1];
+ chk_ptr != ptr_to_last_entry_in_state; ++chk_ptr )
+ if ( *(state_ptr++) != 0 && *chk_ptr != 0 )
+ break;
+
+ if ( chk_ptr == ptr_to_last_entry_in_state )
+ return i;
+
+ else
+ ++i;
+ }
+ }
+
+
+/* inittbl - initialize transition tables
+ *
+ * Initializes "firstfree" to be one beyond the end of the table. Initializes
+ * all "chk" entries to be zero.
+ */
+void inittbl()
+ {
+ register int i;
+
+ zero_out( (char *) chk, (size_t) (current_max_xpairs * sizeof( int )) );
+
+ tblend = 0;
+ firstfree = tblend + 1;
+ numtemps = 0;
+
+ if ( usemecs )
+ {
+ /* Set up doubly-linked meta-equivalence classes; these
+ * are sets of equivalence classes which all have identical
+ * transitions out of TEMPLATES.
+ */
+
+ tecbck[1] = NIL;
+
+ for ( i = 2; i <= numecs; ++i )
+ {
+ tecbck[i] = i - 1;
+ tecfwd[i - 1] = i;
+ }
+
+ tecfwd[numecs] = NIL;
+ }
+ }
+
+
+/* mkdeftbl - make the default, "jam" table entries */
+
+void mkdeftbl()
+ {
+ int i;
+
+ jamstate = lastdfa + 1;
+
+ ++tblend; /* room for transition on end-of-buffer character */
+
+ while ( tblend + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Add in default end-of-buffer transition. */
+ nxt[tblend] = end_of_buffer_state;
+ chk[tblend] = jamstate;
+
+ for ( i = 1; i <= numecs; ++i )
+ {
+ nxt[tblend + i] = 0;
+ chk[tblend + i] = jamstate;
+ }
+
+ jambase = tblend;
+
+ base[jamstate] = jambase;
+ def[jamstate] = 0;
+
+ tblend += numecs;
+ ++numtemps;
+ }
+
+
+/* mkentry - create base/def and nxt/chk entries for transition array
+ *
+ * synopsis
+ * int state[numchars + 1], numchars, statenum, deflink, totaltrans;
+ * mkentry( state, numchars, statenum, deflink, totaltrans );
+ *
+ * "state" is a transition array "numchars" characters in size, "statenum"
+ * is the offset to be used into the base/def tables, and "deflink" is the
+ * entry to put in the "def" table entry. If "deflink" is equal to
+ * "JAMSTATE", then no attempt will be made to fit zero entries of "state"
+ * (i.e., jam entries) into the table. It is assumed that by linking to
+ * "JAMSTATE" they will be taken care of. In any case, entries in "state"
+ * marking transitions to "SAME_TRANS" are treated as though they will be
+ * taken care of by whereever "deflink" points. "totaltrans" is the total
+ * number of transitions out of the state. If it is below a certain threshold,
+ * the tables are searched for an interior spot that will accommodate the
+ * state array.
+ */
+
+void mkentry( state, numchars, statenum, deflink, totaltrans )
+register int *state;
+int numchars, statenum, deflink, totaltrans;
+ {
+ register int minec, maxec, i, baseaddr;
+ int tblbase, tbllast;
+
+ if ( totaltrans == 0 )
+ { /* there are no out-transitions */
+ if ( deflink == JAMSTATE )
+ base[statenum] = JAMSTATE;
+ else
+ base[statenum] = 0;
+
+ def[statenum] = deflink;
+ return;
+ }
+
+ for ( minec = 1; minec <= numchars; ++minec )
+ {
+ if ( state[minec] != SAME_TRANS )
+ if ( state[minec] != 0 || deflink != JAMSTATE )
+ break;
+ }
+
+ if ( totaltrans == 1 )
+ {
+ /* There's only one out-transition. Save it for later to fill
+ * in holes in the tables.
+ */
+ stack1( statenum, minec, state[minec], deflink );
+ return;
+ }
+
+ for ( maxec = numchars; maxec > 0; --maxec )
+ {
+ if ( state[maxec] != SAME_TRANS )
+ if ( state[maxec] != 0 || deflink != JAMSTATE )
+ break;
+ }
+
+ /* Whether we try to fit the state table in the middle of the table
+ * entries we have already generated, or if we just take the state
+ * table at the end of the nxt/chk tables, we must make sure that we
+ * have a valid base address (i.e., non-negative). Note that
+ * negative base addresses dangerous at run-time (because indexing
+ * the nxt array with one and a low-valued character will access
+ * memory before the start of the array.
+ */
+
+ /* Find the first transition of state that we need to worry about. */
+ if ( totaltrans * 100 <= numchars * INTERIOR_FIT_PERCENTAGE )
+ {
+ /* Attempt to squeeze it into the middle of the tables. */
+ baseaddr = firstfree;
+
+ while ( baseaddr < minec )
+ {
+ /* Using baseaddr would result in a negative base
+ * address below; find the next free slot.
+ */
+ for ( ++baseaddr; chk[baseaddr] != 0; ++baseaddr )
+ ;
+ }
+
+ while ( baseaddr + maxec - minec + 1 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ for ( i = minec; i <= maxec; ++i )
+ if ( state[i] != SAME_TRANS &&
+ (state[i] != 0 || deflink != JAMSTATE) &&
+ chk[baseaddr + i - minec] != 0 )
+ { /* baseaddr unsuitable - find another */
+ for ( ++baseaddr;
+ baseaddr < current_max_xpairs &&
+ chk[baseaddr] != 0; ++baseaddr )
+ ;
+
+ while ( baseaddr + maxec - minec + 1 >=
+ current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Reset the loop counter so we'll start all
+ * over again next time it's incremented.
+ */
+
+ i = minec - 1;
+ }
+ }
+
+ else
+ {
+ /* Ensure that the base address we eventually generate is
+ * non-negative.
+ */
+ baseaddr = MAX( tblend + 1, minec );
+ }
+
+ tblbase = baseaddr - minec;
+ tbllast = tblbase + maxec;
+
+ while ( tbllast + 1 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ base[statenum] = tblbase;
+ def[statenum] = deflink;
+
+ for ( i = minec; i <= maxec; ++i )
+ if ( state[i] != SAME_TRANS )
+ if ( state[i] != 0 || deflink != JAMSTATE )
+ {
+ nxt[tblbase + i] = state[i];
+ chk[tblbase + i] = statenum;
+ }
+
+ if ( baseaddr == firstfree )
+ /* Find next free slot in tables. */
+ for ( ++firstfree; chk[firstfree] != 0; ++firstfree )
+ ;
+
+ tblend = MAX( tblend, tbllast );
+ }
+
+
+/* mk1tbl - create table entries for a state (or state fragment) which
+ * has only one out-transition
+ */
+
+void mk1tbl( state, sym, onenxt, onedef )
+int state, sym, onenxt, onedef;
+ {
+ if ( firstfree < sym )
+ firstfree = sym;
+
+ while ( chk[firstfree] != 0 )
+ if ( ++firstfree >= current_max_xpairs )
+ expand_nxt_chk();
+
+ base[state] = firstfree - sym;
+ def[state] = onedef;
+ chk[firstfree] = state;
+ nxt[firstfree] = onenxt;
+
+ if ( firstfree > tblend )
+ {
+ tblend = firstfree++;
+
+ if ( firstfree >= current_max_xpairs )
+ expand_nxt_chk();
+ }
+ }
+
+
+/* mkprot - create new proto entry */
+
+void mkprot( state, statenum, comstate )
+int state[], statenum, comstate;
+ {
+ int i, slot, tblbase;
+
+ if ( ++numprots >= MSP || numecs * numprots >= PROT_SAVE_SIZE )
+ {
+ /* Gotta make room for the new proto by dropping last entry in
+ * the queue.
+ */
+ slot = lastprot;
+ lastprot = protprev[lastprot];
+ protnext[lastprot] = NIL;
+ }
+
+ else
+ slot = numprots;
+
+ protnext[slot] = firstprot;
+
+ if ( firstprot != NIL )
+ protprev[firstprot] = slot;
+
+ firstprot = slot;
+ prottbl[slot] = statenum;
+ protcomst[slot] = comstate;
+
+ /* Copy state into save area so it can be compared with rapidly. */
+ tblbase = numecs * (slot - 1);
+
+ for ( i = 1; i <= numecs; ++i )
+ protsave[tblbase + i] = state[i];
+ }
+
+
+/* mktemplate - create a template entry based on a state, and connect the state
+ * to it
+ */
+
+void mktemplate( state, statenum, comstate )
+int state[], statenum, comstate;
+ {
+ int i, numdiff, tmpbase, tmp[CSIZE + 1];
+ Char transset[CSIZE + 1];
+ int tsptr;
+
+ ++numtemps;
+
+ tsptr = 0;
+
+ /* Calculate where we will temporarily store the transition table
+ * of the template in the tnxt[] array. The final transition table
+ * gets created by cmptmps().
+ */
+
+ tmpbase = numtemps * numecs;
+
+ if ( tmpbase + numecs >= current_max_template_xpairs )
+ {
+ current_max_template_xpairs += MAX_TEMPLATE_XPAIRS_INCREMENT;
+
+ ++num_reallocs;
+
+ tnxt = reallocate_integer_array( tnxt,
+ current_max_template_xpairs );
+ }
+
+ for ( i = 1; i <= numecs; ++i )
+ if ( state[i] == 0 )
+ tnxt[tmpbase + i] = 0;
+ else
+ {
+ transset[tsptr++] = i;
+ tnxt[tmpbase + i] = comstate;
+ }
+
+ if ( usemecs )
+ mkeccl( transset, tsptr, tecfwd, tecbck, numecs, 0 );
+
+ mkprot( tnxt + tmpbase, -numtemps, comstate );
+
+ /* We rely on the fact that mkprot adds things to the beginning
+ * of the proto queue.
+ */
+
+ numdiff = tbldiff( state, firstprot, tmp );
+ mkentry( tmp, numecs, statenum, -numtemps, numdiff );
+ }
+
+
+/* mv2front - move proto queue element to front of queue */
+
+void mv2front( qelm )
+int qelm;
+ {
+ if ( firstprot != qelm )
+ {
+ if ( qelm == lastprot )
+ lastprot = protprev[lastprot];
+
+ protnext[protprev[qelm]] = protnext[qelm];
+
+ if ( protnext[qelm] != NIL )
+ protprev[protnext[qelm]] = protprev[qelm];
+
+ protprev[qelm] = NIL;
+ protnext[qelm] = firstprot;
+ protprev[firstprot] = qelm;
+ firstprot = qelm;
+ }
+ }
+
+
+/* place_state - place a state into full speed transition table
+ *
+ * State is the statenum'th state. It is indexed by equivalence class and
+ * gives the number of the state to enter for a given equivalence class.
+ * Transnum is the number of out-transitions for the state.
+ */
+
+void place_state( state, statenum, transnum )
+int *state, statenum, transnum;
+ {
+ register int i;
+ register int *state_ptr;
+ int position = find_table_space( state, transnum );
+
+ /* "base" is the table of start positions. */
+ base[statenum] = position;
+
+ /* Put in action number marker; this non-zero number makes sure that
+ * find_table_space() knows that this position in chk/nxt is taken
+ * and should not be used for another accepting number in another
+ * state.
+ */
+ chk[position - 1] = 1;
+
+ /* Put in end-of-buffer marker; this is for the same purposes as
+ * above.
+ */
+ chk[position] = 1;
+
+ /* Place the state into chk and nxt. */
+ state_ptr = &state[1];
+
+ for ( i = 1; i <= numecs; ++i, ++state_ptr )
+ if ( *state_ptr != 0 )
+ {
+ chk[position + i] = i;
+ nxt[position + i] = *state_ptr;
+ }
+
+ if ( position + numecs > tblend )
+ tblend = position + numecs;
+ }
+
+
+/* stack1 - save states with only one out-transition to be processed later
+ *
+ * If there's room for another state on the "one-transition" stack, the
+ * state is pushed onto it, to be processed later by mk1tbl. If there's
+ * no room, we process the sucker right now.
+ */
+
+void stack1( statenum, sym, nextstate, deflink )
+int statenum, sym, nextstate, deflink;
+ {
+ if ( onesp >= ONE_STACK_SIZE - 1 )
+ mk1tbl( statenum, sym, nextstate, deflink );
+
+ else
+ {
+ ++onesp;
+ onestate[onesp] = statenum;
+ onesym[onesp] = sym;
+ onenext[onesp] = nextstate;
+ onedef[onesp] = deflink;
+ }
+ }
+
+
+/* tbldiff - compute differences between two state tables
+ *
+ * "state" is the state array which is to be extracted from the pr'th
+ * proto. "pr" is both the number of the proto we are extracting from
+ * and an index into the save area where we can find the proto's complete
+ * state table. Each entry in "state" which differs from the corresponding
+ * entry of "pr" will appear in "ext".
+ *
+ * Entries which are the same in both "state" and "pr" will be marked
+ * as transitions to "SAME_TRANS" in "ext". The total number of differences
+ * between "state" and "pr" is returned as function value. Note that this
+ * number is "numecs" minus the number of "SAME_TRANS" entries in "ext".
+ */
+
+int tbldiff( state, pr, ext )
+int state[], pr, ext[];
+ {
+ register int i, *sp = state, *ep = ext, *protp;
+ register int numdiff = 0;
+
+ protp = &protsave[numecs * (pr - 1)];
+
+ for ( i = numecs; i > 0; --i )
+ {
+ if ( *++protp == *++sp )
+ *++ep = SAME_TRANS;
+ else
+ {
+ *++ep = *sp;
+ ++numdiff;
+ }
+ }
+
+ return numdiff;
+ }
diff --git a/usr.bin/lex/version.h b/usr.bin/lex/version.h
new file mode 100644
index 0000000..623ca12
--- /dev/null
+++ b/usr.bin/lex/version.h
@@ -0,0 +1 @@
+#define FLEX_VERSION "2.5.4"
diff --git a/usr.bin/lex/yylex.c b/usr.bin/lex/yylex.c
new file mode 100644
index 0000000..918d468
--- /dev/null
+++ b/usr.bin/lex/yylex.c
@@ -0,0 +1,216 @@
+/* yylex - scanner front-end for flex */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/ncvs/src/usr.bin/lex/yylex.c,v 1.1.1.2 1996/06/19 20:26:46 nate Exp $ */
+
+#include <ctype.h>
+#include "flexdef.h"
+#include "parse.h"
+
+
+/* yylex - scan for a regular expression token */
+
+int yylex()
+ {
+ int toktype;
+ static int beglin = false;
+ extern char *yytext;
+
+ if ( eofseen )
+ toktype = EOF;
+ else
+ toktype = flexscan();
+
+ if ( toktype == EOF || toktype == 0 )
+ {
+ eofseen = 1;
+
+ if ( sectnum == 1 )
+ {
+ synerr( _( "premature EOF" ) );
+ sectnum = 2;
+ toktype = SECTEND;
+ }
+
+ else
+ toktype = 0;
+ }
+
+ if ( trace )
+ {
+ if ( beglin )
+ {
+ fprintf( stderr, "%d\t", num_rules + 1 );
+ beglin = 0;
+ }
+
+ switch ( toktype )
+ {
+ case '<':
+ case '>':
+ case '^':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
+ case '(':
+ case ')':
+ case '-':
+ case '/':
+ case '\\':
+ case '?':
+ case '.':
+ case '*':
+ case '+':
+ case ',':
+ (void) putc( toktype, stderr );
+ break;
+
+ case '\n':
+ (void) putc( '\n', stderr );
+
+ if ( sectnum == 2 )
+ beglin = 1;
+
+ break;
+
+ case SCDECL:
+ fputs( "%s", stderr );
+ break;
+
+ case XSCDECL:
+ fputs( "%x", stderr );
+ break;
+
+ case SECTEND:
+ fputs( "%%\n", stderr );
+
+ /* We set beglin to be true so we'll start
+ * writing out numbers as we echo rules.
+ * flexscan() has already assigned sectnum.
+ */
+ if ( sectnum == 2 )
+ beglin = 1;
+
+ break;
+
+ case NAME:
+ fprintf( stderr, "'%s'", nmstr );
+ break;
+
+ case CHAR:
+ switch ( yylval )
+ {
+ case '<':
+ case '>':
+ case '^':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
+ case '(':
+ case ')':
+ case '-':
+ case '/':
+ case '\\':
+ case '?':
+ case '.':
+ case '*':
+ case '+':
+ case ',':
+ fprintf( stderr, "\\%c",
+ yylval );
+ break;
+
+ default:
+ if ( ! isascii( yylval ) ||
+ ! isprint( yylval ) )
+ fprintf( stderr,
+ "\\%.3o",
+ (unsigned int) yylval );
+ else
+ (void) putc( yylval,
+ stderr );
+ break;
+ }
+
+ break;
+
+ case NUMBER:
+ fprintf( stderr, "%d", yylval );
+ break;
+
+ case PREVCCL:
+ fprintf( stderr, "[%d]", yylval );
+ break;
+
+ case EOF_OP:
+ fprintf( stderr, "<<EOF>>" );
+ break;
+
+ case OPTION_OP:
+ fprintf( stderr, "%s ", yytext );
+ break;
+
+ case OPT_OUTFILE:
+ case OPT_PREFIX:
+ case CCE_ALNUM:
+ case CCE_ALPHA:
+ case CCE_BLANK:
+ case CCE_CNTRL:
+ case CCE_DIGIT:
+ case CCE_GRAPH:
+ case CCE_LOWER:
+ case CCE_PRINT:
+ case CCE_PUNCT:
+ case CCE_SPACE:
+ case CCE_UPPER:
+ case CCE_XDIGIT:
+ fprintf( stderr, "%s", yytext );
+ break;
+
+ case 0:
+ fprintf( stderr, _( "End Marker\n" ) );
+ break;
+
+ default:
+ fprintf( stderr,
+ _( "*Something Weird* - tok: %d val: %d\n" ),
+ toktype, yylval );
+ break;
+ }
+ }
+
+ return toktype;
+ }
diff --git a/usr.bin/limits/Makefile b/usr.bin/limits/Makefile
new file mode 100644
index 0000000..885930f
--- /dev/null
+++ b/usr.bin/limits/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.1 (Berkeley) 7/19/93
+
+PROG= limits
+SRCS= limits.c
+
+CFLAGS+=-Wall
+LDADD+= -lutil
+DPADD+= ${LIBUTIL}
+
+BINOWN= root
+BINMODE=0555
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/limits/limits.1 b/usr.bin/limits/limits.1
new file mode 100644
index 0000000..64d3cbd
--- /dev/null
+++ b/usr.bin/limits/limits.1
@@ -0,0 +1,304 @@
+.\" Copyright (c) 1996 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" this list of conditions, and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd January 15, 1996
+.Dt LIMITS 1
+.Os FreeBSD
+.Sh NAME
+.Nm limits
+.Nd Set or display process resource limits
+.Sh SYNOPSIS
+.Nm limits
+.Op Fl C Ar class | Fl U Ar user
+.Op Fl SHB
+.Op Fl e
+.Op Fl cdflmnstu Op val
+.Nm limits
+.Op Fl C Ar class | Fl U Ar user
+.Op Fl SHB
+.Op Fl cdflmnstu Op val
+.Op Fl E
+.Op Ar name=value ...
+.Op Ar command
+.Sh DESCRIPTION
+.Nm Limits
+ether prints or sets kernel resource limits, and may optionally set
+environment variables like
+.Xr env 1
+and run a program with the selected resources.
+Three uses of the
+.Nm limits
+command are possible:
+.Pp
+.Bl -hang -width indent
+.It Nm limits Op Ar limitflags
+.Op Ar name=value
+.Ar command
+.Pp
+This usage sets limits according to
+.Ar limitflags ,
+optionally sets environment variables given as
+.Ar name=value
+pairs, and then runs the specified command.
+.It Nm limits Op Ar limitflags
+.Pp
+This usage determines values of resource settings according to
+.Ar limitflags ,
+does not attempt to set them and outputs these values to
+standard output.
+By default, this will output the current kernel resource settings
+active for the calling process.
+Using the
+.Fl C Ar class
+or
+.Fl U Ar user
+flags, you may also display the current resource settings modified
+by the the appropriate login class resource limit entries from
+the
+.Xr login.conf 5
+login capabilities database.
+.It Nm limits Fl e Op Ar limitflags
+.Pp
+This usage determines values of resource settings according to
+.Ar limitflags ,
+but does not set them itself.
+Like the previous usage it outputs these values to standard
+output, except that it will emit them in
+.Em eval
+format, suitable for the calling shell.
+The calling shell is determined by examining the entries in the
+.Pa /proc
+filesystem for the parent process.
+If the shell is known (ie. it is one of sh, csh, bash, tcsh, ksh,
+pdksh or rc),
+.Nm limits
+emits 'limit' or 'ulimit' commands in the format understood by
+that shell.
+If the name of the shell cannot be determined, then the 'ulimit'
+format used by
+.Pa /bin/sh
+is used.
+.Pp
+This is very useful for setting limits used by scripts, or prior
+launching of daemons and other background tasks with specific
+resource limit settings, and provides the benefit of allowing
+global configuration of maximum resource usage by maintaining a
+central database of settings in the login class database.
+.Pp
+Within a shell script,
+.Nm limits
+will normally be used with eval within backticks as follows:
+.Pp
+.Dl eval `limits -e -C daemon`
+.Pp
+which causes the output of
+.Nm limits
+to be evaluated and set by the current shell.
+.El
+.Pp
+The value of limitflags specified in the above contains one or more of the
+following options:
+.Pp
+.Bl -tag -width "-d [limit]"
+.It Fl C Ar class
+Use current resource values, modified by the resource entries applicable
+for the login class "class".
+.It Fl U Ar user
+Use current resource values, modified by the resource entries applicable
+to the login class which "user" belongs to.
+If the user does not belong to a class, then the resource capabilities
+for the "default" class are used, if it exists, or the "root" class if
+the user is a superuser account.
+.It Fl S
+Selects display or setting of "soft" (or current) resource limits.
+If specific limits settings follow this switch, only soft limits are
+affected unless overridden later with either the
+.Fl H
+or
+.Fl B
+flags.
+.It Fl H
+Selects display or setting of "hard" (or maximum) resource limits.
+If specific limits settings follow this switch, only hard limits are
+affected until overridden later with either the
+.Fl S
+or
+.Fl B
+flags.
+.It Fl B
+Selects display or setting of both "soft" (current) or "hard" (maximum)
+resource limits.
+If specific limits settings follow this switch, both soft and hard
+limits are affected until overridden later with either the
+.Fl S
+or
+.Fl H
+flags.
+.Fl e
+Selects "eval mode" formatting for output.
+This is valid only on display mode and cannot be used when running a
+command.
+The exact syntax used for output depeneds upon the type of shell from
+which
+.Nm limits
+is invoked.
+.It Fl c Op Ar limit
+Selects or sets (if 'limit' is specified) the
+.Em coredumsize
+resource limit.
+A value of 0 disables core dumps.
+.It Fl d Op Ar limit
+Selects or sets (if 'limit' is specified) the
+.Em datasize
+resource limit.
+.It Fl f Op Ar limit
+Selects or sets the
+.Em filesize
+resource limit.
+.It Fl l Op Ar limit
+Selects or sets the
+.Em memorylocked
+resource limit.
+.It Fl m Op Ar limit
+Selects or sets the
+.Em memoryuse
+size limit
+.It Fl n Op Ar limit
+Selects or sets the
+.Em openfiles
+resource limit.
+.It Fl s Op Ar limit
+Selects or sets the
+.Em stacksize
+resource limit.
+.It Fl t Op Ar limit
+Selects or sets the
+.Em cputime
+resource limit.
+.It Fl u Op Ar limit
+Selects or sets the
+.Em maxproc
+resource limit.
+.Pp
+Valid values for 'limit' in the above set of flags consist of either the
+string 'infinity' or 'inf' for an infinite (or kernel-defined maximum)
+limit, or a numeric value maybe followed by a suffix.
+Values which relate to size default to a value in bytes, or one of the
+following suffixes may be used as a multiplier:
+.Pp
+.Bl -tag -offset indent -width "xxxx" -compact
+.It b
+512 byte blocks.
+.It k
+kilobytes (1024 bytes).
+.It m
+megabytes (1024*1024 bytes).
+.It g
+gigabytes.
+.It t
+terrabytes.
+.El
+.Pp
+The
+.Em cputime
+resource defaults to a number of seconds, but a multiplier may be
+used, and as with size values, multiple values separated by a valid
+suffix are added together:
+.Bl -tag -offset indent -width "xxxx" -compact
+.It s
+seconds.
+.It m
+minutes.
+.It h
+hours.
+.It d
+days.
+.It w
+weeks.
+.It y
+365 day years.
+.El
+.Pp
+.It Fl E
+The option
+.Sq Fl E
+causes
+.Nm limits
+to completely ignore the environment it inherits.
+.It Fl a
+This option forces all resource settings to be displayed even if
+other specific resource settings have been specified.
+For example, if you wish to disable core dumps when starting up
+the usenet news system, but wish to set all other resource settings
+as well that apply to the 'news' account, you might use:
+.Pp
+.Dl eval `limits -U news -aBec 0`
+.Pp
+As with the
+.Xr setrlimit 3
+call, only the superuser may raise process "hard" resource limits.
+Non-root users may, however, lower them or change "soft" resource limits
+within to any value below the hard limit.
+When invoked to execute a program, the failure of
+.Nm limits
+to raise a hard limit is considered a fatal error.
+.El
+.Sh DIAGNOSTICS
+.Nm Limits
+exits with EXIT_FAILURE if usage is incorrect in any way; ie. an invalid
+option, or set/display options are selected in the same invocation,
+.Fl e
+is used when running a program, etc.
+When run in display or eval mode,
+.Nm limits
+exits with with a status of EXIT_SUCCESS.
+When run in command mode and execution of the command succeeds, the exit status
+will be whatever the executed program returns.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr env 1 ,
+.Xr limit 1 ,
+.Xr sh 1 ,
+.Xr ulimit 1 ,
+.Xr getrlimit 3 ,
+.Xr setrlimit 3 ,
+.Xr login_cap 3 ,
+.Xr login.conf 5
+.Sh BUGS
+.Nm Limits
+does not handle commands with equal (``='') signs in their
+names, for obvious reasons.
+.Pp
+When eval output is selected, the /proc filesystem must be installed
+and mounted for the shell to be correctly determined, and therefore
+output syntax correct for the running shell.
+The default output is valid for /bin/sh, so this means that any
+usage of
+.Nm limits
+in eval mode prior mounting /proc may only occur in standard bourne
+shell scripts.
+.Pp
+.Nm Limits
+makes no effort to ensure that resource settings emitted or displayed
+are valid and settable by the current user.
+Only a superuser account may raise hard limits, and and when doing so
+the FreeBSD kernel will silently lower limits to values less than
+specified if the values given are too high.
diff --git a/usr.bin/limits/limits.c b/usr.bin/limits/limits.c
new file mode 100644
index 0000000..98a2b4c
--- /dev/null
+++ b/usr.bin/limits/limits.c
@@ -0,0 +1,630 @@
+/*-
+ * Copyright (c) 1997 by
+ * David L. Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Display/change(+runprogram)/eval resource limits.
+ *
+ * $Id: limits.c,v 1.3 1997/03/29 04:30:26 imp Exp $
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <login_cap.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+enum
+{
+ SH_NONE,
+ SH_SH, /* sh */
+ SH_CSH, /* csh */
+ SH_BASH, /* gnu bash */
+ SH_TCSH, /* tcsh */
+ SH_KSH, /* (pd)ksh */
+ SH_ZSH, /* zsh */
+ SH_RC, /* rc or es */
+ SH_NUMBER
+};
+
+
+/* eval emitter for popular shells.
+ * Why aren't there any standards here? Most shells support either
+ * the csh 'limit' or sh 'ulimit' command, but each varies just
+ * enough that they aren't very compatible from one to the other.
+ */
+static struct {
+ const char * name; /* Name of shell */
+ const char * inf; /* Name used for 'unlimited' resource */
+ const char * cmd; /* Intro text */
+ const char * hard; /* Hard limit text */
+ const char * soft; /* Soft limit text */
+ const char * both; /* Hard+Soft limit text */
+ struct {
+ const char * pfx;
+ const char * sfx;
+ int divisor;
+ } lprm[RLIM_NLIMITS];
+} shellparm[] =
+{
+ { "", "infinity", "Resource limits%s%s:\n", "-max", "-cur", "",
+ {
+ { " cputime%-4s %8s", " secs\n", 1 },
+ { " filesize%-4s %8s", " kb\n", 1024 },
+ { " datasize%-4s %8s", " kb\n", 1024 },
+ { " stacksize%-4s %8s", " kb\n", 1024 },
+ { " coredumpsize%-4s %8s", " kb\n", 1024 },
+ { " memoryuse%-4s %8s", " kb\n", 1024 },
+ { " memorylocked%-4s %8s", " kb\n", 1024 },
+ { " maxprocesses%-4s %8s", "\n", 1 },
+ { " openfiles%-4s %8s", "\n", 1 }
+ }
+ },
+ { "sh", "unlimited", "", " -H", " -S", "",
+ {
+ { "ulimit%s -t %s", ";\n", 1 },
+ { "ulimit%s -f %s", ";\n", 512 },
+ { "ulimit%s -d %s", ";\n", 1024 },
+ { "ulimit%s -s %s", ";\n", 1024 },
+ { "ulimit%s -c %s", ";\n", 512 },
+ { "ulimit%s -m %s", ";\n", 1024 },
+ { "ulimit%s -l %s", ";\n", 1024 },
+ { "ulimit%s -u %s", ";\n", 1 },
+ { "ulimit%s -n %s", ";\n", 1 }
+ }
+ },
+ { "csh", "unlimited", "", " -h", "", NULL,
+ {
+ { "limit%s cputime %s", ";\n", 1 },
+ { "limit%s filesize %s", ";\n", 1024 },
+ { "limit%s datasize %s", ";\n", 1024 },
+ { "limit%s stacksize %s", ";\n", 1024 },
+ { "limit%s coredumpsize %s", ";\n", 1024 },
+ { "limit%s memoryuse %s", ";\n", 1024 },
+ { "limit%s memorylocked %s", ";\n", 1024 },
+ { "limit%s maxproc %s", ";\n", 1 },
+ { "limit%s openfiles %s", ";\n", 1 }
+ }
+ },
+ { "bash|bash2", "unlimited", "", " -H", " -S", "",
+ {
+ { "ulimit%s -t %s", ";\n", 1 },
+ { "ulimit%s -f %s", ";\n", 1024 },
+ { "ulimit%s -d %s", ";\n", 1024 },
+ { "ulimit%s -s %s", ";\n", 1024 },
+ { "ulimit%s -c %s", ";\n", 1024 },
+ { "ulimit%s -m %s", ";\n", 1024 },
+ { "ulimit%s -l %s", ";\n", 1024 },
+ { "ulimit%s -u %s", ";\n", 1 },
+ { "ulimit%s -n %s", ";\n", 1 }
+ }
+ },
+ { "tcsh", "unlimited", "", " -h", "", NULL,
+ {
+ { "limit%s cputime %s", ";\n", 1 },
+ { "limit%s filesize %s", ";\n", 1024 },
+ { "limit%s datasize %s", ";\n", 1024 },
+ { "limit%s stacksize %s", ";\n", 1024 },
+ { "limit%s coredumpsize %s", ";\n", 1024 },
+ { "limit%s memoryuse %s", ";\n", 1024 },
+ { "limit%s memorylocked %s", ";\n", 1024 },
+ { "limit%s maxproc %s", ";\n", 1 },
+ { "limit%s descriptors %s", ";\n", 1 }
+ }
+ },
+ { "ksh|pdksh", "unlimited", "", " -H", " -S", "",
+ {
+ { "ulimit%s -t %s", ";\n", 1 },
+ { "ulimit%s -f %s", ";\n", 512 },
+ { "ulimit%s -d %s", ";\n", 1024 },
+ { "ulimit%s -s %s", ";\n", 1024 },
+ { "ulimit%s -c %s", ";\n", 512 },
+ { "ulimit%s -m %s", ";\n", 1024 },
+ { "ulimit%s -l %s", ";\n", 1024 },
+ { "ulimit%s -p %s", ";\n", 1 },
+ { "ulimit%s -n %s", ";\n", 1 }
+ }
+ },
+ { "zsh", "unlimited", "", " -H", " -S", "",
+ {
+ { "ulimit%s -t %s", ";\n", 1 },
+ { "ulimit%s -f %s", ";\n", 512 },
+ { "ulimit%s -d %s", ";\n", 1024 },
+ { "ulimit%s -s %s", ";\n", 1024 },
+ { "ulimit%s -c %s", ";\n", 512 },
+ { "ulimit%s -m %s", ";\n", 1024 },
+ { "ulimit%s -l %s", ";\n", 1024 },
+ { "ulimit%s -u %s", ";\n", 1 },
+ { "ulimit%s -n %s", ";\n", 1 }
+ }
+ },
+ { "rc|es", "unlimited", "", " -h", "", NULL,
+ {
+ { "limit%s cputime %s", ";\n", 1 },
+ { "limit%s filesize %s", ";\n", 1024 },
+ { "limit%s datasize %s", ";\n", 1024 },
+ { "limit%s stacksize %s", ";\n", 1024 },
+ { "limit%s coredumpsize %s", ";\n", 1024 },
+ { "limit%s memoryuse %s", ";\n", 1024 },
+ { "limit%s lockedmemory %s", ";\n", 1024 },
+ { "limit%s processes %s", ";\n", 1 },
+ { "limit%s descriptors %s", ";\n", 1 }
+ }
+ },
+ { NULL }
+};
+
+static struct {
+ const char * cap;
+ rlim_t (*func)(login_cap_t *, const char *, rlim_t, rlim_t);
+} resources[RLIM_NLIMITS] = {
+ { "cputime", login_getcaptime },
+ { "filesize", login_getcapsize },
+ { "datasize", login_getcapsize },
+ { "stacksize", login_getcapsize },
+ { "coredumpsize", login_getcapsize },
+ { "memoryuse", login_getcapsize },
+ { "memorylocked", login_getcapsize },
+ { "maxproc", login_getcapnum, },
+ { "openfiles", login_getcapnum }
+};
+
+/*
+ * One letter for each resource levels.
+ * NOTE: There is a dependancy on the corresponding
+ * letter index being equal to the resource number.
+ * If sys/resource.h defines are changed, this needs
+ * to be modified accordingly!
+ */
+
+#define RCS_STRING "tfdscmlun"
+
+static rlim_t resource_num(int which, int ch, const char *str);
+static void usage(const char *msg, ...);
+static int getshelltype(void);
+static void print_limit(rlim_t limit, unsigned divisor, const char *inf,
+ const char *pfx, const char *sfx, const char *which);
+extern char **environ;
+
+static const char rcs_string[] = RCS_STRING;
+
+int
+main(int argc, char *argv[])
+{
+ char *p, *cls = NULL;
+ char *cleanenv[1];
+ struct passwd * pwd = NULL;
+ int rcswhich, shelltype;
+ int i, num_limits = 0;
+ int ch, doeval = 0, doall = 0;
+ login_cap_t * lc = NULL;
+ enum { ANY=0, SOFT=1, HARD=2, BOTH=3, DISPLAYONLY=4 } type = ANY;
+ enum { RCSUNKNOWN=0, RCSSET=1, RCSSEL=2 } todo = RCSUNKNOWN;
+ int which_limits[RLIM_NLIMITS];
+ rlim_t set_limits[RLIM_NLIMITS];
+ struct rlimit limits[RLIM_NLIMITS];
+
+ /* init resource tables */
+ for (i = 0; i < RLIM_NLIMITS; i++) {
+ which_limits[i] = 0; /* Don't set/display any */
+ set_limits[i] = RLIM_INFINITY;
+ /* Get current resource values */
+ getrlimit(i, &limits[i]);
+ }
+
+ optarg = NULL;
+ while ((ch = getopt(argc, argv, ":EeC:U:BSHac:d:f:l:m:n:s:t:u:")) != -1) {
+ switch(ch) {
+ case 'a':
+ doall = 1;
+ break;
+ case 'E':
+ environ = cleanenv;
+ cleanenv[0] = NULL;
+ break;
+ case 'e':
+ doeval = 1;
+ break;
+ case 'C':
+ cls = optarg;
+ break;
+ case 'U':
+ if ((pwd = getpwnam(optarg)) == NULL) {
+ if (!isdigit(*optarg) ||
+ (pwd = getpwuid(atoi(optarg))) == NULL) {
+ usage("Invalid user `%s'\n", optarg);
+ }
+ }
+ break;
+ case 'H':
+ type = HARD;
+ break;
+ case 'S':
+ type = SOFT;
+ break;
+ case 'B':
+ type = SOFT|HARD;
+ break;
+ default:
+ case ':': /* Without arg */
+ if ((p = strchr(rcs_string, optopt)) != NULL) {
+ int rcswhich = p - rcs_string;
+ if (optarg && *optarg == '-') { /* 'arg' is actually a switch */
+ --optind; /* back one arg, and make arg NULL */
+ optarg = NULL;
+ }
+ todo = optarg == NULL ? RCSSEL : RCSSET;
+ if (type == ANY)
+ type = BOTH;
+ which_limits[rcswhich] = optarg ? type : DISPLAYONLY;
+ set_limits[rcswhich] = resource_num(rcswhich, optopt, optarg);
+ num_limits++;
+ break;
+ }
+ /* FALLTHRU */
+ case '?':
+ usage(NULL);
+ }
+ optarg = NULL;
+ }
+
+ /* If user was specified, get class from that */
+ if (pwd != NULL)
+ lc = login_getpwclass(pwd);
+ else if (cls != NULL && *cls != '\0') {
+ lc = login_getclassbyname(cls, NULL);
+ if (lc == NULL || strcmp(cls, lc->lc_class) != 0)
+ fprintf(stderr, "login class '%s' non-existent, using %s\n",
+ cls, lc?lc->lc_class:"current settings");
+ }
+
+ /* If we have a login class, update resource table from that */
+ if (lc != NULL) {
+ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
+ char str[40];
+ rlim_t val;
+
+ /* current value overridden by resourcename or resourcename-cur */
+ sprintf(str, "%s-cur", resources[rcswhich].cap);
+ val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_cur, limits[rcswhich].rlim_cur);
+ limits[rcswhich].rlim_cur = resources[rcswhich].func(lc, str, val, val);
+ /* maximum value overridden by resourcename or resourcename-max */
+ sprintf(str, "%s-max", resources[rcswhich].cap);
+ val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_max, limits[rcswhich].rlim_max);
+ limits[rcswhich].rlim_max = resources[rcswhich].func(lc, str, val, val);
+ }
+ }
+
+ /* now, let's determine what we wish to do with all this */
+
+ argv += optind;
+
+ /* If we're setting limits or doing an eval (ie. we're not just
+ * displaying), then check that hard limits are not lower than
+ * soft limits, and force rasing the hard limit if we need to if
+ * we are raising the soft limit, or lower the soft limit if we
+ * are lowering the hard limit.
+ */
+ if ((*argv || doeval) && getuid() == 0) {
+
+ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
+ if (limits[rcswhich].rlim_max != RLIM_INFINITY) {
+ if (limits[rcswhich].rlim_cur == RLIM_INFINITY) {
+ limits[rcswhich].rlim_max = RLIM_INFINITY;
+ which_limits[rcswhich] |= HARD;
+ } else if (limits[rcswhich].rlim_cur > limits[rcswhich].rlim_max) {
+ if (which_limits[rcswhich] == SOFT) {
+ limits[rcswhich].rlim_max = limits[rcswhich].rlim_cur;
+ which_limits[rcswhich] |= HARD;
+ } else if (which_limits[rcswhich] == HARD) {
+ limits[rcswhich].rlim_cur = limits[rcswhich].rlim_max;
+ which_limits[rcswhich] |= SOFT;
+ } else {
+ /* else.. if we're specifically setting both to
+ * silly values, then let it error out.
+ */
+ }
+ }
+ }
+ }
+ }
+
+ /* See if we've overridden anything specific on the command line */
+ if (num_limits && todo == RCSSET) {
+ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
+ if (which_limits[rcswhich] & HARD)
+ limits[rcswhich].rlim_max = set_limits[rcswhich];
+ if (which_limits[rcswhich] & SOFT)
+ limits[rcswhich].rlim_cur = set_limits[rcswhich];
+ }
+ }
+
+ /* If *argv is not NULL, then we are being asked to
+ * (perhaps) set environment variables and run a program
+ */
+ if (*argv) {
+ if (doeval)
+ usage("-e cannot be used with `cmd' option\n");
+
+ login_close(lc);
+
+ /* set leading environment variables, like eval(1) */
+ while (*argv && (p = strchr(*argv, '=')))
+ (void)setenv(*argv++, ++p, 1);
+
+ /* Set limits */
+ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
+ if (doall || num_limits == 0 || which_limits[rcswhich] != 0)
+ if (setrlimit(rcswhich, &limits[rcswhich]) == -1)
+ err(1, "setrlimit %s", resources[rcswhich].cap);
+ }
+
+ if (*argv == NULL)
+ usage(NULL);
+
+ execvp(*argv, argv);
+ err(1, "%s", *argv);
+ }
+
+ shelltype = doeval ? getshelltype() : SH_NONE;
+
+ if (type == ANY) /* Default to soft limits */
+ type = SOFT;
+
+ /* Display limits */
+ printf(shellparm[shelltype].cmd,
+ lc ? " for class " : " (current)",
+ lc ? lc->lc_class : "");
+
+ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) {
+ if (doall || num_limits == 0 || which_limits[rcswhich] != 0) {
+ if (which_limits[rcswhich] == ANY || which_limits[rcswhich])
+ which_limits[rcswhich] = type;
+ if (shellparm[shelltype].lprm[rcswhich].pfx) {
+ if (shellparm[shelltype].both && limits[rcswhich].rlim_cur == limits[rcswhich].rlim_max) {
+ print_limit(limits[rcswhich].rlim_max,
+ shellparm[shelltype].lprm[rcswhich].divisor,
+ shellparm[shelltype].inf,
+ shellparm[shelltype].lprm[rcswhich].pfx,
+ shellparm[shelltype].lprm[rcswhich].sfx,
+ shellparm[shelltype].both);
+ } else {
+ if (which_limits[rcswhich] & HARD) {
+ print_limit(limits[rcswhich].rlim_max,
+ shellparm[shelltype].lprm[rcswhich].divisor,
+ shellparm[shelltype].inf,
+ shellparm[shelltype].lprm[rcswhich].pfx,
+ shellparm[shelltype].lprm[rcswhich].sfx,
+ shellparm[shelltype].hard);
+ }
+ if (which_limits[rcswhich] & SOFT) {
+ print_limit(limits[rcswhich].rlim_cur,
+ shellparm[shelltype].lprm[rcswhich].divisor,
+ shellparm[shelltype].inf,
+ shellparm[shelltype].lprm[rcswhich].pfx,
+ shellparm[shelltype].lprm[rcswhich].sfx,
+ shellparm[shelltype].soft);
+ }
+ }
+ }
+ }
+ }
+
+ login_close(lc);
+ exit(EXIT_SUCCESS);
+}
+
+
+static void
+usage(char const *msg, ...)
+{
+ if (msg) {
+ va_list argp;
+ va_start(argp, msg);
+ vfprintf(stderr, msg, argp);
+ va_end(argp);
+ }
+ (void)fprintf(stderr,
+ "limits [-C class|-U user] [-eaSHBE] [-cdflmnstu [val]] [[name=val ...] cmd]\n");
+ exit(EXIT_FAILURE);
+}
+
+static void
+print_limit(rlim_t limit, unsigned divisor, const char * inf, const char * pfx, const char * sfx, const char * which)
+{
+ char numbr[64];
+
+ if (limit == RLIM_INFINITY)
+ strcpy(numbr, inf);
+ else
+ sprintf(numbr, "%qd", (quad_t)((limit + divisor/2) / divisor));
+ printf(pfx, which, numbr);
+ printf(sfx, which);
+
+}
+
+
+static rlim_t
+resource_num(int which, int ch, const char *str)
+{
+ rlim_t res = RLIM_INFINITY;
+
+ if (str != NULL &&
+ !(strcasecmp(str, "inf") == 0 ||
+ strcasecmp(str, "infinity") == 0 ||
+ strcasecmp(str, "unlimit") == 0 ||
+ strcasecmp(str, "unlimited") == 0)) {
+ const char * s = str;
+ char *e;
+
+ switch (which) {
+ case RLIMIT_CPU: /* time values */
+ errno = 0;
+ res = 0;
+ while (*s) {
+ rlim_t tim = strtoq(s, &e, 0);
+ if (e == NULL || e == s || errno)
+ break;
+ switch (*e++) {
+ case 0: /* end of string */
+ e--;
+ default:
+ case 's': case 'S': /* seconds */
+ break;
+ case 'm': case 'M': /* minutes */
+ tim *= 60L;
+ break;
+ case 'h': case 'H': /* hours */
+ tim *= (60L * 60L);
+ break;
+ case 'd': case 'D': /* days */
+ tim *= (60L * 60L * 24L);
+ break;
+ case 'w': case 'W': /* weeks */
+ tim *= (60L * 60L * 24L * 7L);
+ case 'y': case 'Y': /* Years */
+ tim *= (60L * 60L * 24L * 365L);
+ }
+ s = e;
+ res += tim;
+ }
+ break;
+ case RLIMIT_FSIZE: /* Size values */
+ case RLIMIT_DATA:
+ case RLIMIT_STACK:
+ case RLIMIT_CORE:
+ case RLIMIT_RSS:
+ case RLIMIT_MEMLOCK:
+ errno = 0;
+ res = 0;
+ while (*s) {
+ rlim_t mult, tim = strtoq(s, &e, 0);
+ if (e == NULL || e == s || errno)
+ break;
+ switch (*e++) {
+ case 0: /* end of string */
+ e--;
+ default:
+ mult = 1;
+ break;
+ case 'b': case 'B': /* 512-byte blocks */
+ mult = 512;
+ break;
+ case 'k': case 'K': /* 1024-byte Kilobytes */
+ mult = 1024;
+ break;
+ case 'm': case 'M': /* 1024-k kbytes */
+ mult = 1024 * 1024;
+ break;
+ case 'g': case 'G': /* 1Gbyte */
+ mult = 1024 * 1024 * 1024;
+ break;
+ case 't': case 'T': /* 1TBte */
+ mult = 1024LL * 1024LL * 1024LL * 1024LL;
+ break;
+ }
+ s = e;
+ res += (tim * mult);
+ }
+ break;
+ case RLIMIT_NPROC:
+ case RLIMIT_NOFILE:
+ res = strtoq(s, &e, 0);
+ s = e;
+ break;
+ }
+ if (*s)
+ usage("invalid value -%c `%s'\n", ch, str);
+ }
+ return res;
+}
+
+
+static int
+getshellbyname(const char * shell)
+{
+ int i;
+ const char * q;
+ const char * p = strrchr(shell, '/');
+
+ p = p ? ++p : shell;
+ for (i = 0; (q = shellparm[i].name) != NULL; i++) {
+ while (*q) {
+ int j = strcspn(q, "|");
+
+ if (j == 0)
+ break;
+ if (strncmp(p, q, j) == 0)
+ return i;
+ if (*(q += j))
+ ++q;
+ }
+ }
+ return SH_SH;
+}
+
+
+/*
+ * Determine the type of shell our parent process is
+ * This is quite tricky, not 100% reliable and probably
+ * not nearly as thorough as it should be. Basically, this
+ * is a "best guess" only, but hopefully will work in
+ * most cases.
+ */
+
+static int
+getshelltype(void)
+{
+ pid_t ppid = getppid();
+
+ if (ppid != 1) {
+ FILE * fp;
+ struct stat st;
+ char procdir[MAXPATHLEN], buf[128];
+ int l = sprintf(procdir, "/proc/%ld/", (long)ppid);
+ char * shell = getenv("SHELL");
+
+ if (shell != NULL && stat(shell, &st) != -1) {
+ struct stat st1;
+
+ strcpy(procdir+l, "file");
+ /* $SHELL is actual shell? */
+ if (stat(procdir, &st1) != -1 && memcmp(&st, &st1, sizeof st) == 0)
+ return getshellbyname(shell);
+ }
+ strcpy(procdir+l, "status");
+ if (stat(procdir, &st) == 0 && (fp = fopen(procdir, "r")) != NULL) {
+ char * p = fgets(buf, sizeof buf, fp)==NULL ? NULL : strtok(buf, " \t");
+ fclose(fp);
+ if (p != NULL)
+ return getshellbyname(p);
+ }
+ }
+ return SH_SH;
+}
+
diff --git a/usr.bin/locate/Makefile b/usr.bin/locate/Makefile
index bc55dab..45f82b9 100644
--- a/usr.bin/locate/Makefile
+++ b/usr.bin/locate/Makefile
@@ -1,4 +1,5 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
SUBDIR= bigram code locate
diff --git a/usr.bin/locate/Makefile.inc b/usr.bin/locate/Makefile.inc
new file mode 100644
index 0000000..0f80876
--- /dev/null
+++ b/usr.bin/locate/Makefile.inc
@@ -0,0 +1,3 @@
+# $Id$
+
+LIBEXECDIR?= /usr/libexec
diff --git a/usr.bin/locate/bigram/Makefile b/usr.bin/locate/bigram/Makefile
index d7d4348..fbba14d 100644
--- a/usr.bin/locate/bigram/Makefile
+++ b/usr.bin/locate/bigram/Makefile
@@ -2,6 +2,8 @@
PROG= locate.bigram
NOMAN= noman
-BINDIR= /usr/libexec
+BINDIR= ${LIBEXECDIR}
+CFLAGS+= -I${.CURDIR}/../locate
+.include "../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/usr.bin/locate/bigram/locate.bigram.c b/usr.bin/locate/bigram/locate.bigram.c
index fc0cbb7..663428a 100644
--- a/usr.bin/locate/bigram/locate.bigram.c
+++ b/usr.bin/locate/bigram/locate.bigram.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -32,6 +33,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
@@ -41,45 +44,66 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)locate.bigram.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
- * bigram < text > bigrams
- *
+ * bigram < sorted_file_names | sort -nr |
+ * awk 'NR <= 128 { printf $2 }' > bigrams
+ *
* List bigrams for 'updatedb' script.
* Use 'code' to encode a file using this output.
*/
#include <stdio.h>
#include <sys/param.h> /* for MAXPATHLEN */
+#include "locate.h"
-char buf1[MAXPATHLEN] = " ";
-char buf2[MAXPATHLEN];
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_int bigram[UCHAR_MAX + 1][UCHAR_MAX + 1];
-main ( )
+int
+main(void)
{
- register char *cp;
- register char *oldpath = buf1, *path = buf2;
+ register u_char *cp;
+ register u_char *oldpath = buf1, *path = buf2;
+ register u_int i, j;
+
+ while (fgets(path, sizeof(buf2), stdin) != NULL) {
+
+ /*
+ * We don't need remove newline character '\n'.
+ * '\n' is less than ASCII_MIN and will be later
+ * ignored at output.
+ */
- while ( fgets ( path, sizeof(buf2), stdin ) != NULL ) {
/* skip longest common prefix */
- for ( cp = path; *cp == *oldpath; cp++, oldpath++ )
- if ( *oldpath == '\0' )
+ for (cp = path; *cp == *oldpath; cp++, oldpath++)
+ if (*cp == '\0')
break;
- /*
- * output post-residue bigrams only
- */
- while ( *cp != '\0' && *(cp + 1) != '\0' ) {
- putchar ( *cp++ );
- putchar ( *cp++ );
- putchar ( '\n' );
+
+ while (*cp != '\0' && *(cp + 1) != '\0') {
+ bigram[(u_char)*cp][(u_char)*(cp + 1)]++;
+ cp += 2;
+ }
+
+ /* swap pointers */
+ if (path == buf1) {
+ path = buf2;
+ oldpath = buf1;
+ } else {
+ path = buf1;
+ oldpath = buf2;
}
- if ( path == buf1 ) /* swap pointers */
- path = buf2, oldpath = buf1;
- else
- path = buf1, oldpath = buf2;
}
- return (0);
+
+ /* output, boundary check */
+ for (i = ASCII_MIN; i <= ASCII_MAX; i++)
+ for (j = ASCII_MIN; j <= ASCII_MAX; j++)
+ if (bigram[i][j] != 0)
+ (void)printf("%4u %c%c\n", bigram[i][j], i, j);
+
+ exit(0);
}
diff --git a/usr.bin/locate/code/Makefile b/usr.bin/locate/code/Makefile
index 743e968..a7d8e80 100644
--- a/usr.bin/locate/code/Makefile
+++ b/usr.bin/locate/code/Makefile
@@ -1,8 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= locate.code
-CFLAGS+=-I${.CURDIR}/../locate
+CFLAGS+=-I${.CURDIR}/../locate
NOMAN= noman
-BINDIR= /usr/libexec
+BINDIR= ${LIBEXECDIR}
+.include "../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/usr.bin/locate/code/locate.code.c b/usr.bin/locate/code/locate.code.c
index 5561dea..47d2059 100644
--- a/usr.bin/locate/code/locate.code.c
+++ b/usr.bin/locate/code/locate.code.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -32,6 +33,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: locate.code.c,v 1.9 1997/02/22 19:55:43 peter Exp $
*/
#ifndef lint
@@ -41,7 +44,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)locate.code.c 8.4 (Berkeley) 5/4/95";
+static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
@@ -70,47 +73,67 @@ static char sccsid[] = "@(#)locate.code.c 8.4 (Berkeley) 5/4/95";
*
* 0-28 likeliest differential counts + offset to make nonnegative
* 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
* 128-255 bigram codes (128 most common, as determined by 'updatedb')
* 32-127 single character (printable) ascii residue (ie, literal)
*
- * SEE ALSO: updatedb.csh, bigram.c
+ * The locate database store any character except newline ('\n')
+ * and NUL ('\0'). The 8-bit character support don't wast extra
+ * space until you have characters in file names less than 32
+ * or greather than 127.
+ *
+ *
+ * SEE ALSO: updatedb.sh, ../bigram/locate.bigram.c
*
* AUTHOR: James A. Woods, Informatics General Corp.,
* NASA Ames Research Center, 10/82
+ * 8-bit file names characters:
+ * Wolfram Schneider, Berlin September 1996
*/
#include <sys/param.h>
-
#include <err.h>
#include <errno.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-
+#include <stdio.h>
#include "locate.h"
#define BGBUFSIZE (NBG * 2) /* size of bigram buffer */
-char buf1[MAXPATHLEN] = " ";
-char buf2[MAXPATHLEN];
-char bigrams[BGBUFSIZE + 1] = { 0 };
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_char bigrams[BGBUFSIZE + 1] = { 0 };
+
+#define LOOKUP 1 /* use a lookup array instead a function, 3x faster */
+#ifdef LOOKUP
+#define BGINDEX(x) (big[(u_char)*x][(u_char)*(x + 1)])
+typedef short bg_t;
+bg_t big[UCHAR_MAX + 1][UCHAR_MAX + 1];
+#else
+#define BGINDEX(x) bgindex(x)
+typedef int bg_t;
int bgindex __P((char *));
+#endif /* LOOKUP */
+
+
void usage __P((void));
+extern int optind;
+extern int optopt;
int
main(argc, argv)
int argc;
char *argv[];
{
- register char *cp, *oldpath, *path;
+ register u_char *cp, *oldpath, *path;
int ch, code, count, diffcount, oldcount;
FILE *fp;
+ register int i, j;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
- case '?':
default:
usage();
}
@@ -125,29 +148,51 @@ main(argc, argv)
/* First copy bigram array to stdout. */
(void)fgets(bigrams, BGBUFSIZE + 1, fp);
+
if (fwrite(bigrams, 1, BGBUFSIZE, stdout) != BGBUFSIZE)
err(1, "stdout");
(void)fclose(fp);
+#ifdef LOOKUP
+ /* init lookup table */
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ for (j = 0; j < UCHAR_MAX + 1; j++)
+ big[i][j] = (bg_t)-1;
+
+ for (cp = bigrams, i = 0; *cp != '\0'; i += 2, cp += 2)
+ big[(u_char)*cp][(u_char)*(cp + 1)] = (bg_t)i;
+
+#endif /* LOOKUP */
+
oldpath = buf1;
path = buf2;
oldcount = 0;
+
while (fgets(path, sizeof(buf2), stdin) != NULL) {
- /* Truncate newline. */
- cp = path + strlen(path) - 1;
- if (cp > path && *cp == '\n')
- *cp = '\0';
- /* Squelch characters that would botch the decoding. */
+ /* skip empty lines */
+ if (*path == '\n')
+ continue;
+
+ /* remove newline */
for (cp = path; *cp != '\0'; cp++) {
- if ((u_char)*cp >= PARITY || *cp <= SWITCH)
+#ifndef LOCATE_CHAR30
+ /* old locate implementations core'd for char 30 */
+ if (*cp == SWITCH)
*cp = '?';
+ else
+#endif /* !LOCATE_CHAR30 */
+
+ /* chop newline */
+ if (*cp == '\n')
+ *cp = '\0';
}
/* Skip longest common prefix. */
for (cp = path; *cp == *oldpath; cp++, oldpath++)
- if (*oldpath == '\0')
+ if (*cp == '\0')
break;
+
count = cp - path;
diffcount = count - oldcount + OFFSET;
oldcount = count;
@@ -160,22 +205,42 @@ main(argc, argv)
err(1, "stdout");
while (*cp != '\0') {
- if (*(cp + 1) == '\0') {
- if (putchar(*cp) == EOF)
- err(1, "stdout");
- break;
- }
- if ((code = bgindex(cp)) < 0) {
- if (putchar(*cp++) == EOF ||
- putchar(*cp++) == EOF)
- err(1, "stdout");
- } else {
- /* Found, so mark byte with parity bit. */
+ /* print *two* characters */
+
+ if ((code = BGINDEX(cp)) != (bg_t)-1) {
+ /*
+ * print *one* as bigram
+ * Found, so mark byte with
+ * parity bit.
+ */
if (putchar((code / 2) | PARITY) == EOF)
err(1, "stdout");
cp += 2;
}
+
+ else {
+ for (i = 0; i < 2; i++) {
+ if (*cp == '\0')
+ break;
+
+ /* print umlauts in file names */
+ if (*cp < ASCII_MIN ||
+ *cp > ASCII_MAX) {
+ if (putchar(UMLAUT) == EOF ||
+ putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+
+ else {
+ /* normal character */
+ if(putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+ }
+
+ }
}
+
if (path == buf1) { /* swap pointers */
path = buf2;
oldpath = buf1;
@@ -190,6 +255,7 @@ main(argc, argv)
exit(0);
}
+#ifndef LOOKUP
int
bgindex(bg) /* Return location of bg in bigrams or -1. */
char *bg;
@@ -198,11 +264,12 @@ bgindex(bg) /* Return location of bg in bigrams or -1. */
bg0 = bg[0];
bg1 = bg[1];
- for (p = bigrams; *p != '\0'; p++)
+ for (p = bigrams; *p != NULL; p++)
if (*p++ == bg0 && *p == bg1)
break;
- return (*p == '\0' ? -1 : --p - bigrams);
+ return (*p == NULL ? -1 : (--p - bigrams));
}
+#endif /* !LOOKUP */
void
usage()
diff --git a/usr.bin/locate/locate/Makefile b/usr.bin/locate/locate/Makefile
index 2e6c696..5e20b83 100644
--- a/usr.bin/locate/locate/Makefile
+++ b/usr.bin/locate/locate/Makefile
@@ -1,10 +1,25 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
PROG= locate
+SRCS= util.c locate.c
+CFLAGS+= -I${.CURDIR} -DMMAP # -DDEBUG (print time) -O2 (10% faster)
+MAN1= locate.1
+MAN8= locate.updatedb.8
+SCRIPTS= updatedb mklocatedb concatdb
+MLINKS+= locate.updatedb.8 updatedb.8
+
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/updatedb.csh ${DESTDIR}/usr/libexec/locate.updatedb
+.for script in ${SCRIPTS}
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/${script}.sh ${DESTDIR}${LIBEXECDIR}/locate.${script}
+.endfor
+
+# only /usr/src/etc/Makefile install files in /etc
+# ${INSTALL} -c -o root -g wheel -m 644 \
+# ${.CURDIR}/locate.rc ${DESTDIR}/etc
.include "../../Makefile.inc"
+.include "../Makefile.inc"
.include <bsd.prog.mk>
diff --git a/usr.bin/locate/locate/concatdb.sh b/usr.bin/locate/locate/concatdb.sh
new file mode 100644
index 0000000..f40c7b3
--- /dev/null
+++ b/usr.bin/locate/locate/concatdb.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# concatdb - concatenate locate databases
+#
+# usage: concatdb database1 ... databaseN > newdb
+#
+# Sequence of databases is important.
+#
+# $Id$
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR=/tmp}; export TMPDIR;
+if test X"$TMPDIR" = X -o ! -d "$TMPDIR"; then
+ TMPDIR=/tmp; export TMPDIR
+fi
+
+# utilities to built locate database
+: ${bigram=locate.bigram}
+: ${code=locate.code}
+: ${sort=sort}
+: ${locate=locate}
+
+
+case $# in
+ [01]) echo 'usage: concatdb databases1 ... databaseN > newdb'
+ exit 1
+ ;;
+esac
+
+
+bigrams=$TMPDIR/_concatdb$$.bigrams
+trap 'rm -f $bigrams' 0 1 2 3 5 10 15
+
+for db
+do
+ $locate -d $db /
+done | $bigram | $sort -nr | awk 'NR <= 128 { printf $2 }' > $bigrams
+
+for db
+do
+ $locate -d $db /
+done | $code $bigrams
diff --git a/usr.bin/locate/locate/fastfind.c b/usr.bin/locate/locate/fastfind.c
new file mode 100644
index 0000000..c17c6f1
--- /dev/null
+++ b/usr.bin/locate/locate/fastfind.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#ifndef _LOCATE_STATISTIC_
+#define _LOCATE_STATISTIC_
+
+void
+statistic (fp, path_fcodes)
+ FILE *fp; /* open database */
+ char *path_fcodes; /* for error message */
+{
+ register int lines, chars, size, big, zwerg;
+ register u_char *p, *s;
+ register int c;
+ int count, umlaut;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+
+ lines = chars = big = zwerg = umlaut = 0;
+ size = NBG + NBG;
+
+ for (c = getc(fp), count = 0; c != EOF; size++) {
+ if (c == SWITCH) {
+ count += getwf(fp) - OFFSET;
+ size += sizeof(int);
+ zwerg++;
+ } else
+ count += c - OFFSET;
+
+ for (p = path + count; (c = getc(fp)) > SWITCH; size++)
+ if (c < PARITY) {
+ if (c == UMLAUT) {
+ c = getc(fp);
+ size++;
+ umlaut++;
+ }
+ p++;
+ } else {
+ /* bigram char */
+ big++;
+ p += 2;
+ }
+
+ p++;
+ lines++;
+ chars += (p - path);
+ }
+
+ (void)printf("\nDatabase: %s\n", path_fcodes);
+ (void)printf("Compression: Front: %2.2f%%, ",
+ (float)(100 * (size + big - (2 * NBG))) / chars);
+ (void)printf("Bigram: %2.2f%%, ", (float)(100 * (size - big)) / size);
+ (void)printf("Total: %2.2f%%\n",
+ (float)(100 * (size - (2 * NBG))) / chars);
+ (void)printf("Filenames: %d, ", lines);
+ (void)printf("Characters: %d, ", chars);
+ (void)printf("Database size: %d\n", size);
+ (void)printf("Bigram characters: %d, ", big);
+ (void)printf("Integers: %d, ", zwerg);
+ (void)printf("8-Bit characters: %d\n", umlaut);
+
+}
+#endif /* _LOCATE_STATISTIC_ */
+
+
+void
+#ifdef FF_MMAP
+
+
+#ifdef FF_ICASE
+fastfind_mmap_icase
+#else
+fastfind_mmap
+#endif /* FF_ICASE */
+(pathpart, paddr, len, database)
+ char *pathpart; /* search string */
+ caddr_t paddr; /* mmap pointer */
+ int len; /* length of database */
+ char *database; /* for error message */
+
+
+#else /* MMAP */
+
+
+#ifdef FF_ICASE
+fastfind_icase
+#else
+fastfind
+#endif /* FF_ICASE */
+
+(fp, pathpart, database)
+ FILE *fp; /* open database */
+ char *pathpart; /* search string */
+ char *database; /* for error message */
+
+
+#endif /* MMAP */
+
+{
+ register u_char *p, *s, *patend, *q, *foundchar;
+ register int c, cc;
+ int count, found, globflag;
+ u_char *cutoff;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+#ifdef FF_ICASE
+ /* use a lookup table for case insensitive search */
+ u_char table[UCHAR_MAX + 1];
+
+ tolower_word(pathpart);
+#endif /* FF_ICASE*/
+
+ /* init bigram table */
+#ifdef FF_MMAP
+ if (len < (2*NBG)) {
+ (void)fprintf(stderr, "database too small: %s\n", database);
+ exit(1);
+ }
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++, len-= 2) {
+ p[c] = check_bigram_char(*paddr++);
+ s[c] = check_bigram_char(*paddr++);
+ }
+#else
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+#endif /* FF_MMAP */
+
+ /* find optimal (last) char for searching */
+ for (p = pathpart; *p != '\0'; p++)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+
+ if (*p == '\0')
+ globflag = 0;
+ else
+ globflag = 1;
+
+ p = pathpart;
+ patend = patprep(p);
+ cc = *patend;
+
+#ifdef FF_ICASE
+ /* set patend char to true */
+ for (c = 0; c < UCHAR_MAX + 1; c++)
+ table[c] = 0;
+
+ table[TOLOWER(*patend)] = 1;
+ table[toupper(*patend)] = 1;
+#endif /* FF_ICASE */
+
+
+ /* main loop */
+ found = count = 0;
+ foundchar = 0;
+
+#ifdef FF_MMAP
+ c = (u_char)*paddr++; len--;
+ for (; len > 0; ) {
+#else
+ c = getc(fp);
+ for (; c != EOF; ) {
+#endif /* FF_MMAP */
+
+ /* go forward or backward */
+ if (c == SWITCH) { /* big step, an integer */
+#ifdef FF_MMAP
+ count += getwm(paddr) - OFFSET;
+ len -= INTSIZE; paddr += INTSIZE;
+#else
+ count += getwf(fp) - OFFSET;
+#endif /* FF_MMAP */
+ } else { /* slow step, =< 14 chars */
+ count += c - OFFSET;
+ }
+
+ /* overlay old path */
+ p = path + count;
+ foundchar = p - 1;
+
+ for (;;) {
+#ifdef FF_MMAP
+ c = (u_char)*paddr++;
+ len--;
+#else
+ c = getc(fp);
+#endif /* FF_MMAP */
+ /*
+ * == UMLAUT: 8 bit char followed
+ * <= SWITCH: offset
+ * >= PARITY: bigram
+ * rest: single ascii char
+ *
+ * offset < SWITCH < UMLAUT < ascii < PARITY < bigram
+ */
+ if (c < PARITY) {
+ if (c <= UMLAUT) {
+ if (c == UMLAUT) {
+#ifdef FF_MMAP
+ c = (u_char)*paddr++;
+ len--;
+#else
+ c = getc(fp);
+#endif /* FF_MMAP */
+
+ } else
+ break; /* SWITCH */
+ }
+#ifdef FF_ICASE
+ if (table[c])
+#else
+ if (c == cc)
+#endif /* FF_ICASE */
+ foundchar = p;
+ *p++ = c;
+ }
+ else {
+ /* bigrams are parity-marked */
+ TO7BIT(c);
+
+#ifndef FF_ICASE
+ if (bigram1[c] == cc ||
+ bigram2[c] == cc)
+#else
+
+ if (table[bigram1[c]] ||
+ table[bigram2[c]])
+#endif /* FF_ICASE */
+ foundchar = p + 1;
+
+ *p++ = bigram1[c];
+ *p++ = bigram2[c];
+ }
+ }
+
+ if (found) { /* previous line matched */
+ cutoff = path;
+ *p-- = '\0';
+ foundchar = p;
+ } else if (foundchar >= path + count) { /* a char matched */
+ *p-- = '\0';
+ cutoff = path + count;
+ } else /* nothing to do */
+ continue;
+
+ found = 0;
+ for (s = foundchar; s >= cutoff; s--) {
+ if (*s == cc
+#ifdef FF_ICASE
+ || TOLOWER(*s) == cc
+#endif /* FF_ICASE */
+ ) { /* fast first char check */
+ for (p = patend - 1, q = s - 1; *p != '\0';
+ p--, q--)
+ if (*q != *p
+#ifdef FF_ICASE
+ && TOLOWER(*q) != *p
+#endif /* FF_ICASE */
+ )
+ break;
+ if (*p == '\0') { /* fast match success */
+ found = 1;
+ if (!globflag ||
+#ifndef FF_ICASE
+ !fnmatch(pathpart, path, 0))
+#else
+ !fnmatch(pathpart, path,
+ FNM_CASEFOLD))
+#endif /* !FF_ICASE */
+ {
+ if (f_silent)
+ counter++;
+ else if (f_limit) {
+ counter++;
+ if (f_limit >= counter)
+ (void)puts(path);
+ else {
+ (void)fprintf(stderr, "[show only %d lines]\n", counter - 1);
+ exit(0);
+ }
+ } else
+ (void)puts(path);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/usr.bin/locate/locate/locate.1 b/usr.bin/locate/locate/locate.1
index 89cc2e8..c580bbe 100644
--- a/usr.bin/locate/locate/locate.1
+++ b/usr.bin/locate/locate/locate.1
@@ -1,3 +1,4 @@
+.\" Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -30,42 +31,165 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)locate.1 8.1 (Berkeley) 6/6/93
+.\" $Id: locate.1,v 1.8 1997/03/06 05:11:55 jmg Exp $
.\"
.Dd June 6, 1993
.Dt LOCATE 1
.Os BSD 4.4
.Sh NAME
.Nm locate
-.Nd find files
+.Nd find filenames quickly
.Sh SYNOPSIS
-.Ar locate
-pattern
+.Nm
+.Op Fl Scims
+.Op Fl l Ar limit
+.Op Fl d Ar database
+pattern ...
.Sh DESCRIPTION
-.Nm Locate
-searches a database for all pathnames which match the specified
+The
+.Nm
+program searches a database for all pathnames which match the specified
.Ar pattern .
-The database is recomputed periodically, and contains the pathnames
+The database is recomputed periodically (usually weekly or daily),
+and contains the pathnames
of all files which are publicly accessible.
.Pp
-Shell globbing and quoting characters (``*'', ``?'', ``\e'', ``[''
-and ``]'')
+Shell globbing and quoting characters
+.Po
+.Dq * ,
+.Dq ? ,
+.Dq \e ,
+.Dq [
+and
+.Dq \]
+.Pc
may be used in
.Ar pattern ,
although they will have to be escaped from the shell.
-Preceding any character with a backslash (``\e'') eliminates any special
+Preceding any character with a backslash
+.Pq Dq \e
+eliminates any special
meaning which it may have.
The matching differs in that no characters must be matched explicitly,
-including slashes (``/'').
+including slashes
+.Pq Dq / .
.Pp
-As a special case, a pattern containing no globbing characters (``foo'')
-is matched as though it were ``*foo*''.
+As a special case, a pattern containing no globbing characters
+.Pq Dq foo
+is matched as though it were
+.Dq *foo* .
+
+Historically, locate store only characters between 32 and 127. The
+current implementation store any character except newline
+.Pq Sq \en
+and NUL
+.Pq Sq \e0 .
+The 8-bit character support doesn't waste extra space for
+plain ASCII file names. Characters less than 32 or greater than 127
+are stored in 2 bytes.
+
+The following options are available:
+.Bl -tag -width 10n indent
+.It Fl S
+Print some statistic about the database and exit.
+.It Fl c
+Suppress normal output; instead print a count of matching file names.
+.It Fl d Ar database
+Search in
+.Ar database
+instead the default file name database.
+Multiple
+.Fl d
+options are allowed. Each additional
+.Fl d
+option adds the specified database to the list
+of databases to be searched.
+
+The option
+.Ar database
+may be a colon-separated list of databases. A single colon is a reference
+to the default database.
+
+$ locate -d $HOME/lib/mydb: foo
+
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database .
+
+$ locate -d $HOME/lib/mydb::/cdrom/locate.database foo
+
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database
+and then in
+.Pa /cdrom/locate.database .
+
+
+.Do
+$ locate -d db1 -d db2 -d db3 pattern
+.Dc
+is the same as
+
+.Dq $ locate -d db1:db2:db3 pattern
+or
+
+.Dq $ locate -d db1:db2 -d db3 pattern .
+
+If
+.Ar -
+is given as the database name, standard input will be read instead.
+For example, you can compress your database
+and use:
+
+$ zcat database.gz | locate -d - pattern
+
+This might be useful on machines with a fast CPU and little RAM and slow
+I/O. Note: you can only use
+.Ar one
+pattern for stdin.
+.It Fl i
+Ignore case distinctions in both the pattern and the database.
+.It Fl l Ar number
+Limit output to
+.Ar number
+of file names and exit.
+.It Fl m
+Use
+.Xr mmap 2
+instead of the
+.Xr stdio 3
+library. This is the default behavior. Usually faster in most cases.
+.It Fl s
+Use the
+.Xr stdio 3
+library instead of
+.Xr mmap 2 .
.Sh FILES
-.Bl -tag -width /var/db/locate.database -compact
+.Bl -tag -width /usr/libexec/locate.updatedb -compact
.It Pa /var/db/locate.database
+locate database
+.It Pa /usr/libexec/locate.updatedb
+Script to update the locate database
+.It Pa /etc/weekly
+Script that usually starts the database rebuild
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LOCATE_PATH -compact
+.It Pa LOCATE_PATH
+path to the locate database if set and not empty, ignored if the
+.Fl d
+option was specified.
.El
.Sh SEE ALSO
.Xr find 1 ,
-.Xr fnmatch 3
+.Xr fnmatch 3 ,
+.Xr locate.updatedb 8
.Rs
.%A Woods, James A.
.%D 1983
@@ -74,8 +198,52 @@ is matched as though it were ``*foo*''.
.%V 8:1
.%P pp. 8-10
.Re
+.Sh BUGS
+The
+.Nm
+program may fail to list some files that are present, or may
+list files that have been removed from the system. This is because
+locate only reports files that are present in the database, which is
+typically only regenerated once a week by the
+.Pa /etc/weekly
+script. Use
+.Xr find 1
+to locate files that are of a more transitory nature.
+
+The
+.Nm
+database was built by user
+.Dq nobody .
+.Xr find 1
+skip directories,
+which are not readable for user
+.Dq nobody ,
+group
+.Dq nobody ,
+or
+world. E.g. if your HOME directory ist not world-readable, all your
+files are
+.Ar not
+in the database.
+
+The
+.Nm
+database is not byte order independent. It is not possible
+to share the databases between machines with different byte order.
+The current
+.Nm
+implementation understand databases in host byte order or
+network byte order if both architectures use the same integer size.
+So you can read on a FreeBSD/i386 machine
+(little endian)
+a locate database which was built on SunOS/sparc machine
+(big endian, net).
+
.Sh HISTORY
The
-.Nm locate
-command appears in
+.Nm
+command first appeared in
.Bx 4.4 .
+Many new features were
+added in
+.Fx 2.2 .
diff --git a/usr.bin/locate/locate/locate.c b/usr.bin/locate/locate/locate.c
index ea43872..a9bed92 100644
--- a/usr.bin/locate/locate/locate.c
+++ b/usr.bin/locate/locate/locate.c
@@ -1,6 +1,7 @@
/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
* Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* James A. Woods.
@@ -15,8 +16,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -32,16 +33,19 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: locate.c,v 1.9 1997/02/22 19:55:47 peter Exp $
*/
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1989, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
+"@(#) Copyright (c) 1995-1996 Wolfram Schneider, Berlin.\n\
+@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
@@ -53,144 +57,315 @@ static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
* bigram coding by a further 20-25%.
*
* The codes are:
- *
- * 0-28 likeliest differential counts + offset to make nonnegative
- * 30 switch code for out-of-range count to follow in next word
- * 128-255 bigram codes (128 most common, as determined by 'updatedb')
- * 32-127 single character (printable) ascii residue (ie, literal)
- *
+ *
+ * 0-28 likeliest differential counts + offset to make nonnegative
+ * 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
+ * 128-255 bigram codes (128 most common, as determined by 'updatedb')
+ * 32-127 single character (printable) ascii residue (ie, literal)
+ *
* A novel two-tiered string search technique is employed:
- *
+ *
* First, a metacharacter-free subpattern and partial pathname is matched
* BACKWARDS to avoid full expansion of the pathname list. The time savings
* is 40-50% over forward matching, which cannot efficiently handle
* overlapped search patterns and compressed path residue.
- *
+ *
* Then, the actual shell glob-style regular expression (if in this form) is
* matched against the candidate pathnames using the slower routines provided
* in the standard 'find'.
*/
#include <sys/param.h>
-
+#include <ctype.h>
+#include <err.h>
#include <fnmatch.h>
-#include <unistd.h>
+#include <locale.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+
+#ifdef MMAP
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+# include <fcntl.h>
+#endif
+
+
+#ifdef sun
+#include <netinet/in.h> /* SunOS byteorder(3) htohl(3) */
+#ifndef __P
+#define __P(x) x
+#endif
+#endif
#include "locate.h"
#include "pathnames.h"
-FILE *fp;
+#ifdef DEBUG
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/resource.h>
+#endif
+
+char *path_fcodes; /* locate database */
+int f_mmap; /* use mmap */
+int f_icase; /* ignore case */
+int f_stdin; /* read database from stdin */
+int f_statistic; /* print statistic */
+int f_silent; /* suppress output, show only count of matches */
+int f_limit; /* limit number of output lines, 0 == infinite */
+u_int counter; /* counter for matches [-c] */
+
+
+void usage __P((void));
+void statistic __P((FILE *, char *));
+void fastfind __P((FILE *, char *, char *));
+void fastfind_icase __P((FILE *, char *, char *));
+void fastfind_mmap __P((char *, caddr_t, int, char *));
+void fastfind_mmap_icase __P((char *, caddr_t, int, char *));
+void search_mmap __P((char *, char **));
+void search_fopen __P((char *, char **));
+unsigned long cputime __P((void));
+
+extern char **colon __P((char **, char*, char*));
+extern void print_matches __P((u_int));
+extern int getwm __P((caddr_t));
+extern int getwf __P((FILE *));
+extern u_char *tolower_word __P((u_char *));
+extern int check_bigram_char __P((int));
+extern char *patprep __P((char *));
+
+extern char *optarg;
+extern int optind;
+
int
main(argc, argv)
- int argc;
- char *argv[];
+ int argc;
+ char **argv;
{
- if (argc != 2) {
- (void)fprintf(stderr, "usage: locate pattern\n");
- exit(1);
- }
- if (!(fp = fopen(_PATH_FCODES, "r"))) {
- (void)fprintf(stderr, "locate: no database file %s.\n",
- _PATH_FCODES);
- exit(1);
- }
- while (*++argv)
- fastfind(*argv);
- exit(0);
+ register int ch;
+ char **dbv = NULL;
+#ifdef MMAP
+ f_mmap = 1; /* mmap is default */
+#endif
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "Scd:il:ms")) != -1)
+ switch(ch) {
+ case 'S': /* statistic lines */
+ f_statistic = 1;
+ break;
+ case 'l': /* limit number of output lines, 0 == infinite */
+ f_limit = atoi(optarg);
+ break;
+ case 'd': /* database */
+ dbv = colon(dbv, optarg, _PATH_FCODES);
+ break;
+ case 'i': /* ignore case */
+ f_icase = 1;
+ break;
+ case 'm': /* mmap */
+#ifdef MMAP
+ f_mmap = 1;
+#else
+ (void)fprintf(stderr, "mmap(2) not implemented\n");
+#endif
+ break;
+ case 's': /* stdio lib */
+ f_mmap = 0;
+ break;
+ case 'c': /* suppress output, show only count of matches */
+ f_silent = 1;
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ /* to few arguments */
+ if (argc < 1 && !(f_statistic))
+ usage();
+
+ /* no (valid) database as argument */
+ if (dbv == NULL || *dbv == NULL) {
+ /* try to read database from enviroment */
+ if ((path_fcodes = getenv("LOCATE_PATH")) == NULL ||
+ *path_fcodes == '\0')
+ /* use default database */
+ dbv = colon(dbv, _PATH_FCODES, _PATH_FCODES);
+ else /* $LOCATE_PATH */
+ dbv = colon(dbv, path_fcodes, _PATH_FCODES);
+ }
+
+ if (f_icase && UCHAR_MAX < 4096) /* init tolower lookup table */
+ for (ch = 0; ch < UCHAR_MAX + 1; ch++)
+ myctype[ch] = tolower(ch);
+
+ /* foreach database ... */
+ while((path_fcodes = *dbv) != NULL) {
+ dbv++;
+
+ if (!strcmp(path_fcodes, "-"))
+ f_stdin = 1;
+ else
+ f_stdin = 0;
+
+#ifndef MMAP
+ f_mmap = 0; /* be paranoid */
+#endif
+ if (!f_mmap || f_stdin || f_statistic)
+ search_fopen(path_fcodes, argv);
+ else
+ search_mmap(path_fcodes, argv);
+ }
+
+ if (f_silent)
+ print_matches(counter);
+ exit(0);
}
-fastfind(pathpart)
- char *pathpart;
+
+void
+search_fopen(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
{
- register char *p, *s;
- register int c;
- int count, found, globflag;
- char *cutoff, *patend, *q, *patprep();
- char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
-
- for (c = 0, p = bigram1, s = bigram2; c < NBG; c++)
- p[c] = getc(fp), s[c] = getc(fp);
-
- p = pathpart;
- globflag = index(p, '*') || index(p, '?') || index(p, '[');
- patend = patprep(p);
-
- found = 0;
- for (c = getc(fp), count = 0; c != EOF;) {
- count += ((c == SWITCH) ? getw(fp) : c) - OFFSET;
- /* overlay old path */
- for (p = path + count; (c = getc(fp)) > SWITCH;)
- if (c < PARITY)
- *p++ = c;
- else { /* bigrams are parity-marked */
- c &= PARITY - 1;
- *p++ = bigram1[c], *p++ = bigram2[c];
- }
- *p-- = NULL;
- cutoff = (found ? path : path + count);
- for (found = 0, s = p; s >= cutoff; s--)
- if (*s == *patend) { /* fast first char check */
- for (p = patend - 1, q = s - 1; *p != NULL;
- p--, q--)
- if (*q != *p)
- break;
- if (*p == NULL) { /* fast match success */
- found = 1;
- if (!globflag ||
- !fnmatch(pathpart, path, 0))
- (void)printf("%s\n", path);
- break;
- }
- }
+ FILE *fp;
+#ifdef DEBUG
+ long t0;
+#endif
+
+ /* can only read stdin once */
+ if (f_stdin) {
+ fp = stdin;
+ if (*(s+1) != NULL) {
+ (void)fprintf(stderr,
+ "read database from stdin, use only");
+ (void)fprintf(stderr, " `%s' as pattern\n", *s);
+ *(s+1) = NULL;
+ }
+ }
+ else if ((fp = fopen(path_fcodes, "r")) == NULL)
+ err(1, "`%s'", path_fcodes);
+
+ /* count only chars or lines */
+ if (f_statistic) {
+ statistic(fp, path_fcodes);
+ (void)fclose(fp);
+ return;
}
-}
-/*
- * extract last glob-free subpattern in name for fast pre-match; prepend
- * '\0' for backwards match; return end of new pattern
- */
-static char globfree[100];
+ /* foreach search string ... */
+ while(*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (!f_stdin &&
+ fseek(fp, (long)0, SEEK_SET) == -1)
+ err(1, "fseek to begin of ``%s''\n", path_fcodes);
+
+ if (f_icase)
+ fastfind_icase(fp, *s, path_fcodes);
+ else
+ fastfind(fp, *s, path_fcodes);
+#ifdef DEBUG
+ (void)fprintf(stderr, "fastfind %ld ms\n", cputime () - t0);
+#endif
+ s++;
+ }
+ (void)fclose(fp);
+}
-char *
-patprep(name)
- char *name;
+#ifdef MMAP
+void
+search_mmap(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
{
- register char *endmark, *p, *subp;
-
- subp = globfree;
- *subp++ = '\0';
- p = name + strlen(name) - 1;
- /* skip trailing metacharacters (and [] ranges) */
- for (; p >= name; p--)
- if (index("*?", *p) == 0)
- break;
- if (p < name)
- p = name;
- if (*p == ']')
- for (p--; p >= name; p--)
- if (*p == '[') {
- p--;
- break;
- }
- if (p < name)
- p = name;
- /*
- * if pattern has only metacharacters, check every path (force '/'
- * search)
- */
- if ((p == name) && index("?*[]", *p) != 0)
- *subp++ = '/';
- else {
- for (endmark = p; p >= name; p--)
- if (index("]*?", *p) != 0)
- break;
- for (++p;
- (p <= endmark) && subp < (globfree + sizeof(globfree));)
- *subp++ = *p++;
+ struct stat sb;
+ int fd;
+ caddr_t p;
+ off_t len;
+#ifdef DEBUG
+ long t0;
+#endif
+ if ((fd = open(path_fcodes, O_RDONLY)) == -1 ||
+ fstat(fd, &sb) == -1)
+ err(1, "`%s'", path_fcodes);
+ len = sb.st_size;
+
+ if ((p = mmap((caddr_t)0, (size_t)len,
+ PROT_READ, MAP_SHARED,
+ fd, (off_t)0)) == MAP_FAILED)
+ err(1, "mmap ``%s''", path_fcodes);
+
+ /* foreach search string ... */
+ while (*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (f_icase)
+ fastfind_mmap_icase(*s, p, (int)len, path_fcodes);
+ else
+ fastfind_mmap(*s, p, (int)len, path_fcodes);
+#ifdef DEBUG
+ (void)fprintf(stderr, "fastfind %ld ms\n", cputime () - t0);
+#endif
+ s++;
}
- *subp = '\0';
- return(--subp);
+
+ if (munmap(p, (size_t)len) == -1)
+ warn("munmap %s\n", path_fcodes);
+
+ (void)close(fd);
}
+#endif /* MMAP */
+
+#ifdef DEBUG
+unsigned long
+cputime ()
+{
+ struct rusage rus;
+
+ getrusage(0, &rus);
+ return(rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000);
+}
+#endif /* DEBUG */
+
+void
+usage ()
+{
+ (void)fprintf(stderr, "usage: locate [-Scims] [-l limit] ");
+ (void)fprintf(stderr, "[-d database] pattern ...\n\n");
+ (void)fprintf(stderr, "default database: `%s' or $LOCATE_PATH\n",
+ _PATH_FCODES);
+ exit(1);
+}
+
+
+/* load fastfind functions */
+
+/* statistic */
+/* fastfind_mmap, fastfind_mmap_icase */
+#ifdef MMAP
+#undef FF_MMAP
+#undef FF_ICASE
+
+#define FF_MMAP
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
+#endif /* MMAP */
+
+/* fopen */
+/* fastfind, fastfind_icase */
+#undef FF_MMAP
+#undef FF_ICASE
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
diff --git a/usr.bin/locate/locate/locate.h b/usr.bin/locate/locate/locate.h
index fe4da28..9e997d4 100644
--- a/usr.bin/locate/locate/locate.h
+++ b/usr.bin/locate/locate/locate.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -31,6 +32,7 @@
* SUCH DAMAGE.
*
* @(#)locate.h 8.1 (Berkeley) 6/6/93
+ * $Id$
*/
/* Symbolic constants shared by locate.c and code.c */
@@ -39,3 +41,32 @@
#define OFFSET 14 /* abs value of max likely diff */
#define PARITY 0200 /* parity bit */
#define SWITCH 30 /* switch code */
+#define UMLAUT 31 /* an 8 bit char followed */
+
+/* 0-28 likeliest differential counts + offset to make nonnegative */
+#define LDC_MIN 0
+#define LDC_MAX 28
+
+/* 128-255 bigram codes (128 most common, as determined by 'updatedb') */
+#define BIGRAM_MIN (UCHAR_MAX - CHAR_MAX)
+#define BIGRAM_MAX UCHAR_MAX
+
+/* 32-127 single character (printable) ascii residue (ie, literal) */
+#define ASCII_MIN 32
+#define ASCII_MAX CHAR_MAX
+
+/* #define TO7BIT(x) (x = ( ((u_char)x) & CHAR_MAX )) */
+#define TO7BIT(x) (x = x & CHAR_MAX )
+
+
+#if UCHAR_MAX >= 4096
+ define TOLOWER(ch) tolower(ch)
+#else
+
+u_char myctype[UCHAR_MAX + 1];
+#define TOLOWER(ch) (myctype[ch])
+#endif
+
+#define INTSIZE (sizeof(int))
+
+#define LOCATE_REG "*?[]\\" /* fnmatch(3) meta characters */
diff --git a/usr.bin/locate/locate/locate.rc b/usr.bin/locate/locate/locate.rc
new file mode 100644
index 0000000..20937c0
--- /dev/null
+++ b/usr.bin/locate/locate/locate.rc
@@ -0,0 +1,26 @@
+#
+# /etc/locate.rc - command script for updatedb(8)
+#
+# $Id$
+
+#
+# All commented values are the defaults
+#
+# temp directory
+#TMPDIR="/tmp"
+
+# the actual database
+#FCODES="/var/db/locate.database"
+
+# directories to be put in the database
+#SEARCHPATHS="/"
+
+# directories unwanted in output
+#PRUNEPATHS="/tmp /usr/tmp /var/tmp"
+
+# filesystems allowed. Beware: a non-listed filesystem will be pruned
+# and if the SEARCHPATHS starts in such a filesystem locate will build
+# an empty database.
+#
+# be carefully if you add 'nfs'
+#FILESYSTEMS="ufs"
diff --git a/usr.bin/locate/locate/locate.updatedb.8 b/usr.bin/locate/locate/locate.updatedb.8
new file mode 100644
index 0000000..a35c607
--- /dev/null
+++ b/usr.bin/locate/locate/locate.updatedb.8
@@ -0,0 +1,64 @@
+.\" Copyright (c) 1996
+.\" Mike Pritchard <mpp@FreeBSD.org>. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Mike Pritchard.
+.\" 4. Neither the name of the author nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd February 11, 1996
+.Dt LOCATE.UPDATEDB 8
+.Os BSD 4.4
+.Sh NAME
+.Nm locate.updatedb
+.Nd update locate database
+.Sh SYNOPSIS
+.Nm /usr/libexec/locate.updatedb
+.Sh DESCRIPTION
+.Nm Locate.updatedb
+updates the database used by
+.Xr locate 1 .
+It is typically run once a week by the
+.Nm /etc/weekly script.
+.Pp
+The contents of the newly built database can be controlled by the
+.Nm /etc/locate.rc file.
+.Sh FILES
+.Bl -tag -width /var/db/locate.database -compact
+.It Pa /var/db/locate.database
+the actual database
+.It Pa /etc/locate.rc
+the configuration file
+.El
+.Sh SEE ALSO
+.Xr locate 1
+.Rs
+.%A Woods, James A.
+.%D 1983
+.%T "Finding Files Fast"
+.%J ";login"
+.%V 8:1
+.%P pp. 8-10
+.Re
diff --git a/usr.bin/locate/locate/mklocatedb.sh b/usr.bin/locate/locate/mklocatedb.sh
new file mode 100644
index 0000000..e2b4fa7
--- /dev/null
+++ b/usr.bin/locate/locate/mklocatedb.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# mklocatedb - build locate database
+#
+# usage: mklocatedb [-presort] < filelist > database
+#
+# $Id$
+
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR=/tmp}; export TMPDIR;
+if test X"$TMPDIR" = X -o ! -d "$TMPDIR"; then
+ TMPDIR=/tmp; export TMPDIR
+fi
+
+# utilities to built locate database
+: ${bigram=locate.bigram}
+: ${code=locate.code}
+: ${sort=sort}
+
+
+sortopt="-u -T $TMPDIR"
+sortcmd=$sort
+
+# Input already sorted
+case X"$1" in
+ X-nosort|X-presort) sortcmd=cat; sortopt=;shift;;
+esac
+
+
+bigrams=$TMPDIR/_mklocatedb$$.bigrams
+filelist=$TMPDIR/_mklocatedb$$.list
+
+trap 'rm -f $bigrams $filelist' 0 1 2 3 5 10 15
+
+
+if $sortcmd $sortopt > $filelist; then
+ $bigram < $filelist | $sort -nr |
+ awk 'NR <= 128 { printf $2 }' > $bigrams &&
+ $code $bigrams < $filelist
+else
+ echo "`basename $0`: cannot build locate database" >&2
+ exit 1
+fi
diff --git a/usr.bin/locate/locate/updatedb.sh b/usr.bin/locate/locate/updatedb.sh
new file mode 100644
index 0000000..e2622da
--- /dev/null
+++ b/usr.bin/locate/locate/updatedb.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# updatedb - update locate database for local mounted filesystems
+#
+# $Id$
+
+LOCATE_CONFIG="/etc/locate.rc"
+if [ -f "$LOCATE_CONFIG" -a -r "$LOCATE_CONFIG" ]; then
+ . $LOCATE_CONFIG
+fi
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR=/usr/libexec}; export LIBEXECDIR
+: ${TMPDIR=/tmp}; export TMPDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+
+: ${mklocatedb=locate.mklocatedb} # make locate database program
+: ${FCODES=/var/db/locate.database} # the database
+: ${SEARCHPATHS="/"} # directories to be put in the database
+: ${PRUNEPATHS="/tmp /usr/tmp /var/tmp"} # unwanted directories
+: ${FILESYSTEMS="ufs"} # allowed filesystems
+: ${find=find}
+
+case X"$SEARCHPATHS" in
+ X) echo "$0: empty variable SEARCHPATHS"; exit 1;; esac
+case X"$FILESYSTEMS" in
+ X) echo "$0: empty variable FILESYSTEMS"; exit 1;; esac
+
+# Make a list a paths to exclude in the locate run
+excludes="! (" or=""
+for fstype in $FILESYSTEMS
+do
+ excludes="$excludes $or -fstype $fstype"
+ or="-or"
+done
+excludes="$excludes ) -prune"
+
+case X"$PRUNEPATHS" in
+ X) ;;
+ *) for path in $PRUNEPATHS
+ do
+ excludes="$excludes -or -path $path -prune"
+ done;;
+esac
+
+tmp=$TMPDIR/_updatedb$$
+trap 'rm -f $tmp' 0 1 2 3 5 10 15
+
+# search locally
+# echo $find $SEARCHPATHS $excludes -or -print && exit
+if $find $SEARCHPATHS $excludes -or -print 2>/dev/null |
+ $mklocatedb > $tmp
+then
+ case X"`$find $tmp -size -257c -print`" in
+ X) cat $tmp > $FCODES;;
+ *) echo "updatedb: locate database $tmp is empty"
+ exit 1
+ esac
+fi
diff --git a/usr.bin/locate/locate/util.c b/usr.bin/locate/locate/util.c
new file mode 100644
index 0000000..57bd157
--- /dev/null
+++ b/usr.bin/locate/locate/util.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sys/param.h>
+#include <stdio.h>
+
+#include "locate.h"
+
+char **colon __P((char **, char*, char*));
+char *patprep __P((char *));
+void print_matches __P((u_int));
+u_char *tolower_word __P((u_char *));
+int getwm __P((caddr_t));
+int getwf __P((FILE *));
+int check_bigram_char __P((int));
+
+/*
+ * Validate bigram chars. If the test failed the database is corrupt
+ * or the database is obviously not a locate database.
+ */
+int
+check_bigram_char(ch)
+ int ch;
+{
+ /* legal bigram: 0, ASCII_MIN ... ASCII_MAX */
+ if (ch == 0 ||
+ (ch >= ASCII_MIN && ch <= ASCII_MAX))
+ return(ch);
+
+ (void)fprintf(stderr, "locate database header corrupt, bigram ");
+ (void)fprintf(stderr, "char outside 0, %d-%d: %d\n",
+ ASCII_MIN, ASCII_MAX, ch);
+ exit(1);
+}
+
+/* split a colon separated string into a char vector
+ *
+ * "bla:foo" -> {"foo", "bla"}
+ * "bla:" -> {"foo", dot}
+ * "bla" -> {"bla"}
+ * "" -> do nothing
+ *
+ */
+char **
+colon(dbv, path, dot)
+ char **dbv;
+ char *path;
+ char *dot; /* default for single ':' */
+{
+ int vlen, slen;
+ char *c, *ch, *p;
+ char **pv;
+
+ if (dbv == NULL) {
+ if ((dbv = malloc(sizeof(char **))) == NULL)
+ err(1, "malloc");
+ *dbv = NULL;
+ }
+
+ /* empty string */
+ if (*path == '\0') {
+ (void)fprintf(stderr, "empty database name, ignored\n");
+ return(dbv);
+ }
+
+ /* length of string vector */
+ for(vlen = 0, pv = dbv; *pv != NULL; pv++, vlen++);
+
+ for (ch = c = path; ; ch++) {
+ if (*ch == ':' ||
+ (!*ch && !(*(ch - 1) == ':' && ch == 1+ path))) {
+ /* single colon -> dot */
+ if (ch == c)
+ p = dot;
+ else {
+ /* a string */
+ slen = ch - c;
+ if ((p = malloc(sizeof(char) * (slen + 1)))
+ == NULL)
+ err(1, "malloc");
+ bcopy(c, p, slen);
+ *(p + slen) = '\0';
+ }
+ /* increase dbv with element p */
+ if ((dbv = realloc(dbv, sizeof(char **) * (vlen + 2)))
+ == NULL)
+ err(1, "realloc");
+ *(dbv + vlen) = p;
+ *(dbv + ++vlen) = NULL;
+ c = ch + 1;
+ }
+ if (*ch == '\0')
+ break;
+ }
+ return (dbv);
+}
+
+void
+print_matches(counter)
+ u_int counter;
+{
+ (void)printf("%d\n", counter);
+}
+
+
+/*
+ * extract last glob-free subpattern in name for fast pre-match; prepend
+ * '\0' for backwards match; return end of new pattern
+ */
+static char globfree[100];
+
+char *
+patprep(name)
+ char *name;
+{
+ register char *endmark, *p, *subp;
+
+ subp = globfree;
+ *subp++ = '\0'; /* set first element to '\0' */
+ p = name + strlen(name) - 1;
+
+ /* skip trailing metacharacters */
+ for (; p >= name; p--)
+ if (index(LOCATE_REG, *p) == NULL)
+ break;
+
+ /*
+ * check if maybe we are in a character class
+ *
+ * 'foo.[ch]'
+ * |----< p
+ */
+ if (p >= name &&
+ (index(p, '[') != NULL || index(p, ']') != NULL)) {
+ for (p = name; *p != '\0'; p++)
+ if (*p == ']' || *p == '[')
+ break;
+ p--;
+
+ /*
+ * cannot find a non-meta character, give up
+ * '*\*[a-z]'
+ * |-------< p
+ */
+ if (p >= name && index(LOCATE_REG, *p) != NULL)
+ p = name - 1;
+ }
+
+ if (p < name)
+ /* only meta chars: "???", force '/' search */
+ *subp++ = '/';
+
+ else {
+ for (endmark = p; p >= name; p--)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+ for (++p;
+ (p <= endmark) && subp < (globfree + sizeof(globfree));)
+ *subp++ = *p++;
+ }
+ *subp = '\0';
+ return(--subp);
+}
+
+/* tolower word */
+u_char *
+tolower_word(word)
+ u_char *word;
+{
+ register u_char *p;
+
+ for(p = word; *p != '\0'; p++)
+ *p = TOLOWER(*p);
+
+ return(word);
+}
+
+
+/*
+ * Read integer from mmap pointer.
+ * Essential a simple ``return *(int *)p'' but avoid sigbus
+ * for integer alignment (SunOS 4.x, 5.x).
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwm(p)
+ caddr_t p;
+{
+ static char buf[INTSIZE];
+ register int i;
+
+ for (i = 0; i < INTSIZE; i++)
+ buf[i] = *p++;
+
+ i = *(int *)buf;
+
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN)) {
+ i = ntohl(i);
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN)) {
+ (void)fprintf(stderr,
+ "integer out of +-MAXPATHLEN (%d): %d\n",
+ MAXPATHLEN, i);
+ exit(1);
+ }
+ }
+ return(i);
+}
+
+/*
+ * Read integer from stream.
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwf(fp)
+ FILE *fp;
+{
+ register int word;
+
+ word = getw(fp);
+
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN)) {
+ word = ntohl(word);
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN)) {
+ (void)fprintf(stderr,
+ "integer out of +-MAXPATHLEN (%d): %d\n",
+ MAXPATHLEN, word);
+ exit(1);
+ }
+ }
+ return(word);
+}
diff --git a/usr.bin/lock/Makefile b/usr.bin/lock/Makefile
index 9403206..1a55d41 100644
--- a/usr.bin/lock/Makefile
+++ b/usr.bin/lock/Makefile
@@ -3,5 +3,7 @@
PROG= lock
BINOWN= root
BINMODE=4555
+DPADD= ${LIBCRYPT}
+LDADD= -lcrypt
.include <bsd.prog.mk>
diff --git a/usr.bin/lock/lock.1 b/usr.bin/lock/lock.1
index ad8575c..fba5442 100644
--- a/usr.bin/lock/lock.1
+++ b/usr.bin/lock/lock.1
@@ -39,6 +39,7 @@
.Nd reserve a terminal
.Sh SYNOPSIS
.Nm lock
+.Op Fl n
.Op Fl p
.Op Fl t Ar timeout
.Sh DESCRIPTION
@@ -53,6 +54,8 @@ with the appropriate permission.
Options:
.Pp
.Bl -tag -width Fl
+.It Fl n
+Don't use a timeout value. Terminal will be locked forever.
.It Fl p
A password is not requested, instead the user's current login password
is used.
diff --git a/usr.bin/lock/lock.c b/usr.bin/lock/lock.c
index 774ebc9..9f76971 100644
--- a/usr.bin/lock/lock.c
+++ b/usr.bin/lock/lock.c
@@ -70,6 +70,7 @@ struct timeval timeout;
struct timeval zerotime;
struct sgttyb tty, ntty;
long nexttime; /* keep the timeout time */
+int no_timeout; /* lock terminal forever */
/*ARGSUSED*/
main(argc, argv)
@@ -90,7 +91,8 @@ main(argc, argv)
sectimeout = TIMEOUT;
mypw = NULL;
usemine = 0;
- while ((ch = getopt(argc, argv, "pt:")) != EOF)
+ no_timeout = 0;
+ while ((ch = getopt(argc, argv, "npt:")) != -1)
switch((char)ch) {
case 't':
if ((sectimeout = atoi(optarg)) <= 0) {
@@ -108,10 +110,13 @@ main(argc, argv)
}
mypw = strdup(pw->pw_passwd);
break;
+ case 'n':
+ no_timeout = 1;
+ break;
case '?':
default:
(void)fprintf(stderr,
- "usage: lock [-p] [-t timeout]\n");
+ "usage: lock [-n] [-p] [-t timeout]\n");
exit(1);
}
timeout.tv_sec = sectimeout * 60;
@@ -169,11 +174,17 @@ main(argc, argv)
ntimer.it_interval = zerotime;
ntimer.it_value = timeout;
- setitimer(ITIMER_REAL, &ntimer, &otimer);
+ if (!no_timeout)
+ setitimer(ITIMER_REAL, &ntimer, &otimer);
/* header info */
+ if (no_timeout) {
+(void)printf("lock: %s on %s. no timeout\ntime now is %.20s%s%s",
+ ttynam, hostname, ap, tzn, ap + 19);
+ } else {
(void)printf("lock: %s on %s. timeout in %d minutes\ntime now is %.20s%s%s",
ttynam, hostname, sectimeout, ap, tzn, ap + 19);
+ }
for (;;) {
(void)printf("Key: ");
@@ -201,9 +212,16 @@ hi()
{
struct timeval timval;
- if (!gettimeofday(&timval, (struct timezone *)NULL))
-(void)printf("lock: type in the unlock key. timeout in %ld:%ld minutes\n",
- (nexttime - timval.tv_sec) / 60, (nexttime - timval.tv_sec) % 60);
+ if (!gettimeofday(&timval, (struct timezone *)NULL)) {
+ (void)printf("lock: type in the unlock key. ");
+ if (no_timeout) {
+ (void)putchar('\n');
+ } else {
+ (void)printf("timeout in %ld:%ld minutes\n",
+ (nexttime - timval.tv_sec) / 60,
+ (nexttime - timval.tv_sec) % 60);
+ }
+ }
}
void
@@ -217,7 +235,9 @@ quit()
void
bye()
{
- (void)ioctl(0, TIOCSETP, &tty);
- (void)printf("lock: timeout\n");
- exit(1);
+ if (!no_timeout) {
+ (void)ioctl(0, TIOCSETP, &tty);
+ (void)printf("lock: timeout\n");
+ exit(1);
+ }
}
diff --git a/usr.bin/lockf/Makefile b/usr.bin/lockf/Makefile
new file mode 100644
index 0000000..47fb6ab
--- /dev/null
+++ b/usr.bin/lockf/Makefile
@@ -0,0 +1,6 @@
+# $Id$
+
+PROG= lockf
+CFLAGS+=-Wall
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/lockf/lockf.1 b/usr.bin/lockf/lockf.1
new file mode 100644
index 0000000..eac10340
--- /dev/null
+++ b/usr.bin/lockf/lockf.1
@@ -0,0 +1,112 @@
+.\"
+.\" Copyright (C) 1997 John D. Polstra. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd January 8, 1997
+.Os FreeBSD
+.Dt LOCKF 1
+.Sh NAME
+.Nm lockf
+.Nd execute a command while holding a file lock
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Op Fl t Ar seconds
+.Ar file
+.Ar command
+.Op Ar arguments
+.Sh DESCRIPTION
+The
+.Nm
+utility acquires an exclusive lock on a
+.Ar file ,
+creating it if necessary.
+While holding the lock, it executes a
+.Ar command
+with optional
+.Ar arguments .
+After the
+.Ar command
+completes,
+.Nm
+releases the lock and removes the
+.Ar file .
+BSD-style locking is used, as described in
+.Xr flock 2 ;
+the mere existence of the
+.Ar file
+is not considered to constitute a lock.
+.Pp
+The following options are supported:
+.Bl -tag -width Fl
+.It Fl s
+Causes
+.Nm
+to operate silently.
+Failure to acquire the lock is indicated only in the exit status.
+.It Fl t Ar seconds
+Specifies a timeout for waiting for the lock. By default,
+.Nm
+waits indefinitely to acquire the lock.
+If a timeout is specified with this option,
+.Nm
+will wait at most the given number of
+.Ar seconds
+before giving up. A timeout of 0 may be given, in which case
+.Nm
+will fail unless it can acquire the lock immediately.
+.El
+.Pp
+In no event will
+.Nm
+break a lock that is held by another process.
+.Sh DIAGNOSTICS
+If
+.Nm
+successfully acquires the lock, it returns the exit status produced by
+.Ar command .
+Otherwise, it returns one of the exit codes defined in
+.Xr sysexits 3 ,
+as follows:
+.Bl -tag -width F_CANTCREATX
+.It Dv EX_TEMPFAIL
+The specified lock file was already locked by another process.
+.It Dv EX_CANTCREAT
+.Nm
+was unable to create the lock file, e.g., because of insufficient access
+privileges.
+.It Dv EX_USAGE
+There was an error on the
+.Nm
+command line.
+.It Dv EX_OSERR
+A system call (e.g., fork) failed unexpectedly.
+.El
+.Sh SEE ALSO
+.Xr flock 2 ,
+.Xr sysexits 3 .
+.Sh AUTHORS
+John Polstra,
+.Aq jdp@polstra.com .
diff --git a/usr.bin/lockf/lockf.c b/usr.bin/lockf/lockf.c
new file mode 100644
index 0000000..8541ce3
--- /dev/null
+++ b/usr.bin/lockf/lockf.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1997 John D. Polstra. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: lockf.c,v 1.4 1997/02/22 19:55:54 peter Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static int acquire_lock(const char *name);
+static void cleanup(void);
+static void killed(int sig);
+static void timeout(int sig);
+static void usage(void);
+static void wait_for_lock(const char *name);
+
+static const char *lockname;
+static volatile sig_atomic_t timed_out;
+
+/*
+ * Execute an arbitrary command while holding a file lock.
+ */
+int
+main(int argc, char **argv)
+{
+ int ch;
+ int lockfd;
+ int silent;
+ int status;
+ int waitsec;
+ pid_t child;
+
+ silent = 0;
+ waitsec = -1; /* Infinite. */
+ while ((ch = getopt(argc, argv, "st:")) != -1) {
+ switch (ch) {
+
+ case 's':
+ silent = 1;
+ break;
+
+ case 't':
+ {
+ char *endptr;
+ waitsec = strtol(optarg, &endptr, 0);
+ if (*optarg == '\0' || *endptr != '\0' || waitsec < 0)
+ errx(EX_USAGE, "invalid timeout \"%s\"", optarg);
+ }
+ break;
+
+ default:
+ usage();
+ }
+ }
+ if (argc - optind < 2)
+ usage();
+ lockname = argv[optind++];
+ argc -= optind;
+ argv += optind;
+
+ if (waitsec > 0) { /* Set up a timeout. */
+ struct sigaction act;
+
+ act.sa_handler = timeout;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* Note that we do not set SA_RESTART. */
+
+ sigaction(SIGALRM, &act, NULL);
+ alarm(waitsec);
+ }
+
+ lockfd = acquire_lock(lockname);
+ while (lockfd == -1 && !timed_out && waitsec != 0) {
+ wait_for_lock(lockname);
+ lockfd = acquire_lock(lockname);
+ }
+
+ if (waitsec > 0)
+ alarm(0);
+
+ if (lockfd == -1) { /* We failed to acquire the lock. */
+ if (silent)
+ exit(EX_TEMPFAIL);
+ errx(EX_TEMPFAIL, "%s: already locked", lockname);
+ }
+
+ /* At this point, we own the lock. */
+
+ if (atexit(cleanup) == -1)
+ err(EX_OSERR, "atexit failed");
+
+ if ((child = fork()) == -1)
+ err(EX_OSERR, "cannot fork");
+
+ if (child == 0) { /* The child process. */
+ close(lockfd);
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ _exit(1);
+ }
+
+ /* This is the parent process. */
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, killed);
+
+ if (waitpid(child, &status, 0) == -1)
+ err(EX_OSERR, "waitpid failed");
+
+ return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
+}
+
+/*
+ * Try to acquire a lock on the given file, but don't wait for it. Returns
+ * an open file descriptor on success, or -1 on failure.
+ */
+static int
+acquire_lock(const char *name)
+{
+ int fd;
+
+ if ((fd = open(name, O_RDONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 0666)) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ return -1;
+ err(EX_CANTCREAT, "cannot open %s", name);
+ }
+ return fd;
+}
+
+/*
+ * Remove the lock file.
+ */
+static void
+cleanup(void)
+{
+ unlink(lockname);
+}
+
+/*
+ * Signal handler for SIGTERM. Cleans up the lock file, then re-raises
+ * the signal.
+ */
+static void
+killed(int sig)
+{
+ cleanup();
+ signal(sig, SIG_DFL);
+ if (kill(getpid(), sig) == -1)
+ err(EX_OSERR, "kill failed");
+}
+
+/*
+ * Signal handler for SIGALRM.
+ */
+static void
+timeout(int sig)
+{
+ timed_out = 1;
+}
+
+static void
+usage(void)
+{
+ errx(EX_USAGE, "usage: lockf [-s] [-t seconds] file command [arguments]");
+}
+
+/*
+ * Wait until it might be possible to acquire a lock on the given file.
+ */
+static void
+wait_for_lock(const char *name)
+{
+ int fd;
+
+ if ((fd = open(name, O_RDONLY|O_EXLOCK)) == -1) {
+ if (errno == ENOENT || errno == EINTR)
+ return;
+ err(EX_CANTCREAT, "cannot open %s", name);
+ }
+ close(fd);
+ return;
+}
diff --git a/usr.bin/logger/logger.c b/usr.bin/logger/logger.c
index 3fd3b6b..553591f 100644
--- a/usr.bin/logger/logger.c
+++ b/usr.bin/logger/logger.c
@@ -72,7 +72,8 @@ main(argc, argv)
tag = NULL;
pri = LOG_NOTICE;
logflags = 0;
- while ((ch = getopt(argc, argv, "f:ip:st:")) != EOF)
+ unsetenv("TZ");
+ while ((ch = getopt(argc, argv, "f:ip:st:")) != -1)
switch((char)ch) {
case 'f': /* file to log */
if (freopen(optarg, "r", stdin) == NULL) {
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
index a11fbc0..9ded00c 100644
--- a/usr.bin/login/Makefile
+++ b/usr.bin/login/Makefile
@@ -1,10 +1,31 @@
-# @(#)Makefile 8.1 (Berkeley) 7/19/93
+# From: @(#)Makefile 8.1 (Berkeley) 7/19/93
+# $Id$
-CFLAGS+=-DKERBEROS
PROG= login
-SRCS= klogin.c login.c
-DPADD= ${LIBUTIL} ${LIBKRB} ${LIBDES}
-LDADD= -lutil -lkrb -ldes
+MAN1= login.1
+MAN5= login.access.5
+SRCS= login.c login_access.c login_fbtab.c
+
+#Uncomment to activate login_auth
+#Warning: requires src/libexec/login_* auth modules
+#LC_AUTH=-DLOGIN_CAP_AUTH
+CFLAGS+=-DSKEY -DLOGIN_ACCESS -DLOGALL -DLOGIN_CAP $(LC_AUTH)
+
+.if defined(KLOGIN_PARANOID)
+CFLAGS+=-DKLOGIN_PARANOID
+.endif
+
+DPADD= ${LIBUTIL} ${LIBSKEY} ${LIBMD} ${LIBCRYPT}
+LDADD= -lutil -lskey -lmd -lcrypt
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && defined(MAKE_EBONES) && !defined(LC_AUTH)
+CFLAGS+=-DKERBEROS
+SRCS+= klogin.c
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+DISTRIBUTION= krb
+.endif
+
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
diff --git a/usr.bin/login/README b/usr.bin/login/README
new file mode 100644
index 0000000..d7c964d
--- /dev/null
+++ b/usr.bin/login/README
@@ -0,0 +1,20 @@
+This login has additional functionalities. They are all based on (part of)
+Wietse Venema's logdaemon package.
+
+
+The following defines can be used:
+1) LOGIN_ACCESS to allow access control on a per tty/user combination
+2) SKEY to allow the use of s/key one time passwords
+3) LOGALL to log all logins
+
+-Guido
+
+This login has some of Berkeley's paranoid/broken (depending on your point
+of view) Kerberos code conditionalized out, so that by default it works like
+klogin does at MIT-LCS. You can define KLOGIN_PARANOID to re-enable this code.
+This define also controls whether a warning message is printed when logging
+into a system with no krb.conf file, which usually means that Kerberos is
+not configured.
+
+-GAWollman
+
diff --git a/usr.bin/login/klogin.c b/usr.bin/login/klogin.c
index 6601a6e..4263786 100644
--- a/usr.bin/login/klogin.c
+++ b/usr.bin/login/klogin.c
@@ -38,7 +38,7 @@ static char sccsid[] = "@(#)klogin.c 8.3 (Berkeley) 4/2/94";
#ifdef KERBEROS
#include <sys/param.h>
#include <sys/syslog.h>
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#include <err.h>
@@ -67,13 +67,19 @@ klogin(pw, instance, localhost, password)
char *instance, *localhost, *password;
{
int kerror;
+ char realm[REALM_SZ], savehost[MAXHOSTNAMELEN];
+ char tkt_location[MAXPATHLEN];
+ char *krb_get_phost();
+ extern int noticketsdontcomplain;
+
+#ifdef KLOGIN_PARANOID
AUTH_DAT authdata;
KTEXT_ST ticket;
struct hostent *hp;
unsigned long faddr;
- char realm[REALM_SZ], savehost[MAXHOSTNAMELEN];
- char tkt_location[MAXPATHLEN];
- char *krb_get_phost();
+
+ noticketsdontcomplain = 0; /* enable warning message */
+#endif
/*
* Root logins don't use Kerberos.
@@ -87,6 +93,8 @@ klogin(pw, instance, localhost, password)
krb_get_lrealm(realm, 0) != KSUCCESS)
return (1);
+ noticketsdontcomplain = 0; /* enable warning message */
+
/*
* get TGT for local realm
* tickets are stored in a file named TKT_ROOT plus uid
@@ -111,6 +119,7 @@ klogin(pw, instance, localhost, password)
}
kerror = krb_get_pw_in_tkt(pw->pw_name, instance,
realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password);
+
/*
* If we got a TGT, get a local "rcmd" ticket and check it so as to
* ensure that we are not talking to a bogus Kerberos server.
@@ -135,6 +144,7 @@ klogin(pw, instance, localhost, password)
(void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost));
savehost[sizeof(savehost)-1] = NULL;
+#ifdef KLOGIN_PARANOID
/*
* if the "VERIFY_SERVICE" doesn't exist in the KDC for this host,
* still allow login with tickets, but log the error condition.
@@ -186,5 +196,9 @@ klogin(pw, instance, localhost, password)
krb_err_txt[kerror]);
dest_tkt();
return (1);
+#else
+ notickets = 0;
+ return (0);
+#endif
}
#endif
diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1
index 6c78b23..e0a4f02 100644
--- a/usr.bin/login/login.1
+++ b/usr.bin/login/login.1
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)login.1 8.2 (Berkeley) 5/5/94
+.\" @(#)login.1 8.1 (Berkeley) 6/9/93
+.\" $Id$
.\"
-.Dd May 5, 1994
+.Dd June 9, 1993
.Dt LOGIN 1
.Os BSD 4
.Sh NAME
@@ -83,11 +84,27 @@ If the file
.Pa /etc/nologin
exists,
.Nm login
-dislays its contents to the user and exits.
+displays its contents to the user and exits.
This is used by
.Xr shutdown 8
to prevent users from logging in when the system is about to go down.
.Pp
+If the file
+.Pa /etc/login.access
+exists,
+.Nm login
+checks to see if the user and host pair are specifically allowed or denied
+access.
+Login access may also be controlled via the login class, which provides
+allow and deny records based on time, tty and remote host name.
+.Pp
+If the file
+.Pa /etc/fbtab
+exists,
+.Nm login
+changes the protection and ownership of certain devices specified in this
+file.
+.Pp
Immediately after logging a user in,
.Nm login
displays the system copyright notice, the date and time the user last
@@ -109,6 +126,12 @@ Login enters information into the environment (see
specifying the user's home directory (HOME), command interpreter (SHELL),
search path (PATH), terminal type (TERM) and user name (both LOGNAME and
USER).
+Other environment variables may be set due to entries in the login
+class capabilities database, for the login class assigned in the
+user's system passwd record.
+The login class also controls the maximum and current process resource
+limits granted to a login, process priorities and many other aspects of
+a user's login environment.
.Pp
The standard shells,
.Xr csh 1
@@ -119,14 +142,18 @@ do not fork before executing the
utility.
.Sh FILES
.Bl -tag -width /var/mail/userXXX -compact
+.It Pa /etc/fbtab
+changes device protections
+.It Pa /etc/login.conf
+login class capabilities database
.It Pa /etc/motd
message-of-the-day
.It Pa /etc/nologin
disallows logins
+.It Pa /etc/login.access
+login access control table
.It Pa /var/run/utmp
current logins
-.It Pa /var/log/lastlog
-last login account records
.It Pa /var/log/wtmp
login account records
.It Pa /var/mail/user
@@ -139,8 +166,12 @@ makes login quieter
.Xr passwd 1 ,
.Xr rlogin 1 ,
.Xr getpass 3 ,
+.Xr fbtab 5 ,
+.Xr login.access 5 ,
+.Xr login.conf 5 ,
.Xr utmp 5 ,
.Xr environ 7 ,
+.Xr nologin 8
.Sh HISTORY
A
.Nm login
diff --git a/usr.bin/login/login.access.5 b/usr.bin/login/login.access.5
new file mode 100644
index 0000000..201c185
--- /dev/null
+++ b/usr.bin/login/login.access.5
@@ -0,0 +1,50 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt LOGIN.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm login.access
+.Nd Login access control table
+.Sh DESCRIPTION
+The
+.Nm login.access
+file specifies (user, host) combinations and/or (user, tty)
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the
+.Nm login.access
+is scanned for the first entry that
+matches the (user, host) combination, or, in case of non-networked
+logins, the first entry that matches the (user, tty) combination. The
+permissions field of that table entry determines whether the login will
+be accepted or refused.
+.Pp
+Each line of the login access control table has three fields separated by a
+":" character: permission : users : origins
+
+The first field should be a "+" (access granted) or "-" (access denied)
+character. The second field should be a list of one or more login names,
+group names, or ALL (always matches). The third field should be a list
+of one or more tty names (for non-networked logins), host names, domain
+names (begin with "."), host addresses, internet network numbers (end
+with "."), ALL (always matches) or LOCAL (matches any string that does
+not contain a "." character). If you run NIS you can use @netgroupname
+in host or user patterns.
+
+The EXCEPT operator makes it possible to write very compact rules.
+
+The group file is searched only when a name does not match that of the
+logged-in user. Only groups are matched in which users are explicitly
+listed: the program does not look at a user's primary group id value.
+.Sh FILES
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+The
+.Nm login.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr login 1
+.Sh AUTHOR
+Guido van Rooij
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
index ef75733..77edbbf 100644
--- a/usr.bin/login/login.c
+++ b/usr.bin/login/login.c
@@ -31,11 +31,11 @@
* SUCH DAMAGE.
*/
-#ifndef lint
+#if 0
static char copyright[] =
"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
+#endif
#ifndef lint
static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
@@ -47,15 +47,19 @@ static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
*/
+#include <sys/copyright.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <grp.h>
+#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
@@ -64,22 +68,46 @@ static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
#include <string.h>
#include <syslog.h>
#include <ttyent.h>
-#include <tzfile.h>
#include <unistd.h>
#include <utmp.h>
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#else /* Undef AUTH as well */
+#undef LOGIN_CAP_AUTH
+#endif
+
+/*
+ * If LOGIN_CAP_AUTH is activated:
+ * kerberose & skey logins are runtime selected via login
+ * login_getstyle() and authentication types for login classes
+ * The actual login itself is handled via /usr/libexec/login_<style>
+ * Valid styles are determined by the auth-type=style,style entries
+ * in the login class.
+ */
+#ifdef LOGIN_CAP_AUTH
+#undef KERBEROS
+#undef SKEY
+#endif /* LOGIN_CAP_AUTH */
+
+#ifdef SKEY
+#include <skey.h>
+#endif /* SKEY */
+
#include "pathnames.h"
void badlogin __P((char *));
void checknologin __P((void));
void dolastlog __P((int));
void getloginname __P((void));
-void motd __P((void));
+void motd __P((char *));
int rootterm __P((char *));
void sigint __P((int));
void sleepexit __P((int));
+void refused __P((char *,char *,int));
char *stypeof __P((char *));
void timedout __P((int));
+void login_fbtab __P((char *, uid_t, gid_t));
#ifdef KERBEROS
int klogin __P((struct passwd *, char *, char *, char *));
#endif
@@ -87,6 +115,8 @@ int klogin __P((struct passwd *, char *, char *, char *));
extern void login __P((struct utmp *));
#define TTYGRPNAME "tty" /* name of group to own ttys */
+#define DEFAULT_BACKOFF 3
+#define DEFAULT_RETRIES 10
/*
* This bounds the time given to login. Not a define so it can
@@ -96,6 +126,7 @@ u_int timeout = 300;
#ifdef KERBEROS
int notickets = 1;
+int noticketsdontcomplain = 1;
char *instance;
char *krbtkfile_env;
int authok;
@@ -103,7 +134,8 @@ int authok;
struct passwd *pwd;
int failures;
-char term[64], *envinit[1], *hostname, *username, *tty;
+char *term, *envinit[1], *hostname, *username, *tty;
+char full_hostname[MAXHOSTNAMELEN];
int
main(argc, argv)
@@ -115,11 +147,27 @@ main(argc, argv)
struct stat st;
struct timeval tp;
struct utmp utmp;
+ int rootok, retries, backoff;
int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
+ int changepass;
+ time_t warntime;
uid_t uid;
- char *domain, *p, *salt, *ttyn;
+ char *domain, *p, *ep, *salt, *ttyn;
char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
char localhost[MAXHOSTNAMELEN];
+ char *shell = NULL;
+#ifdef LOGIN_CAP
+ login_cap_t *lc = NULL;
+#ifdef LOGIN_CAP_AUTH
+ char *style, *authtype;
+ char *auth_method = NULL;
+ char *instance = NULL;
+ int authok;
+#endif /* LOGIN_CAP_AUTH */
+#endif /* LOGIN_CAP */
+#ifdef SKEY
+ int permit_passwd = 0;
+#endif /* SKEY */
(void)signal(SIGALRM, timedout);
(void)alarm(timeout);
@@ -135,7 +183,9 @@ main(argc, argv)
* -h is used by other servers to pass the name of the remote
* host to login so that it may be placed in utmp and wtmp
*/
+ *full_hostname = '\0';
domain = NULL;
+ term = NULL;
if (gethostname(localhost, sizeof(localhost)) < 0)
syslog(LOG_ERR, "couldn't get local hostname: %m");
else
@@ -143,7 +193,7 @@ main(argc, argv)
fflag = hflag = pflag = 0;
uid = getuid();
- while ((ch = getopt(argc, argv, "fh:p")) != EOF)
+ while ((ch = getopt(argc, argv, "fh:p")) != -1)
switch (ch) {
case 'f':
fflag = 1;
@@ -152,9 +202,21 @@ main(argc, argv)
if (uid)
errx(1, "-h option: %s", strerror(EPERM));
hflag = 1;
+ strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
if (domain && (p = strchr(optarg, '.')) &&
strcasecmp(p, domain) == 0)
*p = 0;
+ if (strlen(optarg) > UT_HOSTSIZE) {
+ struct hostent *hp = gethostbyname(optarg);
+
+ if (hp != NULL) {
+ struct in_addr in;
+
+ memmove(&in, hp->h_addr, sizeof(in));
+ optarg = strdup(inet_ntoa(in));
+ } else
+ optarg = "invalid hostname";
+ }
hostname = optarg;
break;
case 'p':
@@ -185,25 +247,64 @@ main(argc, argv)
(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
ttyn = tname;
}
- if (tty = strrchr(ttyn, '/'))
+ if ((tty = strrchr(ttyn, '/')) != NULL)
++tty;
else
tty = ttyn;
+#ifdef LOGIN_CAP_AUTH
+ authtype = hostname ? "rlogin" : "login";
+#endif
+#ifdef LOGIN_CAP
+ /*
+ * Get "login-retries" & "login-backoff" from default class
+ */
+ lc = login_getclass(NULL);
+ retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES);
+ backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF);
+ login_close(lc);
+ lc = NULL;
+#else
+ retries = DEFAULT_RETRIES;
+ backoff = DEFAULT_BACKOFF;
+#endif
+
for (cnt = 0;; ask = 1) {
if (ask) {
fflag = 0;
getloginname();
}
rootlogin = 0;
-#ifdef KERBEROS
+ rootok = rootterm(tty); /* Default (auth may change) */
+#ifdef LOGIN_CAP_AUTH
+ authok = 0;
+ if (auth_method = strchr(username, ':')) {
+ *auth_method = '\0';
+ auth_method++;
+ if (*auth_method == '\0')
+ auth_method = NULL;
+ }
+ /*
+ * We need to do this regardless of whether
+ * kerberos is available.
+ */
if ((instance = strchr(username, '.')) != NULL) {
if (strncmp(instance, ".root", 5) == 0)
rootlogin = 1;
*instance++ = '\0';
} else
instance = "";
-#endif
+#else /* !LOGIN_CAP_AUTH */
+#ifdef KERBEROS
+ if ((instance = strchr(username, '.')) != NULL) {
+ if (strncmp(instance, ".root", 5) == 0)
+ rootlogin = 1;
+ *instance++ = '\0';
+ } else
+ instance = "";
+#endif /* KERBEROS */
+#endif /* LOGIN_CAP_AUTH */
+
if (strlen(username) > UT_NAMESIZE)
username[UT_NAMESIZE] = '\0';
@@ -219,75 +320,190 @@ main(argc, argv)
}
(void)strcpy(tbuf, username);
- if (pwd = getpwnam(username))
+ if ((pwd = getpwnam(username)) != NULL)
salt = pwd->pw_passwd;
else
salt = "xx";
+#ifdef LOGIN_CAP
+ /*
+ * Establish the class now, before we might goto
+ * within the next block. pwd can be NULL since it
+ * falls back to the "default" class if it is.
+ */
+ lc = login_getpwclass(pwd);
+#endif /* LOGIN_CAP */
+
/*
* if we have a valid account name, and it doesn't have a
* password, or the -f option was specified and the caller
* is root or the caller isn't changing their uid, don't
* authenticate.
*/
- if (pwd && (*pwd->pw_passwd == '\0' ||
- fflag && (uid == 0 || uid == pwd->pw_uid)))
- break;
+ rval = 1;
+ if (pwd != NULL) {
+ if (pwd->pw_uid == 0)
+ rootlogin = 1;
+
+ if (fflag && (uid == (uid_t)0 ||
+ uid == (uid_t)pwd->pw_uid)) {
+ /* already authenticated */
+ break;
+ } else if (pwd->pw_passwd[0] == '\0') {
+ if (!rootlogin || rootok) {
+ /* pretend password okay */
+ rval = 0;
+ goto ttycheck;
+ }
+ }
+ }
+
fflag = 0;
- if (pwd && pwd->pw_uid == 0)
- rootlogin = 1;
(void)setpriority(PRIO_PROCESS, 0, -4);
+#ifdef LOGIN_CAP_AUTH
+ /*
+ * This hands off authorization to an authorization program,
+ * depending on the styles available for the "auth-login",
+ * auth-rlogin (or default) authorization styles.
+ * We do this regardless of whether an account exists so that
+ * the remote user cannot tell a "real" from an invented
+ * account name. If we don't have an account we just fall
+ * back to the first method for the "default" class.
+ */
+ if (!(style = login_getstyle(lc, auth_method, authtype))) {
+
+ /*
+ * No available authorization method
+ */
+ rval = 1;
+ (void)printf("No auth method available for %s.\n",
+ authtype);
+ } else {
+
+ /*
+ * Put back the kerberos instance, if any was given.
+ * Don't worry about the non-kerberos case here, since
+ * if kerberos is not available or not selected and an
+ * instance is given at the login prompt, su or rlogin -l,
+ * then anything else should fail as well.
+ */
+ if (*instance)
+ *(instance - 1) = '.';
+
+ rval = authenticate(username,
+ lc ? lc->lc_class : "default",
+ style, authtype);
+ /* Junk it again */
+ if (*instance)
+ *(instance - 1) = '\0';
+ }
+
+ if (!rval) {
+ char * approvp;
+
+ /*
+ * If authentication succeeds, run any approval
+ * program, if applicable for this class.
+ */
+ approvep = login_getcapstr(lc, "approve", NULL, NULL);
+ rval = 1; /* Assume bad login again */
+
+ if (approvep==NULL ||
+ auth_script(approvep, approvep, username,
+ lc->lc_class, 0) == 0) {
+ int r;
+
+ r = auth_scan(AUTH_OKAY);
+ /*
+ * See what the authorize program says
+ */
+ if (r != AUTH_NONE) {
+ rval = 0;
+
+ if (!rootok && (r & AUTH_ROOTOKAY))
+ rootok = 1; /* root approved */
+ else
+ rootlogin = 0;
+
+ if (!authok && (r & AUTH_SECURE))
+ authok = 1; /* secure */
+ }
+ }
+ }
+#else /* !LOGIN_CAP_AUTH */
+#ifdef SKEY
+ permit_passwd = skeyaccess(username, tty,
+ hostname ? full_hostname : NULL,
+ NULL);
+ p = skey_getpass("Password:", pwd, permit_passwd);
+ ep = skey_crypt(p, salt, pwd, permit_passwd);
+#else /* !SKEY */
p = getpass("Password:");
+ ep = crypt(p, salt);
+#endif/* SKEY */
if (pwd) {
#ifdef KERBEROS
+#ifdef SKEY
+ /*
+ * Do not allow user to type in kerberos password
+ * over the net (actually, this is ok for encrypted
+ * links, but we have no way of determining if the
+ * link is encrypted.
+ */
+ if (!permit_passwd) {
+ rval = 1; /* failed */
+ } else
+#endif /* SKEY */
rval = klogin(pwd, instance, localhost, p);
if (rval != 0 && rootlogin && pwd->pw_uid != 0)
rootlogin = 0;
if (rval == 0)
- authok = 1;
- else if (rval == 1)
- rval = strcmp(crypt(p, salt), pwd->pw_passwd);
-#else
- rval = strcmp(crypt(p, salt), pwd->pw_passwd);
-#endif
+ authok = 1; /* kerberos authenticated ok */
+ else if (rval == 1) /* fallback to unix passwd */
+ rval = strcmp(ep, pwd->pw_passwd);
+#else /* !KERBEROS */
+ rval = strcmp(ep, pwd->pw_passwd);
+#endif /* KERBEROS */
}
+
+ /* clear entered password */
memset(p, 0, strlen(p));
+#endif /* LOGIN_CAP_AUTH */
(void)setpriority(PRIO_PROCESS, 0, 0);
+#ifdef LOGIN_CAP_AUTH
+ if (rval)
+ auth_rmfiles();
+#endif
+ ttycheck:
/*
* If trying to log in as root without Kerberos,
* but with insecure terminal, refuse the login attempt.
*/
-#ifdef KERBEROS
- if (authok == 0)
+ if (pwd && !rval) {
+#if defined(KERBEROS) || defined(LOGIN_CAP_AUTH)
+ if (authok == 0 && rootlogin && !rootok)
+#else
+ if (rootlogin && !rootok)
#endif
- if (pwd && rootlogin && !rootterm(tty)) {
- (void)fprintf(stderr,
- "%s login refused on this terminal.\n",
- pwd->pw_name);
- if (hostname)
- syslog(LOG_NOTICE,
- "LOGIN %s REFUSED FROM %s ON TTY %s",
- pwd->pw_name, hostname, tty);
- else
- syslog(LOG_NOTICE,
- "LOGIN %s REFUSED ON TTY %s",
- pwd->pw_name, tty);
- continue;
+ refused(NULL, "NOROOT", 0);
+ else /* valid password & authenticated */
+ break;
}
- if (pwd && !rval)
- break;
-
(void)printf("Login incorrect\n");
failures++;
- /* we allow 10 tries, but after 3 we start backing off */
- if (++cnt > 3) {
- if (cnt >= 10) {
+
+ /*
+ * we allow up to 'retry' (10) tries,
+ * but after 'backoff' (3) we start backing off
+ */
+ if (++cnt > backoff) {
+ if (cnt >= retries) {
badlogin(username);
sleepexit(1);
}
@@ -301,37 +517,113 @@ main(argc, argv)
endpwent();
/* if user not super-user, check for disabled logins */
+#ifdef LOGIN_CAP
+ if (!rootlogin)
+ auth_checknologin(lc);
+#else
if (!rootlogin)
checknologin();
+#endif
- if (chdir(pwd->pw_dir) < 0) {
- (void)printf("No home directory %s!\n", pwd->pw_dir);
- if (chdir("/"))
- exit(0);
+#ifdef LOGIN_CAP
+ quietlog = login_getcapbool(lc, "hushlogin", 0);
+#else
+ quietlog = 0;
+#endif
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+#ifdef LOGIN_CAP
+ if (login_getcapbool(lc, "requirehome", 0))
+ refused("Home directory not available", "HOMEDIR", 1);
+#endif
+ if (chdir("/") < 0)
+ refused("Cannot find root directory", "ROOTDIR", 1);
pwd->pw_dir = "/";
- (void)printf("Logging in with home = \"/\".\n");
+ if (!quietlog || *pwd->pw_dir)
+ printf("No home directory.\nLogging in with home = \"/\".\n");
}
-
- quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
+ if (!quietlog)
+ quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
if (pwd->pw_change || pwd->pw_expire)
(void)gettimeofday(&tp, (struct timezone *)NULL);
- if (pwd->pw_change)
+
+#define DEFAULT_WARN (2L * 7L & 86400L) /* Two weeks */
+
+#ifdef LOGIN_CAP
+ warntime = login_getcaptime(lc, "warnpassword",
+ DEFAULT_WARN, DEFAULT_WARN);
+#else
+ warntime = DEFAULT_WARN;
+#endif
+
+ changepass=0;
+ if (pwd->pw_change) {
if (tp.tv_sec >= pwd->pw_change) {
(void)printf("Sorry -- your password has expired.\n");
- sleepexit(1);
- } else if (pwd->pw_change - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
- (void)printf("Warning: your password expires on %s",
- ctime(&pwd->pw_change));
- if (pwd->pw_expire)
+ changepass=1;
+ syslog(LOG_INFO,
+ "%s Password expired - forcing change",
+ pwd->pw_name);
+ } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog)
+ (void)printf("Warning: your password expires on %s",
+ ctime(&pwd->pw_change));
+ }
+
+#ifdef LOGIN_CAP
+ warntime = login_getcaptime(lc, "warnexpire",
+ DEFAULT_WARN, DEFAULT_WARN);
+#else
+ warntime = DEFAULT_WARN;
+#endif
+
+ if (pwd->pw_expire) {
if (tp.tv_sec >= pwd->pw_expire) {
- (void)printf("Sorry -- your account has expired.\n");
- sleepexit(1);
- } else if (pwd->pw_expire - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
- (void)printf("Warning: your account expires on %s",
- ctime(&pwd->pw_expire));
+ refused("Sorry -- your account has expired",
+ "EXPIRED", 1);
+ } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
+ (void)printf("Warning: your account expires on %s",
+ ctime(&pwd->pw_expire));
+ }
+
+#ifdef LOGIN_CAP
+ if (lc != NULL) {
+ if (hostname) {
+ struct hostent *hp = gethostbyname(full_hostname);
+
+ if (hp == NULL)
+ optarg = NULL;
+ else {
+ struct in_addr in;
+ memmove(&in, hp->h_addr, sizeof(in));
+ optarg = strdup(inet_ntoa(in));
+ }
+ if (!auth_hostok(lc, full_hostname, optarg))
+ refused("Permission denied", "HOST", 1);
+ }
+
+ if (!auth_ttyok(lc, tty))
+ refused("Permission denied", "TTY", 1);
+
+ if (!auth_timeok(lc, time(NULL)))
+ refused("Logins not available right now", "TIME", 1);
+ }
+ shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
+#else /* !LOGIN_CAP */
+ shell=pwd->pw_shell;
+#endif /* LOGIN_CAP */
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = _PATH_BSHELL;
+ if (*shell == '\0') /* Not overridden */
+ shell = pwd->pw_shell;
+ if ((shell = strdup(shell)) == NULL) {
+ syslog(LOG_NOTICE, "memory allocation error");
+ sleepexit(1);
+ }
+
+#ifdef LOGIN_ACCESS
+ if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
+ refused("Permission denied", "ACCESS", 1);
+#endif /* LOGIN_ACCESS */
/* Nothing else left to fail -- really log in. */
memset((void *)&utmp, 0, sizeof(utmp));
@@ -344,87 +636,177 @@ main(argc, argv)
dolastlog(quietlog);
+ /*
+ * Set device protections, depending on what terminal the
+ * user is logged in. This feature is used on Suns to give
+ * console users better privacy.
+ */
+ login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
+
(void)chown(ttyn, pwd->pw_uid,
- (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
- (void)setgid(pwd->pw_gid);
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
- initgroups(username, pwd->pw_gid);
+ /*
+ * Preserve TERM if it happens to be already set.
+ */
+ if ((term = getenv("TERM")) != NULL)
+ term = strdup(term);
- if (*pwd->pw_shell == '\0')
- pwd->pw_shell = _PATH_BSHELL;
+ /*
+ * Exclude cons/vt/ptys only, assume dialup otherwise
+ * TODO: Make dialup tty determination a library call
+ * for consistency (finger etc.)
+ */
+ if (hostname==NULL && isdialuptty(tty))
+ syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
- /* Destroy environment unless user has requested its preservation. */
- if (!pflag)
- environ = envinit;
- (void)setenv("HOME", pwd->pw_dir, 1);
- (void)setenv("SHELL", pwd->pw_shell, 1);
- if (term[0] == '\0')
- (void)strncpy(term, stypeof(tty), sizeof(term));
- (void)setenv("TERM", term, 0);
- (void)setenv("LOGNAME", pwd->pw_name, 1);
- (void)setenv("USER", pwd->pw_name, 1);
- (void)setenv("PATH", _PATH_DEFPATH, 0);
#ifdef KERBEROS
- if (krbtkfile_env)
- (void)setenv("KRBTKFILE", krbtkfile_env, 1);
+ if (!quietlog && notickets == 1 && !noticketsdontcomplain)
+ (void)printf("Warning: no Kerberos tickets issued.\n");
#endif
- if (tty[sizeof("tty")-1] == 'd')
- syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+#ifdef LOGALL
+ /*
+ * Syslog each successful login, so we don't have to watch hundreds
+ * of wtmp or lastlogin files.
+ */
+ if (hostname)
+ syslog(LOG_INFO, "login from %s on %s as %s",
+ full_hostname, tty, pwd->pw_name);
+ else
+ syslog(LOG_INFO, "login on %s as %s",
+ tty, pwd->pw_name);
+#endif
- /* If fflag is on, assume caller/authenticator has logged root login. */
+ /*
+ * If fflag is on, assume caller/authenticator has logged root login.
+ */
if (rootlogin && fflag == 0)
+ {
if (hostname)
syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
- username, tty, hostname);
+ username, tty, full_hostname);
else
- syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
+ username, tty);
+ }
+
+ /*
+ * Destroy environment unless user has requested its preservation.
+ * We need to do this before setusercontext() because that may
+ * set or reset some environment variables.
+ */
+ if (!pflag)
+ environ = envinit;
+
+ /*
+ * We don't need to be root anymore, so
+ * set the user and session context
+ */
+#ifdef LOGIN_CAP
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ exit(1);
+ }
+#else
+ if (setlogin(pwd->pw_name) < 0)
+ syslog(LOG_ERR, "setlogin() failure: %m");
+
+ (void)setgid(pwd->pw_gid);
+ initgroups(username, pwd->pw_gid);
+ (void)setuid(rootlogin ? 0 : pwd->pw_uid);
+#endif
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ if (term != NULL && *term != '\0')
+ (void)setenv("TERM", term, 1); /* Preset overrides */
+ else {
+ (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */
+ }
+ (void)setenv("LOGNAME", pwd->pw_name, 1);
+ (void)setenv("USER", pwd->pw_name, 1);
+ (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
#ifdef KERBEROS
- if (!quietlog && notickets == 1)
- (void)printf("Warning: no Kerberos tickets issued.\n");
+ if (krbtkfile_env)
+ (void)setenv("KRBTKFILE", krbtkfile_env, 1);
+#endif
+#if LOGIN_CAP_AUTH
+ auth_env();
#endif
+#ifdef LOGIN_CAP
if (!quietlog) {
- (void)printf("%s\n\t%s %s\n\n",
- "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
- "The Regents of the University of California. ",
- "All rights reserved.");
- motd();
- (void)snprintf(tbuf,
- sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
+ char *cw;
+
+ cw = login_getcapstr(lc, "copyright", NULL, NULL);
+ if (cw != NULL && access(cw, F_OK) == 0)
+ motd(cw);
+ else
+ (void)printf("%s\n\t%s %s\n",
+ "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
+ "The Regents of the University of California. ",
+ "All rights reserved.");
+
+ (void)printf("\n");
+
+ cw = login_getcapstr(lc, "welcome", NULL, NULL);
+ if (cw == NULL || access(cw, F_OK) != 0)
+ cw = _PATH_MOTDFILE;
+ motd(cw);
+
+ cw = getenv("MAIL"); /* $MAIL may have been set by class */
+ if (cw != NULL) {
+ strncpy(tbuf, cw, sizeof(tbuf));
+ tbuf[sizeof(tbuf)-1] = '\0';
+ } else
+ snprintf(tbuf, sizeof(tbuf), "%s/%s",
+ _PATH_MAILDIR, pwd->pw_name);
+#else
+ if (!quietlog) {
+ (void)printf("%s\n\t%s %s\n",
+ "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
+ "The Regents of the University of California. ",
+ "All rights reserved.");
+ motd(_PATH_MOTDFILE);
+ snprintf(tbuf, sizeof(tbuf), "%s/%s",
+ _PATH_MAILDIR, pwd->pw_name);
+#endif
if (stat(tbuf, &st) == 0 && st.st_size != 0)
(void)printf("You have %smail.\n",
- (st.st_mtime > st.st_atime) ? "new " : "");
+ (st.st_mtime > st.st_atime) ? "new " : "");
}
+#ifdef LOGIN_CAP
+ login_close(lc);
+#endif
+
(void)signal(SIGALRM, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGTSTP, SIG_IGN);
+ if (changepass) {
+ if (system(_PATH_CHPASS) != 0)
+ sleepexit(1);
+ }
+
+ /*
+ * Login shells have a leading '-' in front of argv[0]
+ */
tbuf[0] = '-';
- (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
- p + 1 : pwd->pw_shell);
+ (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell);
- if (setlogin(pwd->pw_name) < 0)
- syslog(LOG_ERR, "setlogin() failure: %m");
+ execlp(shell, tbuf, 0);
+ err(1, "%s", shell);
+}
- /* Discard permissions last so can't get killed and drop core. */
- if (rootlogin)
- (void) setuid(0);
- else
- (void) setuid(pwd->pw_uid);
- execlp(pwd->pw_shell, tbuf, 0);
- err(1, "%s", pwd->pw_shell);
-}
+/*
+ * Allow for authentication style and/or kerberos instance
+ * */
-#ifdef KERBEROS
-#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
-#else
-#define NBUFSIZ (UT_NAMESIZE + 1)
-#endif
+#define NBUFSIZ UT_NAMESIZE + 64
void
getloginname()
@@ -464,44 +846,44 @@ rootterm(ttyn)
return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
}
-jmp_buf motdinterrupt;
+volatile int motdinterrupt;
+/* ARGSUSED */
void
-motd()
+sigint(signo)
+ int signo;
+{
+ motdinterrupt = 1;
+}
+
+void
+motd(motdfile)
+ char *motdfile;
{
int fd, nchars;
sig_t oldint;
- char tbuf[8192];
+ char tbuf[256];
- if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
+ if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
return;
+ motdinterrupt = 0;
oldint = signal(SIGINT, sigint);
- if (setjmp(motdinterrupt) == 0)
- while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
- (void)write(fileno(stdout), tbuf, nchars);
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
+ (void)write(fileno(stdout), tbuf, nchars);
(void)signal(SIGINT, oldint);
(void)close(fd);
}
/* ARGSUSED */
void
-sigint(signo)
- int signo;
-{
-
- longjmp(motdinterrupt, 1);
-}
-
-/* ARGSUSED */
-void
timedout(signo)
int signo;
{
-
(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
exit(0);
}
+#ifndef LOGIN_CAP
void
checknologin()
{
@@ -514,6 +896,7 @@ checknologin()
sleepexit(0);
}
}
+#endif
void
dolastlog(quiet)
@@ -559,10 +942,10 @@ badlogin(name)
return;
if (hostname) {
syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
- failures, failures > 1 ? "S" : "", hostname);
+ failures, failures > 1 ? "S" : "", full_hostname);
syslog(LOG_AUTHPRIV|LOG_NOTICE,
"%d LOGIN FAILURE%s FROM %s, %s",
- failures, failures > 1 ? "S" : "", hostname, name);
+ failures, failures > 1 ? "S" : "", full_hostname, name);
} else {
syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
failures, failures > 1 ? "S" : "", tty);
@@ -579,12 +962,32 @@ char *
stypeof(ttyid)
char *ttyid;
{
+
struct ttyent *t;
return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
}
void
+refused(msg, rtype, lout)
+ char *msg;
+ char *rtype;
+ int lout;
+{
+
+ if (msg != NULL)
+ printf("%s.\n", msg);
+ if (hostname)
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
+ pwd->pw_name, rtype, full_hostname, tty);
+ else
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
+ pwd->pw_name, rtype, tty);
+ if (lout)
+ sleepexit(1);
+}
+
+void
sleepexit(eval)
int eval;
{
diff --git a/usr.bin/login/login_access.c b/usr.bin/login/login_access.c
new file mode 100644
index 0000000..b5003c7
--- /dev/null
+++ b/usr.bin/login/login_access.c
@@ -0,0 +1,239 @@
+ /*
+ * This module implements a simple but effective form of login access
+ * control based on login names and on host (or domain) names, internet
+ * addresses (or network numbers), or on terminal line names in case of
+ * non-networked logins. Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifdef LOGIN_ACCESS
+#ifndef lint
+static char sccsid[] = "%Z% %M% %I% %E% %U%";
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pathnames.h"
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":"; /* field separator */
+static char sep[] = ", \t"; /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES 1
+#define NO 0
+
+static int list_match();
+static int user_match();
+static int from_match();
+static int string_match();
+
+/* login_access - match username/group and host/tty with access control file */
+
+int
+login_access(user, from)
+char *user;
+char *from;
+{
+ FILE *fp;
+ char line[BUFSIZ];
+ char *perm; /* becomes permission field */
+ char *users; /* becomes list of login names */
+ char *froms; /* becomes list of terminals or hosts */
+ int match = NO;
+ int end;
+ int lineno = 0; /* for diagnostics */
+
+ /*
+ * Process the table one line at a time and stop at the first match.
+ * Blank lines and lines that begin with a '#' character are ignored.
+ * Non-comment lines are broken at the ':' character. All fields are
+ * mandatory. The first field should be a "+" or "-" character. A
+ * non-existing table means no access control.
+ */
+
+ if ((fp = fopen(_PATH_LOGACCESS, "r")) != NULL) {
+ while (!match && fgets(line, sizeof(line), fp)) {
+ lineno++;
+ if (line[end = strlen(line) - 1] != '\n') {
+ syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+ _PATH_LOGACCESS, lineno);
+ continue;
+ }
+ if (line[0] == '#')
+ continue; /* comment line */
+ while (end > 0 && isspace(line[end - 1]))
+ end--;
+ line[end] = 0; /* strip trailing whitespace */
+ if (line[0] == 0) /* skip blank lines */
+ continue;
+ if (!(perm = strtok(line, fs))
+ || !(users = strtok((char *) 0, fs))
+ || !(froms = strtok((char *) 0, fs))
+ || strtok((char *) 0, fs)) {
+ syslog(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ if (perm[0] != '+' && perm[0] != '-') {
+ syslog(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ match = (list_match(froms, from, from_match)
+ && list_match(users, user, user_match));
+ }
+ (void) fclose(fp);
+ } else if (errno != ENOENT) {
+ syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS);
+ }
+ return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int list_match(list, item, match_fn)
+char *list;
+char *item;
+int (*match_fn) ();
+{
+ char *tok;
+ int match = NO;
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+ if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ break;
+ if ((match = (*match_fn)(tok, item)) != NULL) /* YES */
+ break;
+ }
+ /* Process exceptions to matches. */
+
+ if (match != NO) {
+ while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+ /* VOID */ ;
+ if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+ return (match);
+ }
+ return (NO);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int netgroup_match(group, machine, user)
+gid_t group;
+char *machine;
+char *user;
+{
+#ifdef NIS
+ static char *mydomain = 0;
+
+ if (mydomain == 0)
+ yp_get_default_domain(&mydomain);
+ return (innetgr(group, machine, user, mydomain));
+#else
+ syslog(LOG_ERR, "NIS netgroup support not configured");
+ return 0;
+#endif
+}
+
+/* user_match - match a username against one token */
+
+static int user_match(tok, string)
+char *tok;
+char *string;
+{
+ struct group *group;
+ int i;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the username, or if
+ * the token is a group that contains the username.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if ((group = getgrnam(tok)) != NULL) {/* try group membership */
+ for (i = 0; group->gr_mem[i]; i++)
+ if (strcasecmp(string, group->gr_mem[i]) == 0)
+ return (YES);
+ }
+ return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int from_match(tok, string)
+char *tok;
+char *string;
+{
+ int tok_len;
+ int str_len;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds. Return
+ * YES if the token fully matches the string. If the token is a domain
+ * name, return YES if it matches the last fields of the string. If the
+ * token has the magic value "LOCAL", return YES if the string does not
+ * contain a "." character. If the token is a network number, return YES
+ * if it matches the head of the string.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, string, (char *) 0));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return (YES);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == 0)
+ return (YES);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+ && strncmp(tok, string, tok_len) == 0) {
+ return (YES);
+ }
+ return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int string_match(tok, string)
+char *tok;
+char *string;
+{
+
+ /*
+ * If the token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the string.
+ */
+
+ if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
+ return (YES);
+ } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+ return (YES);
+ }
+ return (NO);
+}
+#endif /* LOGIN_ACCES */
diff --git a/usr.bin/login/login_fbtab.c b/usr.bin/login/login_fbtab.c
new file mode 100644
index 0000000..37cfe7a
--- /dev/null
+++ b/usr.bin/login/login_fbtab.c
@@ -0,0 +1,153 @@
+/************************************************************************
+* Copyright 1995 by Wietse Venema. All rights reserved.
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+/*
+ SYNOPSIS
+ void login_fbtab(tty, uid, gid)
+ char *tty;
+ uid_t uid;
+ gid_t gid;
+
+ DESCRIPTION
+ This module implements device security as described in the
+ SunOS 4.1.x fbtab(5) and SunOS 5.x logindevperm(4) manual
+ pages. The program first looks for /etc/fbtab. If that file
+ cannot be opened it attempts to process /etc/logindevperm.
+ We expect entries with the folowing format:
+
+ Comments start with a # and extend to the end of the line.
+
+ Blank lines or lines with only a comment are ignored.
+
+ All other lines consist of three fields delimited by
+ whitespace: a login device (/dev/console), an octal
+ permission number (0600), and a ":"-delimited list of
+ devices (/dev/kbd:/dev/mouse). All device names are
+ absolute paths. A path that ends in "/*" refers to all
+ directory entries except "." and "..".
+
+ If the tty argument (relative path) matches a login device
+ name (absolute path), the permissions of the devices in the
+ ":"-delimited list are set as specified in the second
+ field, and their ownership is changed to that of the uid
+ and gid arguments.
+
+ DIAGNOSTICS
+ Problems are reported via the syslog daemon with severity
+ LOG_ERR.
+
+ BUGS
+ This module uses strtok(3), which may cause conflicts with other
+ uses of that same routine.
+
+ AUTHOR
+ Wietse Venema (wietse@wzv.win.tue.nl)
+ Eindhoven University of Technology
+ The Netherlands
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include "pathnames.h"
+
+void login_protect __P((char *, char *, int, uid_t, gid_t));
+void login_fbtab __P((char *tty, uid_t uid, gid_t gid));
+
+#define WSPACE " \t\n"
+
+/* login_fbtab - apply protections specified in /etc/fbtab or logindevperm */
+
+void
+login_fbtab(tty, uid, gid)
+char *tty;
+uid_t uid;
+gid_t gid;
+{
+ FILE *fp;
+ char buf[BUFSIZ];
+ char *devname;
+ char *cp;
+ int prot;
+ char *table;
+
+ if ((fp = fopen(table = _PATH_FBTAB, "r")) == 0
+ && (fp = fopen(table = _PATH_LOGINDEVPERM, "r")) == 0)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (cp = strchr(buf, '#'))
+ *cp = 0; /* strip comment */
+ if ((cp = devname = strtok(buf, WSPACE)) == 0)
+ continue; /* empty or comment */
+ if (strncmp(devname, "/dev/", 5) != 0
+ || (cp = strtok((char *) 0, WSPACE)) == 0
+ || *cp != '0'
+ || sscanf(cp, "%o", &prot) == 0
+ || prot == 0
+ || (prot & 0777) != prot
+ || (cp = strtok((char *) 0, WSPACE)) == 0) {
+ syslog(LOG_ERR, "%s: bad entry: %s", table, cp ? cp : "(null)");
+ continue;
+ }
+ if (strcmp(devname + 5, tty) == 0) {
+ for (cp = strtok(cp, ":"); cp; cp = strtok((char *) 0, ":")) {
+ login_protect(table, cp, prot, uid, gid);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+/* login_protect - protect one device entry */
+
+void
+login_protect(table, path, mask, uid, gid)
+char *table;
+char *path;
+int mask;
+uid_t uid;
+gid_t gid;
+{
+ char buf[BUFSIZ];
+ int pathlen = strlen(path);
+ struct dirent *ent;
+ DIR *dir;
+
+ if (strcmp("/*", path + pathlen - 2) != 0) {
+ if (chmod(path, mask) && errno != ENOENT)
+ syslog(LOG_ERR, "%s: chmod(%s): %m", table, path);
+ if (chown(path, uid, gid) && errno != ENOENT)
+ syslog(LOG_ERR, "%s: chown(%s): %m", table, path);
+ } else {
+ strcpy(buf, path);
+ buf[pathlen - 1] = 0;
+ if ((dir = opendir(buf)) == 0) {
+ syslog(LOG_ERR, "%s: opendir(%s): %m", table, path);
+ } else {
+ while ((ent = readdir(dir)) != 0) {
+ if (strcmp(ent->d_name, ".") != 0
+ && strcmp(ent->d_name, "..") != 0) {
+ strcpy(buf + pathlen - 1, ent->d_name);
+ login_protect(table, buf, mask, uid, gid);
+ }
+ }
+ closedir(dir);
+ }
+ }
+}
diff --git a/usr.bin/login/pathnames.h b/usr.bin/login/pathnames.h
index a9e1a077..9154012 100644
--- a/usr.bin/login/pathnames.h
+++ b/usr.bin/login/pathnames.h
@@ -35,5 +35,9 @@
#include <paths.h>
-#define _PATH_HUSHLOGIN ".hushlogin"
-#define _PATH_MOTDFILE "/etc/motd"
+#define _PATH_HUSHLOGIN ".hushlogin"
+#define _PATH_MOTDFILE "/etc/motd"
+#define _PATH_LOGACCESS "/etc/login.access"
+#define _PATH_FBTAB "/etc/fbtab"
+#define _PATH_LOGINDEVPERM "/etc/logindevperm"
+#define _PATH_CHPASS "/usr/bin/passwd"
diff --git a/usr.bin/logname/logname.1 b/usr.bin/logname/logname.1
index fbcdb3c..d8de2ce 100644
--- a/usr.bin/logname/logname.1
+++ b/usr.bin/logname/logname.1
@@ -33,23 +33,24 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)logname.1 8.1 (Berkeley) 6/9/93
+.\" $Id: logname.1,v 1.3 1997/04/27 08:45:45 jmg Exp $
.\"
-.Dd "June 9, 1993"
+.Dd June 9, 1993
.Dt LOGNAME 1
.Os BSD 4.4
.Sh NAME
.Nm logname
.Nd display user's login name
.Sh SYNOPSIS
-.Nm logname
+.Nm
.Sh DESCRIPTION
The
-.Nm logname
+.Nm
utility writes the user's login name to standard output followed by
a newline.
.Pp
The
-.Nm logname
+.Nm
utility explicitly ignores the
.Ev LOGNAME
and
@@ -58,19 +59,19 @@ environment variables
because the environment cannot be trusted.
.Pp
The
-.Nm logname
+.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
.Xr who 1 ,
.Xr whoami 1 ,
-.Xr getlogin 3
+.Xr getlogin 2
.Sh STANDARDS
The
-.Nm logname
+.Nm
function is expected to conform to
.St -p1003.2 .
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/logname/logname.c b/usr.bin/logname/logname.c
index 98b948a..c0f016e 100644
--- a/usr.bin/logname/logname.c
+++ b/usr.bin/logname/logname.c
@@ -58,7 +58,7 @@ main(argc, argv)
int ch;
char *p;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch (ch) {
case '?':
default:
diff --git a/usr.bin/look/look.1 b/usr.bin/look/look.1
index 3d8a247..be6f666 100644
--- a/usr.bin/look/look.1
+++ b/usr.bin/look/look.1
@@ -101,4 +101,5 @@ This was incorrect and the current man page matches the historic
implementation.
.Sh HISTORY
.Nm Look
-appeared in Version 7 AT&T Unix.
+appeared in
+.At v7 .
diff --git a/usr.bin/look/look.c b/usr.bin/look/look.c
index ddbd67fd..c3b7480 100644
--- a/usr.bin/look/look.c
+++ b/usr.bin/look/look.c
@@ -46,7 +46,7 @@ static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
/*
* look -- find lines in a sorted list.
- *
+ *
* The man page said that TABs and SPACEs participate in -d comparisons.
* In fact, they were ignored. This implements historic practice, not
* the manual page.
@@ -56,6 +56,8 @@ static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
#include <sys/mman.h>
#include <sys/stat.h>
+#include <limits.h>
+#include <locale.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -70,7 +72,7 @@ static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
/*
* FOLD and DICT convert characters to a normal form for comparison,
* according to the user specified flags.
- *
+ *
* DICT expects integers because it uses a non-character value to
* indicate a character which should not participate in comparisons.
*/
@@ -79,17 +81,17 @@ static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
#define LESS (-1)
#define NO_COMPARE (-2)
-#define FOLD(c) (isascii(c) && isupper(c) ? tolower(c) : (c))
-#define DICT(c) (isascii(c) && isalnum(c) ? (c) : NO_COMPARE)
+#define FOLD(c) (isupper(c) ? tolower(c) : (unsigned char) (c))
+#define DICT(c) (isalnum(c) ? (c) & 0xFF /* int */ : NO_COMPARE)
int dflag, fflag;
-char *binary_search __P((char *, char *, char *));
-int compare __P((char *, char *, char *));
+char *binary_search __P((unsigned char *, unsigned char *, unsigned char *));
+int compare __P((unsigned char *, unsigned char *, unsigned char *));
void err __P((const char *fmt, ...));
-char *linear_search __P((char *, char *, char *));
-int look __P((char *, char *, char *));
-void print_from __P((char *, char *, char *));
+char *linear_search __P((unsigned char *, unsigned char *, unsigned char *));
+int look __P((unsigned char *, unsigned char *, unsigned char *));
+void print_from __P((unsigned char *, unsigned char *, unsigned char *));
static void usage __P((void));
@@ -99,11 +101,13 @@ main(argc, argv)
{
struct stat sb;
int ch, fd, termchar;
- char *back, *file, *front, *string, *p;
+ unsigned char *back, *file, *front, *string, *p;
+
+ (void) setlocale(LC_CTYPE, "");
file = _PATH_WORDS;
termchar = '\0';
- while ((ch = getopt(argc, argv, "dft:")) != EOF)
+ while ((ch = getopt(argc, argv, "dft:")) != -1)
switch(ch) {
case 'd':
dflag = 1;
@@ -142,17 +146,17 @@ main(argc, argv)
if (sb.st_size > SIZE_T_MAX)
err("%s: %s", file, strerror(EFBIG));
if ((front = mmap(NULL,
- (size_t)sb.st_size, PROT_READ, 0, fd, (off_t)0)) == NULL)
+ (size_t)sb.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0)) == MAP_FAILED)
err("%s: %s", file, strerror(errno));
back = front + sb.st_size;
exit(look(string, front, back));
}
look(string, front, back)
- char *string, *front, *back;
+ unsigned char *string, *front, *back;
{
register int ch;
- register char *readp, *writep;
+ register unsigned char *readp, *writep;
/* Reformat string string to avoid doing it multiple times later. */
for (readp = writep = string; ch = *readp++;) {
@@ -176,40 +180,40 @@ look(string, front, back)
/*
* Binary search for "string" in memory between "front" and "back".
- *
+ *
* This routine is expected to return a pointer to the start of a line at
* *or before* the first word matching "string". Relaxing the constraint
* this way simplifies the algorithm.
- *
+ *
* Invariants:
- * front points to the beginning of a line at or before the first
+ * front points to the beginning of a line at or before the first
* matching string.
- *
- * back points to the beginning of a line at or after the first
+ *
+ * back points to the beginning of a line at or after the first
* matching line.
- *
+ *
* Base of the Invariants.
- * front = NULL;
+ * front = NULL;
* back = EOF;
- *
+ *
* Advancing the Invariants:
- *
+ *
* p = first newline after halfway point from front to back.
- *
- * If the string at "p" is not greater than the string to match,
+ *
+ * If the string at "p" is not greater than the string to match,
* p is the new front. Otherwise it is the new back.
- *
+ *
* Termination:
- *
- * The definition of the routine allows it return at any point,
+ *
+ * The definition of the routine allows it return at any point,
* since front is always at or before the line to print.
- *
- * In fact, it returns when the chosen "p" equals "back". This
- * implies that there exists a string is least half as long as
- * (back - front), which in turn implies that a linear search will
+ *
+ * In fact, it returns when the chosen "p" equals "back". This
+ * implies that there exists a string is least half as long as
+ * (back - front), which in turn implies that a linear search will
* be no more expensive than the cost of simply printing a string or two.
- *
- * Trying to continue with binary search at this point would be
+ *
+ * Trying to continue with binary search at this point would be
* more trouble than it's worth.
*/
#define SKIP_PAST_NEWLINE(p, back) \
@@ -217,9 +221,9 @@ look(string, front, back)
char *
binary_search(string, front, back)
- register char *string, *front, *back;
+ register unsigned char *string, *front, *back;
{
- register char *p;
+ register unsigned char *p;
p = front + (back - front) / 2;
SKIP_PAST_NEWLINE(p, back);
@@ -242,17 +246,17 @@ binary_search(string, front, back)
/*
* Find the first line that starts with string, linearly searching from front
* to back.
- *
+ *
* Return NULL for no such line.
- *
+ *
* This routine assumes:
- *
- * o front points at the first character in a line.
+ *
+ * o front points at the first character in a line.
* o front is before or at the first line to be printed.
*/
char *
linear_search(string, front, back)
- char *string, *front, *back;
+ unsigned char *string, *front, *back;
{
while (front < back) {
switch (compare(string, front, back)) {
@@ -273,9 +277,9 @@ linear_search(string, front, back)
/*
* Print as many lines as match string, starting at front.
*/
-void
+void
print_from(string, front, back)
- register char *string, *front, *back;
+ register unsigned char *string, *front, *back;
{
for (; front < back && compare(string, front, back) == EQUAL; ++front) {
for (; front < back && *front != '\n'; ++front)
@@ -289,19 +293,19 @@ print_from(string, front, back)
/*
* Return LESS, GREATER, or EQUAL depending on how the string1 compares with
* string2 (s1 ??? s2).
- *
- * o Matches up to len(s1) are EQUAL.
+ *
+ * o Matches up to len(s1) are EQUAL.
* o Matches up to len(s2) are GREATER.
- *
+ *
* Compare understands about the -f and -d flags, and treats comparisons
* appropriately.
- *
+ *
* The string "s1" is null terminated. The string s2 is '\n' terminated (or
* "back" terminated).
*/
int
compare(s1, s2, back)
- register char *s1, *s2, *back;
+ register unsigned char *s1, *s2, *back;
{
register int ch;
diff --git a/usr.bin/lorder/Makefile b/usr.bin/lorder/Makefile
index 70d28f5..a1682d1 100644
--- a/usr.bin/lorder/Makefile
+++ b/usr.bin/lorder/Makefile
@@ -1,17 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
-MAN1= lorder.0
+MAN1= lorder.1
-all lorder: ${MAN1}
-
-clean depend lint tags:
-
-cleandir:
- rm -f ${MAN1}
-
-install: maninstall
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/lorder.sh ${DESTDIR}/${BINDIR}/lorder
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/lorder.sh ${DESTDIR}${BINDIR}/lorder
.include <bsd.prog.mk>
-.include <bsd.man.mk>
diff --git a/usr.bin/lorder/lorder.1 b/usr.bin/lorder/lorder.1
index 387481f..c99e611 100644
--- a/usr.bin/lorder/lorder.1
+++ b/usr.bin/lorder/lorder.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)lorder.1 8.2 (Berkeley) 4/28/95
+.\" @(#)lorder.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd April 28, 1995
+.Dd June 6, 1993
.Dt LORDER 1
.Os
.Sh NAME
diff --git a/usr.bin/lsvfs/Makefile b/usr.bin/lsvfs/Makefile
new file mode 100644
index 0000000..3b25443
--- /dev/null
+++ b/usr.bin/lsvfs/Makefile
@@ -0,0 +1,4 @@
+# $Id$
+PROG= lsvfs
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/lsvfs/lsvfs.1 b/usr.bin/lsvfs/lsvfs.1
new file mode 100644
index 0000000..82a4798
--- /dev/null
+++ b/usr.bin/lsvfs/lsvfs.1
@@ -0,0 +1,55 @@
+.\" $Id$
+.\" Garrett A. Wollman, September 1994
+.\" This file is in the public domain.
+.\"
+.Dd March 16, 1995
+.Dt LSVFS 1
+.Os
+.Sh NAME
+.Nm lsvfs
+.Nd list installed virtual file systems
+.Sh SYNOPSIS
+.Nm lsvfs
+.Op Ar vfsname Ar ...
+.Sh DESCRIPTION
+The
+.Nm lsvfs
+command lists information about the currently loaded virtual filesystem
+modules. When
+.Ar vfsname
+arguments are given,
+.Nm lsvfs
+lists information about the specified VFS modules. Otherwise,
+.Nm lsvfs
+lists all currently loaded modules.
+The information is as follows:
+.Pp
+.Bl -tag -compact -width Filesystem
+.It Filesystem
+the name of the filesystem, as would be used in the
+.Fl t
+option to
+.Xr mount 8
+.It Index
+the kernel filesystem switch slot number for this filesystem, as would be
+used in the
+.Ar type
+parameter to
+.Xr mount 2
+.It Refs
+the number of references to this VFS; i.e., the number of currently
+mounted filesystems of this type
+.It Flags
+flag bits (only
+.Dq static
+is currently defined).
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr mount 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.Tn FreeBSD
+2.0.
diff --git a/usr.bin/lsvfs/lsvfs.c b/usr.bin/lsvfs/lsvfs.c
new file mode 100644
index 0000000..ce63d0e
--- /dev/null
+++ b/usr.bin/lsvfs/lsvfs.c
@@ -0,0 +1,99 @@
+/*
+ * lsvfs - lsit loaded VFSes
+ * Garrett A. Wollman, September 1994
+ * This file is in the public domain.
+ *
+ * $Id: lsvfs.c,v 1.7 1997/02/22 19:55:59 peter Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#define FMT "%-32.32s %5d %5d %s\n"
+#define HDRFMT "%-32.32s %5.5s %5.5s %s\n"
+#define DASHES "-------------------------------- ----- ----- ---------------\n"
+
+static const char *fmt_flags(int);
+
+int
+main(int argc, char **argv)
+{
+ int rv = 0;
+ struct vfsconf *vfc;
+ argc--, argv++;
+
+ setvfsent(1);
+
+ printf(HDRFMT, "Filesystem", "Index", "Refs", "Flags");
+ fputs(DASHES, stdout);
+
+ if(argc) {
+ for(; argc; argc--, argv++) {
+ vfc = getvfsbyname(*argv);
+ if(vfc) {
+ printf(FMT, vfc->vfc_name, vfc->vfc_index, vfc->vfc_refcount,
+ fmt_flags(vfc->vfc_flags));
+ } else {
+ warnx("VFS %s unknown or not loaded", *argv);
+ rv++;
+ }
+ }
+ } else {
+ while(vfc = getvfsent()) {
+ printf(FMT, vfc->vfc_name, vfc->vfc_index, vfc->vfc_refcount,
+ fmt_flags(vfc->vfc_flags));
+ }
+ }
+
+ endvfsent();
+ return rv;
+}
+
+static const char *
+fmt_flags(int flags)
+{
+ /*
+ * NB: if you add new flags, don't forget to add them here vvvvvv too.
+ */
+ static char buf[sizeof
+ "static, network, read-only, synthetic, loopback, unicode"];
+ int comma = 0;
+
+ buf[0] = '\0';
+
+ if(flags & VFCF_STATIC) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "static");
+ }
+
+ if(flags & VFCF_NETWORK) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "network");
+ }
+
+ if(flags & VFCF_READONLY) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "read-only");
+ }
+
+ if(flags & VFCF_SYNTHETIC) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "synthetic");
+ }
+
+ if(flags & VFCF_LOOPBACK) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "loopback");
+ }
+
+ if(flags & VFCF_UNICODE) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "unicode");
+ }
+
+ return buf;
+}
diff --git a/usr.bin/m4/Makefile b/usr.bin/m4/Makefile
new file mode 100644
index 0000000..7a57e83
--- /dev/null
+++ b/usr.bin/m4/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+# -DEXTENDED
+# if you want the paste & spaste macros.
+
+PROG= m4
+CFLAGS+=-DEXTENDED
+SRCS= eval.c expr.c look.c main.c misc.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/m4/NOTES b/usr.bin/m4/NOTES
new file mode 100644
index 0000000..d60f80e
--- /dev/null
+++ b/usr.bin/m4/NOTES
@@ -0,0 +1,64 @@
+m4 - macro processor
+
+PD m4 is based on the macro tool distributed with the software
+tools (VOS) package, and described in the "SOFTWARE TOOLS" and
+"SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include
+most of the command set of SysV m4, the standard UN*X macro processor.
+
+Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
+there may be certain implementation similarities between
+the two. The PD m4 was produced without ANY references to m4
+sources.
+
+written by: Ozan S. Yigit
+
+References:
+
+ Software Tools distribution: macro
+
+ Kernighan, Brian W. and P. J. Plauger, SOFTWARE
+ TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
+
+ Kernighan, Brian W. and P. J. Plauger, SOFTWARE
+ TOOLS, Addison-Wesley, Mass. 1976
+
+ Kernighan, Brian W. and Dennis M. Ritchie,
+ THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
+ Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
+
+ System V man page for M4
+
+
+Implementation Notes:
+
+[1] PD m4 uses a different (and simpler) stack mechanism than the one
+ described in Software Tools and Software Tools in Pascal books.
+ The triple stack thing is replaced with a single stack containing
+ the call frames and the arguments. Each frame is back-linked to a
+ previous stack frame, which enables us to rewind the stack after
+ each nested call is completed. Each argument is a character pointer
+ to the beginning of the argument string within the string space.
+ The only exceptions to this are (*) arg 0 and arg 1, which are
+ the macro definition and macro name strings, stored dynamically
+ for the hash table.
+
+ . .
+ | . | <-- sp | . |
+ +-------+ +-----+
+ | arg 3 ------------------------------->| str |
+ +-------+ | . |
+ | arg 2 --------------+ .
+ +-------+ |
+ * | | |
+ +-------+ | +-----+
+ | plev | <-- fp +---------------->| str |
+ +-------+ | . |
+ | type | .
+ +-------+
+ | prcf -----------+ plev: paren level
+ +-------+ | type: call type
+ | . | | prcf: prev. call frame
+ . |
+ +-------+ |
+ | <----------+
+ +-------+
diff --git a/usr.bin/m4/PSD.doc/Makefile b/usr.bin/m4/PSD.doc/Makefile
new file mode 100644
index 0000000..c60c912
--- /dev/null
+++ b/usr.bin/m4/PSD.doc/Makefile
@@ -0,0 +1,11 @@
+# $OpenBSD: Makefile,v 1.2 1996/06/26 05:36:17 deraadt Exp $
+
+
+DIR= psd/17.m4
+SRCS= m4.ms
+MACROS= -msU
+
+paper.ps: ${SRCS}
+ ${ROFF} ${SRCS} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/mkdep/mkdep.ultrix b/usr.bin/m4/TEST/ack.m4
index 8c48667..ef0b5ef 100644
--- a/usr.bin/mkdep/mkdep.ultrix
+++ b/usr.bin/m4/TEST/ack.m4
@@ -1,8 +1,12 @@
-#!/bin/sh -
+# $OpenBSD: ack.m4,v 1.2 1996/06/26 05:36:18 deraadt Exp $
+# $NetBSD: ack.m4,v 1.4 1995/09/28 05:37:54 tls Exp $
#
-# Copyright (c) 1991, 1993
+# Copyright (c) 1989, 1993
# The Regents of the University of California. All rights reserved.
#
+# This code is derived from software contributed to Berkeley by
+# Ozan Yigit.
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
@@ -31,94 +35,8 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# @(#)mkdep.ultrix 8.1 (Berkeley) 6/6/93
-#
-
-PATH=/bin:/usr/bin:/usr/ucb
-export PATH
-
-MAKE=Makefile # default makefile name is "Makefile"
-
-while :
- do case "$1" in
- # -f allows you to select a makefile name
- -f)
- MAKE=$2
- shift; shift ;;
-
- # the -p flag produces "program: program.c" style dependencies
- # so .o's don't get produced
- -p)
- SED='s;\.o;;'
- shift ;;
- *)
- break ;;
- esac
-done
-
-if [ $# = 0 ] ; then
- echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
- exit 1
-fi
-
-if [ ! -w $MAKE ]; then
- echo "mkdep: no writeable file \"$MAKE\""
- exit 1
-fi
-
-TMP=/tmp/mkdep$$
-
-trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
-
-cp $MAKE ${MAKE}.bak
-
-sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
-
-cat << _EOF_ >> $TMP
-# DO NOT DELETE THIS LINE -- mkdep uses it.
-# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
-
-_EOF_
-
-# If your compiler doesn't have -M, add it. If you can't, the next two
-# lines will try and replace the "cc -M". The real problem is that this
-# hack can't deal with anything that requires a search path, and doesn't
-# even try for anything using bracket (<>) syntax.
+# @(#)ack.m4 8.1 (Berkeley) 6/6/93
#
-# egrep '^#include[ ]*".*"' /dev/null $* |
-# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
-
-# Ultrix has already used -M for something else.
-cc -Em $* |
-sed "
- s; \./; ;g
- $SED" |
-awk '{
- if ($1 != prev) {
- if (rec != "")
- print rec;
- rec = $0;
- prev = $1;
- }
- else {
- if (length(rec $2) > 78) {
- print rec;
- rec = $0;
- }
- else
- rec = rec " " $2
- }
-}
-END {
- print rec
-}' >> $TMP
-
-cat << _EOF_ >> $TMP
-
-# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
-_EOF_
-# copy to preserve permissions
-cp $TMP $MAKE
-rm -f ${MAKE}.bak $TMP
-exit 0
+define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)',
+`ack(DECR($1), ack($1,DECR($2)))')')
diff --git a/usr.bin/locate/locate/updatedb.csh b/usr.bin/m4/TEST/hanoi.m4
index bca8bab..d16f922 100644
--- a/usr.bin/locate/locate/updatedb.csh
+++ b/usr.bin/m4/TEST/hanoi.m4
@@ -1,10 +1,11 @@
-#!/bin/csh -f
+# $OpenBSD: hanoi.m4,v 1.2 1996/06/26 05:36:19 deraadt Exp $
+# $NetBSD: hanoi.m4,v 1.4 1995/09/28 05:37:56 tls Exp $
#
# Copyright (c) 1989, 1993
# The Regents of the University of California. All rights reserved.
#
# This code is derived from software contributed to Berkeley by
-# James A. Woods.
+# Ozan Yigit.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -34,44 +35,13 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# @(#)updatedb.csh 8.4 (Berkeley) 10/27/94
+# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93
#
-set SRCHPATHS = "/" # directories to be put in the database
-set LIBDIR = /usr/libexec # for subprograms
- # for temp files
-if (! $?TMPDIR) setenv TMPDIR /var/tmp
-set FCODES = /var/db/locate.database # the database
+define(hanoi, `trans(A, B, C, $1)')
-set path = ( /bin /usr/bin )
-set bigrams = $TMPDIR/locate.bigrams.$$
-set filelist = $TMPDIR/locate.list.$$
-set errs = $TMPDIR/locate.errs.$$
+define(moved,`move disk from $1 to $2
+')
-# Make a file list and compute common bigrams.
-# Alphabetize '/' before any other char with 'tr'.
-# If the system is very short of sort space, 'bigram' can be made
-# smarter to accumulate common bigrams directly without sorting
-# ('awk', with its associative memory capacity, can do this in several
-# lines, but is too slow, and runs out of string space on small machines).
-
-# search locally or everything
-# find ${SRCHPATHS} -print | \
-find ${SRCHPATHS} \! -fstype local -prune -or -print | \
- tr '/' '\001' | \
- (sort -T $TMPDIR -f; echo $status > $errs) | tr '\001' '/' > $filelist
-
-$LIBDIR/locate.bigram < $filelist | \
- (sort -T /$TMPDIR; echo $status >> $errs) | \
- uniq -c | sort -T /$TMPDIR -nr | \
- awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams
-
-# code the file list
-
-if { grep -s -v 0 $errs } then
- printf 'locate: updatedb failed\n\n'
-else
- $LIBDIR/locate.code $bigrams < $filelist > $FCODES
- chmod 644 $FCODES
- rm $bigrams $filelist $errs
-endif
+define(trans, `ifelse($4,1,`moved($1,$2)',
+ `trans($1,$3,$2,DECR($4))moved($1,$2)trans($3,$2,$1,DECR($4))')')
diff --git a/usr.bin/m4/TEST/hash.m4 b/usr.bin/m4/TEST/hash.m4
new file mode 100644
index 0000000..21b40e1
--- /dev/null
+++ b/usr.bin/m4/TEST/hash.m4
@@ -0,0 +1,57 @@
+# $OpenBSD: hash.m4,v 1.2 1996/06/26 05:36:19 deraadt Exp $
+# $NetBSD: hash.m4,v 1.4 1995/09/28 05:37:58 tls Exp $
+#
+# Copyright (c) 1989, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Ozan Yigit.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)hash.m4 8.1 (Berkeley) 6/6/93
+#
+
+dnl This probably will not run on any m4 that cannot
+dnl handle char constants in eval.
+dnl
+changequote(<,>) define(HASHVAL,99) dnl
+define(hash,<eval(str(substr($1,1),0)%HASHVAL)>) dnl
+define(str,
+ <ifelse($1,",$2,
+ <str(substr(<$1>,1),<eval($2+'substr($1,0,1)')>)>)
+ >) dnl
+define(KEYWORD,<$1,hash($1),>) dnl
+define(TSTART,
+<struct prehash {
+ char *keyword;
+ int hashval;
+} keytab[] = {>) dnl
+define(TEND,< "",0
+};>) dnl
diff --git a/usr.bin/m4/TEST/sqroot.m4 b/usr.bin/m4/TEST/sqroot.m4
new file mode 100644
index 0000000..d01789b
--- /dev/null
+++ b/usr.bin/m4/TEST/sqroot.m4
@@ -0,0 +1,47 @@
+# $OpenBSD: sqroot.m4,v 1.2 1996/06/26 05:36:20 deraadt Exp $
+# $NetBSD: sqroot.m4,v 1.4 1995/09/28 05:38:01 tls Exp $
+#
+# Copyright (c) 1989, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Ozan Yigit.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93
+#
+
+define(square_root,
+ `ifelse(eval($1<0),1,negative-square-root,
+ `square_root_aux($1, 1, eval(($1+1)/2))')')
+define(square_root_aux,
+ `ifelse($3, $2, $3,
+ $3, eval($1/$2), $3,
+ `square_root_aux($1, $3, eval(($3+($1/$3))/2))')')
diff --git a/usr.bin/mkdep/mkdep.append b/usr.bin/m4/TEST/string.m4
index 1c84dd1..bb0bba4 100644
--- a/usr.bin/mkdep/mkdep.append
+++ b/usr.bin/m4/TEST/string.m4
@@ -1,8 +1,12 @@
-#!/bin/sh -
+# $OpenBSD: string.m4,v 1.2 1996/06/26 05:36:20 deraadt Exp $
+# $NetBSD: string.m4,v 1.4 1995/09/28 05:38:03 tls Exp $
#
-# Copyright (c) 1991, 1993
+# Copyright (c) 1989, 1993
# The Regents of the University of California. All rights reserved.
#
+# This code is derived from software contributed to Berkeley by
+# Ozan Yigit.
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
@@ -31,93 +35,13 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# @(#)mkdep.append 8.1 (Berkeley) 6/6/93
+# @(#)string.m4 8.1 (Berkeley) 6/6/93
#
-PATH=/bin:/usr/bin:/usr/ucb
-export PATH
-
-MAKE=Makefile # default makefile name is "Makefile"
-
-while :
- do case "$1" in
- # -f allows you to select a makefile name
- -f)
- MAKE=$2
- shift; shift ;;
-
- # the -p flag produces "program: program.c" style dependencies
- # so .o's don't get produced
- -p)
- SED='s;\.o;;'
- shift ;;
- *)
- break ;;
- esac
-done
-
-if [ $# = 0 ] ; then
- echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
- exit 1
-fi
-
-if [ ! -w $MAKE ]; then
- echo "mkdep: no writeable file \"$MAKE\""
- exit 1
-fi
-
-TMP=/tmp/mkdep$$
-
-trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
-
-cp $MAKE ${MAKE}.bak
-
-sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
-
-cat << _EOF_ >> $TMP
-# DO NOT DELETE THIS LINE -- mkdep uses it.
-# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
-
-_EOF_
-
-# If your compiler doesn't have -M, add it. If you can't, the next two
-# lines will try and replace the "cc -M". The real problem is that this
-# hack can't deal with anything that requires a search path, and doesn't
-# even try for anything using bracket (<>) syntax.
-#
-# egrep '^#include[ ]*".*"' /dev/null $* |
-# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
-
-cc -M $* |
-sed "
- s; \./; ;g
- $SED" |
-awk '{
- if ($1 != prev) {
- if (rec != "")
- print rec;
- rec = $0;
- prev = $1;
- }
- else {
- if (length(rec $2) > 78) {
- print rec;
- rec = $0;
- }
- else
- rec = rec " " $2
- }
-}
-END {
- print rec
-}' >> $TMP
-
-cat << _EOF_ >> $TMP
-
-# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
-_EOF_
+define(string,`integer $1(len(substr($2,1)))
+str($1,substr($2,1),0)
+data $1(len(substr($2,1)))/EOS/
+')
-# copy to preserve permissions
-cp $TMP $MAKE
-rm -f ${MAKE}.bak $TMP
-exit 0
+define(str,`ifelse($2,",,data $1(incr($3))/`LET'substr($2,0,1)/
+`str($1,substr($2,1),incr($3))')')
diff --git a/usr.bin/m4/TEST/test.m4 b/usr.bin/m4/TEST/test.m4
new file mode 100644
index 0000000..1c77b9b
--- /dev/null
+++ b/usr.bin/m4/TEST/test.m4
@@ -0,0 +1,245 @@
+# $OpenBSD: test.m4,v 1.2 1996/06/26 05:36:21 deraadt Exp $
+# $NetBSD: test.m4,v 1.4 1995/09/28 05:38:05 tls Exp $
+#
+# Copyright (c) 1989, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Ozan Yigit.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)test.m4 8.1 (Berkeley) 6/6/93
+#
+
+# test file for mp (not comprehensive)
+#
+# v7 m4 does not have `decr'.
+#
+define(DECR,`eval($1-1)')
+#
+# include string macros
+#
+include(string.m4)
+#
+# create some fortrash strings for an even uglier language
+#
+string(TEXT, "text")
+string(DATA, "data")
+string(BEGIN, "begin")
+string(END, "end")
+string(IF, "if")
+string(THEN, "then")
+string(ELSE, "else")
+string(CASE, "case")
+string(REPEAT, "repeat")
+string(WHILE, "while")
+string(DEFAULT, "default")
+string(UNTIL, "until")
+string(FUNCTION, "function")
+string(PROCEDURE, "procedure")
+string(EXTERNAL, "external")
+string(FORWARD, "forward")
+string(TYPE, "type")
+string(VAR, "var")
+string(CONST, "const")
+string(PROGRAM, "program")
+string(INPUT, "input")
+string(OUTPUT, "output")
+#
+divert(2)
+diversion #1
+divert(3)
+diversion #2
+divert(4)
+diversion #3
+divert(5)
+diversion #4
+divert(0)
+define(abc,xxx)
+ifdef(`abc',defined,undefined)
+#
+# v7 m4 does this wrong. The right output is
+# this is A vEry lon sEntEnCE
+# see m4 documentation for translit.
+#
+translit(`this is a very long sentence', abcdefg, ABCDEF)
+#
+# include towers-of-hanoi
+#
+include(hanoi.m4)
+#
+# some reasonable set of disks
+#
+hanoi(6)
+#
+# include ackermann's function
+#
+include(ack.m4)
+#
+# something like (3,3) will blow away un*x m4.
+#
+ack(2,3)
+#
+# include a square_root function for fixed nums
+#
+include(sqroot.m4)
+#
+# some square roots.
+#
+square_root(15)
+square_root(100)
+square_root(-4)
+square_root(21372)
+#
+# some textual material for enjoyment.
+#
+[taken from the 'Clemson University Computer Newsletter',
+ September 1981, pp. 6-7]
+
+I am a wizard in the magical Kingdom of Transformation and I
+slay dragons for a living. Actually, I am a systems programmer.
+One of the problems with systems programming is explaining to
+non-computer enthusiasts what that is. All of the terms I use to
+describe my job are totally meaningless to them. Usually my response
+to questions about my work is to say as little as possible. For
+instance, if someone asks what happened at work this week, I say
+"Nothing much" and then I change the subject.
+
+With the assistance of my brother, a mechanical engineer, I have devised
+an analogy that everyone can understand. The analogy describes the
+"Kingdom of Transformation" where travelers wander and are magically
+transformed. This kingdom is the computer and the travelers are information.
+The purpose of the computer is to change information to a more meaningful
+forma. The law of conservation applies here: The computer never creates
+and never intentionally destroys data. With no further ado, let us travel
+to the Kingdom of Transformation:
+
+In a land far, far away, there is a magical kingdom called the Kingdom of
+Transformation. A king rules over this land and employs a Council of
+Wizardry. The main purpose of this kingdom is to provide a way for
+neighboring kingdoms to transform citizens into more useful citizens. This
+is done by allowing the citizens to enter the kingdom at one of its ports
+and to travel any of the many routes in the kingdom. They are magically
+transformed along the way. The income of the Kingdom of Transformation
+comes from the many toll roads within its boundaries.
+
+The Kingdom of Transformation was created when several kingdoms got
+together and discovered a mutual need for new talents and abilities for
+citizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to
+create this kingdom. CTK designed the country, its transportation routes,
+and its laws of transformation, and created the major highway system.
+
+Hazards
+=======
+
+Because magic is not truly controllable, CTK invariably, but unknowingly,
+creates dragons. Dragons are huge fire-breathing beasts which sometimes
+injure or kill travelers. Fortunately, they do not travel, but always
+remain near their den.
+
+Other hazards also exist which are potentially harmful. As the roads
+become older and more weatherbeaten, pot-holes will develop, trees will
+fall on travelers, etc. CTK maintenance men are called to fix these
+problems.
+
+Wizards
+=======
+
+The wizards play a major role in creating and maintaining the kingdom but
+get little credit for their work because it is performed secretly. The
+wizards do not wan the workers or travelers to learn their incantations
+because many laws would be broken and chaos would result.
+
+CTK's grand design is always general enough to be applicable in many
+different situations. As a result, it is often difficult to use. The
+first duty of the wizards is to tailor the transformation laws so as to be
+more beneficial and easier to use in their particular environment.
+
+After creation of the kingdom, a major duty of the wizards is to search for
+and kill dragons. If travelers do not return on time or if they return
+injured, the ruler of the country contacts the wizards. If the wizards
+determine that the injury or death occurred due to the traveler's
+negligence, they provide the traveler's country with additional warnings.
+If not, they must determine if the cause was a road hazard or a dragon. If
+the suspect a road hazard, they call in a CTK maintenance man to locate the
+hazard and to eliminate it, as in repairing the pothole in the road. If
+they think that cause was a dragon, then they must find and slay it.
+
+The most difficult part of eliminating a dragon is finding it. Sometimes
+the wizard magically knows where the dragon's lair it, but often the wizard
+must send another traveler along the same route and watch to see where he
+disappears. This sounds like a failsafe method for finding dragons (and a
+suicide mission for thr traveler) but the second traveler does not always
+disappear. Some dragons eat any traveler who comes too close; others are
+very picky.
+
+The wizards may call in CTK who designed the highway system and
+transformation laws to help devise a way to locate the dragon. CTK also
+helps provide the right spell or incantation to slay the dragon. (There is
+no general spell to slay dragons; each dragon must be eliminated with a
+different spell.)
+
+Because neither CTK nor wizards are perfect, spells to not always work
+correctly. At best, nothing happens when the wrong spell is uttered. At
+worst, the dragon becomes a much larger dragon or multiplies into several
+smaller ones. In either case, new spells must be found.
+
+If all existing dragons are quiet (i.e. have eaten sufficiently), wizards
+have time to do other things. They hide in castles and practice spells and
+incatations. They also devise shortcuts for travelers and new laws of
+transformation.
+
+Changes in the Kingdom
+======================
+
+As new transformation kingdoms are created and old ones are maintained,
+CTK, Inc. is constantly learning new things. It learns ways to avoid
+creating some of the dragons that they have previously created. It also
+discovers new and better laws of transformation. As a result, CTK will
+periodically create a new grand design which is far better than the old.
+The wizards determine when is a good time to implement this new design.
+This is when the tourist season is slow or when no important travelers
+(VIPs) are to arrive. The kingdom must be closed for the actual
+implementation and is leter reopened as a new and better place to go.
+
+A final question you might ask is what happens when the number of tourists
+becomes too great for the kingdom to handle in a reasonable period of time
+(i.e., the tourist lines at the ports are too long). The Kingdom of
+Transformation has three options: (1) shorten the paths that a tourist must
+travel, or (2) convince CTK to develop a faster breed of horses so that the
+travelers can finish sooner, or (3) annex more territories so that the
+kingdom can handle more travelers.
+
+Thus ends the story of the Kingdom of Transformation. I hope this has
+explained my job to you: I slay dragons for a living.
+
+#
+#should do an automatic undivert..
+#
diff --git a/usr.bin/m4/eval.c b/usr.bin/m4/eval.c
new file mode 100644
index 0000000..be9c1c0
--- /dev/null
+++ b/usr.bin/m4/eval.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * eval.c
+ * Facility: m4 macro processor
+ * by: oz
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+#include "pathnames.h"
+
+/*
+ * eval - evaluate built-in macros.
+ * argc - number of elements in argv.
+ * argv - element vector :
+ * argv[0] = definition of a user
+ * macro or nil if built-in.
+ * argv[1] = name of the macro or
+ * built-in.
+ * argv[2] = parameters to user-defined
+ * . macro or built-in.
+ * .
+ *
+ * Note that the minimum value for argc is 3. A call in the form
+ * of macro-or-builtin() will result in:
+ * argv[0] = nullstr
+ * argv[1] = macro-or-builtin
+ * argv[2] = nullstr
+ */
+
+void
+eval(argv, argc, td)
+register char *argv[];
+register int argc;
+register int td;
+{
+ register int c, n;
+ static int sysval = 0;
+
+#ifdef DEBUG
+ printf("argc = %d\n", argc);
+ for (n = 0; n < argc; n++)
+ printf("argv[%d] = %s\n", n, argv[n]);
+#endif
+ /*
+ * if argc == 3 and argv[2] is null, then we
+ * have macro-or-builtin() type call. We adjust
+ * argc to avoid further checking..
+ */
+ if (argc == 3 && !*(argv[2]))
+ argc--;
+
+ switch (td & ~STATIC) {
+
+ case DEFITYPE:
+ if (argc > 2)
+ dodefine(argv[2], (argc > 3) ? argv[3] : null);
+ break;
+
+ case PUSDTYPE:
+ if (argc > 2)
+ dopushdef(argv[2], (argc > 3) ? argv[3] : null);
+ break;
+
+ case DUMPTYPE:
+ dodump(argv, argc);
+ break;
+
+ case EXPRTYPE:
+ /*
+ * doexpr - evaluate arithmetic
+ * expression
+ */
+ if (argc > 2)
+ pbnum(expr(argv[2]));
+ break;
+
+ case IFELTYPE:
+ if (argc > 4)
+ doifelse(argv, argc);
+ break;
+
+ case IFDFTYPE:
+ /*
+ * doifdef - select one of two
+ * alternatives based on the existence of
+ * another definition
+ */
+ if (argc > 3) {
+ if (lookup(argv[2]) != nil)
+ pbstr(argv[3]);
+ else if (argc > 4)
+ pbstr(argv[4]);
+ }
+ break;
+
+ case LENGTYPE:
+ /*
+ * dolen - find the length of the
+ * argument
+ */
+ if (argc > 2)
+ pbnum((argc > 2) ? strlen(argv[2]) : 0);
+ break;
+
+ case INCRTYPE:
+ /*
+ * doincr - increment the value of the
+ * argument
+ */
+ if (argc > 2)
+ pbnum(atoi(argv[2]) + 1);
+ break;
+
+ case DECRTYPE:
+ /*
+ * dodecr - decrement the value of the
+ * argument
+ */
+ if (argc > 2)
+ pbnum(atoi(argv[2]) - 1);
+ break;
+
+ case SYSCTYPE:
+ /*
+ * dosys - execute system command
+ */
+ /* Make sure m4 output is NOT interrupted */
+ fflush(stdout);
+ fflush(stderr);
+ if (argc > 2)
+ sysval = system(argv[2]);
+ break;
+
+ case SYSVTYPE:
+ /*
+ * dosysval - return value of the last
+ * system call.
+ *
+ */
+ pbnum(sysval);
+ break;
+
+ case INCLTYPE:
+ if (argc > 2)
+ if (!doincl(argv[2]))
+ oops("%s: %s", argv[2], strerror(errno));
+ break;
+
+ case SINCTYPE:
+ if (argc > 2)
+ (void) doincl(argv[2]);
+ break;
+#ifdef EXTENDED
+ case PASTTYPE:
+ if (argc > 2)
+ if (!dopaste(argv[2]))
+ oops("%s: %s", argv[2], strerror(errno));
+ break;
+
+ case SPASTYPE:
+ if (argc > 2)
+ (void) dopaste(argv[2]);
+ break;
+#endif
+ case CHNQTYPE:
+ dochq(argv, argc);
+ break;
+
+ case CHNCTYPE:
+ dochc(argv, argc);
+ break;
+
+ case SUBSTYPE:
+ /*
+ * dosub - select substring
+ *
+ */
+ if (argc > 3)
+ dosub(argv, argc);
+ break;
+
+ case SHIFTYPE:
+ /*
+ * doshift - push back all arguments
+ * except the first one (i.e. skip
+ * argv[2])
+ */
+ if (argc > 3) {
+ for (n = argc - 1; n > 3; n--) {
+ putback(rquote);
+ pbstr(argv[n]);
+ putback(lquote);
+ putback(',');
+ }
+ putback(rquote);
+ pbstr(argv[3]);
+ putback(lquote);
+ }
+ break;
+
+ case DIVRTYPE:
+ if (argc > 2 && (n = atoi(argv[2])) != 0)
+ dodiv(n);
+ else {
+ active = stdout;
+ oindex = 0;
+ }
+ break;
+
+ case UNDVTYPE:
+ doundiv(argv, argc);
+ break;
+
+ case DIVNTYPE:
+ /*
+ * dodivnum - return the number of
+ * current output diversion
+ */
+ pbnum(oindex);
+ break;
+
+ case UNDFTYPE:
+ /*
+ * doundefine - undefine a previously
+ * defined macro(s) or m4 keyword(s).
+ */
+ if (argc > 2)
+ for (n = 2; n < argc; n++)
+ remhash(argv[n], ALL);
+ break;
+
+ case POPDTYPE:
+ /*
+ * dopopdef - remove the topmost
+ * definitions of macro(s) or m4
+ * keyword(s).
+ */
+ if (argc > 2)
+ for (n = 2; n < argc; n++)
+ remhash(argv[n], TOP);
+ break;
+
+ case MKTMTYPE:
+ /*
+ * dotemp - create a temporary file
+ */
+ if (argc > 2)
+ pbstr(mktemp(argv[2]));
+ break;
+
+ case TRNLTYPE:
+ /*
+ * dotranslit - replace all characters in
+ * the source string that appears in the
+ * "from" string with the corresponding
+ * characters in the "to" string.
+ */
+ if (argc > 3) {
+ char temp[MAXTOK];
+ if (argc > 4)
+ map(temp, argv[2], argv[3], argv[4]);
+ else
+ map(temp, argv[2], argv[3], null);
+ pbstr(temp);
+ }
+ else if (argc > 2)
+ pbstr(argv[2]);
+ break;
+
+ case INDXTYPE:
+ /*
+ * doindex - find the index of the second
+ * argument string in the first argument
+ * string. -1 if not present.
+ */
+ pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
+ break;
+
+ case ERRPTYPE:
+ /*
+ * doerrp - print the arguments to stderr
+ * file
+ */
+ if (argc > 2) {
+ for (n = 2; n < argc; n++)
+ fprintf(stderr, "%s ", argv[n]);
+ fprintf(stderr, "\n");
+ }
+ break;
+
+ case DNLNTYPE:
+ /*
+ * dodnl - eat-up-to and including
+ * newline
+ */
+ while ((c = gpbc()) != '\n' && c != EOF)
+ ;
+ break;
+
+ case M4WRTYPE:
+ /*
+ * dom4wrap - set up for
+ * wrap-up/wind-down activity
+ */
+ m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
+ break;
+
+ case EXITTYPE:
+ /*
+ * doexit - immediate exit from m4.
+ */
+ killdiv();
+ exit((argc > 2) ? atoi(argv[2]) : 0);
+ break;
+
+ case DEFNTYPE:
+ if (argc > 2)
+ for (n = 2; n < argc; n++)
+ dodefn(argv[n]);
+ break;
+
+ default:
+ oops("%s: major botch.", "eval");
+ break;
+ }
+}
+
+char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
+
+/*
+ * expand - user-defined macro expansion
+ */
+void
+expand(argv, argc)
+register char *argv[];
+register int argc;
+{
+ register unsigned char *t;
+ register unsigned char *p;
+ register int n;
+ register int argno;
+
+ t = argv[0]; /* defn string as a whole */
+ p = t;
+ while (*p)
+ p++;
+ p--; /* last character of defn */
+ while (p > t) {
+ if (*(p - 1) != ARGFLAG)
+ putback(*p);
+ else {
+ switch (*p) {
+
+ case '#':
+ pbnum(argc - 2);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if ((argno = *p - '0') < argc - 1)
+ pbstr(argv[argno + 1]);
+ break;
+ case '*':
+ for (n = argc - 1; n > 2; n--) {
+ pbstr(argv[n]);
+ putback(',');
+ }
+ pbstr(argv[2]);
+ break;
+ case '@':
+ for( n = argc - 1; n >= 2; n-- )
+ {
+ putback(rquote);
+ pbstr(argv[n]);
+ putback(lquote);
+ if( n > 2 )
+ putback(',');
+ }
+ break;
+ default:
+ putback(*p);
+ putback('$');
+ break;
+ }
+ p--;
+ }
+ p--;
+ }
+ if (p == t) /* do last character */
+ putback(*p);
+}
+
+/*
+ * dodefine - install definition in the table
+ */
+void
+dodefine(name, defn)
+register char *name;
+register char *defn;
+{
+ register ndptr p;
+
+ if (!*name)
+ oops("null definition.");
+ if (STREQ(name, defn))
+ oops("%s: recursive definition.", name);
+ if ((p = lookup(name)) == nil)
+ p = addent(name);
+ else if (p->defn != null)
+ free((char *) p->defn);
+ if (!*defn)
+ p->defn = null;
+ else
+ p->defn = xstrdup(defn);
+ p->type = MACRTYPE;
+}
+
+/*
+ * dodefn - push back a quoted definition of
+ * the given name.
+ */
+void
+dodefn(name)
+char *name;
+{
+ register ndptr p;
+
+ if ((p = lookup(name)) != nil && p->defn != null) {
+ putback(rquote);
+ pbstr(p->defn);
+ putback(lquote);
+ }
+}
+
+/*
+ * dopushdef - install a definition in the hash table
+ * without removing a previous definition. Since
+ * each new entry is entered in *front* of the
+ * hash bucket, it hides a previous definition from
+ * lookup.
+ */
+void
+dopushdef(name, defn)
+register char *name;
+register char *defn;
+{
+ register ndptr p;
+
+ if (!*name)
+ oops("null definition");
+ if (STREQ(name, defn))
+ oops("%s: recursive definition.", name);
+ p = addent(name);
+ if (!*defn)
+ p->defn = null;
+ else
+ p->defn = xstrdup(defn);
+ p->type = MACRTYPE;
+}
+
+/*
+ * dodumpdef - dump the specified definitions in the hash
+ * table to stderr. If nothing is specified, the entire
+ * hash table is dumped.
+ */
+void
+dodump(argv, argc)
+register char *argv[];
+register int argc;
+{
+ register int n;
+ ndptr p;
+
+ if (argc > 2) {
+ for (n = 2; n < argc; n++)
+ if ((p = lookup(argv[n])) != nil)
+ fprintf(stderr, dumpfmt, p->name,
+ p->defn);
+ }
+ else {
+ for (n = 0; n < HASHSIZE; n++)
+ for (p = hashtab[n]; p != nil; p = p->nxtptr)
+ fprintf(stderr, dumpfmt, p->name,
+ p->defn);
+ }
+}
+
+/*
+ * doifelse - select one of two alternatives - loop.
+ */
+void
+doifelse(argv, argc)
+register char *argv[];
+register int argc;
+{
+ cycle {
+ if (STREQ(argv[2], argv[3]))
+ pbstr(argv[4]);
+ else if (argc == 6)
+ pbstr(argv[5]);
+ else if (argc > 6) {
+ argv += 3;
+ argc -= 3;
+ continue;
+ }
+ break;
+ }
+}
+
+/*
+ * doinclude - include a given file.
+ */
+int
+doincl(ifile)
+char *ifile;
+{
+ if (ilevel + 1 == MAXINP)
+ oops("too many include files.");
+ if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
+ ilevel++;
+ bbase[ilevel] = bufbase = bp;
+ return (1);
+ }
+ else
+ return (0);
+}
+
+#ifdef EXTENDED
+/*
+ * dopaste - include a given file without any
+ * macro processing.
+ */
+int
+dopaste(pfile)
+char *pfile;
+{
+ FILE *pf;
+ register int c;
+
+ if ((pf = fopen(pfile, "r")) != NULL) {
+ while ((c = getc(pf)) != EOF)
+ putc(c, active);
+ (void) fclose(pf);
+ return (1);
+ }
+ else
+ return (0);
+}
+#endif
+
+/*
+ * dochq - change quote characters
+ */
+void
+dochq(argv, argc)
+register char *argv[];
+register int argc;
+{
+ if (argc > 2) {
+ if (*argv[2])
+ lquote = *argv[2];
+ if (argc > 3) {
+ if (*argv[3])
+ rquote = *argv[3];
+ }
+ else
+ rquote = lquote;
+ }
+ else {
+ lquote = LQUOTE;
+ rquote = RQUOTE;
+ }
+}
+
+/*
+ * dochc - change comment characters
+ */
+void
+dochc(argv, argc)
+register char *argv[];
+register int argc;
+{
+ if (argc > 2) {
+ if (*argv[2])
+ scommt = *argv[2];
+ if (argc > 3) {
+ if (*argv[3])
+ ecommt = *argv[3];
+ }
+ else
+ ecommt = ECOMMT;
+ }
+ else {
+ scommt = SCOMMT;
+ ecommt = ECOMMT;
+ }
+}
+
+/*
+ * dodivert - divert the output to a temporary file
+ */
+void
+dodiv(n)
+register int n;
+{
+ if (n < 0 || n >= MAXOUT)
+ n = 0; /* bitbucket */
+ if (outfile[n] == NULL) {
+ m4temp[UNIQUE] = n + '0';
+ if ((outfile[n] = fopen(m4temp, "w")) == NULL)
+ oops("%s: cannot divert.", m4temp);
+ }
+ oindex = n;
+ active = outfile[n];
+}
+
+/*
+ * doundivert - undivert a specified output, or all
+ * other outputs, in numerical order.
+ */
+void
+doundiv(argv, argc)
+register char *argv[];
+register int argc;
+{
+ register int ind;
+ register int n;
+
+ if (argc > 2) {
+ for (ind = 2; ind < argc; ind++) {
+ n = atoi(argv[ind]);
+ if (n > 0 && n < MAXOUT && outfile[n] != NULL)
+ getdiv(n);
+
+ }
+ }
+ else
+ for (n = 1; n < MAXOUT; n++)
+ if (outfile[n] != NULL)
+ getdiv(n);
+}
+
+/*
+ * dosub - select substring
+ */
+void
+dosub(argv, argc)
+register char *argv[];
+register int argc;
+{
+ register unsigned char *ap, *fc, *k;
+ register int nc;
+
+ if (argc < 5)
+ nc = MAXTOK;
+ else
+#ifdef EXPR
+ nc = expr(argv[4]);
+#else
+ nc = atoi(argv[4]);
+#endif
+ ap = argv[2]; /* target string */
+#ifdef EXPR
+ fc = ap + expr(argv[3]); /* first char */
+#else
+ fc = ap + atoi(argv[3]); /* first char */
+#endif
+ if (fc >= ap && fc < ap + strlen(ap))
+ for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
+ putback(*k);
+}
+
+/*
+ * map:
+ * map every character of s1 that is specified in from
+ * into s3 and replace in s. (source s1 remains untouched)
+ *
+ * This is a standard implementation of map(s,from,to) function of ICON
+ * language. Within mapvec, we replace every character of "from" with
+ * the corresponding character in "to". If "to" is shorter than "from",
+ * than the corresponding entries are null, which means that those
+ * characters dissapear altogether. Furthermore, imagine
+ * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
+ * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
+ * ultimately maps to `*'. In order to achieve this effect in an efficient
+ * manner (i.e. without multiple passes over the destination string), we
+ * loop over mapvec, starting with the initial source character. if the
+ * character value (dch) in this location is different than the source
+ * character (sch), sch becomes dch, once again to index into mapvec, until
+ * the character value stabilizes (i.e. sch = dch, in other words
+ * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
+ * character, it will stabilize, since mapvec[0] == 0 at all times. At the
+ * end, we restore mapvec* back to normal where mapvec[n] == n for
+ * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
+ * about 5 times faster than any algorithm that makes multiple passes over
+ * destination string.
+ */
+void
+map(dest, src, from, to)
+register char *dest;
+register char *src;
+register char *from;
+register char *to;
+{
+ register char *tmp;
+ register char sch, dch;
+ static char mapvec[128] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127
+ };
+
+ if (*src) {
+ tmp = from;
+ /*
+ * create a mapping between "from" and
+ * "to"
+ */
+ while (*from)
+ mapvec[*from++] = (*to) ? *to++ : (char) 0;
+
+ while (*src) {
+ sch = *src++;
+ dch = mapvec[sch];
+ while (dch != sch) {
+ sch = dch;
+ dch = mapvec[sch];
+ }
+ if (*dest = dch)
+ dest++;
+ }
+ /*
+ * restore all the changed characters
+ */
+ while (*tmp) {
+ mapvec[*tmp] = *tmp;
+ tmp++;
+ }
+ }
+ *dest = (char) 0;
+}
diff --git a/usr.bin/m4/expr.c b/usr.bin/m4/expr.c
new file mode 100644
index 0000000..4b98e01
--- /dev/null
+++ b/usr.bin/m4/expr.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)expr.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <stdio.h>
+
+/*
+ * expression evaluator: performs a standard recursive
+ * descent parse to evaluate any expression permissible
+ * within the following grammar:
+ *
+ * expr : query EOS
+ * query : lor
+ * | lor "?" query ":" query
+ * lor : land { "||" land }
+ * land : not { "&&" not }
+ * not : eqrel
+ * | '!' not
+ * eqrel : shift { eqrelop shift }
+ * shift : primary { shop primary }
+ * primary : term { addop term }
+ * term : exp { mulop exp }
+ * exp : unary { expop unary }
+ * unary : factor
+ * | unop unary
+ * factor : constant
+ * | "(" query ")"
+ * constant: num
+ * | "'" CHAR "'"
+ * num : DIGIT
+ * | DIGIT num
+ * shop : "<<"
+ * | ">>"
+ * eqrel : "="
+ * | "=="
+ * | "!="
+ * | "<"
+ * | ">"
+ * | "<="
+ * | ">="
+ *
+ *
+ * This expression evaluator is lifted from a public-domain
+ * C Pre-Processor included with the DECUS C Compiler distribution.
+ * It is hacked somewhat to be suitable for m4.
+ *
+ * Originally by: Mike Lutz
+ * Bob Harper
+ */
+
+#define TRUE 1
+#define FALSE 0
+#define EOS (char) 0
+#define EQL 0
+#define NEQ 1
+#define LSS 2
+#define LEQ 3
+#define GTR 4
+#define GEQ 5
+#define OCTAL 8
+#define DECIMAL 10
+
+static char *nxtch; /* Parser scan pointer */
+
+static int query __P((void));
+static int lor __P((void));
+static int land __P((void));
+static int not __P((void));
+static int eqrel __P((void));
+static int shift __P((void));
+static int primary __P((void));
+static int term __P((void));
+static int exp __P((void));
+static int unary __P((void));
+static int factor __P((void));
+static int constant __P((void));
+static int num __P((void));
+static int geteqrel __P((void));
+static int skipws __P((void));
+static void experr __P((char *));
+
+/*
+ * For longjmp
+ */
+#include <setjmp.h>
+static jmp_buf expjump;
+
+/*
+ * macros:
+ * ungetch - Put back the last character examined.
+ * getch - return the next character from expr string.
+ */
+#define ungetch() nxtch--
+#define getch() *nxtch++
+
+int
+expr(expbuf)
+char *expbuf;
+{
+ register int rval;
+
+ nxtch = expbuf;
+ if (setjmp(expjump) != 0)
+ return FALSE;
+
+ rval = query();
+ if (skipws() == EOS)
+ return rval;
+
+ printf("m4: ill-formed expression.\n");
+ return FALSE;
+}
+
+/*
+ * query : lor | lor '?' query ':' query
+ */
+static int
+query()
+{
+ register int bool, true_val, false_val;
+
+ bool = lor();
+ if (skipws() != '?') {
+ ungetch();
+ return bool;
+ }
+
+ true_val = query();
+ if (skipws() != ':')
+ experr("bad query");
+
+ false_val = query();
+ return bool ? true_val : false_val;
+}
+
+/*
+ * lor : land { '||' land }
+ */
+static int
+lor()
+{
+ register int c, vl, vr;
+
+ vl = land();
+ while ((c = skipws()) == '|') {
+ if (getch() != '|')
+ ungetch();
+ vr = land();
+ vl = vl || vr;
+ }
+
+ ungetch();
+ return vl;
+}
+
+/*
+ * land : not { '&&' not }
+ */
+static int
+land()
+{
+ register int c, vl, vr;
+
+ vl = not();
+ while ((c = skipws()) == '&') {
+ if (getch() != '&')
+ ungetch();
+ vr = not();
+ vl = vl && vr;
+ }
+
+ ungetch();
+ return vl;
+}
+
+/*
+ * not : eqrel | '!' not
+ */
+static int
+not()
+{
+ register int val, c;
+
+ if ((c = skipws()) == '!' && getch() != '=') {
+ ungetch();
+ val = not();
+ return !val;
+ }
+
+ if (c == '!')
+ ungetch();
+ ungetch();
+ return eqrel();
+}
+
+/*
+ * eqrel : shift { eqrelop shift }
+ */
+static int
+eqrel()
+{
+ register int vl, vr, eqrel;
+
+ vl = shift();
+ while ((eqrel = geteqrel()) != -1) {
+ vr = shift();
+
+ switch (eqrel) {
+
+ case EQL:
+ vl = (vl == vr);
+ break;
+ case NEQ:
+ vl = (vl != vr);
+ break;
+
+ case LEQ:
+ vl = (vl <= vr);
+ break;
+ case LSS:
+ vl = (vl < vr);
+ break;
+ case GTR:
+ vl = (vl > vr);
+ break;
+ case GEQ:
+ vl = (vl >= vr);
+ break;
+ }
+ }
+ return vl;
+}
+
+/*
+ * shift : primary { shop primary }
+ */
+static int
+shift()
+{
+ register int vl, vr, c;
+
+ vl = primary();
+ while (((c = skipws()) == '<' || c == '>') && getch() == c) {
+ vr = primary();
+
+ if (c == '<')
+ vl <<= vr;
+ else
+ vl >>= vr;
+ }
+
+ if (c == '<' || c == '>')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * primary : term { addop term }
+ */
+static int
+primary()
+{
+ register int c, vl, vr;
+
+ vl = term();
+ while ((c = skipws()) == '+' || c == '-') {
+ vr = term();
+
+ if (c == '+')
+ vl += vr;
+ else
+ vl -= vr;
+ }
+
+ ungetch();
+ return vl;
+}
+
+/*
+ * <term> := <exp> { <mulop> <exp> }
+ */
+static int
+term()
+{
+ register int c, vl, vr;
+
+ vl = exp();
+ while ((c = skipws()) == '*' || c == '/' || c == '%') {
+ vr = exp();
+
+ switch (c) {
+ case '*':
+ vl *= vr;
+ break;
+ case '/':
+ vl /= vr;
+ break;
+ case '%':
+ vl %= vr;
+ break;
+ }
+ }
+ ungetch();
+ return vl;
+}
+
+/*
+ * <term> := <unary> { <expop> <unary> }
+ */
+static int
+exp()
+{
+ register c, vl, vr, n;
+
+ vl = unary();
+ switch (c = skipws()) {
+
+ case '*':
+ if (getch() != '*') {
+ ungetch();
+ break;
+ }
+
+ case '^':
+ vr = exp();
+ n = 1;
+ while (vr-- > 0)
+ n *= vl;
+ return n;
+ }
+
+ ungetch();
+ return vl;
+}
+
+/*
+ * unary : factor | unop unary
+ */
+static int
+unary()
+{
+ register int val, c;
+
+ if ((c = skipws()) == '+' || c == '-' || c == '~') {
+ val = unary();
+
+ switch (c) {
+ case '+':
+ return val;
+ case '-':
+ return -val;
+ case '~':
+ return ~val;
+ }
+ }
+
+ ungetch();
+ return factor();
+}
+
+/*
+ * factor : constant | '(' query ')'
+ */
+static int
+factor()
+{
+ register int val;
+
+ if (skipws() == '(') {
+ val = query();
+ if (skipws() != ')')
+ experr("bad factor");
+ return val;
+ }
+
+ ungetch();
+ return constant();
+}
+
+/*
+ * constant: num | 'char'
+ * Note: constant() handles multi-byte constants
+ */
+static int
+constant()
+{
+ register int i;
+ register int value;
+ register char c;
+ int v[sizeof(int)];
+
+ if (skipws() != '\'') {
+ ungetch();
+ return num();
+ }
+ for (i = 0; i < sizeof(int); i++) {
+ if ((c = getch()) == '\'') {
+ ungetch();
+ break;
+ }
+ if (c == '\\') {
+ switch (c = getch()) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ungetch();
+ c = num();
+ break;
+ case 'n':
+ c = 012;
+ break;
+ case 'r':
+ c = 015;
+ break;
+ case 't':
+ c = 011;
+ break;
+ case 'b':
+ c = 010;
+ break;
+ case 'f':
+ c = 014;
+ break;
+ }
+ }
+ v[i] = c;
+ }
+ if (i == 0 || getch() != '\'')
+ experr("illegal character constant");
+ for (value = 0; --i >= 0;) {
+ value <<= 8;
+ value += v[i];
+ }
+ return value;
+}
+
+/*
+ * num : digit | num digit
+ */
+static int
+num()
+{
+ register int rval, c, base;
+ int ndig;
+
+ base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
+ rval = 0;
+ ndig = 0;
+ while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
+ rval *= base;
+ rval += (c - '0');
+ c = getch();
+ ndig++;
+ }
+ ungetch();
+
+ if (ndig == 0)
+ experr("bad constant");
+
+ return rval;
+
+}
+
+/*
+ * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
+ */
+static int
+geteqrel()
+{
+ register int c1, c2;
+
+ c1 = skipws();
+ c2 = getch();
+
+ switch (c1) {
+
+ case '=':
+ if (c2 != '=')
+ ungetch();
+ return EQL;
+
+ case '!':
+ if (c2 == '=')
+ return NEQ;
+ ungetch();
+ ungetch();
+ return -1;
+
+ case '<':
+ if (c2 == '=')
+ return LEQ;
+ ungetch();
+ return LSS;
+
+ case '>':
+ if (c2 == '=')
+ return GEQ;
+ ungetch();
+ return GTR;
+
+ default:
+ ungetch();
+ ungetch();
+ return -1;
+ }
+}
+
+/*
+ * Skip over any white space and return terminating char.
+ */
+static int
+skipws()
+{
+ register char c;
+
+ while ((c = getch()) <= ' ' && c > EOS)
+ ;
+ return c;
+}
+
+/*
+ * resets environment to eval(), prints an error
+ * and forces eval to return FALSE.
+ */
+static void
+experr(msg)
+char *msg;
+{
+ printf("m4: %s in expr.\n", msg);
+ longjmp(expjump, -1);
+}
diff --git a/usr.bin/m4/extern.h b/usr.bin/m4/extern.h
new file mode 100644
index 0000000..a8df3eb
--- /dev/null
+++ b/usr.bin/m4/extern.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+char *basename __P((char *));
+char *xalloc __P((unsigned long));
+int expr __P((char *));
+ndptr addent __P((char *));
+void chrsave __P((int));
+void dochc __P((char *[], int));
+void dochq __P((char *[], int));
+void dodefine __P((char *, char *));
+void dodefn __P((char *));
+void dodiv __P((int));
+void dodump __P((char *[], int));
+void doifelse __P((char *[], int));
+int doincl __P((char *));
+int dopaste __P((char *));
+void dopushdef __P((char *, char *));
+void dosub __P((char *[], int));
+void doundiv __P((char *[], int));
+void eval __P((char *[], int, int));
+void expand __P((char *[], int));
+void getdiv __P((int));
+char *xstrdup __P((const char *));
+int hash __P((char *));
+int indx __P((char *, char *));
+void killdiv __P((void));
+ndptr lookup __P((char *));
+void map __P((char *, char *, char *, char *));
+void onintr __P((int));
+void oops __P((const char *, ...));
+void pbnum __P((int));
+void pbstr __P((unsigned char *));
+void putback __P((int));
+void remhash __P((char *, int));
+void usage __P((void));
+
+extern ndptr hashtab[]; /* hash table for macros etc. */
+extern stae mstack[]; /* stack of m4 machine */
+extern FILE *active; /* active output file pointer */
+extern FILE *infile[]; /* input file stack (0=stdin) */
+extern FILE *outfile[]; /* diversion array(0=bitbucket) */
+extern int fp; /* m4 call frame pointer */
+extern int ilevel; /* input file stack pointer */
+extern int oindex; /* diversion index. */
+extern int sp; /* current m4 stack pointer */
+extern unsigned char *bp; /* first available character */
+extern unsigned char buf[]; /* push-back buffer */
+extern unsigned char *bufbase; /* buffer base for this ilevel */
+extern unsigned char *bbase[]; /* buffer base per ilevel */
+extern char ecommt; /* end character for comment */
+extern char *endest; /* end of string space */
+extern unsigned char *endpbb; /* end of push-back buffer */
+extern char *ep; /* first free char in strspace */
+extern char lquote; /* left quote character (`) */
+extern char *m4temp; /* filename for diversions */
+extern char *m4wraps; /* m4wrap string default. */
+extern char *null; /* as it says.. just a null. */
+extern char *progname; /* program name */
+extern char rquote; /* right quote character (') */
+extern char scommt; /* start character for comment */
diff --git a/usr.bin/m4/look.c b/usr.bin/m4/look.c
new file mode 100644
index 0000000..3635e1b
--- /dev/null
+++ b/usr.bin/m4/look.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * look.c
+ * Facility: m4 macro processor
+ * by: oz
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+
+int
+hash(name)
+register char *name;
+{
+ register unsigned long h = 0;
+ while (*name)
+ h = (h << 5) + h + *name++;
+ return (h % HASHSIZE);
+}
+
+/*
+ * find name in the hash table
+ */
+ndptr
+lookup(name)
+char *name;
+{
+ register ndptr p;
+
+ for (p = hashtab[hash(name)]; p != nil; p = p->nxtptr)
+ if (STREQ(name, p->name))
+ break;
+ return (p);
+}
+
+/*
+ * hash and create an entry in the hash table.
+ * The new entry is added in front of a hash bucket.
+ */
+ndptr
+addent(name)
+char *name;
+{
+ register int h;
+ ndptr p;
+
+ h = hash(name);
+ p = (ndptr) xalloc(sizeof(struct ndblock));
+ p->nxtptr = hashtab[h];
+ hashtab[h] = p;
+ p->name = xstrdup(name);
+ return p;
+}
+
+static void
+freent(p)
+ndptr p;
+{
+ if (!(p->type & STATIC)) {
+ free((char *) p->name);
+ if (p->defn != null)
+ free((char *) p->defn);
+ }
+ free((char *) p);
+}
+
+/*
+ * remove an entry from the hashtable
+ */
+void
+remhash(name, all)
+char *name;
+int all;
+{
+ register int h;
+ register ndptr xp, tp, mp;
+
+ h = hash(name);
+ mp = hashtab[h];
+ tp = nil;
+ while (mp != nil) {
+ if (STREQ(mp->name, name)) {
+ mp = mp->nxtptr;
+ if (tp == nil) {
+ freent(hashtab[h]);
+ hashtab[h] = mp;
+ }
+ else {
+ xp = tp->nxtptr;
+ tp->nxtptr = mp;
+ freent(xp);
+ }
+ if (!all)
+ break;
+ }
+ else {
+ tp = mp;
+ mp = mp->nxtptr;
+ }
+ }
+}
diff --git a/usr.bin/m4/m4.1 b/usr.bin/m4/m4.1
new file mode 100644
index 0000000..ef2e658
--- /dev/null
+++ b/usr.bin/m4/m4.1
@@ -0,0 +1,181 @@
+.\"
+.\" @(#) $Id$
+.\"
+.Dd January 26, 1993
+.Dt m4 1
+.Os
+.Sh NAME
+.Nm m4
+.Nd macro language processor
+.Sh SYNOPSIS
+.Nm m4
+.Oo
+.Fl D Ns Ar name Ns Op Ar =value
+.Oc
+.Op Fl U Ns Ar name
+.Op Ar filename
+\|.\|.\|.
+.Sh DESCRIPTION
+The
+.Nm m4
+utility is a macro processor that can be used as a front end to any
+language (e.g., C, ratfor, fortran, lex, and yacc).
+Each of the argument files is processed in order.
+If there are no files, or if a filename is \`-\', the standard input is read.
+The processed text is sent to the standard output.
+.Pp
+Macro calls have the form name(argument1[, argument2, ...,] argumentN).
+.Pp
+There cannot be any space following the macro name and the open
+parentheses '('. If the macro name is not followed by an open
+parentheses it is processed with no arguments.
+.Pp
+Macro names consist of a leading alphabetic or underscore
+possibly followed by alphanumeric or underscore characters, therefore
+valid macro names match this pattern [a-zA-Z_][a-zA-Z0-9_]*.
+.Pp
+In arguments to macros, leading unquoted space, tab and newline
+characters are ignored. To quote strings use left and right single
+quotes (e.g., ` this is a string with a leading space'). You can change
+the quote characters with the changequote built-in macro.
+.Pp
+The options are as follows:
+.Bl -tag -width "-Dname[=value]xxx"
+.It Fl D Ns Ar name Ns Oo
+.Ar =value
+.Oc
+Define the symbol
+.Ar name
+to have some value (or NULL).
+.It Fl "U" Ns Ar "name"
+Undefine the symbol
+.Ar name .
+.El
+.Sh SYNTAX
+.Nm m4
+provides the following built-in macros. They may be
+redefined, loosing their original meaning.
+Return values are NULL unless otherwise stated.
+.Bl -tag -width changequotexxx
+.It changecom
+Change the start and end comment sequences. The default is
+the pound sign `#' and the newline character. With no arguments
+comments are turned off. The maximum length for a comment marker is
+five characters.
+.It changequote
+Defines the quote symbols to be the first and second arguments.
+The symbols may be up to five characters long. If no arguments are
+given it restores the default open and close single quotes.
+.It decr
+Decrements the argument by 1. The argument must be a valid numeric string.
+.It define
+Define a new macro named by the first argument to have the
+value of the second argument. Each occurrence of $n (where n
+is 0 through 9) is replaced by the n'th argument. $0 is the name
+of the calling macro. Undefined arguments are replaced by a
+NULL string. $# is replaced by the number of arguments; $*
+is replaced by all arguments comma separated; $@ is the same
+as $* but all arguments are quoted against further expansion.
+.It defn
+Returns the quoted definition for each argument. This can be used to rename
+macro definitions (even for built-in macros).
+.It divert
+There are 10 output queues (numbered 0-9).
+At the end of processing
+.Nm m4
+concatenates all the queues in numerical order to produce the
+final output. Initially the output queue is 0. The divert
+macro allows you to select a new output queue (an invalid argument
+passed to divert causes output to be discarded).
+.It divnum
+Returns the current output queue number.
+.It dnl
+Discard input characters up to and including the next newline.
+.It dumpdef
+Prints the names and definitions for the named items, or for everything
+if no arguments are passed.
+.It errprint
+Prints the first argument on the standard error output stream.
+.It eval
+Computes the first argument as an arithmetic expression using 32-bit
+arithmetic. Operators are the standard C ternary, arithmetic, logical,
+shift, relational, bitwise, and parentheses operators. You can specify
+octal, decimal, and hexadecimal numbers as in C. The second argument (if
+any) specifies the radix for the result and the third argument (if
+any) specifies the minimum number of digits in the result.
+.It expr
+This is an alias for eval.
+.It ifdef
+If the macro named by the first argument is defined then return the second
+argument, otherwise the third. If there is no third argument,
+the value is NULL. The word `unix' is predefined.
+.It ifelse
+If the first argument matches the second argument then ifelse returns
+the third argument. If the match fails the three arguments are
+discarded and the next three arguments are used until there is
+zero or one arguments left, either this last argument or NULL is
+returned if no other matches were found.
+.It include
+Returns the contents of the file specified in the first argument.
+Include aborts with an error message if the file cannot be included.
+.It incr
+Increments the argument by 1. The argument must be a valid numeric string.
+.It index
+Returns the index of the second argument in the first argument (e.g.,
+index(the quick brown fox jumped, fox) returns 16). If the second
+argument is not found index returns -1.
+.It len
+Returns the number of characters in the first argument. Extra arguments
+are ignored.
+.It m4exit
+Immediately exits with the return value specified by the first argument,
+0 if none.
+.It m4wrap
+Allows you to define what happens at the final EOF, usually for cleanup
+purposes (e.g., m4wrap("cleanup(tempfile)") causes the macro cleanup to
+invoked after all other processing is done.)
+.It maketemp
+Translates the string XXXXX in the first argument with the current process
+ID leaving other characters alone. This can be used to create unique
+temporary file names.
+.It paste
+Includes the contents of the file specified by the first argument without
+any macro processing. Aborts with an error message if the file cannot be
+included.
+.It popdef
+Restores the pushdef'ed definition for each argument.
+.It pushdef
+Takes the same arguments as define, but it saves the definition on a
+stack for later retrieval by popdef.
+.It shift
+Returns all but the first argument, the remaining arguments are
+quoted and pushed back with commas in between. The quoting
+nullifies the effect of the extra scan that will subsequently be
+performed.
+.It sinclude
+Similar to include, except it ignores any errors.
+.It spaste
+Similar to paste, except it ignores any errors.
+.It substr
+Returns a substring of the first argument starting at the offset specified
+by the second argument and the length specified by the third argument.
+If no third argument is present it returns the rest of the string.
+.It syscmd
+Passes the first argument to the shell. Nothing is returned.
+.It sysval
+Returns the return value from the last syscmd.
+.It translit
+Transliterate the characters in the first argument from the set
+given by the second argument to the set given by the third. You cannot
+use
+.Xr tr 1
+style abbreviations.
+.It undefine
+Removes the definition for the macro specified by the first argument.
+.It undivert
+Flushes the named output queues (or all queues if no arguments).
+.It unix
+A pre-defined macro for testing the OS platform.
+.El
+.Sh AUTHOR
+Ozan Yigit <oz@sis.yorku.ca> and Richard A. O'Keefe (ok@goanna.cs.rmit.OZ.AU)
diff --git a/usr.bin/m4/main.c b/usr.bin/m4/main.c
new file mode 100644
index 0000000..ca42301
--- /dev/null
+++ b/usr.bin/m4/main.c
@@ -0,0 +1,425 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * main.c
+ * Facility: m4 macro processor
+ * by: oz
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+#include "pathnames.h"
+
+ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
+unsigned char buf[BUFSIZE]; /* push-back buffer */
+unsigned char *bufbase = buf; /* the base for current ilevel */
+unsigned char *bbase[MAXINP]; /* the base for each ilevel */
+unsigned char *bp = buf; /* first available character */
+unsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
+stae mstack[STACKMAX+1]; /* stack of m4 machine */
+char strspace[STRSPMAX+1]; /* string space for evaluation */
+char *ep = strspace; /* first free char in strspace */
+char *endest= strspace+STRSPMAX;/* end of string space */
+int sp; /* current m4 stack pointer */
+int fp; /* m4 call frame pointer */
+FILE *infile[MAXINP]; /* input file stack (0=stdin) */
+FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
+FILE *active; /* active output file pointer */
+char *m4temp; /* filename for diversions */
+int ilevel = 0; /* input file stack pointer */
+int oindex = 0; /* diversion index.. */
+char *null = ""; /* as it says.. just a null.. */
+char *m4wraps = ""; /* m4wrap string default.. */
+char *progname; /* name of this program */
+char lquote = LQUOTE; /* left quote character (`) */
+char rquote = RQUOTE; /* right quote character (') */
+char scommt = SCOMMT; /* start character for comment */
+char ecommt = ECOMMT; /* end character for comment */
+
+struct keyblk keywrds[] = { /* m4 keywords to be installed */
+ "include", INCLTYPE,
+ "sinclude", SINCTYPE,
+ "define", DEFITYPE,
+ "defn", DEFNTYPE,
+ "divert", DIVRTYPE,
+ "expr", EXPRTYPE,
+ "eval", EXPRTYPE,
+ "substr", SUBSTYPE,
+ "ifelse", IFELTYPE,
+ "ifdef", IFDFTYPE,
+ "len", LENGTYPE,
+ "incr", INCRTYPE,
+ "decr", DECRTYPE,
+ "dnl", DNLNTYPE,
+ "changequote", CHNQTYPE,
+ "changecom", CHNCTYPE,
+ "index", INDXTYPE,
+#ifdef EXTENDED
+ "paste", PASTTYPE,
+ "spaste", SPASTYPE,
+#endif
+ "popdef", POPDTYPE,
+ "pushdef", PUSDTYPE,
+ "dumpdef", DUMPTYPE,
+ "shift", SHIFTYPE,
+ "translit", TRNLTYPE,
+ "undefine", UNDFTYPE,
+ "undivert", UNDVTYPE,
+ "divnum", DIVNTYPE,
+ "maketemp", MKTMTYPE,
+ "errprint", ERRPTYPE,
+ "m4wrap", M4WRTYPE,
+ "m4exit", EXITTYPE,
+ "syscmd", SYSCTYPE,
+ "sysval", SYSVTYPE,
+
+#ifdef unix
+ "unix", MACRTYPE,
+#else
+#ifdef vms
+ "vms", MACRTYPE,
+#endif
+#endif
+};
+
+#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
+
+extern int optind;
+extern char *optarg;
+
+void macro();
+void initkwds();
+extern int getopt();
+
+int
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ register int c;
+ register int n;
+ char *p;
+ register FILE *ifp;
+
+ progname = basename(argv[0]);
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, onintr);
+
+ initkwds();
+
+ while ((c = getopt(argc, argv, "tD:U:o:")) != -1)
+ switch(c) {
+
+ case 'D': /* define something..*/
+ for (p = optarg; *p; p++)
+ if (*p == '=')
+ break;
+ if (*p)
+ *p++ = EOS;
+ dodefine(optarg, p);
+ break;
+ case 'U': /* undefine... */
+ remhash(optarg, TOP);
+ break;
+ case 'o': /* specific output */
+ case '?':
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ active = stdout; /* default active output */
+ /* filename for diversions */
+ m4temp = mktemp(xstrdup(_PATH_DIVNAME));
+
+ bbase[0] = bufbase;
+ if (!argc) {
+ sp = -1; /* stack pointer initialized */
+ fp = 0; /* frame pointer initialized */
+ infile[0] = stdin; /* default input (naturally) */
+ macro();
+ } else
+ for (; argc--; ++argv) {
+ p = *argv;
+ if (p[0] == '-' && p[1] == '\0')
+ ifp = stdin;
+ else if ((ifp = fopen(p, "r")) == NULL)
+ oops("%s: %s", p, strerror(errno));
+ sp = -1;
+ fp = 0;
+ infile[0] = ifp;
+ macro();
+ if (ifp != stdin)
+ (void)fclose(ifp);
+ }
+
+ if (*m4wraps) { /* anything for rundown ?? */
+ ilevel = 0; /* in case m4wrap includes.. */
+ bufbase = bp = buf; /* use the entire buffer */
+ putback(EOF); /* eof is a must !! */
+ pbstr(m4wraps); /* user-defined wrapup act */
+ macro(); /* last will and testament */
+ }
+
+ if (active != stdout)
+ active = stdout; /* reset output just in case */
+ for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */
+ if (outfile[n] != NULL)
+ getdiv(n);
+ /* remove bitbucket if used */
+ if (outfile[0] != NULL) {
+ (void) fclose(outfile[0]);
+ m4temp[UNIQUE] = '0';
+#ifdef vms
+ (void) remove(m4temp);
+#else
+ (void) unlink(m4temp);
+#endif
+ }
+
+ return 0;
+}
+
+ndptr inspect();
+
+/*
+ * macro - the work horse..
+ */
+void
+macro() {
+ char token[MAXTOK];
+ register char *s;
+ register int t, l;
+ register ndptr p;
+ register int nlpar;
+
+ cycle {
+ if ((t = gpbc()) == '_' || (t != EOF && isalpha(t))) {
+ putback(t);
+ if ((p = inspect(s = token)) == nil) {
+ if (sp < 0)
+ while (*s)
+ putc(*s++, active);
+ else
+ while (*s)
+ chrsave(*s++);
+ }
+ else {
+ /*
+ * real thing.. First build a call frame:
+ */
+ pushf(fp); /* previous call frm */
+ pushf(p->type); /* type of the call */
+ pushf(0); /* parenthesis level */
+ fp = sp; /* new frame pointer */
+ /*
+ * now push the string arguments:
+ */
+ pushs(p->defn); /* defn string */
+ pushs(p->name); /* macro name */
+ pushs(ep); /* start next..*/
+
+ putback(l = gpbc());
+ if (l != LPAREN) { /* add bracks */
+ putback(RPAREN);
+ putback(LPAREN);
+ }
+ }
+ }
+ else if (t == EOF) {
+ if (sp > -1)
+ oops("unexpected end of input", "");
+ if (ilevel <= 0)
+ break; /* all done thanks.. */
+ --ilevel;
+ (void) fclose(infile[ilevel+1]);
+ bufbase = bbase[ilevel];
+ continue;
+ }
+ /*
+ * non-alpha single-char token seen..
+ * [the order of else if .. stmts is important.]
+ */
+ else if (t == lquote) { /* strip quotes */
+ nlpar = 1;
+ do {
+ if ((l = gpbc()) == rquote)
+ nlpar--;
+ else if (l == lquote)
+ nlpar++;
+ else if (l == EOF)
+ oops("missing right quote", "");
+ if (nlpar > 0) {
+ if (sp < 0)
+ putc(l, active);
+ else
+ chrsave(l);
+ }
+ }
+ while (nlpar != 0);
+ }
+
+ else if (sp < 0) { /* not in a macro at all */
+ if (t == scommt) { /* comment handling here */
+ putc(t, active);
+ while ((t = gpbc()) != ecommt)
+ putc(t, active);
+ }
+ putc(t, active); /* output directly.. */
+ }
+
+ else switch(t) {
+
+ case LPAREN:
+ if (PARLEV > 0)
+ chrsave(t);
+ while ((l = gpbc()) != EOF && isspace(l))
+ ; /* skip blank, tab, nl.. */
+ putback(l);
+ PARLEV++;
+ break;
+
+ case RPAREN:
+ if (--PARLEV > 0)
+ chrsave(t);
+ else { /* end of argument list */
+ chrsave(EOS);
+
+ if (sp == STACKMAX)
+ oops("internal stack overflow", "");
+
+ if (CALTYP == MACRTYPE)
+ expand((char **) mstack+fp+1, sp-fp);
+ else
+ eval((char **) mstack+fp+1, sp-fp, CALTYP);
+
+ ep = PREVEP; /* flush strspace */
+ sp = PREVSP; /* previous sp.. */
+ fp = PREVFP; /* rewind stack...*/
+ }
+ break;
+
+ case COMMA:
+ if (PARLEV == 1) {
+ chrsave(EOS); /* new argument */
+ while ((l = gpbc()) != EOF && isspace(l))
+ ;
+ putback(l);
+ pushs(ep);
+ } else
+ chrsave(t);
+ break;
+
+ default:
+ chrsave(t); /* stack the char */
+ break;
+ }
+ }
+}
+
+/*
+ * build an input token..
+ * consider only those starting with _ or A-Za-z. This is a
+ * combo with lookup to speed things up.
+ */
+ndptr
+inspect(tp)
+register char *tp;
+{
+ register int c;
+ register char *name = tp;
+ register char *etp = tp+MAXTOK;
+ register ndptr p;
+ register unsigned long h = 0;
+
+ while ((c = gpbc()) != EOF && (isalnum(c) || c == '_') && tp < etp)
+ h = (h << 5) + h + (*tp++ = c);
+ putback(c);
+ if (tp == etp)
+ oops("token too long", "");
+
+ *tp = EOS;
+
+ for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
+ if (STREQ(name, p->name))
+ break;
+ return p;
+}
+
+/*
+ * initkwds - initialise m4 keywords as fast as possible.
+ * This very similar to install, but without certain overheads,
+ * such as calling lookup. Malloc is not used for storing the
+ * keyword strings, since we simply use the static pointers
+ * within keywrds block.
+ */
+void
+initkwds() {
+ register int i;
+ register int h;
+ register ndptr p;
+
+ for (i = 0; i < MAXKEYS; i++) {
+ h = hash(keywrds[i].knam);
+ p = (ndptr) xalloc(sizeof(struct ndblock));
+ p->nxtptr = hashtab[h];
+ hashtab[h] = p;
+ p->name = keywrds[i].knam;
+ p->defn = null;
+ p->type = keywrds[i].ktyp | STATIC;
+ }
+}
diff --git a/usr.bin/m4/mdef.h b/usr.bin/m4/mdef.h
new file mode 100644
index 0000000..dd23bde
--- /dev/null
+++ b/usr.bin/m4/mdef.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mdef.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define MACRTYPE 1
+#define DEFITYPE 2
+#define EXPRTYPE 3
+#define SUBSTYPE 4
+#define IFELTYPE 5
+#define LENGTYPE 6
+#define CHNQTYPE 7
+#define SYSCTYPE 8
+#define UNDFTYPE 9
+#define INCLTYPE 10
+#define SINCTYPE 11
+#define PASTTYPE 12
+#define SPASTYPE 13
+#define INCRTYPE 14
+#define IFDFTYPE 15
+#define PUSDTYPE 16
+#define POPDTYPE 17
+#define SHIFTYPE 18
+#define DECRTYPE 19
+#define DIVRTYPE 20
+#define UNDVTYPE 21
+#define DIVNTYPE 22
+#define MKTMTYPE 23
+#define ERRPTYPE 24
+#define M4WRTYPE 25
+#define TRNLTYPE 26
+#define DNLNTYPE 27
+#define DUMPTYPE 28
+#define CHNCTYPE 29
+#define INDXTYPE 30
+#define SYSVTYPE 31
+#define EXITTYPE 32
+#define DEFNTYPE 33
+
+#define STATIC 128
+
+/*
+ * m4 special characters
+ */
+
+#define ARGFLAG '$'
+#define LPAREN '('
+#define RPAREN ')'
+#define LQUOTE '`'
+#define RQUOTE '\''
+#define COMMA ','
+#define SCOMMT '#'
+#define ECOMMT '\n'
+
+#ifdef msdos
+#define system(str) (-1)
+#endif
+
+/*
+ * other important constants
+ */
+
+#define EOS (char) 0
+#define MAXINP 10 /* maximum include files */
+#define MAXOUT 10 /* maximum # of diversions */
+#define MAXSTR 512 /* maximum size of string */
+#define BUFSIZE 4096 /* size of pushback buffer */
+#define STACKMAX 1024 /* size of call stack */
+#define STRSPMAX 4096 /* size of string space */
+#define MAXTOK MAXSTR /* maximum chars in a tokn */
+#define HASHSIZE 199 /* maximum size of hashtab */
+
+#define ALL 1
+#define TOP 0
+
+#define TRUE 1
+#define FALSE 0
+#define cycle for(;;)
+
+/*
+ * m4 data structures
+ */
+
+typedef struct ndblock *ndptr;
+
+struct ndblock { /* hastable structure */
+ char *name; /* entry name.. */
+ char *defn; /* definition.. */
+ int type; /* type of the entry.. */
+ ndptr nxtptr; /* link to next entry.. */
+};
+
+#define nil ((ndptr) 0)
+
+struct keyblk {
+ char *knam; /* keyword name */
+ int ktyp; /* keyword type */
+};
+
+typedef union { /* stack structure */
+ int sfra; /* frame entry */
+ char *sstr; /* string entry */
+} stae;
+
+/*
+ * macros for readibility and/or speed
+ *
+ * gpbc() - get a possibly pushed-back character
+ * pushf() - push a call frame entry onto stack
+ * pushs() - push a string pointer onto stack
+ */
+#define gpbc() (bp > bufbase) ? (*--bp ? *bp : EOF) : getc(infile[ilevel])
+#define pushf(x) if (sp < STACKMAX) mstack[++sp].sfra = (x)
+#define pushs(x) if (sp < STACKMAX) mstack[++sp].sstr = (x)
+
+/*
+ * . .
+ * | . | <-- sp | . |
+ * +-------+ +-----+
+ * | arg 3 ----------------------->| str |
+ * +-------+ | . |
+ * | arg 2 ---PREVEP-----+ .
+ * +-------+ |
+ * . | | |
+ * +-------+ | +-----+
+ * | plev | PARLEV +-------->| str |
+ * +-------+ | . |
+ * | type | CALTYP .
+ * +-------+
+ * | prcf ---PREVFP--+
+ * +-------+ |
+ * | . | PREVSP |
+ * . |
+ * +-------+ |
+ * | <----------+
+ * +-------+
+ *
+ */
+#define PARLEV (mstack[fp].sfra)
+#define CALTYP (mstack[fp-1].sfra)
+#define PREVEP (mstack[fp+3].sstr)
+#define PREVSP (fp-3)
+#define PREVFP (mstack[fp-2].sfra)
diff --git a/usr.bin/m4/misc.c b/usr.bin/m4/misc.c
new file mode 100644
index 0000000..5f12e47
--- /dev/null
+++ b/usr.bin/m4/misc.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+#include "pathnames.h"
+
+/*
+ * find the index of second str in the first str.
+ */
+int
+indx(s1, s2)
+char *s1;
+char *s2;
+{
+ register char *t;
+ register char *p;
+ register char *m;
+
+ for (p = s1; *p; p++) {
+ for (t = p, m = s2; *m && *m == *t; m++, t++);
+ if (!*m)
+ return (p - s1);
+ }
+ return (-1);
+}
+/*
+ * putback - push character back onto input
+ */
+void
+putback(c)
+int c;
+{
+ if (c == EOF)
+ c = 0;
+ else if (c == 0)
+ return;
+ if (bp < endpbb)
+ *bp++ = c;
+ else
+ oops("too many characters pushed back");
+}
+
+/*
+ * pbstr - push string back onto input
+ * putback is replicated to improve
+ * performance.
+ */
+void
+pbstr(s)
+register unsigned char *s;
+{
+ register unsigned char *es;
+ register unsigned char *zp;
+
+ es = s;
+ zp = bp;
+
+ while (*es)
+ es++;
+ es--;
+ while (es >= s)
+ if (zp < endpbb)
+ *zp++ = *es--;
+ if ((bp = zp) == endpbb)
+ oops("too many characters pushed back");
+}
+
+/*
+ * pbnum - convert number to string, push back on input.
+ */
+void
+pbnum(n)
+int n;
+{
+ register int num;
+
+ num = (n < 0) ? -n : n;
+ do {
+ putback(num % 10 + '0');
+ }
+ while ((num /= 10) > 0);
+
+ if (n < 0)
+ putback('-');
+}
+
+/*
+ * chrsave - put single char on string space
+ */
+void
+chrsave(c)
+char c;
+{
+ if (ep < endest)
+ *ep++ = c;
+ else
+ oops("string space overflow");
+}
+
+/*
+ * read in a diversion file, and dispose it.
+ */
+void
+getdiv(n)
+int n;
+{
+ register int c;
+ register FILE *dfil;
+
+ if (active == outfile[n])
+ oops("%s: diversion still active.", "undivert");
+ (void) fclose(outfile[n]);
+ outfile[n] = NULL;
+ m4temp[UNIQUE] = n + '0';
+ if ((dfil = fopen(m4temp, "r")) == NULL)
+ oops("%s: cannot undivert.", m4temp);
+ else
+ while ((c = getc(dfil)) != EOF)
+ putc(c, active);
+ (void) fclose(dfil);
+
+#ifdef vms
+ if (remove(m4temp))
+#else
+ if (unlink(m4temp) == -1)
+#endif
+ oops("%s: cannot unlink.", m4temp);
+}
+
+void
+onintr(signo)
+ int signo;
+{
+ oops("interrupted.");
+}
+
+/*
+ * killdiv - get rid of the diversion files
+ */
+void
+killdiv()
+{
+ register int n;
+
+ for (n = 0; n < MAXOUT; n++)
+ if (outfile[n] != NULL) {
+ (void) fclose(outfile[n]);
+ m4temp[UNIQUE] = n + '0';
+#ifdef vms
+ (void) remove(m4temp);
+#else
+ (void) unlink(m4temp);
+#endif
+ }
+}
+
+char *
+xalloc(n)
+unsigned long n;
+{
+ register char *p = malloc(n);
+
+ if (p == NULL)
+ oops("malloc: %s", strerror(errno));
+ return p;
+}
+
+char *
+xstrdup(s)
+const char *s;
+{
+ register char *p = strdup(s);
+ if (p == NULL)
+ oops("strdup: %s", strerror(errno));
+ return p;
+}
+
+char *
+basename(s)
+register char *s;
+{
+ register char *p;
+ extern char *strrchr();
+
+ if ((p = strrchr(s, '/')) == NULL)
+ return s;
+
+ return ++p;
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: m4 [-Dname[=val]] [-Uname]\n");
+ exit(1);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+oops(const char *fmt, ...)
+#else
+oops(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "%s: ", progname);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/usr.bin/m4/pathnames.h b/usr.bin/m4/pathnames.h
new file mode 100644
index 0000000..dc7f0d3
--- /dev/null
+++ b/usr.bin/m4/pathnames.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: pathnames.h,v 1.4 1997/04/04 18:41:29 deraadt Exp $ */
+/* $NetBSD: pathnames.h,v 1.6 1995/09/29 00:27:55 cgd Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Definitions of diversion files. If the name of the file is changed,
+ * adjust UNIQUE to point to the wildcard (*) character in the filename.
+ */
+
+#ifdef msdos
+#define _PATH_DIVNAME "\\M4*XXXXXX" /* msdos diversion files */
+#define UNIQUE 3 /* unique char location */
+#endif
+
+#if defined(unix) || defined(__NetBSD__) || defined(__OpenBSD__)
+#define _PATH_DIVNAME "/tmp/m4.0XXXXXXXXXX" /* unix diversion files */
+#define UNIQUE 8 /* unique char location */
+#endif
+
+#ifdef vms
+#define _PATH_DIVNAME "sys$login:m4*XXXXXX" /* vms diversion files */
+#define UNIQUE 12 /* unique char location */
+#endif
diff --git a/usr.bin/m4/stdd.h b/usr.bin/m4/stdd.h
new file mode 100644
index 0000000..8d4312e
--- /dev/null
+++ b/usr.bin/m4/stdd.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stdd.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * standard defines
+ */
+
+#define max(a,b) ((a) > (b)? (a): (b))
+#define min(a,b) ((a) < (b)? (a): (b))
+
+#define iswhite(c) ((c) == ' ' || (c) == '\t')
+
+/*
+ * STREQ is an optimised strcmp(a,b)==0
+ * STREQN is an optimised strncmp(a,b,n)==0; assumes n > 0
+ */
+#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
+#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
+
+#define YES 1
+#define NO 0
diff --git a/usr.bin/mail/Makefile b/usr.bin/mail/Makefile
index 576ce83..8724206 100644
--- a/usr.bin/mail/Makefile
+++ b/usr.bin/mail/Makefile
@@ -1,7 +1,6 @@
# @(#)Makefile 8.2 (Berkeley) 1/25/94
PROG= mail
-CFLAGS+=-R -DUSE_OLD_TTY
SRCS= version.c aux.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c edit.c fio.c \
getname.c head.c v7.local.c lex.c list.c main.c names.c popen.c \
quit.c send.c strings.c temp.c tty.c vars.c
@@ -11,9 +10,9 @@ LINKS= ${BINDIR}/mail ${BINDIR}/Mail
MLINKS= mail.1 Mail.1
beforeinstall:
- cd ${.CURDIR}/misc; install -c -o ${BINOWN} -g ${BINGRP} \
+ cd ${.CURDIR}/misc; ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} \
-m 444 ${SFILES} ${DESTDIR}/usr/share/misc
- cd ${.CURDIR}/misc; install -c -o root -g wheel \
+ cd ${.CURDIR}/misc; ${INSTALL} -c -o root -g wheel \
-m 644 ${EFILES} ${DESTDIR}/etc
.include <bsd.prog.mk>
diff --git a/usr.bin/mail/USD.doc/mail1.nr b/usr.bin/mail/USD.doc/mail1.nr
index bbb920d..50e7883 100644
--- a/usr.bin/mail/USD.doc/mail1.nr
+++ b/usr.bin/mail/USD.doc/mail1.nr
@@ -74,7 +74,7 @@ waiting in your system mailbox. If you are a
.i csh
user, you will be notified when new mail arrives if you inform
the shell of the location of your mailbox. On version 7 systems,
-your system mailbox is located in the directory /usr/spool/mail
+your system mailbox is located in the directory /var/mail
in a file with your login name. If your login name is
.q sam,
then you can make
@@ -82,7 +82,7 @@ then you can make
notify you of new mail by including the following line in your .cshrc
file:
.(l
-set mail=/usr/spool/mail/sam
+set mail=/var/mail/sam
.)l
When you read your mail using
.i Mail ,
diff --git a/usr.bin/mail/USD.doc/mail5.nr b/usr.bin/mail/USD.doc/mail5.nr
index b70ce95..87f0acf 100644
--- a/usr.bin/mail/USD.doc/mail5.nr
+++ b/usr.bin/mail/USD.doc/mail5.nr
@@ -939,7 +939,7 @@ to truncate your system mailbox instead of deleting it when it
is empty. This is useful if you elect to protect your mailbox, which
you would do with the shell command:
.(l
-chmod 600 /usr/spool/mail/yourname
+chmod 600 /var/mail/yourname
.)l
where
.i yourname
diff --git a/usr.bin/mail/USD.doc/mail6.nr b/usr.bin/mail/USD.doc/mail6.nr
index e016234..b62f8c5 100644
--- a/usr.bin/mail/USD.doc/mail6.nr
+++ b/usr.bin/mail/USD.doc/mail6.nr
@@ -74,7 +74,7 @@ mail instead of your own. Unwitting others often neglect to protect
their mailboxes, but discretion is advised. Essentially,
.b "\-u user"
is a shorthand way of doing
-.b "\-f /usr/spool/mail/user".
+.b "\-f /var/mail/user".
.ip "\-v"
Use the
.b \-v
diff --git a/usr.bin/mail/USD.doc/mail8.nr b/usr.bin/mail/USD.doc/mail8.nr
index e8e056b..b09afbd 100644
--- a/usr.bin/mail/USD.doc/mail8.nr
+++ b/usr.bin/mail/USD.doc/mail8.nr
@@ -58,7 +58,7 @@ A collection of messages. Often used in the phrase,
.q "Have you read your mail?"
.ip "\fImailbox\fP"
The place where your mail is stored, typically in the directory
-/usr/spool/mail.
+/var/mail.
.ip "\fImessage\fP"
A single letter from someone, initially stored in your
.i mailbox .
diff --git a/usr.bin/mail/aux.c b/usr.bin/mail/aux.c
index f4c2acd..f6f7211 100644
--- a/usr.bin/mail/aux.c
+++ b/usr.bin/mail/aux.c
@@ -152,7 +152,7 @@ argcount(argv)
register char **ap;
for (ap = argv; *ap++ != NOSTR;)
- ;
+ ;
return ap - argv - 1;
}
@@ -295,7 +295,9 @@ struct sstack {
FILE *s_file; /* File we were in. */
int s_cond; /* Saved state of conditionals */
int s_loading; /* Loading .mailrc, etc. */
-} sstack[NOFILE];
+};
+#define SSTACK_SIZE 64 /* XXX was NOFILE. */
+static struct sstack sstack[SSTACK_SIZE];
/*
* Pushdown current input file and switch to a new one.
@@ -315,7 +317,7 @@ source(arglist)
perror(cp);
return(1);
}
- if (ssp >= NOFILE - 1) {
+ if (ssp >= SSTACK_SIZE - 1) {
printf("Too much \"sourcing\" going on.\n");
Fclose(fi);
return(1);
diff --git a/usr.bin/mail/cmd2.c b/usr.bin/mail/cmd2.c
index abe3ca9..ed46fb3 100644
--- a/usr.bin/mail/cmd2.c
+++ b/usr.bin/mail/cmd2.c
@@ -61,7 +61,7 @@ next(msgvec)
if (*msgvec != NULL) {
/*
- * If some messages were supplied, find the
+ * If some messages were supplied, find the
* first applicable one following dot using
* wrap around.
*/
@@ -345,7 +345,7 @@ delm(msgvec)
* Undelete the indicated messages.
*/
int
-undelete(msgvec)
+undelete_messages(msgvec)
int *msgvec;
{
register struct message *mp;
diff --git a/usr.bin/mail/cmdtab.c b/usr.bin/mail/cmdtab.c
index 94e33a0..47fb3c6 100644
--- a/usr.bin/mail/cmdtab.c
+++ b/usr.bin/mail/cmdtab.c
@@ -58,7 +58,7 @@ struct cmd cmdtab[] = {
"delete", delete, W|P|MSGLIST, 0, MMNDEL,
"dp", deltype, W|MSGLIST, 0, MMNDEL,
"dt", deltype, W|MSGLIST, 0, MMNDEL,
- "undelete", undelete, P|MSGLIST, MDELETED,MMNDEL,
+ "undelete", undelete_messages, P|MSGLIST, MDELETED,MMNDEL,
"unset", unset, M|RAWLIST, 1, 1000,
"mail", sendmail, R|M|I|STRLIST, 0, 0,
"mbox", mboxit, W|MSGLIST, 0, 0,
diff --git a/usr.bin/mail/def.h b/usr.bin/mail/def.h
index f843914..6ed65a4 100644
--- a/usr.bin/mail/def.h
+++ b/usr.bin/mail/def.h
@@ -44,7 +44,7 @@
#include <sys/time.h>
#include <signal.h>
-#include <sgtty.h>
+#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -68,10 +68,10 @@
struct message {
short m_flag; /* flags, see below */
- short m_block; /* block number of this message */
short m_offset; /* offset in block of message */
+ long m_block; /* block number of this message */
long m_size; /* Bytes in the message */
- short m_lines; /* Lines in the message */
+ long m_lines; /* Lines in the message */
};
/*
diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h
index 8b1babf..508e281 100644
--- a/usr.bin/mail/extern.h
+++ b/usr.bin/mail/extern.h
@@ -239,7 +239,7 @@ void ttyint __P((int));
void ttystop __P((int));
int type __P((int *));
int type1 __P((int *, int, int));
-int undelete __P((int *));
+int undelete_messages __P((int *));
void unmark __P((int));
char **unpack __P((struct name *));
int unread __P((int []));
diff --git a/usr.bin/mail/lex.c b/usr.bin/mail/lex.c
index 3428203..2c7cb3e 100644
--- a/usr.bin/mail/lex.c
+++ b/usr.bin/mail/lex.c
@@ -458,6 +458,17 @@ lex(word)
register struct cmd *cp;
extern struct cmd cmdtab[];
+ /*
+ * ignore trailing chars after `#'
+ *
+ * lines with beginning `#' are comments
+ * spaces befor `#' are ignored in execute()
+ */
+
+ if (*word == '#')
+ *(word+1) = '\0';
+
+
for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
if (isprefix(word, cp->c_name))
return(cp);
diff --git a/usr.bin/mail/list.c b/usr.bin/mail/list.c
index 18cf1eb..9759f2d 100644
--- a/usr.bin/mail/list.c
+++ b/usr.bin/mail/list.c
@@ -319,7 +319,7 @@ number:
if ((mp->m_flag & colp->co_mask)
!= colp->co_equal)
unmark(i);
-
+
}
for (mp = &message[0]; mp < &message[msgCount]; mp++)
if (mp->m_flag & MMARK)
@@ -693,7 +693,7 @@ matchsubj(str, mesg)
else
strcpy(lastscan, str);
mp = &message[mesg-1];
-
+
/*
* Now look, ignoring case, for the word in the string.
*/
@@ -784,7 +784,7 @@ metamess(meta, f)
return(-1);
case '.':
- /*
+ /*
* Current message.
*/
m = dot - &message[0] + 1;
diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1
index ecf5868..45d5cdc 100644
--- a/usr.bin/mail/mail.1
+++ b/usr.bin/mail/mail.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)mail.1 8.2 (Berkeley) 12/30/93
+.\" $Id$
.\"
.Dd December 30, 1993
.Dt MAIL 1
@@ -77,9 +78,9 @@ In particular, the
special
character when sending mail is only active in interactive mode.
.It Fl n
-Inhibits reading
-.Pa /usr/share/misc/Mail.rc
-upon startup.
+Inhibits reading the system-wide
+.Pa mail.rc
+files upon startup.
.It Fl N
Inhibits the initial display of message headers
when reading mail or editing a mail folder.
@@ -108,7 +109,7 @@ writes undeleted messages back to this file.
.It Fl u
Is equivalent to:
.Pp
-.Dl mail -f /var/spool/mail/user
+.Dl mail -f /var/mail/user
.El
.Ss Sending mail
To send a message to one or more people,
@@ -232,7 +233,7 @@ Unexamined messages go back to the post office.
.Fl f
option above).
.Pp
-.Ss Personal and systemwide distribution lists.
+.Ss Personal and system wide distribution lists.
It is also possible to create a personal distribution lists so that,
for instance, you can send mail to
.Dq Li cohorts
@@ -308,6 +309,8 @@ argument
goes to the
.Ar n Ns 'th
previous message and prints it.
+.It Ic \&#
+ignore the remainder of the line as a comment.
.It Ic \&?
Prints a brief summary of commands.
.It Ic \&!
@@ -479,6 +482,9 @@ ignored fields.
.Pq Ic m
Takes as argument login names and distribution group names and sends
mail to those people.
+.It Ic more
+.Pq Ic \mo
+Takes a list of messages and invokes the pager on that list.
.It Ic mbox
Indicate that a list of messages be sent to
.Ic mbox
@@ -794,8 +800,9 @@ The binary options include the following:
Causes messages saved in
.Ar mbox
to be appended to the end rather than prepended.
-This should always be set (perhaps in
-.Pa /usr/share/misc/Mail.rc ) .
+This should always be set (preferably in one of the system-wide
+.Pa mail.rc
+files).
.It Ar ask
Causes
.Nm mail
@@ -982,10 +989,14 @@ utilizes the
.Ev HOME
and
.Ev USER
-environment variables.
+environment variables. Also, if the
+.Ev MAIL
+environment variable is set, it is used as the
+location of the user's mailbox instead of the
+default in /var/mail.
.Sh FILES
-.Bl -tag -width /usr/share/misc/Mail.help* -compact
-.It Pa /var/spool/mail/*
+.Bl -tag -width /usr/share/misc/mail.*help -compact
+.It Pa /var/mail/*
Post office.
.It ~/mbox
User's old mail.
@@ -993,10 +1004,14 @@ User's old mail.
File giving initial mail commands.
.It Pa /tmp/R*
Temporary files.
-.It Pa /usr/share/misc/Mail.help*
+.It Pa /usr/share/misc/mail.*help
Help files.
-.It Pa /usr/share/misc/Mail.rc
-System initialization file.
+.sp
+.It Pa /usr/share/misc/mail.rc
+.It Pa /usr/local/etc/mail.rc
+.It Pa /etc/mail.rc
+System-wide initialization files. Each file will be sourced, in order,
+if it exists.
.El
.Sh SEE ALSO
.Xr fmt 1 ,
@@ -1011,10 +1026,10 @@ and
.Re
.Sh HISTORY
A
-.Nm mail
+.Nm
command
appeared in
-.At v6 .
+.At v1 .
This man page is derived from
.%T "The Mail Reference Manual"
originally written by Kurt Shoens.
diff --git a/usr.bin/mail/main.c b/usr.bin/mail/main.c
index 1e1579b..d6499bb 100644
--- a/usr.bin/mail/main.c
+++ b/usr.bin/mail/main.c
@@ -42,6 +42,7 @@ static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "rcv.h"
+#include <err.h>
#include <fcntl.h>
#include "extern.h"
@@ -89,7 +90,7 @@ main(argc, argv)
bcc = NIL;
smopts = NIL;
subject = NOSTR;
- while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != EOF) {
+ while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != -1) {
switch (i) {
case 'T':
/*
@@ -207,8 +208,19 @@ Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
input = stdin;
rcvmode = !to;
spreserve();
- if (!nosrc)
- load(_PATH_MASTER_RC);
+ if (!nosrc) {
+ char *s, *path_rc;
+
+ path_rc = malloc(sizeof(_PATH_MASTER_RC));
+ if (path_rc == NULL)
+ errx(1, "malloc(path_rc) failed");
+
+ strcpy(path_rc, _PATH_MASTER_RC);
+ while ((s = strsep(&path_rc, ":")) != NULL)
+ if (*s != '\0')
+ load(s);
+ }
+
/*
* Expand returns a savestr, but load only uses the file name
* for fopen, so it's safe to do this.
@@ -274,16 +286,19 @@ hdrstop(signo)
void
setscreensize()
{
- struct sgttyb tbuf;
struct winsize ws;
+ struct termios tio;
+ speed_t speed = 0;
if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
ws.ws_col = ws.ws_row = 0;
- if (ioctl(1, TIOCGETP, &tbuf) < 0)
- tbuf.sg_ospeed = B9600;
- if (tbuf.sg_ospeed < B1200)
+ if (tcgetattr(1, &tio) != -1)
+ speed = cfgetospeed(&tio);
+ if (speed <= 0)
+ speed = B9600;
+ if (speed < B1200)
screenheight = 9;
- else if (tbuf.sg_ospeed == B1200)
+ else if (speed == B1200)
screenheight = 14;
else if (ws.ws_row != 0)
screenheight = ws.ws_row;
diff --git a/usr.bin/mail/misc/mail.help b/usr.bin/mail/misc/mail.help
index d5858c5..f5c5dd2 100644
--- a/usr.bin/mail/misc/mail.help
+++ b/usr.bin/mail/misc/mail.help
@@ -8,7 +8,7 @@ s <message list> file append messages to file
u <message list> undelete messages
R <message list> reply to message senders
r <message list> reply to message senders and all recipients
-pre <message list> make messages go back to /usr/spool/mail
+pre <message list> make messages go back to /var/mail
m <user list> mail to specific users
q quit, saving unresolved messages in mbox
x quit, do not remove system mailbox
diff --git a/usr.bin/mail/misc/mail.rc b/usr.bin/mail/misc/mail.rc
index 90e937a..21922d7 100644
--- a/usr.bin/mail/misc/mail.rc
+++ b/usr.bin/mail/misc/mail.rc
@@ -1,2 +1,2 @@
-set append dot save
+set append dot save ask
ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via
diff --git a/usr.bin/mail/names.c b/usr.bin/mail/names.c
index b2f8cfe..e17e9f2 100644
--- a/usr.bin/mail/names.c
+++ b/usr.bin/mail/names.c
@@ -598,7 +598,7 @@ elide(names)
np = np->n_flink;
continue;
}
-
+
/*
* Now t points to the last entry with the same name
* as np. Make np point beyond t.
diff --git a/usr.bin/mail/pathnames.h b/usr.bin/mail/pathnames.h
index 13a7672..0b2586f 100644
--- a/usr.bin/mail/pathnames.h
+++ b/usr.bin/mail/pathnames.h
@@ -38,5 +38,5 @@
#define _PATH_EX "/usr/bin/ex"
#define _PATH_HELP "/usr/share/misc/mail.help"
#define _PATH_TILDE "/usr/share/misc/mail.tildehelp"
-#define _PATH_MASTER_RC "/etc/mail.rc"
+#define _PATH_MASTER_RC "/usr/share/misc/mail.rc:/usr/local/etc/mail.rc:/etc/mail.rc"
#define _PATH_MORE "/usr/bin/more"
diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c
index c8b8fea..063e6ad 100644
--- a/usr.bin/mail/send.c
+++ b/usr.bin/mail/send.c
@@ -91,7 +91,7 @@ send(mp, obuf, doign, prefix)
break;
count -= length = strlen(line);
if (firstline) {
- /*
+ /*
* First line is the From line, so no headers
* there to worry about
*/
diff --git a/usr.bin/mail/temp.c b/usr.bin/mail/temp.c
index 9162c9f..0690027 100644
--- a/usr.bin/mail/temp.c
+++ b/usr.bin/mail/temp.c
@@ -71,7 +71,7 @@ tinit()
cp[len + 1] = '\0';
tmpdir = cp;
}
-
+
strcpy(tempMail, tmpdir);
mktemp(strcat(tempMail, "RsXXXXXX"));
strcpy(tempResid, tmpdir);
diff --git a/usr.bin/mail/tty.c b/usr.bin/mail/tty.c
index b39eba5..53cb456 100644
--- a/usr.bin/mail/tty.c
+++ b/usr.bin/mail/tty.c
@@ -61,7 +61,7 @@ grabh(hp, gflags)
struct header *hp;
int gflags;
{
- struct sgttyb ttybuf;
+ struct termios tio;
sig_t saveint;
#ifndef TIOCSTI
sig_t savequit;
@@ -79,15 +79,15 @@ grabh(hp, gflags)
#ifndef TIOCSTI
ttyset = 0;
#endif
- if (ioctl(fileno(stdin), TIOCGETP, &ttybuf) < 0) {
- perror("gtty");
+ if (tcgetattr(fileno(stdin), &tio) < 0) {
+ perror("tcgetattr(stdin)");
return(-1);
}
- c_erase = ttybuf.sg_erase;
- c_kill = ttybuf.sg_kill;
+ c_erase = tio.c_cc[VERASE];
+ c_kill = tio.c_cc[VKILL];
#ifndef TIOCSTI
- ttybuf.sg_erase = 0;
- ttybuf.sg_kill = 0;
+ tio.c_cc[VERASE] = 0;
+ tio.c_cc[VKILL] = 0;
if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
signal(SIGINT, SIG_DFL);
if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
@@ -100,7 +100,7 @@ grabh(hp, gflags)
if (gflags & GTO) {
#ifndef TIOCSTI
if (!ttyset && hp->h_to != NIL)
- ttyset++, stty(fileno(stdin), &ttybuf);
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
#endif
hp->h_to =
extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
@@ -108,14 +108,14 @@ grabh(hp, gflags)
if (gflags & GSUBJECT) {
#ifndef TIOCSTI
if (!ttyset && hp->h_subject != NOSTR)
- ttyset++, stty(fileno(stdin), &ttybuf);
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
#endif
hp->h_subject = readtty("Subject: ", hp->h_subject);
}
if (gflags & GCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_cc != NIL)
- ttyset++, stty(fileno(stdin), &ttybuf);
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
#endif
hp->h_cc =
extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
@@ -123,7 +123,7 @@ grabh(hp, gflags)
if (gflags & GBCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_bcc != NIL)
- ttyset++, stty(fileno(stdin), &ttybuf);
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
#endif
hp->h_bcc =
extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
@@ -133,10 +133,10 @@ out:
signal(SIGTTOU, savettou);
signal(SIGTTIN, savettin);
#ifndef TIOCSTI
- ttybuf.sg_erase = c_erase;
- ttybuf.sg_kill = c_kill;
+ tio.c_cc[VERASE] = c_erase;
+ tio.c_cc[VKILL] = c_kill;
if (ttyset)
- stty(fileno(stdin), &ttybuf);
+ tcsetattr(fileno(stdin), TCSADRAIN, &tio);
signal(SIGQUIT, savequit);
#endif
signal(SIGINT, saveint);
diff --git a/usr.bin/mail/v7.local.c b/usr.bin/mail/v7.local.c
index 5144c01..ade3cbd 100644
--- a/usr.bin/mail/v7.local.c
+++ b/usr.bin/mail/v7.local.c
@@ -55,7 +55,12 @@ void
findmail(user, buf)
char *user, *buf;
{
- (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, user);
+ char *tmp = getenv("MAIL");
+
+ if (tmp == NULL)
+ (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, user);
+ else
+ (void)strcpy(buf, tmp);
}
/*
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile
new file mode 100644
index 0000000..7a9b432
--- /dev/null
+++ b/usr.bin/make/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 5.2 (Berkeley) 12/28/90
+# $Id$
+
+PROG= make
+CFLAGS+= -I${.CURDIR}
+SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \
+ make.c parse.c str.c suff.c targ.c var.c util.c
+SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \
+ lstDatum.c lstDeQueue.c lstDestroy.c lstDupl.c lstEnQueue.c \
+ lstFind.c lstFindFrom.c lstFirst.c lstForEach.c lstForEachFrom.c \
+ lstInit.c lstInsert.c lstIsAtEnd.c lstIsEmpty.c lstLast.c \
+ lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c
+.PATH: ${.CURDIR}/lst.lib
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/make/PSD.doc/Makefile b/usr.bin/make/PSD.doc/Makefile
new file mode 100644
index 0000000..432ff31
--- /dev/null
+++ b/usr.bin/make/PSD.doc/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 8/14/93
+# $Id$
+
+DIR= psd/12.make
+SRCS= tutorial.ms
+MACROS= -ms
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/make/PSD.doc/tutorial.ms b/usr.bin/make/PSD.doc/tutorial.ms
new file mode 100644
index 0000000..7798011
--- /dev/null
+++ b/usr.bin/make/PSD.doc/tutorial.ms
@@ -0,0 +1,3744 @@
+.\" Copyright (c) 1988, 1989 by Adam de Boor
+.\" Copyright (c) 1989 by Berkeley Softworks
+.\" Copyright (c) 1988, 1989, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Adam de Boor.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tutorial.ms 8.1 (Berkeley) 8/18/93
+.\" $Id$
+.\"
+.EH 'PSD:12-%''PMake \*- A Tutorial'
+.OH 'PMake \*- A Tutorial''PSD:12-%'
+.\" xH is a macro to provide numbered headers that are automatically stuffed
+.\" into a table-of-contents, properly indented, etc. If the first argument
+.\" is numeric, it is taken as the depth for numbering (as for .NH), else
+.\" the default (1) is assumed.
+.\"
+.\" @P The initial paragraph distance.
+.\" @Q The piece of section number to increment (or 0 if none given)
+.\" @R Section header.
+.\" @S Indent for toc entry
+.\" @T Argument to NH (can't use @Q b/c giving 0 to NH resets the counter)
+.de xH
+.NH \\$1
+\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.nr PD .1v
+.XS \\n%
+.ta 0.6i
+\\*(SN \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.XE
+.nr PD .3v
+..
+.\" CW is used to place a string in fixed-width or switch to a
+.\" fixed-width font.
+.\" C is a typewriter font for a laserwriter. Use something else if
+.\" you don't have one...
+.de CW
+.ie !\\n(.$ .ft C
+.el \&\\$3\fC\\$1\fP\\$2
+..
+.\" Anything I put in a display I want to be in fixed-width
+.am DS
+.CW
+..
+.\" The stuff in .No produces a little stop sign in the left margin
+.\" that says NOTE in it. Unfortunately, it does cause a break, but
+.\" hey. Can't have everything. In case you're wondering how I came
+.\" up with such weird commands, they came from running grn on a
+.\" gremlin file...
+.de No
+.br
+.ne 0.5i
+.po -0.5i
+.br
+.mk
+.nr g3 \\n(.f
+.nr g4 \\n(.s
+.sp -1
+.\" .st cf
+\D's -1u'\D't 5u'
+.sp -1
+\h'50u'\D'l 71u 0u'\D'l 50u 50u'\D'l 0u 71u'\D'l -50u 50u'\D'l -71u 0u'\D'l -50u -50u'\D'l 0u -71u'\D'l 50u -50u'
+.sp -1
+\D't 3u'
+.sp -1
+.sp 7u
+\h'53u'\D'p 14 68u 0u 46u 46u 0u 68u -46u 46u -68u 0u -47u -46u 0u -68u 47u -46u'
+.sp -1
+.ft R
+.ps 6
+.nr g8 \\n(.d
+.ds g9 "NOTE
+.sp 74u
+\h'85u'\v'0.85n'\h-\w\\*(g9u/2u\&\\*(g9
+.sp |\\n(g8u
+.sp 166u
+\D't 3u'\D's -1u'
+.br
+.po
+.rt
+.ft \\n(g3
+.ps \\n(g4
+..
+.de Bp
+.ie !\\n(.$ .IP \(bu 2
+.el .IP "\&" 2
+..
+.po +.3i
+.TL
+PMake \*- A Tutorial
+.AU
+Adam de Boor
+.AI
+Berkeley Softworks
+2150 Shattuck Ave, Penthouse
+Berkeley, CA 94704
+adam@bsw.uu.net
+\&...!uunet!bsw!adam
+.FS
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appears in all copies.
+The University of California, Berkeley Softworks, and Adam de Boor make no
+representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied warranty.
+.FE
+.PP
+.xH 1 Introduction
+.LP
+PMake is a program for creating other programs, or anything else you
+can think of for it to do. The basic idea behind PMake is that, for
+any given system, be it a program or a document or whatever, there
+will be some files that depend on the state of other files (on when
+they were last modified). PMake takes these dependencies, which you
+must specify, and uses them to build whatever it is you want it to
+build.
+.LP
+PMake is almost fully-compatible with Make, with which you may already
+be familiar. PMake's most important feature is its ability to run
+several different jobs at once, making the creation of systems
+considerably faster. It also has a great deal more functionality than
+Make. Throughout the text, whenever something is mentioned that is an
+important difference between PMake and Make (i.e. something that will
+cause a makefile to fail if you don't do something about it), or is
+simply important, it will be flagged with a little sign in the left
+margin, like this:
+.No
+.LP
+This tutorial is divided into three main sections corresponding to basic,
+intermediate and advanced PMake usage. If you already know Make well,
+you will only need to skim chapter 2 (there are some aspects of
+PMake that I consider basic to its use that didn't exist in Make).
+Things in chapter 3 make life much easier, while those in chapter 4
+are strictly for those who know what they are doing. Chapter 5 has
+definitions for the jargon I use and chapter 6 contains possible
+solutions to the problems presented throughout the tutorial.
+.xH 1 The Basics of PMake
+.LP
+PMake takes as input a file that tells a) which files depend on which
+other files to be complete and b) what to do about files that are
+``out-of-date.'' This file is known as a ``makefile'' and is usually
+.Ix 0 def makefile
+kept in the top-most directory of the system to be built. While you
+can call the makefile anything you want, PMake will look for
+.CW Makefile
+and
+.CW makefile
+(in that order) in the current directory if you don't tell it
+otherwise.
+.Ix 0 def makefile default
+To specify a different makefile, use the
+.B \-f
+flag (e.g.
+.CW "pmake -f program.mk" ''). ``
+.Ix 0 ref flags -f
+.Ix 0 ref makefile other
+.LP
+A makefile has four different types of lines in it:
+.RS
+.IP \(bu 2
+File dependency specifications
+.IP \(bu 2
+Creation commands
+.IP \(bu 2
+Variable assignments
+.IP \(bu 2
+Comments, include statements and conditional directives
+.RE
+.LP
+Any line may be continued over multiple lines by ending it with a
+backslash.
+.Ix 0 def "continuation line"
+The backslash, following newline and any initial whitespace
+on the following line are compressed into a single space before the
+input line is examined by PMake.
+.xH 2 Dependency Lines
+.LP
+As mentioned in the introduction, in any system, there are
+dependencies between the files that make up the system. For instance,
+in a program made up of several C source files and one header file,
+the C files will need to be re-compiled should the header file be
+changed. For a document of several chapters and one macro file, the
+chapters will need to be reprocessed if any of the macros changes.
+.Ix 0 def "dependency"
+These are dependencies and are specified by means of dependency lines in
+the makefile.
+.LP
+.Ix 0 def "dependency line"
+On a dependency line, there are targets and sources, separated by a
+one- or two-character operator.
+The targets ``depend'' on the sources and are usually created from
+them.
+.Ix 0 def target
+.Ix 0 def source
+.Ix 0 ref operator
+Any number of targets and sources may be specified on a dependency line.
+All the targets in the line are made to depend on all the sources.
+Targets and sources need not be actual files, but every source must be
+either an actual file or another target in the makefile.
+If you run out of room, use a backslash at the end of the line to continue onto
+the next one.
+.LP
+Any file may be a target and any file may be a source, but the
+relationship between the two (or however many) is determined by the
+``operator'' that separates them.
+.Ix 0 def operator
+Three types of operators exist: one specifies that the datedness of a
+target is determined by the state of its sources, while another
+specifies other files (the sources) that need to be dealt with before
+the target can be re-created. The third operator is very similar to
+the first, with the additional condition that the target is
+out-of-date if it has no sources. These operations are represented by
+the colon, the exclamation point and the double-colon, respectively, and are
+mutually exclusive. Their exact semantics are as follows:
+.IP ":"
+.Ix 0 def operator colon
+.Ix 0 def :
+If a colon is used, a target on the line is considered to be
+``out-of-date'' (and in need of creation) if
+.RS
+.IP \(bu 2
+any of the sources has been modified more recently than the target, or
+.IP \(bu 2
+the target doesn't exist.
+.RE
+.Ix 0 def out-of-date
+.IP "\&"
+Under this operation, steps will be taken to re-create the target only
+if it is found to be out-of-date by using these two rules.
+.IP "!"
+.Ix 0 def operator force
+.Ix 0 def !
+If an exclamation point is used, the target will always be re-created,
+but this will not happen until all of its sources have been examined
+and re-created, if necessary.
+.IP "::"
+.Ix 0 def operator double-colon
+.Ix 0 def ::
+If a double-colon is used, a target is out-of-date if:
+.RS
+.IP \(bu 2
+any of the sources has been modified more recently than the target, or
+.IP \(bu 2
+the target doesn't exist, or
+.IP \(bu 2
+the target has no sources.
+.RE
+.IP "\&"
+If the target is out-of-date according to these rules, it will be re-created.
+This operator also does something else to the targets, but I'll go
+into that in the next section (``Shell Commands'').
+.LP
+Enough words, now for an example. Take that C program I mentioned
+earlier. Say there are three C files
+.CW a.c , (
+.CW b.c
+and
+.CW c.c )
+each of which
+includes the file
+.CW defs.h .
+The dependencies between the files could then be expressed as follows:
+.DS
+program : a.o b.o c.o
+a.o b.o c.o : defs.h
+a.o : a.c
+b.o : b.c
+c.o : c.c
+.DE
+.LP
+You may be wondering at this point, where
+.CW a.o ,
+.CW b.o
+and
+.CW c.o
+came in and why
+.I they
+depend on
+.CW defs.h
+and the C files don't. The reason is quite simple:
+.CW program
+cannot be made by linking together .c files \*- it must be
+made from .o files. Likewise, if you change
+.CW defs.h ,
+it isn't the .c files that need to be re-created, it's the .o files.
+If you think of dependencies in these terms \*- which files (targets)
+need to be created from which files (sources) \*- you should have no problems.
+.LP
+An important thing to notice about the above example, is that all the
+\&.o files appear as targets on more than one line. This is perfectly
+all right: the target is made to depend on all the sources mentioned
+on all the dependency lines. E.g.
+.CW a.o
+depends on both
+.CW defs.h
+and
+.CW a.c .
+.Ix 0 ref dependency
+.No
+.LP
+The order of the dependency lines in the makefile is
+important: the first target on the first dependency line in the
+makefile will be the one that gets made if you don't say otherwise.
+That's why
+.CW program
+comes first in the example makefile, above.
+.LP
+Both targets and sources may contain the standard C-Shell wildcard
+characters
+.CW { , (
+.CW } ,
+.CW * ,
+.CW ? ,
+.CW [ ,
+and
+.CW ] ),
+but the non-curly-brace ones may only appear in the final component
+(the file portion) of the target or source. The characters mean the
+following things:
+.IP \fB{}\fP
+These enclose a comma-separated list of options and cause the pattern
+to be expanded once for each element of the list. Each expansion
+contains a different element. For example,
+.CW src/{whiffle,beep,fish}.c
+expands to the three words
+.CW src/whiffle.c ,
+.CW src/beep.c ,
+and
+.CW src/fish.c .
+These braces may be nested and, unlike the other wildcard characters,
+the resulting words need not be actual files. All other wildcard
+characters are expanded using the files that exist when PMake is
+started.
+.IP \fB*\fP
+This matches zero or more characters of any sort.
+.CW src/*.c
+will expand to the same three words as above as long as
+.CW src
+contains those three files (and no other files that end in
+.CW .c ).
+.IP \fB?\fP
+Matches any single character.
+.IP \fB[]\fP
+This is known as a character class and contains either a list of
+single characters, or a series of character ranges
+.CW a-z , (
+for example means all characters between a and z), or both. It matches
+any single character contained in the list. E.g.
+.CW [A-Za-z]
+will match all letters, while
+.CW [0123456789]
+will match all numbers.
+.xH 2 Shell Commands
+.LP
+``Isn't that nice,'' you say to yourself, ``but how are files
+actually `re-created,' as he likes to spell it?''
+The re-creation is accomplished by commands you place in the makefile.
+These commands are passed to the Bourne shell (better known as
+``/bin/sh'') to be executed and are
+.Ix 0 ref shell
+.Ix 0 ref re-creation
+.Ix 0 ref update
+expected to do what's necessary to update the target file (PMake
+doesn't actually check to see if the target was created. It just
+assumes it's there).
+.Ix 0 ref target
+.LP
+Shell commands in a makefile look a lot like shell commands you would
+type at a terminal, with one important exception: each command in a
+makefile
+.I must
+be preceded by at least one tab.
+.LP
+Each target has associated with it a shell script made up of
+one or more of these shell commands. The creation script for a target
+should immediately follow the dependency line for that target. While
+any given target may appear on more than one dependency line, only one
+of these dependency lines may be followed by a creation script, unless
+the `::' operator was used on the dependency line.
+.Ix 0 ref operator double-colon
+.Ix 0 ref ::
+.No
+.LP
+If the double-colon was used, each dependency line for the target
+may be followed by a shell script. That script will only be executed
+if the target on the associated dependency line is out-of-date with
+respect to the sources on that line, according to the rules I gave
+earlier.
+I'll give you a good example of this later on.
+.LP
+To expand on the earlier makefile, you might add commands as follows:
+.DS
+program : a.o b.o c.o
+ cc a.o b.o c.o \-o program
+a.o b.o c.o : defs.h
+a.o : a.c
+ cc \-c a.c
+b.o : b.c
+ cc \-c b.c
+c.o : c.c
+ cc \-c c.c
+.DE
+.LP
+Something you should remember when writing a makefile is, the
+commands will be executed if the
+.I target
+on the dependency line is out-of-date, not the sources.
+.Ix 0 ref target
+.Ix 0 ref source
+.Ix 0 ref out-of-date
+In this example, the command
+.CW "cc \-c a.c" '' ``
+will be executed if
+.CW a.o
+is out-of-date. Because of the `:' operator,
+.Ix 0 ref :
+.Ix 0 ref operator colon
+this means that should
+.CW a.c
+.I or
+.CW defs.h
+have been modified more recently than
+.CW a.o ,
+the command will be executed
+.CW a.o "\&" (
+will be considered out-of-date).
+.Ix 0 ref out-of-date
+.LP
+Remember how I said the only difference between a makefile shell
+command and a regular shell command was the leading tab? I lied. There
+is another way in which makefile commands differ from regular ones.
+The first two characters after the initial whitespace are treated
+specially.
+If they are any combination of `@' and `\-', they cause PMake to do
+different things.
+.LP
+In most cases, shell commands are printed before they're
+actually executed. This is to keep you informed of what's going on. If
+an `@' appears, however, this echoing is suppressed. In the case of an
+.CW echo
+command, say
+.CW "echo Linking index" ,'' ``
+it would be
+rather silly to see
+.DS
+echo Linking index
+Linking index
+.DE
+.LP
+so PMake allows you to place an `@' before the command
+.CW "@echo Linking index" '') (``
+to prevent the command from being printed.
+.LP
+The other special character is the `\-'. In case you didn't know,
+shell commands finish with a certain ``exit status.'' This status is
+made available by the operating system to whatever program invoked the
+command. Normally this status will be 0 if everything went ok and
+non-zero if something went wrong. For this reason, PMake will consider
+an error to have occurred if one of the shells it invokes returns a non-zero
+status. When it detects an error, PMake's usual action is to abort
+whatever it's doing and exit with a non-zero status itself (any other
+targets that were being created will continue being made, but nothing
+new will be started. PMake will exit after the last job finishes).
+This behavior can be altered, however, by placing a `\-' at the front
+of a command
+.CW "\-mv index index.old" ''), (``
+certain command-line arguments,
+or doing other things, to be detailed later. In such
+a case, the non-zero status is simply ignored and PMake keeps chugging
+along.
+.No
+.LP
+Because all the commands are given to a single shell to execute, such
+things as setting shell variables, changing directories, etc., last
+beyond the command in which they are found. This also allows shell
+compound commands (like
+.CW for
+loops) to be entered in a natural manner.
+Since this could cause problems for some makefiles that depend on
+each command being executed by a single shell, PMake has a
+.B \-B
+.Ix 0 ref compatibility
+.Ix 0 ref flags -B
+flag (it stands for backwards-compatible) that forces each command to
+be given to a separate shell. It also does several other things, all
+of which I discourage since they are now old-fashioned.\|.\|.\|.
+.No
+.LP
+A target's shell script is fed to the shell on its (the shell's) input stream.
+This means that any commands, such as
+.CW ci
+that need to get input from the terminal won't work right \*- they'll
+get the shell's input, something they probably won't find to their
+liking. A simple way around this is to give a command like this:
+.DS
+ci $(SRCS) < /dev/tty
+.DE
+This would force the program's input to come from the terminal. If you
+can't do this for some reason, your only other alternative is to use
+PMake in its fullest compatibility mode. See
+.B Compatibility
+in chapter 4.
+.Ix 0 ref compatibility
+.LP
+.xH 2 Variables
+.LP
+PMake, like Make before it, has the ability to save text in variables
+to be recalled later at your convenience. Variables in PMake are used
+much like variables in the shell and, by tradition, consist of
+all upper-case letters (you don't
+.I have
+to use all upper-case letters.
+In fact there's nothing to stop you from calling a variable
+.CW @^&$%$ .
+Just tradition). Variables are assigned-to using lines of the form
+.Ix 0 def variable assignment
+.DS
+VARIABLE = value
+.DE
+.Ix 0 def variable assignment
+appended-to by
+.DS
+VARIABLE += value
+.DE
+.Ix 0 def variable appending
+.Ix 0 def variable assignment appended
+.Ix 0 def +=
+conditionally assigned-to (if the variable isn't already defined) by
+.DS
+VARIABLE ?= value
+.DE
+.Ix 0 def variable assignment conditional
+.Ix 0 def ?=
+and assigned-to with expansion (i.e. the value is expanded (see below)
+before being assigned to the variable\*-useful for placing a value at
+the beginning of a variable, or other things) by
+.DS
+VARIABLE := value
+.DE
+.Ix 0 def variable assignment expanded
+.Ix 0 def :=
+.LP
+Any whitespace before
+.I value
+is stripped off. When appending, a space is placed between the old
+value and the stuff being appended.
+.LP
+The final way a variable may be assigned to is using
+.DS
+VARIABLE != shell-command
+.DE
+.Ix 0 def variable assignment shell-output
+.Ix 0 def !=
+In this case,
+.I shell-command
+has all its variables expanded (see below) and is passed off to a
+shell to execute. The output of the shell is then placed in the
+variable. Any newlines (other than the final one) are replaced by
+spaces before the assignment is made. This is typically used to find
+the current directory via a line like:
+.DS
+CWD != pwd
+.DE
+.LP
+.B Note:
+this is intended to be used to execute commands that produce small amounts
+of output (e.g. ``pwd''). The implementation is less than intelligent and will
+likely freeze if you execute something that produces thousands of
+bytes of output (8 Kb is the limit on many UNIX systems).
+.LP
+The value of a variable may be retrieved by enclosing the variable
+name in parentheses or curly braces and preceeding the whole thing
+with a dollar sign.
+.LP
+For example, to set the variable CFLAGS to the string
+.CW "\-I/sprite/src/lib/libc \-O" ,'' ``
+you would place a line
+.DS
+CFLAGS = \-I/sprite/src/lib/libc \-O
+.DE
+in the makefile and use the word
+.CW "$(CFLAGS)"
+wherever you would like the string
+.CW "\-I/sprite/src/lib/libc \-O"
+to appear. This is called variable expansion.
+.Ix 0 def variable expansion
+.No
+.LP
+Unlike Make, PMake will not expand a variable unless it knows
+the variable exists. E.g. if you have a
+.CW "${i}"
+in a shell command and you have not assigned a value to the variable
+.CW i
+(the empty string is considered a value, by the way), where Make would have
+substituted the empty string, PMake will leave the
+.CW "${i}"
+alone.
+To keep PMake from substituting for a variable it knows, precede the
+dollar sign with another dollar sign.
+(e.g. to pass
+.CW "${HOME}"
+to the shell, use
+.CW "$${HOME}" ).
+This causes PMake, in effect, to expand the
+.CW $
+macro, which expands to a single
+.CW $ .
+For compatibility, Make's style of variable expansion will be used
+if you invoke PMake with any of the compatibility flags (\c
+.B \-V ,
+.B \-B
+or
+.B \-M .
+The
+.B \-V
+flag alters just the variable expansion).
+.Ix 0 ref flags -V
+.Ix 0 ref flags -B
+.Ix 0 ref flags -M
+.Ix 0 ref compatibility
+.LP
+.Ix 0 ref variable expansion
+There are two different times at which variable expansion occurs:
+When parsing a dependency line, the expansion occurs immediately
+upon reading the line. If any variable used on a dependency line is
+undefined, PMake will print a message and exit.
+Variables in shell commands are expanded when the command is
+executed.
+Variables used inside another variable are expanded whenever the outer
+variable is expanded (the expansion of an inner variable has no effect
+on the outer variable. I.e. if the outer variable is used on a dependency
+line and in a shell command, and the inner variable changes value
+between when the dependency line is read and the shell command is
+executed, two different values will be substituted for the outer
+variable).
+.Ix 0 def variable types
+.LP
+Variables come in four flavors, though they are all expanded the same
+and all look about the same. They are (in order of expanding scope):
+.RS
+.IP \(bu 2
+Local variables.
+.Ix 0 ref variable local
+.IP \(bu 2
+Command-line variables.
+.Ix 0 ref variable command-line
+.IP \(bu 2
+Global variables.
+.Ix 0 ref variable global
+.IP \(bu 2
+Environment variables.
+.Ix 0 ref variable environment
+.RE
+.LP
+The classification of variables doesn't matter much, except that the
+classes are searched from the top (local) to the bottom (environment)
+when looking up a variable. The first one found wins.
+.xH 3 Local Variables
+.LP
+.Ix 0 def variable local
+Each target can have as many as seven local variables. These are
+variables that are only ``visible'' within that target's shell script
+and contain such things as the target's name, all of its sources (from
+all its dependency lines), those sources that were out-of-date, etc.
+Four local variables are defined for all targets. They are:
+.RS
+.IP ".TARGET"
+.Ix 0 def variable local .TARGET
+.Ix 0 def .TARGET
+The name of the target.
+.IP ".OODATE"
+.Ix 0 def variable local .OODATE
+.Ix 0 def .OODATE
+The list of the sources for the target that were considered out-of-date.
+The order in the list is not guaranteed to be the same as the order in
+which the dependencies were given.
+.IP ".ALLSRC"
+.Ix 0 def variable local .ALLSRC
+.Ix 0 def .ALLSRC
+The list of all sources for this target in the order in which they
+were given.
+.IP ".PREFIX"
+.Ix 0 def variable local .PREFIX
+.Ix 0 def .PREFIX
+The target without its suffix and without any leading path. E.g. for
+the target
+.CW ../../lib/compat/fsRead.c ,
+this variable would contain
+.CW fsRead .
+.RE
+.LP
+Three other local variables are set only for certain targets under
+special circumstances. These are the ``.IMPSRC,''
+.Ix 0 ref variable local .IMPSRC
+.Ix 0 ref .IMPSRC
+``.ARCHIVE,''
+.Ix 0 ref variable local .ARCHIVE
+.Ix 0 ref .ARCHIVE
+and ``.MEMBER''
+.Ix 0 ref variable local .MEMBER
+.Ix 0 ref .MEMBER
+variables. When they are set and how they are used is described later.
+.LP
+Four of these variables may be used in sources as well as in shell
+scripts.
+.Ix 0 def "dynamic source"
+.Ix 0 def source dynamic
+These are ``.TARGET'', ``.PREFIX'', ``.ARCHIVE'' and ``.MEMBER''. The
+variables in the sources are expanded once for each target on the
+dependency line, providing what is known as a ``dynamic source,''
+.Rd 0
+allowing you to specify several dependency lines at once. For example,
+.DS
+$(OBJS) : $(.PREFIX).c
+.DE
+will create a dependency between each object file and its
+corresponding C source file.
+.xH 3 Command-line Variables
+.LP
+.Ix 0 def variable command-line
+Command-line variables are set when PMake is first invoked by giving a
+variable assignment as one of the arguments. For example,
+.DS
+pmake "CFLAGS = -I/sprite/src/lib/libc -O"
+.DE
+would make
+.CW CFLAGS
+be a command-line variable with the given value. Any assignments to
+.CW CFLAGS
+in the makefile will have no effect, because once it
+is set, there is (almost) nothing you can do to change a command-line
+variable (the search order, you see). Command-line variables may be
+set using any of the four assignment operators, though only
+.CW =
+and
+.CW ?=
+behave as you would expect them to, mostly because assignments to
+command-line variables are performed before the makefile is read, thus
+the values set in the makefile are unavailable at the time.
+.CW +=
+.Ix 0 ref +=
+.Ix 0 ref variable assignment appended
+is the same as
+.CW = ,
+because the old value of the variable is sought only in the scope in
+which the assignment is taking place (for reasons of efficiency that I
+won't get into here).
+.CW :=
+and
+.CW ?=
+.Ix 0 ref :=
+.Ix 0 ref ?=
+.Ix 0 ref variable assignment expanded
+.Ix 0 ref variable assignment conditional
+will work if the only variables used are in the environment.
+.CW !=
+is sort of pointless to use from the command line, since the same
+effect can no doubt be accomplished using the shell's own command
+substitution mechanisms (backquotes and all that).
+.xH 3 Global Variables
+.LP
+.Ix 0 def variable global
+Global variables are those set or appended-to in the makefile.
+There are two classes of global variables: those you set and those PMake sets.
+As I said before, the ones you set can have any name you want them to have,
+except they may not contain a colon or an exclamation point.
+The variables PMake sets (almost) always begin with a
+period and always contain upper-case letters, only. The variables are
+as follows:
+.RS
+.IP .PMAKE
+.Ix 0 def variable global .PMAKE
+.Ix 0 def .PMAKE
+.Ix 0 def variable global MAKE
+.Ix 0 def MAKE
+The name by which PMake was invoked is stored in this variable. For
+compatibility, the name is also stored in the MAKE variable.
+.IP .MAKEFLAGS
+.Ix 0 def variable global .MAKEFLAGS
+.Ix 0 def .MAKEFLAGS variable
+.Ix 0 def variable global MFLAGS
+.Ix 0 def MFLAGS
+All the relevant flags with which PMake was invoked. This does not
+include such things as
+.B \-f
+or variable assignments. Again for compatibility, this value is stored
+in the MFLAGS variable as well.
+.RE
+.LP
+Two other variables, ``.INCLUDES'' and ``.LIBS,'' are covered in the
+section on special targets in chapter 3.
+.Ix 0 ref variable global .INCLUDES
+.Ix 0 ref variable global .LIBS
+.LP
+Global variables may be deleted using lines of the form:
+.Ix 0 def #undef
+.Ix 0 def variable deletion
+.DS
+#undef \fIvariable\fP
+.DE
+The
+.CW # ' `
+must be the first character on the line. Note that this may only be
+done on global variables.
+.xH 3 Environment Variables
+.LP
+.Ix 0 def variable environment
+Environment variables are passed by the shell that invoked PMake and
+are given by PMake to each shell it invokes. They are expanded like
+any other variable, but they cannot be altered in any way.
+.LP
+One special environment variable,
+.CW PMAKE ,
+.Ix 0 def variable environment PMAKE
+is examined by PMake for command-line flags, variable assignments,
+etc., it should always use. This variable is examined before the
+actual arguments to PMake are. In addition, all flags given to PMake,
+either through the
+.CW PMAKE
+variable or on the command line, are placed in this environment
+variable and exported to each shell PMake executes. Thus recursive
+invocations of PMake automatically receive the same flags as the
+top-most one.
+.LP
+Using all these variables, you can compress the sample makefile even more:
+.DS
+OBJS = a.o b.o c.o
+program : $(OBJS)
+ cc $(.ALLSRC) \-o $(.TARGET)
+$(OBJS) : defs.h
+a.o : a.c
+ cc \-c a.c
+b.o : b.c
+ cc \-c b.c
+c.o : c.c
+ cc \-c c.c
+.DE
+.Ix 0 ref variable local .ALLSRC
+.Ix 0 ref .ALLSRC
+.Ix 0 ref variable local .TARGET
+.Ix 0 ref .TARGET
+.Rd 3
+.xH 2 Comments
+.LP
+.Ix 0 def comments
+Comments in a makefile start with a `#' character and extend to the
+end of the line. They may appear
+anywhere you want them, except in a shell command (though the shell
+will treat it as a comment, too). If, for some reason, you need to use the `#'
+in a variable or on a dependency line, put a backslash in front of it.
+PMake will compress the two into a single `#' (Note: this isn't true
+if PMake is operating in full-compatibility mode).
+.Ix 0 ref flags -M
+.Ix 0 ref compatibility
+.xH 2 Parallelism
+.No
+.LP
+PMake was specifically designed to re-create several targets at once,
+when possible. You do not have to do anything special to cause this to
+happen (unless PMake was configured to not act in parallel, in which
+case you will have to make use of the
+.B \-L
+and
+.B \-J
+flags (see below)),
+.Ix 0 ref flags -L
+.Ix 0 ref flags -J
+but you do have to be careful at times.
+.LP
+There are several problems you are likely to encounter. One is
+that some makefiles (and programs) are written in such a way that it is
+impossible for two targets to be made at once. The program
+.CW xstr ,
+for example,
+always modifies the files
+.CW strings
+and
+.CW x.c .
+There is no way to change it. Thus you cannot run two of them at once
+without something being trashed. Similarly, if you have commands
+in the makefile that always send output to the same file, you will not
+be able to make more than one target at once unless you change the
+file you use. You can, for instance, add a
+.CW $$$$
+to the end of the file name to tack on the process ID of the shell
+executing the command (each
+.CW $$
+expands to a single
+.CW $ ,
+thus giving you the shell variable
+.CW $$ ).
+Since only one shell is used for all the
+commands, you'll get the same file name for each command in the
+script.
+.LP
+The other problem comes from improperly-specified dependencies that
+worked in Make because of its sequential, depth-first way of examining
+them. While I don't want to go into depth on how PMake
+works (look in chapter 4 if you're interested), I will warn you that
+files in two different ``levels'' of the dependency tree may be
+examined in a different order in PMake than they were in Make. For
+example, given the makefile
+.DS
+a : b c
+b : d
+.DE
+PMake will examine the targets in the order
+.CW c ,
+.CW d ,
+.CW b ,
+.CW a .
+If the makefile's author expected PMake to abort before making
+.CW c
+if an error occurred while making
+.CW b ,
+or if
+.CW b
+needed to exist before
+.CW c
+was made,
+s/he will be sorely disappointed. The dependencies are
+incomplete, since in both these cases,
+.CW c
+would depend on
+.CW b .
+So watch out.
+.LP
+Another problem you may face is that, while PMake is set up to handle the
+output from multiple jobs in a graceful fashion, the same is not so for input.
+It has no way to regulate input to different jobs,
+so if you use the redirection from
+.CW /dev/tty
+I mentioned earlier, you must be careful not to run two of the jobs at once.
+.xH 2 Writing and Debugging a Makefile
+.LP
+Now you know most of what's in a makefile, what do you do next? There
+are two choices: (1) use one of the uncommonly-available makefile
+generators or (2) write your own makefile (I leave out the third choice of
+ignoring PMake and doing everything by hand as being beyond the bounds
+of common sense).
+.LP
+When faced with the writing of a makefile, it is usually best to start
+from first principles: just what
+.I are
+you trying to do? What do you want the makefile finally to produce?
+.LP
+To begin with a somewhat traditional example, let's say you need to
+write a makefile to create a program,
+.CW expr ,
+that takes standard infix expressions and converts them to prefix form (for
+no readily apparent reason). You've got three source files, in C, that
+make up the program:
+.CW main.c ,
+.CW parse.c ,
+and
+.CW output.c .
+Harking back to my pithy advice about dependency lines, you write the
+first line of the file:
+.DS
+expr : main.o parse.o output.o
+.DE
+because you remember
+.CW expr
+is made from
+.CW .o
+files, not
+.CW .c
+files. Similarly for the
+.CW .o
+files you produce the lines:
+.DS
+main.o : main.c
+parse.o : parse.c
+output.o : output.c
+main.o parse.o output.o : defs.h
+.DE
+.LP
+Great. You've now got the dependencies specified. What you need now is
+commands. These commands, remember, must produce the target on the
+dependency line, usually by using the sources you've listed.
+You remember about local variables? Good, so it should come
+to you as no surprise when you write
+.DS
+expr : main.o parse.o output.o
+ cc -o $(.TARGET) $(.ALLSRC)
+.DE
+Why use the variables? If your program grows to produce postfix
+expressions too (which, of course, requires a name change or two), it
+is one fewer place you have to change the file. You cannot do this for
+the object files, however, because they depend on their corresponding
+source files
+.I and
+.CW defs.h ,
+thus if you said
+.DS
+ cc -c $(.ALLSRC)
+.DE
+you'd get (for
+.CW main.o ):
+.DS
+ cc -c main.c defs.h
+.DE
+which is wrong. So you round out the makefile with these lines:
+.DS
+main.o : main.c
+ cc -c main.c
+parse.o : parse.c
+ cc -c parse.c
+output.o : output.c
+ cc -c output.c
+.DE
+.LP
+The makefile is now complete and will, in fact, create the program you
+want it to without unnecessary compilations or excessive typing on
+your part. There are two things wrong with it, however (aside from it
+being altogether too long, something I'll address in chapter 3):
+.IP 1)
+The string
+.CW "main.o parse.o output.o" '' ``
+is repeated twice, necessitating two changes when you add postfix
+(you were planning on that, weren't you?). This is in direct violation
+of de Boor's First Rule of writing makefiles:
+.QP
+.I
+Anything that needs to be written more than once
+should be placed in a variable.
+.IP "\&"
+I cannot emphasize this enough as being very important to the
+maintenance of a makefile and its program.
+.IP 2)
+There is no way to alter the way compilations are performed short of
+editing the makefile and making the change in all places. This is evil
+and violates de Boor's Second Rule, which follows directly from the
+first:
+.QP
+.I
+Any flags or programs used inside a makefile should be placed in a variable so
+they may be changed, temporarily or permanently, with the greatest ease.
+.LP
+The makefile should more properly read:
+.DS
+OBJS = main.o parse.o output.o
+expr : $(OBJS)
+ $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
+main.o : main.c
+ $(CC) $(CFLAGS) -c main.c
+parse.o : parse.c
+ $(CC) $(CFLAGS) -c parse.c
+output.o : output.c
+ $(CC) $(CFLAGS) -c output.c
+$(OBJS) : defs.h
+.DE
+Alternatively, if you like the idea of dynamic sources mentioned in
+section 2.3.1,
+.Rm 0 2.3.1
+.Rd 4
+.Ix 0 ref "dynamic source"
+.Ix 0 ref source dynamic
+you could write it like this:
+.DS
+OBJS = main.o parse.o output.o
+expr : $(OBJS)
+ $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
+$(OBJS) : $(.PREFIX).c defs.h
+ $(CC) $(CFLAGS) -c $(.PREFIX).c
+.DE
+These two rules and examples lead to de Boor's First Corollary:
+.QP
+.I
+Variables are your friends.
+.LP
+Once you've written the makefile comes the sometimes-difficult task of
+.Ix 0 ref debugging
+making sure the darn thing works. Your most helpful tool to make sure
+the makefile is at least syntactically correct is the
+.B \-n
+.Ix 0 ref flags -n
+flag, which allows you to see if PMake will choke on the makefile. The
+second thing the
+.B \-n
+flag lets you do is see what PMake would do without it actually doing
+it, thus you can make sure the right commands would be executed were
+you to give PMake its head.
+.LP
+When you find your makefile isn't behaving as you hoped, the first
+question that comes to mind (after ``What time is it, anyway?'') is
+``Why not?'' In answering this, two flags will serve you well:
+.CW "-d m" '' ``
+.Ix 0 ref flags -d
+and
+.CW "-p 2" .'' ``
+.Ix 0 ref flags -p
+The first causes PMake to tell you as it examines each target in the
+makefile and indicate why it is deciding whatever it is deciding. You
+can then use the information printed for other targets to see where
+you went wrong. The
+.CW "-p 2" '' ``
+flag makes PMake print out its internal state when it is done,
+allowing you to see that you forgot to make that one chapter depend on
+that file of macros you just got a new version of. The output from
+.CW "-p 2" '' ``
+is intended to resemble closely a real makefile, but with additional
+information provided and with variables expanded in those commands
+PMake actually printed or executed.
+.LP
+Something to be especially careful about is circular dependencies.
+.Ix 0 def dependency circular
+E.g.
+.DS
+a : b
+b : c d
+d : a
+.DE
+In this case, because of how PMake works,
+.CW c
+is the only thing PMake will examine, because
+.CW d
+and
+.CW a
+will effectively fall off the edge of the universe, making it
+impossible to examine
+.CW b
+(or them, for that matter).
+PMake will tell you (if run in its normal mode) all the targets
+involved in any cycle it looked at (i.e. if you have two cycles in the
+graph (naughty, naughty), but only try to make a target in one of
+them, PMake will only tell you about that one. You'll have to try to
+make the other to find the second cycle). When run as Make, it will
+only print the first target in the cycle.
+.xH 2 Invoking PMake
+.LP
+.Ix 0 ref flags
+.Ix 0 ref arguments
+.Ix 0 ref usage
+PMake comes with a wide variety of flags to choose from.
+They may appear in any order, interspersed with command-line variable
+assignments and targets to create.
+The flags are as follows:
+.IP "\fB\-d\fP \fIwhat\fP"
+.Ix 0 def flags -d
+.Ix 0 ref debugging
+This causes PMake to spew out debugging information that
+may prove useful to you. If you can't
+figure out why PMake is doing what it's doing, you might try using
+this flag. The
+.I what
+parameter is a string of single characters that tell PMake what
+aspects you are interested in. Most of what I describe will make
+little sense to you, unless you've dealt with Make before. Just
+remember where this table is and come back to it as you read on.
+The characters and the information they produce are as follows:
+.RS
+.IP a
+Archive searching and caching.
+.IP c
+Conditional evaluation.
+.IP d
+The searching and caching of directories.
+.IP j
+Various snippets of information related to the running of the multiple
+shells. Not particularly interesting.
+.IP m
+The making of each target: what target is being examined; when it was
+last modified; whether it is out-of-date; etc.
+.IP p
+Makefile parsing.
+.IP r
+Remote execution.
+.IP s
+The application of suffix-transformation rules. (See chapter 3)
+.IP t
+The maintenance of the list of targets.
+.IP v
+Variable assignment.
+.RE
+.IP "\&"
+Of these all, the
+.CW m
+and
+.CW s
+letters will be most useful to you.
+If the
+.B \-d
+is the final argument or the argument from which it would get these
+key letters (see below for a note about which argument would be used)
+begins with a
+.B \- ,
+all of these debugging flags will be set, resulting in massive amounts
+of output.
+.IP "\fB\-f\fP \fImakefile\fP"
+.Ix 0 def flags -f
+Specify a makefile to read different from the standard makefiles
+.CW Makefile "\&" (
+or
+.CW makefile ).
+.Ix 0 ref makefile default
+.Ix 0 ref makefile other
+If
+.I makefile
+is ``\-'', PMake uses the standard input. This is useful for making
+quick and dirty makefiles.\|.\|.
+.Ix 0 ref makefile "quick and dirty"
+.IP \fB\-h\fP
+.Ix 0 def flags -h
+Prints out a summary of the various flags PMake accepts. It can also
+be used to find out what level of concurrency was compiled into the
+version of PMake you are using (look at
+.B \-J
+and
+.B \-L )
+and various other information on how PMake was configured.
+.Ix 0 ref configuration
+.Ix 0 ref makefile system
+.IP \fB\-i\fP
+.Ix 0 def flags -i
+If you give this flag, PMake will ignore non-zero status returned
+by any of its shells. It's like placing a `\-' before all the commands
+in the makefile.
+.IP \fB\-k\fP
+.Ix 0 def flags -k
+This is similar to
+.B \-i
+in that it allows PMake to continue when it sees an error, but unlike
+.B \-i ,
+where PMake continues blithely as if nothing went wrong,
+.B \-k
+causes it to recognize the error and only continue work on those
+things that don't depend on the target, either directly or indirectly (through
+depending on something that depends on it), whose creation returned the error.
+The `k' is for ``keep going''.\|.\|.
+.Ix 0 ref target
+.IP \fB\-l\fP
+.Ix 0 def flags -l
+PMake has the ability to lock a directory against other
+people executing it in the same directory (by means of a file called
+``LOCK.make'' that it creates and checks for in the directory). This
+is a Good Thing because two people doing the same thing in the same place
+can be disastrous for the final product (too many cooks and all that).
+Whether this locking is the default is up to your system
+administrator. If locking is on,
+.B \-l
+will turn it off, and vice versa. Note that this locking will not
+prevent \fIyou\fP from invoking PMake twice in the same place \*- if
+you own the lock file, PMake will warn you about it but continue to execute.
+.IP "\fB\-m\fP \fIdirectory\fP"
+.Ix 0 def flags -m
+Tells PMake another place to search for included makefiles via the <...>
+style. Several
+.B \-m
+options can be given to form a search path. If this construct is used the
+default system makefile search path is completely overridden.
+To be explained in chapter 3, section 3.2.
+.Rm 2 3.2
+.IP \fB\-n\fP
+.Ix 0 def flags -n
+This flag tells PMake not to execute the commands needed to update the
+out-of-date targets in the makefile. Rather, PMake will simply print
+the commands it would have executed and exit. This is particularly
+useful for checking the correctness of a makefile. If PMake doesn't do
+what you expect it to, it's a good chance the makefile is wrong.
+.IP "\fB\-p\fP \fInumber\fP"
+.Ix 0 def flags -p
+.Ix 0 ref debugging
+This causes PMake to print its input in a reasonable form, though
+not necessarily one that would make immediate sense to anyone but me. The
+.I number
+is a bitwise-or of 1 and 2 where 1 means it should print the input
+before doing any processing and 2 says it should print it after
+everything has been re-created. Thus
+.CW "\-p 3"
+would print it twice\*-once before processing and once after (you
+might find the difference between the two interesting). This is mostly
+useful to me, but you may find it informative in some bizarre circumstances.
+.IP \fB\-q\fP
+.Ix 0 def flags -q
+If you give PMake this flag, it will not try to re-create anything. It
+will just see if anything is out-of-date and exit non-zero if so.
+.IP \fB\-r\fP
+.Ix 0 def flags -r
+When PMake starts up, it reads a default makefile that tells it what
+sort of system it's on and gives it some idea of what to do if you
+don't tell it anything. I'll tell you about it in chapter 3. If you
+give this flag, PMake won't read the default makefile.
+.IP \fB\-s\fP
+.Ix 0 def flags -s
+This causes PMake to not print commands before they're executed. It
+is the equivalent of putting an `@' before every command in the
+makefile.
+.IP \fB\-t\fP
+.Ix 0 def flags -t
+Rather than try to re-create a target, PMake will simply ``touch'' it
+so as to make it appear up-to-date. If the target didn't exist before,
+it will when PMake finishes, but if the target did exist, it will
+appear to have been updated.
+.IP \fB\-v\fP
+.Ix 0 def flags -v
+This is a mixed-compatibility flag intended to mimic the System V
+version of Make. It is the same as giving
+.B \-B ,
+and
+.B \-V
+as well as turning off directory locking. Targets can still be created
+in parallel, however. This is the mode PMake will enter if it is
+invoked either as
+.CW smake '' ``
+or
+.CW vmake ''. ``
+.IP \fB\-x\fP
+.Ix 0 def flags -x
+This tells PMake it's ok to export jobs to other machines, if they're
+available. It is used when running in Make mode, as exporting in this
+mode tends to make things run slower than if the commands were just
+executed locally.
+.IP \fB\-B\fP
+.Ix 0 ref compatibility
+.Ix 0 def flags -B
+Forces PMake to be as backwards-compatible with Make as possible while
+still being itself.
+This includes:
+.RS
+.IP \(bu 2
+Executing one shell per shell command
+.IP \(bu 2
+Expanding anything that looks even vaguely like a variable, with the
+empty string replacing any variable PMake doesn't know.
+.IP \(bu 2
+Refusing to allow you to escape a `#' with a backslash.
+.IP \(bu 2
+Permitting undefined variables on dependency lines and conditionals
+(see below). Normally this causes PMake to abort.
+.RE
+.IP \fB\-C\fP
+.Ix 0 def flags -C
+This nullifies any and all compatibility mode flags you may have given
+or implied up to the time the
+.B \-C
+is encountered. It is useful mostly in a makefile that you wrote for PMake
+to avoid bad things happening when someone runs PMake as
+.CW make '' ``
+or has things set in the environment that tell it to be compatible.
+.B \-C
+is
+.I not
+placed in the
+.CW PMAKE
+environment variable or the
+.CW .MAKEFLAGS
+or
+.CW MFLAGS
+global variables.
+.Ix 0 ref variable environment PMAKE
+.Ix 0 ref variable global .MAKEFLAGS
+.Ix 0 ref variable global MFLAGS
+.Ix 0 ref .MAKEFLAGS variable
+.Ix 0 ref MFLAGS
+.IP "\fB\-D\fP \fIvariable\fP"
+.Ix 0 def flags -D
+Allows you to define a variable to have
+.CW 1 '' ``
+as its value. The variable is a global variable, not a command-line
+variable. This is useful mostly for people who are used to the C
+compiler arguments and those using conditionals, which I'll get into
+in section 4.3
+.Rm 1 4.3
+.IP "\fB\-I\fP \fIdirectory\fP"
+.Ix 0 def flags -I
+Tells PMake another place to search for included makefiles. Yet
+another thing to be explained in chapter 3 (section 3.2, to be
+precise).
+.Rm 2 3.2
+.IP "\fB\-J\fP \fInumber\fP"
+.Ix 0 def flags -J
+Gives the absolute maximum number of targets to create at once on both
+local and remote machines.
+.IP "\fB\-L\fP \fInumber\fP"
+.Ix 0 def flags -L
+This specifies the maximum number of targets to create on the local
+machine at once. This may be 0, though you should be wary of doing
+this, as PMake may hang until a remote machine becomes available, if
+one is not available when it is started.
+.IP \fB\-M\fP
+.Ix 0 ref compatibility
+.Ix 0 def flags -M
+This is the flag that provides absolute, complete, full compatibility
+with Make. It still allows you to use all but a few of the features of
+PMake, but it is non-parallel. This is the mode PMake enters if you
+call it
+.CW make .'' ``
+.IP \fB\-P\fP
+.Ix 0 def flags -P
+.Ix 0 ref "output control"
+When creating targets in parallel, several shells are executing at
+once, each wanting to write its own two cent's-worth to the screen.
+This output must be captured by PMake in some way in order to prevent
+the screen from being filled with garbage even more indecipherable
+than you usually see. PMake has two ways of doing this, one of which
+provides for much cleaner output and a clear separation between the
+output of different jobs, the other of which provides a more immediate
+response so one can tell what is really happpening. The former is done
+by notifying you when the creation of a target starts, capturing the
+output and transferring it to the screen all at once when the job
+finishes. The latter is done by catching the output of the shell (and
+its children) and buffering it until an entire line is received, then
+printing that line preceded by an indication of which job produced
+the output. Since I prefer this second method, it is the one used by
+default. The first method will be used if you give the
+.B \-P
+flag to PMake.
+.IP \fB\-V\fP
+.Ix 0 def flags -V
+As mentioned before, the
+.B \-V
+flag tells PMake to use Make's style of expanding variables,
+substituting the empty string for any variable it doesn't know.
+.IP \fB\-W\fP
+.Ix 0 def flags -W
+There are several times when PMake will print a message at you that is
+only a warning, i.e. it can continue to work in spite of your having
+done something silly (such as forgotten a leading tab for a shell
+command). Sometimes you are well aware of silly things you have done
+and would like PMake to stop bothering you. This flag tells it to shut
+up about anything non-fatal.
+.IP \fB\-X\fP
+.Ix 0 def flags -X
+This flag causes PMake to not attempt to export any jobs to another
+machine.
+.LP
+Several flags may follow a single `\-'. Those flags that require
+arguments take them from successive parameters. E.g.
+.DS
+pmake -fDnI server.mk DEBUG /chip2/X/server/include
+.DE
+will cause PMake to read
+.CW server.mk
+as the input makefile, define the variable
+.CW DEBUG
+as a global variable and look for included makefiles in the directory
+.CW /chip2/X/server/include .
+.xH 2 Summary
+.LP
+A makefile is made of four types of lines:
+.RS
+.IP \(bu 2
+Dependency lines
+.IP \(bu 2
+Creation commands
+.IP \(bu 2
+Variable assignments
+.IP \(bu 2
+Comments, include statements and conditional directives
+.RE
+.LP
+A dependency line is a list of one or more targets, an operator
+.CW : ', (`
+.CW :: ', `
+or
+.CW ! '), `
+and a list of zero or more sources. Sources may contain wildcards and
+certain local variables.
+.LP
+A creation command is a regular shell command preceded by a tab. In
+addition, if the first two characters after the tab (and other
+whitespace) are a combination of
+.CW @ ' `
+or
+.CW - ', `
+PMake will cause the command to not be printed (if the character is
+.CW @ ') `
+or errors from it to be ignored (if
+.CW - '). `
+A blank line, dependency line or variable assignment terminates a
+creation script. There may be only one creation script for each target
+with a
+.CW : ' `
+or
+.CW ! ' `
+operator.
+.LP
+Variables are places to store text. They may be unconditionally
+assigned-to using the
+.CW = ' `
+.Ix 0 ref =
+.Ix 0 ref variable assignment
+operator, appended-to using the
+.CW += ' `
+.Ix 0 ref +=
+.Ix 0 ref variable assignment appended
+operator, conditionally (if the variable is undefined) assigned-to
+with the
+.CW ?= ' `
+.Ix 0 ref ?=
+.Ix 0 ref variable assignment conditional
+operator, and assigned-to with variable expansion with the
+.CW := ' `
+.Ix 0 ref :=
+.Ix 0 ref variable assignment expanded
+operator. The output of a shell command may be assigned to a variable
+using the
+.CW != ' `
+.Ix 0 ref !=
+.Ix 0 ref variable assignment shell-output
+operator. Variables may be expanded (their value inserted) by enclosing
+their name in parentheses or curly braces, prceeded by a dollar sign.
+A dollar sign may be escaped with another dollar sign. Variables are
+not expanded if PMake doesn't know about them. There are seven local
+variables:
+.CW .TARGET ,
+.CW .ALLSRC ,
+.CW .OODATE ,
+.CW .PREFIX ,
+.CW .IMPSRC ,
+.CW .ARCHIVE ,
+and
+.CW .MEMBER .
+Four of them
+.CW .TARGET , (
+.CW .PREFIX ,
+.CW .ARCHIVE ,
+and
+.CW .MEMBER )
+may be used to specify ``dynamic sources.''
+.Ix 0 ref "dynamic source"
+.Ix 0 ref source dynamic
+Variables are good. Know them. Love them. Live them.
+.LP
+Debugging of makefiles is best accomplished using the
+.B \-n ,
+.B "\-d m" ,
+and
+.B "\-p 2"
+flags.
+.xH 2 Exercises
+.ce
+\s+4\fBTBA\fP\s0
+.xH 1 Short-cuts and Other Nice Things
+.LP
+Based on what I've told you so far, you may have gotten the impression
+that PMake is just a way of storing away commands and making sure you
+don't forget to compile something. Good. That's just what it is.
+However, the ways I've described have been inelegant, at best, and
+painful, at worst.
+This chapter contains things that make the
+writing of makefiles easier and the makefiles themselves shorter and
+easier to modify (and, occasionally, simpler). In this chapter, I
+assume you are somewhat more
+familiar with Sprite (or UNIX, if that's what you're using) than I did
+in chapter 2, just so you're on your toes.
+So without further ado...
+.xH 2 Transformation Rules
+.LP
+As you know, a file's name consists of two parts: a base name, which
+gives some hint as to the contents of the file, and a suffix, which
+usually indicates the format of the file.
+Over the years, as
+.UX
+has developed,
+naming conventions, with regard to suffixes, have also developed that have
+become almost as incontrovertible as Law. E.g. a file ending in
+.CW .c
+is assumed to contain C source code; one with a
+.CW .o
+suffix is assumed to be a compiled, relocatable object file that may
+be linked into any program; a file with a
+.CW .ms
+suffix is usually a text file to be processed by Troff with the \-ms
+macro package, and so on.
+One of the best aspects of both Make and PMake comes from their
+understanding of how the suffix of a file pertains to its contents and
+their ability to do things with a file based soley on its suffix. This
+ability comes from something known as a transformation rule. A
+transformation rule specifies how to change a file with one suffix
+into a file with another suffix.
+.LP
+A transformation rule looks much like a dependency line, except the
+target is made of two known suffixes stuck together. Suffixes are made
+known to PMake by placing them as sources on a dependency line whose
+target is the special target
+.CW .SUFFIXES .
+E.g.
+.DS
+\&.SUFFIXES : .o .c
+\&.c.o :
+ $(CC) $(CFLAGS) -c $(.IMPSRC)
+.DE
+The creation script attached to the target is used to transform a file with
+the first suffix (in this case,
+.CW .c )
+into a file with the second suffix (here,
+.CW .o ).
+In addition, the target inherits whatever attributes have been applied
+to the transformation rule.
+The simple rule given above says that to transform a C source file
+into an object file, you compile it using
+.CW cc
+with the
+.CW \-c
+flag.
+This rule is taken straight from the system makefile. Many
+transformation rules (and suffixes) are defined there, and I refer you
+to it for more examples (type
+.CW "pmake -h" '' ``
+to find out where it is).
+.LP
+There are several things to note about the transformation rule given
+above:
+.RS
+.IP 1)
+The
+.CW .IMPSRC
+variable.
+.Ix 0 def variable local .IMPSRC
+.Ix 0 def .IMPSRC
+This variable is set to the ``implied source'' (the file from which
+the target is being created; the one with the first suffix), which, in this
+case, is the .c file.
+.IP 2)
+The
+.CW CFLAGS
+variable. Almost all of the transformation rules in the system
+makefile are set up using variables that you can alter in your
+makefile to tailor the rule to your needs. In this case, if you want
+all your C files to be compiled with the
+.B \-g
+flag, to provide information for
+.CW dbx ,
+you would set the
+.CW CFLAGS
+variable to contain
+.CW -g
+.CW "CFLAGS = -g" '') (``
+and PMake would take care of the rest.
+.RE
+.LP
+To give you a quick example, the makefile in 2.3.4
+.Rm 3 2.3.4
+could be changed to this:
+.DS
+OBJS = a.o b.o c.o
+program : $(OBJS)
+ $(CC) -o $(.TARGET) $(.ALLSRC)
+$(OBJS) : defs.h
+.DE
+The transformation rule I gave above takes the place of the 6 lines\**
+.FS
+This is also somewhat cleaner, I think, than the dynamic source
+solution presented in 2.6
+.FE
+.Rm 4 2.6
+.DS
+a.o : a.c
+ cc -c a.c
+b.o : b.c
+ cc -c b.c
+c.o : c.c
+ cc -c c.c
+.DE
+.LP
+Now you may be wondering about the dependency between the
+.CW .o
+and
+.CW .c
+files \*- it's not mentioned anywhere in the new makefile. This is
+because it isn't needed: one of the effects of applying a
+transformation rule is the target comes to depend on the implied
+source. That's why it's called the implied
+.I source .
+.LP
+For a more detailed example. Say you have a makefile like this:
+.DS
+a.out : a.o b.o
+ $(CC) $(.ALLSRC)
+.DE
+and a directory set up like this:
+.DS
+total 4
+-rw-rw-r-- 1 deboor 34 Sep 7 00:43 Makefile
+-rw-rw-r-- 1 deboor 119 Oct 3 19:39 a.c
+-rw-rw-r-- 1 deboor 201 Sep 7 00:43 a.o
+-rw-rw-r-- 1 deboor 69 Sep 7 00:43 b.c
+.DE
+While just typing
+.CW pmake '' ``
+will do the right thing, it's much more informative to type
+.CW "pmake -d s" ''. ``
+This will show you what PMake is up to as it processes the files. In
+this case, PMake prints the following:
+.DS
+Suff_FindDeps (a.out)
+ using existing source a.o
+ applying .o -> .out to "a.o"
+Suff_FindDeps (a.o)
+ trying a.c...got it
+ applying .c -> .o to "a.c"
+Suff_FindDeps (b.o)
+ trying b.c...got it
+ applying .c -> .o to "b.c"
+Suff_FindDeps (a.c)
+ trying a.y...not there
+ trying a.l...not there
+ trying a.c,v...not there
+ trying a.y,v...not there
+ trying a.l,v...not there
+Suff_FindDeps (b.c)
+ trying b.y...not there
+ trying b.l...not there
+ trying b.c,v...not there
+ trying b.y,v...not there
+ trying b.l,v...not there
+--- a.o ---
+cc -c a.c
+--- b.o ---
+cc -c b.c
+--- a.out ---
+cc a.o b.o
+.DE
+.LP
+.CW Suff_FindDeps
+is the name of a function in PMake that is called to check for implied
+sources for a target using transformation rules.
+The transformations it tries are, naturally
+enough, limited to the ones that have been defined (a transformation
+may be defined multiple times, by the way, but only the most recent
+one will be used). You will notice, however, that there is a definite
+order to the suffixes that are tried. This order is set by the
+relative positions of the suffixes on the
+.CW .SUFFIXES
+line \*- the earlier a suffix appears, the earlier it is checked as
+the source of a transformation. Once a suffix has been defined, the
+only way to change its position in the pecking order is to remove all
+the suffixes (by having a
+.CW .SUFFIXES
+dependency line with no sources) and redefine them in the order you
+want. (Previously-defined transformation rules will be automatically
+redefined as the suffixes they involve are re-entered.)
+.LP
+Another way to affect the search order is to make the dependency
+explicit. In the above example,
+.CW a.out
+depends on
+.CW a.o
+and
+.CW b.o .
+Since a transformation exists from
+.CW .o
+to
+.CW .out ,
+PMake uses that, as indicated by the
+.CW "using existing source a.o" '' ``
+message.
+.LP
+The search for a transformation starts from the suffix of the target
+and continues through all the defined transformations, in the order
+dictated by the suffix ranking, until an existing file with the same
+base (the target name minus the suffix and any leading directories) is
+found. At that point, one or more transformation rules will have been
+found to change the one existing file into the target.
+.LP
+For example, ignoring what's in the system makefile for now, say you
+have a makefile like this:
+.DS
+\&.SUFFIXES : .out .o .c .y .l
+\&.l.c :
+ lex $(.IMPSRC)
+ mv lex.yy.c $(.TARGET)
+\&.y.c :
+ yacc $(.IMPSRC)
+ mv y.tab.c $(.TARGET)
+\&.c.o :
+ cc -c $(.IMPSRC)
+\&.o.out :
+ cc -o $(.TARGET) $(.IMPSRC)
+.DE
+and the single file
+.CW jive.l .
+If you were to type
+.CW "pmake -rd ms jive.out" ,'' ``
+you would get the following output for
+.CW jive.out :
+.DS
+Suff_FindDeps (jive.out)
+ trying jive.o...not there
+ trying jive.c...not there
+ trying jive.y...not there
+ trying jive.l...got it
+ applying .l -> .c to "jive.l"
+ applying .c -> .o to "jive.c"
+ applying .o -> .out to "jive.o"
+.DE
+and this is why: PMake starts with the target
+.CW jive.out ,
+figures out its suffix
+.CW .out ) (
+and looks for things it can transform to a
+.CW .out
+file. In this case, it only finds
+.CW .o ,
+so it looks for the file
+.CW jive.o .
+It fails to find it, so it looks for transformations into a
+.CW .o
+file. Again it has only one choice:
+.CW .c .
+So it looks for
+.CW jive.c
+and, as you know, fails to find it. At this point it has two choices:
+it can create the
+.CW .c
+file from either a
+.CW .y
+file or a
+.CW .l
+file. Since
+.CW .y
+came first on the
+.CW .SUFFIXES
+line, it checks for
+.CW jive.y
+first, but can't find it, so it looks for
+.CW jive.l
+and, lo and behold, there it is.
+At this point, it has defined a transformation path as follows:
+.CW .l
+\(->
+.CW .c
+\(->
+.CW .o
+\(->
+.CW .out
+and applies the transformation rules accordingly. For completeness,
+and to give you a better idea of what PMake actually did with this
+three-step transformation, this is what PMake printed for the rest of
+the process:
+.DS
+Suff_FindDeps (jive.o)
+ using existing source jive.c
+ applying .c -> .o to "jive.c"
+Suff_FindDeps (jive.c)
+ using existing source jive.l
+ applying .l -> .c to "jive.l"
+Suff_FindDeps (jive.l)
+Examining jive.l...modified 17:16:01 Oct 4, 1987...up-to-date
+Examining jive.c...non-existent...out-of-date
+--- jive.c ---
+lex jive.l
+\&.\|.\|. meaningless lex output deleted .\|.\|.
+mv lex.yy.c jive.c
+Examining jive.o...non-existent...out-of-date
+--- jive.o ---
+cc -c jive.c
+Examining jive.out...non-existent...out-of-date
+--- jive.out ---
+cc -o jive.out jive.o
+.DE
+.LP
+One final question remains: what does PMake do with targets that have
+no known suffix? PMake simply pretends it actually has a known suffix
+and searches for transformations accordingly.
+The suffix it chooses is the source for the
+.CW .NULL
+.Ix 0 ref .NULL
+target mentioned later. In the system makefile,
+.CW .out
+is chosen as the ``null suffix''
+.Ix 0 def suffix null
+.Ix 0 def "null suffix"
+because most people use PMake to create programs. You are, however,
+free and welcome to change it to a suffix of your own choosing.
+The null suffix is ignored, however, when PMake is in compatibility
+mode (see chapter 4).
+.xH 2 Including Other Makefiles
+.Ix 0 def makefile inclusion
+.Rd 2
+.LP
+Just as for programs, it is often useful to extract certain parts of a
+makefile into another file and just include it in other makefiles
+somehow. Many compilers allow you say something like
+.DS
+#include "defs.h"
+.DE
+to include the contents of
+.CW defs.h
+in the source file. PMake allows you to do the same thing for
+makefiles, with the added ability to use variables in the filenames.
+An include directive in a makefile looks either like this:
+.DS
+#include <file>
+.DE
+or this
+.DS
+#include "file"
+.DE
+The difference between the two is where PMake searches for the file:
+the first way, PMake will look for
+the file only in the system makefile directory (or directories)
+(to find out what that directory is, give PMake the
+.B \-h
+flag).
+.Ix 0 ref flags -h
+The system makefile directory search path can be overridden via the
+.B \-m
+option.
+.Ix 0 ref flags -m
+For files in double-quotes, the search is more complex:
+.RS
+.IP 1)
+The directory of the makefile that's including the file.
+.IP 2)
+The current directory (the one in which you invoked PMake).
+.IP 3)
+The directories given by you using
+.B \-I
+flags, in the order in which you gave them.
+.IP 4)
+Directories given by
+.CW .PATH
+dependency lines (see chapter 4).
+.IP 5)
+The system makefile directory.
+.RE
+.LP
+in that order.
+.LP
+You are free to use PMake variables in the filename\*-PMake will
+expand them before searching for the file. You must specify the
+searching method with either angle brackets or double-quotes
+.I outside
+of a variable expansion. I.e. the following
+.DS
+SYSTEM = <command.mk>
+
+#include $(SYSTEM)
+.DE
+won't work.
+.xH 2 Saving Commands
+.LP
+.Ix 0 def ...
+There may come a time when you will want to save certain commands to
+be executed when everything else is done. For instance: you're
+making several different libraries at one time and you want to create the
+members in parallel. Problem is,
+.CW ranlib
+is another one of those programs that can't be run more than once in
+the same directory at the same time (each one creates a file called
+.CW __.SYMDEF
+into which it stuffs information for the linker to use. Two of them
+running at once will overwrite each other's file and the result will
+be garbage for both parties). You might want a way to save the ranlib
+commands til the end so they can be run one after the other, thus
+keeping them from trashing each other's file. PMake allows you to do
+this by inserting an ellipsis (``.\|.\|.'') as a command between
+commands to be run at once and those to be run later.
+.LP
+So for the
+.CW ranlib
+case above, you might do this:
+.Rd 5
+.DS
+lib1.a : $(LIB1OBJS)
+ rm -f $(.TARGET)
+ ar cr $(.TARGET) $(.ALLSRC)
+ ...
+ ranlib $(.TARGET)
+
+lib2.a : $(LIB2OBJS)
+ rm -f $(.TARGET)
+ ar cr $(.TARGET) $(.ALLSRC)
+ ...
+ ranlib $(.TARGET)
+.DE
+.Ix 0 ref variable local .TARGET
+.Ix 0 ref variable local .ALLSRC
+This would save both
+.DS
+ranlib $(.TARGET)
+.DE
+commands until the end, when they would run one after the other
+(using the correct value for the
+.CW .TARGET
+variable, of course).
+.LP
+Commands saved in this manner are only executed if PMake manages to
+re-create everything without an error.
+.xH 2 Target Attributes
+.LP
+PMake allows you to give attributes to targets by means of special
+sources. Like everything else PMake uses, these sources begin with a
+period and are made up of all upper-case letters. There are various
+reasons for using them, and I will try to give examples for most of
+them. Others you'll have to find uses for yourself. Think of it as ``an
+exercise for the reader.'' By placing one (or more) of these as a source on a
+dependency line, you are ``marking the target(s) with that
+attribute.'' That's just the way I phrase it, so you know.
+.LP
+Any attributes given as sources for a transformation rule are applied
+to the target of the transformation rule when the rule is applied.
+.Ix 0 def attributes
+.Ix 0 ref source
+.Ix 0 ref target
+.nr pw 12
+.IP .DONTCARE \n(pw
+.Ix 0 def attributes .DONTCARE
+.Ix 0 def .DONTCARE
+If a target is marked with this attribute and PMake can't figure out
+how to create it, it will ignore this fact and assume the file isn't
+really needed or actually exists and PMake just can't find it. This may prove
+wrong, but the error will be noted later on, not when PMake tries to create
+the target so marked. This attribute also prevents PMake from
+attempting to touch the target if it is given the
+.B \-t
+flag.
+.Ix 0 ref flags -t
+.IP .EXEC \n(pw
+.Ix 0 def attributes .EXEC
+.Ix 0 def .EXEC
+This attribute causes its shell script to be executed while having no
+effect on targets that depend on it. This makes the target into a sort
+of subroutine. An example. Say you have some LISP files that need to
+be compiled and loaded into a LISP process. To do this, you echo LISP
+commands into a file and execute a LISP with this file as its input
+when everything's done. Say also that you have to load other files
+from another system before you can compile your files and further,
+that you don't want to go through the loading and dumping unless one
+of
+.I your
+files has changed. Your makefile might look a little bit
+like this (remember, this is an educational example, and don't worry
+about the
+.CW COMPILE
+rule, all will soon become clear, grasshopper):
+.DS
+system : init a.fasl b.fasl c.fasl
+ for i in $(.ALLSRC);
+ do
+ echo -n '(load "' >> input
+ echo -n ${i} >> input
+ echo '")' >> input
+ done
+ echo '(dump "$(.TARGET)")' >> input
+ lisp < input
+
+a.fasl : a.l init COMPILE
+b.fasl : b.l init COMPILE
+c.fasl : c.l init COMPILE
+COMPILE : .USE
+ echo '(compile "$(.ALLSRC)")' >> input
+init : .EXEC
+ echo '(load-system)' > input
+.DE
+.Ix 0 ref .USE
+.Ix 0 ref attributes .USE
+.Ix 0 ref variable local .ALLSRC
+.IP "\&"
+.CW .EXEC
+sources, don't appear in the local variables of targets that depend on
+them (nor are they touched if PMake is given the
+.B \-t
+flag).
+.Ix 0 ref flags -t
+Note that all the rules, not just that for
+.CW system ,
+include
+.CW init
+as a source. This is because none of the other targets can be made
+until
+.CW init
+has been made, thus they depend on it.
+.IP .EXPORT \n(pw
+.Ix 0 def attributes .EXPORT
+.Ix 0 def .EXPORT
+This is used to mark those targets whose creation should be sent to
+another machine if at all possible. This may be used by some
+exportation schemes if the exportation is expensive. You should ask
+your system administrator if it is necessary.
+.IP .EXPORTSAME \n(pw
+.Ix 0 def attributes .EXPORTSAME
+.Ix 0 def .EXPORTSAME
+Tells the export system that the job should be exported to a machine
+of the same architecture as the current one. Certain operations (e.g.
+running text through
+.CW nroff )
+can be performed the same on any architecture (CPU and
+operating system type), while others (e.g. compiling a program with
+.CW cc )
+must be performed on a machine with the same architecture. Not all
+export systems will support this attribute.
+.IP .IGNORE \n(pw
+.Ix 0 def attributes .IGNORE
+.Ix 0 def .IGNORE attribute
+Giving a target the
+.CW .IGNORE
+attribute causes PMake to ignore errors from any of the target's commands, as
+if they all had `\-' before them.
+.IP .INVISIBLE \n(pw
+.Ix 0 def attributes .INVISIBLE
+.Ix 0 def .INVISIBLE
+This allows you to specify one target as a source for another without
+the one affecting the other's local variables. Useful if, say, you
+have a makefile that creates two programs, one of which is used to
+create the other, so it must exist before the other is created. You
+could say
+.DS
+prog1 : $(PROG1OBJS) prog2 MAKEINSTALL
+prog2 : $(PROG2OBJS) .INVISIBLE MAKEINSTALL
+.DE
+where
+.CW MAKEINSTALL
+is some complex .USE rule (see below) that depends on the
+.Ix 0 ref .USE
+.CW .ALLSRC
+variable containing the right things. Without the
+.CW .INVISIBLE
+attribute for
+.CW prog2 ,
+the
+.CW MAKEINSTALL
+rule couldn't be applied. This is not as useful as it should be, and
+the semantics may change (or the whole thing go away) in the
+not-too-distant future.
+.IP .JOIN \n(pw
+.Ix 0 def attributes .JOIN
+.Ix 0 def .JOIN
+This is another way to avoid performing some operations in parallel
+while permitting everything else to be done so. Specifically it
+forces the target's shell script to be executed only if one or more of the
+sources was out-of-date. In addition, the target's name,
+in both its
+.CW .TARGET
+variable and all the local variables of any target that depends on it,
+is replaced by the value of its
+.CW .ALLSRC
+variable.
+As an example, suppose you have a program that has four libraries that
+compile in the same directory along with, and at the same time as, the
+program. You again have the problem with
+.CW ranlib
+that I mentioned earlier, only this time it's more severe: you
+can't just put the ranlib off to the end since the program
+will need those libraries before it can be re-created. You can do
+something like this:
+.DS
+program : $(OBJS) libraries
+ cc -o $(.TARGET) $(.ALLSRC)
+
+libraries : lib1.a lib2.a lib3.a lib4.a .JOIN
+ ranlib $(.OODATE)
+.DE
+.Ix 0 ref variable local .TARGET
+.Ix 0 ref variable local .ALLSRC
+.Ix 0 ref variable local .OODATE
+.Ix 0 ref .TARGET
+.Ix 0 ref .ALLSRC
+.Ix 0 ref .OODATE
+In this case, PMake will re-create the
+.CW $(OBJS)
+as necessary, along with
+.CW lib1.a ,
+.CW lib2.a ,
+.CW lib3.a
+and
+.CW lib4.a .
+It will then execute
+.CW ranlib
+on any library that was changed and set
+.CW program 's
+.CW .ALLSRC
+variable to contain what's in
+.CW $(OBJS)
+followed by
+.CW "lib1.a lib2.a lib3.a lib4.a" .'' ``
+In case you're wondering, it's called
+.CW .JOIN
+because it joins together different threads of the ``input graph'' at
+the target marked with the attribute.
+Another aspect of the .JOIN attribute is it keeps the target from
+being created if the
+.B \-t
+flag was given.
+.Ix 0 ref flags -t
+.IP .MAKE \n(pw
+.Ix 0 def attributes .MAKE
+.Ix 0 def .MAKE
+The
+.CW .MAKE
+attribute marks its target as being a recursive invocation of PMake.
+This forces PMake to execute the script associated with the target (if
+it's out-of-date) even if you gave the
+.B \-n
+or
+.B \-t
+flag. By doing this, you can start at the top of a system and type
+.DS
+pmake -n
+.DE
+and have it descend the directory tree (if your makefiles are set up
+correctly), printing what it would have executed if you hadn't
+included the
+.B \-n
+flag.
+.IP .NOEXPORT \n(pw
+.Ix 0 def attributes .NOEXPORT
+.Ix 0 def .NOEXPORT attribute
+If possible, PMake will attempt to export the creation of all targets to
+another machine (this depends on how PMake was configured). Sometimes,
+the creation is so simple, it is pointless to send it to another
+machine. If you give the target the
+.CW .NOEXPORT
+attribute, it will be run locally, even if you've given PMake the
+.B "\-L 0"
+flag.
+.IP .NOTMAIN \n(pw
+.Ix 0 def attributes .NOTMAIN
+.Ix 0 def .NOTMAIN
+Normally, if you do not specify a target to make in any other way,
+PMake will take the first target on the first dependency line of a
+makefile as the target to create. That target is known as the ``Main
+Target'' and is labeled as such if you print the dependencies out
+using the
+.B \-p
+flag.
+.Ix 0 ref flags -p
+Giving a target this attribute tells PMake that the target is
+definitely
+.I not
+the Main Target.
+This allows you to place targets in an included makefile and
+have PMake create something else by default.
+.IP .PRECIOUS \n(pw
+.Ix 0 def attributes .PRECIOUS
+.Ix 0 def .PRECIOUS attribute
+When PMake is interrupted (you type control-C at the keyboard), it
+will attempt to clean up after itself by removing any half-made
+targets. If a target has the
+.CW .PRECIOUS
+attribute, however, PMake will leave it alone. An additional side
+effect of the `::' operator is to mark the targets as
+.CW .PRECIOUS .
+.Ix 0 ref operator double-colon
+.Ix 0 ref ::
+.IP .SILENT \n(pw
+.Ix 0 def attributes .SILENT
+.Ix 0 def .SILENT attribute
+Marking a target with this attribute keeps its commands from being
+printed when they're executed, just as if they had an `@' in front of them.
+.IP .USE \n(pw
+.Ix 0 def attributes .USE
+.Ix 0 def .USE
+By giving a target this attribute, you turn it into PMake's equivalent
+of a macro. When the target is used as a source for another target,
+the other target acquires the commands, sources and attributes (except
+.CW .USE )
+of the source.
+If the target already has commands, the
+.CW .USE
+target's commands are added to the end. If more than one .USE-marked
+source is given to a target, the rules are applied sequentially.
+.IP "\&" \n(pw
+The typical .USE rule (as I call them) will use the sources of the
+target to which it is applied (as stored in the
+.CW .ALLSRC
+variable for the target) as its ``arguments,'' if you will.
+For example, you probably noticed that the commands for creating
+.CW lib1.a
+and
+.CW lib2.a
+in the example in section 3.3
+.Rm 5 3.3
+were exactly the same. You can use the
+.CW .USE
+attribute to eliminate the repetition, like so:
+.DS
+lib1.a : $(LIB1OBJS) MAKELIB
+lib2.a : $(LIB2OBJS) MAKELIB
+
+MAKELIB : .USE
+ rm -f $(.TARGET)
+ ar cr $(.TARGET) $(.ALLSRC)
+ ...
+ ranlib $(.TARGET)
+.DE
+.Ix 0 ref variable local .TARGET
+.Ix 0 ref variable local .ALLSRC
+.IP "\&" \n(pw
+Several system makefiles (not to be confused with The System Makefile)
+make use of these .USE rules to make your
+life easier (they're in the default, system makefile directory...take a look).
+Note that the .USE rule source itself
+.CW MAKELIB ) (
+does not appear in any of the targets's local variables.
+There is no limit to the number of times I could use the
+.CW MAKELIB
+rule. If there were more libraries, I could continue with
+.CW "lib3.a : $(LIB3OBJS) MAKELIB" '' ``
+and so on and so forth.
+.xH 2 Special Targets
+.LP
+As there were in Make, so there are certain targets that have special
+meaning to PMake. When you use one on a dependency line, it is the
+only target that may appear on the left-hand-side of the operator.
+.Ix 0 ref target
+.Ix 0 ref operator
+As for the attributes and variables, all the special targets
+begin with a period and consist of upper-case letters only.
+I won't describe them all in detail because some of them are rather
+complex and I'll describe them in more detail than you'll want in
+chapter 4.
+The targets are as follows:
+.nr pw 10
+.IP .BEGIN \n(pw
+.Ix 0 def .BEGIN
+Any commands attached to this target are executed before anything else
+is done. You can use it for any initialization that needs doing.
+.IP .DEFAULT \n(pw
+.Ix 0 def .DEFAULT
+This is sort of a .USE rule for any target (that was used only as a
+source) that PMake can't figure out any other way to create. It's only
+``sort of'' a .USE rule because only the shell script attached to the
+.CW .DEFAULT
+target is used. The
+.CW .IMPSRC
+variable of a target that inherits
+.CW .DEFAULT 's
+commands is set to the target's own name.
+.Ix 0 ref .IMPSRC
+.Ix 0 ref variable local .IMPSRC
+.IP .END \n(pw
+.Ix 0 def .END
+This serves a function similar to
+.CW .BEGIN ,
+in that commands attached to it are executed once everything has been
+re-created (so long as no errors occurred). It also serves the extra
+function of being a place on which PMake can hang commands you put off
+to the end. Thus the script for this target will be executed before
+any of the commands you save with the ``.\|.\|.''.
+.Ix 0 ref ...
+.IP .EXPORT \n(pw
+The sources for this target are passed to the exportation system compiled
+into PMake. Some systems will use these sources to configure
+themselves. You should ask your system administrator about this.
+.IP .IGNORE \n(pw
+.Ix 0 def .IGNORE target
+.Ix 0 ref .IGNORE attribute
+.Ix 0 ref attributes .IGNORE
+This target marks each of its sources with the
+.CW .IGNORE
+attribute. If you don't give it any sources, then it is like
+giving the
+.B \-i
+flag when you invoke PMake \*- errors are ignored for all commands.
+.Ix 0 ref flags -i
+.IP .INCLUDES \n(pw
+.Ix 0 def .INCLUDES target
+.Ix 0 def variable global .INCLUDES
+.Ix 0 def .INCLUDES variable
+The sources for this target are taken to be suffixes that indicate a
+file that can be included in a program source file.
+The suffix must have already been declared with
+.CW .SUFFIXES
+(see below).
+Any suffix so marked will have the directories on its search path
+(see
+.CW .PATH ,
+below) placed in the
+.CW .INCLUDES
+variable, each preceded by a
+.B \-I
+flag. This variable can then be used as an argument for the compiler
+in the normal fashion. The
+.CW .h
+suffix is already marked in this way in the system makefile.
+.Ix 0 ref makefile system
+E.g. if you have
+.DS
+\&.SUFFIXES : .bitmap
+\&.PATH.bitmap : /usr/local/X/lib/bitmaps
+\&.INCLUDES : .bitmap
+.DE
+PMake will place
+.CW "-I/usr/local/X/lib/bitmaps" '' ``
+in the
+.CW .INCLUDES
+variable and you can then say
+.DS
+cc $(.INCLUDES) -c xprogram.c
+.DE
+(Note: the
+.CW .INCLUDES
+variable is not actually filled in until the entire makefile has been read.)
+.IP .INTERRUPT \n(pw
+.Ix 0 def .INTERRUPT
+When PMake is interrupted,
+it will execute the commands in the script for this target, if it
+exists.
+.IP .LIBS \n(pw
+.Ix 0 def .LIBS target
+.Ix 0 def .LIBS variable
+.Ix 0 def variable global .LIBS
+This does for libraries what
+.CW .INCLUDES
+does for include files, except the flag used is
+.B \-L ,
+as required by those linkers that allow you to tell them where to find
+libraries. The variable used is
+.CW .LIBS .
+Be forewarned that PMake may not have been compiled to do this if the
+linker on your system doesn't accept the
+.B \-L
+flag, though the
+.CW .LIBS
+variable will always be defined once the makefile has been read.
+.IP .MAIN \n(pw
+.Ix 0 def .MAIN
+If you didn't give a target (or targets) to create when you invoked
+PMake, it will take the sources of this target as the targets to
+create.
+.IP .MAKEFLAGS \n(pw
+.Ix 0 def .MAKEFLAGS target
+This target provides a way for you to always specify flags for PMake
+when the makefile is used. The flags are just as they would be typed
+to the shell (except you can't use shell variables unless they're in
+the environment),
+though the
+.B \-f
+and
+.B \-r
+flags have no effect.
+.IP .NULL \n(pw
+.Ix 0 def .NULL
+.Ix 0 ref suffix null
+.Ix 0 ref "null suffix"
+This allows you to specify what suffix PMake should pretend a file has
+if, in fact, it has no known suffix. Only one suffix may be so
+designated. The last source on the dependency line is the suffix that
+is used (you should, however, only give one suffix.\|.\|.).
+.IP .PATH \n(pw
+.Ix 0 def .PATH
+If you give sources for this target, PMake will take them as
+directories in which to search for files it cannot find in the current
+directory. If you give no sources, it will clear out any directories
+added to the search path before. Since the effects of this all get
+very complex, I'll leave it til chapter four to give you a complete
+explanation.
+.IP .PATH\fIsuffix\fP \n(pw
+.Ix 0 ref .PATH
+This does a similar thing to
+.CW .PATH ,
+but it does it only for files with the given suffix. The suffix must
+have been defined already. Look at
+.B "Search Paths"
+(section 4.1)
+.Rm 6 4.1
+for more information.
+.IP .PRECIOUS \n(pw
+.Ix 0 def .PRECIOUS target
+.Ix 0 ref .PRECIOUS attribute
+.Ix 0 ref attributes .PRECIOUS
+Similar to
+.CW .IGNORE ,
+this gives the
+.CW .PRECIOUS
+attribute to each source on the dependency line, unless there are no
+sources, in which case the
+.CW .PRECIOUS
+attribute is given to every target in the file.
+.IP .RECURSIVE \n(pw
+.Ix 0 def .RECURSIVE
+.Ix 0 ref attributes .MAKE
+.Ix 0 ref .MAKE
+This target applies the
+.CW .MAKE
+attribute to all its sources. It does nothing if you don't give it any sources.
+.IP .SHELL \n(pw
+.Ix 0 def .SHELL
+PMake is not constrained to only using the Bourne shell to execute
+the commands you put in the makefile. You can tell it some other shell
+to use with this target. Check out
+.B "A Shell is a Shell is a Shell"
+(section 4.4)
+.Rm 7 4.4
+for more information.
+.IP .SILENT \n(pw
+.Ix 0 def .SILENT target
+.Ix 0 ref .SILENT attribute
+.Ix 0 ref attributes .SILENT
+When you use
+.CW .SILENT
+as a target, it applies the
+.CW .SILENT
+attribute to each of its sources. If there are no sources on the
+dependency line, then it is as if you gave PMake the
+.B \-s
+flag and no commands will be echoed.
+.IP .SUFFIXES \n(pw
+.Ix 0 def .SUFFIXES
+This is used to give new file suffixes for PMake to handle. Each
+source is a suffix PMake should recognize. If you give a
+.CW .SUFFIXES
+dependency line with no sources, PMake will forget about all the
+suffixes it knew (this also nukes the null suffix).
+For those targets that need to have suffixes defined, this is how you do it.
+.LP
+In addition to these targets, a line of the form
+.DS
+\fIattribute\fP : \fIsources\fP
+.DE
+applies the
+.I attribute
+to all the targets listed as
+.I sources .
+.xH 2 Modifying Variable Expansion
+.LP
+.Ix 0 def variable expansion modified
+.Ix 0 ref variable expansion
+.Ix 0 def variable modifiers
+Variables need not always be expanded verbatim. PMake defines several
+modifiers that may be applied to a variable's value before it is
+expanded. You apply a modifier by placing it after the variable name
+with a colon between the two, like so:
+.DS
+${\fIVARIABLE\fP:\fImodifier\fP}
+.DE
+Each modifier is a single character followed by something specific to
+the modifier itself.
+You may apply as many modifiers as you want \*- each one is applied to
+the result of the previous and is separated from the previous by
+another colon.
+.LP
+There are seven ways to modify a variable's expansion, most of which
+come from the C shell variable modification characters:
+.RS
+.IP "M\fIpattern\fP"
+.Ix 0 def :M
+.Ix 0 def modifier match
+This is used to select only those words (a word is a series of
+characters that are neither spaces nor tabs) that match the given
+.I pattern .
+The pattern is a wildcard pattern like that used by the shell, where
+.CW *
+means 0 or more characters of any sort;
+.CW ?
+is any single character;
+.CW [abcd]
+matches any single character that is either `a', `b', `c' or `d'
+(there may be any number of characters between the brackets);
+.CW [0-9]
+matches any single character that is between `0' and `9' (i.e. any
+digit. This form may be freely mixed with the other bracket form), and
+`\\' is used to escape any of the characters `*', `?', `[' or `:',
+leaving them as regular characters to match themselves in a word.
+For example, the system makefile
+.CW <makedepend.mk>
+uses
+.CW "$(CFLAGS:M-[ID]*)" '' ``
+to extract all the
+.CW \-I
+and
+.CW \-D
+flags that would be passed to the C compiler. This allows it to
+properly locate include files and generate the correct dependencies.
+.IP "N\fIpattern\fP"
+.Ix 0 def :N
+.Ix 0 def modifier nomatch
+This is identical to
+.CW :M
+except it substitutes all words that don't match the given pattern.
+.IP "S/\fIsearch-string\fP/\fIreplacement-string\fP/[g]"
+.Ix 0 def :S
+.Ix 0 def modifier substitute
+Causes the first occurrence of
+.I search-string
+in the variable to be replaced by
+.I replacement-string ,
+unless the
+.CW g
+flag is given at the end, in which case all occurences of the string
+are replaced. The substitution is performed on each word in the
+variable in turn. If
+.I search-string
+begins with a
+.CW ^ ,
+the string must match starting at the beginning of the word. If
+.I search-string
+ends with a
+.CW $ ,
+the string must match to the end of the word (these two may be
+combined to force an exact match). If a backslash preceeds these two
+characters, however, they lose their special meaning. Variable
+expansion also occurs in the normal fashion inside both the
+.I search-string
+and the
+.I replacement-string ,
+.B except
+that a backslash is used to prevent the expansion of a
+.CW $ ,
+not another dollar sign, as is usual.
+Note that
+.I search-string
+is just a string, not a pattern, so none of the usual
+regular-expression/wildcard characters have any special meaning save
+.CW ^
+and
+.CW $ .
+In the replacement string,
+the
+.CW &
+character is replaced by the
+.I search-string
+unless it is preceded by a backslash.
+You are allowed to use any character except
+colon or exclamation point to separate the two strings. This so-called
+delimiter character may be placed in either string by preceeding it
+with a backslash.
+.IP T
+.Ix 0 def :T
+.Ix 0 def modifier tail
+Replaces each word in the variable expansion by its last
+component (its ``tail''). For example, given
+.DS
+OBJS = ../lib/a.o b /usr/lib/libm.a
+TAILS = $(OBJS:T)
+.DE
+the variable
+.CW TAILS
+would expand to
+.CW "a.o b libm.a" .'' ``
+.IP H
+.Ix 0 def :H
+.Ix 0 def modifier head
+This is similar to
+.CW :T ,
+except that every word is replaced by everything but the tail (the
+``head''). Using the same definition of
+.CW OBJS ,
+the string
+.CW "$(OBJS:H)" '' ``
+would expand to
+.CW "../lib /usr/lib" .'' ``
+Note that the final slash on the heads is removed and
+anything without a head is replaced by the empty string.
+.IP E
+.Ix 0 def :E
+.Ix 0 def modifier extension
+.Ix 0 def modifier suffix
+.Ix 0 ref suffix "variable modifier"
+.CW :E
+replaces each word by its suffix (``extension''). So
+.CW "$(OBJS:E)" '' ``
+would give you
+.CW ".o .a" .'' ``
+.IP R
+.Ix 0 def :R
+.Ix 0 def modifier root
+.Ix 0 def modifier base
+This replaces each word by everything but the suffix (the ``root'' of
+the word).
+.CW "$(OBJS:R)" '' ``
+expands to ``
+.CW "../lib/a b /usr/lib/libm" .''
+.RE
+.LP
+In addition, the System V style of substitution is also supported.
+This looks like:
+.DS
+$(\fIVARIABLE\fP:\fIsearch-string\fP=\fIreplacement\fP)
+.DE
+It must be the last modifier in the chain. The search is anchored at
+the end of each word, so only suffixes or whole words may be replaced.
+.xH 2 More on Debugging
+.xH 2 More Exercises
+.IP (3.1)
+You've got a set programs, each of which is created from its own
+assembly-language source file (suffix
+.CW .asm ).
+Each program can be assembled into two versions, one with error-checking
+code assembled in and one without. You could assemble them into files
+with different suffixes
+.CW .eobj \& (
+and
+.CW .obj ,
+for instance), but your linker only understands files that end in
+.CW .obj .
+To top it all off, the final executables
+.I must
+have the suffix
+.CW .exe .
+How can you still use transformation rules to make your life easier
+(Hint: assume the error-checking versions have
+.CW ec
+tacked onto their prefix)?
+.IP (3.2)
+Assume, for a moment or two, you want to perform a sort of
+``indirection'' by placing the name of a variable into another one,
+then you want to get the value of the first by expanding the second
+somehow. Unfortunately, PMake doesn't allow constructs like
+.DS I
+$($(FOO))
+.DE
+What do you do? Hint: no further variable expansion is performed after
+modifiers are applied, thus if you cause a $ to occur in the
+expansion, that's what will be in the result.
+.xH 1 PMake for Gods
+.LP
+This chapter is devoted to those facilities in PMake that allow you to
+do a great deal in a makefile with very little work, as well as do
+some things you couldn't do in Make without a great deal of work (and
+perhaps the use of other programs). The problem with these features,
+is they must be handled with care, or you will end up with a mess.
+.LP
+Once more, I assume a greater familiarity with
+.UX
+or Sprite than I did in the previous two chapters.
+.xH 2 Search Paths
+.Rd 6
+.LP
+PMake supports the dispersal of files into multiple directories by
+allowing you to specify places to look for sources with
+.CW .PATH
+targets in the makefile. The directories you give as sources for these
+targets make up a ``search path.'' Only those files used exclusively
+as sources are actually sought on a search path, the assumption being
+that anything listed as a target in the makefile can be created by the
+makefile and thus should be in the current directory.
+.LP
+There are two types of search paths
+in PMake: one is used for all types of files (including included
+makefiles) and is specified with a plain
+.CW .PATH
+target (e.g.
+.CW ".PATH : RCS" ''), ``
+while the other is specific to a certain type of file, as indicated by
+the file's suffix. A specific search path is indicated by immediately following
+the
+.CW .PATH
+with the suffix of the file. For instance
+.DS
+\&.PATH.h : /sprite/lib/include /sprite/att/lib/include
+.DE
+would tell PMake to look in the directories
+.CW /sprite/lib/include
+and
+.CW /sprite/att/lib/include
+for any files whose suffix is
+.CW .h .
+.LP
+The current directory is always consulted first to see if a file
+exists. Only if it cannot be found there are the directories in the
+specific search path, followed by those in the general search path,
+consulted.
+.LP
+A search path is also used when expanding wildcard characters. If the
+pattern has a recognizable suffix on it, the path for that suffix will
+be used for the expansion. Otherwise the default search path is employed.
+.LP
+When a file is found in some directory other than the current one, all
+local variables that would have contained the target's name
+.CW .ALLSRC , (
+and
+.CW .IMPSRC )
+will instead contain the path to the file, as found by PMake.
+Thus if you have a file
+.CW ../lib/mumble.c
+and a makefile
+.DS
+\&.PATH.c : ../lib
+mumble : mumble.c
+ $(CC) -o $(.TARGET) $(.ALLSRC)
+.DE
+the command executed to create
+.CW mumble
+would be
+.CW "cc -o mumble ../lib/mumble.c" .'' ``
+(As an aside, the command in this case isn't strictly necessary, since
+it will be found using transformation rules if it isn't given. This is because
+.CW .out
+is the null suffix by default and a transformation exists from
+.CW .c
+to
+.CW .out .
+Just thought I'd throw that in.)
+.LP
+If a file exists in two directories on the same search path, the file
+in the first directory on the path will be the one PMake uses. So if
+you have a large system spread over many directories, it would behoove
+you to follow a naming convention that avoids such conflicts.
+.LP
+Something you should know about the way search paths are implemented
+is that each directory is read, and its contents cached, exactly once
+\&\*- when it is first encountered \*- so any changes to the
+directories while PMake is running will not be noted when searching
+for implicit sources, nor will they be found when PMake attempts to
+discover when the file was last modified, unless the file was created in the
+current directory. While people have suggested that PMake should read
+the directories each time, my experience suggests that the caching seldom
+causes problems. In addition, not caching the directories slows things
+down enormously because of PMake's attempts to apply transformation
+rules through non-existent files \*- the number of extra file-system
+searches is truly staggering, especially if many files without
+suffixes are used and the null suffix isn't changed from
+.CW .out .
+.xH 2 Archives and Libraries
+.LP
+.UX
+and Sprite allow you to merge files into an archive using the
+.CW ar
+command. Further, if the files are relocatable object files, you can
+run
+.CW ranlib
+on the archive and get yourself a library that you can link into any
+program you want. The main problem with archives is they double the
+space you need to store the archived files, since there's one copy in
+the archive and one copy out by itself. The problem with libraries is
+you usually think of them as
+.CW -lm
+rather than
+.CW /usr/lib/libm.a
+and the linker thinks they're out-of-date if you so much as look at
+them.
+.LP
+PMake solves the problem with archives by allowing you to tell it to
+examine the files in the archives (so you can remove the individual
+files without having to regenerate them later). To handle the problem
+with libraries, PMake adds an additional way of deciding if a library
+is out-of-date:
+.IP \(bu 2
+If the table of contents is older than the library, or is missing, the
+library is out-of-date.
+.LP
+A library is any target that looks like
+.CW \-l name'' ``
+or that ends in a suffix that was marked as a library using the
+.CW .LIBS
+target.
+.CW .a
+is so marked in the system makefile.
+.LP
+Members of an archive are specified as
+``\fIarchive\fP(\fImember\fP[ \fImember\fP...])''.
+Thus
+.CW libdix.a(window.o) '' ``'
+specifies the file
+.CW window.o
+in the archive
+.CW libdix.a .
+You may also use wildcards to specify the members of the archive. Just
+remember that most the wildcard characters will only find
+.I existing
+files.
+.LP
+A file that is a member of an archive is treated specially. If the
+file doesn't exist, but it is in the archive, the modification time
+recorded in the archive is used for the file when determining if the
+file is out-of-date. When figuring out how to make an archived member target
+(not the file itself, but the file in the archive \*- the
+\fIarchive\fP(\fImember\fP) target), special care is
+taken with the transformation rules, as follows:
+.IP \(bu 2
+\&\fIarchive\fP(\fImember\fP) is made to depend on \fImember\fP.
+.IP \(bu 2
+The transformation from the \fImember\fP's suffix to the
+\fIarchive\fP's suffix is applied to the \fIarchive\fP(\fImember\fP) target.
+.IP \(bu 2
+The \fIarchive\fP(\fImember\fP)'s
+.CW .TARGET
+variable is set to the name of the \fImember\fP if \fImember\fP is
+actually a target, or the path to the member file if \fImember\fP is
+only a source.
+.IP \(bu 2
+The
+.CW .ARCHIVE
+variable for the \fIarchive\fP(\fImember\fP) target is set to the name
+of the \fIarchive\fP.
+.Ix 0 def variable local .ARCHIVE
+.Ix 0 def .ARCHIVE
+.IP \(bu 2
+The
+.CW .MEMBER
+variable is set to the actual string inside the parentheses. In most
+cases, this will be the same as the
+.CW .TARGET
+variable.
+.Ix 0 def variable local .MEMBER
+.Ix 0 def .MEMBER
+.IP \(bu 2
+The \fIarchive\fP(\fImember\fP)'s place in the local variables of the
+targets that depend on it is taken by the value of its
+.CW .TARGET
+variable.
+.LP
+Thus, a program library could be created with the following makefile:
+.DS
+\&.o.a :
+ ...
+ rm -f $(.TARGET:T)
+OBJS = obj1.o obj2.o obj3.o
+libprog.a : libprog.a($(OBJS))
+ ar cru $(.TARGET) $(.OODATE)
+ ranlib $(.TARGET)
+.DE
+This will cause the three object files to be compiled (if the
+corresponding source files were modified after the object file or, if
+that doesn't exist, the archived object file), the out-of-date ones
+archived in
+.CW libprog.a ,
+a table of contents placed in the archive and the newly-archived
+object files to be removed.
+.LP
+All this is used in the
+.CW makelib.mk
+system makefile to create a single library with ease. This makefile
+looks like this:
+.DS
+.SM
+#
+# Rules for making libraries. The object files that make up the library are
+# removed once they are archived.
+#
+# To make several libararies in parallel, you should define the variable
+# "many_libraries". This will serialize the invocations of ranlib.
+#
+# To use, do something like this:
+#
+# OBJECTS = <files in the library>
+#
+# fish.a: fish.a($(OBJECTS)) MAKELIB
+#
+#
+
+#ifndef _MAKELIB_MK
+_MAKELIB_MK =
+
+#include <po.mk>
+
+\&.po.a .o.a :
+ ...
+ rm -f $(.MEMBER)
+
+ARFLAGS ?= crl
+
+#
+# Re-archive the out-of-date members and recreate the library's table of
+# contents using ranlib. If many_libraries is defined, put the ranlib off
+# til the end so many libraries can be made at once.
+#
+MAKELIB : .USE .PRECIOUS
+ ar $(ARFLAGS) $(.TARGET) $(.OODATE)
+#ifndef no_ranlib
+# ifdef many_libraries
+ ...
+# endif many_libraries
+ ranlib $(.TARGET)
+#endif no_ranlib
+
+#endif _MAKELIB_MK
+.DE
+.xH 2 On the Condition...
+.Rd 1
+.LP
+Like the C compiler before it, PMake allows you to configure the makefile,
+based on the current environment, using conditional statements. A
+conditional looks like this:
+.DS
+#if \fIboolean expression\fP
+\fIlines\fP
+#elif \fIanother boolean expression\fP
+\fImore lines\fP
+#else
+\fIstill more lines\fP
+#endif
+.DE
+They may be nested to a maximum depth of 30 and may occur anywhere
+(except in a comment, of course). The
+.CW # '' ``
+must the very first character on the line.
+.LP
+Each
+.I "boolean expression"
+is made up of terms that look like function calls, the standard C
+boolean operators
+.CW && ,
+.CW || ,
+and
+.CW ! ,
+and the standard relational operators
+.CW == ,
+.CW != ,
+.CW > ,
+.CW >= ,
+.CW < ,
+and
+.CW <= ,
+with
+.CW ==
+and
+.CW !=
+being overloaded to allow string comparisons as well.
+.CW &&
+represents logical AND;
+.CW ||
+is logical OR and
+.CW !
+is logical NOT. The arithmetic and string operators take precedence
+over all three of these operators, while NOT takes precedence over
+AND, which takes precedence over OR. This precedence may be
+overridden with parentheses, and an expression may be parenthesized to
+your heart's content. Each term looks like a call on one of four
+functions:
+.nr pw 9
+.Ix 0 def make
+.Ix 0 def conditional make
+.Ix 0 def if make
+.IP make \n(pw
+The syntax is
+.CW make( \fItarget\fP\c
+.CW )
+where
+.I target
+is a target in the makefile. This is true if the given target was
+specified on the command line, or as the source for a
+.CW .MAIN
+target (note that the sources for
+.CW .MAIN
+are only used if no targets were given on the command line).
+.IP defined \n(pw
+.Ix 0 def defined
+.Ix 0 def conditional defined
+.Ix 0 def if defined
+The syntax is
+.CW defined( \fIvariable\fP\c
+.CW )
+and is true if
+.I variable
+is defined. Certain variables are defined in the system makefile that
+identify the system on which PMake is being run.
+.IP exists \n(pw
+.Ix 0 def exists
+.Ix 0 def conditional exists
+.Ix 0 def if exists
+The syntax is
+.CW exists( \fIfile\fP\c
+.CW )
+and is true if the file can be found on the global search path (i.e.
+that defined by
+.CW .PATH
+targets, not by
+.CW .PATH \fIsuffix\fP
+targets).
+.IP empty \n(pw
+.Ix 0 def empty
+.Ix 0 def conditional empty
+.Ix 0 def if empty
+This syntax is much like the others, except the string inside the
+parentheses is of the same form as you would put between parentheses
+when expanding a variable, complete with modifiers and everything. The
+function returns true if the resulting string is empty (NOTE: an undefined
+variable in this context will cause at the very least a warning
+message about a malformed conditional, and at the worst will cause the
+process to stop once it has read the makefile. If you want to check
+for a variable being defined or empty, use the expression
+.CW !defined( \fIvar\fP\c ``
+.CW ") || empty(" \fIvar\fP\c
+.CW ) ''
+as the definition of
+.CW ||
+will prevent the
+.CW empty()
+from being evaluated and causing an error, if the variable is
+undefined). This can be used to see if a variable contains a given
+word, for example:
+.DS
+#if !empty(\fIvar\fP:M\fIword\fP)
+.DE
+.LP
+The arithmetic and string operators may only be used to test the value
+of a variable. The lefthand side must contain the variable expansion,
+while the righthand side contains either a string, enclosed in
+double-quotes, or a number. The standard C numeric conventions (except
+for specifying an octal number) apply to both sides. E.g.
+.DS
+#if $(OS) == 4.3
+
+#if $(MACHINE) == "sun3"
+
+#if $(LOAD_ADDR) < 0xc000
+.DE
+are all valid conditionals. In addition, the numeric value of a
+variable can be tested as a boolean as follows:
+.DS
+#if $(LOAD)
+.DE
+would see if
+.CW LOAD
+contains a non-zero value and
+.DS
+#if !$(LOAD)
+.DE
+would test if
+.CW LOAD
+contains a zero value.
+.LP
+In addition to the bare
+.CW #if ,'' ``
+there are other forms that apply one of the first two functions to each
+term. They are as follows:
+.DS
+ ifdef \fRdefined\fP
+ ifndef \fR!defined\fP
+ ifmake \fRmake\fP
+ ifnmake \fR!make\fP
+.DE
+There are also the ``else if'' forms:
+.CW elif ,
+.CW elifdef ,
+.CW elifndef ,
+.CW elifmake ,
+and
+.CW elifnmake .
+.LP
+For instance, if you wish to create two versions of a program, one of which
+is optimized (the production version) and the other of which is for debugging
+(has symbols for dbx), you have two choices: you can create two
+makefiles, one of which uses the
+.CW \-g
+flag for the compilation, while the other uses the
+.CW \-O
+flag, or you can use another target (call it
+.CW debug )
+to create the debug version. The construct below will take care of
+this for you. I have also made it so defining the variable
+.CW DEBUG
+(say with
+.CW "pmake -D DEBUG" )
+will also cause the debug version to be made.
+.DS
+#if defined(DEBUG) || make(debug)
+CFLAGS += -g
+#else
+CFLAGS += -O
+#endif
+.DE
+There are, of course, problems with this approach. The most glaring
+annoyance is that if you want to go from making a debug version to
+making a production version, you have to remove all the object files,
+or you will get some optimized and some debug versions in the same
+program. Another annoyance is you have to be careful not to make two
+targets that ``conflict'' because of some conditionals in the
+makefile. For instance
+.DS
+#if make(print)
+FORMATTER = ditroff -Plaser_printer
+#endif
+#if make(draft)
+FORMATTER = nroff -Pdot_matrix_printer
+#endif
+.DE
+would wreak havok if you tried
+.CW "pmake draft print" '' ``
+since you would use the same formatter for each target. As I said,
+this all gets somewhat complicated.
+.xH 2 A Shell is a Shell is a Shell
+.Rd 7
+.LP
+In normal operation, the Bourne Shell (better known as
+.CW sh '') ``
+is used to execute the commands to re-create targets. PMake also allows you
+to specify a different shell for it to use when executing these
+commands. There are several things PMake must know about the shell you
+wish to use. These things are specified as the sources for the
+.CW .SHELL
+.Ix 0 ref .SHELL
+.Ix 0 ref target .SHELL
+target by keyword, as follows:
+.IP "\fBpath=\fP\fIpath\fP"
+PMake needs to know where the shell actually resides, so it can
+execute it. If you specify this and nothing else, PMake will use the
+last component of the path and look in its table of the shells it
+knows and use the specification it finds, if any. Use this if you just
+want to use a different version of the Bourne or C Shell (yes, PMake knows
+how to use the C Shell too).
+.IP "\fBname=\fP\fIname\fP"
+This is the name by which the shell is to be known. It is a single
+word and, if no other keywords are specified (other than
+.B path ),
+it is the name by which PMake attempts to find a specification for
+it (as mentioned above). You can use this if you would just rather use
+the C Shell than the Bourne Shell
+.CW ".SHELL: name=csh" '' (``
+will do it).
+.IP "\fBquiet=\fP\fIecho-off command\fP"
+As mentioned before, PMake actually controls whether commands are
+printed by introducing commands into the shell's input stream. This
+keyword, and the next two, control what those commands are. The
+.B quiet
+keyword is the command used to turn echoing off. Once it is turned
+off, echoing is expected to remain off until the echo-on command is given.
+.IP "\fBecho=\fP\fIecho-on command\fP"
+The command PMake should give to turn echoing back on again.
+.IP "\fBfilter=\fP\fIprinted echo-off command\fP"
+Many shells will echo the echo-off command when it is given. This
+keyword tells PMake in what format the shell actually prints the
+echo-off command. Wherever PMake sees this string in the shell's
+output, it will delete it and any following whitespace, up to and
+including the next newline. See the example at the end of this section
+for more details.
+.IP "\fBechoFlag=\fP\fIflag to turn echoing on\fP"
+Unless a target has been marked
+.CW .SILENT ,
+PMake wants to start the shell running with echoing on. To do this, it
+passes this flag to the shell as one of its arguments. If either this
+or the next flag begins with a `\-', the flags will be passed to the
+shell as separate arguments. Otherwise, the two will be concatenated
+(if they are used at the same time, of course).
+.IP "\fBerrFlag=\fP\fIflag to turn error checking on\fP"
+Likewise, unless a target is marked
+.CW .IGNORE ,
+PMake wishes error-checking to be on from the very start. To this end,
+it will pass this flag to the shell as an argument. The same rules for
+an initial `\-' apply as for the
+.B echoFlag .
+.IP "\fBcheck=\fP\fIcommand to turn error checking on\fP"
+Just as for echo-control, error-control is achieved by inserting
+commands into the shell's input stream. This is the command to make
+the shell check for errors. It also serves another purpose if the
+shell doesn't have error-control as commands, but I'll get into that
+in a minute. Again, once error checking has been turned on, it is
+expected to remain on until it is turned off again.
+.IP "\fBignore=\fP\fIcommand to turn error checking off\fP"
+This is the command PMake uses to turn error checking off. It has
+another use if the shell doesn't do error-control, but I'll tell you
+about that.\|.\|.\|now.
+.IP "\fBhasErrCtl=\fP\fIyes or no\fP"
+This takes a value that is either
+.B yes
+or
+.B no .
+Now you might think that the existence of the
+.B check
+and
+.B ignore
+keywords would be enough to tell PMake if the shell can do
+error-control, but you'd be wrong. If
+.B hasErrCtl
+is
+.B yes ,
+PMake uses the check and ignore commands in a straight-forward manner.
+If this is
+.B no ,
+however, their use is rather different. In this case, the check
+command is used as a template, in which the string
+.B %s
+is replaced by the command that's about to be executed, to produce a
+command for the shell that will echo the command to be executed. The
+ignore command is also used as a template, again with
+.B %s
+replaced by the command to be executed, to produce a command that will
+execute the command to be executed and ignore any error it returns.
+When these strings are used as templates, you must provide newline(s)
+.CW \en '') (``
+in the appropriate place(s).
+.LP
+The strings that follow these keywords may be enclosed in single or
+double quotes (the quotes will be stripped off) and may contain the
+usual C backslash-characters (\en is newline, \er is return, \eb is
+backspace, \e' escapes a single-quote inside single-quotes, \e"
+escapes a double-quote inside double-quotes). Now for an example.
+.LP
+This is actually the contents of the
+.CW <shx.mk>
+system makefile, and causes PMake to use the Bourne Shell in such a
+way that each command is printed as it is executed. That is, if more
+than one command is given on a line, each will be printed separately.
+Similarly, each time the body of a loop is executed, the commands
+within that loop will be printed, etc. The specification runs like
+this:
+.DS
+#
+# This is a shell specification to have the bourne shell echo
+# the commands just before executing them, rather than when it reads
+# them. Useful if you want to see how variables are being expanded, etc.
+#
+\&.SHELL : path=/bin/sh \e
+ quiet="set -" \e
+ echo="set -x" \e
+ filter="+ set - " \e
+ echoFlag=x \e
+ errFlag=e \e
+ hasErrCtl=yes \e
+ check="set -e" \e
+ ignore="set +e"
+.DE
+.LP
+It tells PMake the following:
+.Bp
+The shell is located in the file
+.CW /bin/sh .
+It need not tell PMake that the name of the shell is
+.CW sh
+as PMake can figure that out for itself (it's the last component of
+the path).
+.Bp
+The command to stop echoing is
+.CW "set -" .
+.Bp
+The command to start echoing is
+.CW "set -x" .
+.Bp
+When the echo off command is executed, the shell will print
+.CW "+ set - "
+(The `+' comes from using the
+.CW \-x
+flag (rather than the
+.CW \-v
+flag PMake usually uses)). PMake will remove all occurences of this
+string from the output, so you don't notice extra commands you didn't
+put there.
+.Bp
+The flag the Bourne Shell will take to start echoing in this way is
+the
+.CW \-x
+flag. The Bourne Shell will only take its flag arguments concatenated
+as its first argument, so neither this nor the
+.B errFlag
+specification begins with a \-.
+.Bp
+The flag to use to turn error-checking on from the start is
+.CW \-e .
+.Bp
+The shell can turn error-checking on and off, and the commands to do
+so are
+.CW "set +e"
+and
+.CW "set -e" ,
+respectively.
+.LP
+I should note that this specification is for Bourne Shells that are
+not part of Berkeley
+.UX ,
+as shells from Berkeley don't do error control. You can get a similar
+effect, however, by changing the last three lines to be:
+.DS
+ hasErrCtl=no \e
+ check="echo \e"+ %s\e"\en" \e
+ ignore="sh -c '%s || exit 0\en"
+.DE
+.LP
+This will cause PMake to execute the two commands
+.DS
+echo "+ \fIcmd\fP"
+sh -c '\fIcmd\fP || true'
+.DE
+for each command for which errors are to be ignored. (In case you are
+wondering, the thing for
+.CW ignore
+tells the shell to execute another shell without error checking on and
+always exit 0, since the
+.B ||
+causes the
+.CW "exit 0"
+to be executed only if the first command exited non-zero, and if the
+first command exited zero, the shell will also exit zero, since that's
+the last command it executed).
+.xH 2 Compatibility
+.Ix 0 ref compatibility
+.LP
+There are three (well, 3 \(12) levels of backwards-compatibility built
+into PMake. Most makefiles will need none at all. Some may need a
+little bit of work to operate correctly when run in parallel. Each
+level encompasses the previous levels (e.g.
+.B \-B
+(one shell per command) implies
+.B \-V )
+The three levels are described in the following three sections.
+.xH 3 DEFCON 3 \*- Variable Expansion
+.Ix 0 ref compatibility
+.LP
+As noted before, PMake will not expand a variable unless it knows of a
+value for it. This can cause problems for makefiles that expect to
+leave variables undefined except in special circumstances (e.g. if
+more flags need to be passed to the C compiler or the output from a
+text processor should be sent to a different printer). If the
+variables are enclosed in curly braces
+.CW ${PRINTER} ''), (``
+the shell will let them pass. If they are enclosed in parentheses,
+however, the shell will declare a syntax error and the make will come
+to a grinding halt.
+.LP
+You have two choices: change the makefile to define the variables
+(their values can be overridden on the command line, since that's
+where they would have been set if you used Make, anyway) or always give the
+.B \-V
+flag (this can be done with the
+.CW .MAKEFLAGS
+target, if you want).
+.xH 3 DEFCON 2 \*- The Number of the Beast
+.Ix 0 ref compatibility
+.LP
+Then there are the makefiles that expect certain commands, such as
+changing to a different directory, to not affect other commands in a
+target's creation script. You can solve this is either by going
+back to executing one shell per command (which is what the
+.B \-B
+flag forces PMake to do), which slows the process down a good bit and
+requires you to use semicolons and escaped newlines for shell constructs, or
+by changing the makefile to execute the offending command(s) in a subshell
+(by placing the line inside parentheses), like so:
+.DS
+install :: .MAKE
+ (cd src; $(.PMAKE) install)
+ (cd lib; $(.PMAKE) install)
+ (cd man; $(.PMAKE) install)
+.DE
+.Ix 0 ref operator double-colon
+.Ix 0 ref variable global .PMAKE
+.Ix 0 ref .PMAKE
+.Ix 0 ref .MAKE
+.Ix 0 ref attribute .MAKE
+This will always execute the three makes (even if the
+.B \-n
+flag was given) because of the combination of the ``::'' operator and
+the
+.CW .MAKE
+attribute. Each command will change to the proper directory to perform
+the install, leaving the main shell in the directory in which it started.
+.xH 3 "DEFCON 1 \*- Imitation is the Not the Highest Form of Flattery"
+.Ix 0 ref compatibility
+.LP
+The final category of makefile is the one where every command requires
+input, the dependencies are incompletely specified, or you simply
+cannot create more than one target at a time, as mentioned earlier. In
+addition, you may not have the time or desire to upgrade the makefile
+to run smoothly with PMake. If you are the conservative sort, this is
+the compatibility mode for you. It is entered either by giving PMake
+the
+.B \-M
+flag (for Make), or by executing PMake as
+.CW make .'' ``
+In either case, PMake performs things exactly like Make (while still
+supporting most of the nice new features PMake provides). This
+includes:
+.IP \(bu 2
+No parallel execution.
+.IP \(bu 2
+Targets are made in the exact order specified by the makefile. The
+sources for each target are made in strict left-to-right order, etc.
+.IP \(bu 2
+A single Bourne shell is used to execute each command, thus the
+shell's
+.CW $$
+variable is useless, changing directories doesn't work across command
+lines, etc.
+.IP \(bu 2
+If no special characters exist in a command line, PMake will break the
+command into words itself and execute the command directly, without
+executing a shell first. The characters that cause PMake to execute a
+shell are:
+.CW # ,
+.CW = ,
+.CW | ,
+.CW ^ ,
+.CW ( ,
+.CW ) ,
+.CW { ,
+.CW } ,
+.CW ; ,
+.CW & ,
+.CW < ,
+.CW > ,
+.CW * ,
+.CW ? ,
+.CW [ ,
+.CW ] ,
+.CW : ,
+.CW $ ,
+.CW ` ,
+and
+.CW \e .
+You should notice that these are all the characters that are given
+special meaning by the shell (except
+.CW '
+and
+.CW " ,
+which PMake deals with all by its lonesome).
+.IP \(bu 2
+The use of the null suffix is turned off.
+.Ix 0 ref "null suffix"
+.Ix 0 ref suffix null
+.xH 2 The Way Things Work
+.LP
+When PMake reads the makefile, it parses sources and targets into
+nodes in a graph. The graph is directed only in the sense that PMake
+knows which way is up. Each node contains not only links to all its
+parents and children (the nodes that depend on it and those on which
+it depends, respectively), but also a count of the number of its
+children that have already been processed.
+.LP
+The most important thing to know about how PMake uses this graph is
+that the traversal is breadth-first and occurs in two passes.
+.LP
+After PMake has parsed the makefile, it begins with the nodes the user
+has told it to make (either on the command line, or via a
+.CW .MAIN
+target, or by the target being the first in the file not labeled with
+the
+.CW .NOTMAIN
+attribute) placed in a queue. It continues to take the node off the
+front of the queue, mark it as something that needs to be made, pass
+the node to
+.CW Suff_FindDeps
+(mentioned earlier) to find any implicit sources for the node, and
+place all the node's children that have yet to be marked at the end of
+the queue. If any of the children is a
+.CW .USE
+rule, its attributes are applied to the parent, then its commands are
+appended to the parent's list of commands and its children are linked
+to its parent. The parent's unmade children counter is then decremented
+(since the
+.CW .USE
+node has been processed). You will note that this allows a
+.CW .USE
+node to have children that are
+.CW .USE
+nodes and the rules will be applied in sequence.
+If the node has no children, it is placed at the end of
+another queue to be examined in the second pass. This process
+continues until the first queue is empty.
+.LP
+At this point, all the leaves of the graph are in the examination
+queue. PMake removes the node at the head of the queue and sees if it
+is out-of-date. If it is, it is passed to a function that will execute
+the commands for the node asynchronously. When the commands have
+completed, all the node's parents have their unmade children counter
+decremented and, if the counter is then 0, they are placed on the
+examination queue. Likewise, if the node is up-to-date. Only those
+parents that were marked on the downward pass are processed in this
+way. Thus PMake traverses the graph back up to the nodes the user
+instructed it to create. When the examination queue is empty and no
+shells are running to create a target, PMake is finished.
+.LP
+Once all targets have been processed, PMake executes the commands
+attached to the
+.CW .END
+target, either explicitly or through the use of an ellipsis in a shell
+script. If there were no errors during the entire process but there
+are still some targets unmade (PMake keeps a running count of how many
+targets are left to be made), there is a cycle in the graph. PMake does
+a depth-first traversal of the graph to find all the targets that
+weren't made and prints them out one by one.
+.xH 1 Answers to Exercises
+.IP (3.1)
+This is something of a trick question, for which I apologize. The
+trick comes from the UNIX definition of a suffix, which PMake doesn't
+necessarily share. You will have noticed that all the suffixes used in
+this tutorial (and in UNIX in general) begin with a period
+.CW .ms , (
+.CW .c ,
+etc.). Now, PMake's idea of a suffix is more like English's: it's the
+characters at the end of a word. With this in mind, one possible
+.Ix 0 def suffix
+solution to this problem goes as follows:
+.DS I
+\&.SUFFIXES : ec.exe .exe ec.obj .obj .asm
+ec.objec.exe .obj.exe :
+ link -o $(.TARGET) $(.IMPSRC)
+\&.asmec.obj :
+ asm -o $(.TARGET) -DDO_ERROR_CHECKING $(.IMPSRC)
+\&.asm.obj :
+ asm -o $(.TARGET) $(.IMPSRC)
+.DE
+.IP (3.2)
+The trick to this one lies in the ``:='' variable-assignment operator
+and the ``:S'' variable-expansion modifier.
+.Ix 0 ref variable assignment expanded
+.Ix 0 ref variable expansion modified
+.Ix 0 ref modifier substitute
+.Ix 0 ref :S
+.Ix 0 ref :=
+Basically what you want is to take the pointer variable, so to speak,
+and transform it into an invocation of the variable at which it
+points. You might try something like
+.DS I
+$(PTR:S/^/\e$(/:S/$/))
+.DE
+which places
+.CW $( '' ``
+at the front of the variable name and
+.CW ) '' ``
+at the end, thus transforming
+.CW VAR ,'' ``
+for example, into
+.CW $(VAR) ,'' ``
+which is just what we want. Unfortunately (as you know if you've tried
+it), since, as it says in the hint, PMake does no further substitution
+on the result of a modified expansion, that's \fIall\fP you get. The
+solution is to make use of ``:='' to place that string into yet
+another variable, then invoke the other variable directly:
+.DS I
+*PTR := $(PTR:S/^/\e$(/:S/$/)/)
+.DE
+You can then use
+.CW $(*PTR) '' ``
+to your heart's content.
+.de Gp
+.XP
+\&\fB\\$1:\fP
+..
+.xH 1 Glossary of Jargon
+.Gp "attribute"
+A property given to a target that causes PMake to treat it differently.
+.Gp "command script"
+The lines immediately following a dependency line that specify
+commands to execute to create each of the targets on the dependency
+line. Each line in the command script must begin with a tab.
+.Gp "command-line variable"
+A variable defined in an argument when PMake is first executed.
+Overrides all assignments to the same variable name in the makefile.
+.Gp "conditional"
+A construct much like that used in C that allows a makefile to be
+configured on the fly based on the local environment, or on what is being
+made by that invocation of PMake.
+.Gp "creation script"
+Commands used to create a target. See ``command script.''
+.Gp "dependency"
+The relationship between a source and a target. This comes in three
+flavors, as indicated by the operator between the target and the
+source. `:' gives a straight time-wise dependency (if the target is
+older than the source, the target is out-of-date), while `!' provides
+simply an ordering and always considers the target out-of-date. `::'
+is much like `:', save it creates multiple instances of a target each
+of which depends on its own list of sources.
+.Gp "dynamic source"
+This refers to a source that has a local variable invocation in it. It
+allows a single dependency line to specify a different source for each
+target on the line.
+.Gp "global variable"
+Any variable defined in a makefile. Takes precedence over variables
+defined in the environment, but not over command-line or local variables.
+.Gp "input graph"
+What PMake constructs from a makefile. Consists of nodes made of the
+targets in the makefile, and the links between them (the
+dependencies). The links are directed (from source to target) and
+there may not be any cycles (loops) in the graph.
+.Gp "local variable"
+A variable defined by PMake visible only in a target's shell script.
+There are seven local variables, not all of which are defined for
+every target:
+.CW .TARGET ,
+.CW .ALLSRC ,
+.CW .OODATE ,
+.CW .PREFIX ,
+.CW .IMPSRC ,
+.CW .ARCHIVE ,
+and
+.CW .MEMBER .
+.CW .TARGET ,
+.CW .PREFIX ,
+.CW .ARCHIVE ,
+and
+.CW .MEMBER
+may be used on dependency lines to create ``dynamic sources.''
+.Gp "makefile"
+A file that describes how a system is built. If you don't know what it
+is after reading this tutorial.\|.\|.\|.
+.Gp "modifier"
+A letter, following a colon, used to alter how a variable is expanded.
+It has no effect on the variable itself.
+.Gp "operator"
+What separates a source from a target (on a dependency line) and specifies
+the relationship between the two. There are three:
+.CW : ', `
+.CW :: ', `
+and
+.CW ! '. `
+.Gp "search path"
+A list of directories in which a file should be sought. PMake's view
+of the contents of directories in a search path does not change once
+the makefile has been read. A file is sought on a search path only if
+it is exclusively a source.
+.Gp "shell"
+A program to which commands are passed in order to create targets.
+.Gp "source"
+Anything to the right of an operator on a dependency line. Targets on
+the dependency line are usually created from the sources.
+.Gp "special target"
+A target that causes PMake to do special things when it's encountered.
+.Gp "suffix"
+The tail end of a file name. Usually begins with a period,
+.CW .c
+or
+.CW .ms ,
+e.g.
+.Gp "target"
+A word to the left of the operator on a dependency line. More
+generally, any file that PMake might create. A file may be (and often
+is) both a target and a source (what it is depends on how PMake is
+looking at it at the time \*- sort of like the wave/particle duality
+of light, you know).
+.Gp "transformation rule"
+A special construct in a makefile that specifies how to create a file
+of one type from a file of another, as indicated by their suffixes.
+.Gp "variable expansion"
+The process of substituting the value of a variable for a reference to
+it. Expansion may be altered by means of modifiers.
+.Gp "variable"
+A place in which to store text that may be retrieved later. Also used
+to define the local environment. Conditionals exist that test whether
+a variable is defined or not.
+.bp
+.\" Output table of contents last, with an entry for the index, making
+.\" sure to save and restore the last real page number for the index...
+.nr @n \n(PN+1
+.\" We are not generating an index
+.\" .XS \n(@n
+.\" Index
+.\" .XE
+.nr %% \n%
+.PX
+.nr % \n(%%
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c
new file mode 100644
index 0000000..769e6ae
--- /dev/null
+++ b/usr.bin/make/arch.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
+#endif /* not lint */
+
+/*-
+ * arch.c --
+ * Functions to manipulate libraries, archives and their members.
+ *
+ * Once again, cacheing/hashing comes into play in the manipulation
+ * of archives. The first time an archive is referenced, all of its members'
+ * headers are read and hashed and the archive closed again. All hashed
+ * archives are kept on a list which is searched each time an archive member
+ * is referenced.
+ *
+ * The interface to this module is:
+ * Arch_ParseArchive Given an archive specification, return a list
+ * of GNode's, one for each member in the spec.
+ * FAILURE is returned if the specification is
+ * invalid for some reason.
+ *
+ * Arch_Touch Alter the modification time of the archive
+ * member described by the given node to be
+ * the current time.
+ *
+ * Arch_TouchLib Update the modification time of the library
+ * described by the given node. This is special
+ * because it also updates the modification time
+ * of the library's table of contents.
+ *
+ * Arch_MTime Find the modification time of a member of
+ * an archive *in the archive*. The time is also
+ * placed in the member's GNode. Returns the
+ * modification time.
+ *
+ * Arch_MemTime Find the modification time of a member of
+ * an archive. Called when the member doesn't
+ * already exist. Looks in the archive for the
+ * modification time. Returns the modification
+ * time.
+ *
+ * Arch_FindLib Search for a library along a path. The
+ * library name in the GNode should be in
+ * -l<name> format.
+ *
+ * Arch_LibOODate Special function to decide if a library node
+ * is out-of-date.
+ *
+ * Arch_Init Initialize this module.
+ *
+ * Arch_End Cleanup this module.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <ar.h>
+#include <utime.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "config.h"
+
+static Lst archives; /* Lst of archives we've already examined */
+
+typedef struct Arch {
+ char *name; /* Name of archive */
+ Hash_Table members; /* All the members of the archive described
+ * by <name, struct ar_hdr *> key/value pairs */
+ char *fnametab; /* Extended name table strings */
+ size_t fnamesize; /* Size of the string table */
+} Arch;
+
+static int ArchFindArchive __P((ClientData, ClientData));
+static void ArchFree __P((ClientData));
+static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean));
+static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *));
+#if defined(__svr4__) || defined(__SVR4)
+#define SVR4ARCHIVES
+static int ArchSVR4Entry __P((Arch *, char *, size_t, FILE *));
+#endif
+
+/*-
+ *-----------------------------------------------------------------------
+ * ArchFree --
+ * Free memory used by an archive
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+ArchFree(ap)
+ ClientData ap;
+{
+ Arch *a = (Arch *) ap;
+ Hash_Search search;
+ Hash_Entry *entry;
+
+ /* Free memory from hash entries */
+ for (entry = Hash_EnumFirst(&a->members, &search);
+ entry != (Hash_Entry *)NULL;
+ entry = Hash_EnumNext(&search))
+ free((Address) Hash_GetValue (entry));
+
+ free(a->name);
+ if (a->fnametab)
+ free(a->fnametab);
+ Hash_DeleteTable(&a->members);
+ free((Address) a);
+}
+
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_ParseArchive --
+ * Parse the archive specification in the given line and find/create
+ * the nodes for the specified archive members, placing their nodes
+ * on the given list.
+ *
+ * Results:
+ * SUCCESS if it was a valid specification. The linePtr is updated
+ * to point to the first non-space after the archive spec. The
+ * nodes for the members are placed on the given list.
+ *
+ * Side Effects:
+ * Some nodes may be created. The given list is extended.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Arch_ParseArchive (linePtr, nodeLst, ctxt)
+ char **linePtr; /* Pointer to start of specification */
+ Lst nodeLst; /* Lst on which to place the nodes */
+ GNode *ctxt; /* Context in which to expand variables */
+{
+ register char *cp; /* Pointer into line */
+ GNode *gn; /* New node */
+ char *libName; /* Library-part of specification */
+ char *memName; /* Member-part of specification */
+ char nameBuf[MAKE_BSIZE]; /* temporary place for node name */
+ char saveChar; /* Ending delimiter of member-name */
+ Boolean subLibName; /* TRUE if libName should have/had
+ * variable substitution performed on it */
+
+ libName = *linePtr;
+
+ subLibName = FALSE;
+
+ for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
+ if (*cp == '$') {
+ /*
+ * Variable spec, so call the Var module to parse the puppy
+ * so we can safely advance beyond it...
+ */
+ int length;
+ Boolean freeIt;
+ char *result;
+
+ result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ if (result == var_Error) {
+ return(FAILURE);
+ } else {
+ subLibName = TRUE;
+ }
+
+ if (freeIt) {
+ free(result);
+ }
+ cp += length-1;
+ }
+ }
+
+ *cp++ = '\0';
+ if (subLibName) {
+ libName = Var_Subst(NULL, libName, ctxt, TRUE);
+ }
+
+
+ for (;;) {
+ /*
+ * First skip to the start of the member's name, mark that
+ * place and skip to the end of it (either white-space or
+ * a close paren).
+ */
+ Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */
+
+ while (*cp != '\0' && *cp != ')' && isspace (*cp)) {
+ cp++;
+ }
+ memName = cp;
+ while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {
+ if (*cp == '$') {
+ /*
+ * Variable spec, so call the Var module to parse the puppy
+ * so we can safely advance beyond it...
+ */
+ int length;
+ Boolean freeIt;
+ char *result;
+
+ result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ if (result == var_Error) {
+ return(FAILURE);
+ } else {
+ doSubst = TRUE;
+ }
+
+ if (freeIt) {
+ free(result);
+ }
+ cp += length;
+ } else {
+ cp++;
+ }
+ }
+
+ /*
+ * If the specification ends without a closing parenthesis,
+ * chances are there's something wrong (like a missing backslash),
+ * so it's better to return failure than allow such things to happen
+ */
+ if (*cp == '\0') {
+ printf("No closing parenthesis in archive specification\n");
+ return (FAILURE);
+ }
+
+ /*
+ * If we didn't move anywhere, we must be done
+ */
+ if (cp == memName) {
+ break;
+ }
+
+ saveChar = *cp;
+ *cp = '\0';
+
+ /*
+ * XXX: This should be taken care of intelligently by
+ * SuffExpandChildren, both for the archive and the member portions.
+ */
+ /*
+ * If member contains variables, try and substitute for them.
+ * This will slow down archive specs with dynamic sources, of course,
+ * since we'll be (non-)substituting them three times, but them's
+ * the breaks -- we need to do this since SuffExpandChildren calls
+ * us, otherwise we could assume the thing would be taken care of
+ * later.
+ */
+ if (doSubst) {
+ char *buf;
+ char *sacrifice;
+ char *oldMemName = memName;
+
+ memName = Var_Subst(NULL, memName, ctxt, TRUE);
+
+ /*
+ * Now form an archive spec and recurse to deal with nested
+ * variables and multi-word variable values.... The results
+ * are just placed at the end of the nodeLst we're returning.
+ */
+ buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);
+
+ sprintf(buf, "%s(%s)", libName, memName);
+
+ if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
+ /*
+ * Must contain dynamic sources, so we can't deal with it now.
+ * Just create an ARCHV node for the thing and let
+ * SuffExpandChildren handle it...
+ */
+ gn = Targ_FindNode(buf, TARG_CREATE);
+
+ if (gn == NILGNODE) {
+ free(buf);
+ return(FAILURE);
+ } else {
+ gn->type |= OP_ARCHV;
+ (void)Lst_AtEnd(nodeLst, (ClientData)gn);
+ }
+ } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
+ /*
+ * Error in nested call -- free buffer and return FAILURE
+ * ourselves.
+ */
+ free(buf);
+ return(FAILURE);
+ }
+ /*
+ * Free buffer and continue with our work.
+ */
+ free(buf);
+ } else if (Dir_HasWildcards(memName)) {
+ Lst members = Lst_Init(FALSE);
+ char *member;
+
+ Dir_Expand(memName, dirSearchPath, members);
+ while (!Lst_IsEmpty(members)) {
+ member = (char *)Lst_DeQueue(members);
+
+ sprintf(nameBuf, "%s(%s)", libName, member);
+ free(member);
+ gn = Targ_FindNode (nameBuf, TARG_CREATE);
+ if (gn == NILGNODE) {
+ return (FAILURE);
+ } else {
+ /*
+ * We've found the node, but have to make sure the rest of
+ * the world knows it's an archive member, without having
+ * to constantly check for parentheses, so we type the
+ * thing with the OP_ARCHV bit before we place it on the
+ * end of the provided list.
+ */
+ gn->type |= OP_ARCHV;
+ (void) Lst_AtEnd (nodeLst, (ClientData)gn);
+ }
+ }
+ Lst_Destroy(members, NOFREE);
+ } else {
+ sprintf(nameBuf, "%s(%s)", libName, memName);
+ gn = Targ_FindNode (nameBuf, TARG_CREATE);
+ if (gn == NILGNODE) {
+ return (FAILURE);
+ } else {
+ /*
+ * We've found the node, but have to make sure the rest of the
+ * world knows it's an archive member, without having to
+ * constantly check for parentheses, so we type the thing with
+ * the OP_ARCHV bit before we place it on the end of the
+ * provided list.
+ */
+ gn->type |= OP_ARCHV;
+ (void) Lst_AtEnd (nodeLst, (ClientData)gn);
+ }
+ }
+ if (doSubst) {
+ free(memName);
+ }
+
+ *cp = saveChar;
+ }
+
+ /*
+ * If substituted libName, free it now, since we need it no longer.
+ */
+ if (subLibName) {
+ free(libName);
+ }
+
+ /*
+ * We promised the pointer would be set up at the next non-space, so
+ * we must advance cp there before setting *linePtr... (note that on
+ * entrance to the loop, cp is guaranteed to point at a ')')
+ */
+ do {
+ cp++;
+ } while (*cp != '\0' && isspace (*cp));
+
+ *linePtr = cp;
+ return (SUCCESS);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ArchFindArchive --
+ * See if the given archive is the one we are looking for. Called
+ * From ArchStatMember and ArchFindMember via Lst_Find.
+ *
+ * Results:
+ * 0 if it is, non-zero if it isn't.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ArchFindArchive (ar, archName)
+ ClientData ar; /* Current list element */
+ ClientData archName; /* Name we want */
+{
+ return (strcmp ((char *) archName, ((Arch *) ar)->name));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ArchStatMember --
+ * Locate a member of an archive, given the path of the archive and
+ * the path of the desired member.
+ *
+ * Results:
+ * A pointer to the current struct ar_hdr structure for the member. Note
+ * That no position is returned, so this is not useful for touching
+ * archive members. This is mostly because we have no assurances that
+ * The archive will remain constant after we read all the headers, so
+ * there's not much point in remembering the position...
+ *
+ * Side Effects:
+ *
+ *-----------------------------------------------------------------------
+ */
+static struct ar_hdr *
+ArchStatMember (archive, member, hash)
+ char *archive; /* Path to the archive */
+ char *member; /* Name of member. If it is a path, only the
+ * last component is used. */
+ Boolean hash; /* TRUE if archive should be hashed if not
+ * already so. */
+{
+#define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1)
+ FILE * arch; /* Stream to archive */
+ int size; /* Size of archive member */
+ char *cp; /* Useful character pointer */
+ char magic[SARMAG];
+ LstNode ln; /* Lst member containing archive descriptor */
+ Arch *ar; /* Archive descriptor */
+ Hash_Entry *he; /* Entry containing member's description */
+ struct ar_hdr arh; /* archive-member header for reading archive */
+ char memName[MAXPATHLEN+1];
+ /* Current member name while hashing. */
+
+ /*
+ * Because of space constraints and similar things, files are archived
+ * using their final path components, not the entire thing, so we need
+ * to point 'member' to the final component, if there is one, to make
+ * the comparisons easier...
+ */
+ cp = strrchr (member, '/');
+ if (cp != (char *) NULL) {
+ member = cp + 1;
+ }
+
+ ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive);
+ if (ln != NILLNODE) {
+ ar = (Arch *) Lst_Datum (ln);
+
+ he = Hash_FindEntry (&ar->members, member);
+
+ if (he != (Hash_Entry *) NULL) {
+ return ((struct ar_hdr *) Hash_GetValue (he));
+ } else {
+ /* Try truncated name */
+ char copy[AR_MAX_NAME_LEN+1];
+ int len = strlen (member);
+
+ if (len > AR_MAX_NAME_LEN) {
+ len = AR_MAX_NAME_LEN;
+ strncpy(copy, member, AR_MAX_NAME_LEN);
+ copy[AR_MAX_NAME_LEN] = '\0';
+ }
+ if ((he = Hash_FindEntry (&ar->members, copy)) != NULL)
+ return ((struct ar_hdr *) Hash_GetValue (he));
+ return ((struct ar_hdr *) NULL);
+ }
+ }
+
+ if (!hash) {
+ /*
+ * Caller doesn't want the thing hashed, just use ArchFindMember
+ * to read the header for the member out and close down the stream
+ * again. Since the archive is not to be hashed, we assume there's
+ * no need to allocate extra room for the header we're returning,
+ * so just declare it static.
+ */
+ static struct ar_hdr sarh;
+
+ arch = ArchFindMember(archive, member, &sarh, "r");
+
+ if (arch == (FILE *)NULL) {
+ return ((struct ar_hdr *)NULL);
+ } else {
+ fclose(arch);
+ return (&sarh);
+ }
+ }
+
+ /*
+ * We don't have this archive on the list yet, so we want to find out
+ * everything that's in it and cache it so we can get at it quickly.
+ */
+ arch = fopen (archive, "r");
+ if (arch == (FILE *) NULL) {
+ return ((struct ar_hdr *) NULL);
+ }
+
+ /*
+ * We use the ARMAG string to make sure this is an archive we
+ * can handle...
+ */
+ if ((fread (magic, SARMAG, 1, arch) != 1) ||
+ (strncmp (magic, ARMAG, SARMAG) != 0)) {
+ fclose (arch);
+ return ((struct ar_hdr *) NULL);
+ }
+
+ ar = (Arch *)emalloc (sizeof (Arch));
+ ar->name = estrdup (archive);
+ ar->fnametab = NULL;
+ ar->fnamesize = 0;
+ Hash_InitTable (&ar->members, -1);
+ memName[AR_MAX_NAME_LEN] = '\0';
+
+ while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {
+ if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {
+ /*
+ * The header is bogus, so the archive is bad
+ * and there's no way we can recover...
+ */
+ goto badarch;
+ } else {
+ /*
+ * We need to advance the stream's pointer to the start of the
+ * next header. Files are padded with newlines to an even-byte
+ * boundary, so we need to extract the size of the file from the
+ * 'size' field of the header and round it up during the seek.
+ */
+ arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
+ size = (int) strtol(arh.ar_size, NULL, 10);
+
+ (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name));
+ for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
+ continue;
+ }
+ cp[1] = '\0';
+
+#ifdef SVR4ARCHIVES
+ /*
+ * svr4 names are slash terminated. Also svr4 extended AR format.
+ */
+ if (memName[0] == '/') {
+ /*
+ * svr4 magic mode; handle it
+ */
+ switch (ArchSVR4Entry(ar, memName, size, arch)) {
+ case -1: /* Invalid data */
+ goto badarch;
+ case 0: /* List of files entry */
+ continue;
+ default: /* Got the entry */
+ break;
+ }
+ }
+ else {
+ if (cp[0] == '/')
+ cp[0] = '\0';
+ }
+#endif
+
+#ifdef AR_EFMT1
+ /*
+ * BSD 4.4 extended AR format: #1/<namelen>, with name as the
+ * first <namelen> bytes of the file
+ */
+ if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
+ isdigit(memName[sizeof(AR_EFMT1) - 1])) {
+
+ unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);
+
+ if (elen > MAXPATHLEN)
+ goto badarch;
+ if (fread (memName, elen, 1, arch) != 1)
+ goto badarch;
+ memName[elen] = '\0';
+ fseek (arch, -elen, 1);
+ if (DEBUG(ARCH) || DEBUG(MAKE)) {
+ printf("ArchStat: Extended format entry for %s\n", memName);
+ }
+ }
+#endif
+
+ he = Hash_CreateEntry (&ar->members, memName, (Boolean *)NULL);
+ Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr)));
+ memcpy ((Address)Hash_GetValue (he), (Address)&arh,
+ sizeof (struct ar_hdr));
+ }
+ fseek (arch, (size + 1) & ~1, 1);
+ }
+
+ fclose (arch);
+
+ (void) Lst_AtEnd (archives, (ClientData) ar);
+
+ /*
+ * Now that the archive has been read and cached, we can look into
+ * the hash table to find the desired member's header.
+ */
+ he = Hash_FindEntry (&ar->members, member);
+
+ if (he != (Hash_Entry *) NULL) {
+ return ((struct ar_hdr *) Hash_GetValue (he));
+ } else {
+ return ((struct ar_hdr *) NULL);
+ }
+
+badarch:
+ fclose (arch);
+ Hash_DeleteTable (&ar->members);
+ if (ar->fnametab)
+ free(ar->fnametab);
+ free ((Address)ar);
+ return ((struct ar_hdr *) NULL);
+}
+
+#ifdef SVR4ARCHIVES
+/*-
+ *-----------------------------------------------------------------------
+ * ArchSVR4Entry --
+ * Parse an SVR4 style entry that begins with a slash.
+ * If it is "//", then load the table of filenames
+ * If it is "/<offset>", then try to substitute the long file name
+ * from offset of a table previously read.
+ *
+ * Results:
+ * -1: Bad data in archive
+ * 0: A table was loaded from the file
+ * 1: Name was successfully substituted from table
+ * 2: Name was not successfully substituted from table
+ *
+ * Side Effects:
+ * If a table is read, the file pointer is moved to the next archive
+ * member
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ArchSVR4Entry(ar, name, size, arch)
+ Arch *ar;
+ char *name;
+ size_t size;
+ FILE *arch;
+{
+#define ARLONGNAMES1 "//"
+#define ARLONGNAMES2 "/ARFILENAMES"
+ size_t entry;
+ char *ptr, *eptr;
+
+ if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 ||
+ strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) {
+
+ if (ar->fnametab != NULL) {
+ if (DEBUG(ARCH)) {
+ printf("Attempted to redefine an SVR4 name table\n");
+ }
+ return -1;
+ }
+
+ /*
+ * This is a table of archive names, so we build one for
+ * ourselves
+ */
+ ar->fnametab = emalloc(size);
+ ar->fnamesize = size;
+
+ if (fread(ar->fnametab, size, 1, arch) != 1) {
+ if (DEBUG(ARCH)) {
+ printf("Reading an SVR4 name table failed\n");
+ }
+ return -1;
+ }
+ eptr = ar->fnametab + size;
+ for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++)
+ switch (*ptr) {
+ case '/':
+ entry++;
+ *ptr = '\0';
+ break;
+
+ case '\n':
+ break;
+
+ default:
+ break;
+ }
+ if (DEBUG(ARCH)) {
+ printf("Found svr4 archive name table with %d entries\n", entry);
+ }
+ return 0;
+ }
+
+ if (name[1] == ' ' || name[1] == '\0')
+ return 2;
+
+ entry = (size_t) strtol(&name[1], &eptr, 0);
+ if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) {
+ if (DEBUG(ARCH)) {
+ printf("Could not parse SVR4 name %s\n", name);
+ }
+ return 2;
+ }
+ if (entry >= ar->fnamesize) {
+ if (DEBUG(ARCH)) {
+ printf("SVR4 entry offset %s is greater than %d\n",
+ name, ar->fnamesize);
+ }
+ return 2;
+ }
+
+ if (DEBUG(ARCH)) {
+ printf("Replaced %s with %s\n", name, &ar->fnametab[entry]);
+ }
+
+ (void) strncpy(name, &ar->fnametab[entry], MAXPATHLEN);
+ name[MAXPATHLEN] = '\0';
+ return 1;
+}
+#endif
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * ArchFindMember --
+ * Locate a member of an archive, given the path of the archive and
+ * the path of the desired member. If the archive is to be modified,
+ * the mode should be "r+", if not, it should be "r".
+ *
+ * Results:
+ * An FILE *, opened for reading and writing, positioned at the
+ * start of the member's struct ar_hdr, or NULL if the member was
+ * nonexistent. The current struct ar_hdr for member.
+ *
+ * Side Effects:
+ * The passed struct ar_hdr structure is filled in.
+ *
+ *-----------------------------------------------------------------------
+ */
+static FILE *
+ArchFindMember (archive, member, arhPtr, mode)
+ char *archive; /* Path to the archive */
+ char *member; /* Name of member. If it is a path, only the
+ * last component is used. */
+ struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */
+ char *mode; /* The mode for opening the stream */
+{
+ FILE * arch; /* Stream to archive */
+ int size; /* Size of archive member */
+ char *cp; /* Useful character pointer */
+ char magic[SARMAG];
+ int len, tlen;
+
+ arch = fopen (archive, mode);
+ if (arch == (FILE *) NULL) {
+ return ((FILE *) NULL);
+ }
+
+ /*
+ * We use the ARMAG string to make sure this is an archive we
+ * can handle...
+ */
+ if ((fread (magic, SARMAG, 1, arch) != 1) ||
+ (strncmp (magic, ARMAG, SARMAG) != 0)) {
+ fclose (arch);
+ return ((FILE *) NULL);
+ }
+
+ /*
+ * Because of space constraints and similar things, files are archived
+ * using their final path components, not the entire thing, so we need
+ * to point 'member' to the final component, if there is one, to make
+ * the comparisons easier...
+ */
+ cp = strrchr (member, '/');
+ if (cp != (char *) NULL) {
+ member = cp + 1;
+ }
+ len = tlen = strlen (member);
+ if (len > sizeof (arhPtr->ar_name)) {
+ tlen = sizeof (arhPtr->ar_name);
+ }
+
+ while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) {
+ if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) {
+ /*
+ * The header is bogus, so the archive is bad
+ * and there's no way we can recover...
+ */
+ fclose (arch);
+ return ((FILE *) NULL);
+ } else if (strncmp (member, arhPtr->ar_name, tlen) == 0) {
+ /*
+ * If the member's name doesn't take up the entire 'name' field,
+ * we have to be careful of matching prefixes. Names are space-
+ * padded to the right, so if the character in 'name' at the end
+ * of the matched string is anything but a space, this isn't the
+ * member we sought.
+ */
+ if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){
+ goto skip;
+ } else {
+ /*
+ * To make life easier, we reposition the file at the start
+ * of the header we just read before we return the stream.
+ * In a more general situation, it might be better to leave
+ * the file at the actual member, rather than its header, but
+ * not here...
+ */
+ fseek (arch, -sizeof(struct ar_hdr), 1);
+ return (arch);
+ }
+ } else
+#ifdef AR_EFMT1
+ /*
+ * BSD 4.4 extended AR format: #1/<namelen>, with name as the
+ * first <namelen> bytes of the file
+ */
+ if (strncmp(arhPtr->ar_name, AR_EFMT1,
+ sizeof(AR_EFMT1) - 1) == 0 &&
+ isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) {
+
+ unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]);
+ char ename[MAXPATHLEN];
+
+ if (elen > MAXPATHLEN) {
+ fclose (arch);
+ return NULL;
+ }
+ if (fread (ename, elen, 1, arch) != 1) {
+ fclose (arch);
+ return NULL;
+ }
+ ename[elen] = '\0';
+ if (DEBUG(ARCH) || DEBUG(MAKE)) {
+ printf("ArchFind: Extended format entry for %s\n", ename);
+ }
+ if (strncmp(ename, member, len) == 0) {
+ /* Found as extended name */
+ fseek (arch, -sizeof(struct ar_hdr) - elen, 1);
+ return (arch);
+ }
+ fseek (arch, -elen, 1);
+ goto skip;
+ } else
+#endif
+ {
+skip:
+ /*
+ * This isn't the member we're after, so we need to advance the
+ * stream's pointer to the start of the next header. Files are
+ * padded with newlines to an even-byte boundary, so we need to
+ * extract the size of the file from the 'size' field of the
+ * header and round it up during the seek.
+ */
+ arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0';
+ size = (int) strtol(arhPtr->ar_size, NULL, 10);
+ fseek (arch, (size + 1) & ~1, 1);
+ }
+ }
+
+ /*
+ * We've looked everywhere, but the member is not to be found. Close the
+ * archive and return NULL -- an error.
+ */
+ fclose (arch);
+ return ((FILE *) NULL);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_Touch --
+ * Touch a member of an archive.
+ *
+ * Results:
+ * The 'time' field of the member's header is updated.
+ *
+ * Side Effects:
+ * The modification time of the entire archive is also changed.
+ * For a library, this could necessitate the re-ranlib'ing of the
+ * whole thing.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Arch_Touch (gn)
+ GNode *gn; /* Node of member to touch */
+{
+ FILE * arch; /* Stream open to archive, positioned properly */
+ struct ar_hdr arh; /* Current header describing member */
+ char *p1, *p2;
+
+ arch = ArchFindMember(Var_Value (ARCHIVE, gn, &p1),
+ Var_Value (TARGET, gn, &p2),
+ &arh, "r+");
+ if (p1)
+ free(p1);
+ if (p2)
+ free(p2);
+ sprintf(arh.ar_date, "%-12ld", (long) now);
+
+ if (arch != (FILE *) NULL) {
+ (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
+ fclose (arch);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_TouchLib --
+ * Given a node which represents a library, touch the thing, making
+ * sure that the table of contents also is touched.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Both the modification time of the library and of the RANLIBMAG
+ * member are set to 'now'.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Arch_TouchLib (gn)
+ GNode *gn; /* The node of the library to touch */
+{
+#ifdef RANLIBMAG
+ FILE * arch; /* Stream open to archive */
+ struct ar_hdr arh; /* Header describing table of contents */
+ struct utimbuf times; /* Times for utime() call */
+
+ arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+");
+ sprintf(arh.ar_date, "%-12ld", (long) now);
+
+ if (arch != (FILE *) NULL) {
+ (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
+ fclose (arch);
+
+ times.actime = times.modtime = now;
+ utime(gn->path, &times);
+ }
+#endif
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_MTime --
+ * Return the modification time of a member of an archive.
+ *
+ * Results:
+ * The modification time (seconds).
+ *
+ * Side Effects:
+ * The mtime field of the given node is filled in with the value
+ * returned by the function.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Arch_MTime (gn)
+ GNode *gn; /* Node describing archive member */
+{
+ struct ar_hdr *arhPtr; /* Header of desired member */
+ int modTime; /* Modification time as an integer */
+ char *p1, *p2;
+
+ arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn, &p1),
+ Var_Value (TARGET, gn, &p2),
+ TRUE);
+ if (p1)
+ free(p1);
+ if (p2)
+ free(p2);
+
+ if (arhPtr != (struct ar_hdr *) NULL) {
+ modTime = (int) strtol(arhPtr->ar_date, NULL, 10);
+ } else {
+ modTime = 0;
+ }
+
+ gn->mtime = modTime;
+ return (modTime);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_MemMTime --
+ * Given a non-existent archive member's node, get its modification
+ * time from its archived form, if it exists.
+ *
+ * Results:
+ * The modification time.
+ *
+ * Side Effects:
+ * The mtime field is filled in.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Arch_MemMTime (gn)
+ GNode *gn;
+{
+ LstNode ln;
+ GNode *pgn;
+ char *nameStart,
+ *nameEnd;
+
+ if (Lst_Open (gn->parents) != SUCCESS) {
+ gn->mtime = 0;
+ return (0);
+ }
+ while ((ln = Lst_Next (gn->parents)) != NILLNODE) {
+ pgn = (GNode *) Lst_Datum (ln);
+
+ if (pgn->type & OP_ARCHV) {
+ /*
+ * If the parent is an archive specification and is being made
+ * and its member's name matches the name of the node we were
+ * given, record the modification time of the parent in the
+ * child. We keep searching its parents in case some other
+ * parent requires this child to exist...
+ */
+ nameStart = strchr (pgn->name, '(') + 1;
+ nameEnd = strchr (nameStart, ')');
+
+ if (pgn->make &&
+ strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) {
+ gn->mtime = Arch_MTime(pgn);
+ }
+ } else if (pgn->make) {
+ /*
+ * Something which isn't a library depends on the existence of
+ * this target, so it needs to exist.
+ */
+ gn->mtime = 0;
+ break;
+ }
+ }
+
+ Lst_Close (gn->parents);
+
+ return (gn->mtime);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_FindLib --
+ * Search for a library along the given search path.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The node's 'path' field is set to the found path (including the
+ * actual file name, not -l...). If the system can handle the -L
+ * flag when linking (or we cannot find the library), we assume that
+ * the user has placed the .LIBRARIES variable in the final linking
+ * command (or the linker will know where to find it) and set the
+ * TARGET variable for this node to be the node's name. Otherwise,
+ * we set the TARGET variable to be the full path of the library,
+ * as returned by Dir_FindFile.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Arch_FindLib (gn, path)
+ GNode *gn; /* Node of library to find */
+ Lst path; /* Search path */
+{
+ char *libName; /* file name for archive */
+
+ libName = (char *)emalloc (strlen (gn->name) + 6 - 2);
+ sprintf(libName, "lib%s.a", &gn->name[2]);
+
+ gn->path = Dir_FindFile (libName, path);
+
+ free (libName);
+
+#ifdef LIBRARIES
+ Var_Set (TARGET, gn->name, gn);
+#else
+ Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn);
+#endif /* LIBRARIES */
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_LibOODate --
+ * Decide if a node with the OP_LIB attribute is out-of-date. Called
+ * from Make_OODate to make its life easier.
+ *
+ * There are several ways for a library to be out-of-date that are
+ * not available to ordinary files. In addition, there are ways
+ * that are open to regular files that are not available to
+ * libraries. A library that is only used as a source is never
+ * considered out-of-date by itself. This does not preclude the
+ * library's modification time from making its parent be out-of-date.
+ * A library will be considered out-of-date for any of these reasons,
+ * given that it is a target on a dependency line somewhere:
+ * Its modification time is less than that of one of its
+ * sources (gn->mtime < gn->cmtime).
+ * Its modification time is greater than the time at which the
+ * make began (i.e. it's been modified in the course
+ * of the make, probably by archiving).
+ * The modification time of one of its sources is greater than
+ * the one of its RANLIBMAG member (i.e. its table of contents
+ * is out-of-date). We don't compare of the archive time
+ * vs. TOC time because they can be too close. In my
+ * opinion we should not bother with the TOC at all since
+ * this is used by 'ar' rules that affect the data contents
+ * of the archive, not by ranlib rules, which affect the
+ * TOC.
+ *
+ * Results:
+ * TRUE if the library is out-of-date. FALSE otherwise.
+ *
+ * Side Effects:
+ * The library will be hashed if it hasn't been already.
+ *
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Arch_LibOODate (gn)
+ GNode *gn; /* The library's graph node */
+{
+ Boolean oodate;
+
+ if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
+ oodate = FALSE;
+ } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) {
+ oodate = TRUE;
+ } else {
+#ifdef RANLIBMAG
+ struct ar_hdr *arhPtr; /* Header for __.SYMDEF */
+ int modTimeTOC; /* The table-of-contents's mod time */
+
+ arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE);
+
+ if (arhPtr != (struct ar_hdr *)NULL) {
+ modTimeTOC = (int) strtol(arhPtr->ar_date, NULL, 10);
+
+ if (DEBUG(ARCH) || DEBUG(MAKE)) {
+ printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
+ }
+ oodate = (gn->cmtime > modTimeTOC);
+ } else {
+ /*
+ * A library w/o a table of contents is out-of-date
+ */
+ if (DEBUG(ARCH) || DEBUG(MAKE)) {
+ printf("No t.o.c....");
+ }
+ oodate = TRUE;
+ }
+#else
+ oodate = FALSE;
+#endif
+ }
+ return (oodate);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_Init --
+ * Initialize things for this module.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The 'archives' list is initialized.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Arch_Init ()
+{
+ archives = Lst_Init (FALSE);
+}
+
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Arch_End --
+ * Cleanup things for this module.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The 'archives' list is freed
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Arch_End ()
+{
+ Lst_Destroy(archives, ArchFree);
+}
diff --git a/usr.bin/make/buf.c b/usr.bin/make/buf.c
new file mode 100644
index 0000000..462cbef
--- /dev/null
+++ b/usr.bin/make/buf.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * buf.c --
+ * Functions for automatically-expanded buffers.
+ */
+
+#include "sprite.h"
+#include "make.h"
+#include "buf.h"
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/*
+ * BufExpand --
+ * Expand the given buffer to hold the given number of additional
+ * bytes.
+ * Makes sure there's room for an extra NULL byte at the end of the
+ * buffer in case it holds a string.
+ */
+#define BufExpand(bp,nb) \
+ if (bp->left < (nb)+1) {\
+ int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \
+ Byte *newBuf = (Byte *) erealloc((bp)->buffer, newSize); \
+ \
+ (bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \
+ (bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\
+ (bp)->buffer = newBuf;\
+ (bp)->size = newSize;\
+ (bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);\
+ }
+
+#define BUF_DEF_SIZE 256 /* Default buffer size */
+#define BUF_ADD_INC 256 /* Expansion increment when Adding */
+#define BUF_UNGET_INC 16 /* Expansion increment when Ungetting */
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_OvAddByte --
+ * Add a single byte to the buffer. left is zero or negative.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The buffer may be expanded.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_OvAddByte (bp, byte)
+ register Buffer bp;
+ int byte;
+{
+ int nbytes = 1;
+ bp->left = 0;
+ BufExpand (bp, nbytes);
+
+ *bp->inPtr++ = byte;
+ bp->left--;
+
+ /*
+ * Null-terminate
+ */
+ *bp->inPtr = 0;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_AddBytes --
+ * Add a number of bytes to the buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Guess what?
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_AddBytes (bp, numBytes, bytesPtr)
+ register Buffer bp;
+ int numBytes;
+ Byte *bytesPtr;
+{
+
+ BufExpand (bp, numBytes);
+
+ memcpy (bp->inPtr, bytesPtr, numBytes);
+ bp->inPtr += numBytes;
+ bp->left -= numBytes;
+
+ /*
+ * Null-terminate
+ */
+ *bp->inPtr = 0;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_UngetByte --
+ * Place the byte back at the beginning of the buffer.
+ *
+ * Results:
+ * SUCCESS if the byte was added ok. FAILURE if not.
+ *
+ * Side Effects:
+ * The byte is stuffed in the buffer and outPtr is decremented.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_UngetByte (bp, byte)
+ register Buffer bp;
+ int byte;
+{
+
+ if (bp->outPtr != bp->buffer) {
+ bp->outPtr--;
+ *bp->outPtr = byte;
+ } else if (bp->outPtr == bp->inPtr) {
+ *bp->inPtr = byte;
+ bp->inPtr++;
+ bp->left--;
+ *bp->inPtr = 0;
+ } else {
+ /*
+ * Yech. have to expand the buffer to stuff this thing in.
+ * We use a different expansion constant because people don't
+ * usually push back many bytes when they're doing it a byte at
+ * a time...
+ */
+ int numBytes = bp->inPtr - bp->outPtr;
+ Byte *newBuf;
+
+ newBuf = (Byte *)emalloc(bp->size + BUF_UNGET_INC);
+ memcpy ((char *)(newBuf+BUF_UNGET_INC), (char *)bp->outPtr, numBytes+1);
+ bp->outPtr = newBuf + BUF_UNGET_INC;
+ bp->inPtr = bp->outPtr + numBytes;
+ free ((char *)bp->buffer);
+ bp->buffer = newBuf;
+ bp->size += BUF_UNGET_INC;
+ bp->left = bp->size - (bp->inPtr - bp->buffer);
+ bp->outPtr -= 1;
+ *bp->outPtr = byte;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_UngetBytes --
+ * Push back a series of bytes at the beginning of the buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * outPtr is decremented and the bytes copied into the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_UngetBytes (bp, numBytes, bytesPtr)
+ register Buffer bp;
+ int numBytes;
+ Byte *bytesPtr;
+{
+
+ if (bp->outPtr - bp->buffer >= numBytes) {
+ bp->outPtr -= numBytes;
+ memcpy (bp->outPtr, bytesPtr, numBytes);
+ } else if (bp->outPtr == bp->inPtr) {
+ Buf_AddBytes (bp, numBytes, bytesPtr);
+ } else {
+ int curNumBytes = bp->inPtr - bp->outPtr;
+ Byte *newBuf;
+ int newBytes = max(numBytes,BUF_UNGET_INC);
+
+ newBuf = (Byte *)emalloc (bp->size + newBytes);
+ memcpy((char *)(newBuf+newBytes), (char *)bp->outPtr, curNumBytes+1);
+ bp->outPtr = newBuf + newBytes;
+ bp->inPtr = bp->outPtr + curNumBytes;
+ free ((char *)bp->buffer);
+ bp->buffer = newBuf;
+ bp->size += newBytes;
+ bp->left = bp->size - (bp->inPtr - bp->buffer);
+ bp->outPtr -= numBytes;
+ memcpy ((char *)bp->outPtr, (char *)bytesPtr, numBytes);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_GetByte --
+ * Return the next byte from the buffer. Actually returns an integer.
+ *
+ * Results:
+ * Returns BUF_ERROR if there's no byte in the buffer, or the byte
+ * itself if there is one.
+ *
+ * Side Effects:
+ * outPtr is incremented and both outPtr and inPtr will be reset if
+ * the buffer is emptied.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Buf_GetByte (bp)
+ register Buffer bp;
+{
+ int res;
+
+ if (bp->inPtr == bp->outPtr) {
+ return (BUF_ERROR);
+ } else {
+ res = (int) *bp->outPtr;
+ bp->outPtr += 1;
+ if (bp->outPtr == bp->inPtr) {
+ bp->outPtr = bp->inPtr = bp->buffer;
+ bp->left = bp->size;
+ *bp->inPtr = 0;
+ }
+ return (res);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_GetBytes --
+ * Extract a number of bytes from the buffer.
+ *
+ * Results:
+ * The number of bytes gotten.
+ *
+ * Side Effects:
+ * The passed array is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Buf_GetBytes (bp, numBytes, bytesPtr)
+ register Buffer bp;
+ int numBytes;
+ Byte *bytesPtr;
+{
+
+ if (bp->inPtr - bp->outPtr < numBytes) {
+ numBytes = bp->inPtr - bp->outPtr;
+ }
+ memcpy (bytesPtr, bp->outPtr, numBytes);
+ bp->outPtr += numBytes;
+
+ if (bp->outPtr == bp->inPtr) {
+ bp->outPtr = bp->inPtr = bp->buffer;
+ bp->left = bp->size;
+ *bp->inPtr = 0;
+ }
+ return (numBytes);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_GetAll --
+ * Get all the available data at once.
+ *
+ * Results:
+ * A pointer to the data and the number of bytes available.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+Byte *
+Buf_GetAll (bp, numBytesPtr)
+ register Buffer bp;
+ int *numBytesPtr;
+{
+
+ if (numBytesPtr != (int *)NULL) {
+ *numBytesPtr = bp->inPtr - bp->outPtr;
+ }
+
+ return (bp->outPtr);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_Discard --
+ * Throw away bytes in a buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The bytes are discarded.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_Discard (bp, numBytes)
+ register Buffer bp;
+ int numBytes;
+{
+
+ if (bp->inPtr - bp->outPtr <= numBytes) {
+ bp->inPtr = bp->outPtr = bp->buffer;
+ bp->left = bp->size;
+ *bp->inPtr = 0;
+ } else {
+ bp->outPtr += numBytes;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_Size --
+ * Returns the number of bytes in the given buffer. Doesn't include
+ * the null-terminating byte.
+ *
+ * Results:
+ * The number of bytes.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Buf_Size (buf)
+ Buffer buf;
+{
+ return (buf->inPtr - buf->outPtr);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_Init --
+ * Initialize a buffer. If no initial size is given, a reasonable
+ * default is used.
+ *
+ * Results:
+ * A buffer to be given to other functions in this library.
+ *
+ * Side Effects:
+ * The buffer is created, the space allocated and pointers
+ * initialized.
+ *
+ *-----------------------------------------------------------------------
+ */
+Buffer
+Buf_Init (size)
+ int size; /* Initial size for the buffer */
+{
+ Buffer bp; /* New Buffer */
+
+ bp = (Buffer)emalloc(sizeof(*bp));
+
+ if (size <= 0) {
+ size = BUF_DEF_SIZE;
+ }
+ bp->left = bp->size = size;
+ bp->buffer = (Byte *)emalloc(size);
+ bp->inPtr = bp->outPtr = bp->buffer;
+ *bp->inPtr = 0;
+
+ return (bp);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_Destroy --
+ * Nuke a buffer and all its resources.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The buffer is freed.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_Destroy (buf, freeData)
+ Buffer buf; /* Buffer to destroy */
+ Boolean freeData; /* TRUE if the data should be destroyed as well */
+{
+
+ if (freeData) {
+ free ((char *)buf->buffer);
+ }
+ free ((char *)buf);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Buf_ReplaceLastByte --
+ * Replace the last byte in a buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * If the buffer was empty intially, then a new byte will be added.
+ * Otherwise, the last byte is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Buf_ReplaceLastByte (buf, byte)
+ Buffer buf; /* buffer to augment */
+ Byte byte; /* byte to be written */
+{
+ if (buf->inPtr == buf->outPtr)
+ Buf_AddByte(buf, byte);
+ else
+ *(buf->inPtr - 1) = byte;
+}
diff --git a/usr.bin/make/buf.h b/usr.bin/make/buf.h
new file mode 100644
index 0000000..562739d
--- /dev/null
+++ b/usr.bin/make/buf.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)buf.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/*-
+ * buf.h --
+ * Header for users of the buf library.
+ */
+
+#ifndef _BUF_H
+#define _BUF_H
+
+#include "sprite.h"
+
+typedef char Byte;
+
+typedef struct Buffer {
+ int size; /* Current size of the buffer */
+ int left; /* Space left (== size - (inPtr - buffer)) */
+ Byte *buffer; /* The buffer itself */
+ Byte *inPtr; /* Place to write to */
+ Byte *outPtr; /* Place to read from */
+} *Buffer;
+
+/* Buf_AddByte adds a single byte to a buffer. */
+#define Buf_AddByte(bp, byte) \
+ (void) (--(bp)->left <= 0 ? Buf_OvAddByte(bp, byte), 1 : \
+ (*(bp)->inPtr++ = (byte), *(bp)->inPtr = 0), 1)
+
+#define BUF_ERROR 256
+
+void Buf_OvAddByte __P((Buffer, int));
+void Buf_AddBytes __P((Buffer, int, Byte *));
+void Buf_UngetByte __P((Buffer, int));
+void Buf_UngetBytes __P((Buffer, int, Byte *));
+int Buf_GetByte __P((Buffer));
+int Buf_GetBytes __P((Buffer, int, Byte *));
+Byte *Buf_GetAll __P((Buffer, int *));
+void Buf_Discard __P((Buffer, int));
+int Buf_Size __P((Buffer));
+Buffer Buf_Init __P((int));
+void Buf_Destroy __P((Buffer, Boolean));
+void Buf_ReplaceLastByte __P((Buffer, Byte));
+
+#endif /* _BUF_H */
diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c
new file mode 100644
index 0000000..a646103
--- /dev/null
+++ b/usr.bin/make/compat.c
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * compat.c --
+ * The routines in this file implement the full-compatibility
+ * mode of PMake. Most of the special functionality of PMake
+ * is available in this mode. Things not supported:
+ * - different shells.
+ * - friendly variable substitution.
+ *
+ * Interface:
+ * Compat_Run Initialize things for this module and recreate
+ * thems as need creatin'
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "job.h"
+extern int errno;
+
+/*
+ * The following array is used to make a fast determination of which
+ * characters are interpreted specially by the shell. If a command
+ * contains any of these characters, it is executed by the shell, not
+ * directly by us.
+ */
+
+static char meta[256];
+
+static GNode *curTarg = NILGNODE;
+static GNode *ENDNode;
+static void CompatInterrupt __P((int));
+static int CompatRunCommand __P((ClientData, ClientData));
+static int CompatMake __P((ClientData, ClientData));
+
+/*-
+ *-----------------------------------------------------------------------
+ * CompatInterrupt --
+ * Interrupt the creation of the current target and remove it if
+ * it ain't precious.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The target is removed and the process exits. If .INTERRUPT exists,
+ * its commands are run first WITH INTERRUPTS IGNORED..
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+CompatInterrupt (signo)
+ int signo;
+{
+ GNode *gn;
+
+ if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {
+ char *p1;
+ char *file = Var_Value (TARGET, curTarg, &p1);
+
+ if (!noExecute && eunlink(file) != -1) {
+ printf ("*** %s removed\n", file);
+ }
+ if (p1)
+ free(p1);
+
+ /*
+ * Run .INTERRUPT only if hit with interrupt signal
+ */
+ if (signo == SIGINT) {
+ gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
+ if (gn != NILGNODE) {
+ Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
+ }
+ }
+
+ }
+ exit (signo);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CompatRunCommand --
+ * Execute the next command for a target. If the command returns an
+ * error, the node's made field is set to ERROR and creation stops.
+ *
+ * Results:
+ * 0 if the command succeeded, 1 if an error occurred.
+ *
+ * Side Effects:
+ * The node's 'made' field may be set to ERROR.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+CompatRunCommand (cmdp, gnp)
+ ClientData cmdp; /* Command to execute */
+ ClientData gnp; /* Node from which the command came */
+{
+ char *cmdStart; /* Start of expanded command */
+ register char *cp;
+ Boolean silent, /* Don't print command */
+ errCheck; /* Check errors */
+ int reason; /* Reason for child's death */
+ int status; /* Description of child's death */
+ int cpid; /* Child actually found */
+ ReturnStatus stat; /* Status of fork */
+ LstNode cmdNode; /* Node where current command is located */
+ char **av; /* Argument vector for thing to exec */
+ int argc; /* Number of arguments in av or 0 if not
+ * dynamically allocated */
+ Boolean local; /* TRUE if command should be executed
+ * locally */
+ char *cmd = (char *) cmdp;
+ GNode *gn = (GNode *) gnp;
+
+ /*
+ * Avoid clobbered variable warnings by forcing the compiler
+ * to ``unregister'' variables
+ */
+#if __GNUC__
+ (void) &av;
+ (void) &errCheck;
+#endif
+ silent = gn->type & OP_SILENT;
+ errCheck = !(gn->type & OP_IGNORE);
+
+ cmdNode = Lst_Member (gn->commands, (ClientData)cmd);
+ cmdStart = Var_Subst (NULL, cmd, gn, FALSE);
+
+ /*
+ * brk_string will return an argv with a NULL in av[1], thus causing
+ * execvp to choke and die horribly. Besides, how can we execute a null
+ * command? In any case, we warn the user that the command expanded to
+ * nothing (is this the right thing to do?).
+ */
+
+ if (*cmdStart == '\0') {
+ free(cmdStart);
+ Error("%s expands to empty string", cmd);
+ return(0);
+ } else {
+ cmd = cmdStart;
+ }
+ Lst_Replace (cmdNode, (ClientData)cmdStart);
+
+ if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
+ (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
+ return(0);
+ } else if (strcmp(cmdStart, "...") == 0) {
+ gn->type |= OP_SAVE_CMDS;
+ return(0);
+ }
+
+ while ((*cmd == '@') || (*cmd == '-')) {
+ if (*cmd == '@') {
+ silent = TRUE;
+ } else {
+ errCheck = FALSE;
+ }
+ cmd++;
+ }
+
+ while (isspace((unsigned char)*cmd))
+ cmd++;
+
+ /*
+ * Search for meta characters in the command. If there are no meta
+ * characters, there's no need to execute a shell to execute the
+ * command.
+ */
+ for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
+ continue;
+ }
+
+ /*
+ * Print the command before echoing if we're not supposed to be quiet for
+ * this one. We also print the command if -n given.
+ */
+ if (!silent || noExecute) {
+ printf ("%s\n", cmd);
+ fflush(stdout);
+ }
+
+ /*
+ * If we're not supposed to execute any commands, this is as far as
+ * we go...
+ */
+ if (noExecute) {
+ return (0);
+ }
+
+ if (*cp != '\0') {
+ /*
+ * If *cp isn't the null character, we hit a "meta" character and
+ * need to pass the command off to the shell. We give the shell the
+ * -e flag as well as -c if it's supposed to exit when it hits an
+ * error.
+ */
+ static char *shargv[4] = { "/bin/sh" };
+
+ shargv[1] = (errCheck ? "-ec" : "-c");
+ shargv[2] = cmd;
+ shargv[3] = (char *)NULL;
+ av = shargv;
+ argc = 0;
+ } else {
+ /*
+ * No meta-characters, so no need to exec a shell. Break the command
+ * into words to form an argument vector we can execute.
+ * brk_string sticks our name in av[0], so we have to
+ * skip over it...
+ */
+ av = brk_string(cmd, &argc, TRUE);
+ av += 1;
+ }
+
+ local = TRUE;
+
+ /*
+ * Fork and execute the single command. If the fork fails, we abort.
+ */
+ cpid = vfork();
+ if (cpid < 0) {
+ Fatal("Could not fork");
+ }
+ if (cpid == 0) {
+ if (local) {
+ execvp(av[0], av);
+ (void) write (2, av[0], strlen (av[0]));
+ (void) write (2, ": not found\n", sizeof(": not found"));
+ } else {
+ (void)execv(av[0], av);
+ }
+ exit(1);
+ }
+ free(cmdStart);
+ Lst_Replace (cmdNode, (ClientData) NULL);
+
+ /*
+ * The child is off and running. Now all we can do is wait...
+ */
+ while (1) {
+
+ while ((stat = wait(&reason)) != cpid) {
+ if (stat == -1 && errno != EINTR) {
+ break;
+ }
+ }
+
+ if (stat > -1) {
+ if (WIFSTOPPED(reason)) {
+ status = WSTOPSIG(reason); /* stopped */
+ } else if (WIFEXITED(reason)) {
+ status = WEXITSTATUS(reason); /* exited */
+ if (status != 0) {
+ printf ("*** Error code %d", status);
+ }
+ } else {
+ status = WTERMSIG(reason); /* signaled */
+ printf ("*** Signal %d", status);
+ }
+
+
+ if (!WIFEXITED(reason) || (status != 0)) {
+ if (errCheck) {
+ gn->made = ERROR;
+ if (keepgoing) {
+ /*
+ * Abort the current target, but let others
+ * continue.
+ */
+ printf (" (continuing)\n");
+ }
+ } else {
+ /*
+ * Continue executing commands for this target.
+ * If we return 0, this will happen...
+ */
+ printf (" (ignored)\n");
+ status = 0;
+ }
+ }
+ break;
+ } else {
+ Fatal ("error in wait: %d", stat);
+ /*NOTREACHED*/
+ }
+ }
+
+ return (status);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CompatMake --
+ * Make a target.
+ *
+ * Results:
+ * 0
+ *
+ * Side Effects:
+ * If an error is detected and not being ignored, the process exits.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+CompatMake (gnp, pgnp)
+ ClientData gnp; /* The node to make */
+ ClientData pgnp; /* Parent to abort if necessary */
+{
+ GNode *gn = (GNode *) gnp;
+ GNode *pgn = (GNode *) pgnp;
+ if (gn->type & OP_USE) {
+ Make_HandleUse(gn, pgn);
+ } else if (gn->made == UNMADE) {
+ /*
+ * First mark ourselves to be made, then apply whatever transformations
+ * the suffix module thinks are necessary. Once that's done, we can
+ * descend and make all our children. If any of them has an error
+ * but the -k flag was given, our 'make' field will be set FALSE again.
+ * This is our signal to not attempt to do anything but abort our
+ * parent as well.
+ */
+ gn->make = TRUE;
+ gn->made = BEINGMADE;
+ Suff_FindDeps (gn);
+ Lst_ForEach (gn->children, CompatMake, (ClientData)gn);
+ if (!gn->make) {
+ gn->made = ABORTED;
+ pgn->make = FALSE;
+ return (0);
+ }
+
+ if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
+ char *p1;
+ Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
+ if (p1)
+ free(p1);
+ }
+
+ /*
+ * All the children were made ok. Now cmtime contains the modification
+ * time of the newest child, we need to find out if we exist and when
+ * we were modified last. The criteria for datedness are defined by the
+ * Make_OODate function.
+ */
+ if (DEBUG(MAKE)) {
+ printf("Examining %s...", gn->name);
+ }
+ if (! Make_OODate(gn)) {
+ gn->made = UPTODATE;
+ if (DEBUG(MAKE)) {
+ printf("up-to-date.\n");
+ }
+ return (0);
+ } else if (DEBUG(MAKE)) {
+ printf("out-of-date.\n");
+ }
+
+ /*
+ * If the user is just seeing if something is out-of-date, exit now
+ * to tell him/her "yes".
+ */
+ if (queryFlag) {
+ exit (-1);
+ }
+
+ /*
+ * We need to be re-made. We also have to make sure we've got a $?
+ * variable. To be nice, we also define the $> variable using
+ * Make_DoAllVar().
+ */
+ Make_DoAllVar(gn);
+
+ /*
+ * Alter our type to tell if errors should be ignored or things
+ * should not be printed so CompatRunCommand knows what to do.
+ */
+ if (Targ_Ignore (gn)) {
+ gn->type |= OP_IGNORE;
+ }
+ if (Targ_Silent (gn)) {
+ gn->type |= OP_SILENT;
+ }
+
+ if (Job_CheckCommands (gn, Fatal)) {
+ /*
+ * Our commands are ok, but we still have to worry about the -t
+ * flag...
+ */
+ if (!touchFlag) {
+ curTarg = gn;
+ Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn);
+ curTarg = NILGNODE;
+ } else {
+ Job_Touch (gn, gn->type & OP_SILENT);
+ }
+ } else {
+ gn->made = ERROR;
+ }
+
+ if (gn->made != ERROR) {
+ /*
+ * If the node was made successfully, mark it so, update
+ * its modification time and timestamp all its parents. Note
+ * that for .ZEROTIME targets, the timestamping isn't done.
+ * This is to keep its state from affecting that of its parent.
+ */
+ gn->made = MADE;
+#ifndef RECHECK
+ /*
+ * We can't re-stat the thing, but we can at least take care of
+ * rules where a target depends on a source that actually creates
+ * the target, but only if it has changed, e.g.
+ *
+ * parse.h : parse.o
+ *
+ * parse.o : parse.y
+ * yacc -d parse.y
+ * cc -c y.tab.c
+ * mv y.tab.o parse.o
+ * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
+ *
+ * In this case, if the definitions produced by yacc haven't
+ * changed from before, parse.h won't have been updated and
+ * gn->mtime will reflect the current modification time for
+ * parse.h. This is something of a kludge, I admit, but it's a
+ * useful one..
+ *
+ * XXX: People like to use a rule like
+ *
+ * FRC:
+ *
+ * To force things that depend on FRC to be made, so we have to
+ * check for gn->children being empty as well...
+ */
+ if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
+ gn->mtime = now;
+ }
+#else
+ /*
+ * This is what Make does and it's actually a good thing, as it
+ * allows rules like
+ *
+ * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
+ *
+ * to function as intended. Unfortunately, thanks to the stateless
+ * nature of NFS (and the speed of this program), there are times
+ * when the modification time of a file created on a remote
+ * machine will not be modified before the stat() implied by
+ * the Dir_MTime occurs, thus leading us to believe that the file
+ * is unchanged, wreaking havoc with files that depend on this one.
+ *
+ * I have decided it is better to make too much than to make too
+ * little, so this stuff is commented out unless you're sure it's
+ * ok.
+ * -- ardeb 1/12/88
+ */
+ if (noExecute || Dir_MTime(gn) == 0) {
+ gn->mtime = now;
+ }
+ if (gn->cmtime > gn->mtime)
+ gn->mtime = gn->cmtime;
+ if (DEBUG(MAKE)) {
+ printf("update time: %s\n", Targ_FmtTime(gn->mtime));
+ }
+#endif
+ if (!(gn->type & OP_EXEC)) {
+ pgn->childMade = TRUE;
+ Make_TimeStamp(pgn, gn);
+ }
+ } else if (keepgoing) {
+ pgn->make = FALSE;
+ } else {
+ printf ("\n\nStop.\n");
+ exit (1);
+ }
+ } else if (gn->made == ERROR) {
+ /*
+ * Already had an error when making this beastie. Tell the parent
+ * to abort.
+ */
+ pgn->make = FALSE;
+ } else {
+ if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
+ char *p1;
+ Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
+ if (p1)
+ free(p1);
+ }
+ switch(gn->made) {
+ case BEINGMADE:
+ Error("Graph cycles through %s\n", gn->name);
+ gn->made = ERROR;
+ pgn->make = FALSE;
+ break;
+ case MADE:
+ if ((gn->type & OP_EXEC) == 0) {
+ pgn->childMade = TRUE;
+ Make_TimeStamp(pgn, gn);
+ }
+ break;
+ case UPTODATE:
+ if ((gn->type & OP_EXEC) == 0) {
+ Make_TimeStamp(pgn, gn);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Compat_Run --
+ * Initialize this mode and start making.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Guess what?
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Compat_Run(targs)
+ Lst targs; /* List of target nodes to re-create */
+{
+ char *cp; /* Pointer to string of shell meta-characters */
+ GNode *gn = NULL;/* Current root target */
+ int errors; /* Number of targets not remade due to errors */
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ signal(SIGINT, CompatInterrupt);
+ }
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+ signal(SIGTERM, CompatInterrupt);
+ }
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ signal(SIGHUP, CompatInterrupt);
+ }
+ if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
+ signal(SIGQUIT, CompatInterrupt);
+ }
+
+ for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
+ meta[(unsigned char) *cp] = 1;
+ }
+ /*
+ * The null character serves as a sentinel in the string.
+ */
+ meta[0] = 1;
+
+ ENDNode = Targ_FindNode(".END", TARG_CREATE);
+ /*
+ * If the user has defined a .BEGIN target, execute the commands attached
+ * to it.
+ */
+ if (!queryFlag) {
+ gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
+ if (gn != NILGNODE) {
+ Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
+ if (gn->made == ERROR) {
+ printf("\n\nStop.\n");
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * For each entry in the list of targets to create, call CompatMake on
+ * it to create the thing. CompatMake will leave the 'made' field of gn
+ * in one of several states:
+ * UPTODATE gn was already up-to-date
+ * MADE gn was recreated successfully
+ * ERROR An error occurred while gn was being created
+ * ABORTED gn was not remade because one of its inferiors
+ * could not be made due to errors.
+ */
+ errors = 0;
+ while (!Lst_IsEmpty (targs)) {
+ gn = (GNode *) Lst_DeQueue (targs);
+ CompatMake (gn, gn);
+
+ if (gn->made == UPTODATE) {
+ printf ("`%s' is up to date.\n", gn->name);
+ } else if (gn->made == ABORTED) {
+ printf ("`%s' not remade because of errors.\n", gn->name);
+ errors += 1;
+ }
+ }
+
+ /*
+ * If the user has defined a .END target, run its commands.
+ */
+ if (errors == 0) {
+ Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn);
+ }
+}
diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c
new file mode 100644
index 0000000..d5c1fc2
--- /dev/null
+++ b/usr.bin/make/cond.c
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
+#endif /* not lint */
+
+/*-
+ * cond.c --
+ * Functions to handle conditionals in a makefile.
+ *
+ * Interface:
+ * Cond_Eval Evaluate the conditional in the passed line.
+ *
+ */
+
+#include <ctype.h>
+#include <math.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "buf.h"
+
+/*
+ * The parsing of conditional expressions is based on this grammar:
+ * E -> F || E
+ * E -> F
+ * F -> T && F
+ * F -> T
+ * T -> defined(variable)
+ * T -> make(target)
+ * T -> exists(file)
+ * T -> empty(varspec)
+ * T -> target(name)
+ * T -> symbol
+ * T -> $(varspec) op value
+ * T -> $(varspec) == "string"
+ * T -> $(varspec) != "string"
+ * T -> ( E )
+ * T -> ! T
+ * op -> == | != | > | < | >= | <=
+ *
+ * 'symbol' is some other symbol to which the default function (condDefProc)
+ * is applied.
+ *
+ * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
+ * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
+ * LParen for '(', RParen for ')' and will evaluate the other terminal
+ * symbols, using either the default function or the function given in the
+ * terminal, and return the result as either True or False.
+ *
+ * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
+ */
+typedef enum {
+ And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
+} Token;
+
+/*-
+ * Structures to handle elegantly the different forms of #if's. The
+ * last two fields are stored in condInvert and condDefProc, respectively.
+ */
+static void CondPushBack __P((Token));
+static int CondGetArg __P((char **, char **, char *, Boolean));
+static Boolean CondDoDefined __P((int, char *));
+static int CondStrMatch __P((ClientData, ClientData));
+static Boolean CondDoMake __P((int, char *));
+static Boolean CondDoExists __P((int, char *));
+static Boolean CondDoTarget __P((int, char *));
+static Boolean CondCvtArg __P((char *, double *));
+static Token CondToken __P((Boolean));
+static Token CondT __P((Boolean));
+static Token CondF __P((Boolean));
+static Token CondE __P((Boolean));
+
+static struct If {
+ char *form; /* Form of if */
+ int formlen; /* Length of form */
+ Boolean doNot; /* TRUE if default function should be negated */
+ Boolean (*defProc) __P((int, char *)); /* Default function to apply */
+} ifs[] = {
+ { "ifdef", 5, FALSE, CondDoDefined },
+ { "ifndef", 6, TRUE, CondDoDefined },
+ { "ifmake", 6, FALSE, CondDoMake },
+ { "ifnmake", 7, TRUE, CondDoMake },
+ { "if", 2, FALSE, CondDoDefined },
+ { NULL, 0, FALSE, NULL }
+};
+
+static Boolean condInvert; /* Invert the default function */
+static Boolean (*condDefProc) /* Default function to apply */
+ __P((int, char *));
+static char *condExpr; /* The expression to parse */
+static Token condPushBack=None; /* Single push-back token used in
+ * parsing */
+
+#define MAXIF 30 /* greatest depth of #if'ing */
+
+static Boolean condStack[MAXIF]; /* Stack of conditionals's values */
+static int condTop = MAXIF; /* Top-most conditional */
+static int skipIfLevel=0; /* Depth of skipped conditionals */
+static Boolean skipLine = FALSE; /* Whether the parse module is skipping
+ * lines */
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondPushBack --
+ * Push back the most recent token read. We only need one level of
+ * this, so the thing is just stored in 'condPushback'.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * condPushback is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+CondPushBack (t)
+ Token t; /* Token to push back into the "stream" */
+{
+ condPushBack = t;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondGetArg --
+ * Find the argument of a built-in function.
+ *
+ * Results:
+ * The length of the argument and the address of the argument.
+ *
+ * Side Effects:
+ * The pointer is set to point to the closing parenthesis of the
+ * function call.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+CondGetArg (linePtr, argPtr, func, parens)
+ char **linePtr;
+ char **argPtr;
+ char *func;
+ Boolean parens; /* TRUE if arg should be bounded by parens */
+{
+ register char *cp;
+ int argLen;
+ register Buffer buf;
+
+ cp = *linePtr;
+ if (parens) {
+ while (*cp != '(' && *cp != '\0') {
+ cp++;
+ }
+ if (*cp == '(') {
+ cp++;
+ }
+ }
+
+ if (*cp == '\0') {
+ /*
+ * No arguments whatsoever. Because 'make' and 'defined' aren't really
+ * "reserved words", we don't print a message. I think this is better
+ * than hitting the user with a warning message every time s/he uses
+ * the word 'make' or 'defined' at the beginning of a symbol...
+ */
+ *argPtr = cp;
+ return (0);
+ }
+
+ while (*cp == ' ' || *cp == '\t') {
+ cp++;
+ }
+
+ /*
+ * Create a buffer for the argument and start it out at 16 characters
+ * long. Why 16? Why not?
+ */
+ buf = Buf_Init(16);
+
+ while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
+ if (*cp == '$') {
+ /*
+ * Parse the variable spec and install it as part of the argument
+ * if it's valid. We tell Var_Parse to complain on an undefined
+ * variable, so we don't do it too. Nor do we return an error,
+ * though perhaps we should...
+ */
+ char *cp2;
+ int len;
+ Boolean doFree;
+
+ cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
+
+ Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
+ if (doFree) {
+ free(cp2);
+ }
+ cp += len;
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ cp++;
+ }
+ }
+
+ Buf_AddByte(buf, (Byte)'\0');
+ *argPtr = (char *)Buf_GetAll(buf, &argLen);
+ Buf_Destroy(buf, FALSE);
+
+ while (*cp == ' ' || *cp == '\t') {
+ cp++;
+ }
+ if (parens && *cp != ')') {
+ Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",
+ func);
+ return (0);
+ } else if (parens) {
+ /*
+ * Advance pointer past close parenthesis.
+ */
+ cp++;
+ }
+
+ *linePtr = cp;
+ return (argLen);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondDoDefined --
+ * Handle the 'defined' function for conditionals.
+ *
+ * Results:
+ * TRUE if the given variable is defined.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+CondDoDefined (argLen, arg)
+ int argLen;
+ char *arg;
+{
+ char savec = arg[argLen];
+ char *p1;
+ Boolean result;
+
+ arg[argLen] = '\0';
+ if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) {
+ result = TRUE;
+ } else {
+ result = FALSE;
+ }
+ if (p1)
+ free(p1);
+ arg[argLen] = savec;
+ return (result);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondStrMatch --
+ * Front-end for Str_Match so it returns 0 on match and non-zero
+ * on mismatch. Callback function for CondDoMake via Lst_Find
+ *
+ * Results:
+ * 0 if string matches pattern
+ *
+ * Side Effects:
+ * None
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+CondStrMatch(string, pattern)
+ ClientData string;
+ ClientData pattern;
+{
+ return(!Str_Match((char *) string,(char *) pattern));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondDoMake --
+ * Handle the 'make' function for conditionals.
+ *
+ * Results:
+ * TRUE if the given target is being made.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+CondDoMake (argLen, arg)
+ int argLen;
+ char *arg;
+{
+ char savec = arg[argLen];
+ Boolean result;
+
+ arg[argLen] = '\0';
+ if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) {
+ result = FALSE;
+ } else {
+ result = TRUE;
+ }
+ arg[argLen] = savec;
+ return (result);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondDoExists --
+ * See if the given file exists.
+ *
+ * Results:
+ * TRUE if the file exists and FALSE if it does not.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+CondDoExists (argLen, arg)
+ int argLen;
+ char *arg;
+{
+ char savec = arg[argLen];
+ Boolean result;
+ char *path;
+
+ arg[argLen] = '\0';
+ path = Dir_FindFile(arg, dirSearchPath);
+ if (path != (char *)NULL) {
+ result = TRUE;
+ free(path);
+ } else {
+ result = FALSE;
+ }
+ arg[argLen] = savec;
+ return (result);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondDoTarget --
+ * See if the given node exists and is an actual target.
+ *
+ * Results:
+ * TRUE if the node exists as a target and FALSE if it does not.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+CondDoTarget (argLen, arg)
+ int argLen;
+ char *arg;
+{
+ char savec = arg[argLen];
+ Boolean result;
+ GNode *gn;
+
+ arg[argLen] = '\0';
+ gn = Targ_FindNode(arg, TARG_NOCREATE);
+ if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
+ result = TRUE;
+ } else {
+ result = FALSE;
+ }
+ arg[argLen] = savec;
+ return (result);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondCvtArg --
+ * Convert the given number into a double. If the number begins
+ * with 0x, it is interpreted as a hexadecimal integer
+ * and converted to a double from there. All other strings just have
+ * strtod called on them.
+ *
+ * Results:
+ * Sets 'value' to double value of string.
+ * Returns true if the string was a valid number, false o.w.
+ *
+ * Side Effects:
+ * Can change 'value' even if string is not a valid number.
+ *
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+CondCvtArg(str, value)
+ register char *str;
+ double *value;
+{
+ if ((*str == '0') && (str[1] == 'x')) {
+ register long i;
+
+ for (str += 2, i = 0; *str; str++) {
+ int x;
+ if (isdigit((unsigned char) *str))
+ x = *str - '0';
+ else if (isxdigit((unsigned char) *str))
+ x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';
+ else
+ return FALSE;
+ i = (i << 4) + x;
+ }
+ *value = (double) i;
+ return TRUE;
+ }
+ else {
+ char *eptr;
+ *value = strtod(str, &eptr);
+ return *eptr == '\0';
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondToken --
+ * Return the next token from the input.
+ *
+ * Results:
+ * A Token for the next lexical token in the stream.
+ *
+ * Side Effects:
+ * condPushback will be set back to None if it is used.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Token
+CondToken(doEval)
+ Boolean doEval;
+{
+ Token t;
+
+ if (condPushBack == None) {
+ while (*condExpr == ' ' || *condExpr == '\t') {
+ condExpr++;
+ }
+ switch (*condExpr) {
+ case '(':
+ t = LParen;
+ condExpr++;
+ break;
+ case ')':
+ t = RParen;
+ condExpr++;
+ break;
+ case '|':
+ if (condExpr[1] == '|') {
+ condExpr++;
+ }
+ condExpr++;
+ t = Or;
+ break;
+ case '&':
+ if (condExpr[1] == '&') {
+ condExpr++;
+ }
+ condExpr++;
+ t = And;
+ break;
+ case '!':
+ t = Not;
+ condExpr++;
+ break;
+ case '\n':
+ case '\0':
+ t = EndOfFile;
+ break;
+ case '$': {
+ char *lhs;
+ char *rhs;
+ char *op;
+ int varSpecLen;
+ Boolean doFree;
+
+ /*
+ * Parse the variable spec and skip over it, saving its
+ * value in lhs.
+ */
+ t = Err;
+ lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);
+ if (lhs == var_Error) {
+ /*
+ * Even if !doEval, we still report syntax errors, which
+ * is what getting var_Error back with !doEval means.
+ */
+ return(Err);
+ }
+ condExpr += varSpecLen;
+
+ if (!isspace((unsigned char) *condExpr) &&
+ strchr("!=><", *condExpr) == NULL) {
+ Buffer buf;
+ char *cp;
+
+ buf = Buf_Init(0);
+
+ for (cp = lhs; *cp; cp++)
+ Buf_AddByte(buf, (Byte)*cp);
+
+ if (doFree)
+ free(lhs);
+
+ for (;*condExpr && !isspace((unsigned char) *condExpr);
+ condExpr++)
+ Buf_AddByte(buf, (Byte)*condExpr);
+
+ Buf_AddByte(buf, (Byte)'\0');
+ lhs = (char *)Buf_GetAll(buf, &varSpecLen);
+ Buf_Destroy(buf, FALSE);
+
+ doFree = TRUE;
+ }
+
+ /*
+ * Skip whitespace to get to the operator
+ */
+ while (isspace((unsigned char) *condExpr))
+ condExpr++;
+
+ /*
+ * Make sure the operator is a valid one. If it isn't a
+ * known relational operator, pretend we got a
+ * != 0 comparison.
+ */
+ op = condExpr;
+ switch (*condExpr) {
+ case '!':
+ case '=':
+ case '<':
+ case '>':
+ if (condExpr[1] == '=') {
+ condExpr += 2;
+ } else {
+ condExpr += 1;
+ }
+ break;
+ default:
+ op = "!=";
+ rhs = "0";
+
+ goto do_compare;
+ }
+ while (isspace((unsigned char) *condExpr)) {
+ condExpr++;
+ }
+ if (*condExpr == '\0') {
+ Parse_Error(PARSE_WARNING,
+ "Missing right-hand-side of operator");
+ goto error;
+ }
+ rhs = condExpr;
+do_compare:
+ if (*rhs == '"') {
+ /*
+ * Doing a string comparison. Only allow == and != for
+ * operators.
+ */
+ char *string;
+ char *cp, *cp2;
+ int qt;
+ Buffer buf;
+
+do_string_compare:
+ if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
+ Parse_Error(PARSE_WARNING,
+ "String comparison operator should be either == or !=");
+ goto error;
+ }
+
+ buf = Buf_Init(0);
+ qt = *rhs == '"' ? 1 : 0;
+
+ for (cp = &rhs[qt];
+ ((qt && (*cp != '"')) ||
+ (!qt && strchr(" \t)", *cp) == NULL)) &&
+ (*cp != '\0'); cp++) {
+ if ((*cp == '\\') && (cp[1] != '\0')) {
+ /*
+ * Backslash escapes things -- skip over next
+ * character, if it exists.
+ */
+ cp++;
+ Buf_AddByte(buf, (Byte)*cp);
+ } else if (*cp == '$') {
+ int len;
+ Boolean freeIt;
+
+ cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);
+ if (cp2 != var_Error) {
+ Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
+ if (freeIt) {
+ free(cp2);
+ }
+ cp += len - 1;
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ }
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ }
+ }
+
+ Buf_AddByte(buf, (Byte)0);
+
+ string = (char *)Buf_GetAll(buf, (int *)0);
+ Buf_Destroy(buf, FALSE);
+
+ if (DEBUG(COND)) {
+ printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
+ lhs, string, op);
+ }
+ /*
+ * Null-terminate rhs and perform the comparison.
+ * t is set to the result.
+ */
+ if (*op == '=') {
+ t = strcmp(lhs, string) ? False : True;
+ } else {
+ t = strcmp(lhs, string) ? True : False;
+ }
+ free(string);
+ if (rhs == condExpr) {
+ if (!qt && *cp == ')')
+ condExpr = cp;
+ else
+ condExpr = cp + 1;
+ }
+ } else {
+ /*
+ * rhs is either a float or an integer. Convert both the
+ * lhs and the rhs to a double and compare the two.
+ */
+ double left, right;
+ char *string;
+
+ if (!CondCvtArg(lhs, &left))
+ goto do_string_compare;
+ if (*rhs == '$') {
+ int len;
+ Boolean freeIt;
+
+ string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);
+ if (string == var_Error) {
+ right = 0.0;
+ } else {
+ if (!CondCvtArg(string, &right)) {
+ if (freeIt)
+ free(string);
+ goto do_string_compare;
+ }
+ if (freeIt)
+ free(string);
+ if (rhs == condExpr)
+ condExpr += len;
+ }
+ } else {
+ if (!CondCvtArg(rhs, &right))
+ goto do_string_compare;
+ if (rhs == condExpr) {
+ /*
+ * Skip over the right-hand side
+ */
+ while(!isspace((unsigned char) *condExpr) &&
+ (*condExpr != '\0')) {
+ condExpr++;
+ }
+ }
+ }
+
+ if (DEBUG(COND)) {
+ printf("left = %f, right = %f, op = %.2s\n", left,
+ right, op);
+ }
+ switch(op[0]) {
+ case '!':
+ if (op[1] != '=') {
+ Parse_Error(PARSE_WARNING,
+ "Unknown operator");
+ goto error;
+ }
+ t = (left != right ? True : False);
+ break;
+ case '=':
+ if (op[1] != '=') {
+ Parse_Error(PARSE_WARNING,
+ "Unknown operator");
+ goto error;
+ }
+ t = (left == right ? True : False);
+ break;
+ case '<':
+ if (op[1] == '=') {
+ t = (left <= right ? True : False);
+ } else {
+ t = (left < right ? True : False);
+ }
+ break;
+ case '>':
+ if (op[1] == '=') {
+ t = (left >= right ? True : False);
+ } else {
+ t = (left > right ? True : False);
+ }
+ break;
+ }
+ }
+error:
+ if (doFree)
+ free(lhs);
+ break;
+ }
+ default: {
+ Boolean (*evalProc) __P((int, char *));
+ Boolean invert = FALSE;
+ char *arg;
+ int arglen;
+
+ if (strncmp (condExpr, "defined", 7) == 0) {
+ /*
+ * Use CondDoDefined to evaluate the argument and
+ * CondGetArg to extract the argument from the 'function
+ * call'.
+ */
+ evalProc = CondDoDefined;
+ condExpr += 7;
+ arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);
+ if (arglen == 0) {
+ condExpr -= 7;
+ goto use_default;
+ }
+ } else if (strncmp (condExpr, "make", 4) == 0) {
+ /*
+ * Use CondDoMake to evaluate the argument and
+ * CondGetArg to extract the argument from the 'function
+ * call'.
+ */
+ evalProc = CondDoMake;
+ condExpr += 4;
+ arglen = CondGetArg (&condExpr, &arg, "make", TRUE);
+ if (arglen == 0) {
+ condExpr -= 4;
+ goto use_default;
+ }
+ } else if (strncmp (condExpr, "exists", 6) == 0) {
+ /*
+ * Use CondDoExists to evaluate the argument and
+ * CondGetArg to extract the argument from the
+ * 'function call'.
+ */
+ evalProc = CondDoExists;
+ condExpr += 6;
+ arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
+ if (arglen == 0) {
+ condExpr -= 6;
+ goto use_default;
+ }
+ } else if (strncmp(condExpr, "empty", 5) == 0) {
+ /*
+ * Use Var_Parse to parse the spec in parens and return
+ * True if the resulting string is empty.
+ */
+ int length;
+ Boolean doFree;
+ char *val;
+
+ condExpr += 5;
+
+ for (arglen = 0;
+ condExpr[arglen] != '(' && condExpr[arglen] != '\0';
+ arglen += 1)
+ continue;
+
+ if (condExpr[arglen] != '\0') {
+ val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
+ doEval, &length, &doFree);
+ if (val == var_Error) {
+ t = Err;
+ } else {
+ /*
+ * A variable is empty when it just contains
+ * spaces... 4/15/92, christos
+ */
+ char *p;
+ for (p = val; *p && isspace((unsigned char)*p); p++)
+ continue;
+ t = (*p == '\0') ? True : False;
+ }
+ if (doFree) {
+ free(val);
+ }
+ /*
+ * Advance condExpr to beyond the closing ). Note that
+ * we subtract one from arglen + length b/c length
+ * is calculated from condExpr[arglen - 1].
+ */
+ condExpr += arglen + length - 1;
+ } else {
+ condExpr -= 5;
+ goto use_default;
+ }
+ break;
+ } else if (strncmp (condExpr, "target", 6) == 0) {
+ /*
+ * Use CondDoTarget to evaluate the argument and
+ * CondGetArg to extract the argument from the
+ * 'function call'.
+ */
+ evalProc = CondDoTarget;
+ condExpr += 6;
+ arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
+ if (arglen == 0) {
+ condExpr -= 6;
+ goto use_default;
+ }
+ } else {
+ /*
+ * The symbol is itself the argument to the default
+ * function. We advance condExpr to the end of the symbol
+ * by hand (the next whitespace, closing paren or
+ * binary operator) and set to invert the evaluation
+ * function if condInvert is TRUE.
+ */
+ use_default:
+ invert = condInvert;
+ evalProc = condDefProc;
+ arglen = CondGetArg(&condExpr, &arg, "", FALSE);
+ }
+
+ /*
+ * Evaluate the argument using the set function. If invert
+ * is TRUE, we invert the sense of the function.
+ */
+ t = (!doEval || (* evalProc) (arglen, arg) ?
+ (invert ? False : True) :
+ (invert ? True : False));
+ free(arg);
+ break;
+ }
+ }
+ } else {
+ t = condPushBack;
+ condPushBack = None;
+ }
+ return (t);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondT --
+ * Parse a single term in the expression. This consists of a terminal
+ * symbol or Not and a terminal symbol (not including the binary
+ * operators):
+ * T -> defined(variable) | make(target) | exists(file) | symbol
+ * T -> ! T | ( E )
+ *
+ * Results:
+ * True, False or Err.
+ *
+ * Side Effects:
+ * Tokens are consumed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Token
+CondT(doEval)
+ Boolean doEval;
+{
+ Token t;
+
+ t = CondToken(doEval);
+
+ if (t == EndOfFile) {
+ /*
+ * If we reached the end of the expression, the expression
+ * is malformed...
+ */
+ t = Err;
+ } else if (t == LParen) {
+ /*
+ * T -> ( E )
+ */
+ t = CondE(doEval);
+ if (t != Err) {
+ if (CondToken(doEval) != RParen) {
+ t = Err;
+ }
+ }
+ } else if (t == Not) {
+ t = CondT(doEval);
+ if (t == True) {
+ t = False;
+ } else if (t == False) {
+ t = True;
+ }
+ }
+ return (t);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondF --
+ * Parse a conjunctive factor (nice name, wot?)
+ * F -> T && F | T
+ *
+ * Results:
+ * True, False or Err
+ *
+ * Side Effects:
+ * Tokens are consumed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Token
+CondF(doEval)
+ Boolean doEval;
+{
+ Token l, o;
+
+ l = CondT(doEval);
+ if (l != Err) {
+ o = CondToken(doEval);
+
+ if (o == And) {
+ /*
+ * F -> T && F
+ *
+ * If T is False, the whole thing will be False, but we have to
+ * parse the r.h.s. anyway (to throw it away).
+ * If T is True, the result is the r.h.s., be it an Err or no.
+ */
+ if (l == True) {
+ l = CondF(doEval);
+ } else {
+ (void) CondF(FALSE);
+ }
+ } else {
+ /*
+ * F -> T
+ */
+ CondPushBack (o);
+ }
+ }
+ return (l);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * CondE --
+ * Main expression production.
+ * E -> F || E | F
+ *
+ * Results:
+ * True, False or Err.
+ *
+ * Side Effects:
+ * Tokens are, of course, consumed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Token
+CondE(doEval)
+ Boolean doEval;
+{
+ Token l, o;
+
+ l = CondF(doEval);
+ if (l != Err) {
+ o = CondToken(doEval);
+
+ if (o == Or) {
+ /*
+ * E -> F || E
+ *
+ * A similar thing occurs for ||, except that here we make sure
+ * the l.h.s. is False before we bother to evaluate the r.h.s.
+ * Once again, if l is False, the result is the r.h.s. and once
+ * again if l is True, we parse the r.h.s. to throw it away.
+ */
+ if (l == False) {
+ l = CondE(doEval);
+ } else {
+ (void) CondE(FALSE);
+ }
+ } else {
+ /*
+ * E -> F
+ */
+ CondPushBack (o);
+ }
+ }
+ return (l);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Cond_Eval --
+ * Evaluate the conditional in the passed line. The line
+ * looks like this:
+ * #<cond-type> <expr>
+ * where <cond-type> is any of if, ifmake, ifnmake, ifdef,
+ * ifndef, elif, elifmake, elifnmake, elifdef, elifndef
+ * and <expr> consists of &&, ||, !, make(target), defined(variable)
+ * and parenthetical groupings thereof.
+ *
+ * Results:
+ * COND_PARSE if should parse lines after the conditional
+ * COND_SKIP if should skip lines after the conditional
+ * COND_INVALID if not a valid conditional.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Cond_Eval (line)
+ char *line; /* Line to parse */
+{
+ struct If *ifp;
+ Boolean isElse;
+ Boolean value = FALSE;
+ int level; /* Level at which to report errors. */
+
+ level = PARSE_FATAL;
+
+ for (line++; *line == ' ' || *line == '\t'; line++) {
+ continue;
+ }
+
+ /*
+ * Find what type of if we're dealing with. The result is left
+ * in ifp and isElse is set TRUE if it's an elif line.
+ */
+ if (line[0] == 'e' && line[1] == 'l') {
+ line += 2;
+ isElse = TRUE;
+ } else if (strncmp (line, "endif", 5) == 0) {
+ /*
+ * End of a conditional section. If skipIfLevel is non-zero, that
+ * conditional was skipped, so lines following it should also be
+ * skipped. Hence, we return COND_SKIP. Otherwise, the conditional
+ * was read so succeeding lines should be parsed (think about it...)
+ * so we return COND_PARSE, unless this endif isn't paired with
+ * a decent if.
+ */
+ if (skipIfLevel != 0) {
+ skipIfLevel -= 1;
+ return (COND_SKIP);
+ } else {
+ if (condTop == MAXIF) {
+ Parse_Error (level, "if-less endif");
+ return (COND_INVALID);
+ } else {
+ skipLine = FALSE;
+ condTop += 1;
+ return (COND_PARSE);
+ }
+ }
+ } else {
+ isElse = FALSE;
+ }
+
+ /*
+ * Figure out what sort of conditional it is -- what its default
+ * function is, etc. -- by looking in the table of valid "ifs"
+ */
+ for (ifp = ifs; ifp->form != (char *)0; ifp++) {
+ if (strncmp (ifp->form, line, ifp->formlen) == 0) {
+ break;
+ }
+ }
+
+ if (ifp->form == (char *) 0) {
+ /*
+ * Nothing fit. If the first word on the line is actually
+ * "else", it's a valid conditional whose value is the inverse
+ * of the previous if we parsed.
+ */
+ if (isElse && (line[0] == 's') && (line[1] == 'e')) {
+ if (condTop == MAXIF) {
+ Parse_Error (level, "if-less else");
+ return (COND_INVALID);
+ } else if (skipIfLevel == 0) {
+ value = !condStack[condTop];
+ } else {
+ return (COND_SKIP);
+ }
+ } else {
+ /*
+ * Not a valid conditional type. No error...
+ */
+ return (COND_INVALID);
+ }
+ } else {
+ if (isElse) {
+ if (condTop == MAXIF) {
+ Parse_Error (level, "if-less elif");
+ return (COND_INVALID);
+ } else if (skipIfLevel != 0) {
+ /*
+ * If skipping this conditional, just ignore the whole thing.
+ * If we don't, the user might be employing a variable that's
+ * undefined, for which there's an enclosing ifdef that
+ * we're skipping...
+ */
+ return(COND_SKIP);
+ }
+ } else if (skipLine) {
+ /*
+ * Don't even try to evaluate a conditional that's not an else if
+ * we're skipping things...
+ */
+ skipIfLevel += 1;
+ return(COND_SKIP);
+ }
+
+ /*
+ * Initialize file-global variables for parsing
+ */
+ condDefProc = ifp->defProc;
+ condInvert = ifp->doNot;
+
+ line += ifp->formlen;
+
+ while (*line == ' ' || *line == '\t') {
+ line++;
+ }
+
+ condExpr = line;
+ condPushBack = None;
+
+ switch (CondE(TRUE)) {
+ case True:
+ if (CondToken(TRUE) == EndOfFile) {
+ value = TRUE;
+ break;
+ }
+ goto err;
+ /*FALLTHRU*/
+ case False:
+ if (CondToken(TRUE) == EndOfFile) {
+ value = FALSE;
+ break;
+ }
+ /*FALLTHRU*/
+ case Err:
+ err:
+ Parse_Error (level, "Malformed conditional (%s)",
+ line);
+ return (COND_INVALID);
+ default:
+ break;
+ }
+ }
+ if (!isElse) {
+ condTop -= 1;
+ } else if ((skipIfLevel != 0) || condStack[condTop]) {
+ /*
+ * If this is an else-type conditional, it should only take effect
+ * if its corresponding if was evaluated and FALSE. If its if was
+ * TRUE or skipped, we return COND_SKIP (and start skipping in case
+ * we weren't already), leaving the stack unmolested so later elif's
+ * don't screw up...
+ */
+ skipLine = TRUE;
+ return (COND_SKIP);
+ }
+
+ if (condTop < 0) {
+ /*
+ * This is the one case where we can definitely proclaim a fatal
+ * error. If we don't, we're hosed.
+ */
+ Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
+ return (COND_INVALID);
+ } else {
+ condStack[condTop] = value;
+ skipLine = !value;
+ return (value ? COND_PARSE : COND_SKIP);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Cond_End --
+ * Make sure everything's clean at the end of a makefile.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Parse_Error will be called if open conditionals are around.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Cond_End()
+{
+ if (condTop != MAXIF) {
+ Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,
+ MAXIF-condTop == 1 ? "" : "s");
+ }
+ condTop = MAXIF;
+}
diff --git a/usr.bin/make/config.h b/usr.bin/make/config.h
new file mode 100644
index 0000000..d72e654
--- /dev/null
+++ b/usr.bin/make/config.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)config.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+#define DEFSHELL 1 /* Bourne shell */
+
+/*
+ * DEFMAXJOBS
+ * DEFMAXLOCAL
+ * These control the default concurrency. On no occasion will more
+ * than DEFMAXJOBS targets be created at once (locally or remotely)
+ * DEFMAXLOCAL is the highest number of targets which will be
+ * created on the local machine at once. Note that if you set this
+ * to 0, nothing will ever happen...
+ */
+#define DEFMAXJOBS 4
+#define DEFMAXLOCAL 1
+
+/*
+ * INCLUDES
+ * LIBRARIES
+ * These control the handling of the .INCLUDES and .LIBS variables.
+ * If INCLUDES is defined, the .INCLUDES variable will be filled
+ * from the search paths of those suffixes which are marked by
+ * .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS
+ * See suff.c for more details.
+ */
+#define INCLUDES
+#define LIBRARIES
+
+/*
+ * LIBSUFF
+ * Is the suffix used to denote libraries and is used by the Suff module
+ * to find the search path on which to seek any -l<xx> targets.
+ *
+ * RECHECK
+ * If defined, Make_Update will check a target for its current
+ * modification time after it has been re-made, setting it to the
+ * starting time of the make only if the target still doesn't exist.
+ * Unfortunately, under NFS the modification time often doesn't
+ * get updated in time, so a target will appear to not have been
+ * re-made, causing later targets to appear up-to-date. On systems
+ * that don't have this problem, you should defined this. Under
+ * NFS you probably should not, unless you aren't exporting jobs.
+ */
+#define LIBSUFF ".a"
+#define RECHECK
+
+/*
+ * POSIX
+ * Adhere to the POSIX 1003.2 draft for the make(1) program.
+ * - Use MAKEFLAGS instead of MAKE to pick arguments from the
+ * environment.
+ * - Allow empty command lines if starting with tab.
+ */
+#define POSIX
+
+/*
+ * SYSVINCLUDE
+ * Recognize system V like include directives [include "filename"]
+ * SYSVVARSUB
+ * Recognize system V like ${VAR:x=y} variable substitutions
+ */
+#define SYSVINCLUDE
+#define SYSVVARSUB
+
+/*
+ * SUNSHCMD
+ * Recognize SunOS and Solaris:
+ * VAR :sh= CMD # Assign VAR to the command substitution of CMD
+ * ${VAR:sh} # Return the command substitution of the value
+ * # of ${VAR}
+ */
+#define SUNSHCMD
+
+#if !defined(__svr4__) && !defined(__SVR4)
+# ifndef RANLIBMAG
+# define RANLIBMAG "__.SYMDEF"
+# endif
+#endif
diff --git a/usr.bin/make/dir.c b/usr.bin/make/dir.c
new file mode 100644
index 0000000..9fcf94f
--- /dev/null
+++ b/usr.bin/make/dir.c
@@ -0,0 +1,1276 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
+#endif /* not lint */
+
+/*-
+ * dir.c --
+ * Directory searching using wildcards and/or normal names...
+ * Used both for source wildcarding in the Makefile and for finding
+ * implicit sources.
+ *
+ * The interface for this module is:
+ * Dir_Init Initialize the module.
+ *
+ * Dir_End Cleanup the module.
+ *
+ * Dir_HasWildcards Returns TRUE if the name given it needs to
+ * be wildcard-expanded.
+ *
+ * Dir_Expand Given a pattern and a path, return a Lst of names
+ * which match the pattern on the search path.
+ *
+ * Dir_FindFile Searches for a file on a given search path.
+ * If it exists, the entire path is returned.
+ * Otherwise NULL is returned.
+ *
+ * Dir_MTime Return the modification time of a node. The file
+ * is searched for along the default search path.
+ * The path and mtime fields of the node are filled
+ * in.
+ *
+ * Dir_AddDir Add a directory to a search path.
+ *
+ * Dir_MakeFlags Given a search path and a command flag, create
+ * a string with each of the directories in the path
+ * preceded by the command flag and all of them
+ * separated by a space.
+ *
+ * Dir_Destroy Destroy an element of a search path. Frees up all
+ * things that can be freed for the element as long
+ * as the element is no longer referenced by any other
+ * search path.
+ * Dir_ClearPath Resets a search path to the empty list.
+ *
+ * For debugging:
+ * Dir_PrintDirectories Print stats about the directory cache.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+
+/*
+ * A search path consists of a Lst of Path structures. A Path structure
+ * has in it the name of the directory and a hash table of all the files
+ * in the directory. This is used to cut down on the number of system
+ * calls necessary to find implicit dependents and their like. Since
+ * these searches are made before any actions are taken, we need not
+ * worry about the directory changing due to creation commands. If this
+ * hampers the style of some makefiles, they must be changed.
+ *
+ * A list of all previously-read directories is kept in the
+ * openDirectories Lst. This list is checked first before a directory
+ * is opened.
+ *
+ * The need for the caching of whole directories is brought about by
+ * the multi-level transformation code in suff.c, which tends to search
+ * for far more files than regular make does. In the initial
+ * implementation, the amount of time spent performing "stat" calls was
+ * truly astronomical. The problem with hashing at the start is,
+ * of course, that pmake doesn't then detect changes to these directories
+ * during the course of the make. Three possibilities suggest themselves:
+ *
+ * 1) just use stat to test for a file's existence. As mentioned
+ * above, this is very inefficient due to the number of checks
+ * engendered by the multi-level transformation code.
+ * 2) use readdir() and company to search the directories, keeping
+ * them open between checks. I have tried this and while it
+ * didn't slow down the process too much, it could severely
+ * affect the amount of parallelism available as each directory
+ * open would take another file descriptor out of play for
+ * handling I/O for another job. Given that it is only recently
+ * that UNIX OS's have taken to allowing more than 20 or 32
+ * file descriptors for a process, this doesn't seem acceptable
+ * to me.
+ * 3) record the mtime of the directory in the Path structure and
+ * verify the directory hasn't changed since the contents were
+ * hashed. This will catch the creation or deletion of files,
+ * but not the updating of files. However, since it is the
+ * creation and deletion that is the problem, this could be
+ * a good thing to do. Unfortunately, if the directory (say ".")
+ * were fairly large and changed fairly frequently, the constant
+ * rehashing could seriously degrade performance. It might be
+ * good in such cases to keep track of the number of rehashes
+ * and if the number goes over a (small) limit, resort to using
+ * stat in its place.
+ *
+ * An additional thing to consider is that pmake is used primarily
+ * to create C programs and until recently pcc-based compilers refused
+ * to allow you to specify where the resulting object file should be
+ * placed. This forced all objects to be created in the current
+ * directory. This isn't meant as a full excuse, just an explanation of
+ * some of the reasons for the caching used here.
+ *
+ * One more note: the location of a target's file is only performed
+ * on the downward traversal of the graph and then only for terminal
+ * nodes in the graph. This could be construed as wrong in some cases,
+ * but prevents inadvertent modification of files when the "installed"
+ * directory for a file is provided in the search path.
+ *
+ * Another data structure maintained by this module is an mtime
+ * cache used when the searching of cached directories fails to find
+ * a file. In the past, Dir_FindFile would simply perform an access()
+ * call in such a case to determine if the file could be found using
+ * just the name given. When this hit, however, all that was gained
+ * was the knowledge that the file existed. Given that an access() is
+ * essentially a stat() without the copyout() call, and that the same
+ * filesystem overhead would have to be incurred in Dir_MTime, it made
+ * sense to replace the access() with a stat() and record the mtime
+ * in a cache for when Dir_MTime was actually called.
+ */
+
+Lst dirSearchPath; /* main search path */
+
+static Lst openDirectories; /* the list of all open directories */
+
+/*
+ * Variables for gathering statistics on the efficiency of the hashing
+ * mechanism.
+ */
+static int hits, /* Found in directory cache */
+ misses, /* Sad, but not evil misses */
+ nearmisses, /* Found under search path */
+ bigmisses; /* Sought by itself */
+
+static Path *dot; /* contents of current directory */
+static Hash_Table mtimes; /* Results of doing a last-resort stat in
+ * Dir_FindFile -- if we have to go to the
+ * system to find the file, we might as well
+ * have its mtime on record. XXX: If this is done
+ * way early, there's a chance other rules will
+ * have already updated the file, in which case
+ * we'll update it again. Generally, there won't
+ * be two rules to update a single file, so this
+ * should be ok, but... */
+
+
+static int DirFindName __P((ClientData, ClientData));
+static int DirMatchFiles __P((char *, Path *, Lst));
+static void DirExpandCurly __P((char *, char *, Lst, Lst));
+static void DirExpandInt __P((char *, Lst, Lst));
+static int DirPrintWord __P((ClientData, ClientData));
+static int DirPrintDir __P((ClientData, ClientData));
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_Init --
+ * initialize things for this module
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * some directories may be opened.
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_Init ()
+{
+ dirSearchPath = Lst_Init (FALSE);
+ openDirectories = Lst_Init (FALSE);
+ Hash_InitTable(&mtimes, 0);
+
+ /*
+ * Since the Path structure is placed on both openDirectories and
+ * the path we give Dir_AddDir (which in this case is openDirectories),
+ * we need to remove "." from openDirectories and what better time to
+ * do it than when we have to fetch the thing anyway?
+ */
+ Dir_AddDir (openDirectories, ".");
+ dot = (Path *) Lst_DeQueue (openDirectories);
+
+ /*
+ * We always need to have dot around, so we increment its reference count
+ * to make sure it's not destroyed.
+ */
+ dot->refCount += 1;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_End --
+ * cleanup things for this module
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * none
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_End()
+{
+ dot->refCount -= 1;
+ Dir_Destroy((ClientData) dot);
+ Dir_ClearPath(dirSearchPath);
+ Lst_Destroy(dirSearchPath, NOFREE);
+ Dir_ClearPath(openDirectories);
+ Lst_Destroy(openDirectories, NOFREE);
+ Hash_DeleteTable(&mtimes);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * DirFindName --
+ * See if the Path structure describes the same directory as the
+ * given one by comparing their names. Called from Dir_AddDir via
+ * Lst_Find when searching the list of open directories.
+ *
+ * Results:
+ * 0 if it is the same. Non-zero otherwise
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static int
+DirFindName (p, dname)
+ ClientData p; /* Current name */
+ ClientData dname; /* Desired name */
+{
+ return (strcmp (((Path *)p)->name, (char *) dname));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_HasWildcards --
+ * see if the given name has any wildcard characters in it
+ *
+ * Results:
+ * returns TRUE if the word should be expanded, FALSE otherwise
+ *
+ * Side Effects:
+ * none
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Dir_HasWildcards (name)
+ char *name; /* name to check */
+{
+ register char *cp;
+
+ for (cp = name; *cp; cp++) {
+ switch(*cp) {
+ case '{':
+ case '[':
+ case '?':
+ case '*':
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * DirMatchFiles --
+ * Given a pattern and a Path structure, see if any files
+ * match the pattern and add their names to the 'expansions' list if
+ * any do. This is incomplete -- it doesn't take care of patterns like
+ * src / *src / *.c properly (just *.c on any of the directories), but it
+ * will do for now.
+ *
+ * Results:
+ * Always returns 0
+ *
+ * Side Effects:
+ * File names are added to the expansions lst. The directory will be
+ * fully hashed when this is done.
+ *-----------------------------------------------------------------------
+ */
+static int
+DirMatchFiles (pattern, p, expansions)
+ char *pattern; /* Pattern to look for */
+ Path *p; /* Directory to search */
+ Lst expansions; /* Place to store the results */
+{
+ Hash_Search search; /* Index into the directory's table */
+ Hash_Entry *entry; /* Current entry in the table */
+ Boolean isDot; /* TRUE if the directory being searched is . */
+
+ isDot = (*p->name == '.' && p->name[1] == '\0');
+
+ for (entry = Hash_EnumFirst(&p->files, &search);
+ entry != (Hash_Entry *)NULL;
+ entry = Hash_EnumNext(&search))
+ {
+ /*
+ * See if the file matches the given pattern. Note we follow the UNIX
+ * convention that dot files will only be found if the pattern
+ * begins with a dot (note also that as a side effect of the hashing
+ * scheme, .* won't match . or .. since they aren't hashed).
+ */
+ if (Str_Match(entry->name, pattern) &&
+ ((entry->name[0] != '.') ||
+ (pattern[0] == '.')))
+ {
+ (void)Lst_AtEnd(expansions,
+ (isDot ? estrdup(entry->name) :
+ str_concat(p->name, entry->name,
+ STR_ADDSLASH)));
+ }
+ }
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * DirExpandCurly --
+ * Expand curly braces like the C shell. Does this recursively.
+ * Note the special case: if after the piece of the curly brace is
+ * done there are no wildcard characters in the result, the result is
+ * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The given list is filled with the expansions...
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+DirExpandCurly(word, brace, path, expansions)
+ char *word; /* Entire word to expand */
+ char *brace; /* First curly brace in it */
+ Lst path; /* Search path to use */
+ Lst expansions; /* Place to store the expansions */
+{
+ char *end; /* Character after the closing brace */
+ char *cp; /* Current position in brace clause */
+ char *start; /* Start of current piece of brace clause */
+ int bracelevel; /* Number of braces we've seen. If we see a
+ * right brace when this is 0, we've hit the
+ * end of the clause. */
+ char *file; /* Current expansion */
+ int otherLen; /* The length of the other pieces of the
+ * expansion (chars before and after the
+ * clause in 'word') */
+ char *cp2; /* Pointer for checking for wildcards in
+ * expansion before calling Dir_Expand */
+
+ start = brace+1;
+
+ /*
+ * Find the end of the brace clause first, being wary of nested brace
+ * clauses.
+ */
+ for (end = start, bracelevel = 0; *end != '\0'; end++) {
+ if (*end == '{') {
+ bracelevel++;
+ } else if ((*end == '}') && (bracelevel-- == 0)) {
+ break;
+ }
+ }
+ if (*end == '\0') {
+ Error("Unterminated {} clause \"%s\"", start);
+ return;
+ } else {
+ end++;
+ }
+ otherLen = brace - word + strlen(end);
+
+ for (cp = start; cp < end; cp++) {
+ /*
+ * Find the end of this piece of the clause.
+ */
+ bracelevel = 0;
+ while (*cp != ',') {
+ if (*cp == '{') {
+ bracelevel++;
+ } else if ((*cp == '}') && (bracelevel-- <= 0)) {
+ break;
+ }
+ cp++;
+ }
+ /*
+ * Allocate room for the combination and install the three pieces.
+ */
+ file = emalloc(otherLen + cp - start + 1);
+ if (brace != word) {
+ strncpy(file, word, brace-word);
+ }
+ if (cp != start) {
+ strncpy(&file[brace-word], start, cp-start);
+ }
+ strcpy(&file[(brace-word)+(cp-start)], end);
+
+ /*
+ * See if the result has any wildcards in it. If we find one, call
+ * Dir_Expand right away, telling it to place the result on our list
+ * of expansions.
+ */
+ for (cp2 = file; *cp2 != '\0'; cp2++) {
+ switch(*cp2) {
+ case '*':
+ case '?':
+ case '{':
+ case '[':
+ Dir_Expand(file, path, expansions);
+ goto next;
+ }
+ }
+ if (*cp2 == '\0') {
+ /*
+ * Hit the end w/o finding any wildcards, so stick the expansion
+ * on the end of the list.
+ */
+ (void)Lst_AtEnd(expansions, file);
+ } else {
+ next:
+ free(file);
+ }
+ start = cp+1;
+ }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * DirExpandInt --
+ * Internal expand routine. Passes through the directories in the
+ * path one by one, calling DirMatchFiles for each. NOTE: This still
+ * doesn't handle patterns in directories...
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Things are added to the expansions list.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+DirExpandInt(word, path, expansions)
+ char *word; /* Word to expand */
+ Lst path; /* Path on which to look */
+ Lst expansions; /* Place to store the result */
+{
+ LstNode ln; /* Current node */
+ Path *p; /* Directory in the node */
+
+ if (Lst_Open(path) == SUCCESS) {
+ while ((ln = Lst_Next(path)) != NILLNODE) {
+ p = (Path *)Lst_Datum(ln);
+ DirMatchFiles(word, p, expansions);
+ }
+ Lst_Close(path);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * DirPrintWord --
+ * Print a word in the list of expansions. Callback for Dir_Expand
+ * when DEBUG(DIR), via Lst_ForEach.
+ *
+ * Results:
+ * === 0
+ *
+ * Side Effects:
+ * The passed word is printed, followed by a space.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+DirPrintWord(word, dummy)
+ ClientData word;
+ ClientData dummy;
+{
+ printf("%s ", (char *) word);
+
+ return(dummy ? 0 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_Expand --
+ * Expand the given word into a list of words by globbing it looking
+ * in the directories on the given search path.
+ *
+ * Results:
+ * A list of words consisting of the files which exist along the search
+ * path matching the given pattern.
+ *
+ * Side Effects:
+ * Directories may be opened. Who knows?
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_Expand (word, path, expansions)
+ char *word; /* the word to expand */
+ Lst path; /* the list of directories in which to find
+ * the resulting files */
+ Lst expansions; /* the list on which to place the results */
+{
+ char *cp;
+
+ if (DEBUG(DIR)) {
+ printf("expanding \"%s\"...", word);
+ }
+
+ cp = strchr(word, '{');
+ if (cp) {
+ DirExpandCurly(word, cp, path, expansions);
+ } else {
+ cp = strchr(word, '/');
+ if (cp) {
+ /*
+ * The thing has a directory component -- find the first wildcard
+ * in the string.
+ */
+ for (cp = word; *cp; cp++) {
+ if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
+ break;
+ }
+ }
+ if (*cp == '{') {
+ /*
+ * This one will be fun.
+ */
+ DirExpandCurly(word, cp, path, expansions);
+ return;
+ } else if (*cp != '\0') {
+ /*
+ * Back up to the start of the component
+ */
+ char *dirpath;
+
+ while (cp > word && *cp != '/') {
+ cp--;
+ }
+ if (cp != word) {
+ char sc;
+ /*
+ * If the glob isn't in the first component, try and find
+ * all the components up to the one with a wildcard.
+ */
+ sc = cp[1];
+ cp[1] = '\0';
+ dirpath = Dir_FindFile(word, path);
+ cp[1] = sc;
+ /*
+ * dirpath is null if can't find the leading component
+ * XXX: Dir_FindFile won't find internal components.
+ * i.e. if the path contains ../Etc/Object and we're
+ * looking for Etc, it won't be found. Ah well.
+ * Probably not important.
+ */
+ if (dirpath != (char *)NULL) {
+ char *dp = &dirpath[strlen(dirpath) - 1];
+ if (*dp == '/')
+ *dp = '\0';
+ path = Lst_Init(FALSE);
+ Dir_AddDir(path, dirpath);
+ DirExpandInt(cp+1, path, expansions);
+ Lst_Destroy(path, NOFREE);
+ }
+ } else {
+ /*
+ * Start the search from the local directory
+ */
+ DirExpandInt(word, path, expansions);
+ }
+ } else {
+ /*
+ * Return the file -- this should never happen.
+ */
+ DirExpandInt(word, path, expansions);
+ }
+ } else {
+ /*
+ * First the files in dot
+ */
+ DirMatchFiles(word, dot, expansions);
+
+ /*
+ * Then the files in every other directory on the path.
+ */
+ DirExpandInt(word, path, expansions);
+ }
+ }
+ if (DEBUG(DIR)) {
+ Lst_ForEach(expansions, DirPrintWord, (ClientData) 0);
+ fputc('\n', stdout);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_FindFile --
+ * Find the file with the given name along the given search path.
+ *
+ * Results:
+ * The path to the file or NULL. This path is guaranteed to be in a
+ * different part of memory than name and so may be safely free'd.
+ *
+ * Side Effects:
+ * If the file is found in a directory which is not on the path
+ * already (either 'name' is absolute or it is a relative path
+ * [ dir1/.../dirn/file ] which exists below one of the directories
+ * already on the search path), its directory is added to the end
+ * of the path on the assumption that there will be more files in
+ * that directory later on. Sometimes this is true. Sometimes not.
+ *-----------------------------------------------------------------------
+ */
+char *
+Dir_FindFile (name, path)
+ char *name; /* the file to find */
+ Lst path; /* the Lst of directories to search */
+{
+ register char *p1; /* pointer into p->name */
+ register char *p2; /* pointer into name */
+ LstNode ln; /* a list element */
+ register char *file; /* the current filename to check */
+ register Path *p; /* current path member */
+ register char *cp; /* index of first slash, if any */
+ Boolean hasSlash; /* true if 'name' contains a / */
+ struct stat stb; /* Buffer for stat, if necessary */
+ Hash_Entry *entry; /* Entry for mtimes table */
+
+ /*
+ * Find the final component of the name and note whether it has a
+ * slash in it (the name, I mean)
+ */
+ cp = strrchr (name, '/');
+ if (cp) {
+ hasSlash = TRUE;
+ cp += 1;
+ } else {
+ hasSlash = FALSE;
+ cp = name;
+ }
+
+ if (DEBUG(DIR)) {
+ printf("Searching for %s...", name);
+ }
+ /*
+ * No matter what, we always look for the file in the current directory
+ * before anywhere else and we *do not* add the ./ to it if it exists.
+ * This is so there are no conflicts between what the user specifies
+ * (fish.c) and what pmake finds (./fish.c).
+ */
+ if ((!hasSlash || (cp - name == 2 && *name == '.')) &&
+ (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) {
+ if (DEBUG(DIR)) {
+ printf("in '.'\n");
+ }
+ hits += 1;
+ dot->hits += 1;
+ return (estrdup (name));
+ }
+
+ if (Lst_Open (path) == FAILURE) {
+ if (DEBUG(DIR)) {
+ printf("couldn't open path, file not found\n");
+ }
+ misses += 1;
+ return ((char *) NULL);
+ }
+
+ /*
+ * We look through all the directories on the path seeking one which
+ * contains the final component of the given name and whose final
+ * component(s) match the name's initial component(s). If such a beast
+ * is found, we concatenate the directory name and the final component
+ * and return the resulting string. If we don't find any such thing,
+ * we go on to phase two...
+ */
+ while ((ln = Lst_Next (path)) != NILLNODE) {
+ p = (Path *) Lst_Datum (ln);
+ if (DEBUG(DIR)) {
+ printf("%s...", p->name);
+ }
+ if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
+ if (DEBUG(DIR)) {
+ printf("here...");
+ }
+ if (hasSlash) {
+ /*
+ * If the name had a slash, its initial components and p's
+ * final components must match. This is false if a mismatch
+ * is encountered before all of the initial components
+ * have been checked (p2 > name at the end of the loop), or
+ * we matched only part of one of the components of p
+ * along with all the rest of them (*p1 != '/').
+ */
+ p1 = p->name + strlen (p->name) - 1;
+ p2 = cp - 2;
+ while (p2 >= name && p1 >= p->name && *p1 == *p2) {
+ p1 -= 1; p2 -= 1;
+ }
+ if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
+ if (DEBUG(DIR)) {
+ printf("component mismatch -- continuing...");
+ }
+ continue;
+ }
+ }
+ file = str_concat (p->name, cp, STR_ADDSLASH);
+ if (DEBUG(DIR)) {
+ printf("returning %s\n", file);
+ }
+ Lst_Close (path);
+ p->hits += 1;
+ hits += 1;
+ return (file);
+ } else if (hasSlash) {
+ /*
+ * If the file has a leading path component and that component
+ * exactly matches the entire name of the current search
+ * directory, we assume the file doesn't exist and return NULL.
+ */
+ for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
+ continue;
+ }
+ if (*p1 == '\0' && p2 == cp - 1) {
+ if (DEBUG(DIR)) {
+ printf("must be here but isn't -- returing NULL\n");
+ }
+ Lst_Close (path);
+ return ((char *) NULL);
+ }
+ }
+ }
+
+ /*
+ * We didn't find the file on any existing members of the directory.
+ * If the name doesn't contain a slash, that means it doesn't exist.
+ * If it *does* contain a slash, however, there is still hope: it
+ * could be in a subdirectory of one of the members of the search
+ * path. (eg. /usr/include and sys/types.h. The above search would
+ * fail to turn up types.h in /usr/include, but it *is* in
+ * /usr/include/sys/types.h) If we find such a beast, we assume there
+ * will be more (what else can we assume?) and add all but the last
+ * component of the resulting name onto the search path (at the
+ * end). This phase is only performed if the file is *not* absolute.
+ */
+ if (!hasSlash) {
+ if (DEBUG(DIR)) {
+ printf("failed.\n");
+ }
+ misses += 1;
+ return ((char *) NULL);
+ }
+
+ if (*name != '/') {
+ Boolean checkedDot = FALSE;
+
+ if (DEBUG(DIR)) {
+ printf("failed. Trying subdirectories...");
+ }
+ (void) Lst_Open (path);
+ while ((ln = Lst_Next (path)) != NILLNODE) {
+ p = (Path *) Lst_Datum (ln);
+ if (p != dot) {
+ file = str_concat (p->name, name, STR_ADDSLASH);
+ } else {
+ /*
+ * Checking in dot -- DON'T put a leading ./ on the thing.
+ */
+ file = estrdup(name);
+ checkedDot = TRUE;
+ }
+ if (DEBUG(DIR)) {
+ printf("checking %s...", file);
+ }
+
+
+ if (stat (file, &stb) == 0) {
+ if (DEBUG(DIR)) {
+ printf("got it.\n");
+ }
+
+ Lst_Close (path);
+
+ /*
+ * We've found another directory to search. We know there's
+ * a slash in 'file' because we put one there. We nuke it after
+ * finding it and call Dir_AddDir to add this new directory
+ * onto the existing search path. Once that's done, we restore
+ * the slash and triumphantly return the file name, knowing
+ * that should a file in this directory every be referenced
+ * again in such a manner, we will find it without having to do
+ * numerous numbers of access calls. Hurrah!
+ */
+ cp = strrchr (file, '/');
+ *cp = '\0';
+ Dir_AddDir (path, file);
+ *cp = '/';
+
+ /*
+ * Save the modification time so if it's needed, we don't have
+ * to fetch it again.
+ */
+ if (DEBUG(DIR)) {
+ printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
+ file);
+ }
+ entry = Hash_CreateEntry(&mtimes, (char *) file,
+ (Boolean *)NULL);
+ Hash_SetValue(entry, (long)stb.st_mtime);
+ nearmisses += 1;
+ return (file);
+ } else {
+ free (file);
+ }
+ }
+
+ if (DEBUG(DIR)) {
+ printf("failed. ");
+ }
+ Lst_Close (path);
+
+ if (checkedDot) {
+ /*
+ * Already checked by the given name, since . was in the path,
+ * so no point in proceeding...
+ */
+ if (DEBUG(DIR)) {
+ printf("Checked . already, returning NULL\n");
+ }
+ return(NULL);
+ }
+ }
+
+ /*
+ * Didn't find it that way, either. Sigh. Phase 3. Add its directory
+ * onto the search path in any case, just in case, then look for the
+ * thing in the hash table. If we find it, grand. We return a new
+ * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
+ * Note that if the directory holding the file doesn't exist, this will
+ * do an extra search of the final directory on the path. Unless something
+ * weird happens, this search won't succeed and life will be groovy.
+ *
+ * Sigh. We cannot add the directory onto the search path because
+ * of this amusing case:
+ * $(INSTALLDIR)/$(FILE): $(FILE)
+ *
+ * $(FILE) exists in $(INSTALLDIR) but not in the current one.
+ * When searching for $(FILE), we will find it in $(INSTALLDIR)
+ * b/c we added it here. This is not good...
+ */
+#ifdef notdef
+ cp[-1] = '\0';
+ Dir_AddDir (path, name);
+ cp[-1] = '/';
+
+ bigmisses += 1;
+ ln = Lst_Last (path);
+ if (ln == NILLNODE) {
+ return ((char *) NULL);
+ } else {
+ p = (Path *) Lst_Datum (ln);
+ }
+
+ if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
+ return (estrdup (name));
+ } else {
+ return ((char *) NULL);
+ }
+#else /* !notdef */
+ if (DEBUG(DIR)) {
+ printf("Looking for \"%s\"...", name);
+ }
+
+ bigmisses += 1;
+ entry = Hash_FindEntry(&mtimes, name);
+ if (entry != (Hash_Entry *)NULL) {
+ if (DEBUG(DIR)) {
+ printf("got it (in mtime cache)\n");
+ }
+ return(estrdup(name));
+ } else if (stat (name, &stb) == 0) {
+ entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
+ if (DEBUG(DIR)) {
+ printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
+ name);
+ }
+ Hash_SetValue(entry, (long)stb.st_mtime);
+ return (estrdup (name));
+ } else {
+ if (DEBUG(DIR)) {
+ printf("failed. Returning NULL\n");
+ }
+ return ((char *)NULL);
+ }
+#endif /* notdef */
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_MTime --
+ * Find the modification time of the file described by gn along the
+ * search path dirSearchPath.
+ *
+ * Results:
+ * The modification time or 0 if it doesn't exist
+ *
+ * Side Effects:
+ * The modification time is placed in the node's mtime slot.
+ * If the node didn't have a path entry before, and Dir_FindFile
+ * found one for it, the full name is placed in the path slot.
+ *-----------------------------------------------------------------------
+ */
+int
+Dir_MTime (gn)
+ GNode *gn; /* the file whose modification time is
+ * desired */
+{
+ char *fullName; /* the full pathname of name */
+ struct stat stb; /* buffer for finding the mod time */
+ Hash_Entry *entry;
+
+ if (gn->type & OP_ARCHV) {
+ return Arch_MTime (gn);
+ } else if (gn->path == (char *)NULL) {
+ fullName = Dir_FindFile (gn->name, dirSearchPath);
+ } else {
+ fullName = gn->path;
+ }
+
+ if (fullName == (char *)NULL) {
+ fullName = estrdup(gn->name);
+ }
+
+ entry = Hash_FindEntry(&mtimes, fullName);
+ if (entry != (Hash_Entry *)NULL) {
+ /*
+ * Only do this once -- the second time folks are checking to
+ * see if the file was actually updated, so we need to actually go
+ * to the file system.
+ */
+ if (DEBUG(DIR)) {
+ printf("Using cached time %s for %s\n",
+ Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName);
+ }
+ stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
+ Hash_DeleteEntry(&mtimes, entry);
+ } else if (stat (fullName, &stb) < 0) {
+ if (gn->type & OP_MEMBER) {
+ if (fullName != gn->path)
+ free(fullName);
+ return Arch_MemMTime (gn);
+ } else {
+ stb.st_mtime = 0;
+ }
+ }
+ if (fullName && gn->path == (char *)NULL) {
+ gn->path = fullName;
+ }
+
+ gn->mtime = stb.st_mtime;
+ return (gn->mtime);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_AddDir --
+ * Add the given name to the end of the given path. The order of
+ * the arguments is backwards so ParseDoDependency can do a
+ * Lst_ForEach of its list of paths...
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * A structure is added to the list and the directory is
+ * read and hashed.
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_AddDir (path, name)
+ Lst path; /* the path to which the directory should be
+ * added */
+ char *name; /* the name of the directory to add */
+{
+ LstNode ln; /* node in case Path structure is found */
+ register Path *p; /* pointer to new Path structure */
+ DIR *d; /* for reading directory */
+ register struct dirent *dp; /* entry in directory */
+
+ ln = Lst_Find (openDirectories, (ClientData)name, DirFindName);
+ if (ln != NILLNODE) {
+ p = (Path *)Lst_Datum (ln);
+ if (Lst_Member(path, (ClientData)p) == NILLNODE) {
+ p->refCount += 1;
+ (void)Lst_AtEnd (path, (ClientData)p);
+ }
+ } else {
+ if (DEBUG(DIR)) {
+ printf("Caching %s...", name);
+ fflush(stdout);
+ }
+
+ if ((d = opendir (name)) != (DIR *) NULL) {
+ p = (Path *) emalloc (sizeof (Path));
+ p->name = estrdup (name);
+ p->hits = 0;
+ p->refCount = 1;
+ Hash_InitTable (&p->files, -1);
+
+ /*
+ * Skip the first two entries -- these will *always* be . and ..
+ */
+ (void)readdir(d);
+ (void)readdir(d);
+
+ while ((dp = readdir (d)) != (struct dirent *) NULL) {
+#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
+ /*
+ * The sun directory library doesn't check for a 0 inode
+ * (0-inode slots just take up space), so we have to do
+ * it ourselves.
+ */
+ if (dp->d_fileno == 0) {
+ continue;
+ }
+#endif /* sun && d_ino */
+ (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);
+ }
+ (void) closedir (d);
+ (void)Lst_AtEnd (openDirectories, (ClientData)p);
+ (void)Lst_AtEnd (path, (ClientData)p);
+ }
+ if (DEBUG(DIR)) {
+ printf("done\n");
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_CopyDir --
+ * Callback function for duplicating a search path via Lst_Duplicate.
+ * Ups the reference count for the directory.
+ *
+ * Results:
+ * Returns the Path it was given.
+ *
+ * Side Effects:
+ * The refCount of the path is incremented.
+ *
+ *-----------------------------------------------------------------------
+ */
+ClientData
+Dir_CopyDir(p)
+ ClientData p;
+{
+ ((Path *) p)->refCount += 1;
+
+ return ((ClientData)p);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_MakeFlags --
+ * Make a string by taking all the directories in the given search
+ * path and preceding them by the given flag. Used by the suffix
+ * module to create variables for compilers based on suffix search
+ * paths.
+ *
+ * Results:
+ * The string mentioned above. Note that there is no space between
+ * the given flag and each directory. The empty string is returned if
+ * Things don't go well.
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+char *
+Dir_MakeFlags (flag, path)
+ char *flag; /* flag which should precede each directory */
+ Lst path; /* list of directories */
+{
+ char *str; /* the string which will be returned */
+ char *tstr; /* the current directory preceded by 'flag' */
+ LstNode ln; /* the node of the current directory */
+ Path *p; /* the structure describing the current directory */
+
+ str = estrdup ("");
+
+ if (Lst_Open (path) == SUCCESS) {
+ while ((ln = Lst_Next (path)) != NILLNODE) {
+ p = (Path *) Lst_Datum (ln);
+ tstr = str_concat (flag, p->name, 0);
+ str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE);
+ }
+ Lst_Close (path);
+ }
+
+ return (str);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_Destroy --
+ * Nuke a directory descriptor, if possible. Callback procedure
+ * for the suffixes module when destroying a search path.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * If no other path references this directory (refCount == 0),
+ * the Path and all its data are freed.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_Destroy (pp)
+ ClientData pp; /* The directory descriptor to nuke */
+{
+ Path *p = (Path *) pp;
+ p->refCount -= 1;
+
+ if (p->refCount == 0) {
+ LstNode ln;
+
+ ln = Lst_Member (openDirectories, (ClientData)p);
+ (void) Lst_Remove (openDirectories, ln);
+
+ Hash_DeleteTable (&p->files);
+ free((Address)p->name);
+ free((Address)p);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_ClearPath --
+ * Clear out all elements of the given search path. This is different
+ * from destroying the list, notice.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The path is set to the empty list.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_ClearPath(path)
+ Lst path; /* Path to clear */
+{
+ Path *p;
+ while (!Lst_IsEmpty(path)) {
+ p = (Path *)Lst_DeQueue(path);
+ Dir_Destroy((ClientData) p);
+ }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Dir_Concat --
+ * Concatenate two paths, adding the second to the end of the first.
+ * Makes sure to avoid duplicates.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Reference counts for added dirs are upped.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Dir_Concat(path1, path2)
+ Lst path1; /* Dest */
+ Lst path2; /* Source */
+{
+ LstNode ln;
+ Path *p;
+
+ for (ln = Lst_First(path2); ln != NILLNODE; ln = Lst_Succ(ln)) {
+ p = (Path *)Lst_Datum(ln);
+ if (Lst_Member(path1, (ClientData)p) == NILLNODE) {
+ p->refCount += 1;
+ (void)Lst_AtEnd(path1, (ClientData)p);
+ }
+ }
+}
+
+/********** DEBUG INFO **********/
+void
+Dir_PrintDirectories()
+{
+ LstNode ln;
+ Path *p;
+
+ printf ("#*** Directory Cache:\n");
+ printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
+ hits, misses, nearmisses, bigmisses,
+ (hits+bigmisses+nearmisses ?
+ hits * 100 / (hits + bigmisses + nearmisses) : 0));
+ printf ("# %-20s referenced\thits\n", "directory");
+ if (Lst_Open (openDirectories) == SUCCESS) {
+ while ((ln = Lst_Next (openDirectories)) != NILLNODE) {
+ p = (Path *) Lst_Datum (ln);
+ printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
+ }
+ Lst_Close (openDirectories);
+ }
+}
+
+static int DirPrintDir (p, dummy)
+ ClientData p;
+ ClientData dummy;
+{
+ printf ("%s ", ((Path *) p)->name);
+ return (dummy ? 0 : 0);
+}
+
+void
+Dir_PrintPath (path)
+ Lst path;
+{
+ Lst_ForEach (path, DirPrintDir, (ClientData)0);
+}
diff --git a/usr.bin/make/dir.h b/usr.bin/make/dir.h
new file mode 100644
index 0000000..62687c5
--- /dev/null
+++ b/usr.bin/make/dir.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)dir.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/* dir.h --
+ */
+
+#ifndef _DIR
+#define _DIR
+
+typedef struct Path {
+ char *name; /* Name of directory */
+ int refCount; /* Number of paths with this directory */
+ int hits; /* the number of times a file in this
+ * directory has been found */
+ Hash_Table files; /* Hash table of files in directory */
+} Path;
+
+void Dir_Init __P((void));
+void Dir_End __P((void));
+Boolean Dir_HasWildcards __P((char *));
+void Dir_Expand __P((char *, Lst, Lst));
+char *Dir_FindFile __P((char *, Lst));
+int Dir_MTime __P((GNode *));
+void Dir_AddDir __P((Lst, char *));
+char *Dir_MakeFlags __P((char *, Lst));
+void Dir_ClearPath __P((Lst));
+void Dir_Concat __P((Lst, Lst));
+void Dir_PrintDirectories __P((void));
+void Dir_PrintPath __P((Lst));
+void Dir_Destroy __P((ClientData));
+ClientData Dir_CopyDir __P((ClientData));
+
+#endif /* _DIR */
diff --git a/usr.bin/make/for.c b/usr.bin/make/for.c
new file mode 100644
index 0000000..3d8617f
--- /dev/null
+++ b/usr.bin/make/for.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 1992, The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * for.c --
+ * Functions to handle loops in a makefile.
+ *
+ * Interface:
+ * For_Eval Evaluate the loop in the passed line.
+ * For_Run Run accumulated loop
+ *
+ */
+
+#include <ctype.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "buf.h"
+
+/*
+ * For statements are of the form:
+ *
+ * .for <variable> in <varlist>
+ * ...
+ * .endfor
+ *
+ * The trick is to look for the matching end inside for for loop
+ * To do that, we count the current nesting level of the for loops.
+ * and the .endfor statements, accumulating all the statements between
+ * the initial .for loop and the matching .endfor;
+ * then we evaluate the for loop for each variable in the varlist.
+ */
+
+static int forLevel = 0; /* Nesting level */
+static char *forVar; /* Iteration variable */
+static Buffer forBuf; /* Commands in loop */
+static Lst forLst; /* List of items */
+
+/*
+ * State of a for loop.
+ */
+typedef struct _For {
+ Buffer buf; /* Unexpanded buffer */
+ char* var; /* Index name */
+ Lst lst; /* List of variables */
+} For;
+
+static int ForExec __P((ClientData, ClientData));
+
+
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * For_Eval --
+ * Evaluate the for loop in the passed line. The line
+ * looks like this:
+ * .for <variable> in <varlist>
+ *
+ * Results:
+ * TRUE: We found a for loop, or we are inside a for loop
+ * FALSE: We did not find a for loop, or we found the end of the for
+ * for loop.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+For_Eval (line)
+ char *line; /* Line to parse */
+{
+ char *ptr = line, *sub, *wrd;
+ int level; /* Level at which to report errors. */
+
+ level = PARSE_FATAL;
+
+
+ if (forLevel == 0) {
+ Buffer buf;
+ int varlen;
+
+ for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
+ continue;
+ /*
+ * If we are not in a for loop quickly determine if the statement is
+ * a for.
+ */
+ if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
+ !isspace((unsigned char) ptr[3]))
+ return FALSE;
+ ptr += 3;
+
+ /*
+ * we found a for loop, and now we are going to parse it.
+ */
+ while (*ptr && isspace((unsigned char) *ptr))
+ ptr++;
+
+ /*
+ * Grab the variable
+ */
+ buf = Buf_Init(0);
+ for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++)
+ continue;
+ Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd);
+
+ forVar = (char *) Buf_GetAll(buf, &varlen);
+ if (varlen == 0) {
+ Parse_Error (level, "missing variable in for");
+ return 0;
+ }
+ Buf_Destroy(buf, FALSE);
+
+ while (*ptr && isspace((unsigned char) *ptr))
+ ptr++;
+
+ /*
+ * Grab the `in'
+ */
+ if (ptr[0] != 'i' || ptr[1] != 'n' ||
+ !isspace((unsigned char) ptr[2])) {
+ Parse_Error (level, "missing `in' in for");
+ printf("%s\n", ptr);
+ return 0;
+ }
+ ptr += 3;
+
+ while (*ptr && isspace((unsigned char) *ptr))
+ ptr++;
+
+ /*
+ * Make a list with the remaining words
+ */
+ forLst = Lst_Init(FALSE);
+ buf = Buf_Init(0);
+ sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
+
+#define ADDWORD() \
+ Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \
+ Buf_AddByte(buf, (Byte) '\0'), \
+ Lst_AtFront(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \
+ Buf_Destroy(buf, FALSE)
+
+ for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)
+ continue;
+
+ for (wrd = ptr; *ptr; ptr++)
+ if (isspace((unsigned char) *ptr)) {
+ ADDWORD();
+ buf = Buf_Init(0);
+ while (*ptr && isspace((unsigned char) *ptr))
+ ptr++;
+ wrd = ptr--;
+ }
+ if (DEBUG(FOR))
+ (void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub);
+ if (ptr - wrd > 0)
+ ADDWORD();
+ else
+ Buf_Destroy(buf, TRUE);
+ free((Address) sub);
+
+ forBuf = Buf_Init(0);
+ forLevel++;
+ return 1;
+ }
+ else if (*ptr == '.') {
+
+ for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
+ continue;
+
+ if (strncmp(ptr, "endfor", 6) == 0 &&
+ (isspace((unsigned char) ptr[6]) || !ptr[6])) {
+ if (DEBUG(FOR))
+ (void) fprintf(stderr, "For: end for %d\n", forLevel);
+ if (--forLevel < 0) {
+ Parse_Error (level, "for-less endfor");
+ return 0;
+ }
+ }
+ else if (strncmp(ptr, "for", 3) == 0 &&
+ isspace((unsigned char) ptr[3])) {
+ forLevel++;
+ if (DEBUG(FOR))
+ (void) fprintf(stderr, "For: new loop %d\n", forLevel);
+ }
+ }
+
+ if (forLevel != 0) {
+ Buf_AddBytes(forBuf, strlen(line), (Byte *) line);
+ Buf_AddByte(forBuf, (Byte) '\n');
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ForExec --
+ * Expand the for loop for this index and push it in the Makefile
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ForExec(namep, argp)
+ ClientData namep;
+ ClientData argp;
+{
+ char *name = (char *) namep;
+ For *arg = (For *) argp;
+ int len;
+ Var_Set(arg->var, name, VAR_GLOBAL);
+ if (DEBUG(FOR))
+ (void) fprintf(stderr, "--- %s = %s\n", arg->var, name);
+ Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len),
+ VAR_GLOBAL, FALSE));
+ Var_Delete(arg->var, VAR_GLOBAL);
+
+ return 0;
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * For_Run --
+ * Run the for loop, immitating the actions of an include file
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+For_Run()
+{
+ For arg;
+
+ if (forVar == NULL || forBuf == NULL || forLst == NULL)
+ return;
+ arg.var = forVar;
+ arg.buf = forBuf;
+ arg.lst = forLst;
+ forVar = NULL;
+ forBuf = NULL;
+ forLst = NULL;
+
+ Lst_ForEach(arg.lst, ForExec, (ClientData) &arg);
+
+ free((Address)arg.var);
+ Lst_Destroy(arg.lst, (void (*) __P((ClientData))) free);
+ Buf_Destroy(arg.buf, TRUE);
+}
diff --git a/usr.bin/make/hash.c b/usr.bin/make/hash.c
new file mode 100644
index 0000000..a8250a4
--- /dev/null
+++ b/usr.bin/make/hash.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/* hash.c --
+ *
+ * This module contains routines to manipulate a hash table.
+ * See hash.h for a definition of the structure of the hash
+ * table. Hash tables grow automatically as the amount of
+ * information increases.
+ */
+#include "sprite.h"
+#include "make.h"
+#include "hash.h"
+
+/*
+ * Forward references to local procedures that are used before they're
+ * defined:
+ */
+
+static void RebuildTable __P((Hash_Table *));
+
+/*
+ * The following defines the ratio of # entries to # buckets
+ * at which we rebuild the table to make it larger.
+ */
+
+#define rebuildLimit 8
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_InitTable --
+ *
+ * This routine just sets up the hash table.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Memory is allocated for the initial bucket area.
+ *
+ *---------------------------------------------------------
+ */
+
+void
+Hash_InitTable(t, numBuckets)
+ register Hash_Table *t; /* Structure to use to hold table. */
+ int numBuckets; /* How many buckets to create for starters.
+ * This number is rounded up to a power of
+ * two. If <= 0, a reasonable default is
+ * chosen. The table will grow in size later
+ * as needed. */
+{
+ register int i;
+ register struct Hash_Entry **hp;
+
+ /*
+ * Round up the size to a power of two.
+ */
+ if (numBuckets <= 0)
+ i = 16;
+ else {
+ for (i = 2; i < numBuckets; i <<= 1)
+ continue;
+ }
+ t->numEntries = 0;
+ t->size = i;
+ t->mask = i - 1;
+ t->bucketPtr = hp = (struct Hash_Entry **)emalloc(sizeof(*hp) * i);
+ while (--i >= 0)
+ *hp++ = NULL;
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_DeleteTable --
+ *
+ * This routine removes everything from a hash table
+ * and frees up the memory space it occupied (except for
+ * the space in the Hash_Table structure).
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Lots of memory is freed up.
+ *
+ *---------------------------------------------------------
+ */
+
+void
+Hash_DeleteTable(t)
+ Hash_Table *t;
+{
+ register struct Hash_Entry **hp, *h, *nexth = NULL;
+ register int i;
+
+ for (hp = t->bucketPtr, i = t->size; --i >= 0;) {
+ for (h = *hp++; h != NULL; h = nexth) {
+ nexth = h->next;
+ free((char *)h);
+ }
+ }
+ free((char *)t->bucketPtr);
+
+ /*
+ * Set up the hash table to cause memory faults on any future access
+ * attempts until re-initialization.
+ */
+ t->bucketPtr = NULL;
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_FindEntry --
+ *
+ * Searches a hash table for an entry corresponding to key.
+ *
+ * Results:
+ * The return value is a pointer to the entry for key,
+ * if key was present in the table. If key was not
+ * present, NULL is returned.
+ *
+ * Side Effects:
+ * None.
+ *
+ *---------------------------------------------------------
+ */
+
+Hash_Entry *
+Hash_FindEntry(t, key)
+ Hash_Table *t; /* Hash table to search. */
+ char *key; /* A hash key. */
+{
+ register Hash_Entry *e;
+ register unsigned h;
+ register char *p;
+
+ for (h = 0, p = key; *p;)
+ h = (h << 5) - h + *p++;
+ p = key;
+ for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next)
+ if (e->namehash == h && strcmp(e->name, p) == 0)
+ return (e);
+ return (NULL);
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_CreateEntry --
+ *
+ * Searches a hash table for an entry corresponding to
+ * key. If no entry is found, then one is created.
+ *
+ * Results:
+ * The return value is a pointer to the entry. If *newPtr
+ * isn't NULL, then *newPtr is filled in with TRUE if a
+ * new entry was created, and FALSE if an entry already existed
+ * with the given key.
+ *
+ * Side Effects:
+ * Memory may be allocated, and the hash buckets may be modified.
+ *---------------------------------------------------------
+ */
+
+Hash_Entry *
+Hash_CreateEntry(t, key, newPtr)
+ register Hash_Table *t; /* Hash table to search. */
+ char *key; /* A hash key. */
+ Boolean *newPtr; /* Filled in with TRUE if new entry created,
+ * FALSE otherwise. */
+{
+ register Hash_Entry *e;
+ register unsigned h;
+ register char *p;
+ int keylen;
+ struct Hash_Entry **hp;
+
+ /*
+ * Hash the key. As a side effect, save the length (strlen) of the
+ * key in case we need to create the entry.
+ */
+ for (h = 0, p = key; *p;)
+ h = (h << 5) - h + *p++;
+ keylen = p - key;
+ p = key;
+ for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) {
+ if (e->namehash == h && strcmp(e->name, p) == 0) {
+ if (newPtr != NULL)
+ *newPtr = FALSE;
+ return (e);
+ }
+ }
+
+ /*
+ * The desired entry isn't there. Before allocating a new entry,
+ * expand the table if necessary (and this changes the resulting
+ * bucket chain).
+ */
+ if (t->numEntries >= rebuildLimit * t->size)
+ RebuildTable(t);
+ e = (Hash_Entry *) emalloc(sizeof(*e) + keylen);
+ hp = &t->bucketPtr[h & t->mask];
+ e->next = *hp;
+ *hp = e;
+ e->clientData = NULL;
+ e->namehash = h;
+ (void) strcpy(e->name, p);
+ t->numEntries++;
+
+ if (newPtr != NULL)
+ *newPtr = TRUE;
+ return (e);
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_DeleteEntry --
+ *
+ * Delete the given hash table entry and free memory associated with
+ * it.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Hash chain that entry lives in is modified and memory is freed.
+ *
+ *---------------------------------------------------------
+ */
+
+void
+Hash_DeleteEntry(t, e)
+ Hash_Table *t;
+ Hash_Entry *e;
+{
+ register Hash_Entry **hp, *p;
+
+ if (e == NULL)
+ return;
+ for (hp = &t->bucketPtr[e->namehash & t->mask];
+ (p = *hp) != NULL; hp = &p->next) {
+ if (p == e) {
+ *hp = p->next;
+ free((char *)p);
+ t->numEntries--;
+ return;
+ }
+ }
+ (void) write(2, "bad call to Hash_DeleteEntry\n", 29);
+ abort();
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_EnumFirst --
+ * This procedure sets things up for a complete search
+ * of all entries recorded in the hash table.
+ *
+ * Results:
+ * The return value is the address of the first entry in
+ * the hash table, or NULL if the table is empty.
+ *
+ * Side Effects:
+ * The information in searchPtr is initialized so that successive
+ * calls to Hash_Next will return successive HashEntry's
+ * from the table.
+ *
+ *---------------------------------------------------------
+ */
+
+Hash_Entry *
+Hash_EnumFirst(t, searchPtr)
+ Hash_Table *t; /* Table to be searched. */
+ register Hash_Search *searchPtr;/* Area in which to keep state
+ * about search.*/
+{
+ searchPtr->tablePtr = t;
+ searchPtr->nextIndex = 0;
+ searchPtr->hashEntryPtr = NULL;
+ return Hash_EnumNext(searchPtr);
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * Hash_EnumNext --
+ * This procedure returns successive entries in the hash table.
+ *
+ * Results:
+ * The return value is a pointer to the next HashEntry
+ * in the table, or NULL when the end of the table is
+ * reached.
+ *
+ * Side Effects:
+ * The information in searchPtr is modified to advance to the
+ * next entry.
+ *
+ *---------------------------------------------------------
+ */
+
+Hash_Entry *
+Hash_EnumNext(searchPtr)
+ register Hash_Search *searchPtr; /* Area used to keep state about
+ search. */
+{
+ register Hash_Entry *e;
+ Hash_Table *t = searchPtr->tablePtr;
+
+ /*
+ * The hashEntryPtr field points to the most recently returned
+ * entry, or is nil if we are starting up. If not nil, we have
+ * to start at the next one in the chain.
+ */
+ e = searchPtr->hashEntryPtr;
+ if (e != NULL)
+ e = e->next;
+ /*
+ * If the chain ran out, or if we are starting up, we need to
+ * find the next nonempty chain.
+ */
+ while (e == NULL) {
+ if (searchPtr->nextIndex >= t->size)
+ return (NULL);
+ e = t->bucketPtr[searchPtr->nextIndex++];
+ }
+ searchPtr->hashEntryPtr = e;
+ return (e);
+}
+
+/*
+ *---------------------------------------------------------
+ *
+ * RebuildTable --
+ * This local routine makes a new hash table that
+ * is larger than the old one.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The entire hash table is moved, so any bucket numbers
+ * from the old table are invalid.
+ *
+ *---------------------------------------------------------
+ */
+
+static void
+RebuildTable(t)
+ register Hash_Table *t;
+{
+ register Hash_Entry *e, *next = NULL, **hp, **xp;
+ register int i, mask;
+ register Hash_Entry **oldhp;
+ int oldsize;
+
+ oldhp = t->bucketPtr;
+ oldsize = i = t->size;
+ i <<= 1;
+ t->size = i;
+ t->mask = mask = i - 1;
+ t->bucketPtr = hp = (struct Hash_Entry **) emalloc(sizeof(*hp) * i);
+ while (--i >= 0)
+ *hp++ = NULL;
+ for (hp = oldhp, i = oldsize; --i >= 0;) {
+ for (e = *hp++; e != NULL; e = next) {
+ next = e->next;
+ xp = &t->bucketPtr[e->namehash & mask];
+ e->next = *xp;
+ *xp = e;
+ }
+ }
+ free((char *)oldhp);
+}
diff --git a/usr.bin/make/hash.h b/usr.bin/make/hash.h
new file mode 100644
index 0000000..6e88ed8
--- /dev/null
+++ b/usr.bin/make/hash.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)hash.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/* hash.h --
+ *
+ * This file contains definitions used by the hash module,
+ * which maintains hash tables.
+ */
+
+#ifndef _HASH
+#define _HASH
+
+/*
+ * The following defines one entry in the hash table.
+ */
+
+typedef struct Hash_Entry {
+ struct Hash_Entry *next; /* Used to link together all the
+ * entries associated with the same
+ * bucket. */
+ ClientData clientData; /* Arbitrary piece of data associated
+ * with key. */
+ unsigned namehash; /* hash value of key */
+ char name[1]; /* key string */
+} Hash_Entry;
+
+typedef struct Hash_Table {
+ struct Hash_Entry **bucketPtr;/* Pointers to Hash_Entry, one
+ * for each bucket in the table. */
+ int size; /* Actual size of array. */
+ int numEntries; /* Number of entries in the table. */
+ int mask; /* Used to select bits for hashing. */
+} Hash_Table;
+
+/*
+ * The following structure is used by the searching routines
+ * to record where we are in the search.
+ */
+
+typedef struct Hash_Search {
+ Hash_Table *tablePtr; /* Table being searched. */
+ int nextIndex; /* Next bucket to check (after current). */
+ Hash_Entry *hashEntryPtr; /* Next entry to check in current bucket. */
+} Hash_Search;
+
+/*
+ * Macros.
+ */
+
+/*
+ * ClientData Hash_GetValue(h)
+ * Hash_Entry *h;
+ */
+
+#define Hash_GetValue(h) ((h)->clientData)
+
+/*
+ * Hash_SetValue(h, val);
+ * Hash_Entry *h;
+ * char *val;
+ */
+
+#define Hash_SetValue(h, val) ((h)->clientData = (ClientData) (val))
+
+/*
+ * Hash_Size(n) returns the number of words in an object of n bytes
+ */
+
+#define Hash_Size(n) (((n) + sizeof (int) - 1) / sizeof (int))
+
+void Hash_InitTable __P((Hash_Table *, int));
+void Hash_DeleteTable __P((Hash_Table *));
+Hash_Entry *Hash_FindEntry __P((Hash_Table *, char *));
+Hash_Entry *Hash_CreateEntry __P((Hash_Table *, char *, Boolean *));
+void Hash_DeleteEntry __P((Hash_Table *, Hash_Entry *));
+Hash_Entry *Hash_EnumFirst __P((Hash_Table *, Hash_Search *));
+Hash_Entry *Hash_EnumNext __P((Hash_Search *));
+
+#endif /* _HASH */
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c
new file mode 100644
index 0000000..01e493f
--- /dev/null
+++ b/usr.bin/make/job.c
@@ -0,0 +1,3107 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * job.c --
+ * handle the creation etc. of our child processes.
+ *
+ * Interface:
+ * Job_Make Start the creation of the given target.
+ *
+ * Job_CatchChildren Check for and handle the termination of any
+ * children. This must be called reasonably
+ * frequently to keep the whole make going at
+ * a decent clip, since job table entries aren't
+ * removed until their process is caught this way.
+ * Its single argument is TRUE if the function
+ * should block waiting for a child to terminate.
+ *
+ * Job_CatchOutput Print any output our children have produced.
+ * Should also be called fairly frequently to
+ * keep the user informed of what's going on.
+ * If no output is waiting, it will block for
+ * a time given by the SEL_* constants, below,
+ * or until output is ready.
+ *
+ * Job_Init Called to intialize this module. in addition,
+ * any commands attached to the .BEGIN target
+ * are executed before this function returns.
+ * Hence, the makefile must have been parsed
+ * before this function is called.
+ *
+ * Job_Full Return TRUE if the job table is filled.
+ *
+ * Job_Empty Return TRUE if the job table is completely
+ * empty.
+ *
+ * Job_ParseShell Given the line following a .SHELL target, parse
+ * the line as a shell specification. Returns
+ * FAILURE if the spec was incorrect.
+ *
+ * Job_End Perform any final processing which needs doing.
+ * This includes the execution of any commands
+ * which have been/were attached to the .END
+ * target. It should only be called when the
+ * job table is empty.
+ *
+ * Job_AbortAll Abort all currently running jobs. It doesn't
+ * handle output or do anything for the jobs,
+ * just kills them. It should only be called in
+ * an emergency, as it were.
+ *
+ * Job_CheckCommands Verify that the commands for a target are
+ * ok. Provide them if necessary and possible.
+ *
+ * Job_Touch Update a target without really updating it.
+ *
+ * Job_Wait Wait for all currently-running jobs to finish.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <utime.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "job.h"
+#include "pathnames.h"
+#ifdef REMOTE
+#include "rmt.h"
+# define STATIC
+#else
+# define STATIC static
+#endif
+
+extern int errno;
+
+/*
+ * error handling variables
+ */
+static int errors = 0; /* number of errors reported */
+static int aborting = 0; /* why is the make aborting? */
+#define ABORT_ERROR 1 /* Because of an error */
+#define ABORT_INTERRUPT 2 /* Because it was interrupted */
+#define ABORT_WAIT 3 /* Waiting for jobs to finish */
+
+/*
+ * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
+ * is a char! So when we go above 127 we turn negative!
+ */
+#define FILENO(a) ((unsigned) fileno(a))
+
+/*
+ * post-make command processing. The node postCommands is really just the
+ * .END target but we keep it around to avoid having to search for it
+ * all the time.
+ */
+static GNode *postCommands; /* node containing commands to execute when
+ * everything else is done */
+static int numCommands; /* The number of commands actually printed
+ * for a target. Should this number be
+ * 0, no shell will be executed. */
+
+/*
+ * Return values from JobStart.
+ */
+#define JOB_RUNNING 0 /* Job is running */
+#define JOB_ERROR 1 /* Error in starting the job */
+#define JOB_FINISHED 2 /* The job is already finished */
+#define JOB_STOPPED 3 /* The job is stopped */
+
+/*
+ * tfile is the name of a file into which all shell commands are put. It is
+ * used over by removing it before the child shell is executed. The XXXXX in
+ * the string are replaced by the pid of the make process in a 5-character
+ * field with leading zeroes.
+ */
+static char tfile[] = TMPPAT;
+
+
+/*
+ * Descriptions for various shells.
+ */
+static Shell shells[] = {
+ /*
+ * CSH description. The csh can do echo control by playing
+ * with the setting of the 'echo' shell variable. Sadly,
+ * however, it is unable to do error control nicely.
+ */
+{
+ "csh",
+ TRUE, "unset verbose", "set verbose", "unset verbose", 10,
+ FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"",
+ "v", "e",
+},
+ /*
+ * SH description. Echo control is also possible and, under
+ * sun UNIX anyway, one can even control error checking.
+ */
+{
+ "sh",
+ TRUE, "set -", "set -v", "set -", 5,
+ TRUE, "set -e", "set +e",
+#ifdef OLDBOURNESHELL
+ FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",
+#endif
+ "v", "e",
+},
+ /*
+ * UNKNOWN.
+ */
+{
+ (char *) 0,
+ FALSE, (char *) 0, (char *) 0, (char *) 0, 0,
+ FALSE, (char *) 0, (char *) 0,
+ (char *) 0, (char *) 0,
+}
+};
+static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to
+ * which we pass all
+ * commands in the Makefile.
+ * It is set by the
+ * Job_ParseShell function */
+static char *shellPath = NULL, /* full pathname of
+ * executable image */
+ *shellName; /* last component of shell */
+
+
+static int maxJobs; /* The most children we can run at once */
+static int maxLocal; /* The most local ones we can have */
+STATIC int nJobs; /* The number of children currently running */
+STATIC int nLocal; /* The number of local children */
+STATIC Lst jobs; /* The structures that describe them */
+STATIC Boolean jobFull; /* Flag to tell when the job table is full. It
+ * is set TRUE when (1) the total number of
+ * running jobs equals the maximum allowed or
+ * (2) a job can only be run locally, but
+ * nLocal equals maxLocal */
+#ifndef RMT_WILL_WATCH
+static fd_set outputs; /* Set of descriptors of pipes connected to
+ * the output channels of children */
+#endif
+
+STATIC GNode *lastNode; /* The node for which output was most recently
+ * produced. */
+STATIC char *targFmt; /* Format string to use to head output from a
+ * job when it's not the most-recent job heard
+ * from */
+
+#ifdef REMOTE
+# define TARG_FMT "--- %s at %s ---\n" /* Default format */
+# define MESSAGE(fp, gn) \
+ (void) fprintf(fp, targFmt, gn->name, gn->rem.hname);
+#else
+# define TARG_FMT "--- %s ---\n" /* Default format */
+# define MESSAGE(fp, gn) \
+ (void) fprintf(fp, targFmt, gn->name);
+#endif
+
+/*
+ * When JobStart attempts to run a job remotely but can't, and isn't allowed
+ * to run the job locally, or when Job_CatchChildren detects a job that has
+ * been migrated home, the job is placed on the stoppedJobs queue to be run
+ * when the next job finishes.
+ */
+STATIC Lst stoppedJobs; /* Lst of Job structures describing
+ * jobs that were stopped due to concurrency
+ * limits or migration home */
+
+
+#if defined(USE_PGRP) && defined(SYSV)
+# define KILL(pid, sig) killpg(-(pid), (sig))
+#else
+# if defined(USE_PGRP)
+# define KILL(pid, sig) killpg((pid), (sig))
+# else
+# define KILL(pid, sig) kill((pid), (sig))
+# endif
+#endif
+
+/*
+ * Grmpf... There is no way to set bits of the wait structure
+ * anymore with the stupid W*() macros. I liked the union wait
+ * stuff much more. So, we devise our own macros... This is
+ * really ugly, use dramamine sparingly. You have been warned.
+ */
+#define W_SETMASKED(st, val, fun) \
+ { \
+ int sh = (int) ~0; \
+ int mask = fun(sh); \
+ \
+ for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \
+ continue; \
+ *(st) = (*(st) & ~mask) | ((val) << sh); \
+ }
+
+#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG)
+#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS)
+
+
+static int JobCondPassSig __P((ClientData, ClientData));
+static void JobPassSig __P((int));
+static int JobCmpPid __P((ClientData, ClientData));
+static int JobPrintCommand __P((ClientData, ClientData));
+static int JobSaveCommand __P((ClientData, ClientData));
+static void JobClose __P((Job *));
+#ifdef REMOTE
+static int JobCmpRmtID __P((Job *, int));
+# ifdef RMT_WILL_WATCH
+static void JobLocalInput __P((int, Job *));
+# endif
+#else
+static void JobFinish __P((Job *, int *));
+static void JobExec __P((Job *, char **));
+#endif
+static void JobMakeArgv __P((Job *, char **));
+static void JobRestart __P((Job *));
+static int JobStart __P((GNode *, int, Job *));
+static char *JobOutput __P((Job *, char *, char *, int));
+static void JobDoOutput __P((Job *, Boolean));
+static Shell *JobMatchShell __P((char *));
+static void JobInterrupt __P((int, int));
+static void JobRestartJobs __P((void));
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobCondPassSig --
+ * Pass a signal to a job if the job is remote or if USE_PGRP
+ * is defined.
+ *
+ * Results:
+ * === 0
+ *
+ * Side Effects:
+ * None, except the job may bite it.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+JobCondPassSig(jobp, signop)
+ ClientData jobp; /* Job to biff */
+ ClientData signop; /* Signal to send it */
+{
+ Job *job = (Job *) jobp;
+ int signo = *(int *) signop;
+#ifdef RMT_WANTS_SIGNALS
+ if (job->flags & JOB_REMOTE) {
+ (void) Rmt_Signal(job, signo);
+ } else {
+ KILL(job->pid, signo);
+ }
+#else
+ /*
+ * Assume that sending the signal to job->pid will signal any remote
+ * job as well.
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobCondPassSig passing signal %d to child %d.\n",
+ signo, job->pid);
+ (void) fflush(stdout);
+ }
+ KILL(job->pid, signo);
+#endif
+ return 0;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobPassSig --
+ * Pass a signal on to all remote jobs and to all local jobs if
+ * USE_PGRP is defined, then die ourselves.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * We die by the same signal.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobPassSig(signo)
+ int signo; /* The signal number we've received */
+{
+ sigset_t nmask, omask;
+ struct sigaction act;
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo);
+ (void) fflush(stdout);
+ }
+ Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
+
+ /*
+ * Deal with proper cleanup based on the signal received. We only run
+ * the .INTERRUPT target if the signal was in fact an interrupt. The other
+ * three termination signals are more of a "get out *now*" command.
+ */
+ if (signo == SIGINT) {
+ JobInterrupt(TRUE, signo);
+ } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {
+ JobInterrupt(FALSE, signo);
+ }
+
+ /*
+ * Leave gracefully if SIGQUIT, rather than core dumping.
+ */
+ if (signo == SIGQUIT) {
+ Finish(0);
+ }
+
+ /*
+ * Send ourselves the signal now we've given the message to everyone else.
+ * Note we block everything else possible while we're getting the signal.
+ * This ensures that all our jobs get continued when we wake up before
+ * we take any other signal.
+ */
+ sigemptyset(&nmask);
+ sigaddset(&nmask, signo);
+ sigprocmask(SIG_SETMASK, &nmask, &omask);
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction(signo, &act, NULL);
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobPassSig passing signal to self, mask = %x.\n",
+ ~0 & ~(1 << (signo-1)));
+ (void) fflush(stdout);
+ }
+ (void) signal(signo, SIG_DFL);
+
+ (void) KILL(getpid(), signo);
+
+ signo = SIGCONT;
+ Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
+
+ (void) sigprocmask(SIG_SETMASK, &omask, NULL);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ act.sa_handler = JobPassSig;
+ sigaction(signo, &act, NULL);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobCmpPid --
+ * Compare the pid of the job with the given pid and return 0 if they
+ * are equal. This function is called from Job_CatchChildren via
+ * Lst_Find to find the job descriptor of the finished job.
+ *
+ * Results:
+ * 0 if the pid's match
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static int
+JobCmpPid(job, pid)
+ ClientData job; /* job to examine */
+ ClientData pid; /* process id desired */
+{
+ return *(int *) pid - ((Job *) job)->pid;
+}
+
+#ifdef REMOTE
+/*-
+ *-----------------------------------------------------------------------
+ * JobCmpRmtID --
+ * Compare the rmtID of the job with the given rmtID and return 0 if they
+ * are equal.
+ *
+ * Results:
+ * 0 if the rmtID's match
+ *
+ * Side Effects:
+ * None.
+ *-----------------------------------------------------------------------
+ */
+static int
+JobCmpRmtID(job, rmtID)
+ ClientData job; /* job to examine */
+ ClientData rmtID; /* remote id desired */
+{
+ return(*(int *) rmtID - *(int *) job->rmtID);
+}
+#endif
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobPrintCommand --
+ * Put out another command for the given job. If the command starts
+ * with an @ or a - we process it specially. In the former case,
+ * so long as the -s and -n flags weren't given to make, we stick
+ * a shell-specific echoOff command in the script. In the latter,
+ * we ignore errors for the entire job, unless the shell has error
+ * control.
+ * If the command is just "..." we take all future commands for this
+ * job to be commands to be executed once the entire graph has been
+ * made and return non-zero to signal that the end of the commands
+ * was reached. These commands are later attached to the postCommands
+ * node and executed by Job_End when all things are done.
+ * This function is called from JobStart via Lst_ForEach.
+ *
+ * Results:
+ * Always 0, unless the command was "..."
+ *
+ * Side Effects:
+ * If the command begins with a '-' and the shell has no error control,
+ * the JOB_IGNERR flag is set in the job descriptor.
+ * If the command is "..." and we're not ignoring such things,
+ * tailCmds is set to the successor node of the cmd.
+ * numCommands is incremented if the command is actually printed.
+ *-----------------------------------------------------------------------
+ */
+static int
+JobPrintCommand(cmdp, jobp)
+ ClientData cmdp; /* command string to print */
+ ClientData jobp; /* job for which to print it */
+{
+ Boolean noSpecials; /* true if we shouldn't worry about
+ * inserting special commands into
+ * the input stream. */
+ Boolean shutUp = FALSE; /* true if we put a no echo command
+ * into the command file */
+ Boolean errOff = FALSE; /* true if we turned error checking
+ * off before printing the command
+ * and need to turn it back on */
+ char *cmdTemplate; /* Template to use when printing the
+ * command */
+ char *cmdStart; /* Start of expanded command */
+ LstNode cmdNode; /* Node for replacing the command */
+ char *cmd = (char *) cmdp;
+ Job *job = (Job *) jobp;
+
+ noSpecials = (noExecute && !(job->node->type & OP_MAKE));
+
+ if (strcmp(cmd, "...") == 0) {
+ job->node->type |= OP_SAVE_CMDS;
+ if ((job->flags & JOB_IGNDOTS) == 0) {
+ job->tailCmds = Lst_Succ(Lst_Member(job->node->commands,
+ (ClientData)cmd));
+ return 1;
+ }
+ return 0;
+ }
+
+#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \
+ (void) fprintf(stdout, fmt, arg); \
+ (void) fflush(stdout); \
+ } \
+ (void) fprintf(job->cmdFILE, fmt, arg); \
+ (void) fflush(job->cmdFILE);
+
+ numCommands += 1;
+
+ /*
+ * For debugging, we replace each command with the result of expanding
+ * the variables in the command.
+ */
+ cmdNode = Lst_Member(job->node->commands, (ClientData)cmd);
+ cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE);
+ Lst_Replace(cmdNode, (ClientData)cmdStart);
+
+ cmdTemplate = "%s\n";
+
+ /*
+ * Check for leading @' and -'s to control echoing and error checking.
+ */
+ while (*cmd == '@' || *cmd == '-') {
+ if (*cmd == '@') {
+ shutUp = TRUE;
+ } else {
+ errOff = TRUE;
+ }
+ cmd++;
+ }
+
+ while (isspace((unsigned char) *cmd))
+ cmd++;
+
+ if (shutUp) {
+ if (!(job->flags & JOB_SILENT) && !noSpecials &&
+ commandShell->hasEchoCtl) {
+ DBPRINTF("%s\n", commandShell->echoOff);
+ } else {
+ shutUp = FALSE;
+ }
+ }
+
+ if (errOff) {
+ if ( !(job->flags & JOB_IGNERR) && !noSpecials) {
+ if (commandShell->hasErrCtl) {
+ /*
+ * we don't want the error-control commands showing
+ * up either, so we turn off echoing while executing
+ * them. We could put another field in the shell
+ * structure to tell JobDoOutput to look for this
+ * string too, but why make it any more complex than
+ * it already is?
+ */
+ if (!(job->flags & JOB_SILENT) && !shutUp &&
+ commandShell->hasEchoCtl) {
+ DBPRINTF("%s\n", commandShell->echoOff);
+ DBPRINTF("%s\n", commandShell->ignErr);
+ DBPRINTF("%s\n", commandShell->echoOn);
+ } else {
+ DBPRINTF("%s\n", commandShell->ignErr);
+ }
+ } else if (commandShell->ignErr &&
+ (*commandShell->ignErr != '\0'))
+ {
+ /*
+ * The shell has no error control, so we need to be
+ * weird to get it to ignore any errors from the command.
+ * If echoing is turned on, we turn it off and use the
+ * errCheck template to echo the command. Leave echoing
+ * off so the user doesn't see the weirdness we go through
+ * to ignore errors. Set cmdTemplate to use the weirdness
+ * instead of the simple "%s\n" template.
+ */
+ if (!(job->flags & JOB_SILENT) && !shutUp &&
+ commandShell->hasEchoCtl) {
+ DBPRINTF("%s\n", commandShell->echoOff);
+ DBPRINTF(commandShell->errCheck, cmd);
+ shutUp = TRUE;
+ }
+ cmdTemplate = commandShell->ignErr;
+ /*
+ * The error ignoration (hee hee) is already taken care
+ * of by the ignErr template, so pretend error checking
+ * is still on.
+ */
+ errOff = FALSE;
+ } else {
+ errOff = FALSE;
+ }
+ } else {
+ errOff = FALSE;
+ }
+ }
+
+ DBPRINTF(cmdTemplate, cmd);
+
+ if (errOff) {
+ /*
+ * If echoing is already off, there's no point in issuing the
+ * echoOff command. Otherwise we issue it and pretend it was on
+ * for the whole command...
+ */
+ if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
+ DBPRINTF("%s\n", commandShell->echoOff);
+ shutUp = TRUE;
+ }
+ DBPRINTF("%s\n", commandShell->errCheck);
+ }
+ if (shutUp) {
+ DBPRINTF("%s\n", commandShell->echoOn);
+ }
+ return 0;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobSaveCommand --
+ * Save a command to be executed when everything else is done.
+ * Callback function for JobFinish...
+ *
+ * Results:
+ * Always returns 0
+ *
+ * Side Effects:
+ * The command is tacked onto the end of postCommands's commands list.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+JobSaveCommand(cmd, gn)
+ ClientData cmd;
+ ClientData gn;
+{
+ cmd = (ClientData) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE);
+ (void) Lst_AtEnd(postCommands->commands, cmd);
+ return(0);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobClose --
+ * Called to close both input and output pipes when a job is finished.
+ *
+ * Results:
+ * Nada
+ *
+ * Side Effects:
+ * The file descriptors associated with the job are closed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobClose(job)
+ Job *job;
+{
+ if (usePipes) {
+#ifdef RMT_WILL_WATCH
+ Rmt_Ignore(job->inPipe);
+#else
+ FD_CLR(job->inPipe, &outputs);
+#endif
+ if (job->outPipe != job->inPipe) {
+ (void) close(job->outPipe);
+ }
+ JobDoOutput(job, TRUE);
+ (void) close(job->inPipe);
+ } else {
+ (void) close(job->outFd);
+ JobDoOutput(job, TRUE);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobFinish --
+ * Do final processing for the given job including updating
+ * parents and starting new jobs as available/necessary. Note
+ * that we pay no attention to the JOB_IGNERR flag here.
+ * This is because when we're called because of a noexecute flag
+ * or something, jstat.w_status is 0 and when called from
+ * Job_CatchChildren, the status is zeroed if it s/b ignored.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Some nodes may be put on the toBeMade queue.
+ * Final commands for the job are placed on postCommands.
+ *
+ * If we got an error and are aborting (aborting == ABORT_ERROR) and
+ * the job list is now empty, we are done for the day.
+ * If we recognized an error (errors !=0), we set the aborting flag
+ * to ABORT_ERROR so no more jobs will be started.
+ *-----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+JobFinish(job, status)
+ Job *job; /* job to finish */
+ int *status; /* sub-why job went away */
+{
+ Boolean done;
+
+ if ((WIFEXITED(*status) &&
+ (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) ||
+ (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT)))
+ {
+ /*
+ * If it exited non-zero and either we're doing things our
+ * way or we're not ignoring errors, the job is finished.
+ * Similarly, if the shell died because of a signal
+ * the job is also finished. In these
+ * cases, finish out the job's output before printing the exit
+ * status...
+ */
+#ifdef REMOTE
+ KILL(job->pid, SIGCONT);
+#endif
+ JobClose(job);
+ if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
+ (void) fclose(job->cmdFILE);
+ }
+ done = TRUE;
+#ifdef REMOTE
+ if (job->flags & JOB_REMOTE)
+ Rmt_Done(job->rmtID, job->node);
+#endif
+ } else if (WIFEXITED(*status)) {
+ /*
+ * Deal with ignored errors in -B mode. We need to print a message
+ * telling of the ignored error as well as setting status.w_status
+ * to 0 so the next command gets run. To do this, we set done to be
+ * TRUE if in -B mode and the job exited non-zero.
+ */
+ done = WEXITSTATUS(*status) != 0;
+ /*
+ * Old comment said: "Note we don't
+ * want to close down any of the streams until we know we're at the
+ * end."
+ * But we do. Otherwise when are we going to print the rest of the
+ * stuff?
+ */
+ JobClose(job);
+#ifdef REMOTE
+ if (job->flags & JOB_REMOTE)
+ Rmt_Done(job->rmtID, job->node);
+#endif /* REMOTE */
+ } else {
+ /*
+ * No need to close things down or anything.
+ */
+ done = FALSE;
+ }
+
+ if (done ||
+ WIFSTOPPED(*status) ||
+ (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) ||
+ DEBUG(JOB))
+ {
+ FILE *out;
+
+ if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) {
+ /*
+ * If output is going to a file and this job is ignoring
+ * errors, arrange to have the exit status sent to the
+ * output file as well.
+ */
+ out = fdopen(job->outFd, "w");
+ } else {
+ out = stdout;
+ }
+
+ if (WIFEXITED(*status)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Process %d exited.\n", job->pid);
+ (void) fflush(stdout);
+ }
+ if (WEXITSTATUS(*status) != 0) {
+ if (usePipes && job->node != lastNode) {
+ MESSAGE(out, job->node);
+ lastNode = job->node;
+ }
+ (void) fprintf(out, "*** Error code %d%s\n",
+ WEXITSTATUS(*status),
+ (job->flags & JOB_IGNERR) ? "(ignored)" : "");
+
+ if (job->flags & JOB_IGNERR) {
+ *status = 0;
+ }
+ } else if (DEBUG(JOB)) {
+ if (usePipes && job->node != lastNode) {
+ MESSAGE(out, job->node);
+ lastNode = job->node;
+ }
+ (void) fprintf(out, "*** Completed successfully\n");
+ }
+ } else if (WIFSTOPPED(*status)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Process %d stopped.\n", job->pid);
+ (void) fflush(stdout);
+ }
+ if (usePipes && job->node != lastNode) {
+ MESSAGE(out, job->node);
+ lastNode = job->node;
+ }
+ if (!(job->flags & JOB_REMIGRATE)) {
+ (void) fprintf(out, "*** Stopped -- signal %d\n",
+ WSTOPSIG(*status));
+ }
+ job->flags |= JOB_RESUME;
+ (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
+#ifdef REMOTE
+ if (job->flags & JOB_REMIGRATE)
+ JobRestart(job);
+#endif
+ (void) fflush(out);
+ return;
+ } else if (WTERMSIG(*status) == SIGCONT) {
+ /*
+ * If the beastie has continued, shift the Job from the stopped
+ * list to the running one (or re-stop it if concurrency is
+ * exceeded) and go and get another child.
+ */
+ if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {
+ if (usePipes && job->node != lastNode) {
+ MESSAGE(out, job->node);
+ lastNode = job->node;
+ }
+ (void) fprintf(out, "*** Continued\n");
+ }
+ if (!(job->flags & JOB_CONTINUING)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "Warning: process %d was not continuing.\n",
+ job->pid);
+ (void) fflush(stdout);
+ }
+#ifdef notdef
+ /*
+ * We don't really want to restart a job from scratch just
+ * because it continued, especially not without killing the
+ * continuing process! That's why this is ifdef'ed out.
+ * FD - 9/17/90
+ */
+ JobRestart(job);
+#endif
+ }
+ job->flags &= ~JOB_CONTINUING;
+ Lst_AtEnd(jobs, (ClientData)job);
+ nJobs += 1;
+ if (!(job->flags & JOB_REMOTE)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "Process %d is continuing locally.\n",
+ job->pid);
+ (void) fflush(stdout);
+ }
+ nLocal += 1;
+ }
+ if (nJobs == maxJobs) {
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ }
+ (void) fflush(out);
+ return;
+ } else {
+ if (usePipes && job->node != lastNode) {
+ MESSAGE(out, job->node);
+ lastNode = job->node;
+ }
+ (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status));
+ }
+
+ (void) fflush(out);
+ }
+
+ /*
+ * Now handle the -B-mode stuff. If the beast still isn't finished,
+ * try and restart the job on the next command. If JobStart says it's
+ * ok, it's ok. If there's an error, this puppy is done.
+ */
+ if (compatMake && (WIFEXITED(*status) &&
+ !Lst_IsAtEnd(job->node->commands))) {
+ switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) {
+ case JOB_RUNNING:
+ done = FALSE;
+ break;
+ case JOB_ERROR:
+ done = TRUE;
+ W_SETEXITSTATUS(status, 1);
+ break;
+ case JOB_FINISHED:
+ /*
+ * If we got back a JOB_FINISHED code, JobStart has already
+ * called Make_Update and freed the job descriptor. We set
+ * done to false here to avoid fake cycles and double frees.
+ * JobStart needs to do the update so we can proceed up the
+ * graph when given the -n flag..
+ */
+ done = FALSE;
+ break;
+ }
+ } else {
+ done = TRUE;
+ }
+
+
+ if (done &&
+ (aborting != ABORT_ERROR) &&
+ (aborting != ABORT_INTERRUPT) &&
+ (*status == 0))
+ {
+ /*
+ * As long as we aren't aborting and the job didn't return a non-zero
+ * status that we shouldn't ignore, we call Make_Update to update
+ * the parents. In addition, any saved commands for the node are placed
+ * on the .END target.
+ */
+ if (job->tailCmds != NILLNODE) {
+ Lst_ForEachFrom(job->node->commands, job->tailCmds,
+ JobSaveCommand,
+ (ClientData)job->node);
+ }
+ job->node->made = MADE;
+ Make_Update(job->node);
+ free((Address)job);
+ } else if (*status != 0) {
+ errors += 1;
+ free((Address)job);
+ }
+
+ JobRestartJobs();
+
+ /*
+ * Set aborting if any error.
+ */
+ if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {
+ /*
+ * If we found any errors in this batch of children and the -k flag
+ * wasn't given, we set the aborting flag so no more jobs get
+ * started.
+ */
+ aborting = ABORT_ERROR;
+ }
+
+ if ((aborting == ABORT_ERROR) && Job_Empty()) {
+ /*
+ * If we are aborting and the job table is now empty, we finish.
+ */
+ (void) eunlink(tfile);
+ Finish(errors);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Touch --
+ * Touch the given target. Called by JobStart when the -t flag was
+ * given
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The data modification of the file is changed. In addition, if the
+ * file did not exist, it is created.
+ *-----------------------------------------------------------------------
+ */
+void
+Job_Touch(gn, silent)
+ GNode *gn; /* the node of the file to touch */
+ Boolean silent; /* TRUE if should not print messages */
+{
+ int streamID; /* ID of stream opened to do the touch */
+ struct utimbuf times; /* Times for utime() call */
+
+ if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) {
+ /*
+ * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
+ * and, as such, shouldn't really be created.
+ */
+ return;
+ }
+
+ if (!silent) {
+ (void) fprintf(stdout, "touch %s\n", gn->name);
+ (void) fflush(stdout);
+ }
+
+ if (noExecute) {
+ return;
+ }
+
+ if (gn->type & OP_ARCHV) {
+ Arch_Touch(gn);
+ } else if (gn->type & OP_LIB) {
+ Arch_TouchLib(gn);
+ } else {
+ char *file = gn->path ? gn->path : gn->name;
+
+ times.actime = times.modtime = now;
+ if (utime(file, &times) < 0){
+ streamID = open(file, O_RDWR | O_CREAT, 0666);
+
+ if (streamID >= 0) {
+ char c;
+
+ /*
+ * Read and write a byte to the file to change the
+ * modification time, then close the file.
+ */
+ if (read(streamID, &c, 1) == 1) {
+ (void) lseek(streamID, 0L, L_SET);
+ (void) write(streamID, &c, 1);
+ }
+
+ (void) close(streamID);
+ } else {
+ (void) fprintf(stdout, "*** couldn't touch %s: %s",
+ file, strerror(errno));
+ (void) fflush(stdout);
+ }
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_CheckCommands --
+ * Make sure the given node has all the commands it needs.
+ *
+ * Results:
+ * TRUE if the commands list is/was ok.
+ *
+ * Side Effects:
+ * The node will have commands from the .DEFAULT rule added to it
+ * if it needs them.
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Job_CheckCommands(gn, abortProc)
+ GNode *gn; /* The target whose commands need
+ * verifying */
+ void (*abortProc) __P((char *, ...));
+ /* Function to abort with message */
+{
+ if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) &&
+ (gn->type & OP_LIB) == 0) {
+ /*
+ * No commands. Look for .DEFAULT rule from which we might infer
+ * commands
+ */
+ if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) {
+ char *p1;
+ /*
+ * Make only looks for a .DEFAULT if the node was never the
+ * target of an operator, so that's what we do too. If
+ * a .DEFAULT was given, we substitute its commands for gn's
+ * commands and set the IMPSRC variable to be the target's name
+ * The DEFAULT node acts like a transformation rule, in that
+ * gn also inherits any attributes or sources attached to
+ * .DEFAULT itself.
+ */
+ Make_HandleUse(DEFAULT, gn);
+ Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn);
+ if (p1)
+ free(p1);
+ } else if (Dir_MTime(gn) == 0) {
+ /*
+ * The node wasn't the target of an operator we have no .DEFAULT
+ * rule to go on and the target doesn't already exist. There's
+ * nothing more we can do for this branch. If the -k flag wasn't
+ * given, we stop in our tracks, otherwise we just don't update
+ * this node's parents so they never get examined.
+ */
+ static const char msg[] = "make: don't know how to make";
+
+ if (gn->type & OP_OPTIONAL) {
+ (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name);
+ (void) fflush(stdout);
+ } else if (keepgoing) {
+ (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name);
+ (void) fflush(stdout);
+ return FALSE;
+ } else {
+ (*abortProc)("%s %s. Stop", msg, gn->name);
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+#ifdef RMT_WILL_WATCH
+/*-
+ *-----------------------------------------------------------------------
+ * JobLocalInput --
+ * Handle a pipe becoming readable. Callback function for Rmt_Watch
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * JobDoOutput is called.
+ *
+ *-----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+JobLocalInput(stream, job)
+ int stream; /* Stream that's ready (ignored) */
+ Job *job; /* Job to which the stream belongs */
+{
+ JobDoOutput(job, FALSE);
+}
+#endif /* RMT_WILL_WATCH */
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobExec --
+ * Execute the shell for the given job. Called from JobStart and
+ * JobRestart.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * A shell is executed, outputs is altered and the Job structure added
+ * to the job table.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobExec(job, argv)
+ Job *job; /* Job to execute */
+ char **argv;
+{
+ int cpid; /* ID of new child */
+
+ if (DEBUG(JOB)) {
+ int i;
+
+ (void) fprintf(stdout, "Running %s %sly\n", job->node->name,
+ job->flags&JOB_REMOTE?"remote":"local");
+ (void) fprintf(stdout, "\tCommand: ");
+ for (i = 0; argv[i] != NULL; i++) {
+ (void) fprintf(stdout, "%s ", argv[i]);
+ }
+ (void) fprintf(stdout, "\n");
+ (void) fflush(stdout);
+ }
+
+ /*
+ * Some jobs produce no output and it's disconcerting to have
+ * no feedback of their running (since they produce no output, the
+ * banner with their name in it never appears). This is an attempt to
+ * provide that feedback, even if nothing follows it.
+ */
+ if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&
+ !(job->flags & JOB_SILENT)) {
+ MESSAGE(stdout, job->node);
+ lastNode = job->node;
+ }
+
+#ifdef RMT_NO_EXEC
+ if (job->flags & JOB_REMOTE) {
+ goto jobExecFinish;
+ }
+#endif /* RMT_NO_EXEC */
+
+ if ((cpid = vfork()) == -1) {
+ Punt("Cannot fork");
+ } else if (cpid == 0) {
+
+ /*
+ * Must duplicate the input stream down to the child's input and
+ * reset it to the beginning (again). Since the stream was marked
+ * close-on-exec, we must clear that bit in the new input.
+ */
+ if (dup2(FILENO(job->cmdFILE), 0) == -1)
+ Punt("Cannot dup2: %s", strerror(errno));
+ (void) fcntl(0, F_SETFD, 0);
+ (void) lseek(0, 0, L_SET);
+
+ if (usePipes) {
+ /*
+ * Set up the child's output to be routed through the pipe
+ * we've created for it.
+ */
+ if (dup2(job->outPipe, 1) == -1)
+ Punt("Cannot dup2: %s", strerror(errno));
+ } else {
+ /*
+ * We're capturing output in a file, so we duplicate the
+ * descriptor to the temporary file into the standard
+ * output.
+ */
+ if (dup2(job->outFd, 1) == -1)
+ Punt("Cannot dup2: %s", strerror(errno));
+ }
+ /*
+ * The output channels are marked close on exec. This bit was
+ * duplicated by the dup2 (on some systems), so we have to clear
+ * it before routing the shell's error output to the same place as
+ * its standard output.
+ */
+ (void) fcntl(1, F_SETFD, 0);
+ if (dup2(1, 2) == -1)
+ Punt("Cannot dup2: %s", strerror(errno));
+
+#ifdef USE_PGRP
+ /*
+ * We want to switch the child into a different process family so
+ * we can kill it and all its descendants in one fell swoop,
+ * by killing its process family, but not commit suicide.
+ */
+# if defined(SYSV)
+ (void) setsid();
+# else
+ (void) setpgid(0, getpid());
+# endif
+#endif /* USE_PGRP */
+
+#ifdef REMOTE
+ if (job->flags & JOB_REMOTE) {
+ Rmt_Exec(shellPath, argv, FALSE);
+ } else
+#endif /* REMOTE */
+ (void) execv(shellPath, argv);
+
+ (void) write(2, "Could not execute shell\n",
+ sizeof("Could not execute shell"));
+ _exit(1);
+ } else {
+#ifdef REMOTE
+ long omask = sigblock(sigmask(SIGCHLD));
+#endif
+ job->pid = cpid;
+
+ if (usePipes && (job->flags & JOB_FIRST) ) {
+ /*
+ * The first time a job is run for a node, we set the current
+ * position in the buffer to the beginning and mark another
+ * stream to watch in the outputs mask
+ */
+ job->curPos = 0;
+
+#ifdef RMT_WILL_WATCH
+ Rmt_Watch(job->inPipe, JobLocalInput, job);
+#else
+ FD_SET(job->inPipe, &outputs);
+#endif /* RMT_WILL_WATCH */
+ }
+
+ if (job->flags & JOB_REMOTE) {
+#ifndef REMOTE
+ job->rmtID = 0;
+#else
+ job->rmtID = Rmt_LastID(job->pid);
+#endif /* REMOTE */
+ } else {
+ nLocal += 1;
+ /*
+ * XXX: Used to not happen if REMOTE. Why?
+ */
+ if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
+ (void) fclose(job->cmdFILE);
+ job->cmdFILE = NULL;
+ }
+ }
+#ifdef REMOTE
+ (void) sigsetmask(omask);
+#endif
+ }
+
+#ifdef RMT_NO_EXEC
+jobExecFinish:
+#endif
+ /*
+ * Now the job is actually running, add it to the table.
+ */
+ nJobs += 1;
+ (void) Lst_AtEnd(jobs, (ClientData)job);
+ if (nJobs == maxJobs) {
+ jobFull = TRUE;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobMakeArgv --
+ * Create the argv needed to execute the shell for a given job.
+ *
+ *
+ * Results:
+ *
+ * Side Effects:
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobMakeArgv(job, argv)
+ Job *job;
+ char **argv;
+{
+ int argc;
+ static char args[10]; /* For merged arguments */
+
+ argv[0] = shellName;
+ argc = 1;
+
+ if ((commandShell->exit && (*commandShell->exit != '-')) ||
+ (commandShell->echo && (*commandShell->echo != '-')))
+ {
+ /*
+ * At least one of the flags doesn't have a minus before it, so
+ * merge them together. Have to do this because the *(&(@*#*&#$#
+ * Bourne shell thinks its second argument is a file to source.
+ * Grrrr. Note the ten-character limitation on the combined arguments.
+ */
+ (void)sprintf(args, "-%s%s",
+ ((job->flags & JOB_IGNERR) ? "" :
+ (commandShell->exit ? commandShell->exit : "")),
+ ((job->flags & JOB_SILENT) ? "" :
+ (commandShell->echo ? commandShell->echo : "")));
+
+ if (args[1]) {
+ argv[argc] = args;
+ argc++;
+ }
+ } else {
+ if (!(job->flags & JOB_IGNERR) && commandShell->exit) {
+ argv[argc] = commandShell->exit;
+ argc++;
+ }
+ if (!(job->flags & JOB_SILENT) && commandShell->echo) {
+ argv[argc] = commandShell->echo;
+ argc++;
+ }
+ }
+ argv[argc] = NULL;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobRestart --
+ * Restart a job that stopped for some reason.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * jobFull will be set if the job couldn't be run.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobRestart(job)
+ Job *job; /* Job to restart */
+{
+#ifdef REMOTE
+ int host;
+#endif
+
+ if (job->flags & JOB_REMIGRATE) {
+ if (
+#ifdef REMOTE
+ verboseRemigrates ||
+#endif
+ DEBUG(JOB)) {
+ (void) fprintf(stdout, "*** remigrating %x(%s)\n",
+ job->pid, job->node->name);
+ (void) fflush(stdout);
+ }
+
+#ifdef REMOTE
+ if (!Rmt_ReExport(job->pid, job->node, &host)) {
+ if (verboseRemigrates || DEBUG(JOB)) {
+ (void) fprintf(stdout, "*** couldn't migrate...\n");
+ (void) fflush(stdout);
+ }
+#endif
+ if (nLocal != maxLocal) {
+ /*
+ * Job cannot be remigrated, but there's room on the local
+ * machine, so resume the job and note that another
+ * local job has started.
+ */
+ if (
+#ifdef REMOTE
+ verboseRemigrates ||
+#endif
+ DEBUG(JOB)) {
+ (void) fprintf(stdout, "*** resuming on local machine\n");
+ (void) fflush(stdout);
+ }
+ KILL(job->pid, SIGCONT);
+ nLocal +=1;
+#ifdef REMOTE
+ job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE);
+ job->flags |= JOB_CONTINUING;
+#else
+ job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
+#endif
+ } else {
+ /*
+ * Job cannot be restarted. Mark the table as full and
+ * place the job back on the list of stopped jobs.
+ */
+ if (
+#ifdef REMOTE
+ verboseRemigrates ||
+#endif
+ DEBUG(JOB)) {
+ (void) fprintf(stdout, "*** holding\n");
+ (void) fflush(stdout);
+ }
+ (void)Lst_AtFront(stoppedJobs, (ClientData)job);
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ return;
+ }
+#ifdef REMOTE
+ } else {
+ /*
+ * Clear out the remigrate and resume flags. Set the continuing
+ * flag so we know later on that the process isn't exiting just
+ * because of a signal.
+ */
+ job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
+ job->flags |= JOB_CONTINUING;
+ job->rmtID = host;
+ }
+#endif
+
+ (void)Lst_AtEnd(jobs, (ClientData)job);
+ nJobs += 1;
+ if (nJobs == maxJobs) {
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ }
+ } else if (job->flags & JOB_RESTART) {
+ /*
+ * Set up the control arguments to the shell. This is based on the
+ * flags set earlier for this job. If the JOB_IGNERR flag is clear,
+ * the 'exit' flag of the commandShell is used to cause it to exit
+ * upon receiving an error. If the JOB_SILENT flag is clear, the
+ * 'echo' flag of the commandShell is used to get it to start echoing
+ * as soon as it starts processing commands.
+ */
+ char *argv[4];
+
+ JobMakeArgv(job, argv);
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Restarting %s...", job->node->name);
+ (void) fflush(stdout);
+ }
+#ifdef REMOTE
+ if ((job->node->type&OP_NOEXPORT) ||
+ (nLocal < maxLocal && runLocalFirst)
+# ifdef RMT_NO_EXEC
+ || !Rmt_Export(shellPath, argv, job)
+# else
+ || !Rmt_Begin(shellPath, argv, job->node)
+# endif
+#endif
+ {
+ if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) {
+ /*
+ * Can't be exported and not allowed to run locally -- put it
+ * back on the hold queue and mark the table full
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "holding\n");
+ (void) fflush(stdout);
+ }
+ (void)Lst_AtFront(stoppedJobs, (ClientData)job);
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ return;
+ } else {
+ /*
+ * Job may be run locally.
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "running locally\n");
+ (void) fflush(stdout);
+ }
+ job->flags &= ~JOB_REMOTE;
+ }
+ }
+#ifdef REMOTE
+ else {
+ /*
+ * Can be exported. Hooray!
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "exporting\n");
+ (void) fflush(stdout);
+ }
+ job->flags |= JOB_REMOTE;
+ }
+#endif
+ JobExec(job, argv);
+ } else {
+ /*
+ * The job has stopped and needs to be restarted. Why it stopped,
+ * we don't know...
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Resuming %s...", job->node->name);
+ (void) fflush(stdout);
+ }
+ if (((job->flags & JOB_REMOTE) ||
+ (nLocal < maxLocal) ||
+#ifdef REMOTE
+ (((job->flags & JOB_SPECIAL) &&
+ (job->node->type & OP_NOEXPORT)) &&
+ (maxLocal == 0))) &&
+#else
+ ((job->flags & JOB_SPECIAL) &&
+ (maxLocal == 0))) &&
+#endif
+ (nJobs != maxJobs))
+ {
+ /*
+ * If the job is remote, it's ok to resume it as long as the
+ * maximum concurrency won't be exceeded. If it's local and
+ * we haven't reached the local concurrency limit already (or the
+ * job must be run locally and maxLocal is 0), it's also ok to
+ * resume it.
+ */
+ Boolean error;
+ extern int errno;
+ int status;
+
+#ifdef RMT_WANTS_SIGNALS
+ if (job->flags & JOB_REMOTE) {
+ error = !Rmt_Signal(job, SIGCONT);
+ } else
+#endif /* RMT_WANTS_SIGNALS */
+ error = (KILL(job->pid, SIGCONT) != 0);
+
+ if (!error) {
+ /*
+ * Make sure the user knows we've continued the beast and
+ * actually put the thing in the job table.
+ */
+ job->flags |= JOB_CONTINUING;
+ W_SETTERMSIG(&status, SIGCONT);
+ JobFinish(job, &status);
+
+ job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "done\n");
+ (void) fflush(stdout);
+ }
+ } else {
+ Error("couldn't resume %s: %s",
+ job->node->name, strerror(errno));
+ status = 0;
+ W_SETEXITSTATUS(&status, 1);
+ JobFinish(job, &status);
+ }
+ } else {
+ /*
+ * Job cannot be restarted. Mark the table as full and
+ * place the job back on the list of stopped jobs.
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "table full\n");
+ (void) fflush(stdout);
+ }
+ (void) Lst_AtFront(stoppedJobs, (ClientData)job);
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobStart --
+ * Start a target-creation process going for the target described
+ * by the graph node gn.
+ *
+ * Results:
+ * JOB_ERROR if there was an error in the commands, JOB_FINISHED
+ * if there isn't actually anything left to do for the job and
+ * JOB_RUNNING if the job has been started.
+ *
+ * Side Effects:
+ * A new Job node is created and added to the list of running
+ * jobs. PMake is forked and a child shell created.
+ *-----------------------------------------------------------------------
+ */
+static int
+JobStart(gn, flags, previous)
+ GNode *gn; /* target to create */
+ int flags; /* flags for the job to override normal ones.
+ * e.g. JOB_SPECIAL or JOB_IGNDOTS */
+ Job *previous; /* The previous Job structure for this node,
+ * if any. */
+{
+ register Job *job; /* new job descriptor */
+ char *argv[4]; /* Argument vector to shell */
+ static int jobno = 0; /* job number of catching output in a file */
+ Boolean cmdsOK; /* true if the nodes commands were all right */
+ Boolean local; /* Set true if the job was run locally */
+ Boolean noExec; /* Set true if we decide not to run the job */
+
+ if (previous != NULL) {
+ previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
+ job = previous;
+ } else {
+ job = (Job *) emalloc(sizeof(Job));
+ if (job == NULL) {
+ Punt("JobStart out of memory");
+ }
+ flags |= JOB_FIRST;
+ }
+
+ job->node = gn;
+ job->tailCmds = NILLNODE;
+
+ /*
+ * Set the initial value of the flags for this job based on the global
+ * ones and the node's attributes... Any flags supplied by the caller
+ * are also added to the field.
+ */
+ job->flags = 0;
+ if (Targ_Ignore(gn)) {
+ job->flags |= JOB_IGNERR;
+ }
+ if (Targ_Silent(gn)) {
+ job->flags |= JOB_SILENT;
+ }
+ job->flags |= flags;
+
+ /*
+ * Check the commands now so any attributes from .DEFAULT have a chance
+ * to migrate to the node
+ */
+ if (!compatMake && job->flags & JOB_FIRST) {
+ cmdsOK = Job_CheckCommands(gn, Error);
+ } else {
+ cmdsOK = TRUE;
+ }
+
+ /*
+ * If the -n flag wasn't given, we open up OUR (not the child's)
+ * temporary file to stuff commands in it. The thing is rd/wr so we don't
+ * need to reopen it to feed it to the shell. If the -n flag *was* given,
+ * we just set the file to be stdout. Cute, huh?
+ */
+ if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {
+ /*
+ * We're serious here, but if the commands were bogus, we're
+ * also dead...
+ */
+ if (!cmdsOK) {
+ DieHorribly();
+ }
+
+ job->cmdFILE = fopen(tfile, "w+");
+ if (job->cmdFILE == NULL) {
+ Punt("Could not open %s", tfile);
+ }
+ (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1);
+ /*
+ * Send the commands to the command file, flush all its buffers then
+ * rewind and remove the thing.
+ */
+ noExec = FALSE;
+
+ /*
+ * used to be backwards; replace when start doing multiple commands
+ * per shell.
+ */
+ if (compatMake) {
+ /*
+ * Be compatible: If this is the first time for this node,
+ * verify its commands are ok and open the commands list for
+ * sequential access by later invocations of JobStart.
+ * Once that is done, we take the next command off the list
+ * and print it to the command file. If the command was an
+ * ellipsis, note that there's nothing more to execute.
+ */
+ if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){
+ cmdsOK = FALSE;
+ } else {
+ LstNode ln = Lst_Next(gn->commands);
+
+ if ((ln == NILLNODE) ||
+ JobPrintCommand((ClientData) Lst_Datum(ln),
+ (ClientData) job))
+ {
+ noExec = TRUE;
+ Lst_Close(gn->commands);
+ }
+ if (noExec && !(job->flags & JOB_FIRST)) {
+ /*
+ * If we're not going to execute anything, the job
+ * is done and we need to close down the various
+ * file descriptors we've opened for output, then
+ * call JobDoOutput to catch the final characters or
+ * send the file to the screen... Note that the i/o streams
+ * are only open if this isn't the first job.
+ * Note also that this could not be done in
+ * Job_CatchChildren b/c it wasn't clear if there were
+ * more commands to execute or not...
+ */
+ JobClose(job);
+ }
+ }
+ } else {
+ /*
+ * We can do all the commands at once. hooray for sanity
+ */
+ numCommands = 0;
+ Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
+
+ /*
+ * If we didn't print out any commands to the shell script,
+ * there's not much point in executing the shell, is there?
+ */
+ if (numCommands == 0) {
+ noExec = TRUE;
+ }
+ }
+ } else if (noExecute) {
+ /*
+ * Not executing anything -- just print all the commands to stdout
+ * in one fell swoop. This will still set up job->tailCmds correctly.
+ */
+ if (lastNode != gn) {
+ MESSAGE(stdout, gn);
+ lastNode = gn;
+ }
+ job->cmdFILE = stdout;
+ /*
+ * Only print the commands if they're ok, but don't die if they're
+ * not -- just let the user know they're bad and keep going. It
+ * doesn't do any harm in this case and may do some good.
+ */
+ if (cmdsOK) {
+ Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
+ }
+ /*
+ * Don't execute the shell, thank you.
+ */
+ noExec = TRUE;
+ } else {
+ /*
+ * Just touch the target and note that no shell should be executed.
+ * Set cmdFILE to stdout to make life easier. Check the commands, too,
+ * but don't die if they're no good -- it does no harm to keep working
+ * up the graph.
+ */
+ job->cmdFILE = stdout;
+ Job_Touch(gn, job->flags&JOB_SILENT);
+ noExec = TRUE;
+ }
+
+ /*
+ * If we're not supposed to execute a shell, don't.
+ */
+ if (noExec) {
+ /*
+ * Unlink and close the command file if we opened one
+ */
+ if (job->cmdFILE != stdout) {
+ (void) eunlink(tfile);
+ if (job->cmdFILE != NULL)
+ (void) fclose(job->cmdFILE);
+ } else {
+ (void) fflush(stdout);
+ }
+
+ /*
+ * We only want to work our way up the graph if we aren't here because
+ * the commands for the job were no good.
+ */
+ if (cmdsOK) {
+ if (aborting == 0) {
+ if (job->tailCmds != NILLNODE) {
+ Lst_ForEachFrom(job->node->commands, job->tailCmds,
+ JobSaveCommand,
+ (ClientData)job->node);
+ }
+ Make_Update(job->node);
+ }
+ free((Address)job);
+ return(JOB_FINISHED);
+ } else {
+ free((Address)job);
+ return(JOB_ERROR);
+ }
+ } else {
+ (void) fflush(job->cmdFILE);
+ (void) eunlink(tfile);
+ }
+
+ /*
+ * Set up the control arguments to the shell. This is based on the flags
+ * set earlier for this job.
+ */
+ JobMakeArgv(job, argv);
+
+ /*
+ * If we're using pipes to catch output, create the pipe by which we'll
+ * get the shell's output. If we're using files, print out that we're
+ * starting a job and then set up its temporary-file name. This is just
+ * tfile with two extra digits tacked on -- jobno.
+ */
+ if (!compatMake || (job->flags & JOB_FIRST)) {
+ if (usePipes) {
+ int fd[2];
+ if (pipe(fd) == -1)
+ Punt("Cannot create pipe: %s", strerror(errno));
+ job->inPipe = fd[0];
+ job->outPipe = fd[1];
+ (void) fcntl(job->inPipe, F_SETFD, 1);
+ (void) fcntl(job->outPipe, F_SETFD, 1);
+ } else {
+ (void) fprintf(stdout, "Remaking `%s'\n", gn->name);
+ (void) fflush(stdout);
+ sprintf(job->outFile, "%s%02d", tfile, jobno);
+ jobno = (jobno + 1) % 100;
+ job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);
+ (void) fcntl(job->outFd, F_SETFD, 1);
+ }
+ }
+
+#ifdef REMOTE
+ if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) {
+#ifdef RMT_NO_EXEC
+ local = !Rmt_Export(shellPath, argv, job);
+#else
+ local = !Rmt_Begin(shellPath, argv, job->node);
+#endif /* RMT_NO_EXEC */
+ if (!local) {
+ job->flags |= JOB_REMOTE;
+ }
+ } else
+#endif
+ local = TRUE;
+
+ if (local && (((nLocal >= maxLocal) &&
+ !(job->flags & JOB_SPECIAL) &&
+#ifdef REMOTE
+ (!(gn->type & OP_NOEXPORT) || (maxLocal != 0))
+#else
+ (maxLocal != 0)
+#endif
+ )))
+ {
+ /*
+ * The job can only be run locally, but we've hit the limit of
+ * local concurrency, so put the job on hold until some other job
+ * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)
+ * may be run locally even when the local limit has been reached
+ * (e.g. when maxLocal == 0), though they will be exported if at
+ * all possible. In addition, any target marked with .NOEXPORT will
+ * be run locally if maxLocal is 0.
+ */
+ jobFull = TRUE;
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Can only run job locally.\n");
+ (void) fflush(stdout);
+ }
+ job->flags |= JOB_RESTART;
+ (void) Lst_AtEnd(stoppedJobs, (ClientData)job);
+ } else {
+ if ((nLocal >= maxLocal) && local) {
+ /*
+ * If we're running this job locally as a special case (see above),
+ * at least say the table is full.
+ */
+ jobFull = TRUE;
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Local job queue is full.\n");
+ (void) fflush(stdout);
+ }
+ }
+ JobExec(job, argv);
+ }
+ return(JOB_RUNNING);
+}
+
+static char *
+JobOutput(job, cp, endp, msg)
+ register Job *job;
+ register char *cp, *endp;
+ int msg;
+{
+ register char *ecp;
+
+ if (commandShell->noPrint) {
+ ecp = Str_FindSubstring(cp, commandShell->noPrint);
+ while (ecp != NULL) {
+ if (cp != ecp) {
+ *ecp = '\0';
+ if (msg && job->node != lastNode) {
+ MESSAGE(stdout, job->node);
+ lastNode = job->node;
+ }
+ /*
+ * The only way there wouldn't be a newline after
+ * this line is if it were the last in the buffer.
+ * however, since the non-printable comes after it,
+ * there must be a newline, so we don't print one.
+ */
+ (void) fprintf(stdout, "%s", cp);
+ (void) fflush(stdout);
+ }
+ cp = ecp + commandShell->noPLen;
+ if (cp != endp) {
+ /*
+ * Still more to print, look again after skipping
+ * the whitespace following the non-printable
+ * command....
+ */
+ cp++;
+ while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
+ cp++;
+ }
+ ecp = Str_FindSubstring(cp, commandShell->noPrint);
+ } else {
+ return cp;
+ }
+ }
+ }
+ return cp;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobDoOutput --
+ * This function is called at different times depending on
+ * whether the user has specified that output is to be collected
+ * via pipes or temporary files. In the former case, we are called
+ * whenever there is something to read on the pipe. We collect more
+ * output from the given job and store it in the job's outBuf. If
+ * this makes up a line, we print it tagged by the job's identifier,
+ * as necessary.
+ * If output has been collected in a temporary file, we open the
+ * file and read it line by line, transfering it to our own
+ * output channel until the file is empty. At which point we
+ * remove the temporary file.
+ * In both cases, however, we keep our figurative eye out for the
+ * 'noPrint' line for the shell from which the output came. If
+ * we recognize a line, we don't print it. If the command is not
+ * alone on the line (the character after it is not \0 or \n), we
+ * do print whatever follows it.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * curPos may be shifted as may the contents of outBuf.
+ *-----------------------------------------------------------------------
+ */
+STATIC void
+JobDoOutput(job, finish)
+ register Job *job; /* the job whose output needs printing */
+ Boolean finish; /* TRUE if this is the last time we'll be
+ * called for this job */
+{
+ Boolean gotNL = FALSE; /* true if got a newline */
+ Boolean fbuf; /* true if our buffer filled up */
+ register int nr; /* number of bytes read */
+ register int i; /* auxiliary index into outBuf */
+ register int max; /* limit for i (end of current data) */
+ int nRead; /* (Temporary) number of bytes read */
+
+ FILE *oFILE; /* Stream pointer to shell's output file */
+ char inLine[132];
+
+
+ if (usePipes) {
+ /*
+ * Read as many bytes as will fit in the buffer.
+ */
+end_loop:
+ gotNL = FALSE;
+ fbuf = FALSE;
+
+ nRead = read(job->inPipe, &job->outBuf[job->curPos],
+ JOB_BUFSIZE - job->curPos);
+ if (nRead < 0) {
+ if (DEBUG(JOB)) {
+ perror("JobDoOutput(piperead)");
+ }
+ nr = 0;
+ } else {
+ nr = nRead;
+ }
+
+ /*
+ * If we hit the end-of-file (the job is dead), we must flush its
+ * remaining output, so pretend we read a newline if there's any
+ * output remaining in the buffer.
+ * Also clear the 'finish' flag so we stop looping.
+ */
+ if ((nr == 0) && (job->curPos != 0)) {
+ job->outBuf[job->curPos] = '\n';
+ nr = 1;
+ finish = FALSE;
+ } else if (nr == 0) {
+ finish = FALSE;
+ }
+
+ /*
+ * Look for the last newline in the bytes we just got. If there is
+ * one, break out of the loop with 'i' as its index and gotNL set
+ * TRUE.
+ */
+ max = job->curPos + nr;
+ for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
+ if (job->outBuf[i] == '\n') {
+ gotNL = TRUE;
+ break;
+ } else if (job->outBuf[i] == '\0') {
+ /*
+ * Why?
+ */
+ job->outBuf[i] = ' ';
+ }
+ }
+
+ if (!gotNL) {
+ job->curPos += nr;
+ if (job->curPos == JOB_BUFSIZE) {
+ /*
+ * If we've run out of buffer space, we have no choice
+ * but to print the stuff. sigh.
+ */
+ fbuf = TRUE;
+ i = job->curPos;
+ }
+ }
+ if (gotNL || fbuf) {
+ /*
+ * Need to send the output to the screen. Null terminate it
+ * first, overwriting the newline character if there was one.
+ * So long as the line isn't one we should filter (according
+ * to the shell description), we print the line, preceeded
+ * by a target banner if this target isn't the same as the
+ * one for which we last printed something.
+ * The rest of the data in the buffer are then shifted down
+ * to the start of the buffer and curPos is set accordingly.
+ */
+ job->outBuf[i] = '\0';
+ if (i >= job->curPos) {
+ char *cp;
+
+ cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE);
+
+ /*
+ * There's still more in that thar buffer. This time, though,
+ * we know there's no newline at the end, so we add one of
+ * our own free will.
+ */
+ if (*cp != '\0') {
+ if (job->node != lastNode) {
+ MESSAGE(stdout, job->node);
+ lastNode = job->node;
+ }
+ (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
+ (void) fflush(stdout);
+ }
+ }
+ if (i < max - 1) {
+ /* shift the remaining characters down */
+ (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
+ job->curPos = max - (i + 1);
+
+ } else {
+ /*
+ * We have written everything out, so we just start over
+ * from the start of the buffer. No copying. No nothing.
+ */
+ job->curPos = 0;
+ }
+ }
+ if (finish) {
+ /*
+ * If the finish flag is true, we must loop until we hit
+ * end-of-file on the pipe. This is guaranteed to happen
+ * eventually since the other end of the pipe is now closed
+ * (we closed it explicitly and the child has exited). When
+ * we do get an EOF, finish will be set FALSE and we'll fall
+ * through and out.
+ */
+ goto end_loop;
+ }
+ } else {
+ /*
+ * We've been called to retrieve the output of the job from the
+ * temporary file where it's been squirreled away. This consists of
+ * opening the file, reading the output line by line, being sure not
+ * to print the noPrint line for the shell we used, then close and
+ * remove the temporary file. Very simple.
+ *
+ * Change to read in blocks and do FindSubString type things as for
+ * pipes? That would allow for "@echo -n..."
+ */
+ oFILE = fopen(job->outFile, "r");
+ if (oFILE != NULL) {
+ (void) fprintf(stdout, "Results of making %s:\n", job->node->name);
+ (void) fflush(stdout);
+ while (fgets(inLine, sizeof(inLine), oFILE) != NULL) {
+ register char *cp, *endp, *oendp;
+
+ cp = inLine;
+ oendp = endp = inLine + strlen(inLine);
+ if (endp[-1] == '\n') {
+ *--endp = '\0';
+ }
+ cp = JobOutput(job, inLine, endp, FALSE);
+
+ /*
+ * There's still more in that thar buffer. This time, though,
+ * we know there's no newline at the end, so we add one of
+ * our own free will.
+ */
+ (void) fprintf(stdout, "%s", cp);
+ (void) fflush(stdout);
+ if (endp != oendp) {
+ (void) fprintf(stdout, "\n");
+ (void) fflush(stdout);
+ }
+ }
+ (void) fclose(oFILE);
+ (void) eunlink(job->outFile);
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_CatchChildren --
+ * Handle the exit of a child. Called from Make_Make.
+ *
+ * Results:
+ * none.
+ *
+ * Side Effects:
+ * The job descriptor is removed from the list of children.
+ *
+ * Notes:
+ * We do waits, blocking or not, according to the wisdom of our
+ * caller, until there are no more children to report. For each
+ * job, call JobFinish to finish things off. This will take care of
+ * putting jobs on the stoppedJobs queue.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Job_CatchChildren(block)
+ Boolean block; /* TRUE if should block on the wait. */
+{
+ int pid; /* pid of dead child */
+ register Job *job; /* job descriptor for dead child */
+ LstNode jnode; /* list element for finding job */
+ int status; /* Exit/termination status */
+
+ /*
+ * Don't even bother if we know there's no one around.
+ */
+ if (nLocal == 0) {
+ return;
+ }
+
+ while ((pid = waitpid((pid_t) -1, &status,
+ (block?0:WNOHANG)|WUNTRACED)) > 0)
+ {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "Process %d exited or stopped.\n", pid);
+ (void) fflush(stdout);
+ }
+
+
+ jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid);
+
+ if (jnode == NILLNODE) {
+ if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) {
+ jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);
+ if (jnode == NILLNODE) {
+ Error("Resumed child (%d) not in table", pid);
+ continue;
+ }
+ job = (Job *)Lst_Datum(jnode);
+ (void) Lst_Remove(stoppedJobs, jnode);
+ } else {
+ Error("Child (%d) not in table?", pid);
+ continue;
+ }
+ } else {
+ job = (Job *) Lst_Datum(jnode);
+ (void) Lst_Remove(jobs, jnode);
+ nJobs -= 1;
+ if (jobFull && DEBUG(JOB)) {
+ (void) fprintf(stdout, "Job queue is no longer full.\n");
+ (void) fflush(stdout);
+ }
+ jobFull = FALSE;
+#ifdef REMOTE
+ if (!(job->flags & JOB_REMOTE)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "Job queue has one fewer local process.\n");
+ (void) fflush(stdout);
+ }
+ nLocal -= 1;
+ }
+#else
+ nLocal -= 1;
+#endif
+ }
+
+ JobFinish(job, &status);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_CatchOutput --
+ * Catch the output from our children, if we're using
+ * pipes do so. Otherwise just block time until we get a
+ * signal (most likely a SIGCHLD) since there's no point in
+ * just spinning when there's nothing to do and the reaping
+ * of a child can wait for a while.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Output is read from pipes if we're piping.
+ * -----------------------------------------------------------------------
+ */
+void
+Job_CatchOutput()
+{
+ int nfds;
+ struct timeval timeout;
+ fd_set readfds;
+ register LstNode ln;
+ register Job *job;
+#ifdef RMT_WILL_WATCH
+ int pnJobs; /* Previous nJobs */
+#endif
+
+ (void) fflush(stdout);
+#ifdef RMT_WILL_WATCH
+ pnJobs = nJobs;
+
+ /*
+ * It is possible for us to be called with nJobs equal to 0. This happens
+ * if all the jobs finish and a job that is stopped cannot be run
+ * locally (eg if maxLocal is 0) and cannot be exported. The job will
+ * be placed back on the stoppedJobs queue, Job_Empty() will return false,
+ * Make_Run will call us again when there's nothing for which to wait.
+ * nJobs never changes, so we loop forever. Hence the check. It could
+ * be argued that we should sleep for a bit so as not to swamp the
+ * exportation system with requests. Perhaps we should.
+ *
+ * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren
+ * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.
+ * It may use the variable nLocal to determine if it needs to call
+ * Job_CatchChildren (if nLocal is 0, there's nothing for which to
+ * wait...)
+ */
+ while (nJobs != 0 && pnJobs == nJobs) {
+ Rmt_Wait();
+ }
+#else
+ if (usePipes) {
+ readfds = outputs;
+ timeout.tv_sec = SEL_SEC;
+ timeout.tv_usec = SEL_USEC;
+
+ if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0,
+ (fd_set *) 0, &timeout)) <= 0)
+ return;
+ else {
+ if (Lst_Open(jobs) == FAILURE) {
+ Punt("Cannot open job table");
+ }
+ while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) {
+ job = (Job *) Lst_Datum(ln);
+ if (FD_ISSET(job->inPipe, &readfds)) {
+ JobDoOutput(job, FALSE);
+ nfds -= 1;
+ }
+ }
+ Lst_Close(jobs);
+ }
+ }
+#endif /* RMT_WILL_WATCH */
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Make --
+ * Start the creation of a target. Basically a front-end for
+ * JobStart used by the Make module.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Another job is started.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Job_Make(gn)
+ GNode *gn;
+{
+ (void) JobStart(gn, 0, NULL);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Init --
+ * Initialize the process module
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * lists and counters are initialized
+ *-----------------------------------------------------------------------
+ */
+void
+Job_Init(maxproc, maxlocal)
+ int maxproc; /* the greatest number of jobs which may be
+ * running at one time */
+ int maxlocal; /* the greatest number of local jobs which may
+ * be running at once. */
+{
+ GNode *begin; /* node for commands to do at the very start */
+
+ (void) sprintf(tfile, "/tmp/make%05d", getpid());
+
+ jobs = Lst_Init(FALSE);
+ stoppedJobs = Lst_Init(FALSE);
+ maxJobs = maxproc;
+ maxLocal = maxlocal;
+ nJobs = 0;
+ nLocal = 0;
+ jobFull = FALSE;
+
+ aborting = 0;
+ errors = 0;
+
+ lastNode = NILGNODE;
+
+ if (maxJobs == 1
+#ifdef REMOTE
+ || noMessages
+#endif
+ ) {
+ /*
+ * If only one job can run at a time, there's no need for a banner,
+ * no is there?
+ */
+ targFmt = "";
+ } else {
+ targFmt = TARG_FMT;
+ }
+
+ if (shellPath == NULL) {
+ /*
+ * The user didn't specify a shell to use, so we are using the
+ * default one... Both the absolute path and the last component
+ * must be set. The last component is taken from the 'name' field
+ * of the default shell description pointed-to by commandShell.
+ * All default shells are located in _PATH_DEFSHELLDIR.
+ */
+ shellName = commandShell->name;
+ shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
+ }
+
+ if (commandShell->exit == NULL) {
+ commandShell->exit = "";
+ }
+ if (commandShell->echo == NULL) {
+ commandShell->echo = "";
+ }
+
+ /*
+ * Catch the four signals that POSIX specifies if they aren't ignored.
+ * JobPassSig will take care of calling JobInterrupt if appropriate.
+ */
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGINT, JobPassSig);
+ }
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGHUP, JobPassSig);
+ }
+ if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGQUIT, JobPassSig);
+ }
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTERM, JobPassSig);
+ }
+ /*
+ * There are additional signals that need to be caught and passed if
+ * either the export system wants to be told directly of signals or if
+ * we're giving each job its own process group (since then it won't get
+ * signals from the terminal driver as we own the terminal)
+ */
+#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
+ if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTSTP, JobPassSig);
+ }
+ if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTTOU, JobPassSig);
+ }
+ if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTTIN, JobPassSig);
+ }
+ if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGWINCH, JobPassSig);
+ }
+#endif
+
+ begin = Targ_FindNode(".BEGIN", TARG_NOCREATE);
+
+ if (begin != NILGNODE) {
+ JobStart(begin, JOB_SPECIAL, (Job *)0);
+ while (nJobs) {
+ Job_CatchOutput();
+#ifndef RMT_WILL_WATCH
+ Job_CatchChildren(!usePipes);
+#endif /* RMT_WILL_WATCH */
+ }
+ }
+ postCommands = Targ_FindNode(".END", TARG_CREATE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Full --
+ * See if the job table is full. It is considered full if it is OR
+ * if we are in the process of aborting OR if we have
+ * reached/exceeded our local quota. This prevents any more jobs
+ * from starting up.
+ *
+ * Results:
+ * TRUE if the job table is full, FALSE otherwise
+ * Side Effects:
+ * None.
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Job_Full()
+{
+ return(aborting || jobFull);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Empty --
+ * See if the job table is empty. Because the local concurrency may
+ * be set to 0, it is possible for the job table to become empty,
+ * while the list of stoppedJobs remains non-empty. In such a case,
+ * we want to restart as many jobs as we can.
+ *
+ * Results:
+ * TRUE if it is. FALSE if it ain't.
+ *
+ * Side Effects:
+ * None.
+ *
+ * -----------------------------------------------------------------------
+ */
+Boolean
+Job_Empty()
+{
+ if (nJobs == 0) {
+ if (!Lst_IsEmpty(stoppedJobs) && !aborting) {
+ /*
+ * The job table is obviously not full if it has no jobs in
+ * it...Try and restart the stopped jobs.
+ */
+ jobFull = FALSE;
+ JobRestartJobs();
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+ } else {
+ return(FALSE);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobMatchShell --
+ * Find a matching shell in 'shells' given its final component.
+ *
+ * Results:
+ * A pointer to the Shell structure.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Shell *
+JobMatchShell(name)
+ char *name; /* Final component of shell path */
+{
+ register Shell *sh; /* Pointer into shells table */
+ Shell *match; /* Longest-matching shell */
+ register char *cp1,
+ *cp2;
+ char *eoname;
+
+ eoname = name + strlen(name);
+
+ match = NULL;
+
+ for (sh = shells; sh->name != NULL; sh++) {
+ for (cp1 = eoname - strlen(sh->name), cp2 = sh->name;
+ *cp1 != '\0' && *cp1 == *cp2;
+ cp1++, cp2++) {
+ continue;
+ }
+ if (*cp1 != *cp2) {
+ continue;
+ } else if (match == NULL || strlen(match->name) < strlen(sh->name)) {
+ match = sh;
+ }
+ }
+ return(match == NULL ? sh : match);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_ParseShell --
+ * Parse a shell specification and set up commandShell, shellPath
+ * and shellName appropriately.
+ *
+ * Results:
+ * FAILURE if the specification was incorrect.
+ *
+ * Side Effects:
+ * commandShell points to a Shell structure (either predefined or
+ * created from the shell spec), shellPath is the full path of the
+ * shell described by commandShell, while shellName is just the
+ * final component of shellPath.
+ *
+ * Notes:
+ * A shell specification consists of a .SHELL target, with dependency
+ * operator, followed by a series of blank-separated words. Double
+ * quotes can be used to use blanks in words. A backslash escapes
+ * anything (most notably a double-quote and a space) and
+ * provides the functionality it does in C. Each word consists of
+ * keyword and value separated by an equal sign. There should be no
+ * unnecessary spaces in the word. The keywords are as follows:
+ * name Name of shell.
+ * path Location of shell. Overrides "name" if given
+ * quiet Command to turn off echoing.
+ * echo Command to turn echoing on
+ * filter Result of turning off echoing that shouldn't be
+ * printed.
+ * echoFlag Flag to turn echoing on at the start
+ * errFlag Flag to turn error checking on at the start
+ * hasErrCtl True if shell has error checking control
+ * check Command to turn on error checking if hasErrCtl
+ * is TRUE or template of command to echo a command
+ * for which error checking is off if hasErrCtl is
+ * FALSE.
+ * ignore Command to turn off error checking if hasErrCtl
+ * is TRUE or template of command to execute a
+ * command so as to ignore any errors it returns if
+ * hasErrCtl is FALSE.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Job_ParseShell(line)
+ char *line; /* The shell spec */
+{
+ char **words;
+ int wordCount;
+ register char **argv;
+ register int argc;
+ char *path;
+ Shell newShell;
+ Boolean fullSpec = FALSE;
+
+ while (isspace(*line)) {
+ line++;
+ }
+ words = brk_string(line, &wordCount, TRUE);
+
+ memset((Address)&newShell, 0, sizeof(newShell));
+
+ /*
+ * Parse the specification by keyword
+ */
+ for (path = NULL, argc = wordCount - 1, argv = words + 1;
+ argc != 0;
+ argc--, argv++) {
+ if (strncmp(*argv, "path=", 5) == 0) {
+ path = &argv[0][5];
+ } else if (strncmp(*argv, "name=", 5) == 0) {
+ newShell.name = &argv[0][5];
+ } else {
+ if (strncmp(*argv, "quiet=", 6) == 0) {
+ newShell.echoOff = &argv[0][6];
+ } else if (strncmp(*argv, "echo=", 5) == 0) {
+ newShell.echoOn = &argv[0][5];
+ } else if (strncmp(*argv, "filter=", 7) == 0) {
+ newShell.noPrint = &argv[0][7];
+ newShell.noPLen = strlen(newShell.noPrint);
+ } else if (strncmp(*argv, "echoFlag=", 9) == 0) {
+ newShell.echo = &argv[0][9];
+ } else if (strncmp(*argv, "errFlag=", 8) == 0) {
+ newShell.exit = &argv[0][8];
+ } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) {
+ char c = argv[0][10];
+ newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
+ (c != 'T') && (c != 't'));
+ } else if (strncmp(*argv, "check=", 6) == 0) {
+ newShell.errCheck = &argv[0][6];
+ } else if (strncmp(*argv, "ignore=", 7) == 0) {
+ newShell.ignErr = &argv[0][7];
+ } else {
+ Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"",
+ *argv);
+ return(FAILURE);
+ }
+ fullSpec = TRUE;
+ }
+ }
+
+ if (path == NULL) {
+ /*
+ * If no path was given, the user wants one of the pre-defined shells,
+ * yes? So we find the one s/he wants with the help of JobMatchShell
+ * and set things up the right way. shellPath will be set up by
+ * Job_Init.
+ */
+ if (newShell.name == NULL) {
+ Parse_Error(PARSE_FATAL, "Neither path nor name specified");
+ return(FAILURE);
+ } else {
+ commandShell = JobMatchShell(newShell.name);
+ shellName = newShell.name;
+ }
+ } else {
+ /*
+ * The user provided a path. If s/he gave nothing else (fullSpec is
+ * FALSE), try and find a matching shell in the ones we know of.
+ * Else we just take the specification at its word and copy it
+ * to a new location. In either case, we need to record the
+ * path the user gave for the shell.
+ */
+ shellPath = path;
+ path = strrchr(path, '/');
+ if (path == NULL) {
+ path = shellPath;
+ } else {
+ path += 1;
+ }
+ if (newShell.name != NULL) {
+ shellName = newShell.name;
+ } else {
+ shellName = path;
+ }
+ if (!fullSpec) {
+ commandShell = JobMatchShell(shellName);
+ } else {
+ commandShell = (Shell *) emalloc(sizeof(Shell));
+ *commandShell = newShell;
+ }
+ }
+
+ if (commandShell->echoOn && commandShell->echoOff) {
+ commandShell->hasEchoCtl = TRUE;
+ }
+
+ if (!commandShell->hasErrCtl) {
+ if (commandShell->errCheck == NULL) {
+ commandShell->errCheck = "";
+ }
+ if (commandShell->ignErr == NULL) {
+ commandShell->ignErr = "%s\n";
+ }
+ }
+
+ /*
+ * Do not free up the words themselves, since they might be in use by the
+ * shell specification...
+ */
+ free(words);
+ return SUCCESS;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobInterrupt --
+ * Handle the receipt of an interrupt.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * All children are killed. Another job will be started if the
+ * .INTERRUPT target was given.
+ *-----------------------------------------------------------------------
+ */
+static void
+JobInterrupt(runINTERRUPT, signo)
+ int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT
+ * target should be executed */
+ int signo; /* signal received */
+{
+ LstNode ln; /* element in job table */
+ Job *job; /* job descriptor in that element */
+ GNode *interrupt; /* the node describing the .INTERRUPT target */
+
+ aborting = ABORT_INTERRUPT;
+
+ (void) Lst_Open(jobs);
+ while ((ln = Lst_Next(jobs)) != NILLNODE) {
+ job = (Job *) Lst_Datum(ln);
+
+ if (!Targ_Precious(job->node)) {
+ char *file = (job->node->path == NULL ?
+ job->node->name :
+ job->node->path);
+ if (!noExecute && eunlink(file) != -1) {
+ Error("*** %s removed", file);
+ }
+ }
+#ifdef RMT_WANTS_SIGNALS
+ if (job->flags & JOB_REMOTE) {
+ /*
+ * If job is remote, let the Rmt module do the killing.
+ */
+ if (!Rmt_Signal(job, signo)) {
+ /*
+ * If couldn't kill the thing, finish it out now with an
+ * error code, since no exit report will come in likely.
+ */
+ int status;
+
+ status.w_status = 0;
+ status.w_retcode = 1;
+ JobFinish(job, &status);
+ }
+ } else if (job->pid) {
+ KILL(job->pid, signo);
+ }
+#else
+ if (job->pid) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobInterrupt passing signal to child %d.\n",
+ job->pid);
+ (void) fflush(stdout);
+ }
+ KILL(job->pid, signo);
+ }
+#endif /* RMT_WANTS_SIGNALS */
+ }
+
+#ifdef REMOTE
+ (void)Lst_Open(stoppedJobs);
+ while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) {
+ job = (Job *) Lst_Datum(ln);
+
+ if (job->flags & JOB_RESTART) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "%s%s",
+ "JobInterrupt skipping job on stopped queue",
+ "-- it was waiting to be restarted.\n");
+ (void) fflush(stdout);
+ }
+ continue;
+ }
+ if (!Targ_Precious(job->node)) {
+ char *file = (job->node->path == NULL ?
+ job->node->name :
+ job->node->path);
+ if (eunlink(file) == 0) {
+ Error("*** %s removed", file);
+ }
+ }
+ /*
+ * Resume the thing so it will take the signal.
+ */
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobInterrupt passing CONT to stopped child %d.\n",
+ job->pid);
+ (void) fflush(stdout);
+ }
+ KILL(job->pid, SIGCONT);
+#ifdef RMT_WANTS_SIGNALS
+ if (job->flags & JOB_REMOTE) {
+ /*
+ * If job is remote, let the Rmt module do the killing.
+ */
+ if (!Rmt_Signal(job, SIGINT)) {
+ /*
+ * If couldn't kill the thing, finish it out now with an
+ * error code, since no exit report will come in likely.
+ */
+ int status;
+ status.w_status = 0;
+ status.w_retcode = 1;
+ JobFinish(job, &status);
+ }
+ } else if (job->pid) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobInterrupt passing interrupt to stopped child %d.\n",
+ job->pid);
+ (void) fflush(stdout);
+ }
+ KILL(job->pid, SIGINT);
+ }
+#endif /* RMT_WANTS_SIGNALS */
+ }
+#endif
+ Lst_Close(stoppedJobs);
+
+ if (runINTERRUPT && !touchFlag) {
+ interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
+ if (interrupt != NILGNODE) {
+ ignoreErrors = FALSE;
+
+ JobStart(interrupt, JOB_IGNDOTS, (Job *)0);
+ while (nJobs) {
+ Job_CatchOutput();
+#ifndef RMT_WILL_WATCH
+ Job_CatchChildren(!usePipes);
+#endif /* RMT_WILL_WATCH */
+ }
+ }
+ }
+ (void) eunlink(tfile);
+ exit(signo);
+}
+
+/*
+ *-----------------------------------------------------------------------
+ * Job_End --
+ * Do final processing such as the running of the commands
+ * attached to the .END target.
+ *
+ * Results:
+ * Number of errors reported.
+ *
+ * Side Effects:
+ * The process' temporary file (tfile) is removed if it still
+ * existed.
+ *-----------------------------------------------------------------------
+ */
+int
+Job_End()
+{
+ if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) {
+ if (errors) {
+ Error("Errors reported so .END ignored");
+ } else {
+ JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL);
+
+ while (nJobs) {
+ Job_CatchOutput();
+#ifndef RMT_WILL_WATCH
+ Job_CatchChildren(!usePipes);
+#endif /* RMT_WILL_WATCH */
+ }
+ }
+ }
+ (void) eunlink(tfile);
+ return(errors);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_Wait --
+ * Waits for all running jobs to finish and returns. Sets 'aborting'
+ * to ABORT_WAIT to prevent other jobs from starting.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Currently running jobs finish.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Job_Wait()
+{
+ aborting = ABORT_WAIT;
+ while (nJobs != 0) {
+ Job_CatchOutput();
+#ifndef RMT_WILL_WATCH
+ Job_CatchChildren(!usePipes);
+#endif /* RMT_WILL_WATCH */
+ }
+ aborting = 0;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Job_AbortAll --
+ * Abort all currently running jobs without handling output or anything.
+ * This function is to be called only in the event of a major
+ * error. Most definitely NOT to be called from JobInterrupt.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * All children are killed, not just the firstborn
+ *-----------------------------------------------------------------------
+ */
+void
+Job_AbortAll()
+{
+ LstNode ln; /* element in job table */
+ Job *job; /* the job descriptor in that element */
+ int foo;
+
+ aborting = ABORT_ERROR;
+
+ if (nJobs) {
+
+ (void) Lst_Open(jobs);
+ while ((ln = Lst_Next(jobs)) != NILLNODE) {
+ job = (Job *) Lst_Datum(ln);
+
+ /*
+ * kill the child process with increasingly drastic signals to make
+ * darn sure it's dead.
+ */
+#ifdef RMT_WANTS_SIGNALS
+ if (job->flags & JOB_REMOTE) {
+ Rmt_Signal(job, SIGINT);
+ Rmt_Signal(job, SIGKILL);
+ } else {
+ KILL(job->pid, SIGINT);
+ KILL(job->pid, SIGKILL);
+ }
+#else
+ KILL(job->pid, SIGINT);
+ KILL(job->pid, SIGKILL);
+#endif /* RMT_WANTS_SIGNALS */
+ }
+ }
+
+ /*
+ * Catch as many children as want to report in at first, then give up
+ */
+ while (waitpid((pid_t) -1, &foo, WNOHANG) > 0)
+ continue;
+ (void) eunlink(tfile);
+}
+
+#ifdef REMOTE
+/*-
+ *-----------------------------------------------------------------------
+ * JobFlagForMigration --
+ * Handle the eviction of a child. Called from RmtStatusChange.
+ * Flags the child as remigratable and then suspends it.
+ *
+ * Results:
+ * none.
+ *
+ * Side Effects:
+ * The job descriptor is flagged for remigration.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+JobFlagForMigration(hostID)
+ int hostID; /* ID of host we used, for matching children. */
+{
+ register Job *job; /* job descriptor for dead child */
+ LstNode jnode; /* list element for finding job */
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID);
+ (void) fflush(stdout);
+ }
+ jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID);
+
+ if (jnode == NILLNODE) {
+ jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID);
+ if (jnode == NILLNODE) {
+ if (DEBUG(JOB)) {
+ Error("Evicting host(%d) not in table", hostID);
+ }
+ return;
+ }
+ }
+ job = (Job *) Lst_Datum(jnode);
+
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "JobFlagForMigration(%d) found job '%s'.\n", hostID,
+ job->node->name);
+ (void) fflush(stdout);
+ }
+
+ KILL(job->pid, SIGSTOP);
+
+ job->flags |= JOB_REMIGRATE;
+}
+
+#endif
+
+/*-
+ *-----------------------------------------------------------------------
+ * JobRestartJobs --
+ * Tries to restart stopped jobs if there are slots available.
+ * Note that this tries to restart them regardless of pending errors.
+ * It's not good to leave stopped jobs lying around!
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Resumes(and possibly migrates) jobs.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+JobRestartJobs()
+{
+ while (!jobFull && !Lst_IsEmpty(stoppedJobs)) {
+ if (DEBUG(JOB)) {
+ (void) fprintf(stdout,
+ "Job queue is not full. Restarting a stopped job.\n");
+ (void) fflush(stdout);
+ }
+ JobRestart((Job *)Lst_DeQueue(stoppedJobs));
+ }
+}
diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h
new file mode 100644
index 0000000..2d3e961
--- /dev/null
+++ b/usr.bin/make/job.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)job.h 8.1 (Berkeley) 6/6/93
+ * $Id: job.h,v 1.7 1997/02/22 19:27:12 peter Exp $
+ */
+
+/*-
+ * job.h --
+ * Definitions pertaining to the running of jobs in parallel mode.
+ * Exported from job.c for the use of remote-execution modules.
+ */
+#ifndef _JOB_H_
+#define _JOB_H_
+
+#define TMPPAT "/tmp/makeXXXXX"
+
+/*
+ * The SEL_ constants determine the maximum amount of time spent in select
+ * before coming out to see if a child has finished. SEL_SEC is the number of
+ * seconds and SEL_USEC is the number of micro-seconds
+ */
+#define SEL_SEC 0
+#define SEL_USEC 100000
+
+
+/*-
+ * Job Table definitions.
+ *
+ * Each job has several things associated with it:
+ * 1) The process id of the child shell
+ * 2) The graph node describing the target being made by this job
+ * 3) A LstNode for the first command to be saved after the job
+ * completes. This is NILLNODE if there was no "..." in the job's
+ * commands.
+ * 4) An FILE* for writing out the commands. This is only
+ * used before the job is actually started.
+ * 5) A union of things used for handling the shell's output. Different
+ * parts of the union are used based on the value of the usePipes
+ * flag. If it is true, the output is being caught via a pipe and
+ * the descriptors of our pipe, an array in which output is line
+ * buffered and the current position in that buffer are all
+ * maintained for each job. If, on the other hand, usePipes is false,
+ * the output is routed to a temporary file and all that is kept
+ * is the name of the file and the descriptor open to the file.
+ * 6) An identifier provided by and for the exclusive use of the
+ * Rmt module.
+ * 7) A word of flags which determine how the module handles errors,
+ * echoing, etc. for the job
+ *
+ * The job "table" is kept as a linked Lst in 'jobs', with the number of
+ * active jobs maintained in the 'nJobs' variable. At no time will this
+ * exceed the value of 'maxJobs', initialized by the Job_Init function.
+ *
+ * When a job is finished, the Make_Update function is called on each of the
+ * parents of the node which was just remade. This takes care of the upward
+ * traversal of the dependency graph.
+ */
+#define JOB_BUFSIZE 1024
+typedef struct Job {
+ int pid; /* The child's process ID */
+ GNode *node; /* The target the child is making */
+ LstNode tailCmds; /* The node of the first command to be
+ * saved when the job has been run */
+ FILE *cmdFILE; /* When creating the shell script, this is
+ * where the commands go */
+ int rmtID; /* ID returned from Rmt module */
+ short flags; /* Flags to control treatment of job */
+#define JOB_IGNERR 0x001 /* Ignore non-zero exits */
+#define JOB_SILENT 0x002 /* no output */
+#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally
+ * if we can't export it and maxLocal is 0 */
+#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing
+ * commands */
+#define JOB_REMOTE 0x010 /* Job is running remotely */
+#define JOB_FIRST 0x020 /* Job is first job for the node */
+#define JOB_REMIGRATE 0x040 /* Job needs to be remigrated */
+#define JOB_RESTART 0x080 /* Job needs to be completely restarted */
+#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped,
+ * for some reason */
+#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job.
+ * Used to avoid infinite recursion between
+ * JobFinish and JobRestart */
+ union {
+ struct {
+ int op_inPipe; /* Input side of pipe associated
+ * with job's output channel */
+ int op_outPipe; /* Output side of pipe associated with
+ * job's output channel */
+ char op_outBuf[JOB_BUFSIZE + 1];
+ /* Buffer for storing the output of the
+ * job, line by line */
+ int op_curPos; /* Current position in op_outBuf */
+ } o_pipe; /* data used when catching the output via
+ * a pipe */
+ struct {
+ char of_outFile[sizeof(TMPPAT)+2];
+ /* Name of file to which shell output
+ * was rerouted */
+ int of_outFd; /* Stream open to the output
+ * file. Used to funnel all
+ * from a single job to one file
+ * while still allowing
+ * multiple shell invocations */
+ } o_file; /* Data used when catching the output in
+ * a temporary file */
+ } output; /* Data for tracking a shell's output */
+} Job;
+
+#define outPipe output.o_pipe.op_outPipe
+#define inPipe output.o_pipe.op_inPipe
+#define outBuf output.o_pipe.op_outBuf
+#define curPos output.o_pipe.op_curPos
+#define outFile output.o_file.of_outFile
+#define outFd output.o_file.of_outFd
+
+
+/*-
+ * Shell Specifications:
+ * Each shell type has associated with it the following information:
+ * 1) The string which must match the last character of the shell name
+ * for the shell to be considered of this type. The longest match
+ * wins.
+ * 2) A command to issue to turn off echoing of command lines
+ * 3) A command to issue to turn echoing back on again
+ * 4) What the shell prints, and its length, when given the echo-off
+ * command. This line will not be printed when received from the shell
+ * 5) A boolean to tell if the shell has the ability to control
+ * error checking for individual commands.
+ * 6) The string to turn this checking on.
+ * 7) The string to turn it off.
+ * 8) The command-flag to give to cause the shell to start echoing
+ * commands right away.
+ * 9) The command-flag to cause the shell to Lib_Exit when an error is
+ * detected in one of the commands.
+ *
+ * Some special stuff goes on if a shell doesn't have error control. In such
+ * a case, errCheck becomes a printf template for echoing the command,
+ * should echoing be on and ignErr becomes another printf template for
+ * executing the command while ignoring the return status. If either of these
+ * strings is empty when hasErrCtl is FALSE, the command will be executed
+ * anyway as is and if it causes an error, so be it.
+ */
+typedef struct Shell {
+ char *name; /* the name of the shell. For Bourne and C
+ * shells, this is used only to find the
+ * shell description when used as the single
+ * source of a .SHELL target. For user-defined
+ * shells, this is the full path of the shell.
+ */
+ Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */
+ char *echoOff; /* command to turn off echo */
+ char *echoOn; /* command to turn it back on again */
+ char *noPrint; /* command to skip when printing output from
+ * shell. This is usually the command which
+ * was executed to turn off echoing */
+ int noPLen; /* length of noPrint command */
+ Boolean hasErrCtl; /* set if can control error checking for
+ * individual commands */
+ char *errCheck; /* string to turn error checking on */
+ char *ignErr; /* string to turn off error checking */
+ /*
+ * command-line flags
+ */
+ char *echo; /* echo commands */
+ char *exit; /* exit on error */
+} Shell;
+
+
+extern char *targFmt; /* Format string for banner that separates
+ * output from multiple jobs. Contains a
+ * single %s where the name of the node being
+ * made should be put. */
+extern GNode *lastNode; /* Last node for which a banner was printed.
+ * If Rmt module finds it necessary to print
+ * a banner, it should set this to the node
+ * for which the banner was printed */
+extern int nJobs; /* Number of jobs running (local and remote) */
+extern int nLocal; /* Number of jobs running locally */
+extern Lst jobs; /* List of active job descriptors */
+extern Lst stoppedJobs; /* List of jobs that are stopped or didn't
+ * quite get started */
+extern Boolean jobFull; /* Non-zero if no more jobs should/will start*/
+
+
+void Job_Touch __P((GNode *, Boolean));
+Boolean Job_CheckCommands __P((GNode *, void (*abortProc )(char *, ...)));
+void Job_CatchChildren __P((Boolean));
+void Job_CatchOutput __P((void));
+void Job_Make __P((GNode *));
+void Job_Init __P((int, int));
+Boolean Job_Full __P((void));
+Boolean Job_Empty __P((void));
+ReturnStatus Job_ParseShell __P((char *));
+int Job_End __P((void));
+void Job_Wait __P((void));
+void Job_AbortAll __P((void));
+void JobFlagForMigration __P((int));
+
+#endif /* _JOB_H_ */
diff --git a/usr.bin/make/list.h b/usr.bin/make/list.h
new file mode 100644
index 0000000..fef9642
--- /dev/null
+++ b/usr.bin/make/list.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)list.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/*
+ * list.h --
+ *
+ * Structures, macros, and routines exported by the List module.
+ */
+
+#ifndef _LIST
+#define _LIST
+
+#ifndef _SPRITE
+#include "sprite.h"
+#endif _SPRITE
+
+/*
+ * This module defines the list abstraction, which enables one to link
+ * together arbitrary data structures. Lists are doubly-linked and
+ * circular. A list contains a header followed by its real members, if
+ * any. (An empty list therefore consists of a single element, the
+ * header, whose nextPtr and prevPtr fields point to itself). To refer
+ * to a list as a whole, the user keeps a pointer to the header; that
+ * header is initialized by a call to List_Init(), which creates an empty
+ * list given a pointer to a List_Links structure (described below).
+ *
+ * The links are contained in a two-element structure called List_Links.
+ * A list joins List_Links records (that is, each List_Links structure
+ * points to other List_Links structures), but if the List_Links is the
+ * first field within a larger structure, then the larger structures are
+ * effectively linked together as follows:
+ *
+ * header
+ * (List_Links) first elt. second elt.
+ * ----------------- ----------------- -----------------
+ * ..-> | nextPtr | ----> | List_Links | ----> | List_Links |----..
+ * | - - - - - - - | | | | |
+ * ..-- | prevPtr | <---- | | <---- | |<---..
+ * ----------------- - --- --- --- - - --- --- --- -
+ * | rest of | | rest of |
+ * | structure | | structure |
+ * | | | |
+ * | ... | | ... |
+ * ----------------- -----------------
+ *
+ * It is possible to link structures through List_Links fields that are
+ * not at the beginning of the larger structure, but it is then necessary
+ * to perform pointer arithmetic to find the beginning of the larger
+ * structure, given a pointer to some point within it.
+ *
+ * A typical structure might be something like:
+ *
+ * typedef struct {
+ * List_Links links;
+ * char ch;
+ * integer flags;
+ * } EditChar;
+ *
+ * Before an element is inserted in a list for the first time, it must
+ * be initialized by calling the macro List_InitElement().
+ */
+
+
+/*
+ * data structure for lists
+ */
+
+typedef struct List_Links {
+ struct List_Links *prevPtr;
+ struct List_Links *nextPtr;
+} List_Links;
+
+/*
+ * procedures
+ */
+
+void List_Init(); /* initialize a header to a list */
+void List_Insert(); /* insert an element into a list */
+void List_Remove(); /* remove an element from a list */
+void List_Move(); /* move an element elsewhere in a list */
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_InitElement --
+ *
+ * Initialize a list element. Must be called before an element is first
+ * inserted into a list.
+ *
+ * ----------------------------------------------------------------------------
+ */
+#define List_InitElement(elementPtr) \
+ (elementPtr)->prevPtr = (List_Links *) NIL; \
+ (elementPtr)->nextPtr = (List_Links *) NIL;
+
+/*
+ * Macros for stepping through or selecting parts of lists
+ */
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * LIST_FORALL --
+ *
+ * Macro to loop through a list and perform an operation on each member.
+ *
+ * Usage: LIST_FORALL(headerPtr, itemPtr) {
+ * / *
+ * * operation on itemPtr, which points to successive members
+ * * of the list
+ * *
+ * * It may be appropriate to first assign
+ * * foobarPtr = (Foobar *) itemPtr;
+ * * to refer to the entire Foobar structure.
+ * * /
+ * }
+ *
+ * Note: itemPtr must be a List_Links pointer variable, and headerPtr
+ * must evaluate to a pointer to a List_Links structure.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define LIST_FORALL(headerPtr, itemPtr) \
+ for (itemPtr = List_First(headerPtr); \
+ !List_IsAtEnd((headerPtr),itemPtr); \
+ itemPtr = List_Next(itemPtr))
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_IsEmpty --
+ *
+ * Macro: Boolean value, TRUE if the given list does not contain any
+ * members.
+ *
+ * Usage: if (List_IsEmpty(headerPtr)) ...
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define List_IsEmpty(headerPtr) \
+ ((headerPtr) == (headerPtr)->nextPtr)
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_IsAtEnd --
+ *
+ * Macro: Boolean value, TRUE if itemPtr is after the end of headerPtr
+ * (i.e., itemPtr is the header of the list).
+ *
+ * Usage: if (List_IsAtEnd(headerPtr, itemPtr)) ...
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+
+#define List_IsAtEnd(headerPtr, itemPtr) \
+ ((itemPtr) == (headerPtr))
+
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_First --
+ *
+ * Macro to return the first member in a list, which is the header if
+ * the list is empty.
+ *
+ * Usage: firstPtr = List_First(headerPtr);
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define List_First(headerPtr) ((headerPtr)->nextPtr)
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_Last --
+ *
+ * Macro to return the last member in a list, which is the header if
+ * the list is empty.
+ *
+ * Usage: lastPtr = List_Last(headerPtr);
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define List_Last(headerPtr) ((headerPtr)->prevPtr)
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_Prev --
+ *
+ * Macro to return the member preceding the given member in its list.
+ * If the given list member is the first element in the list, List_Prev
+ * returns the list header.
+ *
+ * Usage: prevPtr = List_Prev(itemPtr);
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define List_Prev(itemPtr) ((itemPtr)->prevPtr)
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * List_Next --
+ *
+ * Macro to return the member following the given member in its list.
+ * If the given list member is the last element in the list, List_Next
+ * returns the list header.
+ *
+ * Usage: nextPtr = List_Next(itemPtr);
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#define List_Next(itemPtr) ((itemPtr)->nextPtr)
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * The List_Insert procedure takes two arguments. The first argument
+ * is a pointer to the structure to be inserted into a list, and
+ * the second argument is a pointer to the list member after which
+ * the new element is to be inserted. Macros are used to determine
+ * which existing member will precede the new one.
+ *
+ * The List_Move procedure takes a destination argument with the same
+ * semantics as List_Insert.
+ *
+ * The following macros define where to insert the new element
+ * in the list:
+ *
+ * LIST_AFTER(itemPtr) -- insert after itemPtr
+ * LIST_BEFORE(itemPtr) -- insert before itemPtr
+ * LIST_ATFRONT(headerPtr) -- insert at front of list
+ * LIST_ATREAR(headerPtr) -- insert at end of list
+ *
+ * For example,
+ *
+ * List_Insert(itemPtr, LIST_AFTER(otherPtr));
+ *
+ * will insert itemPtr following otherPtr in the list containing otherPtr.
+ * ----------------------------------------------------------------------------
+ */
+
+#define LIST_AFTER(itemPtr) ((List_Links *) itemPtr)
+
+#define LIST_BEFORE(itemPtr) (((List_Links *) itemPtr)->prevPtr)
+
+#define LIST_ATFRONT(headerPtr) ((List_Links *) headerPtr)
+
+#define LIST_ATREAR(headerPtr) (((List_Links *) headerPtr)->prevPtr)
+
+#endif /* _LIST */
diff --git a/usr.bin/make/lst.h b/usr.bin/make/lst.h
new file mode 100644
index 0000000..2d1d867
--- /dev/null
+++ b/usr.bin/make/lst.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
+ * Copyright (c) 1988, 1989 by Adam de Boor
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)lst.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/*-
+ * lst.h --
+ * Header for using the list library
+ */
+#ifndef _LST_H_
+#define _LST_H_
+
+#include <sprite.h>
+#include <sys/param.h>
+#if __STDC__
+#include <stdlib.h>
+#endif
+
+/*
+ * basic typedef. This is what the Lst_ functions handle
+ */
+
+typedef struct Lst *Lst;
+typedef struct LstNode *LstNode;
+
+#define NILLST ((Lst) NIL)
+#define NILLNODE ((LstNode) NIL)
+
+/*
+ * NOFREE can be used as the freeProc to Lst_Destroy when the elements are
+ * not to be freed.
+ * NOCOPY performs similarly when given as the copyProc to Lst_Duplicate.
+ */
+#define NOFREE ((void (*) __P((ClientData))) 0)
+#define NOCOPY ((ClientData (*) __P((ClientData))) 0)
+
+#define LST_CONCNEW 0 /* create new LstNode's when using Lst_Concat */
+#define LST_CONCLINK 1 /* relink LstNode's when using Lst_Concat */
+
+/*
+ * Creation/destruction functions
+ */
+/* Create a new list */
+Lst Lst_Init __P((Boolean));
+/* Duplicate an existing list */
+Lst Lst_Duplicate __P((Lst, ClientData (*)(ClientData)));
+/* Destroy an old one */
+void Lst_Destroy __P((Lst, void (*)(ClientData)));
+/* True if list is empty */
+Boolean Lst_IsEmpty __P((Lst));
+
+/*
+ * Functions to modify a list
+ */
+/* Insert an element before another */
+ReturnStatus Lst_Insert __P((Lst, LstNode, ClientData));
+/* Insert an element after another */
+ReturnStatus Lst_Append __P((Lst, LstNode, ClientData));
+/* Place an element at the front of a lst. */
+ReturnStatus Lst_AtFront __P((Lst, ClientData));
+/* Place an element at the end of a lst. */
+ReturnStatus Lst_AtEnd __P((Lst, ClientData));
+/* Remove an element */
+ReturnStatus Lst_Remove __P((Lst, LstNode));
+/* Replace a node with a new value */
+ReturnStatus Lst_Replace __P((LstNode, ClientData));
+/* Concatenate two lists */
+ReturnStatus Lst_Concat __P((Lst, Lst, int));
+
+/*
+ * Node-specific functions
+ */
+/* Return first element in list */
+LstNode Lst_First __P((Lst));
+/* Return last element in list */
+LstNode Lst_Last __P((Lst));
+/* Return successor to given element */
+LstNode Lst_Succ __P((LstNode));
+/* Get datum from LstNode */
+ClientData Lst_Datum __P((LstNode));
+
+/*
+ * Functions for entire lists
+ */
+/* Find an element in a list */
+LstNode Lst_Find __P((Lst, ClientData,
+ int (*)(ClientData, ClientData)));
+/* Find an element starting from somewhere */
+LstNode Lst_FindFrom __P((Lst, LstNode, ClientData,
+ int (*cProc)(ClientData, ClientData)));
+/*
+ * See if the given datum is on the list. Returns the LstNode containing
+ * the datum
+ */
+LstNode Lst_Member __P((Lst, ClientData));
+/* Apply a function to all elements of a lst */
+void Lst_ForEach __P((Lst, int (*)(ClientData, ClientData),
+ ClientData));
+/*
+ * Apply a function to all elements of a lst starting from a certain point.
+ * If the list is circular, the application will wrap around to the
+ * beginning of the list again.
+ */
+void Lst_ForEachFrom __P((Lst, LstNode,
+ int (*)(ClientData, ClientData),
+ ClientData));
+/*
+ * these functions are for dealing with a list as a table, of sorts.
+ * An idea of the "current element" is kept and used by all the functions
+ * between Lst_Open() and Lst_Close().
+ */
+/* Open the list */
+ReturnStatus Lst_Open __P((Lst));
+/* Next element please */
+LstNode Lst_Next __P((Lst));
+/* Done yet? */
+Boolean Lst_IsAtEnd __P((Lst));
+/* Finish table access */
+void Lst_Close __P((Lst));
+
+/*
+ * for using the list as a queue
+ */
+/* Place an element at tail of queue */
+ReturnStatus Lst_EnQueue __P((Lst, ClientData));
+/* Remove an element from head of queue */
+ClientData Lst_DeQueue __P((Lst));
+
+#endif /* _LST_H_ */
diff --git a/usr.bin/make/lst.lib/lstAppend.c b/usr.bin/make/lst.lib/lstAppend.c
new file mode 100644
index 0000000..e936f73
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstAppend.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstAppend.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstAppend.c --
+ * Add a new node with a new datum after an existing node
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Append --
+ * Create a new node and add it to the given list after the given node.
+ *
+ * Results:
+ * SUCCESS if all went well.
+ *
+ * Side Effects:
+ * A new ListNode is created and linked in to the List. The lastPtr
+ * field of the List will be altered if ln is the last node in the
+ * list. lastPtr and firstPtr will alter if the list was empty and
+ * ln was NILLNODE.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Append (l, ln, d)
+ Lst l; /* affected list */
+ LstNode ln; /* node after which to append the datum */
+ ClientData d; /* said datum */
+{
+ register List list;
+ register ListNode lNode;
+ register ListNode nLNode;
+
+ if (LstValid (l) && (ln == NILLNODE && LstIsEmpty (l))) {
+ goto ok;
+ }
+
+ if (!LstValid (l) || LstIsEmpty (l) || ! LstNodeValid (ln, l)) {
+ return (FAILURE);
+ }
+ ok:
+
+ list = (List)l;
+ lNode = (ListNode)ln;
+
+ PAlloc (nLNode, ListNode);
+ nLNode->datum = d;
+ nLNode->useCount = nLNode->flags = 0;
+
+ if (lNode == NilListNode) {
+ if (list->isCirc) {
+ nLNode->nextPtr = nLNode->prevPtr = nLNode;
+ } else {
+ nLNode->nextPtr = nLNode->prevPtr = NilListNode;
+ }
+ list->firstPtr = list->lastPtr = nLNode;
+ } else {
+ nLNode->prevPtr = lNode;
+ nLNode->nextPtr = lNode->nextPtr;
+
+ lNode->nextPtr = nLNode;
+ if (nLNode->nextPtr != NilListNode) {
+ nLNode->nextPtr->prevPtr = nLNode;
+ }
+
+ if (lNode == list->lastPtr) {
+ list->lastPtr = nLNode;
+ }
+ }
+
+ return (SUCCESS);
+}
+
diff --git a/usr.bin/make/lst.lib/lstAtEnd.c b/usr.bin/make/lst.lib/lstAtEnd.c
new file mode 100644
index 0000000..c4f7480
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstAtEnd.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstAtEnd.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstAtEnd.c --
+ * Add a node at the end of the list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_AtEnd --
+ * Add a node to the end of the given list
+ *
+ * Results:
+ * SUCCESS if life is good.
+ *
+ * Side Effects:
+ * A new ListNode is created and added to the list.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_AtEnd (l, d)
+ Lst l; /* List to which to add the datum */
+ ClientData d; /* Datum to add */
+{
+ register LstNode end;
+
+ end = Lst_Last (l);
+ return (Lst_Append (l, end, d));
+}
diff --git a/usr.bin/make/lst.lib/lstAtFront.c b/usr.bin/make/lst.lib/lstAtFront.c
new file mode 100644
index 0000000..720e663
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstAtFront.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstAtFront.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstAtFront.c --
+ * Add a node at the front of the list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_AtFront --
+ * Place a piece of data at the front of a list
+ *
+ * Results:
+ * SUCCESS or FAILURE
+ *
+ * Side Effects:
+ * A new ListNode is created and stuck at the front of the list.
+ * hence, firstPtr (and possible lastPtr) in the list are altered.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_AtFront (l, d)
+ Lst l;
+ ClientData d;
+{
+ register LstNode front;
+
+ front = Lst_First (l);
+ return (Lst_Insert (l, front, d));
+}
diff --git a/usr.bin/make/lst.lib/lstClose.c b/usr.bin/make/lst.lib/lstClose.c
new file mode 100644
index 0000000..f28119f
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstClose.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstClose.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstClose.c --
+ * Close a list for sequential access.
+ * The sequential functions access the list in a slightly different way.
+ * CurPtr points to their idea of the current node in the list and they
+ * access the list based on it. Because the list is circular, Lst_Next
+ * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
+ * used to determine when to stop.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Close --
+ * Close a list which was opened for sequential access.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The list is closed.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Lst_Close (l)
+ Lst l; /* The list to close */
+{
+ register List list = (List) l;
+
+ if (LstValid(l) == TRUE) {
+ list->isOpen = FALSE;
+ list->atEnd = Unknown;
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstConcat.c b/usr.bin/make/lst.lib/lstConcat.c
new file mode 100644
index 0000000..5cb8a67
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstConcat.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstConcat.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * listConcat.c --
+ * Function to concatentate two lists.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Concat --
+ * Concatenate two lists. New elements are created to hold the data
+ * elements, if specified, but the elements themselves are not copied.
+ * If the elements should be duplicated to avoid confusion with another
+ * list, the Lst_Duplicate function should be called first.
+ * If LST_CONCLINK is specified, the second list is destroyed since
+ * its pointers have been corrupted and the list is no longer useable.
+ *
+ * Results:
+ * SUCCESS if all went well. FAILURE otherwise.
+ *
+ * Side Effects:
+ * New elements are created and appended the the first list.
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Concat (l1, l2, flags)
+ Lst l1; /* The list to which l2 is to be appended */
+ Lst l2; /* The list to append to l1 */
+ int flags; /* LST_CONCNEW if LstNode's should be duplicated
+ * LST_CONCLINK if should just be relinked */
+{
+ register ListNode ln; /* original LstNode */
+ register ListNode nln; /* new LstNode */
+ register ListNode last; /* the last element in the list. Keeps
+ * bookkeeping until the end */
+ register List list1 = (List)l1;
+ register List list2 = (List)l2;
+
+ if (!LstValid (l1) || !LstValid (l2)) {
+ return (FAILURE);
+ }
+
+ if (flags == LST_CONCLINK) {
+ if (list2->firstPtr != NilListNode) {
+ /*
+ * We set the nextPtr of the
+ * last element of list two to be NIL to make the loop easier and
+ * so we don't need an extra case should the first list turn
+ * out to be non-circular -- the final element will already point
+ * to NIL space and the first element will be untouched if it
+ * existed before and will also point to NIL space if it didn't.
+ */
+ list2->lastPtr->nextPtr = NilListNode;
+ /*
+ * So long as the second list isn't empty, we just link the
+ * first element of the second list to the last element of the
+ * first list. If the first list isn't empty, we then link the
+ * last element of the list to the first element of the second list
+ * The last element of the second list, if it exists, then becomes
+ * the last element of the first list.
+ */
+ list2->firstPtr->prevPtr = list1->lastPtr;
+ if (list1->lastPtr != NilListNode) {
+ list1->lastPtr->nextPtr = list2->firstPtr;
+ } else {
+ list1->firstPtr = list2->firstPtr;
+ }
+ list1->lastPtr = list2->lastPtr;
+ }
+ if (list1->isCirc && list1->firstPtr != NilListNode) {
+ /*
+ * If the first list is supposed to be circular and it is (now)
+ * non-empty, we must make sure it's circular by linking the
+ * first element to the last and vice versa
+ */
+ list1->firstPtr->prevPtr = list1->lastPtr;
+ list1->lastPtr->nextPtr = list1->firstPtr;
+ }
+ free ((Address)l2);
+ } else if (list2->firstPtr != NilListNode) {
+ /*
+ * We set the nextPtr of the last element of list 2 to be nil to make
+ * the loop less difficult. The loop simply goes through the entire
+ * second list creating new LstNodes and filling in the nextPtr, and
+ * prevPtr to fit into l1 and its datum field from the
+ * datum field of the corresponding element in l2. The 'last' node
+ * follows the last of the new nodes along until the entire l2 has
+ * been appended. Only then does the bookkeeping catch up with the
+ * changes. During the first iteration of the loop, if 'last' is nil,
+ * the first list must have been empty so the newly-created node is
+ * made the first node of the list.
+ */
+ list2->lastPtr->nextPtr = NilListNode;
+ for (last = list1->lastPtr, ln = list2->firstPtr;
+ ln != NilListNode;
+ ln = ln->nextPtr)
+ {
+ PAlloc (nln, ListNode);
+ nln->datum = ln->datum;
+ if (last != NilListNode) {
+ last->nextPtr = nln;
+ } else {
+ list1->firstPtr = nln;
+ }
+ nln->prevPtr = last;
+ nln->flags = nln->useCount = 0;
+ last = nln;
+ }
+
+ /*
+ * Finish bookkeeping. The last new element becomes the last element
+ * of list one.
+ */
+ list1->lastPtr = last;
+
+ /*
+ * The circularity of both list one and list two must be corrected
+ * for -- list one because of the new nodes added to it; list two
+ * because of the alteration of list2->lastPtr's nextPtr to ease the
+ * above for loop.
+ */
+ if (list1->isCirc) {
+ list1->lastPtr->nextPtr = list1->firstPtr;
+ list1->firstPtr->prevPtr = list1->lastPtr;
+ } else {
+ last->nextPtr = NilListNode;
+ }
+
+ if (list2->isCirc) {
+ list2->lastPtr->nextPtr = list2->firstPtr;
+ }
+ }
+
+ return (SUCCESS);
+}
+
diff --git a/usr.bin/make/lst.lib/lstDatum.c b/usr.bin/make/lst.lib/lstDatum.c
new file mode 100644
index 0000000..ec7d11c
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstDatum.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstDatum.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstDatum.c --
+ * Return the datum associated with a list node.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Datum --
+ * Return the datum stored in the given node.
+ *
+ * Results:
+ * The datum or (ick!) NIL if the node is invalid.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+ClientData
+Lst_Datum (ln)
+ LstNode ln;
+{
+ if (ln != NILLNODE) {
+ return (((ListNode)ln)->datum);
+ } else {
+ return ((ClientData) NIL);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstDeQueue.c b/usr.bin/make/lst.lib/lstDeQueue.c
new file mode 100644
index 0000000..6233502
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstDeQueue.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstDeQueue.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstDeQueue.c --
+ * Remove the node and return its datum from the head of the list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_DeQueue --
+ * Remove and return the datum at the head of the given list.
+ *
+ * Results:
+ * The datum in the node at the head or (ick) NIL if the list
+ * is empty.
+ *
+ * Side Effects:
+ * The head node is removed from the list.
+ *
+ *-----------------------------------------------------------------------
+ */
+ClientData
+Lst_DeQueue (l)
+ Lst l;
+{
+ ClientData rd;
+ register ListNode tln;
+
+ tln = (ListNode) Lst_First (l);
+ if (tln == NilListNode) {
+ return ((ClientData) NIL);
+ }
+
+ rd = tln->datum;
+ if (Lst_Remove (l, (LstNode)tln) == FAILURE) {
+ return ((ClientData) NIL);
+ } else {
+ return (rd);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstDestroy.c b/usr.bin/make/lst.lib/lstDestroy.c
new file mode 100644
index 0000000..e241452
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstDestroy.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstDestroy.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstDestroy.c --
+ * Nuke a list and all its resources
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Destroy --
+ * Destroy a list and free all its resources. If the freeProc is
+ * given, it is called with the datum from each node in turn before
+ * the node is freed.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The given list is freed in its entirety.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Lst_Destroy (l, freeProc)
+ Lst l;
+ register void (*freeProc) __P((ClientData));
+{
+ register ListNode ln;
+ register ListNode tln = NilListNode;
+ register List list = (List)l;
+
+ if (l == NILLST || ! l) {
+ /*
+ * Note the check for l == (Lst)0 to catch uninitialized static Lst's.
+ * Gross, but useful.
+ */
+ return;
+ }
+
+ /* To ease scanning */
+ if (list->lastPtr != NilListNode)
+ list->lastPtr->nextPtr = NilListNode;
+ else {
+ free ((Address)l);
+ return;
+ }
+
+ if (freeProc) {
+ for (ln = list->firstPtr; ln != NilListNode; ln = tln) {
+ tln = ln->nextPtr;
+ (*freeProc) (ln->datum);
+ free ((Address)ln);
+ }
+ } else {
+ for (ln = list->firstPtr; ln != NilListNode; ln = tln) {
+ tln = ln->nextPtr;
+ free ((Address)ln);
+ }
+ }
+
+ free ((Address)l);
+}
diff --git a/usr.bin/make/lst.lib/lstDupl.c b/usr.bin/make/lst.lib/lstDupl.c
new file mode 100644
index 0000000..cc5e75e
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstDupl.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstDupl.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * listDupl.c --
+ * Duplicate a list. This includes duplicating the individual
+ * elements.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Duplicate --
+ * Duplicate an entire list. If a function to copy a ClientData is
+ * given, the individual client elements will be duplicated as well.
+ *
+ * Results:
+ * The new Lst structure or NILLST if failure.
+ *
+ * Side Effects:
+ * A new list is created.
+ *-----------------------------------------------------------------------
+ */
+Lst
+Lst_Duplicate (l, copyProc)
+ Lst l; /* the list to duplicate */
+ /* A function to duplicate each ClientData */
+ ClientData (*copyProc) __P((ClientData));
+{
+ register Lst nl;
+ register ListNode ln;
+ register List list = (List)l;
+
+ if (!LstValid (l)) {
+ return (NILLST);
+ }
+
+ nl = Lst_Init (list->isCirc);
+ if (nl == NILLST) {
+ return (NILLST);
+ }
+
+ ln = list->firstPtr;
+ while (ln != NilListNode) {
+ if (copyProc != NOCOPY) {
+ if (Lst_AtEnd (nl, (*copyProc) (ln->datum)) == FAILURE) {
+ return (NILLST);
+ }
+ } else if (Lst_AtEnd (nl, ln->datum) == FAILURE) {
+ return (NILLST);
+ }
+
+ if (list->isCirc && ln == list->lastPtr) {
+ ln = NilListNode;
+ } else {
+ ln = ln->nextPtr;
+ }
+ }
+
+ return (nl);
+}
diff --git a/usr.bin/make/lst.lib/lstEnQueue.c b/usr.bin/make/lst.lib/lstEnQueue.c
new file mode 100644
index 0000000..d7627f3
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstEnQueue.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstEnQueue.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstEnQueue.c--
+ * Treat the list as a queue and place a datum at its end
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_EnQueue --
+ * Add the datum to the tail of the given list.
+ *
+ * Results:
+ * SUCCESS or FAILURE as returned by Lst_Append.
+ *
+ * Side Effects:
+ * the lastPtr field is altered all the time and the firstPtr field
+ * will be altered if the list used to be empty.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_EnQueue (l, d)
+ Lst l;
+ ClientData d;
+{
+ if (LstValid (l) == FALSE) {
+ return (FAILURE);
+ }
+
+ return (Lst_Append (l, Lst_Last(l), d));
+}
+
diff --git a/usr.bin/make/lst.lib/lstFind.c b/usr.bin/make/lst.lib/lstFind.c
new file mode 100644
index 0000000..fbbae66
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstFind.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstFind.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstFind.c --
+ * Find a node on a list.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Find --
+ * Find a node on the given list using the given comparison function
+ * and the given datum.
+ *
+ * Results:
+ * The found node or NILLNODE if none matches.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_Find (l, d, cProc)
+ Lst l;
+ ClientData d;
+ int (*cProc) __P((ClientData, ClientData));
+{
+ return (Lst_FindFrom (l, Lst_First(l), d, cProc));
+}
+
diff --git a/usr.bin/make/lst.lib/lstFindFrom.c b/usr.bin/make/lst.lib/lstFindFrom.c
new file mode 100644
index 0000000..6c64cf1
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstFindFrom.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstFindFrom.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstFindFrom.c --
+ * Find a node on a list from a given starting point. Used by Lst_Find.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_FindFrom --
+ * Search for a node starting and ending with the given one on the
+ * given list using the passed datum and comparison function to
+ * determine when it has been found.
+ *
+ * Results:
+ * The found node or NILLNODE
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_FindFrom (l, ln, d, cProc)
+ Lst l;
+ register LstNode ln;
+ register ClientData d;
+ register int (*cProc) __P((ClientData, ClientData));
+{
+ register ListNode tln;
+ Boolean found = FALSE;
+
+ if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
+ return (NILLNODE);
+ }
+
+ tln = (ListNode)ln;
+
+ do {
+ if ((*cProc) (tln->datum, d) == 0) {
+ found = TRUE;
+ break;
+ } else {
+ tln = tln->nextPtr;
+ }
+ } while (tln != (ListNode)ln && tln != NilListNode);
+
+ if (found) {
+ return ((LstNode)tln);
+ } else {
+ return (NILLNODE);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstFirst.c b/usr.bin/make/lst.lib/lstFirst.c
new file mode 100644
index 0000000..e7a3039
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstFirst.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstFirst.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstFirst.c --
+ * Return the first node of a list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_First --
+ * Return the first node on the given list.
+ *
+ * Results:
+ * The first node or NILLNODE if the list is empty.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_First (l)
+ Lst l;
+{
+ if (!LstValid (l) || LstIsEmpty (l)) {
+ return (NILLNODE);
+ } else {
+ return ((LstNode)((List)l)->firstPtr);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstForEach.c b/usr.bin/make/lst.lib/lstForEach.c
new file mode 100644
index 0000000..1688e9d
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstForEach.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstForEach.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstForeach.c --
+ * Perform a given function on all elements of a list.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_ForEach --
+ * Apply the given function to each element of the given list. The
+ * function should return 0 if Lst_ForEach should continue and non-
+ * zero if it should abort.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Only those created by the passed-in function.
+ *
+ *-----------------------------------------------------------------------
+ */
+/*VARARGS2*/
+void
+Lst_ForEach (l, proc, d)
+ Lst l;
+ register int (*proc) __P((ClientData, ClientData));
+ register ClientData d;
+{
+ Lst_ForEachFrom(l, Lst_First(l), proc, d);
+}
+
diff --git a/usr.bin/make/lst.lib/lstForEachFrom.c b/usr.bin/make/lst.lib/lstForEachFrom.c
new file mode 100644
index 0000000..7692c57
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstForEachFrom.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstForEachFrom.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * lstForEachFrom.c --
+ * Perform a given function on all elements of a list starting from
+ * a given point.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_ForEachFrom --
+ * Apply the given function to each element of the given list. The
+ * function should return 0 if traversal should continue and non-
+ * zero if it should abort.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Only those created by the passed-in function.
+ *
+ *-----------------------------------------------------------------------
+ */
+/*VARARGS2*/
+void
+Lst_ForEachFrom (l, ln, proc, d)
+ Lst l;
+ LstNode ln;
+ register int (*proc) __P((ClientData, ClientData));
+ register ClientData d;
+{
+ register ListNode tln = (ListNode)ln;
+ register List list = (List)l;
+ register ListNode next;
+ Boolean done;
+ int result;
+
+ if (!LstValid (list) || LstIsEmpty (list)) {
+ return;
+ }
+
+ do {
+ /*
+ * Take care of having the current element deleted out from under
+ * us.
+ */
+
+ next = tln->nextPtr;
+
+ (void) tln->useCount++;
+ result = (*proc) (tln->datum, d);
+ (void) tln->useCount--;
+
+ /*
+ * We're done with the traversal if
+ * - nothing's been added after the current node and
+ * - the next node to examine is the first in the queue or
+ * doesn't exist.
+ */
+ done = (next == tln->nextPtr &&
+ (next == NilListNode || next == list->firstPtr));
+
+ next = tln->nextPtr;
+
+ if (tln->flags & LN_DELETED) {
+ free((char *)tln);
+ }
+ tln = next;
+ } while (!result && !LstIsEmpty(list) && !done);
+
+}
+
diff --git a/usr.bin/make/lst.lib/lstInit.c b/usr.bin/make/lst.lib/lstInit.c
new file mode 100644
index 0000000..a16fca2
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstInit.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstInit.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * init.c --
+ * Initialize a new linked list.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Init --
+ * Create and initialize a new list.
+ *
+ * Results:
+ * The created list.
+ *
+ * Side Effects:
+ * A list is created, what else?
+ *
+ *-----------------------------------------------------------------------
+ */
+Lst
+Lst_Init(circ)
+ Boolean circ; /* TRUE if the list should be made circular */
+{
+ register List nList;
+
+ PAlloc (nList, List);
+
+ nList->firstPtr = NilListNode;
+ nList->lastPtr = NilListNode;
+ nList->isOpen = FALSE;
+ nList->isCirc = circ;
+ nList->atEnd = Unknown;
+
+ return ((Lst)nList);
+}
diff --git a/usr.bin/make/lst.lib/lstInsert.c b/usr.bin/make/lst.lib/lstInsert.c
new file mode 100644
index 0000000..8c4ebcb
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstInsert.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstInsert.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstInsert.c --
+ * Insert a new datum before an old one
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Insert --
+ * Insert a new node with the given piece of data before the given
+ * node in the given list.
+ *
+ * Results:
+ * SUCCESS or FAILURE.
+ *
+ * Side Effects:
+ * the firstPtr field will be changed if ln is the first node in the
+ * list.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Insert (l, ln, d)
+ Lst l; /* list to manipulate */
+ LstNode ln; /* node before which to insert d */
+ ClientData d; /* datum to be inserted */
+{
+ register ListNode nLNode; /* new lnode for d */
+ register ListNode lNode = (ListNode)ln;
+ register List list = (List)l;
+
+
+ /*
+ * check validity of arguments
+ */
+ if (LstValid (l) && (LstIsEmpty (l) && ln == NILLNODE))
+ goto ok;
+
+ if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
+ return (FAILURE);
+ }
+
+ ok:
+ PAlloc (nLNode, ListNode);
+
+ nLNode->datum = d;
+ nLNode->useCount = nLNode->flags = 0;
+
+ if (ln == NILLNODE) {
+ if (list->isCirc) {
+ nLNode->prevPtr = nLNode->nextPtr = nLNode;
+ } else {
+ nLNode->prevPtr = nLNode->nextPtr = NilListNode;
+ }
+ list->firstPtr = list->lastPtr = nLNode;
+ } else {
+ nLNode->prevPtr = lNode->prevPtr;
+ nLNode->nextPtr = lNode;
+
+ if (nLNode->prevPtr != NilListNode) {
+ nLNode->prevPtr->nextPtr = nLNode;
+ }
+ lNode->prevPtr = nLNode;
+
+ if (lNode == list->firstPtr) {
+ list->firstPtr = nLNode;
+ }
+ }
+
+ return (SUCCESS);
+}
+
diff --git a/usr.bin/make/lst.lib/lstInt.h b/usr.bin/make/lst.lib/lstInt.h
new file mode 100644
index 0000000..4260940
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstInt.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)lstInt.h 8.1 (Berkeley) 6/6/93
+ * $Id$
+ */
+
+/*-
+ * lstInt.h --
+ * Internals for the list library
+ */
+#ifndef _LSTINT_H_
+#define _LSTINT_H_
+
+#include "make.h"
+#include "lst.h"
+
+typedef struct ListNode {
+ struct ListNode *prevPtr; /* previous element in list */
+ struct ListNode *nextPtr; /* next in list */
+ short useCount:8, /* Count of functions using the node.
+ * node may not be deleted until count
+ * goes to 0 */
+ flags:8; /* Node status flags */
+ ClientData datum; /* datum associated with this element */
+} *ListNode;
+/*
+ * Flags required for synchronization
+ */
+#define LN_DELETED 0x0001 /* List node should be removed when done */
+
+#define NilListNode ((ListNode)-1)
+
+typedef enum {
+ Head, Middle, Tail, Unknown
+} Where;
+
+typedef struct {
+ ListNode firstPtr; /* first node in list */
+ ListNode lastPtr; /* last node in list */
+ Boolean isCirc; /* true if the list should be considered
+ * circular */
+/*
+ * fields for sequential access
+ */
+ Where atEnd; /* Where in the list the last access was */
+ Boolean isOpen; /* true if list has been Lst_Open'ed */
+ ListNode curPtr; /* current node, if open. NilListNode if
+ * *just* opened */
+ ListNode prevPtr; /* Previous node, if open. Used by
+ * Lst_Remove */
+} *List;
+
+#define NilList ((List)-1)
+
+/*
+ * PAlloc (var, ptype) --
+ * Allocate a pointer-typedef structure 'ptype' into the variable 'var'
+ */
+#define PAlloc(var,ptype) var = (ptype) emalloc (sizeof (*var))
+
+/*
+ * LstValid (l) --
+ * Return TRUE if the list l is valid
+ */
+#define LstValid(l) (((Lst)l == NILLST) ? FALSE : TRUE)
+
+/*
+ * LstNodeValid (ln, l) --
+ * Return TRUE if the LstNode ln is valid with respect to l
+ */
+#define LstNodeValid(ln, l) ((((LstNode)ln) == NILLNODE) ? FALSE : TRUE)
+
+/*
+ * LstIsEmpty (l) --
+ * TRUE if the list l is empty.
+ */
+#define LstIsEmpty(l) (((List)l)->firstPtr == NilListNode)
+
+#endif _LSTINT_H_
diff --git a/usr.bin/make/lst.lib/lstIsAtEnd.c b/usr.bin/make/lst.lib/lstIsAtEnd.c
new file mode 100644
index 0000000..2c48019
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstIsAtEnd.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstIsAtEnd.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstIsAtEnd.c --
+ * Tell if the current node is at the end of the list.
+ * The sequential functions access the list in a slightly different way.
+ * CurPtr points to their idea of the current node in the list and they
+ * access the list based on it. Because the list is circular, Lst_Next
+ * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
+ * used to determine when to stop.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_IsAtEnd --
+ * Return true if have reached the end of the given list.
+ *
+ * Results:
+ * TRUE if at the end of the list (this includes the list not being
+ * open or being invalid) or FALSE if not. We return TRUE if the list
+ * is invalid or unopend so as to cause the caller to exit its loop
+ * asap, the assumption being that the loop is of the form
+ * while (!Lst_IsAtEnd (l)) {
+ * ...
+ * }
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Lst_IsAtEnd (l)
+ Lst l;
+{
+ register List list = (List) l;
+
+ return (!LstValid (l) || !list->isOpen ||
+ (list->atEnd == Head) || (list->atEnd == Tail));
+}
+
diff --git a/usr.bin/make/lst.lib/lstIsEmpty.c b/usr.bin/make/lst.lib/lstIsEmpty.c
new file mode 100644
index 0000000..6a9a7bd
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstIsEmpty.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstIsEmpty.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstIsEmpty.c --
+ * A single function to decide if a list is empty
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_IsEmpty --
+ * Return TRUE if the given list is empty.
+ *
+ * Results:
+ * TRUE if the list is empty, FALSE otherwise.
+ *
+ * Side Effects:
+ * None.
+ *
+ * A list is considered empty if its firstPtr == NilListNode (or if
+ * the list itself is NILLIST).
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Lst_IsEmpty (l)
+ Lst l;
+{
+ return ( ! LstValid (l) || LstIsEmpty(l));
+}
+
diff --git a/usr.bin/make/lst.lib/lstLast.c b/usr.bin/make/lst.lib/lstLast.c
new file mode 100644
index 0000000..49b2f8e
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstLast.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstLast.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstLast.c --
+ * Return the last element of a list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Last --
+ * Return the last node on the list l.
+ *
+ * Results:
+ * The requested node or NILLNODE if the list is empty.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_Last (l)
+ Lst l;
+{
+ if (!LstValid(l) || LstIsEmpty (l)) {
+ return (NILLNODE);
+ } else {
+ return ((LstNode)((List)l)->lastPtr);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstMember.c b/usr.bin/make/lst.lib/lstMember.c
new file mode 100644
index 0000000..cc5cb4f
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstMember.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstMember.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * lstMember.c --
+ * See if a given datum is on a given list.
+ */
+
+#include "lstInt.h"
+
+LstNode
+Lst_Member (l, d)
+ Lst l;
+ ClientData d;
+{
+ List list = (List) l;
+ register ListNode lNode;
+
+ lNode = list->firstPtr;
+ if (lNode == NilListNode) {
+ return NILLNODE;
+ }
+
+ do {
+ if (lNode->datum == d) {
+ return (LstNode)lNode;
+ }
+ lNode = lNode->nextPtr;
+ } while (lNode != NilListNode && lNode != list->firstPtr);
+
+ return NILLNODE;
+}
diff --git a/usr.bin/make/lst.lib/lstNext.c b/usr.bin/make/lst.lib/lstNext.c
new file mode 100644
index 0000000..f6e2656
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstNext.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstNext.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstNext.c --
+ * Return the next node for a list.
+ * The sequential functions access the list in a slightly different way.
+ * CurPtr points to their idea of the current node in the list and they
+ * access the list based on it. Because the list is circular, Lst_Next
+ * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
+ * used to determine when to stop.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Next --
+ * Return the next node for the given list.
+ *
+ * Results:
+ * The next node or NILLNODE if the list has yet to be opened. Also
+ * if the list is non-circular and the end has been reached, NILLNODE
+ * is returned.
+ *
+ * Side Effects:
+ * the curPtr field is updated.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_Next (l)
+ Lst l;
+{
+ register ListNode tln;
+ register List list = (List)l;
+
+ if ((LstValid (l) == FALSE) ||
+ (list->isOpen == FALSE)) {
+ return (NILLNODE);
+ }
+
+ list->prevPtr = list->curPtr;
+
+ if (list->curPtr == NilListNode) {
+ if (list->atEnd == Unknown) {
+ /*
+ * If we're just starting out, atEnd will be Unknown.
+ * Then we want to start this thing off in the right
+ * direction -- at the start with atEnd being Middle.
+ */
+ list->curPtr = tln = list->firstPtr;
+ list->atEnd = Middle;
+ } else {
+ tln = NilListNode;
+ list->atEnd = Tail;
+ }
+ } else {
+ tln = list->curPtr->nextPtr;
+ list->curPtr = tln;
+
+ if (tln == list->firstPtr || tln == NilListNode) {
+ /*
+ * If back at the front, then we've hit the end...
+ */
+ list->atEnd = Tail;
+ } else {
+ /*
+ * Reset to Middle if gone past first.
+ */
+ list->atEnd = Middle;
+ }
+ }
+
+ return ((LstNode)tln);
+}
+
diff --git a/usr.bin/make/lst.lib/lstOpen.c b/usr.bin/make/lst.lib/lstOpen.c
new file mode 100644
index 0000000..fbb7d0e
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstOpen.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstOpen.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstOpen.c --
+ * Open a list for sequential access. The sequential functions access the
+ * list in a slightly different way. CurPtr points to their idea of the
+ * current node in the list and they access the list based on it.
+ * If the list is circular, Lst_Next and Lst_Prev will go around
+ * the list forever. Lst_IsAtEnd must be used to determine when to stop.
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Open --
+ * Open a list for sequential access. A list can still be searched,
+ * etc., without confusing these functions.
+ *
+ * Results:
+ * SUCCESS or FAILURE.
+ *
+ * Side Effects:
+ * isOpen is set TRUE and curPtr is set to NilListNode so the
+ * other sequential functions no it was just opened and can choose
+ * the first element accessed based on this.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Open (l)
+ register Lst l;
+{
+ if (LstValid (l) == FALSE) {
+ return (FAILURE);
+ }
+ ((List) l)->isOpen = TRUE;
+ ((List) l)->atEnd = LstIsEmpty (l) ? Head : Unknown;
+ ((List) l)->curPtr = NilListNode;
+
+ return (SUCCESS);
+}
+
diff --git a/usr.bin/make/lst.lib/lstRemove.c b/usr.bin/make/lst.lib/lstRemove.c
new file mode 100644
index 0000000..e84d301
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstRemove.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstRemove.c --
+ * Remove an element from a list
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Remove --
+ * Remove the given node from the given list.
+ *
+ * Results:
+ * SUCCESS or FAILURE.
+ *
+ * Side Effects:
+ * The list's firstPtr will be set to NilListNode if ln is the last
+ * node on the list. firsPtr and lastPtr will be altered if ln is
+ * either the first or last node, respectively, on the list.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Remove (l, ln)
+ Lst l;
+ LstNode ln;
+{
+ register List list = (List) l;
+ register ListNode lNode = (ListNode) ln;
+
+ if (!LstValid (l) ||
+ !LstNodeValid (ln, l)) {
+ return (FAILURE);
+ }
+
+ /*
+ * unlink it from the list
+ */
+ if (lNode->nextPtr != NilListNode) {
+ lNode->nextPtr->prevPtr = lNode->prevPtr;
+ }
+ if (lNode->prevPtr != NilListNode) {
+ lNode->prevPtr->nextPtr = lNode->nextPtr;
+ }
+
+ /*
+ * if either the firstPtr or lastPtr of the list point to this node,
+ * adjust them accordingly
+ */
+ if (list->firstPtr == lNode) {
+ list->firstPtr = lNode->nextPtr;
+ }
+ if (list->lastPtr == lNode) {
+ list->lastPtr = lNode->prevPtr;
+ }
+
+ /*
+ * Sequential access stuff. If the node we're removing is the current
+ * node in the list, reset the current node to the previous one. If the
+ * previous one was non-existent (prevPtr == NilListNode), we set the
+ * end to be Unknown, since it is.
+ */
+ if (list->isOpen && (list->curPtr == lNode)) {
+ list->curPtr = list->prevPtr;
+ if (list->curPtr == NilListNode) {
+ list->atEnd = Unknown;
+ }
+ }
+
+ /*
+ * the only way firstPtr can still point to ln is if ln is the last
+ * node on the list (the list is circular, so lNode->nextptr == lNode in
+ * this case). The list is, therefore, empty and is marked as such
+ */
+ if (list->firstPtr == lNode) {
+ list->firstPtr = NilListNode;
+ }
+
+ /*
+ * note that the datum is unmolested. The caller must free it as
+ * necessary and as expected.
+ */
+ if (lNode->useCount == 0) {
+ free ((Address)ln);
+ } else {
+ lNode->flags |= LN_DELETED;
+ }
+
+ return (SUCCESS);
+}
+
diff --git a/usr.bin/make/lst.lib/lstReplace.c b/usr.bin/make/lst.lib/lstReplace.c
new file mode 100644
index 0000000..a2dcb45
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstReplace.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstReplace.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstReplace.c --
+ * Replace the datum in a node with a new datum
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Replace --
+ * Replace the datum in the given node with the new datum
+ *
+ * Results:
+ * SUCCESS or FAILURE.
+ *
+ * Side Effects:
+ * The datum field fo the node is altered.
+ *
+ *-----------------------------------------------------------------------
+ */
+ReturnStatus
+Lst_Replace (ln, d)
+ register LstNode ln;
+ ClientData d;
+{
+ if (ln == NILLNODE) {
+ return (FAILURE);
+ } else {
+ ((ListNode) ln)->datum = d;
+ return (SUCCESS);
+ }
+}
+
diff --git a/usr.bin/make/lst.lib/lstSucc.c b/usr.bin/make/lst.lib/lstSucc.c
new file mode 100644
index 0000000..b43a00c
--- /dev/null
+++ b/usr.bin/make/lst.lib/lstSucc.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * LstSucc.c --
+ * return the successor to a given node
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Succ --
+ * Return the sucessor to the given node on its list.
+ *
+ * Results:
+ * The successor of the node, if it exists (note that on a circular
+ * list, if the node is the only one in the list, it is its own
+ * successor).
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_Succ (ln)
+ LstNode ln;
+{
+ if (ln == NILLNODE) {
+ return (NILLNODE);
+ } else {
+ return ((LstNode) ((ListNode) ln)->nextPtr);
+ }
+}
+
diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c
new file mode 100644
index 0000000..94851ad
--- /dev/null
+++ b/usr.bin/make/main.c
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: main.c,v 1.16 1997/02/22 19:27:14 peter Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * main.c --
+ * The main file for this entire program. Exit routines etc
+ * reside here.
+ *
+ * Utility functions defined in this file:
+ * Main_ParseArgLine Takes a line of arguments, breaks them and
+ * treats them as if they were given when first
+ * invoked. Used by the parse module to implement
+ * the .MFLAGS target.
+ *
+ * Error Print a tagged error message. The global
+ * MAKE variable must have been defined. This
+ * takes a format string and two optional
+ * arguments for it.
+ *
+ * Fatal Print an error message and exit. Also takes
+ * a format string and two arguments.
+ *
+ * Punt Aborts all jobs and exits with a message. Also
+ * takes a format string and two arguments.
+ *
+ * Finish Finish things up by printing the number of
+ * errors which occured, as passed to it, and
+ * exiting.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#ifndef MACHINE
+#include <sys/utsname.h>
+#endif
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "job.h"
+#include "pathnames.h"
+
+#ifndef DEFMAXLOCAL
+#define DEFMAXLOCAL DEFMAXJOBS
+#endif /* DEFMAXLOCAL */
+
+#define MAKEFLAGS ".MAKEFLAGS"
+
+Lst create; /* Targets to be made */
+time_t now; /* Time at start of make */
+GNode *DEFAULT; /* .DEFAULT node */
+Boolean allPrecious; /* .PRECIOUS given on line by itself */
+
+static Boolean noBuiltins; /* -r flag */
+static Lst makefiles; /* ordered list of makefiles to read */
+static Boolean printVars; /* print value of one or more vars */
+static Lst variables; /* list of variables to print */
+int maxJobs; /* -j argument */
+static int maxLocal; /* -L argument */
+Boolean compatMake; /* -B argument */
+Boolean debug; /* -d flag */
+Boolean noExecute; /* -n flag */
+Boolean keepgoing; /* -k flag */
+Boolean queryFlag; /* -q flag */
+Boolean touchFlag; /* -t flag */
+Boolean usePipes; /* !-P flag */
+Boolean ignoreErrors; /* -i flag */
+Boolean beSilent; /* -s flag */
+Boolean oldVars; /* variable substitution style */
+Boolean checkEnvFirst; /* -e flag */
+static Boolean jobsRunning; /* TRUE if the jobs might be running */
+
+static void MainParseArgs __P((int, char **));
+char * chdir_verify_path __P((char *, char *));
+static int ReadMakefile __P((ClientData, ClientData));
+static void usage __P((void));
+
+static char *curdir; /* startup directory */
+static char *objdir; /* where we chdir'ed to */
+
+/*-
+ * MainParseArgs --
+ * Parse a given argument vector. Called from main() and from
+ * Main_ParseArgLine() when the .MAKEFLAGS target is used.
+ *
+ * XXX: Deal with command line overriding .MAKEFLAGS in makefile
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Various global and local flags will be set depending on the flags
+ * given
+ */
+static void
+MainParseArgs(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+ extern char *optarg;
+ int c;
+ int forceJobs = 0;
+
+ optind = 1; /* since we're called more than once */
+#ifdef REMOTE
+# define OPTFLAGS "BD:I:L:PSV:d:ef:ij:km:nqrst"
+#else
+# define OPTFLAGS "BD:I:PSV:d:ef:ij:km:nqrst"
+#endif
+rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
+ switch(c) {
+ case 'D':
+ Var_Set(optarg, "1", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ case 'I':
+ Parse_AddIncludeDir(optarg);
+ Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ case 'V':
+ printVars = TRUE;
+ (void)Lst_AtEnd(variables, (ClientData)optarg);
+ Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ case 'B':
+ compatMake = TRUE;
+ break;
+#ifdef REMOTE
+ case 'L':
+ maxLocal = atoi(optarg);
+ Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+#endif
+ case 'P':
+ usePipes = FALSE;
+ Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL);
+ break;
+ case 'S':
+ keepgoing = FALSE;
+ Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
+ break;
+ case 'd': {
+ char *modules = optarg;
+
+ for (; *modules; ++modules)
+ switch (*modules) {
+ case 'A':
+ debug = ~0;
+ break;
+ case 'a':
+ debug |= DEBUG_ARCH;
+ break;
+ case 'c':
+ debug |= DEBUG_COND;
+ break;
+ case 'd':
+ debug |= DEBUG_DIR;
+ break;
+ case 'f':
+ debug |= DEBUG_FOR;
+ break;
+ case 'g':
+ if (modules[1] == '1') {
+ debug |= DEBUG_GRAPH1;
+ ++modules;
+ }
+ else if (modules[1] == '2') {
+ debug |= DEBUG_GRAPH2;
+ ++modules;
+ }
+ break;
+ case 'j':
+ debug |= DEBUG_JOB;
+ break;
+ case 'm':
+ debug |= DEBUG_MAKE;
+ break;
+ case 's':
+ debug |= DEBUG_SUFF;
+ break;
+ case 't':
+ debug |= DEBUG_TARG;
+ break;
+ case 'v':
+ debug |= DEBUG_VAR;
+ break;
+ default:
+ (void)fprintf(stderr,
+ "make: illegal argument to d option -- %c\n",
+ *modules);
+ usage();
+ }
+ Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ }
+ case 'e':
+ checkEnvFirst = TRUE;
+ Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
+ break;
+ case 'f':
+ (void)Lst_AtEnd(makefiles, (ClientData)optarg);
+ break;
+ case 'i':
+ ignoreErrors = TRUE;
+ Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
+ break;
+ case 'j':
+ forceJobs = TRUE;
+ maxJobs = atoi(optarg);
+#ifndef REMOTE
+ maxLocal = maxJobs;
+#endif
+ Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ case 'k':
+ keepgoing = TRUE;
+ Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
+ break;
+ case 'm':
+ Dir_AddDir(sysIncPath, optarg);
+ Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ break;
+ case 'n':
+ noExecute = TRUE;
+ Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
+ break;
+ case 'q':
+ queryFlag = TRUE;
+ /* Kind of nonsensical, wot? */
+ Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
+ break;
+ case 'r':
+ noBuiltins = TRUE;
+ Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
+ break;
+ case 's':
+ beSilent = TRUE;
+ Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
+ break;
+ case 't':
+ touchFlag = TRUE;
+ Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
+ break;
+ default:
+ case '?':
+ usage();
+ }
+ }
+
+ /*
+ * Be compatible if user did not specify -j and did not explicitly
+ * turned compatibility on
+ */
+ if (!compatMake && !forceJobs)
+ compatMake = TRUE;
+
+ oldVars = TRUE;
+
+ /*
+ * See if the rest of the arguments are variable assignments and
+ * perform them if so. Else take them to be targets and stuff them
+ * on the end of the "create" list.
+ */
+ for (argv += optind, argc -= optind; *argv; ++argv, --argc)
+ if (Parse_IsVar(*argv))
+ Parse_DoVar(*argv, VAR_CMD);
+ else {
+ if (!**argv)
+ Punt("illegal (null) argument.");
+ if (**argv == '-') {
+ if ((*argv)[1])
+ optind = 0; /* -flag... */
+ else
+ optind = 1; /* - */
+ goto rearg;
+ }
+ (void)Lst_AtEnd(create, (ClientData)estrdup(*argv));
+ }
+}
+
+/*-
+ * Main_ParseArgLine --
+ * Used by the parse module when a .MFLAGS or .MAKEFLAGS target
+ * is encountered and by main() when reading the .MAKEFLAGS envariable.
+ * Takes a line of arguments and breaks it into its
+ * component words and passes those words and the number of them to the
+ * MainParseArgs function.
+ * The line should have all its leading whitespace removed.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Only those that come from the various arguments.
+ */
+void
+Main_ParseArgLine(line)
+ char *line; /* Line to fracture */
+{
+ char **argv; /* Manufactured argument vector */
+ int argc; /* Number of arguments in argv */
+
+ if (line == NULL)
+ return;
+ for (; *line == ' '; ++line)
+ continue;
+ if (!*line)
+ return;
+
+ argv = brk_string(line, &argc, TRUE);
+ MainParseArgs(argc, argv);
+}
+
+char *
+chdir_verify_path(path, obpath)
+ char *path;
+ char *obpath;
+{
+ struct stat sb;
+
+ if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ if (chdir(path)) {
+ (void)fprintf(stderr, "make warning: %s: %s.\n",
+ path, strerror(errno));
+ return 0;
+ }
+ else {
+ if (path[0] != '/') {
+ (void) snprintf(obpath, MAXPATHLEN, "%s/%s",
+ curdir, path);
+ return obpath;
+ }
+ else
+ return path;
+ }
+ }
+
+ return 0;
+}
+
+
+/*-
+ * main --
+ * The main function, for obvious reasons. Initializes variables
+ * and a few modules, then parses the arguments give it in the
+ * environment and on the command line. Reads the system makefile
+ * followed by either Makefile, makefile or the file given by the
+ * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
+ * flags it has received by then uses either the Make or the Compat
+ * module to create the initial list of targets.
+ *
+ * Results:
+ * If -q was given, exits -1 if anything was out-of-date. Else it exits
+ * 0.
+ *
+ * Side Effects:
+ * The program exits when done. Targets are created. etc. etc. etc.
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ Lst targs; /* target nodes to create -- passed to Make_Init */
+ Boolean outOfDate = TRUE; /* FALSE if all targets up to date */
+ struct stat sb, sa;
+ char *p, *p1, *path, *pathp, *pwd;
+ char mdpath[MAXPATHLEN + 1];
+ char obpath[MAXPATHLEN + 1];
+ char cdpath[MAXPATHLEN + 1];
+ char *machine = getenv("MACHINE");
+ Lst sysMkPath; /* Path of sys.mk */
+ char *cp = NULL, *start;
+ /* avoid faults on read-only strings */
+ static char syspath[] = _PATH_DEFSYSPATH;
+
+#ifdef RLIMIT_NOFILE
+ /*
+ * get rid of resource limit on file descriptors
+ */
+ {
+ struct rlimit rl;
+ if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
+ rl.rlim_cur != rl.rlim_max) {
+ rl.rlim_cur = rl.rlim_max;
+ (void) setrlimit(RLIMIT_NOFILE, &rl);
+ }
+ }
+#endif
+ /*
+ * Find where we are and take care of PWD for the automounter...
+ * All this code is so that we know where we are when we start up
+ * on a different machine with pmake.
+ */
+ curdir = cdpath;
+ if (getcwd(curdir, MAXPATHLEN) == NULL) {
+ (void)fprintf(stderr, "make: %s.\n", strerror(errno));
+ exit(2);
+ }
+
+ if (stat(curdir, &sa) == -1) {
+ (void)fprintf(stderr, "make: %s: %s.\n",
+ curdir, strerror(errno));
+ exit(2);
+ }
+
+ if ((pwd = getenv("PWD")) != NULL) {
+ if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino &&
+ sa.st_dev == sb.st_dev)
+ (void) strcpy(curdir, pwd);
+ }
+
+ /*
+ * Get the name of this type of MACHINE from utsname
+ * so we can share an executable for similar machines.
+ * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
+ *
+ * Note that while MACHINE is decided at run-time,
+ * MACHINE_ARCH is always known at compile time.
+ */
+ if (!machine) {
+#ifndef MACHINE
+ struct utsname utsname;
+
+ if (uname(&utsname) == -1) {
+ perror("make: uname");
+ exit(2);
+ }
+ machine = utsname.machine;
+#else
+ machine = MACHINE;
+#endif
+ }
+
+ /*
+ * The object directory location is determined using the
+ * following order of preference:
+ *
+ * 1. MAKEOBJDIRPREFIX`cwd`
+ * 2. MAKEOBJDIR
+ * 3. _PATH_OBJDIR.${MACHINE}
+ * 4. _PATH_OBJDIR
+ * 5. _PATH_OBJDIRPREFIX${MACHINE}
+ *
+ * If all fails, use the current directory to build.
+ *
+ * Once things are initted,
+ * have to add the original directory to the search path,
+ * and modify the paths for the Makefiles apropriately. The
+ * current directory is also placed as a variable for make scripts.
+ */
+ if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) {
+ if (!(path = getenv("MAKEOBJDIR"))) {
+ path = _PATH_OBJDIR;
+ pathp = _PATH_OBJDIRPREFIX;
+ (void) snprintf(mdpath, MAXPATHLEN, "%s.%s",
+ path, machine);
+ if (!(objdir = chdir_verify_path(mdpath, obpath)))
+ if (!(objdir=chdir_verify_path(path, obpath))) {
+ (void) snprintf(mdpath, MAXPATHLEN,
+ "%s%s", pathp, curdir);
+ if (!(objdir=chdir_verify_path(mdpath,
+ obpath)))
+ objdir = curdir;
+ }
+ }
+ else if (!(objdir = chdir_verify_path(path, obpath)))
+ objdir = curdir;
+ }
+ else {
+ (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir);
+ if (!(objdir = chdir_verify_path(mdpath, obpath)))
+ objdir = curdir;
+ }
+
+ setenv("PWD", objdir, 1);
+
+ create = Lst_Init(FALSE);
+ makefiles = Lst_Init(FALSE);
+ printVars = FALSE;
+ variables = Lst_Init(FALSE);
+ beSilent = FALSE; /* Print commands as executed */
+ ignoreErrors = FALSE; /* Pay attention to non-zero returns */
+ noExecute = FALSE; /* Execute all commands */
+ keepgoing = FALSE; /* Stop on error */
+ allPrecious = FALSE; /* Remove targets when interrupted */
+ queryFlag = FALSE; /* This is not just a check-run */
+ noBuiltins = FALSE; /* Read the built-in rules */
+ touchFlag = FALSE; /* Actually update targets */
+ usePipes = TRUE; /* Catch child output in pipes */
+ debug = 0; /* No debug verbosity, please. */
+ jobsRunning = FALSE;
+
+ maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */
+#ifdef REMOTE
+ maxJobs = DEFMAXJOBS; /* Set default max concurrency */
+#else
+ maxJobs = maxLocal;
+#endif
+ compatMake = FALSE; /* No compat mode */
+
+
+ /*
+ * Initialize the parsing, directory and variable modules to prepare
+ * for the reading of inclusion paths and variable settings on the
+ * command line
+ */
+ Dir_Init(); /* Initialize directory structures so -I flags
+ * can be processed correctly */
+ Parse_Init(); /* Need to initialize the paths of #include
+ * directories */
+ Var_Init(); /* As well as the lists of variables for
+ * parsing arguments */
+ str_init();
+ if (objdir != curdir)
+ Dir_AddDir(dirSearchPath, curdir);
+ Var_Set(".CURDIR", curdir, VAR_GLOBAL);
+ Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
+
+ /*
+ * Initialize various variables.
+ * MAKE also gets this name, for compatibility
+ * .MAKEFLAGS gets set to the empty string just in case.
+ * MFLAGS also gets initialized empty, for compatibility.
+ */
+ Var_Set("MAKE", argv[0], VAR_GLOBAL);
+ Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
+ Var_Set("MFLAGS", "", VAR_GLOBAL);
+ Var_Set("MACHINE", machine, VAR_GLOBAL);
+#ifdef MACHINE_ARCH
+ Var_Set("MACHINE_ARCH", MACHINE_ARCH, VAR_GLOBAL);
+#endif
+
+ /*
+ * First snag any flags out of the MAKE environment variable.
+ * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
+ * in a different format).
+ */
+#ifdef POSIX
+ Main_ParseArgLine(getenv("MAKEFLAGS"));
+#else
+ Main_ParseArgLine(getenv("MAKE"));
+#endif
+
+ MainParseArgs(argc, argv);
+
+ /*
+ * Initialize archive, target and suffix modules in preparation for
+ * parsing the makefile(s)
+ */
+ Arch_Init();
+ Targ_Init();
+ Suff_Init();
+
+ DEFAULT = NILGNODE;
+ (void)time(&now);
+
+ /*
+ * Set up the .TARGETS variable to contain the list of targets to be
+ * created. If none specified, make the variable empty -- the parser
+ * will fill the thing in with the default or .MAIN target.
+ */
+ if (!Lst_IsEmpty(create)) {
+ LstNode ln;
+
+ for (ln = Lst_First(create); ln != NILLNODE;
+ ln = Lst_Succ(ln)) {
+ char *name = (char *)Lst_Datum(ln);
+
+ Var_Append(".TARGETS", name, VAR_GLOBAL);
+ }
+ } else
+ Var_Set(".TARGETS", "", VAR_GLOBAL);
+
+
+ /*
+ * If no user-supplied system path was given (through the -m option)
+ * add the directories from the DEFSYSPATH (more than one may be given
+ * as dir1:...:dirn) to the system include path.
+ */
+ if (Lst_IsEmpty(sysIncPath)) {
+ for (start = syspath; *start != '\0'; start = cp) {
+ for (cp = start; *cp != '\0' && *cp != ':'; cp++)
+ continue;
+ if (*cp == '\0') {
+ Dir_AddDir(sysIncPath, start);
+ } else {
+ *cp++ = '\0';
+ Dir_AddDir(sysIncPath, start);
+ }
+ }
+ }
+
+ /*
+ * Read in the built-in rules first, followed by the specified
+ * makefile, if it was (makefile != (char *) NULL), or the default
+ * Makefile and makefile, in that order, if it wasn't.
+ */
+ if (!noBuiltins) {
+ LstNode ln;
+
+ sysMkPath = Lst_Init (FALSE);
+ Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath);
+ if (Lst_IsEmpty(sysMkPath))
+ Fatal("make: no system rules (%s).", _PATH_DEFSYSMK);
+ ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile);
+ if (ln != NILLNODE)
+ Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
+ }
+
+ if (!Lst_IsEmpty(makefiles)) {
+ LstNode ln;
+
+ ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);
+ if (ln != NILLNODE)
+ Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
+ } else if (!ReadMakefile("makefile", NULL))
+ (void)ReadMakefile("Makefile", NULL);
+
+ (void)ReadMakefile(".depend", NULL);
+
+ Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
+ if (p1)
+ free(p1);
+
+ /* Install all the flags into the MAKE envariable. */
+ if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p)
+#ifdef POSIX
+ setenv("MAKEFLAGS", p, 1);
+#else
+ setenv("MAKE", p, 1);
+#endif
+ if (p1)
+ free(p1);
+
+ /*
+ * For compatibility, look at the directories in the VPATH variable
+ * and add them to the search path, if the variable is defined. The
+ * variable's value is in the same format as the PATH envariable, i.e.
+ * <directory>:<directory>:<directory>...
+ */
+ if (Var_Exists("VPATH", VAR_CMD)) {
+ char *vpath, *path, *cp, savec;
+ /*
+ * GCC stores string constants in read-only memory, but
+ * Var_Subst will want to write this thing, so store it
+ * in an array
+ */
+ static char VPATH[] = "${VPATH}";
+
+ vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE);
+ path = vpath;
+ do {
+ /* skip to end of directory */
+ for (cp = path; *cp != ':' && *cp != '\0'; cp++)
+ continue;
+ /* Save terminator character so know when to stop */
+ savec = *cp;
+ *cp = '\0';
+ /* Add directory to search path */
+ Dir_AddDir(dirSearchPath, path);
+ *cp = savec;
+ path = cp + 1;
+ } while (savec == ':');
+ (void)free((Address)vpath);
+ }
+
+ /*
+ * Now that all search paths have been read for suffixes et al, it's
+ * time to add the default search path to their lists...
+ */
+ Suff_DoPaths();
+
+ /* print the initial graph, if the user requested it */
+ if (DEBUG(GRAPH1))
+ Targ_PrintGraph(1);
+
+ /* print the values of any variables requested by the user */
+ if (printVars) {
+ LstNode ln;
+
+ for (ln = Lst_First(variables); ln != NILLNODE;
+ ln = Lst_Succ(ln)) {
+ char *value = Var_Value((char *)Lst_Datum(ln),
+ VAR_GLOBAL, &p1);
+
+ printf("%s\n", value ? value : "");
+ if (p1)
+ free(p1);
+ }
+ }
+
+ /*
+ * Have now read the entire graph and need to make a list of targets
+ * to create. If none was given on the command line, we consult the
+ * parsing module to find the main target(s) to create.
+ */
+ if (Lst_IsEmpty(create))
+ targs = Parse_MainName();
+ else
+ targs = Targ_FindList(create, TARG_CREATE);
+
+ if (!compatMake && !printVars) {
+ /*
+ * Initialize job module before traversing the graph, now that
+ * any .BEGIN and .END targets have been read. This is done
+ * only if the -q flag wasn't given (to prevent the .BEGIN from
+ * being executed should it exist).
+ */
+ if (!queryFlag) {
+ if (maxLocal == -1)
+ maxLocal = maxJobs;
+ Job_Init(maxJobs, maxLocal);
+ jobsRunning = TRUE;
+ }
+
+ /* Traverse the graph, checking on all the targets */
+ outOfDate = Make_Run(targs);
+ } else if (!printVars) {
+ /*
+ * Compat_Init will take care of creating all the targets as
+ * well as initializing the module.
+ */
+ Compat_Run(targs);
+ }
+
+ Lst_Destroy(targs, NOFREE);
+ Lst_Destroy(variables, NOFREE);
+ Lst_Destroy(makefiles, NOFREE);
+ Lst_Destroy(create, (void (*) __P((ClientData))) free);
+
+ /* print the graph now it's been processed if the user requested it */
+ if (DEBUG(GRAPH2))
+ Targ_PrintGraph(2);
+
+ Suff_End();
+ Targ_End();
+ Arch_End();
+ str_end();
+ Var_End();
+ Parse_End();
+ Dir_End();
+
+ if (queryFlag && outOfDate)
+ return(1);
+ else
+ return(0);
+}
+
+/*-
+ * ReadMakefile --
+ * Open and parse the given makefile.
+ *
+ * Results:
+ * TRUE if ok. FALSE if couldn't open file.
+ *
+ * Side Effects:
+ * lots
+ */
+static Boolean
+ReadMakefile(p, q)
+ ClientData p, q;
+{
+ char *fname = p; /* makefile to read */
+ extern Lst parseIncPath;
+ FILE *stream;
+ char *name, path[MAXPATHLEN + 1];
+
+ if (!strcmp(fname, "-")) {
+ Parse_File("(stdin)", stdin);
+ Var_Set("MAKEFILE", "", VAR_GLOBAL);
+ } else {
+ if ((stream = fopen(fname, "r")) != NULL)
+ goto found;
+ /* if we've chdir'd, rebuild the path name */
+ if (curdir != objdir && *fname != '/') {
+ (void)sprintf(path, "%s/%s", curdir, fname);
+ if ((stream = fopen(path, "r")) != NULL) {
+ fname = path;
+ goto found;
+ }
+ }
+ /* look in -I and system include directories. */
+ name = Dir_FindFile(fname, parseIncPath);
+ if (!name)
+ name = Dir_FindFile(fname, sysIncPath);
+ if (!name || !(stream = fopen(name, "r")))
+ return(FALSE);
+ fname = name;
+ /*
+ * set the MAKEFILE variable desired by System V fans -- the
+ * placement of the setting here means it gets set to the last
+ * makefile specified, as it is set by SysV make.
+ */
+found: Var_Set("MAKEFILE", fname, VAR_GLOBAL);
+ Parse_File(fname, stream);
+ (void)fclose(stream);
+ }
+ return(TRUE);
+}
+
+/*-
+ * Cmd_Exec --
+ * Execute the command in cmd, and return the output of that command
+ * in a string.
+ *
+ * Results:
+ * A string containing the output of the command, or the empty string
+ * If err is not NULL, it contains the reason for the command failure
+ *
+ * Side Effects:
+ * The string must be freed by the caller.
+ */
+char *
+Cmd_Exec(cmd, err)
+ char *cmd;
+ char **err;
+{
+ char *args[4]; /* Args for invoking the shell */
+ int fds[2]; /* Pipe streams */
+ int cpid; /* Child PID */
+ int pid; /* PID from wait() */
+ char *res; /* result */
+ int status; /* command exit status */
+ Buffer buf; /* buffer to store the result */
+ char *cp;
+ int cc;
+
+
+ *err = NULL;
+
+ /*
+ * Set up arguments for shell
+ */
+ args[0] = "sh";
+ args[1] = "-c";
+ args[2] = cmd;
+ args[3] = NULL;
+
+ /*
+ * Open a pipe for fetching its output
+ */
+ if (pipe(fds) == -1) {
+ *err = "Couldn't create pipe for \"%s\"";
+ goto bad;
+ }
+
+ /*
+ * Fork
+ */
+ switch (cpid = vfork()) {
+ case 0:
+ /*
+ * Close input side of pipe
+ */
+ (void) close(fds[0]);
+
+ /*
+ * Duplicate the output stream to the shell's output, then
+ * shut the extra thing down. Note we don't fetch the error
+ * stream...why not? Why?
+ */
+ (void) dup2(fds[1], 1);
+ (void) close(fds[1]);
+
+ (void) execv("/bin/sh", args);
+ _exit(1);
+ /*NOTREACHED*/
+
+ case -1:
+ *err = "Couldn't exec \"%s\"";
+ goto bad;
+
+ default:
+ /*
+ * No need for the writing half
+ */
+ (void) close(fds[1]);
+
+ buf = Buf_Init (MAKE_BSIZE);
+
+ do {
+ char result[BUFSIZ];
+ cc = read(fds[0], result, sizeof(result));
+ if (cc > 0)
+ Buf_AddBytes(buf, cc, (Byte *) result);
+ }
+ while (cc > 0 || (cc == -1 && errno == EINTR));
+
+ /*
+ * Close the input side of the pipe.
+ */
+ (void) close(fds[0]);
+
+ /*
+ * Wait for the process to exit.
+ */
+ while(((pid = wait(&status)) != cpid) && (pid >= 0))
+ continue;
+
+ if (cc == -1)
+ *err = "Error reading shell's output for \"%s\"";
+
+ res = (char *)Buf_GetAll (buf, &cc);
+ Buf_Destroy (buf, FALSE);
+
+ if (status)
+ *err = "\"%s\" returned non-zero status";
+
+ /*
+ * Null-terminate the result, convert newlines to spaces and
+ * install it in the variable.
+ */
+ res[cc] = '\0';
+ cp = &res[cc] - 1;
+
+ if (*cp == '\n') {
+ /*
+ * A final newline is just stripped
+ */
+ *cp-- = '\0';
+ }
+ while (cp >= res) {
+ if (*cp == '\n') {
+ *cp = ' ';
+ }
+ cp--;
+ }
+ break;
+ }
+ return res;
+bad:
+ res = emalloc(1);
+ *res = '\0';
+ return res;
+}
+
+/*-
+ * Error --
+ * Print an error message given its format.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The message is printed.
+ */
+/* VARARGS */
+void
+#if __STDC__
+Error(char *fmt, ...)
+#else
+Error(va_alist)
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ char *fmt;
+
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+#endif
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+}
+
+/*-
+ * Fatal --
+ * Produce a Fatal error message. If jobs are running, waits for them
+ * to finish.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The program exits
+ */
+/* VARARGS */
+void
+#if __STDC__
+Fatal(char *fmt, ...)
+#else
+Fatal(va_alist)
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ char *fmt;
+
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+#endif
+ if (jobsRunning)
+ Job_Wait();
+
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+
+ if (DEBUG(GRAPH2))
+ Targ_PrintGraph(2);
+ exit(2); /* Not 1 so -q can distinguish error */
+}
+
+/*
+ * Punt --
+ * Major exception once jobs are being created. Kills all jobs, prints
+ * a message and exits.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * All children are killed indiscriminately and the program Lib_Exits
+ */
+/* VARARGS */
+void
+#if __STDC__
+Punt(char *fmt, ...)
+#else
+Punt(va_alist)
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ char *fmt;
+
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+#endif
+
+ (void)fprintf(stderr, "make: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+
+ DieHorribly();
+}
+
+/*-
+ * DieHorribly --
+ * Exit without giving a message.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * A big one...
+ */
+void
+DieHorribly()
+{
+ if (jobsRunning)
+ Job_AbortAll();
+ if (DEBUG(GRAPH2))
+ Targ_PrintGraph(2);
+ exit(2); /* Not 1, so -q can distinguish error */
+}
+
+/*
+ * Finish --
+ * Called when aborting due to errors in child shell to signal
+ * abnormal exit.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The program exits
+ */
+void
+Finish(errors)
+ int errors; /* number of errors encountered in Make_Make */
+{
+ Fatal("%d error%s", errors, errors == 1 ? "" : "s");
+}
+
+/*
+ * emalloc --
+ * malloc, but die on error.
+ */
+void *
+emalloc(len)
+ size_t len;
+{
+ void *p;
+
+ if ((p = malloc(len)) == NULL)
+ enomem();
+ return(p);
+}
+
+/*
+ * estrdup --
+ * strdup, but die on error.
+ */
+char *
+estrdup(str)
+ const char *str;
+{
+ char *p;
+
+ if ((p = strdup(str)) == NULL)
+ enomem();
+ return(p);
+}
+
+/*
+ * erealloc --
+ * realloc, but die on error.
+ */
+void *
+erealloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ if ((ptr = realloc(ptr, size)) == NULL)
+ enomem();
+ return(ptr);
+}
+
+/*
+ * enomem --
+ * die when out of memory.
+ */
+void
+enomem()
+{
+ (void)fprintf(stderr, "make: %s.\n", strerror(errno));
+ exit(2);
+}
+
+/*
+ * enunlink --
+ * Remove a file carefully, avoiding directories.
+ */
+int
+eunlink(file)
+ const char *file;
+{
+ struct stat st;
+
+ if (lstat(file, &st) == -1)
+ return -1;
+
+ if (S_ISDIR(st.st_mode)) {
+ errno = EISDIR;
+ return -1;
+ }
+ return unlink(file);
+}
+
+/*
+ * usage --
+ * exit with usage message
+ */
+static void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: make [-Beiknqrst] [-D variable] [-d flags] [-f makefile ]\n\
+ [-I directory] [-j max_jobs] [-m directory] [-V variable]\n\
+ [variable=value] [target ...]\n");
+ exit(2);
+}
+
+
+int
+PrintAddr(a, b)
+ ClientData a;
+ ClientData b;
+{
+ printf("%lx ", (unsigned long) a);
+ return b ? 0 : 0;
+}
diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1
new file mode 100644
index 0000000..8214e9a
--- /dev/null
+++ b/usr.bin/make/make.1
@@ -0,0 +1,966 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
+.\" $Id$
+.\"
+.Dd March 19, 1994
+.Dt MAKE 1
+.Os
+.Sh NAME
+.Nm make
+.Nd maintain program dependencies
+.Sh SYNOPSIS
+.Nm make
+.Op Fl Beiknqrst
+.Op Fl D Ar variable
+.Op Fl d Ar flags
+.Op Fl f Ar makefile
+.Op Fl I Ar directory
+.Bk -words
+.Op Fl j Ar max_jobs
+.Op Fl m Ar directory
+.Ek
+.Op Fl V Ar variable
+.Op Ar variable=value
+.Op Ar target ...
+.Sh DESCRIPTION
+.Nm Make
+is a program designed to simplify the maintenance of other programs.
+Its input is a list of specifications as to the files upon which programs
+and other files depend.
+If the file
+.Ql Pa makefile
+exists, it is read for this list of specifications.
+If it does not exist, the file
+.Ql Pa Makefile
+is read.
+If the file
+.Ql Pa .depend
+exists, it is read (see
+.Xr mkdep 1) .
+.Pp
+This manual page is intended as a reference document only.
+For a more thorough description of
+.Nm make
+and makefiles, please refer to
+.%T "Make \- A Tutorial" .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl B
+Try to be backwards compatible by executing a single shell per command and
+by executing the commands to make the sources of a dependency line in sequence.
+.It Fl D Ar variable
+Define
+.Ar variable
+to be 1, in the global context.
+.It Fl d Ar flags
+Turn on debugging, and specify which portions of
+.Nm make
+are to print debugging information.
+.Ar Flags
+is one or more of the following:
+.Bl -tag -width Ds
+.It Ar A
+Print all possible debugging information;
+equivalent to specifying all of the debugging flags.
+.It Ar a
+Print debugging information about archive searching and caching.
+.It Ar c
+Print debugging information about conditional evaluation.
+.It Ar d
+Print debugging information about directory searching and caching.
+.It Ar "g1"
+Print the input graph before making anything.
+.It Ar "g2"
+Print the input graph after making everything, or before exiting
+on error.
+.It Ar j
+Print debugging information about running multiple shells.
+.It Ar m
+Print debugging information about making targets, including modification
+dates.
+.It Ar s
+Print debugging information about suffix-transformation rules.
+.It Ar t
+Print debugging information about target list maintenance.
+.It Ar v
+Print debugging information about variable assignment.
+.El
+.It Fl e
+Specify that environmental variables override macro assignments within
+makefiles.
+.It Fl f Ar makefile
+Specify a makefile to read instead of the default
+.Ql Pa makefile
+and
+.Ql Pa Makefile .
+If
+.Ar makefile
+is
+.Ql Fl ,
+standard input is read.
+Multiple makefile's may be specified, and are read in the order specified.
+.It Fl I Ar directory
+Specify a directory in which to search for makefiles and included makefiles.
+The system makefile directory (or directories, see the
+.Fl m
+option) is automatically included as part of this list.
+.It Fl i
+Ignore non-zero exit of shell commands in the makefile.
+Equivalent to specifying
+.Ql Fl
+before each command line in the makefile.
+.It Fl j Ar max_jobs
+Specify the maximum number of jobs that
+.Nm make
+may have running at any one time. Turns compatibility mode off, unless the
+.Ar B
+flag is also specified.
+.It Fl k
+Continue processing after errors are encountered, but only on those targets
+that do not depend on the target whose creation caused the error.
+.It Fl m Ar directory
+Specify a directory in which to search for sys.mk and makefiles included
+via the <...> style. Multiple directories can be added to form a search path.
+This path will override the default system include path: /usr/share/mk.
+Furthermore the system include path will be appended to the search path used
+for "..."-style inclusions (see the
+.Fl I
+option).
+.It Fl n
+Display the commands that would have been executed, but do not actually
+execute them.
+.It Fl q
+Do not execute any commands, but exit 0 if the specified targets are
+up-to-date and 1, otherwise.
+.It Fl r
+Do not use the built-in rules specified in the system makefile.
+.It Fl s
+Do not echo any commands as they are executed.
+Equivalent to specifying
+.Ql Ic @
+before each command line in the makefile.
+.It Fl t
+Rather than re-building a target as specified in the makefile, create it
+or update its modification time to make it appear up-to-date.
+.It Fl V Ar variable
+Print
+.Nm make Ns 's
+idea of the value of
+.Ar variable ,
+in the global context.
+Do not build any targets.
+Multiple instances of this option may be specified;
+the variables will be printed one per line,
+with a blank line for each null or undefined variable.
+.It Ar variable=value
+Set the value of the variable
+.Ar variable
+to
+.Ar value .
+.El
+.Pp
+There are seven different types of lines in a makefile: file dependency
+specifications, shell commands, variable assignments, include statements,
+conditional directives, for loops, and comments.
+.Pp
+In general, lines may be continued from one line to the next by ending
+them with a backslash
+.Pq Ql \e .
+The trailing newline character and initial whitespace on the following
+line are compressed into a single space.
+.Sh FILE DEPENDENCY SPECIFICATIONS
+Dependency lines consist of one or more targets, an operator, and zero
+or more sources.
+This creates a relationship where the targets ``depend'' on the sources
+and are usually created from them.
+The exact relationship between the target and the source is determined
+by the operator that separates them.
+The three operators are as follows:
+.Bl -tag -width flag
+.It Ic \&:
+A target is considered out-of-date if its modification time is less than
+those of any of its sources.
+Sources for a target accumulate over dependency lines when this operator
+is used.
+The target is removed if
+.Nm make
+is interrupted.
+.It Ic \&!
+Targets are always re-created, but not until all sources have been
+examined and re-created as necessary.
+Sources for a target accumulate over dependency lines when this operator
+is used.
+The target is removed if
+.Nm make
+is interrupted.
+.It Ic \&::
+If no sources are specified, the target is always re-created.
+Otherwise, a target is considered out-of-date if any of its sources has
+been modified more recently than the target.
+Sources for a target do not accumulate over dependency lines when this
+operator is used.
+The target will not be removed if
+.Nm make
+is interrupted.
+.El
+.Pp
+Targets and sources may contain the shell wildcard values
+.Ql ? ,
+.Ql * ,
+.Ql []
+and
+.Ql {} .
+The values
+.Ql ? ,
+.Ql *
+and
+.Ql []
+may only be used as part of the final
+component of the target or source, and must be used to describe existing
+files.
+The value
+.Ql {}
+need not necessarily be used to describe existing files.
+Expansion is in directory order, not alphabetically as done in the shell.
+.Sh SHELL COMMANDS
+Each target may have associated with it a series of shell commands, normally
+used to create the target.
+Each of the commands in this script
+.Em must
+be preceded by a tab.
+While any target may appear on a dependency line, only one of these
+dependencies may be followed by a creation script, unless the
+.Ql Ic ::
+operator is used.
+.Pp
+If the first or first two characters of the command line are
+.Ql Ic @
+and/or
+.Ql Ic \- ,
+the command is treated specially.
+A
+.Ql Ic @
+causes the command not to be echoed before it is executed.
+A
+.Ql Ic \-
+causes any non-zero exit status of the command line to be ignored.
+.Sh VARIABLE ASSIGNMENTS
+Variables in make are much like variables in the shell, and, by tradition,
+consist of all upper-case letters.
+The five operators that can be used to assign values to variables are as
+follows:
+.Bl -tag -width Ds
+.It Ic \&=
+Assign the value to the variable.
+Any previous value is overridden.
+.It Ic \&+=
+Append the value to the current value of the variable.
+.It Ic \&?=
+Assign the value to the variable if it is not already defined.
+.It Ic \&:=
+Assign with expansion, i.e. expand the value before assigning it
+to the variable.
+Normally, expansion is not done until the variable is referenced.
+.It Ic \&!=
+Expand the value and pass it to the shell for execution and assign
+the result to the variable.
+Any newlines in the result are replaced with spaces.
+.El
+.Pp
+Any white-space before the assigned
+.Ar value
+is removed; if the value is being appended, a single space is inserted
+between the previous contents of the variable and the appended value.
+.Pp
+Variables are expanded by surrounding the variable name with either
+curly braces
+.Pq Ql {}
+or parentheses
+.Pq Ql ()
+and preceding it with
+a dollar sign
+.Pq Ql \&$ .
+If the variable name contains only a single letter, the surrounding
+braces or parentheses are not required.
+This shorter form is not recommended.
+.Pp
+Variable substitution occurs at two distinct times, depending on where
+the variable is being used.
+Variables in dependency lines are expanded as the line is read.
+Variables in shell commands are expanded when the shell command is
+executed.
+.Pp
+The four different classes of variables (in order of increasing precedence)
+are:
+.Bl -tag -width Ds
+.It Environment variables
+Variables defined as part of
+.Nm make Ns 's
+environment.
+.It Global variables
+Variables defined in the makefile or in included makefiles.
+.It Command line variables
+Variables defined as part of the command line.
+.It Local variables
+Variables that are defined specific to a certain target.
+The seven local variables are as follows:
+.Bl -tag -width ".ARCHIVE"
+.It Va .ALLSRC
+The list of all sources for this target; also known as
+.Ql Va \&> .
+.It Va .ARCHIVE
+The name of the archive file.
+.It Va .IMPSRC
+The name/path of the source from which the target is to be transformed
+(the ``implied'' source); also known as
+.Ql Va \&< .
+.It Va .MEMBER
+The name of the archive member.
+.It Va .OODATE
+The list of sources for this target that were deemed out-of-date; also
+known as
+.Ql Va \&? .
+.It Va .PREFIX
+The file prefix of the file, containing only the file portion, no suffix
+or preceding directory components; also known as
+.Ql Va * .
+.It Va .TARGET
+The name of the target; also known as
+.Ql Va @ .
+.El
+.Pp
+The shorter forms
+.Ql Va @ ,
+.Ql Va ? ,
+.Ql Va \&>
+and
+.Ql Va *
+are permitted for backward
+compatibility with historical makefiles and are not recommended.
+The six variables
+.Ql Va "@F" ,
+.Ql Va "@D" ,
+.Ql Va "<F" ,
+.Ql Va "<D" ,
+.Ql Va "*F"
+and
+.Ql Va "*D"
+are
+permitted for compatibility with
+.At V
+makefiles and are not recommended.
+.Pp
+Four of the local variables may be used in sources on dependency lines
+because they expand to the proper value for each target on the line.
+These variables are
+.Ql Va .TARGET ,
+.Ql Va .PREFIX ,
+.Ql Va .ARCHIVE ,
+and
+.Ql Va .MEMBER .
+.Pp
+In addition,
+.Nm make
+sets or knows about the following variables:
+.Bl -tag -width MAKEFLAGS
+.It Va \&$
+A single dollar sign
+.Ql \&$ ,
+i.e.
+.Ql \&$$
+expands to a single dollar
+sign.
+.It Va .MAKE
+The name that
+.Nm make
+was executed with
+.Pq Va argv Op 0
+.It Va .CURDIR
+A path to the directory where
+.Nm make
+was executed.
+.It Va .OBJDIR
+A path to the directory where the targets are built.
+.It Ev MAKEFLAGS
+The environment variable
+.Ql Ev MAKEFLAGS
+may contain anything that
+may be specified on
+.Nm make Ns 's
+command line.
+Anything specified on
+.Nm make Ns 's
+command line is appended to the
+.Ql Ev MAKEFLAGS
+variable which is then
+entered into the environment for all programs which
+.Nm make
+executes.
+.It Ev PWD
+Alternate path to the current directory.
+.Nm make
+normally sets
+.Ql Va .CURDIR
+to the canonical path given by
+.Xr getcwd 2 .
+However, if the environment variable
+.Ql Ev PWD
+is set and gives a path to the current directory, then
+.Nm make
+sets
+.Ql Va .CURDIR
+to the value of
+.Ql Ev PWD
+instead.
+.Ql Ev PWD
+is set to the value of
+.Ql Va .OBJDIR
+for all programs which
+.Nm make
+executes.
+.El
+.Pp
+Variable expansion may be modified to select or modify each word of the
+variable (where a ``word'' is white-space delimited sequence of characters).
+The general format of a variable expansion is as follows:
+.Pp
+.Dl {variable[:modifier[:...]]}
+.Pp
+Each modifier begins with a colon and one of the following
+special characters.
+The colon may be escaped with a backslash
+.Pq Ql \e .
+.Bl -tag -width Cm E\&
+.It Cm E
+Replaces each word in the variable with its suffix.
+.It Cm H
+Replaces each word in the variable with everything but the last component.
+.It Cm M Ns Ar pattern
+Select only those words that match the rest of the modifier.
+The standard shell wildcard characters
+.Pf ( Ql * ,
+.Ql ? ,
+and
+.Ql Op )
+may
+be used.
+The wildcard characters may be escaped with a backslash
+.Pq Ql \e .
+.It Cm N Ns Ar pattern
+This is identical to
+.Ql Cm M ,
+but selects all words which do not match
+the rest of the modifier.
+.It Cm R
+Replaces each word in the variable with everything but its suffix.
+.Sm off
+.It Cm S No \&/ Ar old_pattern Xo
+.No \&/ Ar new_pattern
+.No \&/ Op Cm g
+.Xc
+.Sm on
+Modify the first occurrence of
+.Ar old_pattern
+in each word to be replaced with
+.Ar new_pattern .
+If a
+.Ql g
+is appended to the last slash of the pattern, all occurrences
+in each word are replaced.
+If
+.Ar old_pattern
+begins with a carat
+.Pq Ql ^ ,
+.Ar old_pattern
+is anchored at the beginning of each word.
+If
+.Ar old_pattern
+ends with a dollar sign
+.Pq Ql \&$ ,
+it is anchored at the end of each word.
+Inside
+.Ar new_string ,
+an ampersand
+.Pq Ql &
+is replaced by
+.Ar old_pattern .
+Any character may be used as a delimiter for the parts of the modifier
+string.
+The anchoring, ampersand and delimiter characters may be escaped with a
+backslash
+.Pq Ql \e .
+.Pp
+Variable expansion occurs in the normal fashion inside both
+.Ar old_string
+and
+.Ar new_string
+with the single exception that a backslash is used to prevent the expansion
+of a dollar sign
+.Pq Ql \&$
+not a preceding dollar sign as is usual.
+.It Cm T
+Replaces each word in the variable with its last component.
+.It Ar old_string=new_string
+This is the
+.At V
+style variable substitution.
+It must be the last modifier specified.
+If
+.Ar old_string
+or
+.Ar new_string
+do not contain the pattern matching character
+.Ar %
+then it is assumed that they are
+anchored at the end of each word, so only suffixes or entire
+words may be replaced. Otherwise
+.Ar %
+is the substring of
+.Ar old_string
+to be replaced in
+.Ar new_string
+.El
+.Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS
+Makefile inclusion, conditional structures and for loops reminiscent
+of the C programming language are provided in
+.Nm make .
+All such structures are identified by a line beginning with a single
+dot
+.Pq Ql \&.
+character.
+Files are included with either
+.Ql .include <file>
+or
+.Ql .include \*qfile\*q .
+Variables between the angle brackets or double quotes are expanded
+to form the file name.
+If angle brackets are used, the included makefile is expected to be in
+the system makefile directory.
+If double quotes are used, the including makefile's directory and any
+directories specified using the
+.Fl I
+option are searched before the system
+makefile directory.
+.Pp
+Conditional expressions are also preceded by a single dot as the first
+character of a line.
+The possible conditionals are as follows:
+.Bl -tag -width Ds
+.It Ic .undef Ar variable
+Un-define the specified global variable.
+Only global variables may be un-defined.
+.It Xo
+.Ic \&.if
+.Oo \&! Oc Ns Ar expression
+.Op Ar operator expression ...
+.Xc
+Test the value of an expression.
+.It Xo
+.Ic .ifdef
+.Oo \&! Oc Ns Ar variable
+.Op Ar operator variable ...
+.Xc
+Test the value of a variable.
+.It Xo
+.Ic .ifndef
+.Oo \&! Oc Ns Ar variable
+.Op Ar operator variable ...
+.Xc
+Test the value of a variable.
+.It Xo
+.Ic .ifmake
+.Oo \&! Oc Ns Ar target
+.Op Ar operator target ...
+.Xc
+Test the target being built.
+.It Xo
+.Ic .ifnmake
+.Oo \&! Oc Ar target
+.Op Ar operator target ...
+.Xc
+Test the target being built.
+.It Ic .else
+Reverse the sense of the last conditional.
+.It Xo
+.Ic .elif
+.Oo \&! Oc Ar expression
+.Op Ar operator expression ...
+.Xc
+A combination of
+.Ql Ic .else
+followed by
+.Ql Ic .if .
+.It Xo
+.Ic .elifdef
+.Oo \&! Oc Ns Ar variable
+.Op Ar operator variable ...
+.Xc
+A combination of
+.Ql Ic .else
+followed by
+.Ql Ic .ifdef .
+.It Xo
+.Ic .elifndef
+.Oo \&! Oc Ns Ar variable
+.Op Ar operator variable ...
+.Xc
+A combination of
+.Ql Ic .else
+followed by
+.Ql Ic .ifndef .
+.It Xo
+.Ic .elifmake
+.Oo \&! Oc Ns Ar target
+.Op Ar operator target ...
+.Xc
+A combination of
+.Ql Ic .else
+followed by
+.Ql Ic .ifmake .
+.It Xo
+.Ic .elifnmake
+.Oo \&! Oc Ns Ar target
+.Op Ar operator target ...
+.Xc
+A combination of
+.Ql Ic .else
+followed by
+.Ql Ic .ifnmake .
+.It Ic .endif
+End the body of the conditional.
+.El
+.Pp
+The
+.Ar operator
+may be any one of the following:
+.Bl -tag -width "Cm XX"
+.It Cm \&|\&|
+logical OR
+.It Cm \&&&
+Logical
+.Tn AND ;
+of higher precedence than
+.Dq .
+.El
+.Pp
+As in C,
+.Nm make
+will only evaluate a conditional as far as is necessary to determine
+its value.
+Parentheses may be used to change the order of evaluation.
+The boolean operator
+.Ql Ic \&!
+may be used to logically negate an entire
+conditional.
+It is of higher precedence than
+.Ql Ic \&&& .
+.Pp
+The value of
+.Ar expression
+may be any of the following:
+.Bl -tag -width Ic defined
+.It Ic defined
+Takes a variable name as an argument and evaluates to true if the variable
+has been defined.
+.It Ic make
+Takes a target name as an argument and evaluates to true if the target
+was specified as part of
+.Nm make Ns 's
+command line or was declared the default target (either implicitly or
+explicitly, see
+.Va .MAIN )
+before the line containing the conditional.
+.It Ic empty
+Takes a variable, with possible modifiers, and evaluates to true if
+the expansion of the variable would result in an empty string.
+.It Ic exists
+Takes a file name as an argument and evaluates to true if the file exists.
+The file is searched for on the system search path (see
+.Va .PATH ) .
+.It Ic target
+Takes a target name as an argument and evaluates to true if the target
+has been defined.
+.El
+.Pp
+.Ar Expression
+may also be an arithmetic or string comparison. Variable expansion is
+performed on both sides of the comparison, after which the integral
+values are compared. A value is interpreted as hexadecimal if it is
+preceded by 0x, otherwise it is decimal; octal numbers are not supported.
+The standard C relational operators are all supported. If after
+variable expansion, either the left or right hand side of a
+.Ql Ic ==
+or
+.Ql Ic "!="
+operator is not an integral value, then
+string comparison is performed between the expanded
+variables.
+If no relational operator is given, it is assumed that the expanded
+variable is being compared against 0.
+.Pp
+When
+.Nm make
+is evaluating one of these conditional expression, and it encounters
+a word it doesn't recognize, either the ``make'' or ``defined''
+expression is applied to it, depending on the form of the conditional.
+If the form is
+.Ql Ic .ifdef
+or
+.Ql Ic .ifndef ,
+the ``defined'' expression
+is applied.
+Similarly, if the form is
+.Ql Ic .ifmake
+or
+.Ql Ic .ifnmake , the ``make''
+expression is applied.
+.Pp
+If the conditional evaluates to true the parsing of the makefile continues
+as before.
+If it evaluates to false, the following lines are skipped.
+In both cases this continues until a
+.Ql Ic .else
+or
+.Ql Ic .endif
+is found.
+.Pp
+For loops are typically used to apply a set of rules to a list of files.
+The syntax of a for loop is:
+.Bl -tag -width Ds
+.It Xo
+.Ic \&.for
+.Ar variable
+.Ic in
+.Ar expression
+.Xc
+.It Xo
+<make-rules>
+.Xc
+.It Xo
+.Ic \&.endfor
+.Xc
+.El
+After the for
+.Ic expression
+is evaluated, it is split into words. The
+iteration
+.Ic variable
+is successively set to each word, and substituted in the
+.Ic make-rules
+inside the body of the for loop.
+.Sh COMMENTS
+Comments begin with a hash
+.Pq Ql \&#
+character, anywhere but in a shell
+command line, and continue to the end of the line.
+.Sh SPECIAL SOURCES
+.Bl -tag -width Ic .IGNORE
+.It Ic .IGNORE
+Ignore any errors from the commands associated with this target, exactly
+as if they all were preceded by a dash
+.Pq Ql \- .
+.It Ic .MAKE
+Execute the commands associated with this target even if the
+.Fl n
+or
+.Fl t
+options were specified.
+Normally used to mark recursive
+.Nm make Ns 's .
+.It Ic .NOTMAIN
+Normally
+.Nm make
+selects the first target it encounters as the default target to be built
+if no target was specified.
+This source prevents this target from being selected.
+.It Ic .OPTIONAL
+If a target is marked with this attribute and
+.Nm make
+can't figure out how to create it, it will ignore this fact and assume
+the file isn't needed or already exists.
+.It Ic .PRECIOUS
+When
+.Nm make
+is interrupted, it removes any partially made targets.
+This source prevents the target from being removed.
+.It Ic .SILENT
+Do not echo any of the commands associated with this target, exactly
+as if they all were preceded by an at sign
+.Pq Ql @ .
+.It Ic .USE
+Turn the target into
+.Nm make Ns 's .
+version of a macro.
+When the target is used as a source for another target, the other target
+acquires the commands, sources, and attributes (except for
+.Ic .USE )
+of the
+source.
+If the target already has commands, the
+.Ic .USE
+target's commands are appended
+to them.
+.It Ic .WAIT
+If special
+.Ic .WAIT
+source is appears in a dependency line, the sources that precede it are
+made before the sources that succeed it in the line. Loops are not being
+detected and targets that form loops will be silently ignored.
+.El
+.Sh "SPECIAL TARGETS"
+Special targets may not be included with other targets, i.e. they must be
+the only target specified.
+.Bl -tag -width Ic .BEGIN
+.It Ic .BEGIN
+Any command lines attached to this target are executed before anything
+else is done.
+.It Ic .DEFAULT
+This is sort of a
+.Ic .USE
+rule for any target (that was used only as a
+source) that
+.Nm make
+can't figure out any other way to create.
+Only the shell script is used.
+The
+.Ic .IMPSRC
+variable of a target that inherits
+.Ic .DEFAULT Ns 's
+commands is set
+to the target's own name.
+.It Ic .END
+Any command lines attached to this target are executed after everything
+else is done.
+.It Ic .IGNORE
+Mark each of the sources with the
+.Ic .IGNORE
+attribute.
+If no sources are specified, this is the equivalent of specifying the
+.Fl i
+option.
+.It Ic .INTERRUPT
+If
+.Nm make
+is interrupted, the commands for this target will be executed.
+.It Ic .MAIN
+If no target is specified when
+.Nm make
+is invoked, this target will be built.
+.It Ic .MAKEFLAGS
+This target provides a way to specify flags for
+.Nm make
+when the makefile is used.
+The flags are as if typed to the shell, though the
+.Fl f
+option will have
+no effect.
+.\" XXX: NOT YET!!!!
+.\" .It Ic .NOTPARALLEL
+.\" The named targets are executed in non parallel mode. If no targets are
+.\" specified, then all targets are executed in non parallel mode.
+.It Ic .NOTPARALLEL
+Disable parallel mode.
+.It Ic .NO_PARALLEL
+Same as above, for compatibility with other pmake variants.
+.It Ic .ORDER
+The named targets are made in sequence.
+.\" XXX: NOT YET!!!!
+.\" .It Ic .PARALLEL
+.\" The named targets are executed in parallel mode. If no targets are
+.\" specified, then all targets are executed in parallel mode.
+.It Ic .PATH
+The sources are directories which are to be searched for files not
+found in the current directory.
+If no sources are specified, any previously specified directories are
+deleted.
+.It Ic .PHONY
+Apply the
+.Ic .PHONY
+attribute to any specified sources. Targets with this attribute are always
+considered to be out of date.
+.It Ic .PRECIOUS
+Apply the
+.Ic .PRECIOUS
+attribute to any specified sources.
+If no sources are specified, the
+.Ic .PRECIOUS
+attribute is applied to every
+target in the file.
+.It Ic .SILENT
+Apply the
+.Ic .SILENT
+attribute to any specified sources.
+If no sources are specified, the
+.Ic .SILENT
+attribute is applied to every
+command in the file.
+.It Ic .SUFFIXES
+Each source specifies a suffix to
+.Nm make .
+If no sources are specified, any previous specified suffices are deleted.
+.Sh ENVIRONMENT
+.Nm Make
+utilizes the following environment variables, if they exist:
+.Ev MACHINE ,
+.Ev MAKE ,
+.Ev MAKEFLAGS ,
+.Ev MAKEOBJDIR ,
+.Ev MAKEOBJDIRPREFIX ,
+and
+.Ev PWD .
+.Sh FILES
+.Bl -tag -width /usr/share/doc/psd/12.make -compact
+.It .depend
+list of dependencies
+.It Makefile
+list of dependencies
+.It makefile
+list of dependencies
+.It sys.mk
+system makefile
+.It /usr/share/mk
+system makefile directory
+.It /usr/share/doc/psd/12.make
+PMake tutorial
+.El
+.Sh SEE ALSO
+.Xr mkdep 1
+.Rs
+.%T "PMake - A Tutorial"
+.Re
+.Sh HISTORY
+A
+.Nm Make
+command appeared in
+.At v7 .
diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c
new file mode 100644
index 0000000..c9c4b61
--- /dev/null
+++ b/usr.bin/make/make.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*-
+ * make.c --
+ * The functions which perform the examination of targets and
+ * their suitability for creation
+ *
+ * Interface:
+ * Make_Run Initialize things for the module and recreate
+ * whatever needs recreating. Returns TRUE if
+ * work was (or would have been) done and FALSE
+ * otherwise.
+ *
+ * Make_Update Update all parents of a given child. Performs
+ * various bookkeeping chores like the updating
+ * of the cmtime field of the parent, filling
+ * of the IMPSRC context variable, etc. It will
+ * place the parent on the toBeMade queue if it
+ * should be.
+ *
+ * Make_TimeStamp Function to set the parent's cmtime field
+ * based on a child's modification time.
+ *
+ * Make_DoAllVar Set up the various local variables for a
+ * target, including the .ALLSRC variable, making
+ * sure that any variable that needs to exist
+ * at the very least has the empty value.
+ *
+ * Make_OODate Determine if a target is out-of-date.
+ *
+ * Make_HandleUse See if a child is a .USE node for a parent
+ * and perform the .USE actions if so.
+ */
+
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "job.h"
+
+static Lst toBeMade; /* The current fringe of the graph. These
+ * are nodes which await examination by
+ * MakeOODate. It is added to by
+ * Make_Update and subtracted from by
+ * MakeStartJobs */
+static int numNodes; /* Number of nodes to be processed. If this
+ * is non-zero when Job_Empty() returns
+ * TRUE, there's a cycle in the graph */
+
+static int MakeAddChild __P((ClientData, ClientData));
+static int MakeAddAllSrc __P((ClientData, ClientData));
+static int MakeTimeStamp __P((ClientData, ClientData));
+static int MakeHandleUse __P((ClientData, ClientData));
+static Boolean MakeStartJobs __P((void));
+static int MakePrintStatus __P((ClientData, ClientData));
+/*-
+ *-----------------------------------------------------------------------
+ * Make_TimeStamp --
+ * Set the cmtime field of a parent node based on the mtime stamp in its
+ * child. Called from MakeOODate via Lst_ForEach.
+ *
+ * Results:
+ * Always returns 0.
+ *
+ * Side Effects:
+ * The cmtime of the parent node will be changed if the mtime
+ * field of the child is greater than it.
+ *-----------------------------------------------------------------------
+ */
+int
+Make_TimeStamp (pgn, cgn)
+ GNode *pgn; /* the current parent */
+ GNode *cgn; /* the child we've just examined */
+{
+ if (cgn->mtime > pgn->cmtime) {
+ pgn->cmtime = cgn->mtime;
+ }
+ return (0);
+}
+
+static int
+MakeTimeStamp (pgn, cgn)
+ ClientData pgn; /* the current parent */
+ ClientData cgn; /* the child we've just examined */
+{
+ return Make_TimeStamp((GNode *) pgn, (GNode *) cgn);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Make_OODate --
+ * See if a given node is out of date with respect to its sources.
+ * Used by Make_Run when deciding which nodes to place on the
+ * toBeMade queue initially and by Make_Update to screen out USE and
+ * EXEC nodes. In the latter case, however, any other sort of node
+ * must be considered out-of-date since at least one of its children
+ * will have been recreated.
+ *
+ * Results:
+ * TRUE if the node is out of date. FALSE otherwise.
+ *
+ * Side Effects:
+ * The mtime field of the node and the cmtime field of its parents
+ * will/may be changed.
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Make_OODate (gn)
+ register GNode *gn; /* the node to check */
+{
+ Boolean oodate;
+
+ /*
+ * Certain types of targets needn't even be sought as their datedness
+ * doesn't depend on their modification time...
+ */
+ if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) {
+ (void) Dir_MTime (gn);
+ if (DEBUG(MAKE)) {
+ if (gn->mtime != 0) {
+ printf ("modified %s...", Targ_FmtTime(gn->mtime));
+ } else {
+ printf ("non-existent...");
+ }
+ }
+ }
+
+ /*
+ * A target is remade in one of the following circumstances:
+ * its modification time is smaller than that of its youngest child
+ * and it would actually be run (has commands or type OP_NOP)
+ * it's the object of a force operator
+ * it has no children, was on the lhs of an operator and doesn't exist
+ * already.
+ *
+ * Libraries are only considered out-of-date if the archive module says
+ * they are.
+ *
+ * These weird rules are brought to you by Backward-Compatability and
+ * the strange people who wrote 'Make'.
+ */
+ if (gn->type & OP_USE) {
+ /*
+ * If the node is a USE node it is *never* out of date
+ * no matter *what*.
+ */
+ if (DEBUG(MAKE)) {
+ printf(".USE node...");
+ }
+ oodate = FALSE;
+ } else if (gn->type & OP_LIB) {
+ if (DEBUG(MAKE)) {
+ printf("library...");
+ }
+
+ /*
+ * always out of date if no children and :: target
+ */
+
+ oodate = Arch_LibOODate (gn) ||
+ ((gn->cmtime == 0) && (gn->type & OP_DOUBLEDEP));
+ } else if (gn->type & OP_JOIN) {
+ /*
+ * A target with the .JOIN attribute is only considered
+ * out-of-date if any of its children was out-of-date.
+ */
+ if (DEBUG(MAKE)) {
+ printf(".JOIN node...");
+ }
+ oodate = gn->childMade;
+ } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
+ /*
+ * A node which is the object of the force (!) operator or which has
+ * the .EXEC attribute is always considered out-of-date.
+ */
+ if (DEBUG(MAKE)) {
+ if (gn->type & OP_FORCE) {
+ printf("! operator...");
+ } else if (gn->type & OP_PHONY) {
+ printf(".PHONY node...");
+ } else {
+ printf(".EXEC node...");
+ }
+ }
+ oodate = TRUE;
+ } else if ((gn->mtime < gn->cmtime) ||
+ ((gn->cmtime == 0) &&
+ ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP))))
+ {
+ /*
+ * A node whose modification time is less than that of its
+ * youngest child or that has no children (cmtime == 0) and
+ * either doesn't exist (mtime == 0) or was the object of a
+ * :: operator is out-of-date. Why? Because that's the way Make does
+ * it.
+ */
+ if (DEBUG(MAKE)) {
+ if (gn->mtime < gn->cmtime) {
+ printf("modified before source...");
+ } else if (gn->mtime == 0) {
+ printf("non-existent and no sources...");
+ } else {
+ printf(":: operator and no sources...");
+ }
+ }
+ oodate = TRUE;
+ } else {
+#if 0
+ /* WHY? */
+ if (DEBUG(MAKE)) {
+ printf("source %smade...", gn->childMade ? "" : "not ");
+ }
+ oodate = gn->childMade;
+#else
+ oodate = FALSE;
+#endif /* 0 */
+ }
+
+ /*
+ * If the target isn't out-of-date, the parents need to know its
+ * modification time. Note that targets that appear to be out-of-date
+ * but aren't, because they have no commands and aren't of type OP_NOP,
+ * have their mtime stay below their children's mtime to keep parents from
+ * thinking they're out-of-date.
+ */
+ if (!oodate) {
+ Lst_ForEach (gn->parents, MakeTimeStamp, (ClientData)gn);
+ }
+
+ return (oodate);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * MakeAddChild --
+ * Function used by Make_Run to add a child to the list l.
+ * It will only add the child if its make field is FALSE.
+ *
+ * Results:
+ * Always returns 0
+ *
+ * Side Effects:
+ * The given list is extended
+ *-----------------------------------------------------------------------
+ */
+static int
+MakeAddChild (gnp, lp)
+ ClientData gnp; /* the node to add */
+ ClientData lp; /* the list to which to add it */
+{
+ GNode *gn = (GNode *) gnp;
+ Lst l = (Lst) lp;
+ if (!gn->make && !(gn->type & OP_USE)) {
+ (void)Lst_EnQueue (l, (ClientData)gn);
+ }
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Make_HandleUse --
+ * Function called by Make_Run and SuffApplyTransform on the downward
+ * pass to handle .USE and transformation nodes. A callback function
+ * for Lst_ForEach, it implements the .USE and transformation
+ * functionality by copying the node's commands, type flags
+ * and children to the parent node. Should be called before the
+ * children are enqueued to be looked at by MakeAddChild.
+ *
+ * A .USE node is much like an explicit transformation rule, except
+ * its commands are always added to the target node, even if the
+ * target already has commands.
+ *
+ * Results:
+ * returns 0.
+ *
+ * Side Effects:
+ * Children and commands may be added to the parent and the parent's
+ * type may be changed.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Make_HandleUse (cgn, pgn)
+ register GNode *cgn; /* The .USE node */
+ register GNode *pgn; /* The target of the .USE node */
+{
+ register GNode *gn; /* A child of the .USE node */
+ register LstNode ln; /* An element in the children list */
+
+ if (cgn->type & (OP_USE|OP_TRANSFORM)) {
+ if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) {
+ /*
+ * .USE or transformation and target has no commands -- append
+ * the child's commands to the parent.
+ */
+ (void) Lst_Concat (pgn->commands, cgn->commands, LST_CONCNEW);
+ }
+
+ if (Lst_Open (cgn->children) == SUCCESS) {
+ while ((ln = Lst_Next (cgn->children)) != NILLNODE) {
+ gn = (GNode *)Lst_Datum (ln);
+
+ if (Lst_Member (pgn->children, gn) == NILLNODE) {
+ (void) Lst_AtEnd (pgn->children, gn);
+ (void) Lst_AtEnd (gn->parents, pgn);
+ pgn->unmade += 1;
+ }
+ }
+ Lst_Close (cgn->children);
+ }
+
+ pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);
+
+ /*
+ * This child node is now "made", so we decrement the count of
+ * unmade children in the parent... We also remove the child
+ * from the parent's list to accurately reflect the number of decent
+ * children the parent has. This is used by Make_Run to decide
+ * whether to queue the parent or examine its children...
+ */
+ if (cgn->type & OP_USE) {
+ pgn->unmade -= 1;
+ }
+ }
+ return (0);
+}
+static int
+MakeHandleUse (pgn, cgn)
+ ClientData pgn; /* the current parent */
+ ClientData cgn; /* the child we've just examined */
+{
+ return Make_HandleUse((GNode *) pgn, (GNode *) cgn);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Make_Update --
+ * Perform update on the parents of a node. Used by JobFinish once
+ * a node has been dealt with and by MakeStartJobs if it finds an
+ * up-to-date node.
+ *
+ * Results:
+ * Always returns 0
+ *
+ * Side Effects:
+ * The unmade field of pgn is decremented and pgn may be placed on
+ * the toBeMade queue if this field becomes 0.
+ *
+ * If the child was made, the parent's childMade field will be set true
+ * and its cmtime set to now.
+ *
+ * If the child wasn't made, the cmtime field of the parent will be
+ * altered if the child's mtime is big enough.
+ *
+ * Finally, if the child is the implied source for the parent, the
+ * parent's IMPSRC variable is set appropriately.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Make_Update (cgn)
+ register GNode *cgn; /* the child node */
+{
+ register GNode *pgn; /* the parent node */
+ register char *cname; /* the child's name */
+ register LstNode ln; /* Element in parents and iParents lists */
+ char *p1;
+
+ cname = Var_Value (TARGET, cgn, &p1);
+ if (p1)
+ free(p1);
+
+ /*
+ * If the child was actually made, see what its modification time is
+ * now -- some rules won't actually update the file. If the file still
+ * doesn't exist, make its mtime now.
+ */
+ if (cgn->made != UPTODATE) {
+#ifndef RECHECK
+ /*
+ * We can't re-stat the thing, but we can at least take care of rules
+ * where a target depends on a source that actually creates the
+ * target, but only if it has changed, e.g.
+ *
+ * parse.h : parse.o
+ *
+ * parse.o : parse.y
+ * yacc -d parse.y
+ * cc -c y.tab.c
+ * mv y.tab.o parse.o
+ * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
+ *
+ * In this case, if the definitions produced by yacc haven't changed
+ * from before, parse.h won't have been updated and cgn->mtime will
+ * reflect the current modification time for parse.h. This is
+ * something of a kludge, I admit, but it's a useful one..
+ * XXX: People like to use a rule like
+ *
+ * FRC:
+ *
+ * To force things that depend on FRC to be made, so we have to
+ * check for gn->children being empty as well...
+ */
+ if (!Lst_IsEmpty(cgn->commands) || Lst_IsEmpty(cgn->children)) {
+ cgn->mtime = now;
+ }
+#else
+ /*
+ * This is what Make does and it's actually a good thing, as it
+ * allows rules like
+ *
+ * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
+ *
+ * to function as intended. Unfortunately, thanks to the stateless
+ * nature of NFS (by which I mean the loose coupling of two clients
+ * using the same file from a common server), there are times
+ * when the modification time of a file created on a remote
+ * machine will not be modified before the local stat() implied by
+ * the Dir_MTime occurs, thus leading us to believe that the file
+ * is unchanged, wreaking havoc with files that depend on this one.
+ *
+ * I have decided it is better to make too much than to make too
+ * little, so this stuff is commented out unless you're sure it's ok.
+ * -- ardeb 1/12/88
+ */
+ /*
+ * Christos, 4/9/92: If we are saving commands pretend that
+ * the target is made now. Otherwise archives with ... rules
+ * don't work!
+ */
+ if (noExecute || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) {
+ cgn->mtime = now;
+ }
+ if (DEBUG(MAKE)) {
+ printf("update time: %s\n", Targ_FmtTime(cgn->mtime));
+ }
+#endif
+ }
+
+ if (Lst_Open (cgn->parents) == SUCCESS) {
+ while ((ln = Lst_Next (cgn->parents)) != NILLNODE) {
+ pgn = (GNode *)Lst_Datum (ln);
+ if (pgn->make) {
+ pgn->unmade -= 1;
+
+ if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
+ if (cgn->made == MADE) {
+ pgn->childMade = TRUE;
+ if (pgn->cmtime < cgn->mtime) {
+ pgn->cmtime = cgn->mtime;
+ }
+ } else {
+ (void)Make_TimeStamp (pgn, cgn);
+ }
+ }
+ if (pgn->unmade == 0) {
+ /*
+ * Queue the node up -- any unmade predecessors will
+ * be dealt with in MakeStartJobs.
+ */
+ (void)Lst_EnQueue (toBeMade, (ClientData)pgn);
+ } else if (pgn->unmade < 0) {
+ Error ("Graph cycles through %s", pgn->name);
+ }
+ }
+ }
+ Lst_Close (cgn->parents);
+ }
+ /*
+ * Deal with successor nodes. If any is marked for making and has an unmade
+ * count of 0, has not been made and isn't in the examination queue,
+ * it means we need to place it in the queue as it restrained itself
+ * before.
+ */
+ for (ln = Lst_First(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) {
+ GNode *succ = (GNode *)Lst_Datum(ln);
+
+ if (succ->make && succ->unmade == 0 && succ->made == UNMADE &&
+ Lst_Member(toBeMade, (ClientData)succ) == NILLNODE)
+ {
+ (void)Lst_EnQueue(toBeMade, (ClientData)succ);
+ }
+ }
+
+ /*
+ * Set the .PREFIX and .IMPSRC variables for all the implied parents
+ * of this node.
+ */
+ if (Lst_Open (cgn->iParents) == SUCCESS) {
+ char *p1;
+ char *cpref = Var_Value(PREFIX, cgn, &p1);
+
+ while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) {
+ pgn = (GNode *)Lst_Datum (ln);
+ if (pgn->make) {
+ Var_Set (IMPSRC, cname, pgn);
+ Var_Set (PREFIX, cpref, pgn);
+ }
+ }
+ if (p1)
+ free(p1);
+ Lst_Close (cgn->iParents);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * MakeAddAllSrc --
+ * Add a child's name to the ALLSRC and OODATE variables of the given
+ * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only
+ * if it has not been given the .EXEC, .USE or .INVISIBLE attributes.
+ * .EXEC and .USE children are very rarely going to be files, so...
+ * A child is added to the OODATE variable if its modification time is
+ * later than that of its parent, as defined by Make, except if the
+ * parent is a .JOIN node. In that case, it is only added to the OODATE
+ * variable if it was actually made (since .JOIN nodes don't have
+ * modification times, the comparison is rather unfair...)..
+ *
+ * Results:
+ * Always returns 0
+ *
+ * Side Effects:
+ * The ALLSRC variable for the given node is extended.
+ *-----------------------------------------------------------------------
+ */
+static int
+MakeAddAllSrc (cgnp, pgnp)
+ ClientData cgnp; /* The child to add */
+ ClientData pgnp; /* The parent to whose ALLSRC variable it should be */
+ /* added */
+{
+ GNode *cgn = (GNode *) cgnp;
+ GNode *pgn = (GNode *) pgnp;
+ if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) {
+ char *child;
+ char *p1 = NULL;
+
+ if (OP_NOP(cgn->type)) {
+ /*
+ * this node is only source; use the specific pathname for it
+ */
+ child = cgn->path ? cgn->path : cgn->name;
+ }
+ else
+ child = Var_Value(TARGET, cgn, &p1);
+ Var_Append (ALLSRC, child, pgn);
+ if (pgn->type & OP_JOIN) {
+ if (cgn->made == MADE) {
+ Var_Append(OODATE, child, pgn);
+ }
+ } else if ((pgn->mtime < cgn->mtime) ||
+ (cgn->mtime >= now && cgn->made == MADE))
+ {
+ /*
+ * It goes in the OODATE variable if the parent is younger than the
+ * child or if the child has been modified more recently than
+ * the start of the make. This is to keep pmake from getting
+ * confused if something else updates the parent after the
+ * make starts (shouldn't happen, I know, but sometimes it
+ * does). In such a case, if we've updated the kid, the parent
+ * is likely to have a modification time later than that of
+ * the kid and anything that relies on the OODATE variable will
+ * be hosed.
+ *
+ * XXX: This will cause all made children to go in the OODATE
+ * variable, even if they're not touched, if RECHECK isn't defined,
+ * since cgn->mtime is set to now in Make_Update. According to
+ * some people, this is good...
+ */
+ Var_Append(OODATE, child, pgn);
+ }
+ if (p1)
+ free(p1);
+ }
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Make_DoAllVar --
+ * Set up the ALLSRC and OODATE variables. Sad to say, it must be
+ * done separately, rather than while traversing the graph. This is
+ * because Make defined OODATE to contain all sources whose modification
+ * times were later than that of the target, *not* those sources that
+ * were out-of-date. Since in both compatibility and native modes,
+ * the modification time of the parent isn't found until the child
+ * has been dealt with, we have to wait until now to fill in the
+ * variable. As for ALLSRC, the ordering is important and not
+ * guaranteed when in native mode, so it must be set here, too.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The ALLSRC and OODATE variables of the given node is filled in.
+ * If the node is a .JOIN node, its TARGET variable will be set to
+ * match its ALLSRC variable.
+ *-----------------------------------------------------------------------
+ */
+void
+Make_DoAllVar (gn)
+ GNode *gn;
+{
+ Lst_ForEach (gn->children, MakeAddAllSrc, (ClientData) gn);
+
+ if (!Var_Exists (OODATE, gn)) {
+ Var_Set (OODATE, "", gn);
+ }
+ if (!Var_Exists (ALLSRC, gn)) {
+ Var_Set (ALLSRC, "", gn);
+ }
+
+ if (gn->type & OP_JOIN) {
+ char *p1;
+ Var_Set (TARGET, Var_Value (ALLSRC, gn, &p1), gn);
+ if (p1)
+ free(p1);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * MakeStartJobs --
+ * Start as many jobs as possible.
+ *
+ * Results:
+ * If the query flag was given to pmake, no job will be started,
+ * but as soon as an out-of-date target is found, this function
+ * returns TRUE. At all other times, this function returns FALSE.
+ *
+ * Side Effects:
+ * Nodes are removed from the toBeMade queue and job table slots
+ * are filled.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+MakeStartJobs ()
+{
+ register GNode *gn;
+
+ while (!Job_Full() && !Lst_IsEmpty (toBeMade)) {
+ gn = (GNode *) Lst_DeQueue (toBeMade);
+ if (DEBUG(MAKE)) {
+ printf ("Examining %s...", gn->name);
+ }
+ /*
+ * Make sure any and all predecessors that are going to be made,
+ * have been.
+ */
+ if (!Lst_IsEmpty(gn->preds)) {
+ LstNode ln;
+
+ for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){
+ GNode *pgn = (GNode *)Lst_Datum(ln);
+
+ if (pgn->make && pgn->made == UNMADE) {
+ if (DEBUG(MAKE)) {
+ printf("predecessor %s not made yet.\n", pgn->name);
+ }
+ break;
+ }
+ }
+ /*
+ * If ln isn't nil, there's a predecessor as yet unmade, so we
+ * just drop this node on the floor. When the node in question
+ * has been made, it will notice this node as being ready to
+ * make but as yet unmade and will place the node on the queue.
+ */
+ if (ln != NILLNODE) {
+ continue;
+ }
+ }
+
+ numNodes--;
+ if (Make_OODate (gn)) {
+ if (DEBUG(MAKE)) {
+ printf ("out-of-date\n");
+ }
+ if (queryFlag) {
+ return (TRUE);
+ }
+ Make_DoAllVar (gn);
+ Job_Make (gn);
+ } else {
+ if (DEBUG(MAKE)) {
+ printf ("up-to-date\n");
+ }
+ gn->made = UPTODATE;
+ if (gn->type & OP_JOIN) {
+ /*
+ * Even for an up-to-date .JOIN node, we need it to have its
+ * context variables so references to it get the correct
+ * value for .TARGET when building up the context variables
+ * of its parent(s)...
+ */
+ Make_DoAllVar (gn);
+ }
+
+ Make_Update (gn);
+ }
+ }
+ return (FALSE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * MakePrintStatus --
+ * Print the status of a top-level node, viz. it being up-to-date
+ * already or not created due to an error in a lower level.
+ * Callback function for Make_Run via Lst_ForEach.
+ *
+ * Results:
+ * Always returns 0.
+ *
+ * Side Effects:
+ * A message may be printed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+MakePrintStatus(gnp, cyclep)
+ ClientData gnp; /* Node to examine */
+ ClientData cyclep; /* True if gn->unmade being non-zero implies
+ * a cycle in the graph, not an error in an
+ * inferior */
+{
+ GNode *gn = (GNode *) gnp;
+ Boolean cycle = *(Boolean *) cyclep;
+ if (gn->made == UPTODATE) {
+ printf ("`%s' is up to date.\n", gn->name);
+ } else if (gn->unmade != 0) {
+ if (cycle) {
+ Boolean t = TRUE;
+ /*
+ * If printing cycles and came to one that has unmade children,
+ * print out the cycle by recursing on its children. Note a
+ * cycle like:
+ * a : b
+ * b : c
+ * c : b
+ * will cause this to erroneously complain about a being in
+ * the cycle, but this is a good approximation.
+ */
+ if (gn->made == CYCLE) {
+ Error("Graph cycles through `%s'", gn->name);
+ gn->made = ENDCYCLE;
+ Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);
+ gn->made = UNMADE;
+ } else if (gn->made != ENDCYCLE) {
+ gn->made = CYCLE;
+ Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);
+ }
+ } else {
+ printf ("`%s' not remade because of errors.\n", gn->name);
+ }
+ }
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Make_Run --
+ * Initialize the nodes to remake and the list of nodes which are
+ * ready to be made by doing a breadth-first traversal of the graph
+ * starting from the nodes in the given list. Once this traversal
+ * is finished, all the 'leaves' of the graph are in the toBeMade
+ * queue.
+ * Using this queue and the Job module, work back up the graph,
+ * calling on MakeStartJobs to keep the job table as full as
+ * possible.
+ *
+ * Results:
+ * TRUE if work was done. FALSE otherwise.
+ *
+ * Side Effects:
+ * The make field of all nodes involved in the creation of the given
+ * targets is set to 1. The toBeMade list is set to contain all the
+ * 'leaves' of these subgraphs.
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Make_Run (targs)
+ Lst targs; /* the initial list of targets */
+{
+ register GNode *gn; /* a temporary pointer */
+ register Lst examine; /* List of targets to examine */
+ int errors; /* Number of errors the Job module reports */
+
+ toBeMade = Lst_Init (FALSE);
+
+ examine = Lst_Duplicate(targs, NOCOPY);
+ numNodes = 0;
+
+ /*
+ * Make an initial downward pass over the graph, marking nodes to be made
+ * as we go down. We call Suff_FindDeps to find where a node is and
+ * to get some children for it if it has none and also has no commands.
+ * If the node is a leaf, we stick it on the toBeMade queue to
+ * be looked at in a minute, otherwise we add its children to our queue
+ * and go on about our business.
+ */
+ while (!Lst_IsEmpty (examine)) {
+ gn = (GNode *) Lst_DeQueue (examine);
+
+ if (!gn->make) {
+ gn->make = TRUE;
+ numNodes++;
+
+ /*
+ * Apply any .USE rules before looking for implicit dependencies
+ * to make sure everything has commands that should...
+ */
+ Lst_ForEach (gn->children, MakeHandleUse, (ClientData)gn);
+ Suff_FindDeps (gn);
+
+ if (gn->unmade != 0) {
+ Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine);
+ } else {
+ (void)Lst_EnQueue (toBeMade, (ClientData)gn);
+ }
+ }
+ }
+
+ Lst_Destroy (examine, NOFREE);
+
+ if (queryFlag) {
+ /*
+ * We wouldn't do any work unless we could start some jobs in the
+ * next loop... (we won't actually start any, of course, this is just
+ * to see if any of the targets was out of date)
+ */
+ return (MakeStartJobs());
+ } else {
+ /*
+ * Initialization. At the moment, no jobs are running and until some
+ * get started, nothing will happen since the remaining upward
+ * traversal of the graph is performed by the routines in job.c upon
+ * the finishing of a job. So we fill the Job table as much as we can
+ * before going into our loop.
+ */
+ (void) MakeStartJobs();
+ }
+
+ /*
+ * Main Loop: The idea here is that the ending of jobs will take
+ * care of the maintenance of data structures and the waiting for output
+ * will cause us to be idle most of the time while our children run as
+ * much as possible. Because the job table is kept as full as possible,
+ * the only time when it will be empty is when all the jobs which need
+ * running have been run, so that is the end condition of this loop.
+ * Note that the Job module will exit if there were any errors unless the
+ * keepgoing flag was given.
+ */
+ while (!Job_Empty ()) {
+ Job_CatchOutput ();
+ Job_CatchChildren (!usePipes);
+ (void)MakeStartJobs();
+ }
+
+ errors = Job_End();
+
+ /*
+ * Print the final status of each target. E.g. if it wasn't made
+ * because some inferior reported an error.
+ */
+ errors = ((errors == 0) && (numNodes != 0));
+ Lst_ForEach(targs, MakePrintStatus, (ClientData) &errors);
+
+ return (TRUE);
+}
diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h
new file mode 100644
index 0000000..91e2d3a
--- /dev/null
+++ b/usr.bin/make/make.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)make.h 8.3 (Berkeley) 6/13/95
+ * $Id$
+ */
+
+/*-
+ * make.h --
+ * The global definitions for pmake
+ */
+
+#ifndef _MAKE_H_
+#define _MAKE_H_
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if !defined(MAKE_BOOTSTRAP) && defined(BSD)
+#include <sys/cdefs.h>
+#else
+#ifndef __P
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#else
+#define __P(protos) () /* traditional C preprocessor */
+#endif
+#endif
+#endif
+#if __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#include "sprite.h"
+#include "lst.h"
+#include "config.h"
+#include "buf.h"
+
+/*-
+ * The structure for an individual graph node. Each node has several
+ * pieces of data associated with it.
+ * 1) the name of the target it describes
+ * 2) the location of the target file in the file system.
+ * 3) the type of operator used to define its sources (qv. parse.c)
+ * 4) whether it is involved in this invocation of make
+ * 5) whether the target has been remade
+ * 6) whether any of its children has been remade
+ * 7) the number of its children that are, as yet, unmade
+ * 8) its modification time
+ * 9) the modification time of its youngest child (qv. make.c)
+ * 10) a list of nodes for which this is a source
+ * 11) a list of nodes on which this depends
+ * 12) a list of nodes that depend on this, as gleaned from the
+ * transformation rules.
+ * 13) a list of nodes of the same name created by the :: operator
+ * 14) a list of nodes that must be made (if they're made) before
+ * this node can be, but that do no enter into the datedness of
+ * this node.
+ * 15) a list of nodes that must be made (if they're made) after
+ * this node is, but that do not depend on this node, in the
+ * normal sense.
+ * 16) a Lst of ``local'' variables that are specific to this target
+ * and this target only (qv. var.c [$@ $< $?, etc.])
+ * 17) a Lst of strings that are commands to be given to a shell
+ * to create this target.
+ */
+typedef struct GNode {
+ char *name; /* The target's name */
+ char *path; /* The full pathname of the file */
+ int type; /* Its type (see the OP flags, below) */
+ int order; /* Its wait weight */
+
+ Boolean make; /* TRUE if this target needs to be remade */
+ enum {
+ UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED,
+ CYCLE, ENDCYCLE,
+ } made; /* Set to reflect the state of processing
+ * on this node:
+ * UNMADE - Not examined yet
+ * BEINGMADE - Target is already being made.
+ * Indicates a cycle in the graph. (compat
+ * mode only)
+ * MADE - Was out-of-date and has been made
+ * UPTODATE - Was already up-to-date
+ * ERROR - An error occured while it was being
+ * made (used only in compat mode)
+ * ABORTED - The target was aborted due to
+ * an error making an inferior (compat).
+ * CYCLE - Marked as potentially being part of
+ * a graph cycle. If we come back to a
+ * node marked this way, it is printed
+ * and 'made' is changed to ENDCYCLE.
+ * ENDCYCLE - the cycle has been completely
+ * printed. Go back and unmark all its
+ * members.
+ */
+ Boolean childMade; /* TRUE if one of this target's children was
+ * made */
+ int unmade; /* The number of unmade children */
+
+ int mtime; /* Its modification time */
+ int cmtime; /* The modification time of its youngest
+ * child */
+
+ Lst iParents; /* Links to parents for which this is an
+ * implied source, if any */
+ Lst cohorts; /* Other nodes for the :: operator */
+ Lst parents; /* Nodes that depend on this one */
+ Lst children; /* Nodes on which this one depends */
+ Lst successors; /* Nodes that must be made after this one */
+ Lst preds; /* Nodes that must be made before this one */
+
+ Lst context; /* The local variables */
+ Lst commands; /* Creation commands */
+
+ struct _Suff *suffix; /* Suffix for the node (determined by
+ * Suff_FindDeps and opaque to everyone
+ * but the Suff module) */
+} GNode;
+
+/*
+ * Manifest constants
+ */
+#define NILGNODE ((GNode *) NIL)
+
+/*
+ * The OP_ constants are used when parsing a dependency line as a way of
+ * communicating to other parts of the program the way in which a target
+ * should be made. These constants are bitwise-OR'ed together and
+ * placed in the 'type' field of each node. Any node that has
+ * a 'type' field which satisfies the OP_NOP function was never never on
+ * the lefthand side of an operator, though it may have been on the
+ * righthand side...
+ */
+#define OP_DEPENDS 0x00000001 /* Execution of commands depends on
+ * kids (:) */
+#define OP_FORCE 0x00000002 /* Always execute commands (!) */
+#define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids
+ * per line (::) */
+#define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP)
+
+#define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't
+ * exist and can't be created */
+#define OP_USE 0x00000010 /* Use associated commands for parents */
+#define OP_EXEC 0x00000020 /* Target is never out of date, but always
+ * execute commands anyway. Its time
+ * doesn't matter, so it has none...sort
+ * of */
+#define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */
+#define OP_PRECIOUS 0x00000080 /* Don't remove the target when
+ * interrupted */
+#define OP_SILENT 0x00000100 /* Don't echo commands when executed */
+#define OP_MAKE 0x00000200 /* Target is a recurrsive make so its
+ * commands should always be executed when
+ * it is out of date, regardless of the
+ * state of the -n or -t flags */
+#define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its
+ * children was out-of-date */
+#define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents.
+ * I.e. it doesn't show up in the parents's
+ * local variables. */
+#define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main
+ * target' processing in parse.c */
+#define OP_PHONY 0x00010000 /* Not a file target; run always */
+/* Attributes applied by PMake */
+#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */
+#define OP_MEMBER 0x40000000 /* Target is a member of an archive */
+#define OP_LIB 0x20000000 /* Target is a library */
+#define OP_ARCHV 0x10000000 /* Target is an archive construct */
+#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should.
+ * Used when parsing to catch multiple
+ * commands for a target */
+#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */
+#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */
+
+/*
+ * OP_NOP will return TRUE if the node with the given type was not the
+ * object of a dependency operator
+ */
+#define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000)
+
+/*
+ * The TARG_ constants are used when calling the Targ_FindNode and
+ * Targ_FindList functions in targ.c. They simply tell the functions what to
+ * do if the desired node(s) is (are) not found. If the TARG_CREATE constant
+ * is given, a new, empty node will be created for the target, placed in the
+ * table of all targets and its address returned. If TARG_NOCREATE is given,
+ * a NIL pointer will be returned.
+ */
+#define TARG_CREATE 0x01 /* create node if not found */
+#define TARG_NOCREATE 0x00 /* don't create it */
+
+/*
+ * There are several places where expandable buffers are used (parse.c and
+ * var.c). This constant is merely the starting point for those buffers. If
+ * lines tend to be much shorter than this, it would be best to reduce BSIZE.
+ * If longer, it should be increased. Reducing it will cause more copying to
+ * be done for longer lines, but will save space for shorter ones. In any
+ * case, it ought to be a power of two simply because most storage allocation
+ * schemes allocate in powers of two.
+ */
+#define MAKE_BSIZE 256 /* starting size for expandable buffers */
+
+/*
+ * These constants are all used by the Str_Concat function to decide how the
+ * final string should look. If STR_ADDSPACE is given, a space will be
+ * placed between the two strings. If STR_ADDSLASH is given, a '/' will
+ * be used instead of a space. If neither is given, no intervening characters
+ * will be placed between the two strings in the final output. If the
+ * STR_DOFREE bit is set, the two input strings will be freed before
+ * Str_Concat returns.
+ */
+#define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */
+#define STR_DOFREE 0x02 /* free source strings after concatenation */
+#define STR_ADDSLASH 0x04 /* add a slash when Str_Concat'ing */
+
+/*
+ * Error levels for parsing. PARSE_FATAL means the process cannot continue
+ * once the makefile has been parsed. PARSE_WARNING means it can. Passed
+ * as the first argument to Parse_Error.
+ */
+#define PARSE_WARNING 2
+#define PARSE_FATAL 1
+
+/*
+ * Values returned by Cond_Eval.
+ */
+#define COND_PARSE 0 /* Parse the next lines */
+#define COND_SKIP 1 /* Skip the next lines */
+#define COND_INVALID 2 /* Not a conditional statement */
+
+/*
+ * Definitions for the "local" variables. Used only for clarity.
+ */
+#define TARGET "@" /* Target of dependency */
+#define OODATE "?" /* All out-of-date sources */
+#define ALLSRC ">" /* All sources */
+#define IMPSRC "<" /* Source implied by transformation */
+#define PREFIX "*" /* Common prefix */
+#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
+#define MEMBER "%" /* Member in "archive(member)" syntax */
+
+#define FTARGET "@F" /* file part of TARGET */
+#define DTARGET "@D" /* directory part of TARGET */
+#define FIMPSRC "<F" /* file part of IMPSRC */
+#define DIMPSRC "<D" /* directory part of IMPSRC */
+#define FPREFIX "*F" /* file part of PREFIX */
+#define DPREFIX "*D" /* directory part of PREFIX */
+
+/*
+ * Global Variables
+ */
+extern Lst create; /* The list of target names specified on the
+ * command line. used to resolve #if
+ * make(...) statements */
+extern Lst dirSearchPath; /* The list of directories to search when
+ * looking for targets */
+
+extern Boolean compatMake; /* True if we are make compatible */
+extern Boolean ignoreErrors; /* True if should ignore all errors */
+extern Boolean beSilent; /* True if should print no commands */
+extern Boolean noExecute; /* True if should execute nothing */
+extern Boolean allPrecious; /* True if every target is precious */
+extern Boolean keepgoing; /* True if should continue on unaffected
+ * portions of the graph when have an error
+ * in one portion */
+extern Boolean touchFlag; /* TRUE if targets should just be 'touched'
+ * if out of date. Set by the -t flag */
+extern Boolean usePipes; /* TRUE if should capture the output of
+ * subshells by means of pipes. Otherwise it
+ * is routed to temporary files from which it
+ * is retrieved when the shell exits */
+extern Boolean queryFlag; /* TRUE if we aren't supposed to really make
+ * anything, just see if the targets are out-
+ * of-date */
+
+extern Boolean checkEnvFirst; /* TRUE if environment should be searched for
+ * variables before the global context */
+
+extern GNode *DEFAULT; /* .DEFAULT rule */
+
+extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g
+ * in the Makefile itself */
+extern GNode *VAR_CMD; /* Variables defined on the command line */
+extern char var_Error[]; /* Value returned by Var_Parse when an error
+ * is encountered. It actually points to
+ * an empty string, so naive callers needn't
+ * worry about it. */
+
+extern time_t now; /* The time at the start of this whole
+ * process */
+
+extern Boolean oldVars; /* Do old-style variable substitution */
+
+extern Lst sysIncPath; /* The system include path. */
+
+/*
+ * debug control:
+ * There is one bit per module. It is up to the module what debug
+ * information to print.
+ */
+extern int debug;
+#define DEBUG_ARCH 0x0001
+#define DEBUG_COND 0x0002
+#define DEBUG_DIR 0x0004
+#define DEBUG_GRAPH1 0x0008
+#define DEBUG_GRAPH2 0x0010
+#define DEBUG_JOB 0x0020
+#define DEBUG_MAKE 0x0040
+#define DEBUG_SUFF 0x0080
+#define DEBUG_TARG 0x0100
+#define DEBUG_VAR 0x0200
+#define DEBUG_FOR 0x0400
+
+#ifdef __STDC__
+#define CONCAT(a,b) a##b
+#else
+#define I(a) a
+#define CONCAT(a,b) I(a)b
+#endif /* __STDC__ */
+
+#define DEBUG(module) (debug & CONCAT(DEBUG_,module))
+
+/*
+ * Since there are so many, all functions that return non-integer values are
+ * extracted by means of a sed script or two and stuck in the file "nonints.h"
+ */
+#include "nonints.h"
+
+int Make_TimeStamp __P((GNode *, GNode *));
+Boolean Make_OODate __P((GNode *));
+int Make_HandleUse __P((GNode *, GNode *));
+void Make_Update __P((GNode *));
+void Make_DoAllVar __P((GNode *));
+Boolean Make_Run __P((Lst));
+
+#endif /* _MAKE_H_ */
diff --git a/usr.bin/make/nonints.h b/usr.bin/make/nonints.h
new file mode 100644
index 0000000..1c56450
--- /dev/null
+++ b/usr.bin/make/nonints.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94
+ * $Id$
+ */
+
+/* arch.c */
+ReturnStatus Arch_ParseArchive __P((char **, Lst, GNode *));
+void Arch_Touch __P((GNode *));
+void Arch_TouchLib __P((GNode *));
+int Arch_MTime __P((GNode *));
+int Arch_MemMTime __P((GNode *));
+void Arch_FindLib __P((GNode *, Lst));
+Boolean Arch_LibOODate __P((GNode *));
+void Arch_Init __P((void));
+void Arch_End __P((void));
+
+/* compat.c */
+void Compat_Run __P((Lst));
+
+/* cond.c */
+int Cond_Eval __P((char *));
+void Cond_End __P((void));
+
+/* for.c */
+int For_Eval __P((char *));
+void For_Run __P((void));
+
+/* main.c */
+void Main_ParseArgLine __P((char *));
+int main __P((int, char **));
+char *Cmd_Exec __P((char *, char **));
+void Error __P((char *, ...));
+void Fatal __P((char *, ...));
+void Punt __P((char *, ...));
+void DieHorribly __P((void));
+int PrintAddr __P((ClientData, ClientData));
+void Finish __P((int));
+char *estrdup __P((const char *));
+void *emalloc __P((size_t));
+void *erealloc __P((void *, size_t));
+void enomem __P((void));
+int eunlink __P((const char *));
+
+/* parse.c */
+void Parse_Error __P((int, char *, ...));
+Boolean Parse_AnyExport __P((void));
+Boolean Parse_IsVar __P((char *));
+void Parse_DoVar __P((char *, GNode *));
+void Parse_AddIncludeDir __P((char *));
+void Parse_File __P((char *, FILE *));
+void Parse_Init __P((void));
+void Parse_End __P((void));
+void Parse_FromString __P((char *));
+Lst Parse_MainName __P((void));
+
+/* str.c */
+void str_init __P((void));
+void str_end __P((void));
+char *str_concat __P((char *, char *, int));
+char **brk_string __P((char *, int *, Boolean));
+char *Str_FindSubstring __P((char *, char *));
+int Str_Match __P((char *, char *));
+char *Str_SYSVMatch __P((char *, char *, int *len));
+void Str_SYSVSubst __P((Buffer, char *, char *, int));
+
+/* suff.c */
+void Suff_ClearSuffixes __P((void));
+Boolean Suff_IsTransform __P((char *));
+GNode *Suff_AddTransform __P((char *));
+int Suff_EndTransform __P((ClientData, ClientData));
+void Suff_AddSuffix __P((char *));
+Lst Suff_GetPath __P((char *));
+void Suff_DoPaths __P((void));
+void Suff_AddInclude __P((char *));
+void Suff_AddLib __P((char *));
+void Suff_FindDeps __P((GNode *));
+void Suff_SetNull __P((char *));
+void Suff_Init __P((void));
+void Suff_End __P((void));
+void Suff_PrintAll __P((void));
+
+/* targ.c */
+void Targ_Init __P((void));
+void Targ_End __P((void));
+GNode *Targ_NewGN __P((char *));
+GNode *Targ_FindNode __P((char *, int));
+Lst Targ_FindList __P((Lst, int));
+Boolean Targ_Ignore __P((GNode *));
+Boolean Targ_Silent __P((GNode *));
+Boolean Targ_Precious __P((GNode *));
+void Targ_SetMain __P((GNode *));
+int Targ_PrintCmd __P((ClientData, ClientData));
+char *Targ_FmtTime __P((time_t));
+void Targ_PrintType __P((int));
+void Targ_PrintGraph __P((int));
+
+/* var.c */
+void Var_Delete __P((char *, GNode *));
+void Var_Set __P((char *, char *, GNode *));
+void Var_Append __P((char *, char *, GNode *));
+Boolean Var_Exists __P((char *, GNode *));
+char *Var_Value __P((char *, GNode *, char **));
+char *Var_Parse __P((char *, GNode *, Boolean, int *, Boolean *));
+char *Var_Subst __P((char *, char *, GNode *, Boolean));
+char *Var_GetTail __P((char *));
+char *Var_GetHead __P((char *));
+void Var_Init __P((void));
+void Var_End __P((void));
+void Var_Dump __P((GNode *));
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
new file mode 100644
index 0000000..234364f
--- /dev/null
+++ b/usr.bin/make/parse.c
@@ -0,0 +1,2596 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * parse.c --
+ * Functions to parse a makefile.
+ *
+ * One function, Parse_Init, must be called before any functions
+ * in this module are used. After that, the function Parse_File is the
+ * main entry point and controls most of the other functions in this
+ * module.
+ *
+ * Most important structures are kept in Lsts. Directories for
+ * the #include "..." function are kept in the 'parseIncPath' Lst, while
+ * those for the #include <...> are kept in the 'sysIncPath' Lst. The
+ * targets currently being defined are kept in the 'targets' Lst.
+ *
+ * The variables 'fname' and 'lineno' are used to track the name
+ * of the current file and the line number in that file so that error
+ * messages can be more meaningful.
+ *
+ * Interface:
+ * Parse_Init Initialization function which must be
+ * called before anything else in this module
+ * is used.
+ *
+ * Parse_End Cleanup the module
+ *
+ * Parse_File Function used to parse a makefile. It must
+ * be given the name of the file, which should
+ * already have been opened, and a function
+ * to call to read a character from the file.
+ *
+ * Parse_IsVar Returns TRUE if the given line is a
+ * variable assignment. Used by MainParseArgs
+ * to determine if an argument is a target
+ * or a variable assignment. Used internally
+ * for pretty much the same thing...
+ *
+ * Parse_Error Function called when an error occurs in
+ * parsing. Used by the variable and
+ * conditional modules.
+ * Parse_MainName Returns a Lst of the main target to create.
+ */
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+#include "job.h"
+#include "buf.h"
+#include "pathnames.h"
+
+/*
+ * These values are returned by ParseEOF to tell Parse_File whether to
+ * CONTINUE parsing, i.e. it had only reached the end of an include file,
+ * or if it's DONE.
+ */
+#define CONTINUE 1
+#define DONE 0
+static Lst targets; /* targets we're working on */
+static Lst targCmds; /* command lines for targets */
+static Boolean inLine; /* true if currently in a dependency
+ * line or its commands */
+typedef struct {
+ char *str;
+ char *ptr;
+} PTR;
+
+static char *fname; /* name of current file (for errors) */
+static int lineno; /* line number in current file */
+static FILE *curFILE = NULL; /* current makefile */
+
+static PTR *curPTR = NULL; /* current makefile */
+
+static int fatals = 0;
+
+static GNode *mainNode; /* The main target to create. This is the
+ * first target on the first dependency
+ * line in the first makefile */
+/*
+ * Definitions for handling #include specifications
+ */
+typedef struct IFile {
+ char *fname; /* name of previous file */
+ int lineno; /* saved line number */
+ FILE * F; /* the open stream */
+ PTR * p; /* the char pointer */
+} IFile;
+
+static Lst includes; /* stack of IFiles generated by
+ * #includes */
+Lst parseIncPath; /* list of directories for "..." includes */
+Lst sysIncPath; /* list of directories for <...> includes */
+
+/*-
+ * specType contains the SPECial TYPE of the current target. It is
+ * Not if the target is unspecial. If it *is* special, however, the children
+ * are linked as children of the parent but not vice versa. This variable is
+ * set in ParseDoDependency
+ */
+typedef enum {
+ Begin, /* .BEGIN */
+ Default, /* .DEFAULT */
+ End, /* .END */
+ Ignore, /* .IGNORE */
+ Includes, /* .INCLUDES */
+ Interrupt, /* .INTERRUPT */
+ Libs, /* .LIBS */
+ MFlags, /* .MFLAGS or .MAKEFLAGS */
+ Main, /* .MAIN and we don't have anything user-specified to
+ * make */
+ NoExport, /* .NOEXPORT */
+ Not, /* Not special */
+ NotParallel, /* .NOTPARALELL */
+ Null, /* .NULL */
+ Order, /* .ORDER */
+ Parallel, /* .PARALLEL */
+ ExPath, /* .PATH */
+ Phony, /* .PHONY */
+#ifdef POSIX
+ Posix, /* .POSIX */
+#endif
+ Precious, /* .PRECIOUS */
+ ExShell, /* .SHELL */
+ Silent, /* .SILENT */
+ SingleShell, /* .SINGLESHELL */
+ Suffixes, /* .SUFFIXES */
+ Wait, /* .WAIT */
+ Attribute /* Generic attribute */
+} ParseSpecial;
+
+static ParseSpecial specType;
+static int waiting;
+
+/*
+ * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER
+ * seen, then set to each successive source on the line.
+ */
+static GNode *predecessor;
+
+/*
+ * The parseKeywords table is searched using binary search when deciding
+ * if a target or source is special. The 'spec' field is the ParseSpecial
+ * type of the keyword ("Not" if the keyword isn't special as a target) while
+ * the 'op' field is the operator to apply to the list of targets if the
+ * keyword is used as a source ("0" if the keyword isn't special as a source)
+ */
+static struct {
+ char *name; /* Name of keyword */
+ ParseSpecial spec; /* Type when used as a target */
+ int op; /* Operator when used as a source */
+} parseKeywords[] = {
+{ ".BEGIN", Begin, 0 },
+{ ".DEFAULT", Default, 0 },
+{ ".END", End, 0 },
+{ ".EXEC", Attribute, OP_EXEC },
+{ ".IGNORE", Ignore, OP_IGNORE },
+{ ".INCLUDES", Includes, 0 },
+{ ".INTERRUPT", Interrupt, 0 },
+{ ".INVISIBLE", Attribute, OP_INVISIBLE },
+{ ".JOIN", Attribute, OP_JOIN },
+{ ".LIBS", Libs, 0 },
+{ ".MAIN", Main, 0 },
+{ ".MAKE", Attribute, OP_MAKE },
+{ ".MAKEFLAGS", MFlags, 0 },
+{ ".MFLAGS", MFlags, 0 },
+{ ".NOTMAIN", Attribute, OP_NOTMAIN },
+{ ".NOTPARALLEL", NotParallel, 0 },
+{ ".NO_PARALLEL", NotParallel, 0 },
+{ ".NULL", Null, 0 },
+{ ".OPTIONAL", Attribute, OP_OPTIONAL },
+{ ".ORDER", Order, 0 },
+{ ".PARALLEL", Parallel, 0 },
+{ ".PATH", ExPath, 0 },
+{ ".PHONY", Phony, OP_PHONY },
+#ifdef POSIX
+{ ".POSIX", Posix, 0 },
+#endif
+{ ".PRECIOUS", Precious, OP_PRECIOUS },
+{ ".RECURSIVE", Attribute, OP_MAKE },
+{ ".SHELL", ExShell, 0 },
+{ ".SILENT", Silent, OP_SILENT },
+{ ".SINGLESHELL", SingleShell, 0 },
+{ ".SUFFIXES", Suffixes, 0 },
+{ ".USE", Attribute, OP_USE },
+{ ".WAIT", Wait, 0 },
+};
+
+static int ParseFindKeyword __P((char *));
+static int ParseLinkSrc __P((ClientData, ClientData));
+static int ParseDoOp __P((ClientData, ClientData));
+static int ParseAddDep __P((ClientData, ClientData));
+static void ParseDoSrc __P((int, char *, Lst));
+static int ParseFindMain __P((ClientData, ClientData));
+static int ParseAddDir __P((ClientData, ClientData));
+static int ParseClearPath __P((ClientData, ClientData));
+static void ParseDoDependency __P((char *));
+static int ParseAddCmd __P((ClientData, ClientData));
+static int ParseReadc __P((void));
+static void ParseUnreadc __P((int));
+static void ParseHasCommands __P((ClientData));
+static void ParseDoInclude __P((char *));
+#ifdef SYSVINCLUDE
+static void ParseTraditionalInclude __P((char *));
+#endif
+static int ParseEOF __P((int));
+static char *ParseReadLine __P((void));
+static char *ParseSkipLine __P((int));
+static void ParseFinishLine __P((void));
+
+/*-
+ *----------------------------------------------------------------------
+ * ParseFindKeyword --
+ * Look in the table of keywords for one matching the given string.
+ *
+ * Results:
+ * The index of the keyword, or -1 if it isn't there.
+ *
+ * Side Effects:
+ * None
+ *----------------------------------------------------------------------
+ */
+static int
+ParseFindKeyword (str)
+ char *str; /* String to find */
+{
+ register int start,
+ end,
+ cur;
+ register int diff;
+
+ start = 0;
+ end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
+
+ do {
+ cur = start + ((end - start) / 2);
+ diff = strcmp (str, parseKeywords[cur].name);
+
+ if (diff == 0) {
+ return (cur);
+ } else if (diff < 0) {
+ end = cur - 1;
+ } else {
+ start = cur + 1;
+ }
+ } while (start <= end);
+ return (-1);
+}
+
+/*-
+ * Parse_Error --
+ * Error message abort function for parsing. Prints out the context
+ * of the error (line number and file) as well as the message with
+ * two optional arguments.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * "fatals" is incremented if the level is PARSE_FATAL.
+ */
+/* VARARGS */
+void
+#if __STDC__
+Parse_Error(int type, char *fmt, ...)
+#else
+Parse_Error(va_alist)
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */
+ char *fmt;
+
+ va_start(ap);
+ type = va_arg(ap, int);
+ fmt = va_arg(ap, char *);
+#endif
+
+ (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);
+ if (type == PARSE_WARNING)
+ (void)fprintf(stderr, "warning: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+ if (type == PARSE_FATAL)
+ fatals += 1;
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseLinkSrc --
+ * Link the parent node to its new child. Used in a Lst_ForEach by
+ * ParseDoDependency. If the specType isn't 'Not', the parent
+ * isn't linked as a parent of the child.
+ *
+ * Results:
+ * Always = 0
+ *
+ * Side Effects:
+ * New elements are added to the parents list of cgn and the
+ * children list of cgn. the unmade field of pgn is updated
+ * to reflect the additional child.
+ *---------------------------------------------------------------------
+ */
+static int
+ParseLinkSrc (pgnp, cgnp)
+ ClientData pgnp; /* The parent node */
+ ClientData cgnp; /* The child node */
+{
+ GNode *pgn = (GNode *) pgnp;
+ GNode *cgn = (GNode *) cgnp;
+ if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {
+ (void)Lst_AtEnd (pgn->children, (ClientData)cgn);
+ if (specType == Not) {
+ (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);
+ }
+ pgn->unmade += 1;
+ }
+ return (0);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseDoOp --
+ * Apply the parsed operator to the given target node. Used in a
+ * Lst_ForEach call by ParseDoDependency once all targets have
+ * been found and their operator parsed. If the previous and new
+ * operators are incompatible, a major error is taken.
+ *
+ * Results:
+ * Always 0
+ *
+ * Side Effects:
+ * The type field of the node is altered to reflect any new bits in
+ * the op.
+ *---------------------------------------------------------------------
+ */
+static int
+ParseDoOp (gnp, opp)
+ ClientData gnp; /* The node to which the operator is to be
+ * applied */
+ ClientData opp; /* The operator to apply */
+{
+ GNode *gn = (GNode *) gnp;
+ int op = *(int *) opp;
+ /*
+ * If the dependency mask of the operator and the node don't match and
+ * the node has actually had an operator applied to it before, and
+ * the operator actually has some dependency information in it, complain.
+ */
+ if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
+ !OP_NOP(gn->type) && !OP_NOP(op))
+ {
+ Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
+ return (1);
+ }
+
+ if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
+ /*
+ * If the node was the object of a :: operator, we need to create a
+ * new instance of it for the children and commands on this dependency
+ * line. The new instance is placed on the 'cohorts' list of the
+ * initial one (note the initial one is not on its own cohorts list)
+ * and the new instance is linked to all parents of the initial
+ * instance.
+ */
+ register GNode *cohort;
+ LstNode ln;
+
+ cohort = Targ_NewGN(gn->name);
+ /*
+ * Duplicate links to parents so graph traversal is simple. Perhaps
+ * some type bits should be duplicated?
+ *
+ * Make the cohort invisible as well to avoid duplicating it into
+ * other variables. True, parents of this target won't tend to do
+ * anything with their local variables, but better safe than
+ * sorry.
+ */
+ Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);
+ cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
+ (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
+
+ /*
+ * Replace the node in the targets list with the new copy
+ */
+ ln = Lst_Member(targets, (ClientData)gn);
+ Lst_Replace(ln, (ClientData)cohort);
+ gn = cohort;
+ }
+ /*
+ * We don't want to nuke any previous flags (whatever they were) so we
+ * just OR the new operator into the old
+ */
+ gn->type |= op;
+
+ return (0);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseAddDep --
+ * Check if the pair of GNodes given needs to be synchronized.
+ * This has to be when two nodes are on different sides of a
+ * .WAIT directive.
+ *
+ * Results:
+ * Returns 1 if the two targets need to be ordered, 0 otherwise.
+ * If it returns 1, the search can stop
+ *
+ * Side Effects:
+ * A dependency can be added between the two nodes.
+ *
+ *---------------------------------------------------------------------
+ */
+int
+ParseAddDep(pp, sp)
+ ClientData pp;
+ ClientData sp;
+{
+ GNode *p = (GNode *) pp;
+ GNode *s = (GNode *) sp;
+
+ if (p->order < s->order) {
+ /*
+ * XXX: This can cause loops, and loops can cause unmade targets,
+ * but checking is tedious, and the debugging output can show the
+ * problem
+ */
+ (void)Lst_AtEnd(p->successors, (ClientData)s);
+ (void)Lst_AtEnd(s->preds, (ClientData)p);
+ return 0;
+ }
+ else
+ return 1;
+}
+
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseDoSrc --
+ * Given the name of a source, figure out if it is an attribute
+ * and apply it to the targets if it is. Else decide if there is
+ * some attribute which should be applied *to* the source because
+ * of some special target and apply it if so. Otherwise, make the
+ * source be a child of the targets in the list 'targets'
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Operator bits may be added to the list of targets or to the source.
+ * The targets may have a new source added to their lists of children.
+ *---------------------------------------------------------------------
+ */
+static void
+ParseDoSrc (tOp, src, allsrc)
+ int tOp; /* operator (if any) from special targets */
+ char *src; /* name of the source to handle */
+ Lst allsrc; /* List of all sources to wait for */
+{
+ GNode *gn = NULL;
+
+ if (*src == '.' && isupper (src[1])) {
+ int keywd = ParseFindKeyword(src);
+ if (keywd != -1) {
+ int op = parseKeywords[keywd].op;
+ if (op != 0) {
+ Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
+ return;
+ }
+ if (parseKeywords[keywd].spec == Wait) {
+ waiting++;
+ return;
+ }
+ }
+ }
+
+ switch (specType) {
+ case Main:
+ /*
+ * If we have noted the existence of a .MAIN, it means we need
+ * to add the sources of said target to the list of things
+ * to create. The string 'src' is likely to be free, so we
+ * must make a new copy of it. Note that this will only be
+ * invoked if the user didn't specify a target on the command
+ * line. This is to allow #ifmake's to succeed, or something...
+ */
+ (void) Lst_AtEnd (create, (ClientData)estrdup(src));
+ /*
+ * Add the name to the .TARGETS variable as well, so the user cna
+ * employ that, if desired.
+ */
+ Var_Append(".TARGETS", src, VAR_GLOBAL);
+ return;
+
+ case Order:
+ /*
+ * Create proper predecessor/successor links between the previous
+ * source and the current one.
+ */
+ gn = Targ_FindNode(src, TARG_CREATE);
+ if (predecessor != NILGNODE) {
+ (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
+ (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
+ }
+ /*
+ * The current source now becomes the predecessor for the next one.
+ */
+ predecessor = gn;
+ break;
+
+ default:
+ /*
+ * If the source is not an attribute, we need to find/create
+ * a node for it. After that we can apply any operator to it
+ * from a special target or link it to its parents, as
+ * appropriate.
+ *
+ * In the case of a source that was the object of a :: operator,
+ * the attribute is applied to all of its instances (as kept in
+ * the 'cohorts' list of the node) or all the cohorts are linked
+ * to all the targets.
+ */
+ gn = Targ_FindNode (src, TARG_CREATE);
+ if (tOp) {
+ gn->type |= tOp;
+ } else {
+ Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);
+ }
+ if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
+ register GNode *cohort;
+ register LstNode ln;
+
+ for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){
+ cohort = (GNode *)Lst_Datum(ln);
+ if (tOp) {
+ cohort->type |= tOp;
+ } else {
+ Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);
+ }
+ }
+ }
+ break;
+ }
+
+ gn->order = waiting;
+ (void)Lst_AtEnd(allsrc, (ClientData)gn);
+ if (waiting) {
+ Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ParseFindMain --
+ * Find a real target in the list and set it to be the main one.
+ * Called by ParseDoDependency when a main target hasn't been found
+ * yet.
+ *
+ * Results:
+ * 0 if main not found yet, 1 if it is.
+ *
+ * Side Effects:
+ * mainNode is changed and Targ_SetMain is called.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ParseFindMain(gnp, dummy)
+ ClientData gnp; /* Node to examine */
+ ClientData dummy;
+{
+ GNode *gn = (GNode *) gnp;
+ if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
+ mainNode = gn;
+ Targ_SetMain(gn);
+ return (dummy ? 1 : 1);
+ } else {
+ return (dummy ? 0 : 0);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ParseAddDir --
+ * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
+ *
+ * Results:
+ * === 0
+ *
+ * Side Effects:
+ * See Dir_AddDir.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ParseAddDir(path, name)
+ ClientData path;
+ ClientData name;
+{
+ Dir_AddDir((Lst) path, (char *) name);
+ return(0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ParseClearPath --
+ * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
+ *
+ * Results:
+ * === 0
+ *
+ * Side Effects:
+ * See Dir_ClearPath
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+ParseClearPath(path, dummy)
+ ClientData path;
+ ClientData dummy;
+{
+ Dir_ClearPath((Lst) path);
+ return(dummy ? 0 : 0);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseDoDependency --
+ * Parse the dependency line in line.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The nodes of the sources are linked as children to the nodes of the
+ * targets. Some nodes may be created.
+ *
+ * We parse a dependency line by first extracting words from the line and
+ * finding nodes in the list of all targets with that name. This is done
+ * until a character is encountered which is an operator character. Currently
+ * these are only ! and :. At this point the operator is parsed and the
+ * pointer into the line advanced until the first source is encountered.
+ * The parsed operator is applied to each node in the 'targets' list,
+ * which is where the nodes found for the targets are kept, by means of
+ * the ParseDoOp function.
+ * The sources are read in much the same way as the targets were except
+ * that now they are expanded using the wildcarding scheme of the C-Shell
+ * and all instances of the resulting words in the list of all targets
+ * are found. Each of the resulting nodes is then linked to each of the
+ * targets as one of its children.
+ * Certain targets are handled specially. These are the ones detailed
+ * by the specType variable.
+ * The storing of transformation rules is also taken care of here.
+ * A target is recognized as a transformation rule by calling
+ * Suff_IsTransform. If it is a transformation rule, its node is gotten
+ * from the suffix module via Suff_AddTransform rather than the standard
+ * Targ_FindNode in the target module.
+ *---------------------------------------------------------------------
+ */
+static void
+ParseDoDependency (line)
+ char *line; /* the line to parse */
+{
+ char *cp; /* our current position */
+ GNode *gn; /* a general purpose temporary node */
+ int op; /* the operator on the line */
+ char savec; /* a place to save a character */
+ Lst paths; /* List of search paths to alter when parsing
+ * a list of .PATH targets */
+ int tOp; /* operator from special target */
+ Lst sources; /* list of archive source names after
+ * expansion */
+ Lst curTargs; /* list of target names to be found and added
+ * to the targets list */
+ Lst curSrcs; /* list of sources in order */
+
+ tOp = 0;
+
+ specType = Not;
+ waiting = 0;
+ paths = (Lst)NULL;
+
+ curTargs = Lst_Init(FALSE);
+ curSrcs = Lst_Init(FALSE);
+
+ do {
+ for (cp = line;
+ *cp && !isspace (*cp) &&
+ (*cp != '!') && (*cp != ':') && (*cp != '(');
+ cp++)
+ {
+ if (*cp == '$') {
+ /*
+ * Must be a dynamic source (would have been expanded
+ * otherwise), so call the Var module to parse the puppy
+ * so we can safely advance beyond it...There should be
+ * no errors in this, as they would have been discovered
+ * in the initial Var_Subst and we wouldn't be here.
+ */
+ int length;
+ Boolean freeIt;
+ char *result;
+
+ result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
+
+ if (freeIt) {
+ free(result);
+ }
+ cp += length-1;
+ }
+ continue;
+ }
+ if (*cp == '(') {
+ /*
+ * Archives must be handled specially to make sure the OP_ARCHV
+ * flag is set in their 'type' field, for one thing, and because
+ * things like "archive(file1.o file2.o file3.o)" are permissible.
+ * Arch_ParseArchive will set 'line' to be the first non-blank
+ * after the archive-spec. It creates/finds nodes for the members
+ * and places them on the given list, returning SUCCESS if all
+ * went well and FAILURE if there was an error in the
+ * specification. On error, line should remain untouched.
+ */
+ if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
+ Parse_Error (PARSE_FATAL,
+ "Error in archive specification: \"%s\"", line);
+ return;
+ } else {
+ continue;
+ }
+ }
+ savec = *cp;
+
+ if (!*cp) {
+ /*
+ * Ending a dependency line without an operator is a Bozo
+ * no-no
+ */
+ Parse_Error (PARSE_FATAL, "Need an operator");
+ return;
+ }
+ *cp = '\0';
+ /*
+ * Have a word in line. See if it's a special target and set
+ * specType to match it.
+ */
+ if (*line == '.' && isupper (line[1])) {
+ /*
+ * See if the target is a special target that must have it
+ * or its sources handled specially.
+ */
+ int keywd = ParseFindKeyword(line);
+ if (keywd != -1) {
+ if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
+ Parse_Error(PARSE_FATAL, "Mismatched special targets");
+ return;
+ }
+
+ specType = parseKeywords[keywd].spec;
+ tOp = parseKeywords[keywd].op;
+
+ /*
+ * Certain special targets have special semantics:
+ * .PATH Have to set the dirSearchPath
+ * variable too
+ * .MAIN Its sources are only used if
+ * nothing has been specified to
+ * create.
+ * .DEFAULT Need to create a node to hang
+ * commands on, but we don't want
+ * it in the graph, nor do we want
+ * it to be the Main Target, so we
+ * create it, set OP_NOTMAIN and
+ * add it to the list, setting
+ * DEFAULT to the new node for
+ * later use. We claim the node is
+ * A transformation rule to make
+ * life easier later, when we'll
+ * use Make_HandleUse to actually
+ * apply the .DEFAULT commands.
+ * .PHONY The list of targets
+ * .BEGIN
+ * .END
+ * .INTERRUPT Are not to be considered the
+ * main target.
+ * .NOTPARALLEL Make only one target at a time.
+ * .SINGLESHELL Create a shell for each command.
+ * .ORDER Must set initial predecessor to NIL
+ */
+ switch (specType) {
+ case ExPath:
+ if (paths == NULL) {
+ paths = Lst_Init(FALSE);
+ }
+ (void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
+ break;
+ case Main:
+ if (!Lst_IsEmpty(create)) {
+ specType = Not;
+ }
+ break;
+ case Begin:
+ case End:
+ case Interrupt:
+ gn = Targ_FindNode(line, TARG_CREATE);
+ gn->type |= OP_NOTMAIN;
+ (void)Lst_AtEnd(targets, (ClientData)gn);
+ break;
+ case Default:
+ gn = Targ_NewGN(".DEFAULT");
+ gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
+ (void)Lst_AtEnd(targets, (ClientData)gn);
+ DEFAULT = gn;
+ break;
+ case NotParallel:
+ {
+ extern int maxJobs;
+
+ maxJobs = 1;
+ break;
+ }
+ case SingleShell:
+ compatMake = 1;
+ break;
+ case Order:
+ predecessor = NILGNODE;
+ break;
+ default:
+ break;
+ }
+ } else if (strncmp (line, ".PATH", 5) == 0) {
+ /*
+ * .PATH<suffix> has to be handled specially.
+ * Call on the suffix module to give us a path to
+ * modify.
+ */
+ Lst path;
+
+ specType = ExPath;
+ path = Suff_GetPath (&line[5]);
+ if (path == NILLST) {
+ Parse_Error (PARSE_FATAL,
+ "Suffix '%s' not defined (yet)",
+ &line[5]);
+ return;
+ } else {
+ if (paths == (Lst)NULL) {
+ paths = Lst_Init(FALSE);
+ }
+ (void)Lst_AtEnd(paths, (ClientData)path);
+ }
+ }
+ }
+
+ /*
+ * Have word in line. Get or create its node and stick it at
+ * the end of the targets list
+ */
+ if ((specType == Not) && (*line != '\0')) {
+ if (Dir_HasWildcards(line)) {
+ /*
+ * Targets are to be sought only in the current directory,
+ * so create an empty path for the thing. Note we need to
+ * use Dir_Destroy in the destruction of the path as the
+ * Dir module could have added a directory to the path...
+ */
+ Lst emptyPath = Lst_Init(FALSE);
+
+ Dir_Expand(line, emptyPath, curTargs);
+
+ Lst_Destroy(emptyPath, Dir_Destroy);
+ } else {
+ /*
+ * No wildcards, but we want to avoid code duplication,
+ * so create a list with the word on it.
+ */
+ (void)Lst_AtEnd(curTargs, (ClientData)line);
+ }
+
+ while(!Lst_IsEmpty(curTargs)) {
+ char *targName = (char *)Lst_DeQueue(curTargs);
+
+ if (!Suff_IsTransform (targName)) {
+ gn = Targ_FindNode (targName, TARG_CREATE);
+ } else {
+ gn = Suff_AddTransform (targName);
+ }
+
+ (void)Lst_AtEnd (targets, (ClientData)gn);
+ }
+ } else if (specType == ExPath && *line != '.' && *line != '\0') {
+ Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
+ }
+
+ *cp = savec;
+ /*
+ * If it is a special type and not .PATH, it's the only target we
+ * allow on this line...
+ */
+ if (specType != Not && specType != ExPath) {
+ Boolean warn = FALSE;
+
+ while ((*cp != '!') && (*cp != ':') && *cp) {
+ if (*cp != ' ' && *cp != '\t') {
+ warn = TRUE;
+ }
+ cp++;
+ }
+ if (warn) {
+ Parse_Error(PARSE_WARNING, "Extra target ignored");
+ }
+ } else {
+ while (*cp && isspace (*cp)) {
+ cp++;
+ }
+ }
+ line = cp;
+ } while ((*line != '!') && (*line != ':') && *line);
+
+ /*
+ * Don't need the list of target names anymore...
+ */
+ Lst_Destroy(curTargs, NOFREE);
+
+ if (!Lst_IsEmpty(targets)) {
+ switch(specType) {
+ default:
+ Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
+ break;
+ case Default:
+ case Begin:
+ case End:
+ case Interrupt:
+ /*
+ * These four create nodes on which to hang commands, so
+ * targets shouldn't be empty...
+ */
+ case Not:
+ /*
+ * Nothing special here -- targets can be empty if it wants.
+ */
+ break;
+ }
+ }
+
+ /*
+ * Have now parsed all the target names. Must parse the operator next. The
+ * result is left in op .
+ */
+ if (*cp == '!') {
+ op = OP_FORCE;
+ } else if (*cp == ':') {
+ if (cp[1] == ':') {
+ op = OP_DOUBLEDEP;
+ cp++;
+ } else {
+ op = OP_DEPENDS;
+ }
+ } else {
+ Parse_Error (PARSE_FATAL, "Missing dependency operator");
+ return;
+ }
+
+ cp++; /* Advance beyond operator */
+
+ Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
+
+ /*
+ * Get to the first source
+ */
+ while (*cp && isspace (*cp)) {
+ cp++;
+ }
+ line = cp;
+
+ /*
+ * Several special targets take different actions if present with no
+ * sources:
+ * a .SUFFIXES line with no sources clears out all old suffixes
+ * a .PRECIOUS line makes all targets precious
+ * a .IGNORE line ignores errors for all targets
+ * a .SILENT line creates silence when making all targets
+ * a .PATH removes all directories from the search path(s).
+ */
+ if (!*line) {
+ switch (specType) {
+ case Suffixes:
+ Suff_ClearSuffixes ();
+ break;
+ case Precious:
+ allPrecious = TRUE;
+ break;
+ case Ignore:
+ ignoreErrors = TRUE;
+ break;
+ case Silent:
+ beSilent = TRUE;
+ break;
+ case ExPath:
+ Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
+ break;
+#ifdef POSIX
+ case Posix:
+ Var_Set("%POSIX", "1003.2", VAR_GLOBAL);
+ break;
+#endif
+ default:
+ break;
+ }
+ } else if (specType == MFlags) {
+ /*
+ * Call on functions in main.c to deal with these arguments and
+ * set the initial character to a null-character so the loop to
+ * get sources won't get anything
+ */
+ Main_ParseArgLine (line);
+ *line = '\0';
+ } else if (specType == ExShell) {
+ if (Job_ParseShell (line) != SUCCESS) {
+ Parse_Error (PARSE_FATAL, "improper shell specification");
+ return;
+ }
+ *line = '\0';
+ } else if ((specType == NotParallel) || (specType == SingleShell)) {
+ *line = '\0';
+ }
+
+ /*
+ * NOW GO FOR THE SOURCES
+ */
+ if ((specType == Suffixes) || (specType == ExPath) ||
+ (specType == Includes) || (specType == Libs) ||
+ (specType == Null))
+ {
+ while (*line) {
+ /*
+ * If the target was one that doesn't take files as its sources
+ * but takes something like suffixes, we take each
+ * space-separated word on the line as a something and deal
+ * with it accordingly.
+ *
+ * If the target was .SUFFIXES, we take each source as a
+ * suffix and add it to the list of suffixes maintained by the
+ * Suff module.
+ *
+ * If the target was a .PATH, we add the source as a directory
+ * to search on the search path.
+ *
+ * If it was .INCLUDES, the source is taken to be the suffix of
+ * files which will be #included and whose search path should
+ * be present in the .INCLUDES variable.
+ *
+ * If it was .LIBS, the source is taken to be the suffix of
+ * files which are considered libraries and whose search path
+ * should be present in the .LIBS variable.
+ *
+ * If it was .NULL, the source is the suffix to use when a file
+ * has no valid suffix.
+ */
+ char savec;
+ while (*cp && !isspace (*cp)) {
+ cp++;
+ }
+ savec = *cp;
+ *cp = '\0';
+ switch (specType) {
+ case Suffixes:
+ Suff_AddSuffix (line);
+ break;
+ case ExPath:
+ Lst_ForEach(paths, ParseAddDir, (ClientData)line);
+ break;
+ case Includes:
+ Suff_AddInclude (line);
+ break;
+ case Libs:
+ Suff_AddLib (line);
+ break;
+ case Null:
+ Suff_SetNull (line);
+ break;
+ default:
+ break;
+ }
+ *cp = savec;
+ if (savec != '\0') {
+ cp++;
+ }
+ while (*cp && isspace (*cp)) {
+ cp++;
+ }
+ line = cp;
+ }
+ if (paths) {
+ Lst_Destroy(paths, NOFREE);
+ }
+ } else {
+ while (*line) {
+ /*
+ * The targets take real sources, so we must beware of archive
+ * specifications (i.e. things with left parentheses in them)
+ * and handle them accordingly.
+ */
+ while (*cp && !isspace (*cp)) {
+ if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
+ /*
+ * Only stop for a left parenthesis if it isn't at the
+ * start of a word (that'll be for variable changes
+ * later) and isn't preceded by a dollar sign (a dynamic
+ * source).
+ */
+ break;
+ } else {
+ cp++;
+ }
+ }
+
+ if (*cp == '(') {
+ GNode *gn;
+
+ sources = Lst_Init (FALSE);
+ if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
+ Parse_Error (PARSE_FATAL,
+ "Error in source archive spec \"%s\"", line);
+ return;
+ }
+
+ while (!Lst_IsEmpty (sources)) {
+ gn = (GNode *) Lst_DeQueue (sources);
+ ParseDoSrc (tOp, gn->name, curSrcs);
+ }
+ Lst_Destroy (sources, NOFREE);
+ cp = line;
+ } else {
+ if (*cp) {
+ *cp = '\0';
+ cp += 1;
+ }
+
+ ParseDoSrc (tOp, line, curSrcs);
+ }
+ while (*cp && isspace (*cp)) {
+ cp++;
+ }
+ line = cp;
+ }
+ }
+
+ if (mainNode == NILGNODE) {
+ /*
+ * If we have yet to decide on a main target to make, in the
+ * absence of any user input, we want the first target on
+ * the first dependency line that is actually a real target
+ * (i.e. isn't a .USE or .EXEC rule) to be made.
+ */
+ Lst_ForEach (targets, ParseFindMain, (ClientData)0);
+ }
+
+ /*
+ * Finally, destroy the list of sources
+ */
+ Lst_Destroy(curSrcs, NOFREE);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * Parse_IsVar --
+ * Return TRUE if the passed line is a variable assignment. A variable
+ * assignment consists of a single word followed by optional whitespace
+ * followed by either a += or an = operator.
+ * This function is used both by the Parse_File function and main when
+ * parsing the command-line arguments.
+ *
+ * Results:
+ * TRUE if it is. FALSE if it ain't
+ *
+ * Side Effects:
+ * none
+ *---------------------------------------------------------------------
+ */
+Boolean
+Parse_IsVar (line)
+ register char *line; /* the line to check */
+{
+ register Boolean wasSpace = FALSE; /* set TRUE if found a space */
+ register Boolean haveName = FALSE; /* Set TRUE if have a variable name */
+ int level = 0;
+#define ISEQOPERATOR(c) \
+ (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
+
+ /*
+ * Skip to variable name
+ */
+ for (;(*line == ' ') || (*line == '\t'); line++)
+ continue;
+
+ for (; *line != '=' || level != 0; line++)
+ switch (*line) {
+ case '\0':
+ /*
+ * end-of-line -- can't be a variable assignment.
+ */
+ return FALSE;
+
+ case ' ':
+ case '\t':
+ /*
+ * there can be as much white space as desired so long as there is
+ * only one word before the operator
+ */
+ wasSpace = TRUE;
+ break;
+
+ case '(':
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ case ')':
+ level--;
+ break;
+
+ default:
+ if (wasSpace && haveName) {
+ if (ISEQOPERATOR(*line)) {
+ /*
+ * We must have a finished word
+ */
+ if (level != 0)
+ return FALSE;
+
+ /*
+ * When an = operator [+?!:] is found, the next
+ * character must be an = or it ain't a valid
+ * assignment.
+ */
+ if (line[1] == '=')
+ return haveName;
+#ifdef SUNSHCMD
+ /*
+ * This is a shell command
+ */
+ if (strncmp(line, ":sh", 3) == 0)
+ return haveName;
+#endif
+ }
+ /*
+ * This is the start of another word, so not assignment.
+ */
+ return FALSE;
+ }
+ else {
+ haveName = TRUE;
+ wasSpace = FALSE;
+ }
+ break;
+ }
+
+ return haveName;
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * Parse_DoVar --
+ * Take the variable assignment in the passed line and do it in the
+ * global context.
+ *
+ * Note: There is a lexical ambiguity with assignment modifier characters
+ * in variable names. This routine interprets the character before the =
+ * as a modifier. Therefore, an assignment like
+ * C++=/usr/bin/CC
+ * is interpreted as "C+ +=" instead of "C++ =".
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * the variable structure of the given variable name is altered in the
+ * global context.
+ *---------------------------------------------------------------------
+ */
+void
+Parse_DoVar (line, ctxt)
+ char *line; /* a line guaranteed to be a variable
+ * assignment. This reduces error checks */
+ GNode *ctxt; /* Context in which to do the assignment */
+{
+ char *cp; /* pointer into line */
+ enum {
+ VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
+ } type; /* Type of assignment */
+ char *opc; /* ptr to operator character to
+ * null-terminate the variable name */
+ /*
+ * Avoid clobbered variable warnings by forcing the compiler
+ * to ``unregister'' variables
+ */
+#if __GNUC__
+ (void) &cp;
+ (void) &line;
+#endif
+
+ /*
+ * Skip to variable name
+ */
+ while ((*line == ' ') || (*line == '\t')) {
+ line++;
+ }
+
+ /*
+ * Skip to operator character, nulling out whitespace as we go
+ */
+ for (cp = line + 1; *cp != '='; cp++) {
+ if (isspace (*cp)) {
+ *cp = '\0';
+ }
+ }
+ opc = cp-1; /* operator is the previous character */
+ *cp++ = '\0'; /* nuke the = */
+
+ /*
+ * Check operator type
+ */
+ switch (*opc) {
+ case '+':
+ type = VAR_APPEND;
+ *opc = '\0';
+ break;
+
+ case '?':
+ /*
+ * If the variable already has a value, we don't do anything.
+ */
+ *opc = '\0';
+ if (Var_Exists(line, ctxt)) {
+ return;
+ } else {
+ type = VAR_NORMAL;
+ }
+ break;
+
+ case ':':
+ type = VAR_SUBST;
+ *opc = '\0';
+ break;
+
+ case '!':
+ type = VAR_SHELL;
+ *opc = '\0';
+ break;
+
+ default:
+#ifdef SUNSHCMD
+ while (*opc != ':')
+ if (--opc < line)
+ break;
+
+ if (strncmp(opc, ":sh", 3) == 0) {
+ type = VAR_SHELL;
+ *opc = '\0';
+ break;
+ }
+#endif
+ type = VAR_NORMAL;
+ break;
+ }
+
+ while (isspace (*cp)) {
+ cp++;
+ }
+
+ if (type == VAR_APPEND) {
+ Var_Append (line, cp, ctxt);
+ } else if (type == VAR_SUBST) {
+ /*
+ * Allow variables in the old value to be undefined, but leave their
+ * invocation alone -- this is done by forcing oldVars to be false.
+ * XXX: This can cause recursive variables, but that's not hard to do,
+ * and this allows someone to do something like
+ *
+ * CFLAGS = $(.INCLUDES)
+ * CFLAGS := -I.. $(CFLAGS)
+ *
+ * And not get an error.
+ */
+ Boolean oldOldVars = oldVars;
+
+ oldVars = FALSE;
+ cp = Var_Subst(NULL, cp, ctxt, FALSE);
+ oldVars = oldOldVars;
+
+ Var_Set(line, cp, ctxt);
+ free(cp);
+ } else if (type == VAR_SHELL) {
+ Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.
+ * if any variable expansion was performed */
+ char *res, *err;
+
+ if (strchr(cp, '$') != NULL) {
+ /*
+ * There's a dollar sign in the command, so perform variable
+ * expansion on the whole thing. The resulting string will need
+ * freeing when we're done, so set freeCmd to TRUE.
+ */
+ cp = Var_Subst(NULL, cp, VAR_CMD, TRUE);
+ freeCmd = TRUE;
+ }
+
+ res = Cmd_Exec(cp, &err);
+ Var_Set(line, res, ctxt);
+ free(res);
+
+ if (err)
+ Parse_Error(PARSE_WARNING, err, cp);
+
+ if (freeCmd)
+ free(cp);
+ } else {
+ /*
+ * Normal assignment -- just do it.
+ */
+ Var_Set(line, cp, ctxt);
+ }
+}
+
+
+/*-
+ * ParseAddCmd --
+ * Lst_ForEach function to add a command line to all targets
+ *
+ * Results:
+ * Always 0
+ *
+ * Side Effects:
+ * A new element is added to the commands list of the node.
+ */
+static int
+ParseAddCmd(gnp, cmd)
+ ClientData gnp; /* the node to which the command is to be added */
+ ClientData cmd; /* the command to add */
+{
+ GNode *gn = (GNode *) gnp;
+ /* if target already supplied, ignore commands */
+ if (!(gn->type & OP_HAS_COMMANDS))
+ (void)Lst_AtEnd(gn->commands, cmd);
+ return(0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ParseHasCommands --
+ * Callback procedure for Parse_File when destroying the list of
+ * targets on the last dependency line. Marks a target as already
+ * having commands if it does, to keep from having shell commands
+ * on multiple dependency lines.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * OP_HAS_COMMANDS may be set for the target.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+ParseHasCommands(gnp)
+ ClientData gnp; /* Node to examine */
+{
+ GNode *gn = (GNode *) gnp;
+ if (!Lst_IsEmpty(gn->commands)) {
+ gn->type |= OP_HAS_COMMANDS;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Parse_AddIncludeDir --
+ * Add a directory to the path searched for included makefiles
+ * bracketed by double-quotes. Used by functions in main.c
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The directory is appended to the list.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Parse_AddIncludeDir (dir)
+ char *dir; /* The name of the directory to add */
+{
+ Dir_AddDir (parseIncPath, dir);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseDoInclude --
+ * Push to another file.
+ *
+ * The input is the line minus the #include. A file spec is a string
+ * enclosed in <> or "". The former is looked for only in sysIncPath.
+ * The latter in . and the directories specified by -I command line
+ * options
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * A structure is added to the includes Lst and readProc, lineno,
+ * fname and curFILE are altered for the new file
+ *---------------------------------------------------------------------
+ */
+static void
+ParseDoInclude (file)
+ char *file; /* file specification */
+{
+ char *fullname; /* full pathname of file */
+ IFile *oldFile; /* state associated with current file */
+ char endc; /* the character which ends the file spec */
+ char *cp; /* current position in file spec */
+ Boolean isSystem; /* TRUE if makefile is a system makefile */
+
+ /*
+ * Skip to delimiter character so we know where to look
+ */
+ while ((*file == ' ') || (*file == '\t')) {
+ file++;
+ }
+
+ if ((*file != '"') && (*file != '<')) {
+ Parse_Error (PARSE_FATAL,
+ ".include filename must be delimited by '\"' or '<'");
+ return;
+ }
+
+ /*
+ * Set the search path on which to find the include file based on the
+ * characters which bracket its name. Angle-brackets imply it's
+ * a system Makefile while double-quotes imply it's a user makefile
+ */
+ if (*file == '<') {
+ isSystem = TRUE;
+ endc = '>';
+ } else {
+ isSystem = FALSE;
+ endc = '"';
+ }
+
+ /*
+ * Skip to matching delimiter
+ */
+ for (cp = ++file; *cp && *cp != endc; cp++) {
+ continue;
+ }
+
+ if (*cp != endc) {
+ Parse_Error (PARSE_FATAL,
+ "Unclosed %cinclude filename. '%c' expected",
+ '.', endc);
+ return;
+ }
+ *cp = '\0';
+
+ /*
+ * Substitute for any variables in the file name before trying to
+ * find the thing.
+ */
+ file = Var_Subst (NULL, file, VAR_CMD, FALSE);
+
+ /*
+ * Now we know the file's name and its search path, we attempt to
+ * find the durn thing. A return of NULL indicates the file don't
+ * exist.
+ */
+ if (!isSystem) {
+ /*
+ * Include files contained in double-quotes are first searched for
+ * relative to the including file's location. We don't want to
+ * cd there, of course, so we just tack on the old file's
+ * leading path components and call Dir_FindFile to see if
+ * we can locate the beast.
+ */
+ char *prefEnd, *Fname;
+
+ /* Make a temporary copy of this, to be safe. */
+ Fname = estrdup(fname);
+
+ prefEnd = strrchr (Fname, '/');
+ if (prefEnd != (char *)NULL) {
+ char *newName;
+
+ *prefEnd = '\0';
+ if (file[0] == '/')
+ newName = estrdup(file);
+ else
+ newName = str_concat (Fname, file, STR_ADDSLASH);
+ fullname = Dir_FindFile (newName, parseIncPath);
+ if (fullname == (char *)NULL) {
+ fullname = Dir_FindFile(newName, dirSearchPath);
+ }
+ free (newName);
+ *prefEnd = '/';
+ } else {
+ fullname = (char *)NULL;
+ }
+ free (Fname);
+ } else {
+ fullname = (char *)NULL;
+ }
+
+ if (fullname == (char *)NULL) {
+ /*
+ * System makefile or makefile wasn't found in same directory as
+ * included makefile. Search for it first on the -I search path,
+ * then on the .PATH search path, if not found in a -I directory.
+ * XXX: Suffix specific?
+ */
+ fullname = Dir_FindFile (file, parseIncPath);
+ if (fullname == (char *)NULL) {
+ fullname = Dir_FindFile(file, dirSearchPath);
+ }
+ }
+
+ if (fullname == (char *)NULL) {
+ /*
+ * Still haven't found the makefile. Look for it on the system
+ * path as a last resort.
+ */
+ fullname = Dir_FindFile(file, sysIncPath);
+ }
+
+ if (fullname == (char *) NULL) {
+ *cp = endc;
+ Parse_Error (PARSE_FATAL, "Could not find %s", file);
+ return;
+ }
+
+ free(file);
+
+ /*
+ * Once we find the absolute path to the file, we get to save all the
+ * state from the current file before we can start reading this
+ * include file. The state is stored in an IFile structure which
+ * is placed on a list with other IFile structures. The list makes
+ * a very nice stack to track how we got here...
+ */
+ oldFile = (IFile *) emalloc (sizeof (IFile));
+ oldFile->fname = fname;
+
+ oldFile->F = curFILE;
+ oldFile->p = curPTR;
+ oldFile->lineno = lineno;
+
+ (void) Lst_AtFront (includes, (ClientData)oldFile);
+
+ /*
+ * Once the previous state has been saved, we can get down to reading
+ * the new file. We set up the name of the file to be the absolute
+ * name of the include file so error messages refer to the right
+ * place. Naturally enough, we start reading at line number 0.
+ */
+ fname = fullname;
+ lineno = 0;
+
+ curFILE = fopen (fullname, "r");
+ curPTR = NULL;
+ if (curFILE == (FILE * ) NULL) {
+ Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
+ /*
+ * Pop to previous file
+ */
+ (void) ParseEOF(0);
+ }
+}
+
+
+/*-
+ *---------------------------------------------------------------------
+ * Parse_FromString --
+ * Start Parsing from the given string
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * A structure is added to the includes Lst and readProc, lineno,
+ * fname and curFILE are altered for the new file
+ *---------------------------------------------------------------------
+ */
+void
+Parse_FromString(str)
+ char *str;
+{
+ IFile *oldFile; /* state associated with this file */
+
+ if (DEBUG(FOR))
+ (void) fprintf(stderr, "%s\n----\n", str);
+
+ oldFile = (IFile *) emalloc (sizeof (IFile));
+ oldFile->lineno = lineno;
+ oldFile->fname = fname;
+ oldFile->F = curFILE;
+ oldFile->p = curPTR;
+
+ (void) Lst_AtFront (includes, (ClientData)oldFile);
+
+ curFILE = NULL;
+ curPTR = (PTR *) emalloc (sizeof (PTR));
+ curPTR->str = curPTR->ptr = str;
+ lineno = 0;
+ fname = estrdup(fname);
+}
+
+
+#ifdef SYSVINCLUDE
+/*-
+ *---------------------------------------------------------------------
+ * ParseTraditionalInclude --
+ * Push to another file.
+ *
+ * The input is the line minus the "include". The file name is
+ * the string following the "include".
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * A structure is added to the includes Lst and readProc, lineno,
+ * fname and curFILE are altered for the new file
+ *---------------------------------------------------------------------
+ */
+static void
+ParseTraditionalInclude (file)
+ char *file; /* file specification */
+{
+ char *fullname; /* full pathname of file */
+ IFile *oldFile; /* state associated with current file */
+ char *cp; /* current position in file spec */
+ char *prefEnd;
+
+ /*
+ * Skip over whitespace
+ */
+ while ((*file == ' ') || (*file == '\t')) {
+ file++;
+ }
+
+ if (*file == '\0') {
+ Parse_Error (PARSE_FATAL,
+ "Filename missing from \"include\"");
+ return;
+ }
+
+ /*
+ * Skip to end of line or next whitespace
+ */
+ for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) {
+ continue;
+ }
+
+ *cp = '\0';
+
+ /*
+ * Substitute for any variables in the file name before trying to
+ * find the thing.
+ */
+ file = Var_Subst (NULL, file, VAR_CMD, FALSE);
+
+ /*
+ * Now we know the file's name, we attempt to find the durn thing.
+ * A return of NULL indicates the file don't exist.
+ *
+ * Include files are first searched for relative to the including
+ * file's location. We don't want to cd there, of course, so we
+ * just tack on the old file's leading path components and call
+ * Dir_FindFile to see if we can locate the beast.
+ * XXX - this *does* search in the current directory, right?
+ */
+
+ prefEnd = strrchr (fname, '/');
+ if (prefEnd != (char *)NULL) {
+ char *newName;
+
+ *prefEnd = '\0';
+ newName = str_concat (fname, file, STR_ADDSLASH);
+ fullname = Dir_FindFile (newName, parseIncPath);
+ if (fullname == (char *)NULL) {
+ fullname = Dir_FindFile(newName, dirSearchPath);
+ }
+ free (newName);
+ *prefEnd = '/';
+ } else {
+ fullname = (char *)NULL;
+ }
+
+ if (fullname == (char *)NULL) {
+ /*
+ * System makefile or makefile wasn't found in same directory as
+ * included makefile. Search for it first on the -I search path,
+ * then on the .PATH search path, if not found in a -I directory.
+ * XXX: Suffix specific?
+ */
+ fullname = Dir_FindFile (file, parseIncPath);
+ if (fullname == (char *)NULL) {
+ fullname = Dir_FindFile(file, dirSearchPath);
+ }
+ }
+
+ if (fullname == (char *)NULL) {
+ /*
+ * Still haven't found the makefile. Look for it on the system
+ * path as a last resort.
+ */
+ fullname = Dir_FindFile(file, sysIncPath);
+ }
+
+ if (fullname == (char *) NULL) {
+ Parse_Error (PARSE_FATAL, "Could not find %s", file);
+ return;
+ }
+
+ /*
+ * Once we find the absolute path to the file, we get to save all the
+ * state from the current file before we can start reading this
+ * include file. The state is stored in an IFile structure which
+ * is placed on a list with other IFile structures. The list makes
+ * a very nice stack to track how we got here...
+ */
+ oldFile = (IFile *) emalloc (sizeof (IFile));
+ oldFile->fname = fname;
+
+ oldFile->F = curFILE;
+ oldFile->p = curPTR;
+ oldFile->lineno = lineno;
+
+ (void) Lst_AtFront (includes, (ClientData)oldFile);
+
+ /*
+ * Once the previous state has been saved, we can get down to reading
+ * the new file. We set up the name of the file to be the absolute
+ * name of the include file so error messages refer to the right
+ * place. Naturally enough, we start reading at line number 0.
+ */
+ fname = fullname;
+ lineno = 0;
+
+ curFILE = fopen (fullname, "r");
+ curPTR = NULL;
+ if (curFILE == (FILE * ) NULL) {
+ Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
+ /*
+ * Pop to previous file
+ */
+ (void) ParseEOF(1);
+ }
+}
+#endif
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseEOF --
+ * Called when EOF is reached in the current file. If we were reading
+ * an include file, the includes stack is popped and things set up
+ * to go back to reading the previous file at the previous location.
+ *
+ * Results:
+ * CONTINUE if there's more to do. DONE if not.
+ *
+ * Side Effects:
+ * The old curFILE, is closed. The includes list is shortened.
+ * lineno, curFILE, and fname are changed if CONTINUE is returned.
+ *---------------------------------------------------------------------
+ */
+static int
+ParseEOF (opened)
+ int opened;
+{
+ IFile *ifile; /* the state on the top of the includes stack */
+
+ if (Lst_IsEmpty (includes)) {
+ return (DONE);
+ }
+
+ ifile = (IFile *) Lst_DeQueue (includes);
+ free ((Address) fname);
+ fname = ifile->fname;
+ lineno = ifile->lineno;
+ if (opened && curFILE)
+ (void) fclose (curFILE);
+ if (curPTR) {
+ free((Address) curPTR->str);
+ free((Address) curPTR);
+ }
+ curFILE = ifile->F;
+ curPTR = ifile->p;
+ free ((Address)ifile);
+ return (CONTINUE);
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseReadc --
+ * Read a character from the current file
+ *
+ * Results:
+ * The character that was read
+ *
+ * Side Effects:
+ *---------------------------------------------------------------------
+ */
+static int
+ParseReadc()
+{
+ if (curFILE)
+ return fgetc(curFILE);
+
+ if (curPTR && *curPTR->ptr)
+ return *curPTR->ptr++;
+ return EOF;
+}
+
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseUnreadc --
+ * Put back a character to the current file
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ *---------------------------------------------------------------------
+ */
+static void
+ParseUnreadc(c)
+ int c;
+{
+ if (curFILE) {
+ ungetc(c, curFILE);
+ return;
+ }
+ if (curPTR) {
+ *--(curPTR->ptr) = c;
+ return;
+ }
+}
+
+
+/* ParseSkipLine():
+ * Grab the next line
+ */
+static char *
+ParseSkipLine(skip)
+ int skip; /* Skip lines that don't start with . */
+{
+ char *line;
+ int c, lastc, lineLength = 0;
+ Buffer buf;
+
+ buf = Buf_Init(MAKE_BSIZE);
+
+ do {
+ Buf_Discard(buf, lineLength);
+ lastc = '\0';
+
+ while (((c = ParseReadc()) != '\n' || lastc == '\\')
+ && c != EOF) {
+ if (c == '\n') {
+ Buf_ReplaceLastByte(buf, (Byte)' ');
+ lineno++;
+
+ while ((c = ParseReadc()) == ' ' || c == '\t');
+
+ if (c == EOF)
+ break;
+ }
+
+ Buf_AddByte(buf, (Byte)c);
+ lastc = c;
+ }
+
+ if (c == EOF) {
+ Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop");
+ Buf_Destroy(buf, TRUE);
+ return((char *)NULL);
+ }
+
+ lineno++;
+ Buf_AddByte(buf, (Byte)'\0');
+ line = (char *)Buf_GetAll(buf, &lineLength);
+ } while (skip == 1 && line[0] != '.');
+
+ Buf_Destroy(buf, FALSE);
+ return line;
+}
+
+
+/*-
+ *---------------------------------------------------------------------
+ * ParseReadLine --
+ * Read an entire line from the input file. Called only by Parse_File.
+ * To facilitate escaped newlines and what have you, a character is
+ * buffered in 'lastc', which is '\0' when no characters have been
+ * read. When we break out of the loop, c holds the terminating
+ * character and lastc holds a character that should be added to
+ * the line (unless we don't read anything but a terminator).
+ *
+ * Results:
+ * A line w/o its newline
+ *
+ * Side Effects:
+ * Only those associated with reading a character
+ *---------------------------------------------------------------------
+ */
+static char *
+ParseReadLine ()
+{
+ Buffer buf; /* Buffer for current line */
+ register int c; /* the current character */
+ register int lastc; /* The most-recent character */
+ Boolean semiNL; /* treat semi-colons as newlines */
+ Boolean ignDepOp; /* TRUE if should ignore dependency operators
+ * for the purposes of setting semiNL */
+ Boolean ignComment; /* TRUE if should ignore comments (in a
+ * shell command */
+ char *line; /* Result */
+ char *ep; /* to strip trailing blanks */
+ int lineLength; /* Length of result */
+
+ semiNL = FALSE;
+ ignDepOp = FALSE;
+ ignComment = FALSE;
+
+ /*
+ * Handle special-characters at the beginning of the line. Either a
+ * leading tab (shell command) or pound-sign (possible conditional)
+ * forces us to ignore comments and dependency operators and treat
+ * semi-colons as semi-colons (by leaving semiNL FALSE). This also
+ * discards completely blank lines.
+ */
+ for (;;) {
+ c = ParseReadc();
+
+ if (c == '\t') {
+ ignComment = ignDepOp = TRUE;
+ break;
+ } else if (c == '\n') {
+ lineno++;
+ } else if (c == '#') {
+ ParseUnreadc(c);
+ break;
+ } else {
+ /*
+ * Anything else breaks out without doing anything
+ */
+ break;
+ }
+ }
+
+ if (c != EOF) {
+ lastc = c;
+ buf = Buf_Init(MAKE_BSIZE);
+
+ while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
+ (c != EOF))
+ {
+test_char:
+ switch(c) {
+ case '\n':
+ /*
+ * Escaped newline: read characters until a non-space or an
+ * unescaped newline and replace them all by a single space.
+ * This is done by storing the space over the backslash and
+ * dropping through with the next nonspace. If it is a
+ * semi-colon and semiNL is TRUE, it will be recognized as a
+ * newline in the code below this...
+ */
+ lineno++;
+ lastc = ' ';
+ while ((c = ParseReadc ()) == ' ' || c == '\t') {
+ continue;
+ }
+ if (c == EOF || c == '\n') {
+ goto line_read;
+ } else {
+ /*
+ * Check for comments, semiNL's, etc. -- easier than
+ * ParseUnreadc(c); continue;
+ */
+ goto test_char;
+ }
+ /*NOTREACHED*/
+ break;
+
+ case ';':
+ /*
+ * Semi-colon: Need to see if it should be interpreted as a
+ * newline
+ */
+ if (semiNL) {
+ /*
+ * To make sure the command that may be following this
+ * semi-colon begins with a tab, we push one back into the
+ * input stream. This will overwrite the semi-colon in the
+ * buffer. If there is no command following, this does no
+ * harm, since the newline remains in the buffer and the
+ * whole line is ignored.
+ */
+ ParseUnreadc('\t');
+ goto line_read;
+ }
+ break;
+ case '=':
+ if (!semiNL) {
+ /*
+ * Haven't seen a dependency operator before this, so this
+ * must be a variable assignment -- don't pay attention to
+ * dependency operators after this.
+ */
+ ignDepOp = TRUE;
+ } else if (lastc == ':' || lastc == '!') {
+ /*
+ * Well, we've seen a dependency operator already, but it
+ * was the previous character, so this is really just an
+ * expanded variable assignment. Revert semi-colons to
+ * being just semi-colons again and ignore any more
+ * dependency operators.
+ *
+ * XXX: Note that a line like "foo : a:=b" will blow up,
+ * but who'd write a line like that anyway?
+ */
+ ignDepOp = TRUE; semiNL = FALSE;
+ }
+ break;
+ case '#':
+ if (!ignComment) {
+ if (
+#if 0
+ compatMake &&
+#endif
+ (lastc != '\\')) {
+ /*
+ * If the character is a hash mark and it isn't escaped
+ * (or we're being compatible), the thing is a comment.
+ * Skip to the end of the line.
+ */
+ do {
+ c = ParseReadc();
+ } while ((c != '\n') && (c != EOF));
+ goto line_read;
+ } else {
+ /*
+ * Don't add the backslash. Just let the # get copied
+ * over.
+ */
+ lastc = c;
+ continue;
+ }
+ }
+ break;
+ case ':':
+ case '!':
+ if (!ignDepOp && (c == ':' || c == '!')) {
+ /*
+ * A semi-colon is recognized as a newline only on
+ * dependency lines. Dependency lines are lines with a
+ * colon or an exclamation point. Ergo...
+ */
+ semiNL = TRUE;
+ }
+ break;
+ }
+ /*
+ * Copy in the previous character and save this one in lastc.
+ */
+ Buf_AddByte (buf, (Byte)lastc);
+ lastc = c;
+
+ }
+ line_read:
+ lineno++;
+
+ if (lastc != '\0') {
+ Buf_AddByte (buf, (Byte)lastc);
+ }
+ Buf_AddByte (buf, (Byte)'\0');
+ line = (char *)Buf_GetAll (buf, &lineLength);
+ Buf_Destroy (buf, FALSE);
+
+ /*
+ * Strip trailing blanks and tabs from the line.
+ * Do not strip a blank or tab that is preceeded by
+ * a '\'
+ */
+ ep = line;
+ while (*ep)
+ ++ep;
+ while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {
+ if (ep > line + 1 && ep[-2] == '\\')
+ break;
+ --ep;
+ }
+ *ep = 0;
+
+ if (line[0] == '.') {
+ /*
+ * The line might be a conditional. Ask the conditional module
+ * about it and act accordingly
+ */
+ switch (Cond_Eval (line)) {
+ case COND_SKIP:
+ /*
+ * Skip to next conditional that evaluates to COND_PARSE.
+ */
+ do {
+ free (line);
+ line = ParseSkipLine(1);
+ } while (line && Cond_Eval(line) != COND_PARSE);
+ if (line == NULL)
+ break;
+ /*FALLTHRU*/
+ case COND_PARSE:
+ free ((Address) line);
+ line = ParseReadLine();
+ break;
+ case COND_INVALID:
+ if (For_Eval(line)) {
+ int ok;
+ free(line);
+ do {
+ /*
+ * Skip after the matching end
+ */
+ line = ParseSkipLine(0);
+ if (line == NULL) {
+ Parse_Error (PARSE_FATAL,
+ "Unexpected end of file in for loop.\n");
+ break;
+ }
+ ok = For_Eval(line);
+ free(line);
+ }
+ while (ok);
+ if (line != NULL)
+ For_Run();
+ line = ParseReadLine();
+ }
+ break;
+ }
+ }
+ return (line);
+
+ } else {
+ /*
+ * Hit end-of-file, so return a NULL line to indicate this.
+ */
+ return((char *)NULL);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * ParseFinishLine --
+ * Handle the end of a dependency group.
+ *
+ * Results:
+ * Nothing.
+ *
+ * Side Effects:
+ * inLine set FALSE. 'targets' list destroyed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+ParseFinishLine()
+{
+ if (inLine) {
+ Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
+ Lst_Destroy (targets, ParseHasCommands);
+ targets = NULL;
+ inLine = FALSE;
+ }
+}
+
+
+/*-
+ *---------------------------------------------------------------------
+ * Parse_File --
+ * Parse a file into its component parts, incorporating it into the
+ * current dependency graph. This is the main function and controls
+ * almost every other function in this module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Loads. Nodes are added to the list of all targets, nodes and links
+ * are added to the dependency graph. etc. etc. etc.
+ *---------------------------------------------------------------------
+ */
+void
+Parse_File(name, stream)
+ char *name; /* the name of the file being read */
+ FILE * stream; /* Stream open to makefile to parse */
+{
+ register char *cp, /* pointer into the line */
+ *line; /* the line we're working on */
+
+ inLine = FALSE;
+ fname = name;
+ curFILE = stream;
+ lineno = 0;
+ fatals = 0;
+
+ do {
+ while ((line = ParseReadLine ()) != NULL) {
+ if (*line == '.') {
+ /*
+ * Lines that begin with the special character are either
+ * include or undef directives.
+ */
+ for (cp = line + 1; isspace (*cp); cp++) {
+ continue;
+ }
+ if (strncmp (cp, "include", 7) == 0) {
+ ParseDoInclude (cp + 7);
+ goto nextLine;
+ } else if (strncmp(cp, "undef", 5) == 0) {
+ char *cp2;
+ for (cp += 5; isspace((unsigned char) *cp); cp++) {
+ continue;
+ }
+
+ for (cp2 = cp; !isspace((unsigned char) *cp2) &&
+ (*cp2 != '\0'); cp2++) {
+ continue;
+ }
+
+ *cp2 = '\0';
+
+ Var_Delete(cp, VAR_GLOBAL);
+ goto nextLine;
+ }
+ }
+ if (*line == '#') {
+ /* If we're this far, the line must be a comment. */
+ goto nextLine;
+ }
+
+ if (*line == '\t') {
+ /*
+ * If a line starts with a tab, it can only hope to be
+ * a creation command.
+ */
+#ifndef POSIX
+ shellCommand:
+#endif
+ for (cp = line + 1; isspace (*cp); cp++) {
+ continue;
+ }
+ if (*cp) {
+ if (inLine) {
+ /*
+ * So long as it's not a blank line and we're actually
+ * in a dependency spec, add the command to the list of
+ * commands of all targets in the dependency spec
+ */
+ Lst_ForEach (targets, ParseAddCmd, cp);
+ Lst_AtEnd(targCmds, (ClientData) line);
+ continue;
+ } else {
+ Parse_Error (PARSE_FATAL,
+ "Unassociated shell command \"%s\"",
+ cp);
+ }
+ }
+#ifdef SYSVINCLUDE
+ } else if (strncmp (line, "include", 7) == 0 &&
+ isspace((unsigned char) line[7]) &&
+ strchr(line, ':') == NULL) {
+ /*
+ * It's an S3/S5-style "include".
+ */
+ ParseTraditionalInclude (line + 7);
+ goto nextLine;
+#endif
+ } else if (Parse_IsVar (line)) {
+ ParseFinishLine();
+ Parse_DoVar (line, VAR_GLOBAL);
+ } else {
+ /*
+ * We now know it's a dependency line so it needs to have all
+ * variables expanded before being parsed. Tell the variable
+ * module to complain if some variable is undefined...
+ * To make life easier on novices, if the line is indented we
+ * first make sure the line has a dependency operator in it.
+ * If it doesn't have an operator and we're in a dependency
+ * line's script, we assume it's actually a shell command
+ * and add it to the current list of targets.
+ */
+#ifndef POSIX
+ Boolean nonSpace = FALSE;
+#endif
+
+ cp = line;
+ if (isspace((unsigned char) line[0])) {
+ while ((*cp != '\0') && isspace((unsigned char) *cp)) {
+ cp++;
+ }
+ if (*cp == '\0') {
+ goto nextLine;
+ }
+#ifndef POSIX
+ while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
+ nonSpace = TRUE;
+ cp++;
+ }
+#endif
+ }
+
+#ifndef POSIX
+ if (*cp == '\0') {
+ if (inLine) {
+ Parse_Error (PARSE_WARNING,
+ "Shell command needs a leading tab");
+ goto shellCommand;
+ } else if (nonSpace) {
+ Parse_Error (PARSE_FATAL, "Missing operator");
+ }
+ } else {
+#endif
+ ParseFinishLine();
+
+ cp = Var_Subst (NULL, line, VAR_CMD, TRUE);
+ free (line);
+ line = cp;
+
+ /*
+ * Need a non-circular list for the target nodes
+ */
+ if (targets)
+ Lst_Destroy(targets, NOFREE);
+
+ targets = Lst_Init (FALSE);
+ inLine = TRUE;
+
+ ParseDoDependency (line);
+#ifndef POSIX
+ }
+#endif
+ }
+
+ nextLine:
+
+ free (line);
+ }
+ /*
+ * Reached EOF, but it may be just EOF of an include file...
+ */
+ } while (ParseEOF(1) == CONTINUE);
+
+ /*
+ * Make sure conditionals are clean
+ */
+ Cond_End();
+
+ if (fatals) {
+ fprintf (stderr, "Fatal errors encountered -- cannot continue\n");
+ exit (1);
+ }
+}
+
+/*-
+ *---------------------------------------------------------------------
+ * Parse_Init --
+ * initialize the parsing module
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * the parseIncPath list is initialized...
+ *---------------------------------------------------------------------
+ */
+void
+Parse_Init ()
+{
+ mainNode = NILGNODE;
+ parseIncPath = Lst_Init (FALSE);
+ sysIncPath = Lst_Init (FALSE);
+ includes = Lst_Init (FALSE);
+ targCmds = Lst_Init (FALSE);
+}
+
+void
+Parse_End()
+{
+ Lst_Destroy(targCmds, (void (*) __P((ClientData))) free);
+ if (targets)
+ Lst_Destroy(targets, NOFREE);
+ Lst_Destroy(sysIncPath, Dir_Destroy);
+ Lst_Destroy(parseIncPath, Dir_Destroy);
+ Lst_Destroy(includes, NOFREE); /* Should be empty now */
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Parse_MainName --
+ * Return a Lst of the main target to create for main()'s sake. If
+ * no such target exists, we Punt with an obnoxious error message.
+ *
+ * Results:
+ * A Lst of the single node to create.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+Lst
+Parse_MainName()
+{
+ Lst main; /* result list */
+
+ main = Lst_Init (FALSE);
+
+ if (mainNode == NILGNODE) {
+ Punt ("no target to make.");
+ /*NOTREACHED*/
+ } else if (mainNode->type & OP_DOUBLEDEP) {
+ (void) Lst_AtEnd (main, (ClientData)mainNode);
+ Lst_Concat(main, mainNode->cohorts, LST_CONCNEW);
+ }
+ else
+ (void) Lst_AtEnd (main, (ClientData)mainNode);
+ return (main);
+}
diff --git a/usr.bin/tip/pathnames.h b/usr.bin/make/pathnames.h
index b58251d..4405682 100644
--- a/usr.bin/tip/pathnames.h
+++ b/usr.bin/make/pathnames.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1989, 1993
+ * Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,15 +30,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ * from: @(#)pathnames.h 5.2 (Berkeley) 6/1/90
+ * $Id$
*/
-#include <paths.h>
-
-#define _PATH_ACULOG "/var/log/aculog"
-#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK..%s"
-#ifdef notdef
-#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK/LCK..%s"
-#endif
-#define _PATH_PHONES "/etc/phones"
-#define _PATH_REMOTE "/etc/remote"
+#define _PATH_OBJDIR "obj"
+#define _PATH_OBJDIRPREFIX "/usr/obj"
+#define _PATH_DEFSHELLDIR "/bin"
+#define _PATH_DEFSYSMK "sys.mk"
+#define _PATH_DEFSYSPATH "/usr/share/mk"
diff --git a/usr.bin/make/bit.h b/usr.bin/make/sprite.h
index 53b3745..d2646f4 100644
--- a/usr.bin/make/bit.h
+++ b/usr.bin/make/sprite.h
@@ -35,66 +35,78 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)bit.h 8.2 (Berkeley) 4/28/95
+ * from: @(#)sprite.h 8.1 (Berkeley) 6/6/93
+ * $Id$
*/
/*
- * bit.h --
+ * sprite.h --
*
- * Definition of macros for setting and clearing bits in an array
- * of integers.
- *
- * It is assumed that "int" is 32 bits wide.
+ * Common constants and type declarations for Sprite.
*/
-#ifndef _BIT
-#define _BIT
+#ifndef _SPRITE
+#define _SPRITE
+
+
+/*
+ * A boolean type is defined as an integer, not an enum. This allows a
+ * boolean argument to be an expression that isn't strictly 0 or 1 valued.
+ */
-#include "sprite.h"
+typedef int Boolean;
+#ifndef TRUE
+#define TRUE 1
+#endif TRUE
+#ifndef FALSE
+#define FALSE 0
+#endif FALSE
-#define BIT_NUM_BITS_PER_INT 32
-#define BIT_NUM_BITS_PER_BYTE 8
+/*
+ * Functions that must return a status can return a ReturnStatus to
+ * indicate success or type of failure.
+ */
-#define Bit_NumInts(numBits) \
- (((numBits)+BIT_NUM_BITS_PER_INT -1)/BIT_NUM_BITS_PER_INT)
+typedef int ReturnStatus;
-#define Bit_NumBytes(numBits) \
- (Bit_NumInts(numBits) * sizeof(int))
+/*
+ * The following statuses overlap with the first 2 generic statuses
+ * defined in status.h:
+ *
+ * SUCCESS There was no error.
+ * FAILURE There was a general error.
+ */
-#define Bit_Alloc(numBits, bitArrayPtr) \
- bitArrayPtr = (int *)malloc((unsigned)Bit_NumBytes(numBits)); \
- Bit_Zero((numBits), (bitArrayPtr))
+#define SUCCESS 0x00000000
+#define FAILURE 0x00000001
-#define Bit_Free(bitArrayPtr) \
- free((char *)bitArrayPtr)
-#define Bit_Set(numBits, bitArrayPtr) \
- ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] |= \
- (1 << ((numBits) % BIT_NUM_BITS_PER_INT)))
+/*
+ * A nil pointer must be something that will cause an exception if
+ * referenced. There are two nils: the kernels nil and the nil used
+ * by user processes.
+ */
-#define Bit_IsSet(numBits, bitArrayPtr) \
- ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] & \
- (1 << ((numBits) % BIT_NUM_BITS_PER_INT)))
+#define NIL ~0
+#define USER_NIL 0
+#ifndef NULL
+#define NULL 0
+#endif NULL
-#define Bit_Clear(numBits, bitArrayPtr) \
- ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] &= \
- ~(1 << ((numBits) % BIT_NUM_BITS_PER_INT)))
+/*
+ * An address is just a pointer in C. It is defined as a character pointer
+ * so that address arithmetic will work properly, a byte at a time.
+ */
-#define Bit_IsClear(numBits, bitArrayPtr) \
- (!(Bit_IsSet((numBits), (bitArrayPtr))))
+typedef char *Address;
-#define Bit_Copy(numBits, srcArrayPtr, destArrayPtr) \
- bcopy((char *)(srcArrayPtr), (char *)(destArrayPtr), \
- Bit_NumBytes(numBits))
+/*
+ * ClientData is an uninterpreted word. It is defined as an int so that
+ * kdbx will not interpret client data as a string. Unlike an "Address",
+ * client data will generally not be used in arithmetic.
+ * But we don't have kdbx anymore so we define it as void (christos)
+ */
-#define Bit_Zero(numBits, bitArrayPtr) \
- bzero((char *)(bitArrayPtr), Bit_NumBytes(numBits))
+typedef void *ClientData;
-extern int Bit_FindFirstSet();
-extern int Bit_FindFirstClear();
-extern Boolean Bit_Intersect();
-extern Boolean Bit_Union();
-extern Boolean Bit_AnySet();
-extern int *Bit_Expand();
-
-#endif /* _BIT */
+#endif /* _SPRITE */
diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c
new file mode 100644
index 0000000..03ea87a
--- /dev/null
+++ b/usr.bin/make/str.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "make.h"
+
+static char **argv, *buffer;
+static int argmax, curlen;
+
+/*
+ * str_init --
+ * Initialize the strings package
+ *
+ */
+void
+str_init()
+{
+ char *p1;
+ argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *));
+ argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1);
+}
+
+
+/*
+ * str_end --
+ * Cleanup the strings package
+ *
+ */
+void
+str_end()
+{
+ if (argv) {
+ if (argv[0])
+ free(argv[0]);
+ free((Address) argv);
+ }
+ if (buffer)
+ free(buffer);
+}
+
+/*-
+ * str_concat --
+ * concatenate the two strings, inserting a space or slash between them,
+ * freeing them if requested.
+ *
+ * returns --
+ * the resulting string in allocated space.
+ */
+char *
+str_concat(s1, s2, flags)
+ char *s1, *s2;
+ int flags;
+{
+ register int len1, len2;
+ register char *result;
+
+ /* get the length of both strings */
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+
+ /* allocate length plus separator plus EOS */
+ result = emalloc((u_int)(len1 + len2 + 2));
+
+ /* copy first string into place */
+ memcpy(result, s1, len1);
+
+ /* add separator character */
+ if (flags & STR_ADDSPACE) {
+ result[len1] = ' ';
+ ++len1;
+ } else if (flags & STR_ADDSLASH) {
+ result[len1] = '/';
+ ++len1;
+ }
+
+ /* copy second string plus EOS into place */
+ memcpy(result + len1, s2, len2 + 1);
+
+ /* free original strings */
+ if (flags & STR_DOFREE) {
+ (void)free(s1);
+ (void)free(s2);
+ }
+ return(result);
+}
+
+/*-
+ * brk_string --
+ * Fracture a string into an array of words (as delineated by tabs or
+ * spaces) taking quotation marks into account. Leading tabs/spaces
+ * are ignored.
+ *
+ * returns --
+ * Pointer to the array of pointers to the words. To make life easier,
+ * the first word is always the value of the .MAKE variable.
+ */
+char **
+brk_string(str, store_argc, expand)
+ register char *str;
+ int *store_argc;
+ Boolean expand;
+{
+ register int argc, ch;
+ register char inquote, *p, *start, *t;
+ int len;
+
+ /* skip leading space chars. */
+ for (; *str == ' ' || *str == '\t'; ++str)
+ continue;
+
+ /* allocate room for a copy of the string */
+ if ((len = strlen(str) + 1) > curlen) {
+ if (buffer)
+ free(buffer);
+ buffer = emalloc(curlen = len);
+ }
+
+ /*
+ * copy the string; at the same time, parse backslashes,
+ * quotes and build the argument list.
+ */
+ argc = 1;
+ inquote = '\0';
+ for (p = str, start = t = buffer;; ++p) {
+ switch(ch = *p) {
+ case '"':
+ case '\'':
+ if (inquote)
+ if (inquote == ch)
+ inquote = '\0';
+ else
+ break;
+ else {
+ inquote = (char) ch;
+ /* Don't miss "" or '' */
+ if (start == NULL && p[1] == inquote) {
+ start = t + 1;
+ break;
+ }
+ }
+ if (!expand) {
+ if (!start)
+ start = t;
+ *t++ = ch;
+ }
+ continue;
+ case ' ':
+ case '\t':
+ case '\n':
+ if (inquote)
+ break;
+ if (!start)
+ continue;
+ /* FALLTHROUGH */
+ case '\0':
+ /*
+ * end of a token -- make sure there's enough argv
+ * space and save off a pointer.
+ */
+ if (!start)
+ goto done;
+
+ *t++ = '\0';
+ if (argc == argmax) {
+ argmax *= 2; /* ramp up fast */
+ argv = (char **)erealloc(argv,
+ (argmax + 1) * sizeof(char *));
+ }
+ argv[argc++] = start;
+ start = (char *)NULL;
+ if (ch == '\n' || ch == '\0')
+ goto done;
+ continue;
+ case '\\':
+ if (!expand) {
+ if (!start)
+ start = t;
+ *t++ = '\\';
+ ch = *++p;
+ break;
+ }
+
+ switch (ch = *++p) {
+ case '\0':
+ case '\n':
+ /* hmmm; fix it up as best we can */
+ ch = '\\';
+ --p;
+ break;
+ case 'b':
+ ch = '\b';
+ break;
+ case 'f':
+ ch = '\f';
+ break;
+ case 'n':
+ ch = '\n';
+ break;
+ case 'r':
+ ch = '\r';
+ break;
+ case 't':
+ ch = '\t';
+ break;
+ }
+ break;
+ }
+ if (!start)
+ start = t;
+ *t++ = (char) ch;
+ }
+done: argv[argc] = (char *)NULL;
+ *store_argc = argc;
+ return(argv);
+}
+
+/*
+ * Str_FindSubstring -- See if a string contains a particular substring.
+ *
+ * Results: If string contains substring, the return value is the location of
+ * the first matching instance of substring in string. If string doesn't
+ * contain substring, the return value is NULL. Matching is done on an exact
+ * character-for-character basis with no wildcards or special characters.
+ *
+ * Side effects: None.
+ */
+char *
+Str_FindSubstring(string, substring)
+ register char *string; /* String to search. */
+ char *substring; /* Substring to find in string */
+{
+ register char *a, *b;
+
+ /*
+ * First scan quickly through the two strings looking for a single-
+ * character match. When it's found, then compare the rest of the
+ * substring.
+ */
+
+ for (b = substring; *string != 0; string += 1) {
+ if (*string != *b)
+ continue;
+ a = string;
+ for (;;) {
+ if (*b == 0)
+ return(string);
+ if (*a++ != *b++)
+ break;
+ }
+ b = substring;
+ }
+ return((char *) NULL);
+}
+
+/*
+ * Str_Match --
+ *
+ * See if a particular string matches a particular pattern.
+ *
+ * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
+ * matching operation permits the following special characters in the
+ * pattern: *?\[] (see the man page for details on what these mean).
+ *
+ * Side effects: None.
+ */
+int
+Str_Match(string, pattern)
+ register char *string; /* String */
+ register char *pattern; /* Pattern */
+{
+ char c2;
+
+ for (;;) {
+ /*
+ * See if we're at the end of both the pattern and the
+ * string. If, we succeeded. If we're at the end of the
+ * pattern but not at the end of the string, we failed.
+ */
+ if (*pattern == 0)
+ return(!*string);
+ if (*string == 0 && *pattern != '*')
+ return(0);
+ /*
+ * Check for a "*" as the next pattern character. It matches
+ * any substring. We handle this by calling ourselves
+ * recursively for each postfix of string, until either we
+ * match or we reach the end of the string.
+ */
+ if (*pattern == '*') {
+ pattern += 1;
+ if (*pattern == 0)
+ return(1);
+ while (*string != 0) {
+ if (Str_Match(string, pattern))
+ return(1);
+ ++string;
+ }
+ return(0);
+ }
+ /*
+ * Check for a "?" as the next pattern character. It matches
+ * any single character.
+ */
+ if (*pattern == '?')
+ goto thisCharOK;
+ /*
+ * Check for a "[" as the next pattern character. It is
+ * followed by a list of characters that are acceptable, or
+ * by a range (two characters separated by "-").
+ */
+ if (*pattern == '[') {
+ ++pattern;
+ for (;;) {
+ if ((*pattern == ']') || (*pattern == 0))
+ return(0);
+ if (*pattern == *string)
+ break;
+ if (pattern[1] == '-') {
+ c2 = pattern[2];
+ if (c2 == 0)
+ return(0);
+ if ((*pattern <= *string) &&
+ (c2 >= *string))
+ break;
+ if ((*pattern >= *string) &&
+ (c2 <= *string))
+ break;
+ pattern += 2;
+ }
+ ++pattern;
+ }
+ while ((*pattern != ']') && (*pattern != 0))
+ ++pattern;
+ goto thisCharOK;
+ }
+ /*
+ * If the next pattern character is '/', just strip off the
+ * '/' so we do exact matching on the character that follows.
+ */
+ if (*pattern == '\\') {
+ ++pattern;
+ if (*pattern == 0)
+ return(0);
+ }
+ /*
+ * There's no special character. Just make sure that the
+ * next characters of each string match.
+ */
+ if (*pattern != *string)
+ return(0);
+thisCharOK: ++pattern;
+ ++string;
+ }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Str_SYSVMatch --
+ * Check word against pattern for a match (% is wild),
+ *
+ * Results:
+ * Returns the beginning position of a match or null. The number
+ * of characters matched is returned in len.
+ *
+ * Side Effects:
+ * None
+ *
+ *-----------------------------------------------------------------------
+ */
+char *
+Str_SYSVMatch(word, pattern, len)
+ char *word; /* Word to examine */
+ char *pattern; /* Pattern to examine against */
+ int *len; /* Number of characters to substitute */
+{
+ char *p = pattern;
+ char *w = word;
+ char *m;
+
+ if (*p == '\0') {
+ /* Null pattern is the whole string */
+ *len = strlen(w);
+ return w;
+ }
+
+ if ((m = strchr(p, '%')) != NULL) {
+ /* check that the prefix matches */
+ for (; p != m && *w && *w == *p; w++, p++)
+ continue;
+
+ if (p != m)
+ return NULL; /* No match */
+
+ if (*++p == '\0') {
+ /* No more pattern, return the rest of the string */
+ *len = strlen(w);
+ return w;
+ }
+ }
+
+ m = w;
+
+ /* Find a matching tail */
+ do
+ if (strcmp(p, w) == 0) {
+ *len = w - m;
+ return m;
+ }
+ while (*w++ != '\0');
+
+ return NULL;
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Str_SYSVSubst --
+ * Substitute '%' on the pattern with len characters from src.
+ * If the pattern does not contain a '%' prepend len characters
+ * from src.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Places result on buf
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Str_SYSVSubst(buf, pat, src, len)
+ Buffer buf;
+ char *pat;
+ char *src;
+ int len;
+{
+ char *m;
+
+ if ((m = strchr(pat, '%')) != NULL) {
+ /* Copy the prefix */
+ Buf_AddBytes(buf, m - pat, (Byte *) pat);
+ /* skip the % */
+ pat = m + 1;
+ }
+
+ /* Copy the pattern */
+ Buf_AddBytes(buf, len, (Byte *) src);
+
+ /* append the rest */
+ Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
+}
diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c
new file mode 100644
index 0000000..5d3cf9a
--- /dev/null
+++ b/usr.bin/make/suff.c
@@ -0,0 +1,2449 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
+#endif /* not lint */
+
+/*-
+ * suff.c --
+ * Functions to maintain suffix lists and find implicit dependents
+ * using suffix transformation rules
+ *
+ * Interface:
+ * Suff_Init Initialize all things to do with suffixes.
+ *
+ * Suff_End Cleanup the module
+ *
+ * Suff_DoPaths This function is used to make life easier
+ * when searching for a file according to its
+ * suffix. It takes the global search path,
+ * as defined using the .PATH: target, and appends
+ * its directories to the path of each of the
+ * defined suffixes, as specified using
+ * .PATH<suffix>: targets. In addition, all
+ * directories given for suffixes labeled as
+ * include files or libraries, using the .INCLUDES
+ * or .LIBS targets, are played with using
+ * Dir_MakeFlags to create the .INCLUDES and
+ * .LIBS global variables.
+ *
+ * Suff_ClearSuffixes Clear out all the suffixes and defined
+ * transformations.
+ *
+ * Suff_IsTransform Return TRUE if the passed string is the lhs
+ * of a transformation rule.
+ *
+ * Suff_AddSuffix Add the passed string as another known suffix.
+ *
+ * Suff_GetPath Return the search path for the given suffix.
+ *
+ * Suff_AddInclude Mark the given suffix as denoting an include
+ * file.
+ *
+ * Suff_AddLib Mark the given suffix as denoting a library.
+ *
+ * Suff_AddTransform Add another transformation to the suffix
+ * graph. Returns GNode suitable for framing, I
+ * mean, tacking commands, attributes, etc. on.
+ *
+ * Suff_SetNull Define the suffix to consider the suffix of
+ * any file that doesn't have a known one.
+ *
+ * Suff_FindDeps Find implicit sources for and the location of
+ * a target based on its suffix. Returns the
+ * bottom-most node added to the graph or NILGNODE
+ * if the target had no implicit sources.
+ */
+
+#include <stdio.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+
+static Lst sufflist; /* Lst of suffixes */
+static Lst suffClean; /* Lst of suffixes to be cleaned */
+static Lst srclist; /* Lst of sources */
+static Lst transforms; /* Lst of transformation rules */
+
+static int sNum = 0; /* Counter for assigning suffix numbers */
+
+/*
+ * Structure describing an individual suffix.
+ */
+typedef struct _Suff {
+ char *name; /* The suffix itself */
+ int nameLen; /* Length of the suffix */
+ short flags; /* Type of suffix */
+#define SUFF_INCLUDE 0x01 /* One which is #include'd */
+#define SUFF_LIBRARY 0x02 /* One which contains a library */
+#define SUFF_NULL 0x04 /* The empty suffix */
+ Lst searchPath; /* The path along which files of this suffix
+ * may be found */
+ int sNum; /* The suffix number */
+ int refCount; /* Reference count of list membership */
+ Lst parents; /* Suffixes we have a transformation to */
+ Lst children; /* Suffixes we have a transformation from */
+ Lst ref; /* List of lists this suffix is referenced */
+} Suff;
+
+/*
+ * Structure used in the search for implied sources.
+ */
+typedef struct _Src {
+ char *file; /* The file to look for */
+ char *pref; /* Prefix from which file was formed */
+ Suff *suff; /* The suffix on the file */
+ struct _Src *parent; /* The Src for which this is a source */
+ GNode *node; /* The node describing the file */
+ int children; /* Count of existing children (so we don't free
+ * this thing too early or never nuke it) */
+#ifdef DEBUG_SRC
+ Lst cp; /* Debug; children list */
+#endif
+} Src;
+
+/*
+ * A structure for passing more than one argument to the Lst-library-invoked
+ * function...
+ */
+typedef struct {
+ Lst l;
+ Src *s;
+} LstSrc;
+
+static Suff *suffNull; /* The NULL suffix for this run */
+static Suff *emptySuff; /* The empty suffix required for POSIX
+ * single-suffix transformation rules */
+
+
+static char *SuffStrIsPrefix __P((char *, char *));
+static char *SuffSuffIsSuffix __P((Suff *, char *));
+static int SuffSuffIsSuffixP __P((ClientData, ClientData));
+static int SuffSuffHasNameP __P((ClientData, ClientData));
+static int SuffSuffIsPrefix __P((ClientData, ClientData));
+static int SuffGNHasNameP __P((ClientData, ClientData));
+static void SuffUnRef __P((ClientData, ClientData));
+static void SuffFree __P((ClientData));
+static void SuffInsert __P((Lst, Suff *));
+static void SuffRemove __P((Lst, Suff *));
+static Boolean SuffParseTransform __P((char *, Suff **, Suff **));
+static int SuffRebuildGraph __P((ClientData, ClientData));
+static int SuffAddSrc __P((ClientData, ClientData));
+static int SuffRemoveSrc __P((Lst));
+static void SuffAddLevel __P((Lst, Src *));
+static Src *SuffFindThem __P((Lst, Lst));
+static Src *SuffFindCmds __P((Src *, Lst));
+static int SuffExpandChildren __P((ClientData, ClientData));
+static Boolean SuffApplyTransform __P((GNode *, GNode *, Suff *, Suff *));
+static void SuffFindDeps __P((GNode *, Lst));
+static void SuffFindArchiveDeps __P((GNode *, Lst));
+static void SuffFindNormalDeps __P((GNode *, Lst));
+static int SuffPrintName __P((ClientData, ClientData));
+static int SuffPrintSuff __P((ClientData, ClientData));
+static int SuffPrintTrans __P((ClientData, ClientData));
+
+ /*************** Lst Predicates ****************/
+/*-
+ *-----------------------------------------------------------------------
+ * SuffStrIsPrefix --
+ * See if pref is a prefix of str.
+ *
+ * Results:
+ * NULL if it ain't, pointer to character in str after prefix if so
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static char *
+SuffStrIsPrefix (pref, str)
+ register char *pref; /* possible prefix */
+ register char *str; /* string to check */
+{
+ while (*str && *pref == *str) {
+ pref++;
+ str++;
+ }
+
+ return (*pref ? NULL : str);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffSuffIsSuffix --
+ * See if suff is a suffix of str. Str should point to THE END of the
+ * string to check. (THE END == the null byte)
+ *
+ * Results:
+ * NULL if it ain't, pointer to character in str before suffix if
+ * it is.
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static char *
+SuffSuffIsSuffix (s, str)
+ register Suff *s; /* possible suffix */
+ char *str; /* string to examine */
+{
+ register char *p1; /* Pointer into suffix name */
+ register char *p2; /* Pointer into string being examined */
+
+ p1 = s->name + s->nameLen;
+ p2 = str;
+
+ while (p1 >= s->name && *p1 == *p2) {
+ p1--;
+ p2--;
+ }
+
+ return (p1 == s->name - 1 ? p2 : NULL);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffSuffIsSuffixP --
+ * Predicate form of SuffSuffIsSuffix. Passed as the callback function
+ * to Lst_Find.
+ *
+ * Results:
+ * 0 if the suffix is the one desired, non-zero if not.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffSuffIsSuffixP(s, str)
+ ClientData s;
+ ClientData str;
+{
+ return(!SuffSuffIsSuffix((Suff *) s, (char *) str));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffSuffHasNameP --
+ * Callback procedure for finding a suffix based on its name. Used by
+ * Suff_GetPath.
+ *
+ * Results:
+ * 0 if the suffix is of the given name. non-zero otherwise.
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffSuffHasNameP (s, sname)
+ ClientData s; /* Suffix to check */
+ ClientData sname; /* Desired name */
+{
+ return (strcmp ((char *) sname, ((Suff *) s)->name));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffSuffIsPrefix --
+ * See if the suffix described by s is a prefix of the string. Care
+ * must be taken when using this to search for transformations and
+ * what-not, since there could well be two suffixes, one of which
+ * is a prefix of the other...
+ *
+ * Results:
+ * 0 if s is a prefix of str. non-zero otherwise
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffSuffIsPrefix (s, str)
+ ClientData s; /* suffix to compare */
+ ClientData str; /* string to examine */
+{
+ return (SuffStrIsPrefix (((Suff *) s)->name, (char *) str) == NULL ? 1 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffGNHasNameP --
+ * See if the graph node has the desired name
+ *
+ * Results:
+ * 0 if it does. non-zero if it doesn't
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffGNHasNameP (gn, name)
+ ClientData gn; /* current node we're looking at */
+ ClientData name; /* name we're looking for */
+{
+ return (strcmp ((char *) name, ((GNode *) gn)->name));
+}
+
+ /*********** Maintenance Functions ************/
+
+static void
+SuffUnRef(lp, sp)
+ ClientData lp;
+ ClientData sp;
+{
+ Lst l = (Lst) lp;
+
+ LstNode ln = Lst_Member(l, sp);
+ if (ln != NILLNODE) {
+ Lst_Remove(l, ln);
+ ((Suff *) sp)->refCount--;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffFree --
+ * Free up all memory associated with the given suffix structure.
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * the suffix entry is detroyed
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffFree (sp)
+ ClientData sp;
+{
+ Suff *s = (Suff *) sp;
+
+ if (s == suffNull)
+ suffNull = NULL;
+
+ if (s == emptySuff)
+ emptySuff = NULL;
+
+ Lst_Destroy (s->ref, NOFREE);
+ Lst_Destroy (s->children, NOFREE);
+ Lst_Destroy (s->parents, NOFREE);
+ Lst_Destroy (s->searchPath, Dir_Destroy);
+
+ free ((Address)s->name);
+ free ((Address)s);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffRemove --
+ * Remove the suffix into the list
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The reference count for the suffix is decremented and the
+ * suffix is possibly freed
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffRemove(l, s)
+ Lst l;
+ Suff *s;
+{
+ SuffUnRef((ClientData) l, (ClientData) s);
+ if (s->refCount == 0)
+ SuffFree((ClientData) s);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffInsert --
+ * Insert the suffix into the list keeping the list ordered by suffix
+ * numbers.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The reference count of the suffix is incremented
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffInsert (l, s)
+ Lst l; /* the list where in s should be inserted */
+ Suff *s; /* the suffix to insert */
+{
+ LstNode ln; /* current element in l we're examining */
+ Suff *s2 = NULL; /* the suffix descriptor in this element */
+
+ if (Lst_Open (l) == FAILURE) {
+ return;
+ }
+ while ((ln = Lst_Next (l)) != NILLNODE) {
+ s2 = (Suff *) Lst_Datum (ln);
+ if (s2->sNum >= s->sNum) {
+ break;
+ }
+ }
+
+ Lst_Close (l);
+ if (DEBUG(SUFF)) {
+ printf("inserting %s(%d)...", s->name, s->sNum);
+ }
+ if (ln == NILLNODE) {
+ if (DEBUG(SUFF)) {
+ printf("at end of list\n");
+ }
+ (void)Lst_AtEnd (l, (ClientData)s);
+ s->refCount++;
+ (void)Lst_AtEnd(s->ref, (ClientData) l);
+ } else if (s2->sNum != s->sNum) {
+ if (DEBUG(SUFF)) {
+ printf("before %s(%d)\n", s2->name, s2->sNum);
+ }
+ (void)Lst_Insert (l, ln, (ClientData)s);
+ s->refCount++;
+ (void)Lst_AtEnd(s->ref, (ClientData) l);
+ } else if (DEBUG(SUFF)) {
+ printf("already there\n");
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_ClearSuffixes --
+ * This is gross. Nuke the list of suffixes but keep all transformation
+ * rules around. The transformation graph is destroyed in this process,
+ * but we leave the list of rules so when a new graph is formed the rules
+ * will remain.
+ * This function is called from the parse module when a
+ * .SUFFIXES:\n line is encountered.
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * the sufflist and its graph nodes are destroyed
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_ClearSuffixes ()
+{
+ Lst_Concat (suffClean, sufflist, LST_CONCLINK);
+ sufflist = Lst_Init(FALSE);
+ sNum = 0;
+ suffNull = emptySuff;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffParseTransform --
+ * Parse a transformation string to find its two component suffixes.
+ *
+ * Results:
+ * TRUE if the string is a valid transformation and FALSE otherwise.
+ *
+ * Side Effects:
+ * The passed pointers are overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+SuffParseTransform(str, srcPtr, targPtr)
+ char *str; /* String being parsed */
+ Suff **srcPtr; /* Place to store source of trans. */
+ Suff **targPtr; /* Place to store target of trans. */
+{
+ register LstNode srcLn; /* element in suffix list of trans source*/
+ register Suff *src; /* Source of transformation */
+ register LstNode targLn; /* element in suffix list of trans target*/
+ register char *str2; /* Extra pointer (maybe target suffix) */
+ LstNode singleLn; /* element in suffix list of any suffix
+ * that exactly matches str */
+ Suff *single = NULL;/* Source of possible transformation to
+ * null suffix */
+
+ srcLn = NILLNODE;
+ singleLn = NILLNODE;
+
+ /*
+ * Loop looking first for a suffix that matches the start of the
+ * string and then for one that exactly matches the rest of it. If
+ * we can find two that meet these criteria, we've successfully
+ * parsed the string.
+ */
+ for (;;) {
+ if (srcLn == NILLNODE) {
+ srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix);
+ } else {
+ srcLn = Lst_FindFrom (sufflist, Lst_Succ(srcLn), (ClientData)str,
+ SuffSuffIsPrefix);
+ }
+ if (srcLn == NILLNODE) {
+ /*
+ * Ran out of source suffixes -- no such rule
+ */
+ if (singleLn != NILLNODE) {
+ /*
+ * Not so fast Mr. Smith! There was a suffix that encompassed
+ * the entire string, so we assume it was a transformation
+ * to the null suffix (thank you POSIX). We still prefer to
+ * find a double rule over a singleton, hence we leave this
+ * check until the end.
+ *
+ * XXX: Use emptySuff over suffNull?
+ */
+ *srcPtr = single;
+ *targPtr = suffNull;
+ return(TRUE);
+ }
+ return (FALSE);
+ }
+ src = (Suff *) Lst_Datum (srcLn);
+ str2 = str + src->nameLen;
+ if (*str2 == '\0') {
+ single = src;
+ singleLn = srcLn;
+ } else {
+ targLn = Lst_Find(sufflist, (ClientData)str2, SuffSuffHasNameP);
+ if (targLn != NILLNODE) {
+ *srcPtr = src;
+ *targPtr = (Suff *)Lst_Datum(targLn);
+ return (TRUE);
+ }
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_IsTransform --
+ * Return TRUE if the given string is a transformation rule
+ *
+ *
+ * Results:
+ * TRUE if the string is a concatenation of two known suffixes.
+ * FALSE otherwise
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Suff_IsTransform (str)
+ char *str; /* string to check */
+{
+ Suff *src, *targ;
+
+ return (SuffParseTransform(str, &src, &targ));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_AddTransform --
+ * Add the transformation rule described by the line to the
+ * list of rules and place the transformation itself in the graph
+ *
+ * Results:
+ * The node created for the transformation in the transforms list
+ *
+ * Side Effects:
+ * The node is placed on the end of the transforms Lst and links are
+ * made between the two suffixes mentioned in the target name
+ *-----------------------------------------------------------------------
+ */
+GNode *
+Suff_AddTransform (line)
+ char *line; /* name of transformation to add */
+{
+ GNode *gn; /* GNode of transformation rule */
+ Suff *s, /* source suffix */
+ *t; /* target suffix */
+ LstNode ln; /* Node for existing transformation */
+
+ ln = Lst_Find (transforms, (ClientData)line, SuffGNHasNameP);
+ if (ln == NILLNODE) {
+ /*
+ * Make a new graph node for the transformation. It will be filled in
+ * by the Parse module.
+ */
+ gn = Targ_NewGN (line);
+ (void)Lst_AtEnd (transforms, (ClientData)gn);
+ } else {
+ /*
+ * New specification for transformation rule. Just nuke the old list
+ * of commands so they can be filled in again... We don't actually
+ * free the commands themselves, because a given command can be
+ * attached to several different transformations.
+ */
+ gn = (GNode *) Lst_Datum (ln);
+ Lst_Destroy (gn->commands, NOFREE);
+ Lst_Destroy (gn->children, NOFREE);
+ gn->commands = Lst_Init (FALSE);
+ gn->children = Lst_Init (FALSE);
+ }
+
+ gn->type = OP_TRANSFORM;
+
+ (void)SuffParseTransform(line, &s, &t);
+
+ /*
+ * link the two together in the proper relationship and order
+ */
+ if (DEBUG(SUFF)) {
+ printf("defining transformation from `%s' to `%s'\n",
+ s->name, t->name);
+ }
+ SuffInsert (t->children, s);
+ SuffInsert (s->parents, t);
+
+ return (gn);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_EndTransform --
+ * Handle the finish of a transformation definition, removing the
+ * transformation from the graph if it has neither commands nor
+ * sources. This is a callback procedure for the Parse module via
+ * Lst_ForEach
+ *
+ * Results:
+ * === 0
+ *
+ * Side Effects:
+ * If the node has no commands or children, the children and parents
+ * lists of the affected suffices are altered.
+ *
+ *-----------------------------------------------------------------------
+ */
+int
+Suff_EndTransform(gnp, dummy)
+ ClientData gnp; /* Node for transformation */
+ ClientData dummy; /* Node for transformation */
+{
+ GNode *gn = (GNode *) gnp;
+
+ if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) &&
+ Lst_IsEmpty(gn->children))
+ {
+ Suff *s, *t;
+
+ (void)SuffParseTransform(gn->name, &s, &t);
+
+ if (DEBUG(SUFF)) {
+ printf("deleting transformation from %s to %s\n",
+ s->name, t->name);
+ }
+
+ /*
+ * Remove the source from the target's children list. We check for a
+ * nil return to handle a beanhead saying something like
+ * .c.o .c.o:
+ *
+ * We'll be called twice when the next target is seen, but .c and .o
+ * are only linked once...
+ */
+ SuffRemove(t->children, s);
+
+ /*
+ * Remove the target from the source's parents list
+ */
+ SuffRemove(s->parents, t);
+ } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) {
+ printf("transformation %s complete\n", gn->name);
+ }
+
+ return(dummy ? 0 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffRebuildGraph --
+ * Called from Suff_AddSuffix via Lst_ForEach to search through the
+ * list of existing transformation rules and rebuild the transformation
+ * graph when it has been destroyed by Suff_ClearSuffixes. If the
+ * given rule is a transformation involving this suffix and another,
+ * existing suffix, the proper relationship is established between
+ * the two.
+ *
+ * Results:
+ * Always 0.
+ *
+ * Side Effects:
+ * The appropriate links will be made between this suffix and
+ * others if transformation rules exist for it.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffRebuildGraph(transformp, sp)
+ ClientData transformp; /* Transformation to test */
+ ClientData sp; /* Suffix to rebuild */
+{
+ GNode *transform = (GNode *) transformp;
+ Suff *s = (Suff *) sp;
+ char *cp;
+ LstNode ln;
+ Suff *s2;
+
+ /*
+ * First see if it is a transformation from this suffix.
+ */
+ cp = SuffStrIsPrefix(s->name, transform->name);
+ if (cp != (char *)NULL) {
+ ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP);
+ if (ln != NILLNODE) {
+ /*
+ * Found target. Link in and return, since it can't be anything
+ * else.
+ */
+ s2 = (Suff *)Lst_Datum(ln);
+ SuffInsert(s2->children, s);
+ SuffInsert(s->parents, s2);
+ return(0);
+ }
+ }
+
+ /*
+ * Not from, maybe to?
+ */
+ cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name));
+ if (cp != (char *)NULL) {
+ /*
+ * Null-terminate the source suffix in order to find it.
+ */
+ cp[1] = '\0';
+ ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP);
+ /*
+ * Replace the start of the target suffix
+ */
+ cp[1] = s->name[0];
+ if (ln != NILLNODE) {
+ /*
+ * Found it -- establish the proper relationship
+ */
+ s2 = (Suff *)Lst_Datum(ln);
+ SuffInsert(s->children, s2);
+ SuffInsert(s2->parents, s);
+ }
+ }
+ return(0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_AddSuffix --
+ * Add the suffix in string to the end of the list of known suffixes.
+ * Should we restructure the suffix graph? Make doesn't...
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * A GNode is created for the suffix and a Suff structure is created and
+ * added to the suffixes list unless the suffix was already known.
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_AddSuffix (str)
+ char *str; /* the name of the suffix to add */
+{
+ Suff *s; /* new suffix descriptor */
+ LstNode ln;
+
+ ln = Lst_Find (sufflist, (ClientData)str, SuffSuffHasNameP);
+ if (ln == NILLNODE) {
+ s = (Suff *) emalloc (sizeof (Suff));
+
+ s->name = estrdup (str);
+ s->nameLen = strlen (s->name);
+ s->searchPath = Lst_Init (FALSE);
+ s->children = Lst_Init (FALSE);
+ s->parents = Lst_Init (FALSE);
+ s->ref = Lst_Init (FALSE);
+ s->sNum = sNum++;
+ s->flags = 0;
+ s->refCount = 0;
+
+ (void)Lst_AtEnd (sufflist, (ClientData)s);
+ /*
+ * Look for any existing transformations from or to this suffix.
+ * XXX: Only do this after a Suff_ClearSuffixes?
+ */
+ Lst_ForEach (transforms, SuffRebuildGraph, (ClientData)s);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_GetPath --
+ * Return the search path for the given suffix, if it's defined.
+ *
+ * Results:
+ * The searchPath for the desired suffix or NILLST if the suffix isn't
+ * defined.
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+Lst
+Suff_GetPath (sname)
+ char *sname;
+{
+ LstNode ln;
+ Suff *s;
+
+ ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
+ if (ln == NILLNODE) {
+ return (NILLST);
+ } else {
+ s = (Suff *) Lst_Datum (ln);
+ return (s->searchPath);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_DoPaths --
+ * Extend the search paths for all suffixes to include the default
+ * search path.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The searchPath field of all the suffixes is extended by the
+ * directories in dirSearchPath. If paths were specified for the
+ * ".h" suffix, the directories are stuffed into a global variable
+ * called ".INCLUDES" with each directory preceeded by a -I. The same
+ * is done for the ".a" suffix, except the variable is called
+ * ".LIBS" and the flag is -L.
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_DoPaths()
+{
+ register Suff *s;
+ register LstNode ln;
+ char *ptr;
+ Lst inIncludes; /* Cumulative .INCLUDES path */
+ Lst inLibs; /* Cumulative .LIBS path */
+
+ if (Lst_Open (sufflist) == FAILURE) {
+ return;
+ }
+
+ inIncludes = Lst_Init(FALSE);
+ inLibs = Lst_Init(FALSE);
+
+ while ((ln = Lst_Next (sufflist)) != NILLNODE) {
+ s = (Suff *) Lst_Datum (ln);
+ if (!Lst_IsEmpty (s->searchPath)) {
+#ifdef INCLUDES
+ if (s->flags & SUFF_INCLUDE) {
+ Dir_Concat(inIncludes, s->searchPath);
+ }
+#endif /* INCLUDES */
+#ifdef LIBRARIES
+ if (s->flags & SUFF_LIBRARY) {
+ Dir_Concat(inLibs, s->searchPath);
+ }
+#endif /* LIBRARIES */
+ Dir_Concat(s->searchPath, dirSearchPath);
+ } else {
+ Lst_Destroy (s->searchPath, Dir_Destroy);
+ s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir);
+ }
+ }
+
+ Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL);
+ free(ptr);
+ Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL);
+ free(ptr);
+
+ Lst_Destroy(inIncludes, Dir_Destroy);
+ Lst_Destroy(inLibs, Dir_Destroy);
+
+ Lst_Close (sufflist);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_AddInclude --
+ * Add the given suffix as a type of file which gets included.
+ * Called from the parse module when a .INCLUDES line is parsed.
+ * The suffix must have already been defined.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The SUFF_INCLUDE bit is set in the suffix's flags field
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_AddInclude (sname)
+ char *sname; /* Name of suffix to mark */
+{
+ LstNode ln;
+ Suff *s;
+
+ ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
+ if (ln != NILLNODE) {
+ s = (Suff *) Lst_Datum (ln);
+ s->flags |= SUFF_INCLUDE;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_AddLib --
+ * Add the given suffix as a type of file which is a library.
+ * Called from the parse module when parsing a .LIBS line. The
+ * suffix must have been defined via .SUFFIXES before this is
+ * called.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The SUFF_LIBRARY bit is set in the suffix's flags field
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_AddLib (sname)
+ char *sname; /* Name of suffix to mark */
+{
+ LstNode ln;
+ Suff *s;
+
+ ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
+ if (ln != NILLNODE) {
+ s = (Suff *) Lst_Datum (ln);
+ s->flags |= SUFF_LIBRARY;
+ }
+}
+
+ /********** Implicit Source Search Functions *********/
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffAddSrc --
+ * Add a suffix as a Src structure to the given list with its parent
+ * being the given Src structure. If the suffix is the null suffix,
+ * the prefix is used unaltered as the file name in the Src structure.
+ *
+ * Results:
+ * always returns 0
+ *
+ * Side Effects:
+ * A Src structure is created and tacked onto the end of the list
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffAddSrc (sp, lsp)
+ ClientData sp; /* suffix for which to create a Src structure */
+ ClientData lsp; /* list and parent for the new Src */
+{
+ Suff *s = (Suff *) sp;
+ LstSrc *ls = (LstSrc *) lsp;
+ Src *s2; /* new Src structure */
+ Src *targ; /* Target structure */
+
+ targ = ls->s;
+
+ if ((s->flags & SUFF_NULL) && (*s->name != '\0')) {
+ /*
+ * If the suffix has been marked as the NULL suffix, also create a Src
+ * structure for a file with no suffix attached. Two birds, and all
+ * that...
+ */
+ s2 = (Src *) emalloc (sizeof (Src));
+ s2->file = estrdup(targ->pref);
+ s2->pref = targ->pref;
+ s2->parent = targ;
+ s2->node = NILGNODE;
+ s2->suff = s;
+ s->refCount++;
+ s2->children = 0;
+ targ->children += 1;
+ (void)Lst_AtEnd (ls->l, (ClientData)s2);
+#ifdef DEBUG_SRC
+ s2->cp = Lst_Init(FALSE);
+ Lst_AtEnd(targ->cp, (ClientData) s2);
+ printf("1 add %x %x to %x:", targ, s2, ls->l);
+ Lst_ForEach(ls->l, PrintAddr, (ClientData) 0);
+ printf("\n");
+#endif
+ }
+ s2 = (Src *) emalloc (sizeof (Src));
+ s2->file = str_concat (targ->pref, s->name, 0);
+ s2->pref = targ->pref;
+ s2->parent = targ;
+ s2->node = NILGNODE;
+ s2->suff = s;
+ s->refCount++;
+ s2->children = 0;
+ targ->children += 1;
+ (void)Lst_AtEnd (ls->l, (ClientData)s2);
+#ifdef DEBUG_SRC
+ s2->cp = Lst_Init(FALSE);
+ Lst_AtEnd(targ->cp, (ClientData) s2);
+ printf("2 add %x %x to %x:", targ, s2, ls->l);
+ Lst_ForEach(ls->l, PrintAddr, (ClientData) 0);
+ printf("\n");
+#endif
+
+ return(0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffAddLevel --
+ * Add all the children of targ as Src structures to the given list
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Lots of structures are created and added to the list
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffAddLevel (l, targ)
+ Lst l; /* list to which to add the new level */
+ Src *targ; /* Src structure to use as the parent */
+{
+ LstSrc ls;
+
+ ls.s = targ;
+ ls.l = l;
+
+ Lst_ForEach (targ->suff->children, SuffAddSrc, (ClientData)&ls);
+}
+
+/*-
+ *----------------------------------------------------------------------
+ * SuffRemoveSrc --
+ * Free all src structures in list that don't have a reference count
+ *
+ * Results:
+ * Ture if an src was removed
+ *
+ * Side Effects:
+ * The memory is free'd.
+ *----------------------------------------------------------------------
+ */
+static int
+SuffRemoveSrc (l)
+ Lst l;
+{
+ LstNode ln;
+ Src *s;
+ int t = 0;
+
+ if (Lst_Open (l) == FAILURE) {
+ return 0;
+ }
+#ifdef DEBUG_SRC
+ printf("cleaning %lx: ", (unsigned long) l);
+ Lst_ForEach(l, PrintAddr, (ClientData) 0);
+ printf("\n");
+#endif
+
+
+ while ((ln = Lst_Next (l)) != NILLNODE) {
+ s = (Src *) Lst_Datum (ln);
+ if (s->children == 0) {
+ free ((Address)s->file);
+ if (!s->parent)
+ free((Address)s->pref);
+ else {
+#ifdef DEBUG_SRC
+ LstNode ln = Lst_Member(s->parent->cp, (ClientData)s);
+ if (ln != NILLNODE)
+ Lst_Remove(s->parent->cp, ln);
+#endif
+ --s->parent->children;
+ }
+#ifdef DEBUG_SRC
+ printf("free: [l=%x] p=%x %d\n", l, s, s->children);
+ Lst_Destroy(s->cp, NOFREE);
+#endif
+ Lst_Remove(l, ln);
+ free ((Address)s);
+ t |= 1;
+ Lst_Close(l);
+ return TRUE;
+ }
+#ifdef DEBUG_SRC
+ else {
+ printf("keep: [l=%x] p=%x %d: ", l, s, s->children);
+ Lst_ForEach(s->cp, PrintAddr, (ClientData) 0);
+ printf("\n");
+ }
+#endif
+ }
+
+ Lst_Close(l);
+
+ return t;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffFindThem --
+ * Find the first existing file/target in the list srcs
+ *
+ * Results:
+ * The lowest structure in the chain of transformations
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static Src *
+SuffFindThem (srcs, slst)
+ Lst srcs; /* list of Src structures to search through */
+ Lst slst;
+{
+ Src *s; /* current Src */
+ Src *rs; /* returned Src */
+ char *ptr;
+
+ rs = (Src *) NULL;
+
+ while (!Lst_IsEmpty (srcs)) {
+ s = (Src *) Lst_DeQueue (srcs);
+
+ if (DEBUG(SUFF)) {
+ printf ("\ttrying %s...", s->file);
+ }
+
+ /*
+ * A file is considered to exist if either a node exists in the
+ * graph for it or the file actually exists.
+ */
+ if (Targ_FindNode(s->file, TARG_NOCREATE) != NILGNODE) {
+#ifdef DEBUG_SRC
+ printf("remove %x from %x\n", s, srcs);
+#endif
+ rs = s;
+ break;
+ }
+
+ if ((ptr = Dir_FindFile (s->file, s->suff->searchPath)) != NULL) {
+ rs = s;
+#ifdef DEBUG_SRC
+ printf("remove %x from %x\n", s, srcs);
+#endif
+ free(ptr);
+ break;
+ }
+
+ if (DEBUG(SUFF)) {
+ printf ("not there\n");
+ }
+
+ SuffAddLevel (srcs, s);
+ Lst_AtEnd(slst, (ClientData) s);
+ }
+
+ if (DEBUG(SUFF) && rs) {
+ printf ("got it\n");
+ }
+ return (rs);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffFindCmds --
+ * See if any of the children of the target in the Src structure is
+ * one from which the target can be transformed. If there is one,
+ * a Src structure is put together for it and returned.
+ *
+ * Results:
+ * The Src structure of the "winning" child, or NIL if no such beast.
+ *
+ * Side Effects:
+ * A Src structure may be allocated.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Src *
+SuffFindCmds (targ, slst)
+ Src *targ; /* Src structure to play with */
+ Lst slst;
+{
+ LstNode ln; /* General-purpose list node */
+ register GNode *t, /* Target GNode */
+ *s; /* Source GNode */
+ int prefLen;/* The length of the defined prefix */
+ Suff *suff; /* Suffix on matching beastie */
+ Src *ret; /* Return value */
+ char *cp;
+
+ t = targ->node;
+ (void) Lst_Open (t->children);
+ prefLen = strlen (targ->pref);
+
+ while ((ln = Lst_Next (t->children)) != NILLNODE) {
+ s = (GNode *)Lst_Datum (ln);
+
+ cp = strrchr (s->name, '/');
+ if (cp == (char *)NULL) {
+ cp = s->name;
+ } else {
+ cp++;
+ }
+ if (strncmp (cp, targ->pref, prefLen) == 0) {
+ /*
+ * The node matches the prefix ok, see if it has a known
+ * suffix.
+ */
+ ln = Lst_Find (sufflist, (ClientData)&cp[prefLen],
+ SuffSuffHasNameP);
+ if (ln != NILLNODE) {
+ /*
+ * It even has a known suffix, see if there's a transformation
+ * defined between the node's suffix and the target's suffix.
+ *
+ * XXX: Handle multi-stage transformations here, too.
+ */
+ suff = (Suff *)Lst_Datum (ln);
+
+ if (Lst_Member (suff->parents,
+ (ClientData)targ->suff) != NILLNODE)
+ {
+ /*
+ * Hot Damn! Create a new Src structure to describe
+ * this transformation (making sure to duplicate the
+ * source node's name so Suff_FindDeps can free it
+ * again (ick)), and return the new structure.
+ */
+ ret = (Src *)emalloc (sizeof (Src));
+ ret->file = estrdup(s->name);
+ ret->pref = targ->pref;
+ ret->suff = suff;
+ suff->refCount++;
+ ret->parent = targ;
+ ret->node = s;
+ ret->children = 0;
+ targ->children += 1;
+#ifdef DEBUG_SRC
+ ret->cp = Lst_Init(FALSE);
+ printf("3 add %x %x\n", targ, ret);
+ Lst_AtEnd(targ->cp, (ClientData) ret);
+#endif
+ Lst_AtEnd(slst, (ClientData) ret);
+ if (DEBUG(SUFF)) {
+ printf ("\tusing existing source %s\n", s->name);
+ }
+ return (ret);
+ }
+ }
+ }
+ }
+ Lst_Close (t->children);
+ return ((Src *)NULL);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffExpandChildren --
+ * Expand the names of any children of a given node that contain
+ * variable invocations or file wildcards into actual targets.
+ *
+ * Results:
+ * === 0 (continue)
+ *
+ * Side Effects:
+ * The expanded node is removed from the parent's list of children,
+ * and the parent's unmade counter is decremented, but other nodes
+ * may be added.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+SuffExpandChildren(cgnp, pgnp)
+ ClientData cgnp; /* Child to examine */
+ ClientData pgnp; /* Parent node being processed */
+{
+ GNode *cgn = (GNode *) cgnp;
+ GNode *pgn = (GNode *) pgnp;
+ GNode *gn; /* New source 8) */
+ LstNode prevLN; /* Node after which new source should be put */
+ LstNode ln; /* List element for old source */
+ char *cp; /* Expanded value */
+
+ /*
+ * New nodes effectively take the place of the child, so place them
+ * after the child
+ */
+ prevLN = Lst_Member(pgn->children, (ClientData)cgn);
+
+ /*
+ * First do variable expansion -- this takes precedence over
+ * wildcard expansion. If the result contains wildcards, they'll be gotten
+ * to later since the resulting words are tacked on to the end of
+ * the children list.
+ */
+ if (strchr(cgn->name, '$') != (char *)NULL) {
+ if (DEBUG(SUFF)) {
+ printf("Expanding \"%s\"...", cgn->name);
+ }
+ cp = Var_Subst(NULL, cgn->name, pgn, TRUE);
+
+ if (cp != (char *)NULL) {
+ Lst members = Lst_Init(FALSE);
+
+ if (cgn->type & OP_ARCHV) {
+ /*
+ * Node was an archive(member) target, so we want to call
+ * on the Arch module to find the nodes for us, expanding
+ * variables in the parent's context.
+ */
+ char *sacrifice = cp;
+
+ (void)Arch_ParseArchive(&sacrifice, members, pgn);
+ } else {
+ /*
+ * Break the result into a vector of strings whose nodes
+ * we can find, then add those nodes to the members list.
+ * Unfortunately, we can't use brk_string b/c it
+ * doesn't understand about variable specifications with
+ * spaces in them...
+ */
+ char *start;
+ char *initcp = cp; /* For freeing... */
+
+ for (start = cp; *start == ' ' || *start == '\t'; start++)
+ continue;
+ for (cp = start; *cp != '\0'; cp++) {
+ if (*cp == ' ' || *cp == '\t') {
+ /*
+ * White-space -- terminate element, find the node,
+ * add it, skip any further spaces.
+ */
+ *cp++ = '\0';
+ gn = Targ_FindNode(start, TARG_CREATE);
+ (void)Lst_AtEnd(members, (ClientData)gn);
+ while (*cp == ' ' || *cp == '\t') {
+ cp++;
+ }
+ /*
+ * Adjust cp for increment at start of loop, but
+ * set start to first non-space.
+ */
+ start = cp--;
+ } else if (*cp == '$') {
+ /*
+ * Start of a variable spec -- contact variable module
+ * to find the end so we can skip over it.
+ */
+ char *junk;
+ int len;
+ Boolean doFree;
+
+ junk = Var_Parse(cp, pgn, TRUE, &len, &doFree);
+ if (junk != var_Error) {
+ cp += len - 1;
+ }
+
+ if (doFree) {
+ free(junk);
+ }
+ } else if (*cp == '\\' && *cp != '\0') {
+ /*
+ * Escaped something -- skip over it
+ */
+ cp++;
+ }
+ }
+
+ if (cp != start) {
+ /*
+ * Stuff left over -- add it to the list too
+ */
+ gn = Targ_FindNode(start, TARG_CREATE);
+ (void)Lst_AtEnd(members, (ClientData)gn);
+ }
+ /*
+ * Point cp back at the beginning again so the variable value
+ * can be freed.
+ */
+ cp = initcp;
+ }
+ /*
+ * Add all elements of the members list to the parent node.
+ */
+ while(!Lst_IsEmpty(members)) {
+ gn = (GNode *)Lst_DeQueue(members);
+
+ if (DEBUG(SUFF)) {
+ printf("%s...", gn->name);
+ }
+ if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
+ (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
+ prevLN = Lst_Succ(prevLN);
+ (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
+ pgn->unmade++;
+ }
+ }
+ Lst_Destroy(members, NOFREE);
+ /*
+ * Free the result
+ */
+ free((char *)cp);
+ }
+ /*
+ * Now the source is expanded, remove it from the list of children to
+ * keep it from being processed.
+ */
+ ln = Lst_Member(pgn->children, (ClientData)cgn);
+ pgn->unmade--;
+ Lst_Remove(pgn->children, ln);
+ if (DEBUG(SUFF)) {
+ printf("\n");
+ }
+ } else if (Dir_HasWildcards(cgn->name)) {
+ Lst exp; /* List of expansions */
+ Lst path; /* Search path along which to expand */
+
+ /*
+ * Find a path along which to expand the word.
+ *
+ * If the word has a known suffix, use that path.
+ * If it has no known suffix and we're allowed to use the null
+ * suffix, use its path.
+ * Else use the default system search path.
+ */
+ cp = cgn->name + strlen(cgn->name);
+ ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffIsSuffixP);
+
+ if (DEBUG(SUFF)) {
+ printf("Wildcard expanding \"%s\"...", cgn->name);
+ }
+
+ if (ln != NILLNODE) {
+ Suff *s = (Suff *)Lst_Datum(ln);
+
+ if (DEBUG(SUFF)) {
+ printf("suffix is \"%s\"...", s->name);
+ }
+ path = s->searchPath;
+ } else {
+ /*
+ * Use default search path
+ */
+ path = dirSearchPath;
+ }
+
+ /*
+ * Expand the word along the chosen path
+ */
+ exp = Lst_Init(FALSE);
+ Dir_Expand(cgn->name, path, exp);
+
+ while (!Lst_IsEmpty(exp)) {
+ /*
+ * Fetch next expansion off the list and find its GNode
+ */
+ cp = (char *)Lst_DeQueue(exp);
+
+ if (DEBUG(SUFF)) {
+ printf("%s...", cp);
+ }
+ gn = Targ_FindNode(cp, TARG_CREATE);
+
+ /*
+ * If gn isn't already a child of the parent, make it so and
+ * up the parent's count of unmade children.
+ */
+ if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
+ (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
+ prevLN = Lst_Succ(prevLN);
+ (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
+ pgn->unmade++;
+ }
+ }
+
+ /*
+ * Nuke what's left of the list
+ */
+ Lst_Destroy(exp, NOFREE);
+
+ /*
+ * Now the source is expanded, remove it from the list of children to
+ * keep it from being processed.
+ */
+ ln = Lst_Member(pgn->children, (ClientData)cgn);
+ pgn->unmade--;
+ Lst_Remove(pgn->children, ln);
+ if (DEBUG(SUFF)) {
+ printf("\n");
+ }
+ }
+
+ return(0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffApplyTransform --
+ * Apply a transformation rule, given the source and target nodes
+ * and suffixes.
+ *
+ * Results:
+ * TRUE if successful, FALSE if not.
+ *
+ * Side Effects:
+ * The source and target are linked and the commands from the
+ * transformation are added to the target node's commands list.
+ * All attributes but OP_DEPMASK and OP_TRANSFORM are applied
+ * to the target. The target also inherits all the sources for
+ * the transformation rule.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+SuffApplyTransform(tGn, sGn, t, s)
+ GNode *tGn; /* Target node */
+ GNode *sGn; /* Source node */
+ Suff *t; /* Target suffix */
+ Suff *s; /* Source suffix */
+{
+ LstNode ln; /* General node */
+ char *tname; /* Name of transformation rule */
+ GNode *gn; /* Node for same */
+
+ if (Lst_Member(tGn->children, (ClientData)sGn) == NILLNODE) {
+ /*
+ * Not already linked, so form the proper links between the
+ * target and source.
+ */
+ (void)Lst_AtEnd(tGn->children, (ClientData)sGn);
+ (void)Lst_AtEnd(sGn->parents, (ClientData)tGn);
+ tGn->unmade += 1;
+ }
+
+ if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) {
+ /*
+ * When a :: node is used as the implied source of a node, we have
+ * to link all its cohorts in as sources as well. Only the initial
+ * sGn gets the target in its iParents list, however, as that
+ * will be sufficient to get the .IMPSRC variable set for tGn
+ */
+ for (ln=Lst_First(sGn->cohorts); ln != NILLNODE; ln=Lst_Succ(ln)) {
+ gn = (GNode *)Lst_Datum(ln);
+
+ if (Lst_Member(tGn->children, (ClientData)gn) == NILLNODE) {
+ /*
+ * Not already linked, so form the proper links between the
+ * target and source.
+ */
+ (void)Lst_AtEnd(tGn->children, (ClientData)gn);
+ (void)Lst_AtEnd(gn->parents, (ClientData)tGn);
+ tGn->unmade += 1;
+ }
+ }
+ }
+ /*
+ * Locate the transformation rule itself
+ */
+ tname = str_concat(s->name, t->name, 0);
+ ln = Lst_Find(transforms, (ClientData)tname, SuffGNHasNameP);
+ free(tname);
+
+ if (ln == NILLNODE) {
+ /*
+ * Not really such a transformation rule (can happen when we're
+ * called to link an OP_MEMBER and OP_ARCHV node), so return
+ * FALSE.
+ */
+ return(FALSE);
+ }
+
+ gn = (GNode *)Lst_Datum(ln);
+
+ if (DEBUG(SUFF)) {
+ printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
+ }
+
+ /*
+ * Record last child for expansion purposes
+ */
+ ln = Lst_Last(tGn->children);
+
+ /*
+ * Pass the buck to Make_HandleUse to apply the rule
+ */
+ (void)Make_HandleUse(gn, tGn);
+
+ /*
+ * Deal with wildcards and variables in any acquired sources
+ */
+ ln = Lst_Succ(ln);
+ if (ln != NILLNODE) {
+ Lst_ForEachFrom(tGn->children, ln,
+ SuffExpandChildren, (ClientData)tGn);
+ }
+
+ /*
+ * Keep track of another parent to which this beast is transformed so
+ * the .IMPSRC variable can be set correctly for the parent.
+ */
+ (void)Lst_AtEnd(sGn->iParents, (ClientData)tGn);
+
+ return(TRUE);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffFindArchiveDeps --
+ * Locate dependencies for an OP_ARCHV node.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Same as Suff_FindDeps
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffFindArchiveDeps(gn, slst)
+ GNode *gn; /* Node for which to locate dependencies */
+ Lst slst;
+{
+ char *eoarch; /* End of archive portion */
+ char *eoname; /* End of member portion */
+ GNode *mem; /* Node for member */
+ static char *copy[] = { /* Variables to be copied from the member node */
+ TARGET, /* Must be first */
+ PREFIX, /* Must be second */
+ };
+ int i; /* Index into copy and vals */
+ Suff *ms; /* Suffix descriptor for member */
+ char *name; /* Start of member's name */
+
+ /*
+ * The node is an archive(member) pair. so we must find a
+ * suffix for both of them.
+ */
+ eoarch = strchr (gn->name, '(');
+ eoname = strchr (eoarch, ')');
+
+ *eoname = '\0'; /* Nuke parentheses during suffix search */
+ *eoarch = '\0'; /* So a suffix can be found */
+
+ name = eoarch + 1;
+
+ /*
+ * To simplify things, call Suff_FindDeps recursively on the member now,
+ * so we can simply compare the member's .PREFIX and .TARGET variables
+ * to locate its suffix. This allows us to figure out the suffix to
+ * use for the archive without having to do a quadratic search over the
+ * suffix list, backtracking for each one...
+ */
+ mem = Targ_FindNode(name, TARG_CREATE);
+ SuffFindDeps(mem, slst);
+
+ /*
+ * Create the link between the two nodes right off
+ */
+ if (Lst_Member(gn->children, (ClientData)mem) == NILLNODE) {
+ (void)Lst_AtEnd(gn->children, (ClientData)mem);
+ (void)Lst_AtEnd(mem->parents, (ClientData)gn);
+ gn->unmade += 1;
+ }
+
+ /*
+ * Copy in the variables from the member node to this one.
+ */
+ for (i = (sizeof(copy)/sizeof(copy[0]))-1; i >= 0; i--) {
+ char *p1;
+ Var_Set(copy[i], Var_Value(copy[i], mem, &p1), gn);
+ if (p1)
+ free(p1);
+
+ }
+
+ ms = mem->suffix;
+ if (ms == NULL) {
+ /*
+ * Didn't know what it was -- use .NULL suffix if not in make mode
+ */
+ if (DEBUG(SUFF)) {
+ printf("using null suffix\n");
+ }
+ ms = suffNull;
+ }
+
+
+ /*
+ * Set the other two local variables required for this target.
+ */
+ Var_Set (MEMBER, name, gn);
+ Var_Set (ARCHIVE, gn->name, gn);
+
+ if (ms != NULL) {
+ /*
+ * Member has a known suffix, so look for a transformation rule from
+ * it to a possible suffix of the archive. Rather than searching
+ * through the entire list, we just look at suffixes to which the
+ * member's suffix may be transformed...
+ */
+ LstNode ln;
+
+ /*
+ * Use first matching suffix...
+ */
+ ln = Lst_Find(ms->parents, eoarch, SuffSuffIsSuffixP);
+
+ if (ln != NILLNODE) {
+ /*
+ * Got one -- apply it
+ */
+ if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&
+ DEBUG(SUFF))
+ {
+ printf("\tNo transformation from %s -> %s\n",
+ ms->name, ((Suff *)Lst_Datum(ln))->name);
+ }
+ }
+ }
+
+ /*
+ * Replace the opening and closing parens now we've no need of the separate
+ * pieces.
+ */
+ *eoarch = '('; *eoname = ')';
+
+ /*
+ * Pretend gn appeared to the left of a dependency operator so
+ * the user needn't provide a transformation from the member to the
+ * archive.
+ */
+ if (OP_NOP(gn->type)) {
+ gn->type |= OP_DEPENDS;
+ }
+
+ /*
+ * Flag the member as such so we remember to look in the archive for
+ * its modification time.
+ */
+ mem->type |= OP_MEMBER;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * SuffFindNormalDeps --
+ * Locate implicit dependencies for regular targets.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Same as Suff_FindDeps...
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+SuffFindNormalDeps(gn, slst)
+ GNode *gn; /* Node for which to find sources */
+ Lst slst;
+{
+ char *eoname; /* End of name */
+ char *sopref; /* Start of prefix */
+ LstNode ln; /* Next suffix node to check */
+ Lst srcs; /* List of sources at which to look */
+ Lst targs; /* List of targets to which things can be
+ * transformed. They all have the same file,
+ * but different suff and pref fields */
+ Src *bottom; /* Start of found transformation path */
+ Src *src; /* General Src pointer */
+ char *pref; /* Prefix to use */
+ Src *targ; /* General Src target pointer */
+
+
+ eoname = gn->name + strlen(gn->name);
+
+ sopref = gn->name;
+
+ /*
+ * Begin at the beginning...
+ */
+ ln = Lst_First(sufflist);
+ srcs = Lst_Init(FALSE);
+ targs = Lst_Init(FALSE);
+
+ /*
+ * We're caught in a catch-22 here. On the one hand, we want to use any
+ * transformation implied by the target's sources, but we can't examine
+ * the sources until we've expanded any variables/wildcards they may hold,
+ * and we can't do that until we've set up the target's local variables
+ * and we can't do that until we know what the proper suffix for the
+ * target is (in case there are two suffixes one of which is a suffix of
+ * the other) and we can't know that until we've found its implied
+ * source, which we may not want to use if there's an existing source
+ * that implies a different transformation.
+ *
+ * In an attempt to get around this, which may not work all the time,
+ * but should work most of the time, we look for implied sources first,
+ * checking transformations to all possible suffixes of the target,
+ * use what we find to set the target's local variables, expand the
+ * children, then look for any overriding transformations they imply.
+ * Should we find one, we discard the one we found before.
+ */
+
+ while (ln != NILLNODE) {
+ /*
+ * Look for next possible suffix...
+ */
+ ln = Lst_FindFrom(sufflist, ln, eoname, SuffSuffIsSuffixP);
+
+ if (ln != NILLNODE) {
+ int prefLen; /* Length of the prefix */
+ Src *targ;
+
+ /*
+ * Allocate a Src structure to which things can be transformed
+ */
+ targ = (Src *)emalloc(sizeof (Src));
+ targ->file = estrdup(gn->name);
+ targ->suff = (Suff *)Lst_Datum(ln);
+ targ->suff->refCount++;
+ targ->node = gn;
+ targ->parent = (Src *)NULL;
+ targ->children = 0;
+#ifdef DEBUG_SRC
+ targ->cp = Lst_Init(FALSE);
+#endif
+
+ /*
+ * Allocate room for the prefix, whose end is found by subtracting
+ * the length of the suffix from the end of the name.
+ */
+ prefLen = (eoname - targ->suff->nameLen) - sopref;
+ targ->pref = emalloc(prefLen + 1);
+ memcpy(targ->pref, sopref, prefLen);
+ targ->pref[prefLen] = '\0';
+
+ /*
+ * Add nodes from which the target can be made
+ */
+ SuffAddLevel(srcs, targ);
+
+ /*
+ * Record the target so we can nuke it
+ */
+ (void)Lst_AtEnd(targs, (ClientData)targ);
+
+ /*
+ * Search from this suffix's successor...
+ */
+ ln = Lst_Succ(ln);
+ }
+ }
+
+ /*
+ * Handle target of unknown suffix...
+ */
+ if (Lst_IsEmpty(targs) && suffNull != NULL) {
+ if (DEBUG(SUFF)) {
+ printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
+ }
+
+ targ = (Src *)emalloc(sizeof (Src));
+ targ->file = estrdup(gn->name);
+ targ->suff = suffNull;
+ targ->suff->refCount++;
+ targ->node = gn;
+ targ->parent = (Src *)NULL;
+ targ->children = 0;
+ targ->pref = estrdup(sopref);
+#ifdef DEBUG_SRC
+ targ->cp = Lst_Init(FALSE);
+#endif
+
+ /*
+ * Only use the default suffix rules if we don't have commands
+ * or dependencies defined for this gnode
+ */
+ if (Lst_IsEmpty(gn->commands) && Lst_IsEmpty(gn->children))
+ SuffAddLevel(srcs, targ);
+ else {
+ if (DEBUG(SUFF))
+ printf("not ");
+ }
+
+ if (DEBUG(SUFF))
+ printf("adding suffix rules\n");
+
+ (void)Lst_AtEnd(targs, (ClientData)targ);
+ }
+
+ /*
+ * Using the list of possible sources built up from the target suffix(es),
+ * try and find an existing file/target that matches.
+ */
+ bottom = SuffFindThem(srcs, slst);
+
+ if (bottom == (Src *)NULL) {
+ /*
+ * No known transformations -- use the first suffix found for setting
+ * the local variables.
+ */
+ if (!Lst_IsEmpty(targs)) {
+ targ = (Src *)Lst_Datum(Lst_First(targs));
+ } else {
+ targ = (Src *)NULL;
+ }
+ } else {
+ /*
+ * Work up the transformation path to find the suffix of the
+ * target to which the transformation was made.
+ */
+ for (targ = bottom; targ->parent != NULL; targ = targ->parent)
+ continue;
+ }
+
+ /*
+ * The .TARGET variable we always set to be the name at this point,
+ * since it's only set to the path if the thing is only a source and
+ * if it's only a source, it doesn't matter what we put here as far
+ * as expanding sources is concerned, since it has none...
+ */
+ Var_Set(TARGET, gn->name, gn);
+
+ pref = (targ != NULL) ? targ->pref : gn->name;
+ Var_Set(PREFIX, pref, gn);
+
+ /*
+ * Now we've got the important local variables set, expand any sources
+ * that still contain variables or wildcards in their names.
+ */
+ Lst_ForEach(gn->children, SuffExpandChildren, (ClientData)gn);
+
+ if (targ == NULL) {
+ if (DEBUG(SUFF)) {
+ printf("\tNo valid suffix on %s\n", gn->name);
+ }
+
+sfnd_abort:
+ /*
+ * Deal with finding the thing on the default search path if the
+ * node is only a source (not on the lhs of a dependency operator
+ * or [XXX] it has neither children or commands).
+ */
+ if (OP_NOP(gn->type) ||
+ (Lst_IsEmpty(gn->children) && Lst_IsEmpty(gn->commands)))
+ {
+ gn->path = Dir_FindFile(gn->name,
+ (targ == NULL ? dirSearchPath :
+ targ->suff->searchPath));
+ if (gn->path != NULL) {
+ char *ptr;
+ Var_Set(TARGET, gn->path, gn);
+
+ if (targ != NULL) {
+ /*
+ * Suffix known for the thing -- trim the suffix off
+ * the path to form the proper .PREFIX variable.
+ */
+ int savep = strlen(gn->path) - targ->suff->nameLen;
+ char savec;
+
+ if (gn->suffix)
+ gn->suffix->refCount--;
+ gn->suffix = targ->suff;
+ gn->suffix->refCount++;
+
+ savec = gn->path[savep];
+ gn->path[savep] = '\0';
+
+ if ((ptr = strrchr(gn->path, '/')) != NULL)
+ ptr++;
+ else
+ ptr = gn->path;
+
+ Var_Set(PREFIX, ptr, gn);
+
+ gn->path[savep] = savec;
+ } else {
+ /*
+ * The .PREFIX gets the full path if the target has
+ * no known suffix.
+ */
+ if (gn->suffix)
+ gn->suffix->refCount--;
+ gn->suffix = NULL;
+
+ if ((ptr = strrchr(gn->path, '/')) != NULL)
+ ptr++;
+ else
+ ptr = gn->path;
+
+ Var_Set(PREFIX, ptr, gn);
+ }
+ }
+ } else {
+ /*
+ * Not appropriate to search for the thing -- set the
+ * path to be the name so Dir_MTime won't go grovelling for
+ * it.
+ */
+ if (gn->suffix)
+ gn->suffix->refCount--;
+ gn->suffix = (targ == NULL) ? NULL : targ->suff;
+ if (gn->suffix)
+ gn->suffix->refCount++;
+ if (gn->path != NULL)
+ free(gn->path);
+ gn->path = estrdup(gn->name);
+ }
+
+ goto sfnd_return;
+ }
+
+ /*
+ * If the suffix indicates that the target is a library, mark that in
+ * the node's type field.
+ */
+ if (targ->suff->flags & SUFF_LIBRARY) {
+ gn->type |= OP_LIB;
+ }
+
+ /*
+ * Check for overriding transformation rule implied by sources
+ */
+ if (!Lst_IsEmpty(gn->children)) {
+ src = SuffFindCmds(targ, slst);
+
+ if (src != (Src *)NULL) {
+ /*
+ * Free up all the Src structures in the transformation path
+ * up to, but not including, the parent node.
+ */
+ while (bottom && bottom->parent != NULL) {
+ if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) {
+ Lst_AtEnd(slst, (ClientData) bottom);
+ }
+ bottom = bottom->parent;
+ }
+ bottom = src;
+ }
+ }
+
+ if (bottom == NULL) {
+ /*
+ * No idea from where it can come -- return now.
+ */
+ goto sfnd_abort;
+ }
+
+ /*
+ * We now have a list of Src structures headed by 'bottom' and linked via
+ * their 'parent' pointers. What we do next is create links between
+ * source and target nodes (which may or may not have been created)
+ * and set the necessary local variables in each target. The
+ * commands for each target are set from the commands of the
+ * transformation rule used to get from the src suffix to the targ
+ * suffix. Note that this causes the commands list of the original
+ * node, gn, to be replaced by the commands of the final
+ * transformation rule. Also, the unmade field of gn is incremented.
+ * Etc.
+ */
+ if (bottom->node == NILGNODE) {
+ bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);
+ }
+
+ for (src = bottom; src->parent != (Src *)NULL; src = src->parent) {
+ targ = src->parent;
+
+ if (src->node->suffix)
+ src->node->suffix->refCount--;
+ src->node->suffix = src->suff;
+ src->node->suffix->refCount++;
+
+ if (targ->node == NILGNODE) {
+ targ->node = Targ_FindNode(targ->file, TARG_CREATE);
+ }
+
+ SuffApplyTransform(targ->node, src->node,
+ targ->suff, src->suff);
+
+ if (targ->node != gn) {
+ /*
+ * Finish off the dependency-search process for any nodes
+ * between bottom and gn (no point in questing around the
+ * filesystem for their implicit source when it's already
+ * known). Note that the node can't have any sources that
+ * need expanding, since SuffFindThem will stop on an existing
+ * node, so all we need to do is set the standard and System V
+ * variables.
+ */
+ targ->node->type |= OP_DEPS_FOUND;
+
+ Var_Set(PREFIX, targ->pref, targ->node);
+
+ Var_Set(TARGET, targ->node->name, targ->node);
+ }
+ }
+
+ if (gn->suffix)
+ gn->suffix->refCount--;
+ gn->suffix = src->suff;
+ gn->suffix->refCount++;
+
+ /*
+ * So Dir_MTime doesn't go questing for it...
+ */
+ if (gn->path)
+ free(gn->path);
+ gn->path = estrdup(gn->name);
+
+ /*
+ * Nuke the transformation path and the Src structures left over in the
+ * two lists.
+ */
+sfnd_return:
+ if (bottom)
+ if (Lst_Member(slst, (ClientData) bottom) == NILLNODE)
+ Lst_AtEnd(slst, (ClientData) bottom);
+
+ while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs))
+ continue;
+
+ Lst_Concat(slst, srcs, LST_CONCLINK);
+ Lst_Concat(slst, targs, LST_CONCLINK);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_FindDeps --
+ * Find implicit sources for the target described by the graph node
+ * gn
+ *
+ * Results:
+ * Nothing.
+ *
+ * Side Effects:
+ * Nodes are added to the graph below the passed-in node. The nodes
+ * are marked to have their IMPSRC variable filled in. The
+ * PREFIX variable is set for the given node and all its
+ * implied children.
+ *
+ * Notes:
+ * The path found by this target is the shortest path in the
+ * transformation graph, which may pass through non-existent targets,
+ * to an existing target. The search continues on all paths from the
+ * root suffix until a file is found. I.e. if there's a path
+ * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but
+ * the .c and .l files don't, the search will branch out in
+ * all directions from .o and again from all the nodes on the
+ * next level until the .l,v node is encountered.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+void
+Suff_FindDeps(gn)
+ GNode *gn;
+{
+
+ SuffFindDeps(gn, srclist);
+ while (SuffRemoveSrc(srclist))
+ continue;
+}
+
+
+static void
+SuffFindDeps (gn, slst)
+ GNode *gn; /* node we're dealing with */
+ Lst slst;
+{
+ if (gn->type & OP_DEPS_FOUND) {
+ /*
+ * If dependencies already found, no need to do it again...
+ */
+ return;
+ } else {
+ gn->type |= OP_DEPS_FOUND;
+ }
+
+ if (DEBUG(SUFF)) {
+ printf ("SuffFindDeps (%s)\n", gn->name);
+ }
+
+ if (gn->type & OP_ARCHV) {
+ SuffFindArchiveDeps(gn, slst);
+ } else if (gn->type & OP_LIB) {
+ /*
+ * If the node is a library, it is the arch module's job to find it
+ * and set the TARGET variable accordingly. We merely provide the
+ * search path, assuming all libraries end in ".a" (if the suffix
+ * hasn't been defined, there's nothing we can do for it, so we just
+ * set the TARGET variable to the node's name in order to give it a
+ * value).
+ */
+ LstNode ln;
+ Suff *s;
+
+ ln = Lst_Find (sufflist, (ClientData)LIBSUFF, SuffSuffHasNameP);
+ if (gn->suffix)
+ gn->suffix->refCount--;
+ if (ln != NILLNODE) {
+ gn->suffix = s = (Suff *) Lst_Datum (ln);
+ gn->suffix->refCount++;
+ Arch_FindLib (gn, s->searchPath);
+ } else {
+ gn->suffix = NULL;
+ Var_Set (TARGET, gn->name, gn);
+ }
+ /*
+ * Because a library (-lfoo) target doesn't follow the standard
+ * filesystem conventions, we don't set the regular variables for
+ * the thing. .PREFIX is simply made empty...
+ */
+ Var_Set(PREFIX, "", gn);
+ } else {
+ SuffFindNormalDeps(gn, slst);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_SetNull --
+ * Define which suffix is the null suffix.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * 'suffNull' is altered.
+ *
+ * Notes:
+ * Need to handle the changing of the null suffix gracefully so the
+ * old transformation rules don't just go away.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_SetNull(name)
+ char *name; /* Name of null suffix */
+{
+ Suff *s;
+ LstNode ln;
+
+ ln = Lst_Find(sufflist, (ClientData)name, SuffSuffHasNameP);
+ if (ln != NILLNODE) {
+ s = (Suff *)Lst_Datum(ln);
+ if (suffNull != (Suff *)NULL) {
+ suffNull->flags &= ~SUFF_NULL;
+ }
+ s->flags |= SUFF_NULL;
+ /*
+ * XXX: Here's where the transformation mangling would take place
+ */
+ suffNull = s;
+ } else {
+ Parse_Error (PARSE_WARNING, "Desired null suffix %s not defined.",
+ name);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Suff_Init --
+ * Initialize suffixes module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Many
+ *-----------------------------------------------------------------------
+ */
+void
+Suff_Init ()
+{
+ sufflist = Lst_Init (FALSE);
+ suffClean = Lst_Init(FALSE);
+ srclist = Lst_Init (FALSE);
+ transforms = Lst_Init (FALSE);
+
+ sNum = 0;
+ /*
+ * Create null suffix for single-suffix rules (POSIX). The thing doesn't
+ * actually go on the suffix list or everyone will think that's its
+ * suffix.
+ */
+ emptySuff = suffNull = (Suff *) emalloc (sizeof (Suff));
+
+ suffNull->name = estrdup ("");
+ suffNull->nameLen = 0;
+ suffNull->searchPath = Lst_Init (FALSE);
+ Dir_Concat(suffNull->searchPath, dirSearchPath);
+ suffNull->children = Lst_Init (FALSE);
+ suffNull->parents = Lst_Init (FALSE);
+ suffNull->ref = Lst_Init (FALSE);
+ suffNull->sNum = sNum++;
+ suffNull->flags = SUFF_NULL;
+ suffNull->refCount = 1;
+
+}
+
+
+/*-
+ *----------------------------------------------------------------------
+ * Suff_End --
+ * Cleanup the this module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The memory is free'd.
+ *----------------------------------------------------------------------
+ */
+
+void
+Suff_End()
+{
+ Lst_Destroy(sufflist, SuffFree);
+ Lst_Destroy(suffClean, SuffFree);
+ if (suffNull)
+ SuffFree(suffNull);
+ Lst_Destroy(srclist, NOFREE);
+ Lst_Destroy(transforms, NOFREE);
+}
+
+
+/********************* DEBUGGING FUNCTIONS **********************/
+
+static int SuffPrintName(s, dummy)
+ ClientData s;
+ ClientData dummy;
+{
+ printf ("%s ", ((Suff *) s)->name);
+ return (dummy ? 0 : 0);
+}
+
+static int
+SuffPrintSuff (sp, dummy)
+ ClientData sp;
+ ClientData dummy;
+{
+ Suff *s = (Suff *) sp;
+ int flags;
+ int flag;
+
+ printf ("# `%s' [%d] ", s->name, s->refCount);
+
+ flags = s->flags;
+ if (flags) {
+ fputs (" (", stdout);
+ while (flags) {
+ flag = 1 << (ffs(flags) - 1);
+ flags &= ~flag;
+ switch (flag) {
+ case SUFF_NULL:
+ printf ("NULL");
+ break;
+ case SUFF_INCLUDE:
+ printf ("INCLUDE");
+ break;
+ case SUFF_LIBRARY:
+ printf ("LIBRARY");
+ break;
+ }
+ fputc(flags ? '|' : ')', stdout);
+ }
+ }
+ fputc ('\n', stdout);
+ printf ("#\tTo: ");
+ Lst_ForEach (s->parents, SuffPrintName, (ClientData)0);
+ fputc ('\n', stdout);
+ printf ("#\tFrom: ");
+ Lst_ForEach (s->children, SuffPrintName, (ClientData)0);
+ fputc ('\n', stdout);
+ printf ("#\tSearch Path: ");
+ Dir_PrintPath (s->searchPath);
+ fputc ('\n', stdout);
+ return (dummy ? 0 : 0);
+}
+
+static int
+SuffPrintTrans (tp, dummy)
+ ClientData tp;
+ ClientData dummy;
+{
+ GNode *t = (GNode *) tp;
+
+ printf ("%-16s: ", t->name);
+ Targ_PrintType (t->type);
+ fputc ('\n', stdout);
+ Lst_ForEach (t->commands, Targ_PrintCmd, (ClientData)0);
+ fputc ('\n', stdout);
+ return(dummy ? 0 : 0);
+}
+
+void
+Suff_PrintAll()
+{
+ printf ("#*** Suffixes:\n");
+ Lst_ForEach (sufflist, SuffPrintSuff, (ClientData)0);
+
+ printf ("#*** Transformations:\n");
+ Lst_ForEach (transforms, SuffPrintTrans, (ClientData)0);
+}
diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c
new file mode 100644
index 0000000..3fdc65b
--- /dev/null
+++ b/usr.bin/make/targ.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * targ.c --
+ * Functions for maintaining the Lst allTargets. Target nodes are
+ * kept in two structures: a Lst, maintained by the list library, and a
+ * hash table, maintained by the hash library.
+ *
+ * Interface:
+ * Targ_Init Initialization procedure.
+ *
+ * Targ_End Cleanup the module
+ *
+ * Targ_NewGN Create a new GNode for the passed target
+ * (string). The node is *not* placed in the
+ * hash table, though all its fields are
+ * initialized.
+ *
+ * Targ_FindNode Find the node for a given target, creating
+ * and storing it if it doesn't exist and the
+ * flags are right (TARG_CREATE)
+ *
+ * Targ_FindList Given a list of names, find nodes for all
+ * of them. If a name doesn't exist and the
+ * TARG_NOCREATE flag was given, an error message
+ * is printed. Else, if a name doesn't exist,
+ * its node is created.
+ *
+ * Targ_Ignore Return TRUE if errors should be ignored when
+ * creating the given target.
+ *
+ * Targ_Silent Return TRUE if we should be silent when
+ * creating the given target.
+ *
+ * Targ_Precious Return TRUE if the target is precious and
+ * should not be removed if we are interrupted.
+ *
+ * Debugging:
+ * Targ_PrintGraph Print out the entire graphm all variables
+ * and statistics for the directory cache. Should
+ * print something for suffixes, too, but...
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include "make.h"
+#include "hash.h"
+#include "dir.h"
+
+static Lst allTargets; /* the list of all targets found so far */
+static Lst allGNs; /* List of all the GNodes */
+static Hash_Table targets; /* a hash table of same */
+
+#define HTSIZE 191 /* initial size of hash table */
+
+static int TargPrintOnlySrc __P((ClientData, ClientData));
+static int TargPrintName __P((ClientData, ClientData));
+static int TargPrintNode __P((ClientData, ClientData));
+static void TargFreeGN __P((ClientData));
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_Init --
+ * Initialize this module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The allTargets list and the targets hash table are initialized
+ *-----------------------------------------------------------------------
+ */
+void
+Targ_Init ()
+{
+ allTargets = Lst_Init (FALSE);
+ Hash_InitTable (&targets, HTSIZE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_End --
+ * Finalize this module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * All lists and gnodes are cleared
+ *-----------------------------------------------------------------------
+ */
+void
+Targ_End ()
+{
+ Lst_Destroy(allTargets, NOFREE);
+ if (allGNs)
+ Lst_Destroy(allGNs, TargFreeGN);
+ Hash_DeleteTable(&targets);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_NewGN --
+ * Create and initialize a new graph node
+ *
+ * Results:
+ * An initialized graph node with the name field filled with a copy
+ * of the passed name
+ *
+ * Side Effects:
+ * The gnode is added to the list of all gnodes.
+ *-----------------------------------------------------------------------
+ */
+GNode *
+Targ_NewGN (name)
+ char *name; /* the name to stick in the new node */
+{
+ register GNode *gn;
+
+ gn = (GNode *) emalloc (sizeof (GNode));
+ gn->name = estrdup (name);
+ gn->path = (char *) 0;
+ if (name[0] == '-' && name[1] == 'l') {
+ gn->type = OP_LIB;
+ } else {
+ gn->type = 0;
+ }
+ gn->unmade = 0;
+ gn->make = FALSE;
+ gn->made = UNMADE;
+ gn->childMade = FALSE;
+ gn->order = 0;
+ gn->mtime = gn->cmtime = 0;
+ gn->iParents = Lst_Init (FALSE);
+ gn->cohorts = Lst_Init (FALSE);
+ gn->parents = Lst_Init (FALSE);
+ gn->children = Lst_Init (FALSE);
+ gn->successors = Lst_Init (FALSE);
+ gn->preds = Lst_Init (FALSE);
+ gn->context = Lst_Init (FALSE);
+ gn->commands = Lst_Init (FALSE);
+ gn->suffix = NULL;
+
+ if (allGNs == NULL)
+ allGNs = Lst_Init(FALSE);
+ Lst_AtEnd(allGNs, (ClientData) gn);
+
+ return (gn);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * TargFreeGN --
+ * Destroy a GNode
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * None.
+ *-----------------------------------------------------------------------
+ */
+static void
+TargFreeGN (gnp)
+ ClientData gnp;
+{
+ GNode *gn = (GNode *) gnp;
+
+
+ free(gn->name);
+ if (gn->path)
+ free(gn->path);
+
+ Lst_Destroy(gn->iParents, NOFREE);
+ Lst_Destroy(gn->cohorts, NOFREE);
+ Lst_Destroy(gn->parents, NOFREE);
+ Lst_Destroy(gn->children, NOFREE);
+ Lst_Destroy(gn->successors, NOFREE);
+ Lst_Destroy(gn->preds, NOFREE);
+ Lst_Destroy(gn->context, NOFREE);
+ Lst_Destroy(gn->commands, NOFREE);
+ free((Address)gn);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_FindNode --
+ * Find a node in the list using the given name for matching
+ *
+ * Results:
+ * The node in the list if it was. If it wasn't, return NILGNODE of
+ * flags was TARG_NOCREATE or the newly created and initialized node
+ * if it was TARG_CREATE
+ *
+ * Side Effects:
+ * Sometimes a node is created and added to the list
+ *-----------------------------------------------------------------------
+ */
+GNode *
+Targ_FindNode (name, flags)
+ char *name; /* the name to find */
+ int flags; /* flags governing events when target not
+ * found */
+{
+ GNode *gn; /* node in that element */
+ Hash_Entry *he; /* New or used hash entry for node */
+ Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
+ /* an entry for the node */
+
+
+ if (flags & TARG_CREATE) {
+ he = Hash_CreateEntry (&targets, name, &isNew);
+ if (isNew) {
+ gn = Targ_NewGN (name);
+ Hash_SetValue (he, gn);
+ (void) Lst_AtEnd (allTargets, (ClientData)gn);
+ }
+ } else {
+ he = Hash_FindEntry (&targets, name);
+ }
+
+ if (he == (Hash_Entry *) NULL) {
+ return (NILGNODE);
+ } else {
+ return ((GNode *) Hash_GetValue (he));
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_FindList --
+ * Make a complete list of GNodes from the given list of names
+ *
+ * Results:
+ * A complete list of graph nodes corresponding to all instances of all
+ * the names in names.
+ *
+ * Side Effects:
+ * If flags is TARG_CREATE, nodes will be created for all names in
+ * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
+ * an error message will be printed for each name which can't be found.
+ * -----------------------------------------------------------------------
+ */
+Lst
+Targ_FindList (names, flags)
+ Lst names; /* list of names to find */
+ int flags; /* flags used if no node is found for a given
+ * name */
+{
+ Lst nodes; /* result list */
+ register LstNode ln; /* name list element */
+ register GNode *gn; /* node in tLn */
+ char *name;
+
+ nodes = Lst_Init (FALSE);
+
+ if (Lst_Open (names) == FAILURE) {
+ return (nodes);
+ }
+ while ((ln = Lst_Next (names)) != NILLNODE) {
+ name = (char *)Lst_Datum(ln);
+ gn = Targ_FindNode (name, flags);
+ if (gn != NILGNODE) {
+ /*
+ * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
+ * are added to the list in the order in which they were
+ * encountered in the makefile.
+ */
+ (void) Lst_AtEnd (nodes, (ClientData)gn);
+ if (gn->type & OP_DOUBLEDEP) {
+ (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
+ }
+ } else if (flags == TARG_NOCREATE) {
+ Error ("\"%s\" -- target unknown.", name);
+ }
+ }
+ Lst_Close (names);
+ return (nodes);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_Ignore --
+ * Return true if should ignore errors when creating gn
+ *
+ * Results:
+ * TRUE if should ignore errors
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Targ_Ignore (gn)
+ GNode *gn; /* node to check for */
+{
+ if (ignoreErrors || gn->type & OP_IGNORE) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_Silent --
+ * Return true if be silent when creating gn
+ *
+ * Results:
+ * TRUE if should be silent
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Targ_Silent (gn)
+ GNode *gn; /* node to check for */
+{
+ if (beSilent || gn->type & OP_SILENT) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_Precious --
+ * See if the given target is precious
+ *
+ * Results:
+ * TRUE if it is precious. FALSE otherwise
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Targ_Precious (gn)
+ GNode *gn; /* the node to check */
+{
+ if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/******************* DEBUG INFO PRINTING ****************/
+
+static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_SetMain --
+ * Set our idea of the main target we'll be creating. Used for
+ * debugging output.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * "mainTarg" is set to the main target's node.
+ *-----------------------------------------------------------------------
+ */
+void
+Targ_SetMain (gn)
+ GNode *gn; /* The main target we'll create */
+{
+ mainTarg = gn;
+}
+
+static int
+TargPrintName (gnp, ppath)
+ ClientData gnp;
+ ClientData ppath;
+{
+ GNode *gn = (GNode *) gnp;
+ printf ("%s ", gn->name);
+#ifdef notdef
+ if (ppath) {
+ if (gn->path) {
+ printf ("[%s] ", gn->path);
+ }
+ if (gn == mainTarg) {
+ printf ("(MAIN NAME) ");
+ }
+ }
+#endif /* notdef */
+ return (ppath ? 0 : 0);
+}
+
+
+int
+Targ_PrintCmd (cmd, dummy)
+ ClientData cmd;
+ ClientData dummy;
+{
+ printf ("\t%s\n", (char *) cmd);
+ return (dummy ? 0 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_FmtTime --
+ * Format a modification time in some reasonable way and return it.
+ *
+ * Results:
+ * The time reformatted.
+ *
+ * Side Effects:
+ * The time is placed in a static area, so it is overwritten
+ * with each call.
+ *
+ *-----------------------------------------------------------------------
+ */
+char *
+Targ_FmtTime (time)
+ time_t time;
+{
+ struct tm *parts;
+ static char buf[40];
+ static char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ parts = localtime(&time);
+
+ sprintf (buf, "%d:%02d:%02d %s %d, %d",
+ parts->tm_hour, parts->tm_min, parts->tm_sec,
+ months[parts->tm_mon], parts->tm_mday, 1900 + parts->tm_year);
+ return(buf);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_PrintType --
+ * Print out a type field giving only those attributes the user can
+ * set.
+ *
+ * Results:
+ *
+ * Side Effects:
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Targ_PrintType (type)
+ register int type;
+{
+ register int tbit;
+
+#ifdef __STDC__
+#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
+#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
+#else
+#define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
+#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
+#endif /* __STDC__ */
+
+ type &= ~OP_OPMASK;
+
+ while (type) {
+ tbit = 1 << (ffs(type) - 1);
+ type &= ~tbit;
+
+ switch(tbit) {
+ PRINTBIT(OPTIONAL);
+ PRINTBIT(USE);
+ PRINTBIT(EXEC);
+ PRINTBIT(IGNORE);
+ PRINTBIT(PRECIOUS);
+ PRINTBIT(SILENT);
+ PRINTBIT(MAKE);
+ PRINTBIT(JOIN);
+ PRINTBIT(INVISIBLE);
+ PRINTBIT(NOTMAIN);
+ PRINTDBIT(LIB);
+ /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
+ case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
+ PRINTDBIT(ARCHV);
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * TargPrintNode --
+ * print the contents of a node
+ *-----------------------------------------------------------------------
+ */
+static int
+TargPrintNode (gnp, passp)
+ ClientData gnp;
+ ClientData passp;
+{
+ GNode *gn = (GNode *) gnp;
+ int pass = *(int *) passp;
+ if (!OP_NOP(gn->type)) {
+ printf("#\n");
+ if (gn == mainTarg) {
+ printf("# *** MAIN TARGET ***\n");
+ }
+ if (pass == 2) {
+ if (gn->unmade) {
+ printf("# %d unmade children\n", gn->unmade);
+ } else {
+ printf("# No unmade children\n");
+ }
+ if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
+ if (gn->mtime != 0) {
+ printf("# last modified %s: %s\n",
+ Targ_FmtTime(gn->mtime),
+ (gn->made == UNMADE ? "unmade" :
+ (gn->made == MADE ? "made" :
+ (gn->made == UPTODATE ? "up-to-date" :
+ "error when made"))));
+ } else if (gn->made != UNMADE) {
+ printf("# non-existent (maybe): %s\n",
+ (gn->made == MADE ? "made" :
+ (gn->made == UPTODATE ? "up-to-date" :
+ (gn->made == ERROR ? "error when made" :
+ "aborted"))));
+ } else {
+ printf("# unmade\n");
+ }
+ }
+ if (!Lst_IsEmpty (gn->iParents)) {
+ printf("# implicit parents: ");
+ Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
+ fputc ('\n', stdout);
+ }
+ }
+ if (!Lst_IsEmpty (gn->parents)) {
+ printf("# parents: ");
+ Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
+ fputc ('\n', stdout);
+ }
+
+ printf("%-16s", gn->name);
+ switch (gn->type & OP_OPMASK) {
+ case OP_DEPENDS:
+ printf(": "); break;
+ case OP_FORCE:
+ printf("! "); break;
+ case OP_DOUBLEDEP:
+ printf(":: "); break;
+ }
+ Targ_PrintType (gn->type);
+ Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
+ fputc ('\n', stdout);
+ Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
+ printf("\n\n");
+ if (gn->type & OP_DOUBLEDEP) {
+ Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
+ }
+ }
+ return (0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * TargPrintOnlySrc --
+ * Print only those targets that are just a source.
+ *
+ * Results:
+ * 0.
+ *
+ * Side Effects:
+ * The name of each file is printed preceeded by #\t
+ *
+ *-----------------------------------------------------------------------
+ */
+static int
+TargPrintOnlySrc(gnp, dummy)
+ ClientData gnp;
+ ClientData dummy;
+{
+ GNode *gn = (GNode *) gnp;
+ if (OP_NOP(gn->type))
+ printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
+
+ return (dummy ? 0 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_PrintGraph --
+ * print the entire graph. heh heh
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * lots o' output
+ *-----------------------------------------------------------------------
+ */
+void
+Targ_PrintGraph (pass)
+ int pass; /* Which pass this is. 1 => no processing
+ * 2 => processing done */
+{
+ printf("#*** Input graph:\n");
+ Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
+ printf("\n\n");
+ printf("#\n# Files that are only sources:\n");
+ Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
+ printf("#*** Global Variables:\n");
+ Var_Dump (VAR_GLOBAL);
+ printf("#*** Command-line Variables:\n");
+ Var_Dump (VAR_CMD);
+ printf("\n");
+ Dir_PrintDirectories();
+ printf("\n");
+ Suff_PrintAll();
+}
diff --git a/usr.bin/make/util.c b/usr.bin/make/util.c
new file mode 100644
index 0000000..62b0e79
--- /dev/null
+++ b/usr.bin/make/util.c
@@ -0,0 +1,349 @@
+/*
+ * Missing stuff from OS's
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <stdio.h>
+#include "make.h"
+
+#if !__STDC__
+# ifndef const
+# define const
+# endif
+#endif
+
+#ifdef sun
+
+
+
+extern int errno, sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(e)
+ int e;
+{
+ static char buf[100];
+ if (e < 0 || e >= sys_nerr) {
+ sprintf(buf, "Unknown error %d", e);
+ return buf;
+ }
+ else
+ return sys_errlist[e];
+}
+#endif
+
+#ifdef ultrix
+#include <string.h>
+
+/* strdup
+ *
+ * Make a duplicate of a string.
+ * For systems which lack this function.
+ */
+char *
+strdup(str)
+ const char *str;
+{
+ size_t len;
+
+ if (str == NULL)
+ return NULL;
+ len = strlen(str) + 1;
+ if ((p = malloc(len)) == NULL)
+ return NULL;
+
+ return memcpy(p, str, len);
+}
+
+#endif
+
+#if defined(sun) || defined(__hpux) || defined(__sgi)
+
+int
+setenv(name, value, dum)
+ const char *name;
+ const char *value;
+ int dum;
+{
+ register char *p;
+ int len = strlen(name) + strlen(value) + 2; /* = \0 */
+ char *ptr = (char*) malloc(len);
+
+ (void) dum;
+
+ if (ptr == NULL)
+ return -1;
+
+ p = ptr;
+
+ while (*name)
+ *p++ = *name++;
+
+ *p++ = '=';
+
+ while (*value)
+ *p++ = *value++;
+
+ *p = '\0';
+
+ len = putenv(ptr);
+/* free(ptr); */
+ return len;
+}
+#endif
+
+#ifdef __hpux
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+
+int
+killpg(pid, sig)
+ int pid, sig;
+{
+ return kill(-pid, sig);
+}
+
+void
+srandom(seed)
+ long seed;
+{
+ srand48(seed);
+}
+
+long
+random()
+{
+ return lrand48();
+}
+
+/* turn into bsd signals */
+void (*
+signal(s, a)) ()
+ int s;
+ void (*a)();
+{
+ struct sigvec osv, sv;
+
+ (void) sigvector(s, (struct sigvec *) 0, &osv);
+ sv = osv;
+ sv.sv_handler = a;
+#ifdef SV_BSDSIG
+ sv.sv_flags = SV_BSDSIG;
+#endif
+
+ if (sigvector(s, &sv, (struct sigvec *) 0) == -1)
+ return (BADSIG);
+ return (osv.sv_handler);
+}
+
+#if !defined(BSD) && !defined(d_fileno)
+# define d_fileno d_ino
+#endif
+
+#ifndef DEV_DEV_COMPARE
+# define DEV_DEV_COMPARE(a, b) ((a) == (b))
+#endif
+#define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
+#define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
+
+
+/* strrcpy():
+ * Like strcpy, going backwards and returning the new pointer
+ */
+static char *
+strrcpy(ptr, str)
+ register char *ptr, *str;
+{
+ register int len = strlen(str);
+
+ while (len)
+ *--ptr = str[--len];
+
+ return (ptr);
+} /* end strrcpy */
+
+
+char *
+getwd(pathname)
+ char *pathname;
+{
+ DIR *dp;
+ struct dirent *d;
+ extern int errno;
+
+ struct stat st_root, st_cur, st_next, st_dotdot;
+ char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
+ char *pathptr, *nextpathptr, *cur_name_add;
+
+ /* find the inode of root */
+ if (stat("/", &st_root) == -1) {
+ (void) sprintf(pathname,
+ "getwd: Cannot stat \"/\" (%s)", strerror(errno));
+ return (NULL);
+ }
+ pathbuf[MAXPATHLEN - 1] = '\0';
+ pathptr = &pathbuf[MAXPATHLEN - 1];
+ nextpathbuf[MAXPATHLEN - 1] = '\0';
+ cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
+
+ /* find the inode of the current directory */
+ if (lstat(".", &st_cur) == -1) {
+ (void) sprintf(pathname,
+ "getwd: Cannot stat \".\" (%s)", strerror(errno));
+ return (NULL);
+ }
+ nextpathptr = strrcpy(nextpathptr, "../");
+
+ /* Descend to root */
+ for (;;) {
+
+ /* look if we found root yet */
+ if (st_cur.st_ino == st_root.st_ino &&
+ DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
+ (void) strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
+ return (pathname);
+ }
+
+ /* open the parent directory */
+ if (stat(nextpathptr, &st_dotdot) == -1) {
+ (void) sprintf(pathname,
+ "getwd: Cannot stat directory \"%s\" (%s)",
+ nextpathptr, strerror(errno));
+ return (NULL);
+ }
+ if ((dp = opendir(nextpathptr)) == NULL) {
+ (void) sprintf(pathname,
+ "getwd: Cannot open directory \"%s\" (%s)",
+ nextpathptr, strerror(errno));
+ return (NULL);
+ }
+
+ /* look in the parent for the entry with the same inode */
+ if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
+ /* Parent has same device. No need to stat every member */
+ for (d = readdir(dp); d != NULL; d = readdir(dp))
+ if (d->d_fileno == st_cur.st_ino)
+ break;
+ }
+ else {
+ /*
+ * Parent has a different device. This is a mount point so we
+ * need to stat every member
+ */
+ for (d = readdir(dp); d != NULL; d = readdir(dp)) {
+ if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
+ continue;
+ (void) strcpy(cur_name_add, d->d_name);
+ if (lstat(nextpathptr, &st_next) == -1) {
+ (void) sprintf(pathname, "getwd: Cannot stat \"%s\" (%s)",
+ d->d_name, strerror(errno));
+ (void) closedir(dp);
+ return (NULL);
+ }
+ /* check if we found it yet */
+ if (st_next.st_ino == st_cur.st_ino &&
+ DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
+ break;
+ }
+ }
+ if (d == NULL) {
+ (void) sprintf(pathname, "getwd: Cannot find \".\" in \"..\"");
+ (void) closedir(dp);
+ return (NULL);
+ }
+ st_cur = st_dotdot;
+ pathptr = strrcpy(pathptr, d->d_name);
+ pathptr = strrcpy(pathptr, "/");
+ nextpathptr = strrcpy(nextpathptr, "../");
+ (void) closedir(dp);
+ *cur_name_add = '\0';
+ }
+} /* end getwd */
+
+
+char *sys_siglist[] = {
+ "Signal 0",
+ "Hangup", /* SIGHUP */
+ "Interrupt", /* SIGINT */
+ "Quit", /* SIGQUIT */
+ "Illegal instruction", /* SIGILL */
+ "Trace/BPT trap", /* SIGTRAP */
+ "IOT trap", /* SIGIOT */
+ "EMT trap", /* SIGEMT */
+ "Floating point exception", /* SIGFPE */
+ "Killed", /* SIGKILL */
+ "Bus error", /* SIGBUS */
+ "Segmentation fault", /* SIGSEGV */
+ "Bad system call", /* SIGSYS */
+ "Broken pipe", /* SIGPIPE */
+ "Alarm clock", /* SIGALRM */
+ "Terminated", /* SIGTERM */
+ "User defined signal 1", /* SIGUSR1 */
+ "User defined signal 2", /* SIGUSR2 */
+ "Child exited", /* SIGCLD */
+ "Power-fail restart", /* SIGPWR */
+ "Virtual timer expired", /* SIGVTALRM */
+ "Profiling timer expired", /* SIGPROF */
+ "I/O possible", /* SIGIO */
+ "Window size changes", /* SIGWINDOW */
+ "Stopped (signal)", /* SIGSTOP */
+ "Stopped", /* SIGTSTP */
+ "Continued", /* SIGCONT */
+ "Stopped (tty input)", /* SIGTTIN */
+ "Stopped (tty output)", /* SIGTTOU */
+ "Urgent I/O condition", /* SIGURG */
+ "Remote lock lost (NFS)", /* SIGLOST */
+ "Signal 31", /* reserved */
+ "DIL signal" /* SIGDIL */
+};
+
+int
+utimes(file, tvp)
+ char *file;
+ struct timeval tvp[2];
+{
+ struct utimbuf t;
+
+ t.actime = tvp[0].tv_sec;
+ t.modtime = tvp[1].tv_sec;
+ return(utime(file, &t));
+}
+
+
+#endif /* __hpux */
+
+#if defined(sun) && defined(__svr4__)
+#include <signal.h>
+
+/* turn into bsd signals */
+void (*
+signal(s, a)) ()
+ int s;
+ void (*a)();
+{
+ struct sigaction sa, osa;
+
+ sa.sa_handler = a;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+
+ if (sigaction(s, &sa, &osa) == -1)
+ return SIG_ERR;
+ else
+ return osa.sa_handler;
+}
+
+#endif
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c
new file mode 100644
index 0000000..f0d741c
--- /dev/null
+++ b/usr.bin/make/var.c
@@ -0,0 +1,2044 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1989 by Berkeley Softworks
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
+#endif /* not lint */
+
+/*-
+ * var.c --
+ * Variable-handling functions
+ *
+ * Interface:
+ * Var_Set Set the value of a variable in the given
+ * context. The variable is created if it doesn't
+ * yet exist. The value and variable name need not
+ * be preserved.
+ *
+ * Var_Append Append more characters to an existing variable
+ * in the given context. The variable needn't
+ * exist already -- it will be created if it doesn't.
+ * A space is placed between the old value and the
+ * new one.
+ *
+ * Var_Exists See if a variable exists.
+ *
+ * Var_Value Return the value of a variable in a context or
+ * NULL if the variable is undefined.
+ *
+ * Var_Subst Substitute named variable, or all variables if
+ * NULL in a string using
+ * the given context as the top-most one. If the
+ * third argument is non-zero, Parse_Error is
+ * called if any variables are undefined.
+ *
+ * Var_Parse Parse a variable expansion from a string and
+ * return the result and the number of characters
+ * consumed.
+ *
+ * Var_Delete Delete a variable in a context.
+ *
+ * Var_Init Initialize this module.
+ *
+ * Debugging:
+ * Var_Dump Print out all variables defined in the given
+ * context.
+ *
+ * XXX: There's a lot of duplication in these functions.
+ */
+
+#include <ctype.h>
+#include "make.h"
+#include "buf.h"
+
+/*
+ * This is a harmless return value for Var_Parse that can be used by Var_Subst
+ * to determine if there was an error in parsing -- easier than returning
+ * a flag, as things outside this module don't give a hoot.
+ */
+char var_Error[] = "";
+
+/*
+ * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
+ * set false. Why not just use a constant? Well, gcc likes to condense
+ * identical string instances...
+ */
+static char varNoError[] = "";
+
+/*
+ * Internally, variables are contained in four different contexts.
+ * 1) the environment. They may not be changed. If an environment
+ * variable is appended-to, the result is placed in the global
+ * context.
+ * 2) the global context. Variables set in the Makefile are located in
+ * the global context. It is the penultimate context searched when
+ * substituting.
+ * 3) the command-line context. All variables set on the command line
+ * are placed in this context. They are UNALTERABLE once placed here.
+ * 4) the local context. Each target has associated with it a context
+ * list. On this list are located the structures describing such
+ * local variables as $(@) and $(*)
+ * The four contexts are searched in the reverse order from which they are
+ * listed.
+ */
+GNode *VAR_GLOBAL; /* variables from the makefile */
+GNode *VAR_CMD; /* variables defined on the command-line */
+
+static Lst allVars; /* List of all variables */
+
+#define FIND_CMD 0x1 /* look in VAR_CMD when searching */
+#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
+#define FIND_ENV 0x4 /* look in the environment also */
+
+typedef struct Var {
+ char *name; /* the variable's name */
+ Buffer val; /* its value */
+ int flags; /* miscellaneous status flags */
+#define VAR_IN_USE 1 /* Variable's value currently being used.
+ * Used to avoid recursion */
+#define VAR_FROM_ENV 2 /* Variable comes from the environment */
+#define VAR_JUNK 4 /* Variable is a junk variable that
+ * should be destroyed when done with
+ * it. Used by Var_Parse for undefined,
+ * modified variables */
+} Var;
+
+typedef struct {
+ char *lhs; /* String to match */
+ int leftLen; /* Length of string */
+ char *rhs; /* Replacement string (w/ &'s removed) */
+ int rightLen; /* Length of replacement */
+ int flags;
+#define VAR_SUB_GLOBAL 1 /* Apply substitution globally */
+#define VAR_MATCH_START 2 /* Match at start of word */
+#define VAR_MATCH_END 4 /* Match at end of word */
+} VarPattern;
+
+static int VarCmp __P((ClientData, ClientData));
+static Var *VarFind __P((char *, GNode *, int));
+static void VarAdd __P((char *, char *, GNode *));
+static void VarDelete __P((ClientData));
+static Boolean VarHead __P((char *, Boolean, Buffer, ClientData));
+static Boolean VarTail __P((char *, Boolean, Buffer, ClientData));
+static Boolean VarSuffix __P((char *, Boolean, Buffer, ClientData));
+static Boolean VarRoot __P((char *, Boolean, Buffer, ClientData));
+static Boolean VarMatch __P((char *, Boolean, Buffer, ClientData));
+#ifdef SYSVVARSUB
+static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, ClientData));
+#endif
+static Boolean VarNoMatch __P((char *, Boolean, Buffer, ClientData));
+static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData));
+static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer,
+ ClientData),
+ ClientData));
+static int VarPrintVar __P((ClientData, ClientData));
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarCmp --
+ * See if the given variable matches the named one. Called from
+ * Lst_Find when searching for a variable of a given name.
+ *
+ * Results:
+ * 0 if they match. non-zero otherwise.
+ *
+ * Side Effects:
+ * none
+ *-----------------------------------------------------------------------
+ */
+static int
+VarCmp (v, name)
+ ClientData v; /* VAR structure to compare */
+ ClientData name; /* name to look for */
+{
+ return (strcmp ((char *) name, ((Var *) v)->name));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarFind --
+ * Find the given variable in the given context and any other contexts
+ * indicated.
+ *
+ * Results:
+ * A pointer to the structure describing the desired variable or
+ * NIL if the variable does not exist.
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static Var *
+VarFind (name, ctxt, flags)
+ char *name; /* name to find */
+ GNode *ctxt; /* context in which to find it */
+ int flags; /* FIND_GLOBAL set means to look in the
+ * VAR_GLOBAL context as well.
+ * FIND_CMD set means to look in the VAR_CMD
+ * context also.
+ * FIND_ENV set means to look in the
+ * environment */
+{
+ LstNode var;
+ Var *v;
+
+ /*
+ * If the variable name begins with a '.', it could very well be one of
+ * the local ones. We check the name against all the local variables
+ * and substitute the short version in for 'name' if it matches one of
+ * them.
+ */
+ if (*name == '.' && isupper((unsigned char) name[1]))
+ switch (name[1]) {
+ case 'A':
+ if (!strcmp(name, ".ALLSRC"))
+ name = ALLSRC;
+ if (!strcmp(name, ".ARCHIVE"))
+ name = ARCHIVE;
+ break;
+ case 'I':
+ if (!strcmp(name, ".IMPSRC"))
+ name = IMPSRC;
+ break;
+ case 'M':
+ if (!strcmp(name, ".MEMBER"))
+ name = MEMBER;
+ break;
+ case 'O':
+ if (!strcmp(name, ".OODATE"))
+ name = OODATE;
+ break;
+ case 'P':
+ if (!strcmp(name, ".PREFIX"))
+ name = PREFIX;
+ break;
+ case 'T':
+ if (!strcmp(name, ".TARGET"))
+ name = TARGET;
+ break;
+ }
+ /*
+ * First look for the variable in the given context. If it's not there,
+ * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
+ * depending on the FIND_* flags in 'flags'
+ */
+ var = Lst_Find (ctxt->context, (ClientData)name, VarCmp);
+
+ if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
+ var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
+ }
+ if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) &&
+ (ctxt != VAR_GLOBAL))
+ {
+ var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
+ }
+ if ((var == NILLNODE) && (flags & FIND_ENV)) {
+ char *env;
+
+ if ((env = getenv (name)) != NULL) {
+ int len;
+
+ v = (Var *) emalloc(sizeof(Var));
+ v->name = estrdup(name);
+
+ len = strlen(env);
+
+ v->val = Buf_Init(len);
+ Buf_AddBytes(v->val, len, (Byte *)env);
+
+ v->flags = VAR_FROM_ENV;
+ return (v);
+ } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
+ (ctxt != VAR_GLOBAL))
+ {
+ var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
+ if (var == NILLNODE) {
+ return ((Var *) NIL);
+ } else {
+ return ((Var *)Lst_Datum(var));
+ }
+ } else {
+ return((Var *)NIL);
+ }
+ } else if (var == NILLNODE) {
+ return ((Var *) NIL);
+ } else {
+ return ((Var *) Lst_Datum (var));
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarAdd --
+ * Add a new variable of name name and value val to the given context
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The new variable is placed at the front of the given context
+ * The name and val arguments are duplicated so they may
+ * safely be freed.
+ *-----------------------------------------------------------------------
+ */
+static void
+VarAdd (name, val, ctxt)
+ char *name; /* name of variable to add */
+ char *val; /* value to set it to */
+ GNode *ctxt; /* context in which to set it */
+{
+ register Var *v;
+ int len;
+
+ v = (Var *) emalloc (sizeof (Var));
+
+ v->name = estrdup (name);
+
+ len = val ? strlen(val) : 0;
+ v->val = Buf_Init(len+1);
+ Buf_AddBytes(v->val, len, (Byte *)val);
+
+ v->flags = 0;
+
+ (void) Lst_AtFront (ctxt->context, (ClientData)v);
+ (void) Lst_AtEnd (allVars, (ClientData) v);
+ if (DEBUG(VAR)) {
+ printf("%s:%s = %s\n", ctxt->name, name, val);
+ }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarDelete --
+ * Delete a variable and all the space associated with it.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+static void
+VarDelete(vp)
+ ClientData vp;
+{
+ Var *v = (Var *) vp;
+ free(v->name);
+ Buf_Destroy(v->val, TRUE);
+ free((Address) v);
+}
+
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Delete --
+ * Remove a variable from a context.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The Var structure is removed and freed.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+Var_Delete(name, ctxt)
+ char *name;
+ GNode *ctxt;
+{
+ LstNode ln;
+
+ if (DEBUG(VAR)) {
+ printf("%s:delete %s\n", ctxt->name, name);
+ }
+ ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp);
+ if (ln != NILLNODE) {
+ register Var *v;
+
+ v = (Var *)Lst_Datum(ln);
+ Lst_Remove(ctxt->context, ln);
+ ln = Lst_Member(allVars, v);
+ Lst_Remove(allVars, ln);
+ VarDelete((ClientData) v);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Set --
+ * Set the variable name to the value val in the given context.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * If the variable doesn't yet exist, a new record is created for it.
+ * Else the old value is freed and the new one stuck in its place
+ *
+ * Notes:
+ * The variable is searched for only in its context before being
+ * created in that context. I.e. if the context is VAR_GLOBAL,
+ * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
+ * VAR_CMD->context is searched. This is done to avoid the literally
+ * thousands of unnecessary strcmp's that used to be done to
+ * set, say, $(@) or $(<).
+ *-----------------------------------------------------------------------
+ */
+void
+Var_Set (name, val, ctxt)
+ char *name; /* name of variable to set */
+ char *val; /* value to give to the variable */
+ GNode *ctxt; /* context in which to set it */
+{
+ register Var *v;
+
+ /*
+ * We only look for a variable in the given context since anything set
+ * here will override anything in a lower context, so there's not much
+ * point in searching them all just to save a bit of memory...
+ */
+ v = VarFind (name, ctxt, 0);
+ if (v == (Var *) NIL) {
+ VarAdd (name, val, ctxt);
+ } else {
+ Buf_Discard(v->val, Buf_Size(v->val));
+ Buf_AddBytes(v->val, strlen(val), (Byte *)val);
+
+ if (DEBUG(VAR)) {
+ printf("%s:%s = %s\n", ctxt->name, name, val);
+ }
+ }
+ /*
+ * Any variables given on the command line are automatically exported
+ * to the environment (as per POSIX standard)
+ */
+ if (ctxt == VAR_CMD) {
+ setenv(name, val, 1);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Append --
+ * The variable of the given name has the given value appended to it in
+ * the given context.
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * If the variable doesn't exist, it is created. Else the strings
+ * are concatenated (with a space in between).
+ *
+ * Notes:
+ * Only if the variable is being sought in the global context is the
+ * environment searched.
+ * XXX: Knows its calling circumstances in that if called with ctxt
+ * an actual target, it will only search that context since only
+ * a local variable could be being appended to. This is actually
+ * a big win and must be tolerated.
+ *-----------------------------------------------------------------------
+ */
+void
+Var_Append (name, val, ctxt)
+ char *name; /* Name of variable to modify */
+ char *val; /* String to append to it */
+ GNode *ctxt; /* Context in which this should occur */
+{
+ register Var *v;
+
+ v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
+
+ if (v == (Var *) NIL) {
+ VarAdd (name, val, ctxt);
+ } else {
+ Buf_AddByte(v->val, (Byte)' ');
+ Buf_AddBytes(v->val, strlen(val), (Byte *)val);
+
+ if (DEBUG(VAR)) {
+ printf("%s:%s = %s\n", ctxt->name, name,
+ (char *) Buf_GetAll(v->val, (int *)NULL));
+ }
+
+ if (v->flags & VAR_FROM_ENV) {
+ /*
+ * If the original variable came from the environment, we
+ * have to install it in the global context (we could place
+ * it in the environment, but then we should provide a way to
+ * export other variables...)
+ */
+ v->flags &= ~VAR_FROM_ENV;
+ Lst_AtFront(ctxt->context, (ClientData)v);
+ }
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Exists --
+ * See if the given variable exists.
+ *
+ * Results:
+ * TRUE if it does, FALSE if it doesn't
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+Boolean
+Var_Exists(name, ctxt)
+ char *name; /* Variable to find */
+ GNode *ctxt; /* Context in which to start search */
+{
+ Var *v;
+
+ v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
+
+ if (v == (Var *)NIL) {
+ return(FALSE);
+ } else if (v->flags & VAR_FROM_ENV) {
+ free(v->name);
+ Buf_Destroy(v->val, TRUE);
+ free((char *)v);
+ }
+ return(TRUE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Value --
+ * Return the value of the named variable in the given context
+ *
+ * Results:
+ * The value if the variable exists, NULL if it doesn't
+ *
+ * Side Effects:
+ * None
+ *-----------------------------------------------------------------------
+ */
+char *
+Var_Value (name, ctxt, frp)
+ char *name; /* name to find */
+ GNode *ctxt; /* context in which to search for it */
+ char **frp;
+{
+ Var *v;
+
+ v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
+ *frp = NULL;
+ if (v != (Var *) NIL) {
+ char *p = ((char *)Buf_GetAll(v->val, (int *)NULL));
+ if (v->flags & VAR_FROM_ENV) {
+ Buf_Destroy(v->val, FALSE);
+ free((Address) v);
+ *frp = p;
+ }
+ return p;
+ } else {
+ return ((char *) NULL);
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarHead --
+ * Remove the tail of the given word and place the result in the given
+ * buffer.
+ *
+ * Results:
+ * TRUE if characters were added to the buffer (a space needs to be
+ * added to the buffer before the next word).
+ *
+ * Side Effects:
+ * The trimmed word is added to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarHead (word, addSpace, buf, dummy)
+ char *word; /* Word to trim */
+ Boolean addSpace; /* True if need to add a space to the buffer
+ * before sticking in the head */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData dummy;
+{
+ register char *slash;
+
+ slash = strrchr (word, '/');
+ if (slash != (char *)NULL) {
+ if (addSpace) {
+ Buf_AddByte (buf, (Byte)' ');
+ }
+ *slash = '\0';
+ Buf_AddBytes (buf, strlen (word), (Byte *)word);
+ *slash = '/';
+ return (TRUE);
+ } else {
+ /*
+ * If no directory part, give . (q.v. the POSIX standard)
+ */
+ if (addSpace) {
+ Buf_AddBytes(buf, 2, (Byte *)" .");
+ } else {
+ Buf_AddByte(buf, (Byte)'.');
+ }
+ }
+ return(dummy ? TRUE : TRUE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarTail --
+ * Remove the head of the given word and place the result in the given
+ * buffer.
+ *
+ * Results:
+ * TRUE if characters were added to the buffer (a space needs to be
+ * added to the buffer before the next word).
+ *
+ * Side Effects:
+ * The trimmed word is added to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarTail (word, addSpace, buf, dummy)
+ char *word; /* Word to trim */
+ Boolean addSpace; /* TRUE if need to stick a space in the
+ * buffer before adding the tail */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData dummy;
+{
+ register char *slash;
+
+ if (addSpace) {
+ Buf_AddByte (buf, (Byte)' ');
+ }
+
+ slash = strrchr (word, '/');
+ if (slash != (char *)NULL) {
+ *slash++ = '\0';
+ Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
+ slash[-1] = '/';
+ } else {
+ Buf_AddBytes (buf, strlen(word), (Byte *)word);
+ }
+ return (dummy ? TRUE : TRUE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarSuffix --
+ * Place the suffix of the given word in the given buffer.
+ *
+ * Results:
+ * TRUE if characters were added to the buffer (a space needs to be
+ * added to the buffer before the next word).
+ *
+ * Side Effects:
+ * The suffix from the word is placed in the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarSuffix (word, addSpace, buf, dummy)
+ char *word; /* Word to trim */
+ Boolean addSpace; /* TRUE if need to add a space before placing
+ * the suffix in the buffer */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData dummy;
+{
+ register char *dot;
+
+ dot = strrchr (word, '.');
+ if (dot != (char *)NULL) {
+ if (addSpace) {
+ Buf_AddByte (buf, (Byte)' ');
+ }
+ *dot++ = '\0';
+ Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
+ dot[-1] = '.';
+ addSpace = TRUE;
+ }
+ return (dummy ? addSpace : addSpace);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarRoot --
+ * Remove the suffix of the given word and place the result in the
+ * buffer.
+ *
+ * Results:
+ * TRUE if characters were added to the buffer (a space needs to be
+ * added to the buffer before the next word).
+ *
+ * Side Effects:
+ * The trimmed word is added to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarRoot (word, addSpace, buf, dummy)
+ char *word; /* Word to trim */
+ Boolean addSpace; /* TRUE if need to add a space to the buffer
+ * before placing the root in it */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData dummy;
+{
+ register char *dot;
+
+ if (addSpace) {
+ Buf_AddByte (buf, (Byte)' ');
+ }
+
+ dot = strrchr (word, '.');
+ if (dot != (char *)NULL) {
+ *dot = '\0';
+ Buf_AddBytes (buf, strlen (word), (Byte *)word);
+ *dot = '.';
+ } else {
+ Buf_AddBytes (buf, strlen(word), (Byte *)word);
+ }
+ return (dummy ? TRUE : TRUE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarMatch --
+ * Place the word in the buffer if it matches the given pattern.
+ * Callback function for VarModify to implement the :M modifier.
+ *
+ * Results:
+ * TRUE if a space should be placed in the buffer before the next
+ * word.
+ *
+ * Side Effects:
+ * The word may be copied to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarMatch (word, addSpace, buf, pattern)
+ char *word; /* Word to examine */
+ Boolean addSpace; /* TRUE if need to add a space to the
+ * buffer before adding the word, if it
+ * matches */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData pattern; /* Pattern the word must match */
+{
+ if (Str_Match(word, (char *) pattern)) {
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ addSpace = TRUE;
+ Buf_AddBytes(buf, strlen(word), (Byte *)word);
+ }
+ return(addSpace);
+}
+
+#ifdef SYSVVARSUB
+/*-
+ *-----------------------------------------------------------------------
+ * VarSYSVMatch --
+ * Place the word in the buffer if it matches the given pattern.
+ * Callback function for VarModify to implement the System V %
+ * modifiers.
+ *
+ * Results:
+ * TRUE if a space should be placed in the buffer before the next
+ * word.
+ *
+ * Side Effects:
+ * The word may be copied to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarSYSVMatch (word, addSpace, buf, patp)
+ char *word; /* Word to examine */
+ Boolean addSpace; /* TRUE if need to add a space to the
+ * buffer before adding the word, if it
+ * matches */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData patp; /* Pattern the word must match */
+{
+ int len;
+ char *ptr;
+ VarPattern *pat = (VarPattern *) patp;
+
+ if (addSpace)
+ Buf_AddByte(buf, (Byte)' ');
+
+ addSpace = TRUE;
+
+ if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
+ Str_SYSVSubst(buf, pat->rhs, ptr, len);
+ else
+ Buf_AddBytes(buf, strlen(word), (Byte *) word);
+
+ return(addSpace);
+}
+#endif
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarNoMatch --
+ * Place the word in the buffer if it doesn't match the given pattern.
+ * Callback function for VarModify to implement the :N modifier.
+ *
+ * Results:
+ * TRUE if a space should be placed in the buffer before the next
+ * word.
+ *
+ * Side Effects:
+ * The word may be copied to the buffer.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarNoMatch (word, addSpace, buf, pattern)
+ char *word; /* Word to examine */
+ Boolean addSpace; /* TRUE if need to add a space to the
+ * buffer before adding the word, if it
+ * matches */
+ Buffer buf; /* Buffer in which to store it */
+ ClientData pattern; /* Pattern the word must match */
+{
+ if (!Str_Match(word, (char *) pattern)) {
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ addSpace = TRUE;
+ Buf_AddBytes(buf, strlen(word), (Byte *)word);
+ }
+ return(addSpace);
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarSubstitute --
+ * Perform a string-substitution on the given word, placing the
+ * result in the passed buffer.
+ *
+ * Results:
+ * TRUE if a space is needed before more characters are added.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarSubstitute (word, addSpace, buf, patternp)
+ char *word; /* Word to modify */
+ Boolean addSpace; /* True if space should be added before
+ * other characters */
+ Buffer buf; /* Buffer for result */
+ ClientData patternp; /* Pattern for substitution */
+{
+ register int wordLen; /* Length of word */
+ register char *cp; /* General pointer */
+ VarPattern *pattern = (VarPattern *) patternp;
+
+ wordLen = strlen(word);
+ if (1) { /* substitute in each word of the variable */
+ /*
+ * Break substitution down into simple anchored cases
+ * and if none of them fits, perform the general substitution case.
+ */
+ if ((pattern->flags & VAR_MATCH_START) &&
+ (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
+ /*
+ * Anchored at start and beginning of word matches pattern
+ */
+ if ((pattern->flags & VAR_MATCH_END) &&
+ (wordLen == pattern->leftLen)) {
+ /*
+ * Also anchored at end and matches to the end (word
+ * is same length as pattern) add space and rhs only
+ * if rhs is non-null.
+ */
+ if (pattern->rightLen != 0) {
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ addSpace = TRUE;
+ Buf_AddBytes(buf, pattern->rightLen,
+ (Byte *)pattern->rhs);
+ }
+ } else if (pattern->flags & VAR_MATCH_END) {
+ /*
+ * Doesn't match to end -- copy word wholesale
+ */
+ goto nosub;
+ } else {
+ /*
+ * Matches at start but need to copy in trailing characters
+ */
+ if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ addSpace = TRUE;
+ }
+ Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
+ Buf_AddBytes(buf, wordLen - pattern->leftLen,
+ (Byte *)(word + pattern->leftLen));
+ }
+ } else if (pattern->flags & VAR_MATCH_START) {
+ /*
+ * Had to match at start of word and didn't -- copy whole word.
+ */
+ goto nosub;
+ } else if (pattern->flags & VAR_MATCH_END) {
+ /*
+ * Anchored at end, Find only place match could occur (leftLen
+ * characters from the end of the word) and see if it does. Note
+ * that because the $ will be left at the end of the lhs, we have
+ * to use strncmp.
+ */
+ cp = word + (wordLen - pattern->leftLen);
+ if ((cp >= word) &&
+ (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
+ /*
+ * Match found. If we will place characters in the buffer,
+ * add a space before hand as indicated by addSpace, then
+ * stuff in the initial, unmatched part of the word followed
+ * by the right-hand-side.
+ */
+ if (((cp - word) + pattern->rightLen) != 0) {
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ addSpace = TRUE;
+ }
+ Buf_AddBytes(buf, cp - word, (Byte *)word);
+ Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
+ } else {
+ /*
+ * Had to match at end and didn't. Copy entire word.
+ */
+ goto nosub;
+ }
+ } else {
+ /*
+ * Pattern is unanchored: search for the pattern in the word using
+ * String_FindSubstring, copying unmatched portions and the
+ * right-hand-side for each match found, handling non-global
+ * substitutions correctly, etc. When the loop is done, any
+ * remaining part of the word (word and wordLen are adjusted
+ * accordingly through the loop) is copied straight into the
+ * buffer.
+ * addSpace is set FALSE as soon as a space is added to the
+ * buffer.
+ */
+ register Boolean done;
+ int origSize;
+
+ done = FALSE;
+ origSize = Buf_Size(buf);
+ while (!done) {
+ cp = Str_FindSubstring(word, pattern->lhs);
+ if (cp != (char *)NULL) {
+ if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
+ Buf_AddByte(buf, (Byte)' ');
+ addSpace = FALSE;
+ }
+ Buf_AddBytes(buf, cp-word, (Byte *)word);
+ Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
+ wordLen -= (cp - word) + pattern->leftLen;
+ word = cp + pattern->leftLen;
+ if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
+ done = TRUE;
+ }
+ } else {
+ done = TRUE;
+ }
+ }
+ if (wordLen != 0) {
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ Buf_AddBytes(buf, wordLen, (Byte *)word);
+ }
+ /*
+ * If added characters to the buffer, need to add a space
+ * before we add any more. If we didn't add any, just return
+ * the previous value of addSpace.
+ */
+ return ((Buf_Size(buf) != origSize) || addSpace);
+ }
+ /*
+ * Common code for anchored substitutions:
+ * addSpace was set TRUE if characters were added to the buffer.
+ */
+ return (addSpace);
+ }
+ nosub:
+ if (addSpace) {
+ Buf_AddByte(buf, (Byte)' ');
+ }
+ Buf_AddBytes(buf, wordLen, (Byte *)word);
+ return(TRUE);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * VarModify --
+ * Modify each of the words of the passed string using the given
+ * function. Used to implement all modifiers.
+ *
+ * Results:
+ * A string of all the words modified appropriately.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static char *
+VarModify (str, modProc, datum)
+ char *str; /* String whose words should be trimmed */
+ /* Function to use to modify them */
+ Boolean (*modProc) __P((char *, Boolean, Buffer, ClientData));
+ ClientData datum; /* Datum to pass it */
+{
+ Buffer buf; /* Buffer for the new string */
+ Boolean addSpace; /* TRUE if need to add a space to the
+ * buffer before adding the trimmed
+ * word */
+ char **av; /* word list [first word does not count] */
+ int ac, i;
+
+ buf = Buf_Init (0);
+ addSpace = FALSE;
+
+ av = brk_string(str, &ac, FALSE);
+
+ for (i = 1; i < ac; i++)
+ addSpace = (*modProc)(av[i], addSpace, buf, datum);
+
+ Buf_AddByte (buf, '\0');
+ str = (char *)Buf_GetAll (buf, (int *)NULL);
+ Buf_Destroy (buf, FALSE);
+ return (str);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Parse --
+ * Given the start of a variable invocation, extract the variable
+ * name and find its value, then modify it according to the
+ * specification.
+ *
+ * Results:
+ * The (possibly-modified) value of the variable or var_Error if the
+ * specification is invalid. The length of the specification is
+ * placed in *lengthPtr (for invalid specifications, this is just
+ * 2...?).
+ * A Boolean in *freePtr telling whether the returned string should
+ * be freed by the caller.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+char *
+Var_Parse (str, ctxt, err, lengthPtr, freePtr)
+ char *str; /* The string to parse */
+ GNode *ctxt; /* The context for the variable */
+ Boolean err; /* TRUE if undefined variables are an error */
+ int *lengthPtr; /* OUT: The length of the specification */
+ Boolean *freePtr; /* OUT: TRUE if caller should free result */
+{
+ register char *tstr; /* Pointer into str */
+ Var *v; /* Variable in invocation */
+ register char *cp; /* Secondary pointer into str (place marker
+ * for tstr) */
+ Boolean haveModifier;/* TRUE if have modifiers for the variable */
+ register char endc; /* Ending character when variable in parens
+ * or braces */
+ register char startc=0; /* Starting character when variable in parens
+ * or braces */
+ int cnt; /* Used to count brace pairs when variable in
+ * in parens or braces */
+ char *start;
+ Boolean dynamic; /* TRUE if the variable is local and we're
+ * expanding it in a non-local context. This
+ * is done to support dynamic sources. The
+ * result is just the invocation, unaltered */
+
+ *freePtr = FALSE;
+ dynamic = FALSE;
+ start = str;
+
+ if (str[1] != '(' && str[1] != '{') {
+ /*
+ * If it's not bounded by braces of some sort, life is much simpler.
+ * We just need to check for the first character and return the
+ * value if it exists.
+ */
+ char name[2];
+
+ name[0] = str[1];
+ name[1] = '\0';
+
+ v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
+ if (v == (Var *)NIL) {
+ *lengthPtr = 2;
+
+ if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
+ /*
+ * If substituting a local variable in a non-local context,
+ * assume it's for dynamic source stuff. We have to handle
+ * this specially and return the longhand for the variable
+ * with the dollar sign escaped so it makes it back to the
+ * caller. Only four of the local variables are treated
+ * specially as they are the only four that will be set
+ * when dynamic sources are expanded.
+ */
+ switch (str[1]) {
+ case '@':
+ return("$(.TARGET)");
+ case '%':
+ return("$(.ARCHIVE)");
+ case '*':
+ return("$(.PREFIX)");
+ case '!':
+ return("$(.MEMBER)");
+ }
+ }
+ /*
+ * Error
+ */
+ return (err ? var_Error : varNoError);
+ } else {
+ haveModifier = FALSE;
+ tstr = &str[1];
+ endc = str[1];
+ }
+ } else {
+ startc = str[1];
+ endc = startc == '(' ? ')' : '}';
+
+ /*
+ * Skip to the end character or a colon, whichever comes first.
+ */
+ for (tstr = str + 2;
+ *tstr != '\0' && *tstr != endc && *tstr != ':';
+ tstr++)
+ {
+ continue;
+ }
+ if (*tstr == ':') {
+ haveModifier = TRUE;
+ } else if (*tstr != '\0') {
+ haveModifier = FALSE;
+ } else {
+ /*
+ * If we never did find the end character, return NULL
+ * right now, setting the length to be the distance to
+ * the end of the string, since that's what make does.
+ */
+ *lengthPtr = tstr - str;
+ return (var_Error);
+ }
+ *tstr = '\0';
+
+ v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
+ if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
+ ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D'))
+ {
+ /*
+ * Check for bogus D and F forms of local variables since we're
+ * in a local context and the name is the right length.
+ */
+ switch(str[2]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ case '>':
+ case '<':
+ {
+ char vname[2];
+ char *val;
+
+ /*
+ * Well, it's local -- go look for it.
+ */
+ vname[0] = str[2];
+ vname[1] = '\0';
+ v = VarFind(vname, ctxt, 0);
+
+ if (v != (Var *)NIL) {
+ /*
+ * No need for nested expansion or anything, as we're
+ * the only one who sets these things and we sure don't
+ * but nested invocations in them...
+ */
+ val = (char *)Buf_GetAll(v->val, (int *)NULL);
+
+ if (str[3] == 'D') {
+ val = VarModify(val, VarHead, (ClientData)0);
+ } else {
+ val = VarModify(val, VarTail, (ClientData)0);
+ }
+ /*
+ * Resulting string is dynamically allocated, so
+ * tell caller to free it.
+ */
+ *freePtr = TRUE;
+ *lengthPtr = tstr-start+1;
+ *tstr = endc;
+ return(val);
+ }
+ break;
+ }
+ }
+ }
+
+ if (v == (Var *)NIL) {
+ if ((((tstr-str) == 3) ||
+ ((((tstr-str) == 4) && (str[3] == 'F' ||
+ str[3] == 'D')))) &&
+ ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
+ {
+ /*
+ * If substituting a local variable in a non-local context,
+ * assume it's for dynamic source stuff. We have to handle
+ * this specially and return the longhand for the variable
+ * with the dollar sign escaped so it makes it back to the
+ * caller. Only four of the local variables are treated
+ * specially as they are the only four that will be set
+ * when dynamic sources are expanded.
+ */
+ switch (str[2]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ dynamic = TRUE;
+ break;
+ }
+ } else if (((tstr-str) > 4) && (str[2] == '.') &&
+ isupper((unsigned char) str[3]) &&
+ ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
+ {
+ int len;
+
+ len = (tstr-str) - 3;
+ if ((strncmp(str+2, ".TARGET", len) == 0) ||
+ (strncmp(str+2, ".ARCHIVE", len) == 0) ||
+ (strncmp(str+2, ".PREFIX", len) == 0) ||
+ (strncmp(str+2, ".MEMBER", len) == 0))
+ {
+ dynamic = TRUE;
+ }
+ }
+
+ if (!haveModifier) {
+ /*
+ * No modifiers -- have specification length so we can return
+ * now.
+ */
+ *lengthPtr = tstr - start + 1;
+ *tstr = endc;
+ if (dynamic) {
+ str = emalloc(*lengthPtr + 1);
+ strncpy(str, start, *lengthPtr);
+ str[*lengthPtr] = '\0';
+ *freePtr = TRUE;
+ return(str);
+ } else {
+ return (err ? var_Error : varNoError);
+ }
+ } else {
+ /*
+ * Still need to get to the end of the variable specification,
+ * so kludge up a Var structure for the modifications
+ */
+ v = (Var *) emalloc(sizeof(Var));
+ v->name = &str[1];
+ v->val = Buf_Init(1);
+ v->flags = VAR_JUNK;
+ }
+ }
+ }
+
+ if (v->flags & VAR_IN_USE) {
+ Fatal("Variable %s is recursive.", v->name);
+ /*NOTREACHED*/
+ } else {
+ v->flags |= VAR_IN_USE;
+ }
+ /*
+ * Before doing any modification, we have to make sure the value
+ * has been fully expanded. If it looks like recursion might be
+ * necessary (there's a dollar sign somewhere in the variable's value)
+ * we just call Var_Subst to do any other substitutions that are
+ * necessary. Note that the value returned by Var_Subst will have
+ * been dynamically-allocated, so it will need freeing when we
+ * return.
+ */
+ str = (char *)Buf_GetAll(v->val, (int *)NULL);
+ if (strchr (str, '$') != (char *)NULL) {
+ str = Var_Subst(NULL, str, ctxt, err);
+ *freePtr = TRUE;
+ }
+
+ v->flags &= ~VAR_IN_USE;
+
+ /*
+ * Now we need to apply any modifiers the user wants applied.
+ * These are:
+ * :M<pattern> words which match the given <pattern>.
+ * <pattern> is of the standard file
+ * wildcarding form.
+ * :S<d><pat1><d><pat2><d>[g]
+ * Substitute <pat2> for <pat1> in the value
+ * :H Substitute the head of each word
+ * :T Substitute the tail of each word
+ * :E Substitute the extension (minus '.') of
+ * each word
+ * :R Substitute the root of each word
+ * (pathname minus the suffix).
+ * :lhs=rhs Like :S, but the rhs goes to the end of
+ * the invocation.
+ */
+ if ((str != (char *)NULL) && haveModifier) {
+ /*
+ * Skip initial colon while putting it back.
+ */
+ *tstr++ = ':';
+ while (*tstr != endc) {
+ char *newStr; /* New value to return */
+ char termc; /* Character which terminated scan */
+
+ if (DEBUG(VAR)) {
+ printf("Applying :%c to \"%s\"\n", *tstr, str);
+ }
+ switch (*tstr) {
+ case 'N':
+ case 'M':
+ {
+ char *pattern;
+ char *cp2;
+ Boolean copy;
+
+ copy = FALSE;
+ for (cp = tstr + 1;
+ *cp != '\0' && *cp != ':' && *cp != endc;
+ cp++)
+ {
+ if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
+ copy = TRUE;
+ cp++;
+ }
+ }
+ termc = *cp;
+ *cp = '\0';
+ if (copy) {
+ /*
+ * Need to compress the \:'s out of the pattern, so
+ * allocate enough room to hold the uncompressed
+ * pattern (note that cp started at tstr+1, so
+ * cp - tstr takes the null byte into account) and
+ * compress the pattern into the space.
+ */
+ pattern = emalloc(cp - tstr);
+ for (cp2 = pattern, cp = tstr + 1;
+ *cp != '\0';
+ cp++, cp2++)
+ {
+ if ((*cp == '\\') &&
+ (cp[1] == ':' || cp[1] == endc)) {
+ cp++;
+ }
+ *cp2 = *cp;
+ }
+ *cp2 = '\0';
+ } else {
+ pattern = &tstr[1];
+ }
+ if (*tstr == 'M' || *tstr == 'm') {
+ newStr = VarModify(str, VarMatch, (ClientData)pattern);
+ } else {
+ newStr = VarModify(str, VarNoMatch,
+ (ClientData)pattern);
+ }
+ if (copy) {
+ free(pattern);
+ }
+ break;
+ }
+ case 'S':
+ {
+ VarPattern pattern;
+ register char delim;
+ Buffer buf; /* Buffer for patterns */
+
+ pattern.flags = 0;
+ delim = tstr[1];
+ tstr += 2;
+ /*
+ * If pattern begins with '^', it is anchored to the
+ * start of the word -- skip over it and flag pattern.
+ */
+ if (*tstr == '^') {
+ pattern.flags |= VAR_MATCH_START;
+ tstr += 1;
+ }
+
+ buf = Buf_Init(0);
+
+ /*
+ * Pass through the lhs looking for 1) escaped delimiters,
+ * '$'s and backslashes (place the escaped character in
+ * uninterpreted) and 2) unescaped $'s that aren't before
+ * the delimiter (expand the variable substitution).
+ * The result is left in the Buffer buf.
+ */
+ for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
+ if ((*cp == '\\') &&
+ ((cp[1] == delim) ||
+ (cp[1] == '$') ||
+ (cp[1] == '\\')))
+ {
+ Buf_AddByte(buf, (Byte)cp[1]);
+ cp++;
+ } else if (*cp == '$') {
+ if (cp[1] != delim) {
+ /*
+ * If unescaped dollar sign not before the
+ * delimiter, assume it's a variable
+ * substitution and recurse.
+ */
+ char *cp2;
+ int len;
+ Boolean freeIt;
+
+ cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
+ Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
+ if (freeIt) {
+ free(cp2);
+ }
+ cp += len - 1;
+ } else {
+ /*
+ * Unescaped $ at end of pattern => anchor
+ * pattern at end.
+ */
+ pattern.flags |= VAR_MATCH_END;
+ }
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ }
+ }
+
+ Buf_AddByte(buf, (Byte)'\0');
+
+ /*
+ * If lhs didn't end with the delimiter, complain and
+ * return NULL
+ */
+ if (*cp != delim) {
+ *lengthPtr = cp - start + 1;
+ if (*freePtr) {
+ free(str);
+ }
+ Buf_Destroy(buf, TRUE);
+ Error("Unclosed substitution for %s (%c missing)",
+ v->name, delim);
+ return (var_Error);
+ }
+
+ /*
+ * Fetch pattern and destroy buffer, but preserve the data
+ * in it, since that's our lhs. Note that Buf_GetAll
+ * will return the actual number of bytes, which includes
+ * the null byte, so we have to decrement the length by
+ * one.
+ */
+ pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
+ pattern.leftLen--;
+ Buf_Destroy(buf, FALSE);
+
+ /*
+ * Now comes the replacement string. Three things need to
+ * be done here: 1) need to compress escaped delimiters and
+ * ampersands and 2) need to replace unescaped ampersands
+ * with the l.h.s. (since this isn't regexp, we can do
+ * it right here) and 3) expand any variable substitutions.
+ */
+ buf = Buf_Init(0);
+
+ tstr = cp + 1;
+ for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
+ if ((*cp == '\\') &&
+ ((cp[1] == delim) ||
+ (cp[1] == '&') ||
+ (cp[1] == '\\') ||
+ (cp[1] == '$')))
+ {
+ Buf_AddByte(buf, (Byte)cp[1]);
+ cp++;
+ } else if ((*cp == '$') && (cp[1] != delim)) {
+ char *cp2;
+ int len;
+ Boolean freeIt;
+
+ cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
+ Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
+ cp += len - 1;
+ if (freeIt) {
+ free(cp2);
+ }
+ } else if (*cp == '&') {
+ Buf_AddBytes(buf, pattern.leftLen,
+ (Byte *)pattern.lhs);
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ }
+ }
+
+ Buf_AddByte(buf, (Byte)'\0');
+
+ /*
+ * If didn't end in delimiter character, complain
+ */
+ if (*cp != delim) {
+ *lengthPtr = cp - start + 1;
+ if (*freePtr) {
+ free(str);
+ }
+ Buf_Destroy(buf, TRUE);
+ Error("Unclosed substitution for %s (%c missing)",
+ v->name, delim);
+ return (var_Error);
+ }
+
+ pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
+ pattern.rightLen--;
+ Buf_Destroy(buf, FALSE);
+
+ /*
+ * Check for global substitution. If 'g' after the final
+ * delimiter, substitution is global and is marked that
+ * way.
+ */
+ cp++;
+ if (*cp == 'g') {
+ pattern.flags |= VAR_SUB_GLOBAL;
+ cp++;
+ }
+
+ termc = *cp;
+ newStr = VarModify(str, VarSubstitute,
+ (ClientData)&pattern);
+ /*
+ * Free the two strings.
+ */
+ free(pattern.lhs);
+ free(pattern.rhs);
+ break;
+ }
+ case 'T':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify (str, VarTail, (ClientData)0);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ /*FALLTHRU*/
+ case 'H':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify (str, VarHead, (ClientData)0);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ /*FALLTHRU*/
+ case 'E':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify (str, VarSuffix, (ClientData)0);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ /*FALLTHRU*/
+ case 'R':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify (str, VarRoot, (ClientData)0);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ /*FALLTHRU*/
+#ifdef SUNSHCMD
+ case 's':
+ if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
+ char *err;
+ newStr = Cmd_Exec (str, &err);
+ if (err)
+ Error (err, str);
+ cp = tstr + 2;
+ termc = *cp;
+ break;
+ }
+ /*FALLTHRU*/
+#endif
+ default:
+ {
+#ifdef SYSVVARSUB
+ /*
+ * This can either be a bogus modifier or a System-V
+ * substitution command.
+ */
+ VarPattern pattern;
+ Boolean eqFound;
+
+ pattern.flags = 0;
+ eqFound = FALSE;
+ /*
+ * First we make a pass through the string trying
+ * to verify it is a SYSV-make-style translation:
+ * it must be: <string1>=<string2>)
+ */
+ cp = tstr;
+ cnt = 1;
+ while (*cp != '\0' && cnt) {
+ if (*cp == '=') {
+ eqFound = TRUE;
+ /* continue looking for endc */
+ }
+ else if (*cp == endc)
+ cnt--;
+ else if (*cp == startc)
+ cnt++;
+ if (cnt)
+ cp++;
+ }
+ if (*cp == endc && eqFound) {
+
+ /*
+ * Now we break this sucker into the lhs and
+ * rhs. We must null terminate them of course.
+ */
+ for (cp = tstr; *cp != '='; cp++)
+ continue;
+ pattern.lhs = tstr;
+ pattern.leftLen = cp - tstr;
+ *cp++ = '\0';
+
+ pattern.rhs = cp;
+ cnt = 1;
+ while (cnt) {
+ if (*cp == endc)
+ cnt--;
+ else if (*cp == startc)
+ cnt++;
+ if (cnt)
+ cp++;
+ }
+ pattern.rightLen = cp - pattern.rhs;
+ *cp = '\0';
+
+ /*
+ * SYSV modifications happen through the whole
+ * string. Note the pattern is anchored at the end.
+ */
+ newStr = VarModify(str, VarSYSVMatch,
+ (ClientData)&pattern);
+
+ /*
+ * Restore the nulled characters
+ */
+ pattern.lhs[pattern.leftLen] = '=';
+ pattern.rhs[pattern.rightLen] = endc;
+ termc = endc;
+ } else
+#endif
+ {
+ Error ("Unknown modifier '%c'\n", *tstr);
+ for (cp = tstr+1;
+ *cp != ':' && *cp != endc && *cp != '\0';
+ cp++)
+ continue;
+ termc = *cp;
+ newStr = var_Error;
+ }
+ }
+ }
+ if (DEBUG(VAR)) {
+ printf("Result is \"%s\"\n", newStr);
+ }
+
+ if (*freePtr) {
+ free (str);
+ }
+ str = newStr;
+ if (str != var_Error) {
+ *freePtr = TRUE;
+ } else {
+ *freePtr = FALSE;
+ }
+ if (termc == '\0') {
+ Error("Unclosed variable specification for %s", v->name);
+ } else if (termc == ':') {
+ *cp++ = termc;
+ } else {
+ *cp = termc;
+ }
+ tstr = cp;
+ }
+ *lengthPtr = tstr - start + 1;
+ } else {
+ *lengthPtr = tstr - start + 1;
+ *tstr = endc;
+ }
+
+ if (v->flags & VAR_FROM_ENV) {
+ Boolean destroy = FALSE;
+
+ if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
+ destroy = TRUE;
+ } else {
+ /*
+ * Returning the value unmodified, so tell the caller to free
+ * the thing.
+ */
+ *freePtr = TRUE;
+ }
+ Buf_Destroy(v->val, destroy);
+ free((Address)v);
+ } else if (v->flags & VAR_JUNK) {
+ /*
+ * Perform any free'ing needed and set *freePtr to FALSE so the caller
+ * doesn't try to free a static pointer.
+ */
+ if (*freePtr) {
+ free(str);
+ }
+ *freePtr = FALSE;
+ Buf_Destroy(v->val, TRUE);
+ free((Address)v);
+ if (dynamic) {
+ str = emalloc(*lengthPtr + 1);
+ strncpy(str, start, *lengthPtr);
+ str[*lengthPtr] = '\0';
+ *freePtr = TRUE;
+ } else {
+ str = var_Error;
+ }
+ }
+ return (str);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Subst --
+ * Substitute for all variables in the given string in the given context
+ * If undefErr is TRUE, Parse_Error will be called when an undefined
+ * variable is encountered.
+ *
+ * Results:
+ * The resulting string.
+ *
+ * Side Effects:
+ * None. The old string must be freed by the caller
+ *-----------------------------------------------------------------------
+ */
+char *
+Var_Subst (var, str, ctxt, undefErr)
+ char *var; /* Named variable || NULL for all */
+ char *str; /* the string in which to substitute */
+ GNode *ctxt; /* the context wherein to find variables */
+ Boolean undefErr; /* TRUE if undefineds are an error */
+{
+ Buffer buf; /* Buffer for forming things */
+ char *val; /* Value to substitute for a variable */
+ int length; /* Length of the variable invocation */
+ Boolean doFree; /* Set true if val should be freed */
+ static Boolean errorReported; /* Set true if an error has already
+ * been reported to prevent a plethora
+ * of messages when recursing */
+
+ buf = Buf_Init (MAKE_BSIZE);
+ errorReported = FALSE;
+
+ while (*str) {
+ if (var == NULL && (*str == '$') && (str[1] == '$')) {
+ /*
+ * A dollar sign may be escaped either with another dollar sign.
+ * In such a case, we skip over the escape character and store the
+ * dollar sign into the buffer directly.
+ */
+ str++;
+ Buf_AddByte(buf, (Byte)*str);
+ str++;
+ } else if (*str != '$') {
+ /*
+ * Skip as many characters as possible -- either to the end of
+ * the string or to the next dollar sign (variable invocation).
+ */
+ char *cp;
+
+ for (cp = str++; *str != '$' && *str != '\0'; str++)
+ continue;
+ Buf_AddBytes(buf, str - cp, (Byte *)cp);
+ } else {
+ if (var != NULL) {
+ int expand;
+ for (;;) {
+ if (str[1] != '(' && str[1] != '{') {
+ if (str[1] != *var) {
+ Buf_AddBytes(buf, 2, (Byte *) str);
+ str += 2;
+ expand = FALSE;
+ }
+ else
+ expand = TRUE;
+ break;
+ }
+ else {
+ char *p;
+
+ /*
+ * Scan up to the end of the variable name.
+ */
+ for (p = &str[2]; *p &&
+ *p != ':' && *p != ')' && *p != '}'; p++)
+ if (*p == '$')
+ break;
+ /*
+ * A variable inside the variable. We cannot expand
+ * the external variable yet, so we try again with
+ * the nested one
+ */
+ if (*p == '$') {
+ Buf_AddBytes(buf, p - str, (Byte *) str);
+ str = p;
+ continue;
+ }
+
+ if (strncmp(var, str + 2, p - str - 2) != 0 ||
+ var[p - str - 2] != '\0') {
+ /*
+ * Not the variable we want to expand, scan
+ * until the next variable
+ */
+ for (;*p != '$' && *p != '\0'; p++)
+ continue;
+ Buf_AddBytes(buf, p - str, (Byte *) str);
+ str = p;
+ expand = FALSE;
+ }
+ else
+ expand = TRUE;
+ break;
+ }
+ }
+ if (!expand)
+ continue;
+ }
+
+ val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
+
+ /*
+ * When we come down here, val should either point to the
+ * value of this variable, suitably modified, or be NULL.
+ * Length should be the total length of the potential
+ * variable invocation (from $ to end character...)
+ */
+ if (val == var_Error || val == varNoError) {
+ /*
+ * If performing old-time variable substitution, skip over
+ * the variable and continue with the substitution. Otherwise,
+ * store the dollar sign and advance str so we continue with
+ * the string...
+ */
+ if (oldVars) {
+ str += length;
+ } else if (undefErr) {
+ /*
+ * If variable is undefined, complain and skip the
+ * variable. The complaint will stop us from doing anything
+ * when the file is parsed.
+ */
+ if (!errorReported) {
+ Parse_Error (PARSE_FATAL,
+ "Undefined variable \"%.*s\"",length,str);
+ }
+ str += length;
+ errorReported = TRUE;
+ } else {
+ Buf_AddByte (buf, (Byte)*str);
+ str += 1;
+ }
+ } else {
+ /*
+ * We've now got a variable structure to store in. But first,
+ * advance the string pointer.
+ */
+ str += length;
+
+ /*
+ * Copy all the characters from the variable value straight
+ * into the new string.
+ */
+ Buf_AddBytes (buf, strlen (val), (Byte *)val);
+ if (doFree) {
+ free ((Address)val);
+ }
+ }
+ }
+ }
+
+ Buf_AddByte (buf, '\0');
+ str = (char *)Buf_GetAll (buf, (int *)NULL);
+ Buf_Destroy (buf, FALSE);
+ return (str);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_GetTail --
+ * Return the tail from each of a list of words. Used to set the
+ * System V local variables.
+ *
+ * Results:
+ * The resulting string.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+char *
+Var_GetTail(file)
+ char *file; /* Filename to modify */
+{
+ return(VarModify(file, VarTail, (ClientData)0));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_GetHead --
+ * Find the leading components of a (list of) filename(s).
+ * XXX: VarHead does not replace foo by ., as (sun) System V make
+ * does.
+ *
+ * Results:
+ * The leading components.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+char *
+Var_GetHead(file)
+ char *file; /* Filename to manipulate */
+{
+ return(VarModify(file, VarHead, (ClientData)0));
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Init --
+ * Initialize the module
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * The VAR_CMD and VAR_GLOBAL contexts are created
+ *-----------------------------------------------------------------------
+ */
+void
+Var_Init ()
+{
+ VAR_GLOBAL = Targ_NewGN ("Global");
+ VAR_CMD = Targ_NewGN ("Command");
+ allVars = Lst_Init(FALSE);
+
+}
+
+
+void
+Var_End ()
+{
+ Lst_Destroy(allVars, VarDelete);
+}
+
+
+/****************** PRINT DEBUGGING INFO *****************/
+static int
+VarPrintVar (vp, dummy)
+ ClientData vp;
+ ClientData dummy;
+{
+ Var *v = (Var *) vp;
+ printf ("%-16s = %s\n", v->name, (char *) Buf_GetAll(v->val, (int *)NULL));
+ return (dummy ? 0 : 0);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * Var_Dump --
+ * print all variables in a context
+ *-----------------------------------------------------------------------
+ */
+void
+Var_Dump (ctxt)
+ GNode *ctxt;
+{
+ Lst_ForEach (ctxt->context, VarPrintVar, (ClientData) 0);
+}
diff --git a/usr.bin/makewhatis/makewhatis.local.8 b/usr.bin/makewhatis/makewhatis.local.8
new file mode 100644
index 0000000..b7fd62f
--- /dev/null
+++ b/usr.bin/makewhatis/makewhatis.local.8
@@ -0,0 +1,70 @@
+.\" Copyright (c) April 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: makewhatis.local.8,v 1.5 1997/02/22 15:47:02 peter Exp $
+.Dd April 26, 1996
+.Dt MAKEWHATIS.LOCAL 8
+.Os FreeBSD 2.2
+.Sh NAME
+.Nm makewhatis.local , catman.local
+.Nd start makewhatis for local file systems
+.Sh SYNOPSIS
+.Nm /usr/libexec/makewhatis.local
+.Op options
+.Ar directories ...
+.Nm /usr/libexec/catman.local
+.Op options
+.Ar directories ...
+.Sh DESCRIPTION
+.Nm
+start
+.Xr makewhatis 1
+only for file systems physically mounted on the system
+where the
+.Nm
+is being executed. Running makewhatis
+from
+.Pa /etc/weekly
+for rw nfs-mounted /usr may kill
+your NFS server -- all NFS clients start makewhatis at the same time!
+So use this wrapper for
+.Xr cron 8
+instead of calling makewhatis directly.
+.Sh FILES
+.Bl -tag -width /etc/weekly.XXX -compact
+.It Pa /etc/weekly
+run
+.Nm
+every week
+.El
+.Sh SEE ALSO
+.Xr catman 1 ,
+.Xr find 1 ,
+.Xr makewhatis 1 ,
+.Xr cron 8 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.2 .
diff --git a/usr.bin/makewhatis/makewhatis.local.sh b/usr.bin/makewhatis/makewhatis.local.sh
new file mode 100644
index 0000000..9ad997b
--- /dev/null
+++ b/usr.bin/makewhatis/makewhatis.local.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# Copyright (c) April 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# makewhatis.local - start makewhatis(1) only for file systems
+# physically mounted on the system
+#
+# Running makewhatis from /etc/weekly for rw nfs-mounted /usr may kill
+# your NFS server -- all clients start makewhatis at the same time!
+# So use this wrapper instead calling makewhatis directly.
+#
+# PS: this wrapper works also for catman(1)
+#
+# $Id$
+
+PATH=/bin:/usr/bin:$PATH; export PATH
+opt= dirs= localdirs=
+
+for arg
+do
+ case "$arg" in
+ -*) opt="$opt $arg";;
+ *) dirs="$dirs $arg";;
+ esac
+done
+
+dirs=`echo $dirs | sed 's/:/ /g'`
+case X"$dirs" in X) echo "usage: $0 [options] directories ..."; exit 1;; esac
+
+localdirs=`find -H $dirs -fstype local -type d -prune -print`
+
+case X"$localdirs" in
+ X) echo "$0: no local-mounted manual directories found: $dirs"
+ exit 1;;
+ *) exec `basename $0 .local` $opt $localdirs;;
+esac
diff --git a/usr.bin/mesg/mesg.1 b/usr.bin/mesg/mesg.1
index 70e29a9..7e96c55 100644
--- a/usr.bin/mesg/mesg.1
+++ b/usr.bin/mesg/mesg.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)mesg.1 8.1 (Berkeley) 6/6/93
+.\" $Id: mesg.1,v 1.4 1997/02/22 19:56:08 peter Exp $
.\"
.Dd June 6, 1993
.Dt MESG 1
@@ -73,7 +74,7 @@ utility exits with one of the following values:
Messages are allowed.
.It Li "\ 1"
Messages are not allowed.
-.It Li "\>1"
+.It Li ">1"
An error has occurred.
.El
.Sh FILES
@@ -88,4 +89,4 @@ An error has occurred.
A
.Nm mesg
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/mesg/mesg.c b/usr.bin/mesg/mesg.c
index ad666f7..96906c6 100644
--- a/usr.bin/mesg/mesg.c
+++ b/usr.bin/mesg/mesg.c
@@ -65,7 +65,7 @@ main(argc, argv)
char *tty;
int ch;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch (ch) {
case '?':
default:
diff --git a/usr.bin/mk_cmds/Makefile b/usr.bin/mk_cmds/Makefile
new file mode 100644
index 0000000..a240c05
--- /dev/null
+++ b/usr.bin/mk_cmds/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+
+PROG= mk_cmds
+#
+# NB: ct.c must come before cmd_tbl.c so that y.tab.h will be generated.
+#
+SRCS= mk_cmds.c options.c utils.c ct.c cmd_tbl.c
+CFLAGS+= -I. -I${.CURDIR}/../../lib/libss -DIN_MK_CMDS
+LFLAGS= -l
+CLEANFILES+= y.tab.c y.tab.h lex.yy.c cmd_tbl.c ct.c
+NOMAN= # XXX
+
+LDADD+= -ll
+DPADD+= ${LIBL}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/mk_cmds/cmd_tbl.l b/usr.bin/mk_cmds/cmd_tbl.l
new file mode 100644
index 0000000..0c615ce
--- /dev/null
+++ b/usr.bin/mk_cmds/cmd_tbl.l
@@ -0,0 +1,79 @@
+%{
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board.
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include <string.h>
+#include "y.tab.h"
+#include "copyright.h"
+
+extern char *last_token, *ds();
+
+static int l_command_table()
+{
+ last_token = "command_table";
+ return COMMAND_TABLE;
+}
+
+static int l_request()
+{
+ last_token = "request";
+ return REQUEST;
+}
+
+static int l_unimplemented()
+{
+ last_token = "unimplemented";
+ return UNIMPLEMENTED;
+}
+
+static int l_end()
+{
+ last_token = "end";
+ return END;
+}
+
+static int l_quoted_string()
+{
+ register char *p;
+ yylval.dynstr = ds(yytext+1);
+ if ( (p=rindex(yylval.dynstr, '"')) )
+ *p='\0';
+ last_token = ds(yylval.dynstr);
+ return STRING;
+}
+
+static int l_string()
+{
+ yylval.dynstr = ds(yytext);
+ last_token = ds(yylval.dynstr);
+ return STRING;
+}
+
+
+%}
+
+N [0-9]
+PC [^\"]
+AN [A-Z_a-z0-9]
+%%
+
+command_table return l_command_table();
+request return l_request();
+unimplemented return l_unimplemented();
+end return l_end();
+
+[\t\n ] ;
+
+\"{PC}*\" return l_quoted_string();
+
+{AN}* return l_string();
+
+#.*\n ;
+
+. return (*yytext);
+
+%%
+
diff --git a/usr.bin/mk_cmds/copyright.h b/usr.bin/mk_cmds/copyright.h
new file mode 100644
index 0000000..e0d1572
--- /dev/null
+++ b/usr.bin/mk_cmds/copyright.h
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987, 1989 by the Student Information Processing Board
+ of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/usr.bin/mk_cmds/ct.y b/usr.bin/mk_cmds/ct.y
new file mode 100644
index 0000000..c1b0d2f
--- /dev/null
+++ b/usr.bin/mk_cmds/ct.y
@@ -0,0 +1,77 @@
+%{
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright info, see copyright.h.
+ */
+#include <stdio.h>
+#include "copyright.h"
+
+char *str_concat3(), *ds(), *generate_rqte(), *quote();
+long flag_value();
+char *last_token = (char *)NULL;
+FILE *output_file;
+long gensym_n = 0;
+
+%}
+%union {
+ char *dynstr;
+ long flags;
+}
+
+%token COMMAND_TABLE REQUEST UNKNOWN UNIMPLEMENTED END
+%token <dynstr> STRING
+%token <dynstr> FLAGNAME
+%type <dynstr> namelist header request_list
+%type <dynstr> request_entry
+%type <flags> flag_list options
+%left OPTIONS
+%{
+#include "ss.h"
+%}
+%start command_table
+%%
+command_table : header request_list END ';'
+ { write_ct($1, $2); }
+ ;
+
+header : COMMAND_TABLE STRING ';'
+ { $$ = $2; }
+ ;
+
+request_list : request_list request_entry
+ { $$ = str_concat3($1, $2, ""); }
+ |
+ { $$ = ""; }
+ ;
+
+request_entry : REQUEST STRING ',' STRING ',' namelist ',' options ';'
+ { $$ = generate_rqte($2, quote($4), $6, $8); }
+ | REQUEST STRING ',' STRING ',' namelist ';'
+ { $$ = generate_rqte($2, quote($4), $6, 0); }
+ | UNKNOWN namelist ';'
+ { $$ = generate_rqte("ss_unknown_request",
+ (char *)NULL, $2, 0); }
+ | UNIMPLEMENTED STRING ',' STRING ',' namelist ';'
+ { $$ = generate_rqte("ss_unimplemented", quote($4), $6, 3); }
+ ;
+
+options : '(' flag_list ')'
+ { $$ = $2; }
+ | '(' ')'
+ { $$ = 0; }
+ ;
+
+flag_list : flag_list ',' STRING
+ { $$ = $1 | flag_val($3); }
+ | STRING
+ { $$ = flag_val($1); }
+ ;
+
+namelist: STRING
+ { $$ = quote(ds($1)); }
+ | namelist ',' STRING
+ { $$ = str_concat3($1, quote($3), ",\n "); }
+ ;
+
+%%
diff --git a/usr.bin/mk_cmds/mk_cmds.c b/usr.bin/mk_cmds/mk_cmds.c
new file mode 100644
index 0000000..1c3a3fb
--- /dev/null
+++ b/usr.bin/mk_cmds/mk_cmds.c
@@ -0,0 +1,97 @@
+/*
+ * make_commands.c
+ *
+ * Header: mk_cmds.c,v 1.6 89/01/25 07:47:26 raeburn Exp
+ * $Locker: $
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <strings.h>
+#include "ss_internal.h"
+
+static const char copyright[] =
+ "Copyright 1987 by MIT Student Information Processing Board";
+
+extern pointer malloc PROTOTYPE((unsigned));
+extern char *last_token;
+extern FILE *output_file;
+
+extern FILE *yyin, *yyout;
+extern int yylineno;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char c_file[MAXPATHLEN];
+ int result;
+ char *path, *p;
+
+ if (argc != 2) {
+ fputs("Usage: ", stderr);
+ fputs(argv[0], stderr);
+ fputs(" cmdtbl.ct\n", stderr);
+ exit(1);
+ }
+
+ path = malloc(strlen(argv[1])+4); /* extra space to add ".ct" */
+ strcpy(path, argv[1]);
+ p = rindex(path, '/');
+ if (p == (char *)NULL)
+ p = path;
+ else
+ p++;
+ p = rindex(p, '.');
+ if (p == (char *)NULL || strcmp(p, ".ct"))
+ strcat(path, ".ct");
+ yyin = fopen(path, "r");
+ if (!yyin) {
+ perror(path);
+ exit(1);
+ }
+
+ p = rindex(path, '.');
+ *p = '\0';
+ strcpy(c_file, path);
+ strcat(c_file, ".c");
+ *p = '.';
+
+ output_file = fopen(c_file, "w+");
+ if (!output_file) {
+ perror(c_file);
+ exit(1);
+ }
+
+ fputs("/* ", output_file);
+ fputs(c_file, output_file);
+ fputs(" - automatically generated from ", output_file);
+ fputs(path, output_file);
+ fputs(" */\n", output_file);
+ fputs("#include <ss/ss.h>\n\n", output_file);
+ fputs("#ifndef __STDC__\n#define const\n#endif\n\n", output_file);
+ /* parse it */
+ result = yyparse();
+ /* put file descriptors back where they belong */
+ fclose(yyin); /* bye bye input file */
+ fclose(output_file); /* bye bye output file */
+
+ return result;
+}
+
+int
+yyerror(s)
+ char *s;
+{
+ fputs(s, stderr);
+ fprintf(stderr, "\nLine %d; last token was '%s'\n",
+ yylineno, last_token);
+ return 0;
+}
diff --git a/usr.bin/mk_cmds/options.c b/usr.bin/mk_cmds/options.c
new file mode 100644
index 0000000..dd648b0
--- /dev/null
+++ b/usr.bin/mk_cmds/options.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "copyright.h"
+#include <stdio.h>
+#include "ss.h"
+
+struct option {
+ char *text;
+ long value;
+};
+
+static struct option options[] = {
+ { "dont_list", SS_OPT_DONT_LIST },
+ { "^list", SS_OPT_DONT_LIST },
+ { "dont_summarize", SS_OPT_DONT_SUMMARIZE },
+ { "^summarize", SS_OPT_DONT_SUMMARIZE },
+ { (char *)NULL, 0 }
+};
+
+long
+flag_val(string)
+ register char *string;
+{
+ register struct option *opt;
+ for (opt = options; opt->text; opt++)
+ if (!strcmp(opt->text, string))
+ return(opt->value);
+ return(0);
+}
diff --git a/usr.bin/mk_cmds/utils.c b/usr.bin/mk_cmds/utils.c
new file mode 100644
index 0000000..e46afce
--- /dev/null
+++ b/usr.bin/mk_cmds/utils.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include <stdlib.h>
+#include "copyright.h"
+#include "ss_internal.h" /* includes stdio and string */
+
+extern FILE *output_file;
+
+char *gensym(), *str_concat3(), *quote(), *ds();
+extern long gensym_n;
+
+void write_ct(hdr, rql)
+ char const *hdr, *rql;
+{
+ char *sym;
+ sym = gensym("ssu");
+ fputs("static ss_request_entry ", output_file);
+ fputs(sym, output_file);
+ fputs("[] = {\n", output_file);
+ fputs(rql, output_file);
+ fputs(" { 0, 0, 0, 0 }\n", output_file);
+ fputs("};\n\nss_request_table ", output_file);
+ fputs(hdr, output_file);
+ fprintf(output_file, " = { %d, ", SS_RQT_TBL_V2);
+ fputs(sym, output_file);
+ fputs(" };\n", output_file);
+}
+
+char * generate_cmds_string(cmds)
+ char const *cmds;
+{
+ char * var_name = gensym("ssu");
+ fputs("static char const * const ", output_file);
+ fputs(var_name, output_file);
+ fputs("[] = {\n", output_file);
+ fputs(cmds, output_file);
+ fputs(",\n (char const *)0\n};\n", output_file);
+ return(var_name);
+}
+
+void generate_function_definition(func)
+ char const *func;
+{
+ fputs("extern void ", output_file);
+ fputs(func, output_file);
+ fputs(" __SS_PROTO;\n", output_file);
+}
+
+char * generate_rqte(func_name, info_string, cmds, options)
+ char const *func_name;
+ char const *info_string;
+ char const *cmds;
+ int options;
+{
+ int size;
+ char *string, *var_name, numbuf[16];
+ var_name = generate_cmds_string(cmds);
+ generate_function_definition(func_name);
+ size = 6; /* " { " */
+ size += strlen(var_name)+7; /* "quux, " */
+ size += strlen(func_name)+7; /* "foo, " */
+ size += strlen(info_string)+9; /* "\"Info!\", " */
+ sprintf(numbuf, "%d", options);
+ size += strlen(numbuf);
+ size += 4; /* " }," + NL */
+ string = malloc(size * sizeof(char *));
+ strcpy(string, " { ");
+ strcat(string, var_name);
+ strcat(string, ",\n ");
+ strcat(string, func_name);
+ strcat(string, ",\n ");
+ strcat(string, info_string);
+ strcat(string, ",\n ");
+ strcat(string, numbuf);
+ strcat(string, " },\n");
+ return(string);
+}
+
+char *
+gensym(name)
+ char *name;
+{
+ char *symbol;
+
+ symbol = malloc((strlen(name)+6) * sizeof(char));
+ gensym_n++;
+ sprintf(symbol, "%s%05ld", name, gensym_n);
+ return(symbol);
+}
+
+/* concatenate three strings and return the result */
+char *str_concat3(a, b, c)
+ register char *a, *b, *c;
+{
+ char *result;
+ int size_a = strlen(a);
+ int size_b = strlen(b);
+ int size_c = strlen(c);
+
+ result = malloc((size_a + size_b + size_c + 2)*sizeof(char));
+ strcpy(result, a);
+ strcpy(&result[size_a], c);
+ strcpy(&result[size_a+size_c], b);
+ return(result);
+}
+
+/* return copy of string enclosed in double-quotes */
+char *quote(string)
+ register char *string;
+{
+ register char *result;
+ int len;
+ len = strlen(string)+1;
+ result = malloc(len+2);
+ result[0] = '"';
+ bcopy(string, &result[1], len-1);
+ result[len] = '"';
+ result[len+1] = '\0';
+ return(result);
+}
+
+/* make duplicate of string and return pointer */
+char *ds(s)
+ register char *s;
+{
+ register int len = strlen(s) + 1;
+ register char *new;
+ new = malloc(len);
+ bcopy(s, new, len);
+ return(new);
+}
diff --git a/usr.bin/mkdep/Makefile b/usr.bin/mkdep/Makefile
index 61f62fd..a094bc5 100644
--- a/usr.bin/mkdep/Makefile
+++ b/usr.bin/mkdep/Makefile
@@ -1,16 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
-MAN1= mkdep.0
+MAN1= mkdep.1
-.if (${MACHINE} == "hp300" || ${MACHINE} == "i386" || \
- ${MACHINE} == "mips" || ${MACHINE} == "sparc")
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/mkdep.gcc.sh ${DESTDIR}/usr/bin/mkdep
-.else
-beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/mkdep.sh ${DESTDIR}/usr/bin/mkdep
-.endif
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/mkdep.gcc.sh ${DESTDIR}${BINDIR}/mkdep
.include <bsd.prog.mk>
diff --git a/usr.bin/mkdep/mkdep.gcc.sh b/usr.bin/mkdep/mkdep.gcc.sh
index 26f80d6..8ad51d0 100644
--- a/usr.bin/mkdep/mkdep.gcc.sh
+++ b/usr.bin/mkdep/mkdep.gcc.sh
@@ -32,10 +32,9 @@
# SUCH DAMAGE.
#
# @(#)mkdep.gcc.sh 8.1 (Berkeley) 6/6/93
-#
+# $Id$
-PATH=/bin:/usr/bin:/usr/ucb
-export PATH
+PATH=/bin:/usr/bin; export PATH
D=.depend # default dependency file is .depend
append=0
@@ -63,31 +62,39 @@ while :
esac
done
-if [ $# = 0 ] ; then
- echo 'usage: mkdep [-p] [-f depend_file] [cc_flags] file ...'
- exit 1
-fi
-
-TMP=/tmp/mkdep$$
+case $# in 0)
+ echo 'usage: mkdep [-ap] [-f file] [flags] file ...' >&2
+ exit 1;;
+esac
+TMP=_mkdep$$
trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
+trap 'rm -f $TMP' 0
-if [ x$pflag = x ]; then
- cpp -M $* | sed -e 's; \./; ;g' > $TMP
-else
- cpp -M $* | sed -e 's;\.o :; :;' -e 's; \./; ;g' > $TMP
-fi
+# For C sources, mkdep must use exactly the same cpp and predefined flags
+# as the compiler would. This is easily arranged by letting the compiler
+# pick the cpp. mkdep must be told the cpp to use for exceptional cases.
+MKDEP_CPP=${MKDEP_CPP-"cc -E"}
-if [ $? != 0 ]; then
- echo 'mkdep: compile failed.'
- rm -f $TMP
- exit 1
-fi
+echo "# $@" > $TMP # store arguments for debugging
-if [ $append = 1 ]; then
- cat $TMP >> $D
- rm -f $TMP
+if $MKDEP_CPP -M "$@" >> $TMP; then :
else
- mv $TMP $D
+ echo 'mkdep: compile failed' >&2
+ exit 1
fi
-exit 0
+
+case x$pflag in
+ x) case $append in
+ 0) sed -e 's; \./; ;g' < $TMP > $D;;
+ *) sed -e 's; \./; ;g' < $TMP >> $D;;
+ esac
+ ;;
+ *) case $append in
+ 0) sed -e 's;\.o:;:;' -e 's; \./; ;g' < $TMP > $D;;
+ *) sed -e 's;\.o:;:;' -e 's; \./; ;g' < $TMP >> $D;;
+ esac
+ ;;
+esac
+
+exit $?
diff --git a/usr.bin/mkdep/mkdep.old.compiler b/usr.bin/mkdep/mkdep.old.compiler
deleted file mode 100644
index 5c77773..0000000
--- a/usr.bin/mkdep/mkdep.old.compiler
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/bin/sh -
-#
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-# must display the following acknowledgement:
-# This product includes software developed by the University of
-# California, Berkeley and its contributors.
-# 4. Neither the name of the University nor the names of its contributors
-# may be used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# @(#)mkdep.old.compiler 8.1 (Berkeley) 6/6/93
-#
-
-# This is a version of mkdep that works pretty well
-# with compilers that don't have -M.
-MAKE=Makefile # default makefile name is "Makefile"
-
-PATH=/bin:/usr/bin:/usr/ucb:/lib:/usr/lib
-
-INCL=
-
-while :
- do case "$1" in
- # -f allows you to select a makefile name
- -f)
- MAKE=$2
- shift; shift ;;
-
- # the -p flag produces "program: program.c" style dependencies
- # so .o's don't get produced
- -p)
- SED='s;\.o;;'
- shift ;;
- *)
- break ;;
- esac
-done
-
-if [ $# = 0 ] ; then
- echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
- exit 1
-fi
-
-if [ ! -w $MAKE ]; then
- echo "mkdep: no writeable file \"$MAKE\""
- exit 1
-fi
-
-TMP=/tmp/mkdep$$
-
-trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
-
-cp $MAKE ${MAKE}.bak
-sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
-
-cat << _EOF_ >> $TMP
-# DO NOT DELETE THIS LINE -- mkdep uses it.
-# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
-
-_EOF_
-
-
-for i do
- case "$i" in
- -c|-M|-O)
- ;;
- -I*)
- INCL="$INCL $i";;
- -D*|-U*)
- FLAGS="$FLAGS $i";;
- *)
- # assume source file
- # put '$dep' in front of dependencies
- dep=`echo "$i" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.o/'`
-
- # Find includes, remove leading numerics, remove ./,
- # remove double quotes, and remove trailing numerics.
- # Sort that, discarding duplicates, and add '$dep'.
- cpp $INCL $FLAGS "$i" | sed -e '
- /^#/!d
- s/# [0-9]* //
- s,"./,",
- s/"\(.*\)"/\1/
- s/ [ 0-9]*$//' |
- sort -u | sed -e "s/^/$dep: /";;
- esac
-done |
-sed "
- s; \./; ;g
- /\.c:$/d
- $SED" |
-awk '{
- if ($1 != prev) {
- if (rec != "")
- print rec;
- rec = $0;
- prev = $1;
- }
- else {
- if (length(rec $2) > 78) {
- print rec;
- rec = $0;
- }
- else
- rec = rec " " $2
- }
-}
-END {
- print rec
-}' >> $TMP
-
-cat << _EOF_ >> $TMP
-
-# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
-_EOF_
-
-# copy to preserve permissions
-cp $TMP $MAKE
-rm -f $TMP
-exit 0
diff --git a/usr.bin/mkfifo/mkfifo.1 b/usr.bin/mkfifo/mkfifo.1
index f0607a7..3aa3ee9 100644
--- a/usr.bin/mkfifo/mkfifo.1
+++ b/usr.bin/mkfifo/mkfifo.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)mkfifo.1 8.2 (Berkeley) 1/5/94
+.\" $Id$
.\"
.Dd January 5, 1994
.Dt MKFIFO 1
@@ -41,32 +42,36 @@
.Nm mkfifo
.Nd make fifos
.Sh SYNOPSIS
-.Nm mkfifo
+.Nm
.Ar fifo_name ...
.Sh DESCRIPTION
-.Nm Mkfifo
-creates the fifos requested, in the order specified,
+The
+.Nm
+command creates the fifos requested, in the order specified,
using mode
.Li \&0777 .
.Pp
-.Nm Mkfifo
-requires write permission in the parent directory.
+The
+.Nm
+command requires write permission in the parent directory.
.Pp
-.Nm Mkfifo
-exits 0 if successful, and >0 if an error occurred.
+The
+.Nm
+command exits 0 if successful, and >0 if an error occurred.
.Sh STANDARDS
The
-.Nm mkfifo
+.Nm
utility is expected to be
.St -p1003.2
compliant.
.Sh SEE ALSO
.Xr mkdir 1 ,
-.Xr mknod 1 ,
.Xr rm 1 ,
-.Xr mkfifo 2
+.Xr mkfifo 2 ,
+.Xr mknod 2 ,
+.Xr mknod 8
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/mkfifo/mkfifo.c b/usr.bin/mkfifo/mkfifo.c
index 53b7435..ddd9a8b 100644
--- a/usr.bin/mkfifo/mkfifo.c
+++ b/usr.bin/mkfifo/mkfifo.c
@@ -56,7 +56,7 @@ main(argc, argv)
extern int optind;
int ch, exitval;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/mklocale/Makefile b/usr.bin/mklocale/Makefile
index ec108bd..f07bf46 100644
--- a/usr.bin/mklocale/Makefile
+++ b/usr.bin/mklocale/Makefile
@@ -4,5 +4,7 @@ PROG= mklocale
SRCS= yacc.c lex.c
CFLAGS+=-I.
CLEANFILES+=y.tab.h yacc.c lex.c
+MAN1= mklocale.1
+SUBDIR= data
.include <bsd.prog.mk>
diff --git a/usr.bin/mklocale/README.locale_name b/usr.bin/mklocale/README.locale_name
new file mode 100644
index 0000000..f34cf67
--- /dev/null
+++ b/usr.bin/mklocale/README.locale_name
@@ -0,0 +1,7 @@
+Locale name string format must be compliant with XPG3 and
+using following format.
+ <locale name> ::= <language>_<territory>.<encoding>
+ <language> ::= based on ISO 639
+ <territory> ::= based on ISO 3166 (country code)
+ <encoding> ::= "EUC", "KOI8-R", ...
+
diff --git a/usr.bin/mklocale/data/Makefile b/usr.bin/mklocale/data/Makefile
new file mode 100644
index 0000000..6416bed
--- /dev/null
+++ b/usr.bin/mklocale/data/Makefile
@@ -0,0 +1,50 @@
+# $Id: Makefile,v 1.8 1997/02/28 22:44:31 adam Exp $
+
+NOMAN=YES
+CLEANFILES+= ${LOCALES:S/$/.out/g}
+
+LOCALES= ja_JP.EUC \
+ ko_KR.EUC \
+ lt_LN.ASCII \
+ lt_LN.ISO_8859-1 \
+ lt_LN.ISO_8859-2 \
+ ru_SU.CP866 \
+ ru_SU.KOI8-R
+
+LOCALEDIR= ${DESTDIR}/usr/share/locale
+
+.if exists(${.OBJDIR}/../mklocale)
+MKLOCALE=${.OBJDIR}/../mklocale
+.else
+MKLOCALE=${.CURDIR}/../mklocale
+.endif
+
+LATIN1LINKS = \
+ da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES fi_FI \
+ fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT nl_BE nl_NL no_NO \
+ pt_PT sv_SE
+
+LATIN2LINKS = hr_HR
+
+.SUFFIXES: .src .out
+
+.src.out:
+ ${MKLOCALE} -o ${.TARGET} ${.IMPSRC}
+
+all: ${LOCALES:S/$/.out/g}
+
+afterinstall:
+.for locale in ${LOCALES}
+ ${INSTALL} ${COPY} -m 644 -o ${BINOWN} -g ${BINGRP} \
+ ${locale}.out ${LOCALEDIR}/${locale}/LC_CTYPE
+.endfor
+.for link in ${LATIN1LINKS}
+ ln -fs ../lt_LN.ISO_8859-1/LC_CTYPE \
+ ${LOCALEDIR}/${link}.ISO_8859-1/LC_CTYPE
+.endfor
+.for link in ${LATIN2LINKS}
+ ln -fs ../lt_LN.ISO_8859-2/LC_CTYPE \
+ ${LOCALEDIR}/${link}.ISO_8859-2/LC_CTYPE
+.endfor
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/mklocale/data/ja_JP.EUC.src b/usr.bin/mklocale/data/ja_JP.EUC.src
new file mode 100644
index 0000000..88fdc91
--- /dev/null
+++ b/usr.bin/mklocale/data/ja_JP.EUC.src
@@ -0,0 +1,158 @@
+# @(#)Japanese 8.1 (Berkeley) 6/6/93
+
+/*
+ * Japanese LOCALE_CTYPE definitions using EUC of JIS character sets
+ */
+
+ENCODING "EUC"
+
+/* JIS JIS JIS */
+/* X201 X208 X201 */
+/* 00-7f 84-fe */
+
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+
+/*
+ * Code Set 1
+ */
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+
+MAPLOWER < 'A' - 'Z' : 'a' >
+MAPLOWER < 'a' - 'z' : 'a' >
+MAPUPPER < 'A' - 'Z' : 'A' >
+MAPUPPER < 'a' - 'z' : 'A' >
+TODIGIT < '0' - '9' : 0 >
+TODIGIT < 'A' - 'F' : 10 >
+TODIGIT < 'a' - 'f' : 10 >
+
+/*
+ * Code Set 2
+ */
+
+SPACE 0xa1a1
+PHONOGRAM 0xa1bc
+SPECIAL 0xa1a2 - 0xa1fe
+PUNCT 0xa1a2 - 0xa1f8 /* A few too many in here... */
+
+SPECIAL 0xa2a1 - 0xa2ae 0xa2ba - 0xa2c1 0xa2ca - 0xa2d0 0xa2dc - 0xa2ea
+SPECIAL 0xa2f2 - 0xa2f9 0xa2fe
+
+DIGIT 0xa3b0 - 0xa3b9
+UPPER 0xa3c1 - 0xa3da /* Romaji */
+LOWER 0xa3e1 - 0xa3fa /* Romaji */
+MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > /* English */
+MAPLOWER < 0xa3e1 - 0xa3fa : 0xa3e1 > /* English */
+MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 >
+MAPUPPER < 0xa3e1 - 0xa3fa : 0xa3c1 >
+
+XDIGIT 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
+
+TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
+TODIGIT < 0xa3c1 - 0xa3c6 : 10 >
+TODIGIT < 0xa3e1 - 0xa3e6 : 10 >
+
+PHONOGRAM 0xa4a1 - 0xa4f3
+PHONOGRAM 0xa5a1 - 0xa5f6
+
+UPPER 0xa6a1 - 0xa6b8 /* Greek */
+LOWER 0xa6c1 - 0xa6d8 /* Greek */
+MAPLOWER < 0xa6a1 - 0xa6b8 : 0xa6c1 >
+MAPLOWER < 0xa6c1 - 0xa6d8 : 0xa6c1 >
+MAPUPPER < 0xa6a1 - 0xa6b8 : 0xa6a1 >
+MAPUPPER < 0xa6c1 - 0xa6d8 : 0xa6a1 >
+
+UPPER 0xa7a1 - 0xa7c1 /* Cyrillic */
+LOWER 0xa7d1 - 0xa7f1 /* Cyrillic */
+MAPLOWER < 0xa7a1 - 0xa7c1 : 0xa7d1 >
+MAPLOWER < 0xa7d1 - 0xa7f1 : 0xa7d1 >
+MAPUPPER < 0xa7a1 - 0xa7c1 : 0xa7a1 >
+MAPUPPER < 0xa7d1 - 0xa7f1 : 0xa7a1 >
+
+SPECIAL 0xa8a1 - 0xa8c0
+
+IDEOGRAM 0xb0a1 - 0xb0fe
+IDEOGRAM 0xb1a1 - 0xb1fe
+IDEOGRAM 0xb2a1 - 0xb2fe
+IDEOGRAM 0xb3a1 - 0xb3fe
+IDEOGRAM 0xb4a1 - 0xb4fe
+IDEOGRAM 0xb5a1 - 0xb5fe
+IDEOGRAM 0xb6a1 - 0xb6fe
+IDEOGRAM 0xb7a1 - 0xb7fe
+IDEOGRAM 0xb8a1 - 0xb8fe
+IDEOGRAM 0xb9a1 - 0xb9fe
+IDEOGRAM 0xbaa1 - 0xbafe
+IDEOGRAM 0xbba1 - 0xbbfe
+IDEOGRAM 0xbca1 - 0xbcfe
+IDEOGRAM 0xbda1 - 0xbdfe
+IDEOGRAM 0xbea1 - 0xbefe
+IDEOGRAM 0xbfa1 - 0xbffe
+IDEOGRAM 0xc0a1 - 0xc0fe
+IDEOGRAM 0xc1a1 - 0xc1fe
+IDEOGRAM 0xc2a1 - 0xc2fe
+IDEOGRAM 0xc3a1 - 0xc3fe
+IDEOGRAM 0xc4a1 - 0xc4fe
+IDEOGRAM 0xc5a1 - 0xc5fe
+IDEOGRAM 0xc6a1 - 0xc6fe
+IDEOGRAM 0xc7a1 - 0xc7fe
+IDEOGRAM 0xc8a1 - 0xc8fe
+IDEOGRAM 0xc9a1 - 0xc9fe
+IDEOGRAM 0xcaa1 - 0xcafe
+IDEOGRAM 0xcba1 - 0xcbfe
+IDEOGRAM 0xcca1 - 0xccfe
+IDEOGRAM 0xcda1 - 0xcdfe
+IDEOGRAM 0xcea1 - 0xcefe
+IDEOGRAM 0xcfa1 - 0xcfd3
+IDEOGRAM 0xd0a1 - 0xd0fe
+IDEOGRAM 0xd1a1 - 0xd1fe
+IDEOGRAM 0xd2a1 - 0xd2fe
+IDEOGRAM 0xd3a1 - 0xd3fe
+IDEOGRAM 0xd4a1 - 0xd4fe
+IDEOGRAM 0xd5a1 - 0xd5fe
+IDEOGRAM 0xd6a1 - 0xd6fe
+IDEOGRAM 0xd7a1 - 0xd7fe
+IDEOGRAM 0xd8a1 - 0xd8fe
+IDEOGRAM 0xd9a1 - 0xd9fe
+IDEOGRAM 0xdaa1 - 0xdafe
+IDEOGRAM 0xdba1 - 0xdbfe
+IDEOGRAM 0xdca1 - 0xdcfe
+IDEOGRAM 0xdda1 - 0xddfe
+IDEOGRAM 0xdea1 - 0xdefe
+IDEOGRAM 0xdfa1 - 0xdffe
+IDEOGRAM 0xe0a1 - 0xe0fe
+IDEOGRAM 0xe1a1 - 0xe1fe
+IDEOGRAM 0xe2a1 - 0xe2fe
+IDEOGRAM 0xe3a1 - 0xe3fe
+IDEOGRAM 0xe4a1 - 0xe4fe
+IDEOGRAM 0xe5a1 - 0xe5fe
+IDEOGRAM 0xe6a1 - 0xe6fe
+IDEOGRAM 0xe7a1 - 0xe7fe
+IDEOGRAM 0xe8a1 - 0xe8fe
+IDEOGRAM 0xe9a1 - 0xe9fe
+IDEOGRAM 0xeaa1 - 0xeafe
+IDEOGRAM 0xeba1 - 0xebfe
+IDEOGRAM 0xeca1 - 0xecfe
+IDEOGRAM 0xeda1 - 0xedfe
+IDEOGRAM 0xeea1 - 0xeefe
+IDEOGRAM 0xefa1 - 0xeffe
+IDEOGRAM 0xf0a1 - 0xf0fe
+IDEOGRAM 0xf1a1 - 0xf1fe
+IDEOGRAM 0xf2a1 - 0xf2fe
+IDEOGRAM 0xf3a1 - 0xf3fe
+IDEOGRAM 0xf4a1 - 0xf4a4
+
+/*
+ * This is for Code Set 3, half-width kana
+ */
+SPECIAL 0xa1 - 0xdf
+PHONOGRAM 0xa1 - 0xdf
+CONTROL 0x84 - 0x97 0x9b - 0x9f 0xe0 - 0xfe
diff --git a/usr.bin/mklocale/data/ko_KR.EUC.src b/usr.bin/mklocale/data/ko_KR.EUC.src
new file mode 100644
index 0000000..ce54ab3
--- /dev/null
+++ b/usr.bin/mklocale/data/ko_KR.EUC.src
@@ -0,0 +1,119 @@
+/*
+ * Korean LC_CTYPE definitions using EUC-KR character sets
+ * (ko_KR.EUC.src)
+ *
+ * Choi Jun Ho, junker@jazz.snu.ac.kr
+ * NARAE, Seoul National Univ., CS Dept.
+ * Last Updated on Mar 24 1997
+ *
+ * It is based on manpage mklocale(1), euc(4), ja_JP.EUC.src.
+ *
+ */
+
+ENCODING "EUC"
+
+/* EUC-KR(KS C 5601.1992)
+ * 0xa1a1-0xfefe
+ * byte 1: 0xa1-0xfe
+ * byte 2: 0xa1-0xfe
+ */
+
+/* We have only codeset 1 and 2, so others are dummy.
+ But it must be defined to work in 2.2 xpg4 locale routine...
+ */
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+
+/*
+ * Code Set 1, US-ASCII equivalent
+ */
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+
+MAPLOWER < 'A' - 'Z' : 'a' > < 'a' - 'z' : 'a' >
+MAPUPPER < 'A' - 'Z' : 'A' > < 'a' - 'z' : 'A' >
+TODIGIT < '0' - '9' : 0 >
+TODIGIT < 'A' - 'F' : 10 > < 'a' - 'f' : 10 >
+
+/*
+ * Code Set 2, EUC-KR
+ */
+ALPHA 0xa3c1 - 0xa3da 0xa3e1 - 0xa3fa
+DIGIT 0xa3b0 - 0xa3b9
+UPPER 0xa3c1 - 0xa3da
+LOWER 0xa3e1 - 0xa3fa
+PUNCT 0xa3a1 - 0xa3af 0xa3ba - 0xa3c0 0xa3db - 0xa3e0 0xa3fb - 0xa3fe
+SPACE 0xa1a1
+XDIGIT 0xa3b0 - 0xa3b9 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
+BLANK 0xa1a1
+PRINT 0xa1a1 - 0xfefe
+SPECIAL 0xa1a2 - 0xa2e5
+
+MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > < 0xa3e1 - 0xa3fa : 0xa3e1 >
+MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 > < 0xa3b0 - 0xa3b9 : 0xa3c1 >
+TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
+TODIGIT < 0xa3c1 - 0xa3c6 : 10 > < 0xa3e1 - 0xa3e6 : 10 >
+
+
+UPPER 0xa5c1 - 0xa5d8 /* Greek */
+LOWER 0xa5e1 - 0xa5f8 /* Greek */
+MAPLOWER < 0xa5c1 - 0xa5d8 : 0xa5e1 > < 0xa5e1 - 0xa5f8 : 0xa5e1 >
+MAPUPPER < 0xa5c1 - 0xa5d8 : 0xa5c1 > < 0xa5e1 - 0xa5f8 : 0xa5c1 >
+
+UPPER 0xaca1 - 0xacc1 /* Cyrillic */
+LOWER 0xacd1 - 0xacf1 /* Cyrillic */
+MAPLOWER < 0xaca1 - 0xacc1 : 0xacd1 > < 0xacd1 - 0xacf1 : 0xacd1 >
+MAPUPPER < 0xaca1 - 0xacc1 : 0xaca1 > < 0xacd1 - 0xacf1 : 0xaca1 >
+
+DIGIT 0xa5a1 - 0xa5aa 0xa5b0 - 0xa5b9 /* Greek Digit */
+SPECIAL 0xa6a1 - 0xa6e4 0xa7a1 - 0xa7ef /* Symbols */
+SPECIAL 0xa8a1 - 0xa8fe 0xa9a1 - 0xa9fe /* Circle Symbols */
+
+PHONOGRAM 0xa4a1 - 0xa4fe /* Full-width Hangul glyph */
+PHONOGRAM 0xaaa1 - 0xaaf3 /* Full-width Hirakana */
+PHONOGRAM 0xaba1 - 0xabf6 /* Full-width Katakana */
+
+PHONOGRAM 0xb0a1 - 0xb0fe 0xb1a1 - 0xb1fe 0xb2a1 - 0xb2fe
+PHONOGRAM 0xb3a1 - 0xb3fe 0xb4a1 - 0xb4fe 0xb5a1 - 0xb5fe
+PHONOGRAM 0xb6a1 - 0xb6fe 0xb7a1 - 0xb7fe 0xb8a1 - 0xb8fe
+PHONOGRAM 0xb9a1 - 0xb9fe 0xbaa1 - 0xbafe 0xbba1 - 0xbbfe
+PHONOGRAM 0xbca1 - 0xbcfe 0xbda1 - 0xbdfe 0xbea1 - 0xbefe
+PHONOGRAM 0xbfa1 - 0xbffe 0xc0a1 - 0xc0fe 0xc1a1 - 0xc1fe
+PHONOGRAM 0xc2a1 - 0xc2fe 0xc3a1 - 0xc3fe 0xc4a1 - 0xc4fe
+PHONOGRAM 0xc5a1 - 0xc5fe 0xc6a1 - 0xc6fe 0xc7a1 - 0xc7fe
+PHONOGRAM 0xc8a1 - 0xc8fe /* Hangul composed */
+
+IDEOGRAM 0xcaa1 - 0xcafe 0xcba1 - 0xcbfe 0xcca1 - 0xccfe
+IDEOGRAM 0xcda1 - 0xcdfe 0xcea1 - 0xcefe 0xcfa1 - 0xcffe
+IDEOGRAM 0xd0a1 - 0xd0fe 0xd1a1 - 0xd1fe 0xd2a1 - 0xd2fe
+IDEOGRAM 0xd3a1 - 0xd3fe 0xd4a1 - 0xd4fe 0xd5a1 - 0xd5fe
+IDEOGRAM 0xd6a1 - 0xd6fe 0xd7a1 - 0xd7fe 0xd8a1 - 0xd8fe
+IDEOGRAM 0xd9a1 - 0xd9fe 0xdaa1 - 0xdafe 0xdba1 - 0xdbfe
+IDEOGRAM 0xdca1 - 0xdcfe 0xdda1 - 0xddfe 0xdea1 - 0xdefe
+IDEOGRAM 0xdfa1 - 0xdffe 0xe0a1 - 0xe0fe 0xe1a1 - 0xe1fe
+IDEOGRAM 0xe2a1 - 0xe2fe 0xe3a1 - 0xe3fe 0xe4a1 - 0xe4fe
+IDEOGRAM 0xe5a1 - 0xe5fe 0xe6a1 - 0xe6fe 0xe7a1 - 0xe7fe
+IDEOGRAM 0xe8a1 - 0xe8fe 0xe9a1 - 0xe9fe 0xeaa1 - 0xeafe
+IDEOGRAM 0xeba1 - 0xebfe 0xeca1 - 0xecfe 0xeda1 - 0xedfe
+IDEOGRAM 0xeea1 - 0xeefe 0xefa1 - 0xeffe 0xf0a1 - 0xf0fe
+IDEOGRAM 0xf1a1 - 0xf1fe 0xf2a1 - 0xf2fe 0xf3a1 - 0xf3fe
+IDEOGRAM 0xf4a1 - 0xf4fe 0xf5a1 - 0xf5fe 0xf6a1 - 0xf6fe
+IDEOGRAM 0xf7a1 - 0xf7fe 0xf8a1 - 0xf8fe 0xf9a1 - 0xf9fe
+IDEOGRAM 0xfaa1 - 0xfafe 0xfba1 - 0xfbfe 0xfca1 - 0xfcfe
+IDEOGRAM 0xfda1 - 0xfdfe /* Hanja */
+
+/* We don't have codeset 3 and 4.
+ So codeset 3 is only dummy definition
+ */
+PRINT 0xa1 - 0xfe
+SPECIAL 0xa1 - 0xfe
+
+/* End of LC_CTYPE definition */
diff --git a/usr.bin/mklocale/POSIX b/usr.bin/mklocale/data/lt_LN.ASCII.src
index ead0bc8..95cbeeb 100644
--- a/usr.bin/mklocale/POSIX
+++ b/usr.bin/mklocale/data/lt_LN.ASCII.src
@@ -1,14 +1,9 @@
-# @(#)POSIX 8.1 (Berkeley) 6/6/93
-
/*
- * Standard LOCALE_CTYPE for the C Locale
+ * Standard LOCALE_CTYPE for the ASCII Locale
*/
-ENCODING "UTF2"
-VARIABLE A comment line or data line. Only 1 allowed. Copied verbatim.
+ENCODING "NONE"
+VARIABLE Strict 7bit ASCII locale
-#
-# This is a comment
-#
ALPHA 'A' - 'Z' 'a' - 'z'
CONTROL 0x00 - 0x1f 0x7f
DIGIT '0' - '9'
@@ -17,7 +12,7 @@ LOWER 'a' - 'z'
PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
SPACE 0x09 - 0x0d 0x20
UPPER 'A' - 'Z'
-XDIGIT 'a' - 'f' 'A' - 'F'
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
BLANK ' ' '\t'
PRINT 0x20 - 0x7e
# IDEOGRAM
diff --git a/usr.bin/mklocale/data/lt_LN.ISO_8859-1.src b/usr.bin/mklocale/data/lt_LN.ISO_8859-1.src
new file mode 100644
index 0000000..82faff3
--- /dev/null
+++ b/usr.bin/mklocale/data/lt_LN.ISO_8859-1.src
@@ -0,0 +1,39 @@
+/*
+ * Standard LOCALE_CTYPE for the iso_8859_1 Locale
+ */
+ENCODING "NONE"
+VARIABLE ISO 8859-1 Latin-1 character set
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z' 0xc0 - 0xd6 0xd8 - 0xf6 0xf8 - 0xff
+CONTROL 0x00 - 0x1f 0x7f - 0x9f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e 0xa1 - 0xff
+LOWER 'a' - 'z' 0xdf - 0xf6 0xf8 - 0xff
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e 0xa1 - 0xbf 0xd7 0xf7
+SPACE 0x09 - 0x0d ' ' 0xa0
+UPPER 'A' - 'Z' 0xc0 - 0xd6 0xd8 - 0xde
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t' 0xa0
+PRINT 0x20 - 0x7e 0xa0 - 0xff
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPLOWER <0xc0 - 0xd6 : 0xe0>
+MAPLOWER <0xd8 - 0xde : 0xf8>
+MAPLOWER <0xdf - 0xf6 : 0xdf>
+MAPLOWER <0xf8 - 0xff : 0xf8>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+MAPUPPER <0xc0 - 0xd6 : 0xc0>
+MAPUPPER <0xd8 - 0xde : 0xd8>
+MAPUPPER <0xe0 - 0xf6 : 0xc0>
+MAPUPPER <0xf8 - 0xfe : 0xd8>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/usr.bin/mklocale/data/lt_LN.ISO_8859-2.src b/usr.bin/mklocale/data/lt_LN.ISO_8859-2.src
new file mode 100644
index 0000000..3f9ad91
--- /dev/null
+++ b/usr.bin/mklocale/data/lt_LN.ISO_8859-2.src
@@ -0,0 +1,79 @@
+/*
+ * LOCALE_CTYPE for the iso_8859_2 Locale
+ *
+ * $Id$
+ */
+
+ENCODING "NONE"
+VARIABLE ISO 8859-2 Latin-2 character set
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z'
+ 0xa1 0xa3 0xa5 0xa6 0xa9 - 0xac 0xae 0xaf
+ 0xb1 0xb3 0xb5 0xb6 0xb9 - 0xbc 0xbe 0xbf
+ 0xc0 - 0xd6 0xd8 - 0xf6 0xf8 - 0xfe
+CONTROL 0x00 - 0x1f 0x7f - 0x9f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e 0xa0 - 0xff
+LOWER 'a' - 'z'
+ 0xb1 0xb3 0xb5 0xb6 0xb9 - 0xbc 0xbe 0xbf
+ 0xdf - 0xf6 0xf8 - 0xfe
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+ 0xa2 0xa4 0xa7 0xa8 0xad 0xb0 0xb2 0xb4 0xb7 0xb8 0xbd
+ 0xd7 0xf7 0xff
+SPACE 0x09 - 0x0d 0x20 0xa0
+UPPER 'A' - 'Z'
+ 0xa1 0xa3 0xa5 0xa6 0xa9 - 0xac 0xae 0xaf
+ 0xc0 - 0xd6 0xd8 - 0xde
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t' 0xa0
+PRINT 0x20 - 0x7e 0xa0 - 0xff
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPLOWER <0xa1 0xb1>
+MAPLOWER <0xa3 0xb3>
+MAPLOWER <0xa5 0xb5>
+MAPLOWER <0xa6 0xb6>
+MAPLOWER <0xa9 - 0xac : 0xb9>
+MAPLOWER <0xae 0xbe>
+MAPLOWER <0xaf 0xbf>
+MAPLOWER <0xb1 0xb1>
+MAPLOWER <0xb3 0xb3>
+MAPLOWER <0xb5 0xb5>
+MAPLOWER <0xb6 0xb6>
+MAPLOWER <0xb9 - 0xbc : 0xb9>
+MAPLOWER <0xbe 0xbe>
+MAPLOWER <0xbf 0xbf>
+MAPLOWER <0xc0 - 0xd6 : 0xe0>
+MAPLOWER <0xd8 - 0xde : 0xf8>
+MAPLOWER <0xdf - 0xf6 : 0xdf>
+MAPLOWER <0xf8 - 0xfe : 0xf8>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+MAPUPPER <0xa1 0xa1>
+MAPUPPER <0xa3 0xa3>
+MAPUPPER <0xa5 0xa5>
+MAPUPPER <0xa6 0xa6>
+MAPUPPER <0xa9 - 0xac : 0xa9>
+MAPUPPER <0xae 0xae>
+MAPUPPER <0xaf 0xaf>
+MAPUPPER <0xb1 0xa1>
+MAPUPPER <0xb3 0xa3>
+MAPUPPER <0xb5 0xa5>
+MAPUPPER <0xb6 0xa6>
+MAPUPPER <0xb9 - 0xbc : 0xa9>
+MAPUPPER <0xbe 0xae>
+MAPUPPER <0xbf 0xaf>
+MAPUPPER <0xc0 - 0xd6 : 0xc0>
+MAPUPPER <0xd8 - 0xdf : 0xd8>
+MAPUPPER <0xe0 - 0xf6 : 0xc0>
+MAPUPPER <0xf8 - 0xfe : 0xd8>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/usr.bin/mklocale/data/ru_SU.CP866.src b/usr.bin/mklocale/data/ru_SU.CP866.src
new file mode 100644
index 0000000..659482b
--- /dev/null
+++ b/usr.bin/mklocale/data/ru_SU.CP866.src
@@ -0,0 +1,42 @@
+/*
+ * LOCALE_CTYPE for Russian Alternative character set (CP866)
+ */
+ENCODING "NONE"
+VARIABLE Russian Alternative charset (CP866) by ache@astral.msk.su
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z' 0x80 - 0xaf 0xe0 - 0xf1
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e 0x80 - 0xff
+LOWER 'a' - 'z' 0xa0 - 0xaf 0xe0 - 0xef 0xf1
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z' 0x80 - 0x9f 0xf0
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e 0x80 - 0xff
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPLOWER <0x80 - 0x8f : 0xa0>
+MAPLOWER <0x90 - 0x9f : 0xe0>
+MAPLOWER <0xf0 0xf1>
+MAPLOWER <0xa0 - 0xaf : 0xa0>
+MAPLOWER <0xe0 - 0xef : 0xe0>
+MAPLOWER <0xf1 0xf1>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+MAPUPPER <0x80 - 0x9f : 0x80>
+MAPUPPER <0xf0 0xf0>
+MAPUPPER <0xa0 - 0xaf : 0x80>
+MAPUPPER <0xe0 - 0xef : 0x90>
+MAPUPPER <0xf1 0xf0>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/usr.bin/mklocale/data/ru_SU.KOI8-R.src b/usr.bin/mklocale/data/ru_SU.KOI8-R.src
new file mode 100644
index 0000000..b9582fe
--- /dev/null
+++ b/usr.bin/mklocale/data/ru_SU.KOI8-R.src
@@ -0,0 +1,39 @@
+/*
+ * LOCALE_CTYPE for Russian koi8-r character set (RFC1489)
+ */
+ENCODING "NONE"
+VARIABLE Russian koi8-r character set by ache@astral.msk.su
+
+#
+# This is a comment
+#
+ALPHA 'A' - 'Z' 'a' - 'z' 0xa3 0xb3 0xc0 - 0xff
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e 0x80 - 0x99 0x9b - 0xff
+LOWER 'a' - 'z' 0xa3 0xc0 - 0xdf
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20 0x9a
+UPPER 'A' - 'Z' 0xb3 0xe0 - 0xff
+XDIGIT '0' - '9' 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t' 0x9a
+PRINT 0x20 - 0x7e 0x80 - 0xff
+# IDEOGRAM
+# SPECIAL
+# PHONEGRAM
+
+MAPLOWER <'A' - 'Z' : 'a'>
+MAPLOWER <'a' - 'z' : 'a'>
+MAPLOWER <0xb3 0xa3>
+MAPLOWER <0xa3 0xa3>
+MAPLOWER <0xe0 - 0xff : 0xc0>
+MAPLOWER <0xc0 - 0xdf : 0xc0>
+MAPUPPER <'A' - 'Z' : 'A'>
+MAPUPPER <'a' - 'z' : 'A'>
+MAPUPPER <0xb3 0xb3>
+MAPUPPER <0xa3 0xb3>
+MAPUPPER <0xe0 - 0xff : 0xe0>
+MAPUPPER <0xc0 - 0xdf : 0xe0>
+TODIGIT <'0' - '9' : 0>
+TODIGIT <'A' - 'F' : 10>
+TODIGIT <'a' - 'f' : 10>
diff --git a/usr.bin/mklocale/ldef.h b/usr.bin/mklocale/ldef.h
index 95b51da..532787c 100644
--- a/usr.bin/mklocale/ldef.h
+++ b/usr.bin/mklocale/ldef.h
@@ -43,11 +43,11 @@ typedef struct rune_list {
rune_t min;
rune_t max;
rune_t map;
- u_long *types;
+ unsigned long *types;
struct rune_list *next;
} rune_list;
typedef struct rune_map {
- u_long map[_CACHED_RUNES];
+ unsigned long map[_CACHED_RUNES];
rune_list *root;
} rune_map;
diff --git a/usr.bin/mklocale/mklocale.1 b/usr.bin/mklocale/mklocale.1
index b0b0c62..8b59b4b 100644
--- a/usr.bin/mklocale/mklocale.1
+++ b/usr.bin/mklocale/mklocale.1
@@ -34,7 +34,7 @@
.\"
.\" @(#)mklocale.1 8.2 (Berkeley) 4/18/94
.\"
-.Dd "April 18, 1994"
+.Dd April 18, 1994
.Dt MKLOCALE 1
.Os
.Sh NAME
@@ -241,6 +241,7 @@ Defines runes which are special characters, printable and graphic.
Defines runes which are phonograms, printable and graphic.
.El
.Sh SEE ALSO
+.Xr mklocale 1 ,
.Xr mbrune 3 ,
.Xr rune 3 ,
.Xr setlocale 3 ,
diff --git a/usr.bin/mklocale/yacc.y b/usr.bin/mklocale/yacc.y
index 193b7b1..760d112 100644
--- a/usr.bin/mklocale/yacc.y
+++ b/usr.bin/mklocale/yacc.y
@@ -55,9 +55,9 @@ rune_map types = { 0, };
_RuneLocale new_locale = { 0, };
-void set_map __P((rune_map *, rune_list *, u_long));
+void set_map __P((rune_map *, rune_list *, unsigned long));
void set_digitmap __P((rune_map *, rune_list *));
-void add_map __P((rune_map *, rune_list *, u_long));
+void add_map __P((rune_map *, rune_list *, unsigned long));
%}
%union {
@@ -251,11 +251,11 @@ xmalloc(sz)
return(r);
}
-u_long *
+unsigned long *
xlalloc(sz)
unsigned int sz;
{
- u_long *r = (u_long *)malloc(sz * sizeof(u_long));
+ unsigned long *r = (unsigned long *)malloc(sz * sizeof(unsigned long));
if (!r) {
perror("xlalloc");
abort();
@@ -263,12 +263,13 @@ xlalloc(sz)
return(r);
}
-u_long *
+unsigned long *
xrelalloc(old, sz)
- u_long *old;
+ unsigned long *old;
unsigned int sz;
{
- u_long *r = (u_long *)realloc((char *)old, sz * sizeof(u_long));
+ unsigned long *r = (unsigned long *)realloc((char *)old,
+ sz * sizeof(unsigned long));
if (!r) {
perror("xrelalloc");
abort();
@@ -280,7 +281,7 @@ void
set_map(map, list, flag)
rune_map *map;
rune_list *list;
- u_long flag;
+ unsigned long flag;
{
while (list) {
rune_list *nlist = list->next;
@@ -315,7 +316,7 @@ void
add_map(map, list, flag)
rune_map *map;
rune_list *list;
- u_long flag;
+ unsigned long flag;
{
rune_t i;
rune_list *lr = 0;
@@ -478,7 +479,7 @@ add_map(map, list, flag)
for (i = r->max+1; i <= list->max; ++i)
r->types[i - r->min] = flag;
}
- r->max = r->max;
+ r->max = list->max;
free(list);
}
@@ -660,8 +661,9 @@ dump_tables()
list->types[x] = htonl(list->types[x]);
if (!list->map) {
- if (fwrite((char *)&list->types,
- (list->max - list->min + 1)*sizeof(u_long), 1, fp) != 1) {
+ if (fwrite((char *)list->types,
+ (list->max - list->min + 1) * sizeof(unsigned long),
+ 1, fp) != 1) {
perror(locale_file);
exit(1);
}
@@ -728,7 +730,7 @@ dump_tables()
fprintf(stderr, "\nTYPES:\n\n");
for (x = 0; x < _CACHED_RUNES; ++x) {
- u_long r = types.map[x];
+ unsigned long r = types.map[x];
if (r) {
if (isprint(x))
@@ -756,7 +758,7 @@ dump_tables()
for (list = types.root; list; list = list->next) {
if (list->map && list->min + 3 < list->max) {
- u_long r = list->map;
+ unsigned long r = list->map;
fprintf(stderr, "%04x: %2d", list->min, r & 0xff);
@@ -795,7 +797,7 @@ dump_tables()
fprintf(stderr, "\n");
} else
for (x = list->min; x <= list->max; ++x) {
- u_long r = ntohl(list->types[x - list->min]);
+ unsigned long r = ntohl(list->types[x - list->min]);
if (r) {
fprintf(stderr, "%04x: %2d", x, r & 0xff);
diff --git a/usr.bin/mkstr/mkstr.1 b/usr.bin/mkstr/mkstr.1
index f0493c1..7a53af9 100644
--- a/usr.bin/mkstr/mkstr.1
+++ b/usr.bin/mkstr/mkstr.1
@@ -119,8 +119,8 @@ oops:
}
.Ed
.Sh SEE ALSO
-.Xr lseek 2 ,
-.Xr xstr 1
+.Xr xstr 1 ,
+.Xr lseek 2
.Sh HISTORY
.Nm Mkstr
appeared in
@@ -128,7 +128,7 @@ appeared in
.Sh BUGS
.Nm mkstr
was intended for the limited architecture of the PDP 11 family.
-Very few programs actually use it. The pascal interpreter,
+Very few programs actually use it. The Pascal interpreter,
.Xr \&pi 1
and the editor,
.Xr \&ex 1
diff --git a/usr.bin/modstat/Makefile b/usr.bin/modstat/Makefile
new file mode 100644
index 0000000..5e238ce
--- /dev/null
+++ b/usr.bin/modstat/Makefile
@@ -0,0 +1,42 @@
+#
+# Makefile for modstat
+#
+# 25 May 93 Terry Lambert Original
+#
+# Copyright (c) 1993 Terrence R. Lambert.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Terrence R. Lambert.
+# 4. The name Terrence R. Lambert may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $Id$
+#
+
+PROG= modstat
+MAN8= modstat.8
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/modstat/modstat.8 b/usr.bin/modstat/modstat.8
new file mode 100644
index 0000000..359a856
--- /dev/null
+++ b/usr.bin/modstat/modstat.8
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1993 Christopher G. Demetriou
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 7, 1993
+.Dt MODSTAT 8
+.Os
+.Sh NAME
+.Nm modstat
+.Nd display status of loaded kernel modules
+.Sh SYNOPSIS
+.Nm modstat
+.Op Fl i Ar id
+.Op Fl n Ar name
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the status of any loadable kernel modules
+present in the kernel.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl i Ar id
+Display the status of only the module with this ID.
+.It Fl n Ar name
+Display the status of only the module with this name.
+.El
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with a status of 0 on success
+and with a nonzero status if an error occurs.
+.Sh SEE ALSO
+.Xr lkm 4 ,
+.Xr modload 8 ,
+.Xr modunload 8
+.Sh HISTORY
+The
+.Nm
+command was designed to be similar in functionality
+to the corresponding command in
+.Tn "SunOS 4.1.3" .
+.Sh AUTHOR
+.Bl -tag
+Terrence R. Lambert, terry@cs.weber.edu
+.El
diff --git a/usr.bin/modstat/modstat.c b/usr.bin/modstat/modstat.c
new file mode 100644
index 0000000..a11f4d5
--- /dev/null
+++ b/usr.bin/modstat/modstat.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1993 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: modstat.c,v 1.7 1997/03/11 14:41:52 peter Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <string.h>
+#include <a.out.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/lkm.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include "pathnames.h"
+
+void
+usage()
+{
+
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "modstat [-i <module id>] [-n <module name>]\n");
+ exit(1);
+}
+
+static char *type_names[] = {
+ "SYSCALL",
+ "VFS",
+ "DEV",
+ "STRMOD",
+ "EXEC",
+ "MISC"
+};
+
+int
+dostat(devfd, modnum, modname)
+ int devfd;
+ int modnum;
+ char *modname;
+{
+ struct lmc_stat sbuf;
+
+ sbuf.name[MAXLKMNAME - 1] = '\0'; /* In case strncpy limits the string. */
+ if (modname != NULL)
+ strncpy(sbuf.name, modname, MAXLKMNAME - 1);
+
+ sbuf.id = modnum;
+
+ if (ioctl(devfd, LMSTAT, &sbuf) == -1) {
+ switch (errno) {
+ case EINVAL: /* out of range */
+ return 2;
+ case ENOENT: /* no such entry */
+ return 1;
+ default: /* other error (EFAULT, etc) */
+ warn("LMSTAT");
+ return 4;
+ }
+ }
+
+ /*
+ * Decode this stat buffer...
+ */
+ printf("%-7s %3d %3d %08x %04x %8x %3d %s\n",
+ type_names[sbuf.type],
+ sbuf.id, /* module id */
+ sbuf.offset, /* offset into modtype struct */
+ sbuf.area, /* address module loaded at */
+ sbuf.size, /* size in pages(K) */
+ sbuf.private, /* kernel address of private area */
+ sbuf.ver, /* Version; always 1 for now */
+ sbuf.name /* name from private area */
+ );
+
+ /*
+ * Done (success).
+ */
+ return 0;
+}
+
+int devfd;
+
+void
+cleanup()
+{
+
+ close(devfd);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ int modnum = -1;
+ char *modname = NULL;
+
+ while ((c = getopt(argc, argv, "i:n:")) != -1) {
+ switch (c) {
+ case 'i':
+ modnum = atoi(optarg);
+ break; /* number */
+ case 'n':
+ modname = optarg;
+ break; /* name */
+ case '?':
+ usage();
+ default:
+ printf("default!\n");
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ /*
+ * Open the virtual device device driver for exclusive use (needed
+ * to ioctl() to retrive the loaded module(s) status).
+ */
+ if ((devfd = open(_PATH_LKM, O_RDONLY, 0)) == -1)
+ err(2, _PATH_LKM);
+
+ atexit(cleanup);
+
+ printf("Type Id Off Loadaddr Size Info Rev Module Name\n");
+
+ /*
+ * Oneshot?
+ */
+ if (modnum != -1 || modname != NULL) {
+ if (dostat(devfd, modnum, modname))
+ exit(3);
+ exit(0);
+ }
+
+ /*
+ * Start at 0 and work up until "EINVAL".
+ */
+ for (modnum = 0; dostat(devfd, modnum, NULL) < 2; modnum++)
+ ;
+
+ exit(0);
+}
diff --git a/usr.bin/modstat/pathnames.h b/usr.bin/modstat/pathnames.h
new file mode 100644
index 0000000..81f70f2
--- /dev/null
+++ b/usr.bin/modstat/pathnames.h
@@ -0,0 +1,3 @@
+#include <paths.h>
+
+#define _PATH_LKM "/dev/lkm"
diff --git a/usr.bin/more/Makefile b/usr.bin/more/Makefile
index 58f9e81..e63efcf 100644
--- a/usr.bin/more/Makefile
+++ b/usr.bin/more/Makefile
@@ -1,15 +1,16 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
PROG= more
-CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR} -DTERMIOS
SRCS= ch.c command.c decode.c help.c input.c line.c linenum.c main.c \
option.c os.c output.c position.c prim.c screen.c signal.c tags.c \
ttyin.c
-DPADD= ${LIBTERM} ${LIBCOMPAT}
-LDADD= -ltermcap -lcompat
+DPADD= ${LIBTERMCAP}
+LDADD= -ltermcap
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/more.help \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/more.help \
${DESTDIR}/usr/share/misc
.include <bsd.prog.mk>
diff --git a/usr.bin/more/ch.c b/usr.bin/more/ch.c
index 668e601..52e80d0 100644
--- a/usr.bin/more/ch.c
+++ b/usr.bin/more/ch.c
@@ -96,7 +96,7 @@ static off_t last_piped_pos;
#define ch_get() \
((buf_head->block == ch_block && \
ch_offset < buf_head->datasize) ? \
- buf_head->data[ch_offset] : fch_get())
+ (unsigned char)buf_head->data[ch_offset] : fch_get())
static
fch_get()
@@ -130,7 +130,7 @@ fch_get()
* find it already buffered.
*/
if (ispipe)
- return(bp->data[ch_offset]);
+ return((unsigned char)bp->data[ch_offset]);
goto found;
}
/*
@@ -189,15 +189,15 @@ read_more:
if (bs_mode) {
for (p = &bp->data[bp->datasize]; --n >= 0;) {
- *--p &= 0177;
+ *--p;
if (*p == EOI)
*p = 0200;
}
}
else {
for (t = p; --n >= 0; ++p) {
- ch = *p & 0177;
- if (ch == '\r' && n && (p[1] & 0177) == '\n') {
+ ch = *p;
+ if (ch == '\r' && n && p[1] == '\n') {
++p;
*t++ = '\n';
}
@@ -233,7 +233,7 @@ found:
*/
goto read_more;
- return(bp->data[ch_offset]);
+ return((unsigned char)bp->data[ch_offset]);
}
/*
@@ -428,7 +428,7 @@ ch_addbuf(nnew)
char *calloc();
/*
- * We don't have enough buffers.
+ * We don't have enough buffers.
* Allocate some new ones.
*/
newbufs = (struct buf *)calloc((u_int)nnew, sizeof(struct buf));
diff --git a/usr.bin/more/command.c b/usr.bin/more/command.c
index 51f5847..2b8d3a4 100644
--- a/usr.bin/more/command.c
+++ b/usr.bin/more/command.c
@@ -39,6 +39,7 @@ static char sccsid[] = "@(#)command.c 8.1 (Berkeley) 6/6/93";
#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
+#include <string.h>
#include <less.h>
#include "pathnames.h"
@@ -76,6 +77,7 @@ static int wsearch; /* Search for matches (1) or non-matches (0) */
static
cmd_erase()
{
+ int c;
/*
* backspace past beginning of the string: this usually means
* abort the command.
@@ -84,7 +86,8 @@ cmd_erase()
return(1);
/* erase an extra character, for the carat. */
- if (CONTROL_CHAR(*--cp)) {
+ c = *--cp;
+ if (CONTROL_CHAR(c)) {
backspace();
--cmd_col;
}
@@ -141,6 +144,7 @@ cmd_char(c)
if (CONTROL_CHAR(c)) {
putchr('^');
cmd_col++;
+ c &= ~0200;
c = CARAT_CHAR(c);
}
putchr(c);
@@ -170,7 +174,7 @@ prompt()
repaint();
/* if no -e flag and we've hit EOF on the last file, quit. */
- if ((!quit_at_eof || short_file) && hit_eof && curr_ac + 1 >= ac)
+ if (!quit_at_eof && hit_eof && curr_ac + 1 >= ac)
quit();
/* select the proper prompt and display it. */
@@ -484,7 +488,7 @@ again: if (sigs)
* to 0 and get a new character for the start
* of the pattern.
*/
- start_mca(action,
+ start_mca(action,
(action == A_F_SEARCH) ? "!/" : "!?");
wsearch = 0;
c = getcc();
@@ -494,10 +498,10 @@ again: if (sigs)
if (number <= 0)
number = 1;
if (wsearch)
- start_mca(last_mca,
+ start_mca(last_mca,
(last_mca == A_F_SEARCH) ? "/" : "?");
else
- start_mca(last_mca,
+ start_mca(last_mca,
(last_mca == A_F_SEARCH) ? "!/" : "!?");
CMD_EXEC;
(void)search(mca == A_F_SEARCH, (char *)NULL,
@@ -573,6 +577,7 @@ again: if (sigs)
start_mca(A_PREFIX, "");
if (CONTROL_CHAR(c)) {
putchr('^');
+ c &= ~0200;
c = CARAT_CHAR(c);
}
putchr(c);
@@ -590,16 +595,27 @@ editfile()
extern char *current_file;
static int dolinenumber;
static char *editor;
+ char *base;
int c;
char buf[MAXPATHLEN * 2 + 20], *getenv();
if (editor == NULL) {
editor = getenv("EDITOR");
- /* pass the line number to vi */
- if (editor == NULL || *editor == '\0') {
+
+ /* default editor is vi */
+ if (editor == NULL || *editor == '\0')
editor = _PATH_VI;
+
+ /* check last component in case of full path */
+ base = strrchr(editor, '/');
+ if (!base)
+ base = editor;
+ else
+ base++;
+
+ /* emacs also accepts vi-style +nnnn */
+ if (strcmp(base, "vi") == 0 || strcmp(base, "emacs") == 0)
dolinenumber = 1;
- }
else
dolinenumber = 0;
}
diff --git a/usr.bin/more/input.c b/usr.bin/more/input.c
index 521bc53..bdf65bb 100644
--- a/usr.bin/more/input.c
+++ b/usr.bin/more/input.c
@@ -37,7 +37,7 @@ static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
- * High level routines dealing with getting lines of input
+ * High level routines dealing with getting lines of input
* from the file being viewed.
*
* When we speak of "lines" here, we mean PRINTABLE lines;
@@ -204,7 +204,7 @@ back_line(curr_pos)
* until we reach the curr_pos.
*
* {{ This algorithm is pretty inefficient if the lines
- * are much longer than the screen width,
+ * are much longer than the screen width,
* but I don't know of any better way. }}
*/
if (ch_seek(new_pos))
diff --git a/usr.bin/more/less.h b/usr.bin/more/less.h
index 70de6de..c4dd23f 100644
--- a/usr.bin/more/less.h
+++ b/usr.bin/more/less.h
@@ -47,7 +47,7 @@
#define BO_CHAR '\203' /* Enter boldface mode */
#define BE_CHAR '\204' /* Exit boldface mode */
-#define CONTROL_CHAR(c) (iscntrl(c))
+#define CONTROL_CHAR(c) (!isprint(c))
#define CARAT_CHAR(c) ((c == '\177') ? '?' : (c | 0100))
#define TOP (0)
diff --git a/usr.bin/more/line.c b/usr.bin/more/line.c
index 7634f35..0f2b6c6 100644
--- a/usr.bin/more/line.c
+++ b/usr.bin/more/line.c
@@ -67,9 +67,9 @@ static int column; /* Printable length, accounting for
* else to end boldface mode.
* LN_UL_X means we are one character after LN_UNDERLINE
* (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
- * LN_UL_XB means we are one character after LN_UL_X
+ * LN_UL_XB means we are one character after LN_UL_X
* (we have gotten the backspace in "_\bX" or "X\b_";
- * we expect one more ordinary character,
+ * we expect one more ordinary character,
* which will put us back in state LN_UNDERLINE).
* LN_BO_X means we are one character after LN_BOLDFACE
* (we have gotten the 'X' in "X\bX").
@@ -155,7 +155,7 @@ pappend(c)
* Almost out of room in the line buffer.
* Don't take any chances.
* {{ Linebuf is supposed to be big enough that this
- * will never happen, but may need to be made
+ * will never happen, but may need to be made
* bigger for wide screens or lots of backspaces. }}
*/
return(1);
@@ -167,10 +167,9 @@ pappend(c)
switch (ln_state) {
case LN_NORMAL:
if (curr <= linebuf + 1
- || curr[-1] != (char)('H' | 0200))
+ || curr[-1] != '\b')
break;
- column -= 2;
- if (c == curr[-2])
+ if (c == ((unsigned char)curr[-2]))
goto enter_boldface;
if (c == '_' || curr[-2] == '_')
goto enter_underline;
@@ -183,9 +182,9 @@ enter_boldface:
* Switch into boldface mode.
*/
column--;
- if (column + bo_width + be_width + 1 >= sc_width)
+ if (column + bo_width + be_width >= sc_width)
/*
- * Not enough room left on the screen to
+ * Not enough room left on the screen to
* enter and exit boldface mode.
*/
return (1);
@@ -194,7 +193,7 @@ enter_boldface:
&& curr[-3] == ' ') {
/*
* Special case for magic cookie terminals:
- * if the previous char was a space, replace
+ * if the previous char was a space, replace
* it with the "enter boldface" sequence.
*/
curr[-3] = BO_CHAR;
@@ -213,19 +212,19 @@ enter_underline:
* the current char). Switch into underline mode.
*/
column--;
- if (column + ul_width + ue_width + 1 >= sc_width)
+ if (column + ul_width + ue_width >= sc_width)
/*
- * Not enough room left on the screen to
+ * Not enough room left on the screen to
* enter and exit underline mode.
*/
return (1);
- if (ul_width > 0 &&
+ if (ul_width > 0 &&
curr > linebuf + 2 && curr[-3] == ' ')
{
/*
* Special case for magic cookie terminals:
- * if the previous char was a space, replace
+ * if the previous char was a space, replace
* it with the "enter underline" sequence.
*/
curr[-3] = UL_CHAR;
@@ -243,7 +242,7 @@ enter_underline:
/*
* Termination of a sequence "_\bX" or "X\b_".
*/
- if (c != '_' && curr[-2] != '_' && c == curr[-2])
+ if (c != '_' && curr[-2] != '_' && c == ((unsigned char)curr[-2]))
{
/*
* We seem to have run on from underlining
@@ -260,7 +259,7 @@ enter_underline:
}
ln_ul_xb_case:
if (c == '_')
- c = curr[-2];
+ c = (unsigned char)curr[-2];
curr -= 2;
ln_state = LN_UNDERLINE;
break;
@@ -268,7 +267,7 @@ ln_ul_xb_case:
/*
* Termination of a sequnce "X\bX".
*/
- if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
+ if (c != ((unsigned char)curr[-2]) && (c == '_' || curr[-2] == '_'))
{
/*
* We seem to have run on from
@@ -286,9 +285,9 @@ ln_bo_xb_case:
ln_state = LN_BOLDFACE;
break;
case LN_UNDERLINE:
- if (column + ue_width + bo_width + 1 + be_width >= sc_width)
+ if (column + ue_width + bo_width + be_width >= sc_width)
/*
- * We have just barely enough room to
+ * We have just barely enough room to
* exit underline mode and handle a possible
* underline/boldface run on mixup.
*/
@@ -301,9 +300,9 @@ ln_bo_xb_case:
ln_state = LN_BO_XB;
break;
}
- if (column + be_width + ul_width + 1 + ue_width >= sc_width)
+ if (column + be_width + ul_width + ue_width >= sc_width)
/*
- * We have just barely enough room to
+ * We have just barely enough room to
* exit underline mode and handle a possible
* underline/boldface run on mixup.
*/
@@ -334,7 +333,7 @@ ln_bo_xb_case:
else
curr++;
ln_state = LN_NORMAL;
- }
+ }
break;
case LN_BO_X:
if (c == '\b')
@@ -360,7 +359,7 @@ ln_bo_xb_case:
else
curr++;
ln_state = LN_NORMAL;
- }
+ }
break;
}
}
@@ -378,30 +377,31 @@ ln_bo_xb_case:
if (c == '\b') {
if (ln_state == LN_NORMAL)
- NEW_COLUMN(2);
+ NEW_COLUMN(0);
else
column--;
- *curr++ = ('H' | 0200);
+ *curr++ = c;
return(0);
- }
+ }
- if (CONTROL_CHAR(c)) {
- /*
- * Put a "^X" into the buffer. The 0200 bit is used to tell
- * put_line() to prefix the char with a ^. We don't actually
- * put the ^ in the buffer because we sometimes need to move
- * chars around, and such movement might separate the ^ from
- * its following character.
- */
+ switch ((char)c) {
+ case UL_CHAR:
+ case UE_CHAR:
+ case BO_CHAR:
+ case BE_CHAR:
+ c &= ~0200;
+ /* fall through */
+ case '\200':
NEW_COLUMN(2);
- *curr++ = (CARAT_CHAR(c) | 0200);
- return(0);
+ break;
+ default:
+ if (CONTROL_CHAR(c))
+ NEW_COLUMN(2);
+ else
+ NEW_COLUMN(1);
+ break;
}
- /*
- * Ordinary character. Just put it in the buffer.
- */
- NEW_COLUMN(1);
*curr++ = c;
return (0);
}
diff --git a/usr.bin/more/linenum.c b/usr.bin/more/linenum.c
index 4bfefa8..dd3d82d 100644
--- a/usr.bin/more/linenum.c
+++ b/usr.bin/more/linenum.c
@@ -242,7 +242,7 @@ longloopmessage()
ierror("Calculating line numbers");
/*
* Set the lnloop flag here, so if the user interrupts while
- * we are calculating line numbers, the signal handler will
+ * we are calculating line numbers, the signal handler will
* turn off line numbers (linenums=0).
*/
lnloop = 1;
@@ -292,9 +292,9 @@ find_linenum(pos)
* reading the file forward or backward till we
* get to the place we want.
*
- * First decide whether we should go forward from the
+ * First decide whether we should go forward from the
* previous one or backwards from the next one.
- * The decision is based on which way involves
+ * The decision is based on which way involves
* traversing fewer bytes in the file.
*/
flush();
diff --git a/usr.bin/more/main.c b/usr.bin/more/main.c
index f019bdc..26be68b 100644
--- a/usr.bin/more/main.c
+++ b/usr.bin/more/main.c
@@ -50,7 +50,9 @@ static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/7/93";
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
-#include <less.h>
+#include <stdlib.h>
+#include <locale.h>
+#include "less.h"
int ispipe;
int new_file;
@@ -250,7 +252,9 @@ main(argc, argv)
char **argv;
{
int envargc, argcnt;
- char *envargv[2], *getenv();
+ char *envargv[2];
+
+ (void) setlocale(LC_ALL, "");
/*
* Process command line arguments and MORE environment arguments.
@@ -284,7 +288,8 @@ main(argc, argv)
*/
if (ac < 1) {
(void)edit("-");
- cat_file();
+ if (file >= 0)
+ cat_file();
} else {
do {
(void)edit((char *)NULL);
@@ -337,7 +342,7 @@ char *
save(s)
char *s;
{
- char *p, *strcpy(), *malloc();
+ char *p, *strcpy();
p = malloc((u_int)strlen(s)+1);
if (p == NULL)
diff --git a/usr.bin/more/more.1 b/usr.bin/more/more.1
index 209b617..3355c04 100644
--- a/usr.bin/more/more.1
+++ b/usr.bin/more/more.1
@@ -79,9 +79,6 @@ exits as soon as it reaches end-of-file. The
.Fl e
option tells more to
exit if it reaches end-of-file twice without an intervening operation.
-If the file is shorter than a single screen
-.Nm more
-will exit at end-of-file regardless.
.It Fl i
The
.Fl i
@@ -212,8 +209,10 @@ All marks are lost when a new file is examined.
.It Ic \&/ Ns Ar pattern
Search forward in the file for the N-th line containing the pattern.
N defaults to 1.
-The pattern is a regular expression, as recognized by
-.Xr ed .
+The pattern is a POSIX.2
+.Dq extended format
+regular expression, as described in
+.Xr re_format 7 .
The search starts at the second line displayed.
.It Ic \&? Ns Ar pattern
Search backward in the file for the N-th line containing the pattern.
@@ -288,6 +287,9 @@ characteristics necessary to manipulate the screen.
.Sh SEE ALSO
.Xr ctags 1 ,
.Xr vi 1
+.Sh BUGS
+Incorrect output can result from omitting the -u flag when accessing regular
+files with CRLF line termination.
.Sh AUTHOR
This software is derived from software contributed to Berkeley
by Mark Nudleman.
diff --git a/usr.bin/more/option.c b/usr.bin/more/option.c
index 29349d0..a95e700 100644
--- a/usr.bin/more/option.c
+++ b/usr.bin/more/option.c
@@ -69,7 +69,7 @@ option(argc, argv)
(*a)[0] = '-';
optind = 1; /* called twice, re-init getopt. */
- while ((ch = getopt(argc, argv, "0123456789/:ceinst:ux:f")) != EOF)
+ while ((ch = getopt(argc, argv, "0123456789/:ceinst:ux:f")) != -1)
switch((char)ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
diff --git a/usr.bin/more/output.c b/usr.bin/more/output.c
index 21514ede..5b0a562 100644
--- a/usr.bin/more/output.c
+++ b/usr.bin/more/output.c
@@ -33,15 +33,16 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* High level routines dealing with the output to the screen.
*/
+#include <ctype.h>
#include <stdio.h>
-#include <less.h>
+#include "less.h"
int errmsgs; /* Count of messages displayed by error() */
@@ -54,6 +55,8 @@ extern int tabstop;
extern int screen_trashed;
extern int any_display;
extern char *line;
+extern int mode_flags;
+static int last_pos_highlighted = 0;
/* display the line which is in the line buffer. */
put_line()
@@ -75,14 +78,19 @@ put_line()
if (line == NULL)
line = "";
+ if (last_pos_highlighted)
+ {
+ clear_eol();
+ last_pos_highlighted = 0;
+ }
column = 0;
for (p = line; *p != '\0'; p++)
{
- switch (c = *p)
+ switch ((char)(c = (unsigned char)*p))
{
case UL_CHAR:
ul_enter();
- column += ul_width +1;
+ column += ul_width;
break;
case UE_CHAR:
ul_exit();
@@ -90,7 +98,7 @@ put_line()
break;
case BO_CHAR:
bo_enter();
- column += bo_width +1;
+ column += bo_width;
break;
case BE_CHAR:
bo_exit();
@@ -108,15 +116,11 @@ put_line()
column--;
break;
default:
- if (c & 0200)
+ if (c == 0200 || CONTROL_CHAR(c))
{
- /*
- * Control characters arrive here as the
- * normal character [CARAT_CHAR(c)] with
- * the 0200 bit set. See pappend().
- */
+ c &= ~0200;
putchr('^');
- putchr(c & 0177);
+ putchr(CARAT_CHAR(c));
column += 2;
} else
{
@@ -124,6 +128,8 @@ put_line()
column++;
}
}
+ if (column == sc_width && mode_flags)
+ last_pos_highlighted = 1;
}
if (column < sc_width || !auto_wrap || ignaw)
putchr('\n');
@@ -204,17 +210,15 @@ error(s)
* edit() makes sure these messages can be seen before they
* are overwritten or scrolled away.
*/
- if (s != NULL) {
- (void)write(2, s, strlen(s));
- (void)write(2, "\n", 1);
- }
+ (void)write(2, s, strlen(s));
+ (void)write(2, "\n", 1);
return;
}
lower_left();
clear_eol();
so_enter();
- if (s != NULL) {
+ if (s) {
putstr(s);
putstr(" ");
}
@@ -228,7 +232,7 @@ error(s)
}
lower_left();
- if ((s != NULL ? strlen(s) : 0) + sizeof(return_to_continue) +
+ if ((s==NULL)?0:(strlen(s)) + sizeof(return_to_continue) +
so_width + se_width + 1 > sc_width)
/*
* Printing the message has probably scrolled the screen.
diff --git a/usr.bin/more/position.c b/usr.bin/more/position.c
index 8564be0..57ffb32 100644
--- a/usr.bin/more/position.c
+++ b/usr.bin/more/position.c
@@ -42,7 +42,7 @@ static char sccsid[] = "@(#)position.c 8.1 (Berkeley) 6/6/93";
* first char on each currently displayed line.
*
* {{ The position table is scrolled by moving all the entries.
- * Would be better to have a circular table
+ * Would be better to have a circular table
* and just change a couple of pointers. }}
*/
diff --git a/usr.bin/more/prim.c b/usr.bin/more/prim.c
index d5af8f3..adb17d1 100644
--- a/usr.bin/more/prim.c
+++ b/usr.bin/more/prim.c
@@ -43,6 +43,8 @@ static char sccsid[] = "@(#)prim.c 8.1 (Berkeley) 6/6/93";
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
+#include <regex.h>
+#include <limits.h>
#include <less.h>
int back_scroll = -1;
@@ -113,7 +115,7 @@ forw(n, pos, only_last)
squish_check();
/*
- * do_repaint tells us not to display anything till the end,
+ * do_repaint tells us not to display anything till the end,
* then just repaint the entire screen.
*/
do_repaint = (only_last && n > sc_height-1);
@@ -288,7 +290,7 @@ backward(n, only_last)
* never empty.
*/
if (pos == NULL_POSITION)
- return;
+ return;
back(n, pos, only_last);
}
@@ -354,9 +356,9 @@ jump_back(n)
* nearest known line rather than at the beginning. }}
*/
if (ch_seek((off_t)0)) {
- /*
- * Probably a pipe with beginning of file no longer buffered.
- * If he wants to go to line 1, we do the best we can,
+ /*
+ * Probably a pipe with beginning of file no longer buffered.
+ * If he wants to go to line 1, we do the best we can,
* by going to the first line which is still buffered.
*/
if (n <= 1 && ch_beg_seek() == 0)
@@ -427,7 +429,7 @@ jump_loc(pos)
if ((nline = onscreen(pos)) >= 0) {
/*
- * The line is currently displayed.
+ * The line is currently displayed.
* Just scroll there.
*/
forw(nline, position(BOTTOM_PLUS_ONE), 0);
@@ -577,7 +579,7 @@ get_back_scroll()
}
/*
- * Search for the n-th occurence of a specified pattern,
+ * Search for the n-th occurence of a specified pattern,
* either forward or backward.
*/
search(search_forward, pattern, n, wantmatch)
@@ -591,86 +593,31 @@ search(search_forward, pattern, n, wantmatch)
register char *q;
int linenum;
int linematch;
-#ifdef RECOMP
- char *re_comp();
- char *errmsg;
-#else
-#ifdef REGCMP
- char *regcmp();
- static char *cpattern = NULL;
-#else
- static char lpbuf[100];
- static char *last_pattern = NULL;
- char *strcpy();
-#endif
-#endif
+ static regex_t rx;
+ static int oncethru;
+ int regerr;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ if (pattern && pattern[0]) {
+ if (oncethru) {
+ regfree(&rx);
+ }
- /*
- * For a caseless search, convert any uppercase in the pattern to
- * lowercase.
- */
- if (caseless && pattern != NULL)
- for (p = pattern; *p; p++)
- if (isupper(*p))
- *p = tolower(*p);
-#ifdef RECOMP
+ regerr = regcomp(&rx, pattern, (REG_EXTENDED | REG_NOSUB
+ | (caseless ? REG_ICASE : 0)));
- /*
- * (re_comp handles a null pattern internally,
- * so there is no need to check for a null pattern here.)
- */
- if ((errmsg = re_comp(pattern)) != NULL)
- {
- error(errmsg);
- return(0);
- }
-#else
-#ifdef REGCMP
- if (pattern == NULL || *pattern == '\0')
- {
- /*
- * A null pattern means use the previous pattern.
- * The compiled previous pattern is in cpattern, so just use it.
- */
- if (cpattern == NULL)
- {
- error("No previous regular expression");
- return(0);
- }
- } else
- {
- /*
- * Otherwise compile the given pattern.
- */
- char *s;
- if ((s = regcmp(pattern, 0)) == NULL)
- {
- error("Invalid pattern");
- return(0);
- }
- if (cpattern != NULL)
- free(cpattern);
- cpattern = s;
- }
-#else
- if (pattern == NULL || *pattern == '\0')
- {
- /*
- * Null pattern means use the previous pattern.
- */
- if (last_pattern == NULL)
- {
- error("No previous regular expression");
- return(0);
+ if (regerr) {
+ regerror(regerr, &rx, errbuf, sizeof errbuf);
+ error(errbuf);
+ oncethru = 0;
+ regfree(&rx);
+ return 0;
}
- pattern = last_pattern;
- } else
- {
- (void)strcpy(lpbuf, pattern);
- last_pattern = lpbuf;
+ oncethru = 1;
+ } else if (!oncethru) {
+ error("No previous regular expression");
+ return 0;
}
-#endif
-#endif
/*
* Figure out where to start the search.
@@ -709,8 +656,8 @@ search(search_forward, pattern, n, wantmatch)
for (;;)
{
/*
- * Get lines until we find a matching one or
- * until we hit end-of-file (or beginning-of-file
+ * Get lines until we find a matching one or
+ * until we hit end-of-file (or beginning-of-file
* if we're going backwards).
*/
if (sigs)
@@ -722,7 +669,7 @@ search(search_forward, pattern, n, wantmatch)
if (search_forward)
{
/*
- * Read the next line, and save the
+ * Read the next line, and save the
* starting position of that line in linepos.
*/
linepos = pos;
@@ -781,18 +728,9 @@ search(search_forward, pattern, n, wantmatch)
/*
* Test the next line to see if we have a match.
- * This is done in a variety of ways, depending
- * on what pattern matching functions are available.
*/
-#ifdef REGCMP
- linematch = (regex(cpattern, line) != NULL);
-#else
-#ifdef RECOMP
- linematch = (re_exec(line) == 1);
-#else
- linematch = match(pattern, line);
-#endif
-#endif
+ linematch = !regexec(&rx, line, 0, 0, 0);
+
/*
* We are successful if wantmatch and linematch are
* both true (want a match and got it),
@@ -809,26 +747,3 @@ search(search_forward, pattern, n, wantmatch)
return(1);
}
-#if !defined(REGCMP) && !defined(RECOMP)
-/*
- * We have neither regcmp() nor re_comp().
- * We use this function to do simple pattern matching.
- * It supports no metacharacters like *, etc.
- */
-static
-match(pattern, buf)
- char *pattern, *buf;
-{
- register char *pp, *lp;
-
- for ( ; *buf != '\0'; buf++)
- {
- for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
- if (*pp == '\0' || *lp == '\0')
- break;
- if (*pp == '\0')
- return (1);
- }
- return (0);
-}
-#endif
diff --git a/usr.bin/more/screen.c b/usr.bin/more/screen.c
index edfae1e..bf12ad6 100644
--- a/usr.bin/more/screen.c
+++ b/usr.bin/more/screen.c
@@ -106,6 +106,11 @@ int bo_width, be_width; /* Printing width of boldface sequences */
int ul_width, ue_width; /* Printing width of underline sequences */
int so_width, se_width; /* Printing width of standout sequences */
+int mode_flags = 0;
+#define M_SO 1
+#define M_UL 2
+#define M_BO 4
+
/*
* These two variables are sometimes defined in,
* and needed by, the termcap library.
@@ -120,9 +125,9 @@ char *tgoto();
/*
* Change terminal to "raw mode", or restore to "normal" mode.
- * "Raw mode" means
+ * "Raw mode" means
* 1. An outstanding read will complete on receipt of a single keystroke.
- * 2. Input is not echoed.
+ * 2. Input is not echoed.
* 3. On output, \n is mapped to \r\n.
* 4. \t is NOT expanded into spaces.
* 5. Signal-causing characters such as ctrl-C (interrupt),
@@ -160,7 +165,7 @@ raw_mode(on)
#if TERMIO
ospeed = s.c_cflag & CBAUD;
#else
- ospeed = cfgetospeed(&s);
+ /* more work needed here */
#endif
erase_char = s.c_cc[VERASE];
kill_char = s.c_cc[VKILL];
@@ -335,7 +340,7 @@ get_term()
if (hard || sc_move == NULL || *sc_move == '\0')
{
/*
- * This is not an error here, because we don't
+ * This is not an error here, because we don't
* always need sc_move.
* We need it only if we don't have home or lower-left.
*/
@@ -377,7 +382,7 @@ get_term()
{
/*
* This last resort for sc_home is supposed to
- * be an up-arrow suggesting moving to the
+ * be an up-arrow suggesting moving to the
* top of the "virtual screen". (The one in
* your imagination as you try to use this on
* a hard copy terminal.)
@@ -385,7 +390,7 @@ get_term()
sc_home = "|\b^";
} else
{
- /*
+ /*
* No "home" string,
* but we can use "move(0,0)".
*/
@@ -404,7 +409,7 @@ get_term()
} else
{
/*
- * No "lower-left" string,
+ * No "lower-left" string,
* but we can use "move(0,last-line)".
*/
(void)strcpy(sp, tgoto(sc_move, 0, sc_height-1));
@@ -417,7 +422,7 @@ get_term()
* To add a line at top of screen and scroll the display down,
* we use "al" (add line) or "sr" (scroll reverse).
*/
- if ((sc_addline = tgetstr("al", &sp)) == NULL ||
+ if ((sc_addline = tgetstr("al", &sp)) == NULL ||
*sc_addline == '\0')
sc_addline = tgetstr("sr", &sp);
@@ -440,7 +445,7 @@ get_term()
/*
- * Below are the functions which perform all the
+ * Below are the functions which perform all the
* terminal-specific screen manipulation.
*/
@@ -503,6 +508,12 @@ bell()
*/
clear()
{
+ if (mode_flags & M_SO)
+ so_exit();
+ if (mode_flags & M_UL)
+ ul_exit();
+ if (mode_flags & M_BO)
+ bo_exit();
tputs(sc_clear, sc_height, putchr);
}
@@ -512,6 +523,12 @@ clear()
*/
clear_eol()
{
+ if (mode_flags & M_SO)
+ so_exit();
+ if (mode_flags & M_UL)
+ ul_exit();
+ if (mode_flags & M_BO)
+ bo_exit();
tputs(sc_eol_clear, 1, putchr);
}
@@ -521,6 +538,7 @@ clear_eol()
so_enter()
{
tputs(sc_s_in, 1, putchr);
+ mode_flags |= M_SO;
}
/*
@@ -529,15 +547,17 @@ so_enter()
so_exit()
{
tputs(sc_s_out, 1, putchr);
+ mode_flags &= ~M_SO;
}
/*
- * Begin "underline" (hopefully real underlining,
+ * Begin "underline" (hopefully real underlining,
* otherwise whatever the terminal provides).
*/
ul_enter()
{
tputs(sc_u_in, 1, putchr);
+ mode_flags |= M_UL;
}
/*
@@ -546,6 +566,7 @@ ul_enter()
ul_exit()
{
tputs(sc_u_out, 1, putchr);
+ mode_flags &= ~M_UL;
}
/*
@@ -554,6 +575,7 @@ ul_exit()
bo_enter()
{
tputs(sc_b_in, 1, putchr);
+ mode_flags |= M_BO;
}
/*
@@ -562,15 +584,16 @@ bo_enter()
bo_exit()
{
tputs(sc_b_out, 1, putchr);
+ mode_flags &= ~M_BO;
}
/*
- * Erase the character to the left of the cursor
+ * Erase the character to the left of the cursor
* and move the cursor left.
*/
backspace()
{
- /*
+ /*
* Try to erase the previous character by overstriking with a space.
*/
tputs(sc_backspace, 1, putchr);
diff --git a/usr.bin/more/tags.c b/usr.bin/more/tags.c
index 029557e..0d805fa 100644
--- a/usr.bin/more/tags.c
+++ b/usr.bin/more/tags.c
@@ -147,7 +147,7 @@ findtag(tag)
* We don't use search() for several reasons:
* - We don't want to blow away any search string we may have saved.
* - The various regular-expression functions (from different systems:
- * regcmp vs. re_comp) behave differently in the presence of
+ * regcmp vs. re_comp) behave differently in the presence of
* parentheses (which are almost always found in a tag).
*/
tagsearch()
@@ -161,14 +161,14 @@ tagsearch()
for (;;)
{
/*
- * Get lines until we find a matching one or
+ * Get lines until we find a matching one or
* until we hit end-of-file.
*/
if (sigs)
return (1);
/*
- * Read the next line, and save the
+ * Read the next line, and save the
* starting position of that line in linepos.
*/
linepos = pos;
diff --git a/usr.bin/more/ttyin.c b/usr.bin/more/ttyin.c
index 52ff92e..51376cd 100644
--- a/usr.bin/more/ttyin.c
+++ b/usr.bin/more/ttyin.c
@@ -75,5 +75,5 @@ getchr()
quit();
}
} while (result != 1);
- return (c & 0177);
+ return ((unsigned char)c);
}
diff --git a/usr.bin/msgs/Makefile b/usr.bin/msgs/Makefile
index 2398907..8613f79c 100644
--- a/usr.bin/msgs/Makefile
+++ b/usr.bin/msgs/Makefile
@@ -1,7 +1,8 @@
-# @(#)Makefile 8.2 (Berkeley) 4/28/95
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
PROG= msgs
-DPADD= ${LIBTERM}
-LDADD= -ltermlib
+DPADD= ${LIBTERMCAP}
+LDADD= -ltermcap
.include <bsd.prog.mk>
diff --git a/usr.bin/msgs/msgs.1 b/usr.bin/msgs/msgs.1
index fe61924..2a763c2 100644
--- a/usr.bin/msgs/msgs.1
+++ b/usr.bin/msgs/msgs.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)msgs.1 8.2 (Berkeley) 4/28/95
+.\" @(#)msgs.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd April 28, 1995
+.Dd June 6, 1993
.Dt MSGS 1
.Os BSD 4
.Sh NAME
@@ -196,17 +196,17 @@ and
environment variables for the default home directory and
terminal type.
.Sh FILES
-.Bl -tag -width /usr/msgs/* -compact
-.It Pa /usr/msgs/*
+.Bl -tag -width /var/msgs/* -compact
+.It Pa /var/msgs/*
database
.It ~/.msgsrc
number of next message to be presented
.El
.Sh SEE ALSO
-.Xr aliases 5 ,
-.\".Xr crontab 5 ,
.Xr mail 1 ,
-.Xr more 1
+.Xr more 1 ,
+.Xr aliases 5
+.\".Xr crontab 5 ,
.Sh HISTORY
The
.Nm msgs
diff --git a/usr.bin/msgs/msgs.c b/usr.bin/msgs/msgs.c
index 6804282..9af8f58 100644
--- a/usr.bin/msgs/msgs.c
+++ b/usr.bin/msgs/msgs.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
@@ -64,28 +64,28 @@ static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
#define V7 /* will look for TERM in the environment */
#define OBJECT /* will object to messages without Subjects */
-/* #define REJECT /* will reject messages without Subjects
+/* #define REJECT */ /* will reject messages without Subjects
(OBJECT must be defined also) */
-/* #define UNBUFFERED /* use unbuffered output */
+/* #define UNBUFFERED *//* use unbuffered output */
#include <sys/param.h>
-#include <sys/dir.h>
-#include <sys/ioctl.h>
#include <sys/stat.h>
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
+#include <locale.h>
#include <pwd.h>
#include <setjmp.h>
+#include <termios.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "pathnames.h"
-#define CMODE 0666 /* bounds file creation mode */
+#define CMODE 0644 /* bounds file creation mode */
#define NO 0
#define YES 1
#define SUPERUSER 0 /* superuser uid */
@@ -154,13 +154,14 @@ int argc; char *argv[];
bool newrc, already;
int rcfirst = 0; /* first message to print (from .rc) */
int rcback = 0; /* amount to back off of rcfirst */
- int firstmsg, nextmsg, lastmsg = 0;
+ int firstmsg = 0, nextmsg = 0, lastmsg = 0;
int blast = 0;
FILE *bounds;
#ifdef UNBUFFERED
setbuf(stdout, NULL);
#endif
+ setlocale(LC_ALL, "");
time(&t);
setuid(uid = getuid());
@@ -244,7 +245,7 @@ int argc; char *argv[];
keep = t - (rcback? rcback : NDAYS) DAYS;
if (clean || bounds == NULL) { /* relocate message bounds */
- struct direct *dp;
+ struct dirent *dp;
struct stat stbuf;
bool seenany = NO;
DIR *dirp;
@@ -330,7 +331,7 @@ int argc; char *argv[];
perror(fname);
exit(errno);
}
- chmod(fname, 0644);
+ chmod(fname, CMODE);
fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
fclose(bounds);
@@ -631,7 +632,7 @@ int length;
fflush(stdout);
}
- /* trick to force wait on output */
+ /* force wait on output */
tcdrain(fileno(stdout));
}
@@ -854,9 +855,9 @@ FILE *infile;
char *
nxtfld(s)
-char *s;
+unsigned char *s;
{
- if (*s) while (*s && *s > ' ') s++; /* skip over this field */
- if (*s) while (*s && *s <= ' ') s++; /* find start of next field */
+ if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */
+ if (*s) while (*s && isspace(*s)) s++; /* find start of next field */
return (s);
}
diff --git a/usr.bin/mt/mt.1 b/usr.bin/mt/mt.1
index 9edaab6..54df097 100644
--- a/usr.bin/mt/mt.1
+++ b/usr.bin/mt/mt.1
@@ -60,7 +60,7 @@ The available commands are listed below. Only as many
characters as are required to uniquely identify a command
need be specified.
.Bl -tag -width "eof, weof"
-.It Cm eof , weof
+.It Cm weof
Write
.Ar count
end-of-file marks at the current position on the tape.
@@ -86,8 +86,33 @@ Rewind the tape
.It Cm offline , rewoffl
Rewind the tape and place the tape unit off-line
(Count is ignored).
+.It Cm erase
+Erase the tape
+(Count is ignored).
+.It Cm retension
+Re-tension the tape
+(one full wind forth and back, Count is ignored).
.It Cm status
Print status information about the tape unit.
+.It Cm blocksize
+Set the block size for the tape unit. Zero means variable-length
+blocks.
+.It Cm density
+Set the density for the tape unit. For the density codes, see below.
+The density value could be given either numerically, or as a string,
+corresponding to the
+.Dq Reference
+field. If the string is abbreviated, it will be resolved in the order
+shown in the table, and the first matching entry will be used. If the
+given string and the resulting canonical density name do not match
+exactly, an informational message is printed about what the given
+string has been taken for.
+.It Cm eom
+Forward space to end of recorded medium
+(Count is ignored).
+.It Cm comp
+Set compression mode.
+(Not yet implemented.)
.El
.Pp
If a tape name is not specified, and the environment variable
@@ -95,11 +120,68 @@ If a tape name is not specified, and the environment variable
does not exist;
.Nm mt
uses the device
-.Pa /dev/rmt12 .
+.Pa /dev/nrst0 .
.Pp
.Nm Mt
returns a 0 exit status when the operation(s) were successful,
1 if the command was unrecognized, and 2 if an operation failed.
+.Pp
+The different density codes are as follows:
+.Pp
+.Dl 0x0 default for device
+.Dl 0xE reserved for ECMA
+.Bd -literal -offset indent
+Value Tracks Density(bpi) Code Type Reference Note
+0x1 9 800 NRZI R X3.22-1983 2
+0x2 9 1600 PE R X3.39-1986 2
+0x3 9 6250 GCR R X3.54-1986 2
+0x5 4/9 8000 GCR C X3.136-1986 1
+0x6 9 3200 PE R X3.157-1987 2
+0x7 4 6400 IMFM C X3.116-1986 1
+0x8 4 8000 GCR CS X3.158-1986 1
+0x9 18 37871 GCR C X3B5/87-099 2
+0xA 22 6667 MFM C X3B5/86-199 1
+0xB 4 1600 PE C X3.56-1986 1
+0xC 24 12690 GCR C HI-TC1 1,5
+0xD 24 25380 GCR C HI-TC2 1,5
+0xF 15 10000 GCR C QIC-120 1,5
+0x10 18 10000 GCR C QIC-150 1,5
+0x11 26 16000 GCR C QIC-320(525?) 1,5
+0x12 30 51667 RLL C QIC-1350 1,5
+0x13 1 61000 DDS CS X3B5/88-185A 4
+0x14 1 43245 RLL CS X3.202-1991 4
+0x15 1 45434 RLL CS ECMA TC17 4
+0x16 48 10000 MFM C X3.193-1990 1
+0x17 48 42500 MFM C X3B5/91-174 1
+.Ed
+
+where Code means:
+.Bd -literal -offset indent
+NRZI Non Return to Zero, change on ones
+GCR Group Code Recording
+PE Phase Encoded
+IMFM Inverted Modified Frequency Modulation
+MFM Modified Frequency Modulation
+DDS Dat Data Storage
+RLL Run Length Encoding
+.Ed
+
+where Type means:
+.Bd -literal -offset indent
+R Reel-to-Reel
+C Cartridge
+CS cassette
+.Ed
+
+where Notes means:
+.Bd -literal -offset indent
+1 Serial Recorded
+2 Parallel Recorded
+3 Old format know as QIC-11
+4 Helical Scan
+5 Not ANSI standard, rather industry standard.
+.Ed
+
.Sh ENVIRONMENT
If the following environment variable exists, it is utilized by
.Nm mt .
@@ -113,12 +195,16 @@ argument
.Ar tapename
is not given.
.Sh FILES
-.Bl -tag -width /dev/rmt* -compact
-.It Pa /dev/rmt*
+.Bl -tag -width /dev/rwt* -compact
+.It Pa /dev/rwt*
Raw magnetic tape interface
+.It Pa /dev/*st[0-9]*
+SCSI magnetic tape interface
.El
.Sh SEE ALSO
.\".Xr mtio 4 ,
+.Xr st 4 ,
+.\".Xr wt 4 ,
.Xr dd 1 ,
.Xr ioctl 2 ,
.Xr environ 7
@@ -127,4 +213,14 @@ The
.Nm mt
command appeared in
.Bx 4.3 .
+
+Extensions regarding the
+.Xr st 4
+driver appeared in 386BSD 0.1 as a separate
+.Xr st 1
+command, and have been merged into the
+.Nm
+command in
+.Fx 2.1 .
.\" mt.1: mtio(4) missing
+.\" mt.1: wt(4) missing
diff --git a/usr.bin/mt/mt.c b/usr.bin/mt/mt.c
index 172a424..ae94971 100644
--- a/usr.bin/mt/mt.c
+++ b/usr.bin/mt/mt.c
@@ -57,14 +57,32 @@ static char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 5/4/95";
#include <string.h>
#include <unistd.h>
+/* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */
+#if defined(__FreeBSD__)
+/* c_flags */
+#define NEED_2ARGS 0x01
+#define ZERO_ALLOWED 0x02
+#define IS_DENSITY 0x04
+#define DISABLE_THIS 0x08
+#endif /* defined(__FreeBSD__) */
+
struct commands {
char *c_name;
int c_code;
int c_ronly;
+#if defined(__FreeBSD__)
+ int c_flags;
+#endif /* defined(__FreeBSD__) */
} com[] = {
{ "bsf", MTBSF, 1 },
{ "bsr", MTBSR, 1 },
- { "eof", MTWEOF, 0 },
+#if defined(__FreeBSD__)
+ /* XXX FreeBSD considered "eof" dangerous, since it's being
+ confused with "eom" (and is an alias for "weof" anyway) */
+ { "eof", MTWEOF, 0, DISABLE_THIS },
+#else
+ { "eof", MTWEOF, 0 },
+#endif
{ "fsf", MTFSF, 1 },
{ "fsr", MTFSR, 1 },
{ "offline", MTOFFL, 1 },
@@ -72,6 +90,14 @@ struct commands {
{ "rewoffl", MTOFFL, 1 },
{ "status", MTNOP, 1 },
{ "weof", MTWEOF, 0 },
+#if defined(__FreeBSD__)
+ { "erase", MTERASE, 0 },
+ { "blocksize", MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED },
+ { "density", MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED|IS_DENSITY },
+ { "eom", MTEOD, 1 },
+ { "comp", MTCOMP, 0, NEED_2ARGS|ZERO_ALLOWED },
+ { "retension", MTRETENS, 1 },
+#endif /* defined(__FreeBSD__) */
{ NULL }
};
@@ -79,6 +105,12 @@ void err __P((const char *, ...));
void printreg __P((char *, u_int, char *));
void status __P((struct mtget *));
void usage __P((void));
+#if defined (__FreeBSD__)
+void st_status (struct mtget *);
+int stringtodens (const char *s);
+const char *denstostring (int d);
+void warn_eof __P((void));
+#endif /* defined (__FreeBSD__) */
int
main(argc, argv)
@@ -94,7 +126,7 @@ main(argc, argv)
if ((tape = getenv("TAPE")) == NULL)
tape = DEFTAPE;
- while ((ch = getopt(argc, argv, "f:t:")) != EOF)
+ while ((ch = getopt(argc, argv, "f:t:")) != -1)
switch(ch) {
case 'f':
case 't':
@@ -117,13 +149,44 @@ main(argc, argv)
if (strncmp(p, comp->c_name, len) == 0)
break;
}
+#if defined(__FreeBSD__)
+ if((comp->c_flags & NEED_2ARGS) && argc != 2)
+ usage();
+ if(comp->c_flags & DISABLE_THIS) {
+ warn_eof();
+ }
+#endif /* defined(__FreeBSD__) */
if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0)
err("%s: %s", tape, strerror(errno));
if (comp->c_code != MTNOP) {
mt_com.mt_op = comp->c_code;
if (*argv) {
+#if defined (__FreeBSD__)
+ if (!isdigit(**argv) &&
+ comp->c_flags & IS_DENSITY) {
+ const char *dcanon;
+ mt_com.mt_count = stringtodens(*argv);
+ if (mt_com.mt_count == 0)
+ err("%s: unknown density", *argv);
+ dcanon = denstostring(mt_com.mt_count);
+ if (strcmp(dcanon, *argv) != 0)
+ printf(
+ "Using \"%s\" as an alias for %s\n",
+ *argv, dcanon);
+ p = "";
+ } else
+ /* allow for hex numbers; useful for density */
+ mt_com.mt_count = strtol(*argv, &p, 0);
+#else
mt_com.mt_count = strtol(*argv, &p, 10);
- if (mt_com.mt_count <= 0 || *p)
+#endif /* defined(__FreeBSD__) */
+ if (mt_com.mt_count <=
+#if defined (__FreeBSD__)
+ ((comp->c_flags & ZERO_ALLOWED)? -1: 0)
+#else
+ 0
+#endif /* defined (__FreeBSD__) */
+ || *p)
err("%s: illegal count", *argv);
}
else
@@ -158,6 +221,10 @@ main(argc, argv)
#include <tahoe/vba/cyreg.h>
#endif
+#ifdef __FreeBSD__
+#include <machine/wtio.h>
+#endif
+
struct tape_desc {
short t_type; /* type of magtape device */
char *t_name; /* printing name */
@@ -178,6 +245,19 @@ struct tape_desc {
#ifdef tahoe
{ MT_ISCY, "cipher", CYS_BITS, CYCW_BITS },
#endif
+#if defined (__FreeBSD__)
+ /*
+ * XXX This is weird. The st driver reports the tape drive
+ * as 0x7 (MT_ISAR - Sun/Archive compatible); the wt driver
+ * either reports MT_ISVIPER1 for an Archive tape, or 0x11
+ * (MT_ISMFOUR) for other tapes.
+ * XXX for the wt driver, rely on it behaving like a "standard"
+ * magtape driver.
+ */
+ { MT_ISAR, "SCSI tape drive", 0, 0 },
+ { MT_ISVIPER1, "Archive Viper", WTDS_BITS, WTER_BITS },
+ { MT_ISMFOUR, "Wangtek", WTDS_BITS, WTER_BITS },
+#endif /* defined (__FreeBSD__) */
{ 0 }
};
@@ -199,10 +279,18 @@ status(bp)
if (mt->t_type == bp->mt_type)
break;
}
+#if defined (__FreeBSD__)
+ if(mt->t_type == MT_ISAR)
+ st_status(bp);
+ else {
+#endif /* defined (__FreeBSD__) */
(void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid);
- printreg("ds", bp->mt_dsreg, mt->t_dsbits);
- printreg("\ner", bp->mt_erreg, mt->t_erbits);
+ printreg("ds", (unsigned short)bp->mt_dsreg, mt->t_dsbits);
+ printreg("\ner", (unsigned short)bp->mt_erreg, mt->t_erbits);
(void)putchar('\n');
+#if defined (__FreeBSD__)
+ }
+#endif /* defined (__FreeBSD__) */
}
/*
@@ -221,6 +309,8 @@ printreg(s, v, bits)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
+ if (!bits)
+ return;
bits++;
if (v && bits) {
putchar('<');
@@ -274,3 +364,104 @@ err(fmt, va_alist)
exit(1);
/* NOTREACHED */
}
+
+#if defined (__FreeBSD__)
+
+struct densities {
+ int dens;
+ const char *name;
+} dens [] = {
+ { 0x1, "X3.22-1983" },
+ { 0x2, "X3.39-1986" },
+ { 0x3, "X3.54-1986" },
+ { 0x5, "X3.136-1986" },
+ { 0x6, "X3.157-1987" },
+ { 0x7, "X3.116-1986" },
+ { 0x8, "X3.158-1986" },
+ { 0x9, "X3B5/87-099" },
+ { 0xA, "X3B5/86-199" },
+ { 0xB, "X3.56-1986" },
+ { 0xC, "HI-TC1" },
+ { 0xD, "HI-TC2" },
+ { 0xF, "QIC-120" },
+ { 0x10, "QIC-150" },
+ { 0x11, "QIC-320" },
+ { 0x12, "QIC-1350" },
+ { 0x13, "X3B5/88-185A" },
+ { 0x14, "X3.202-1991" },
+ { 0x15, "ECMA TC17" },
+ { 0x16, "X3.193-1990" },
+ { 0x17, "X3B5/91-174" },
+ { 0, 0 }
+};
+
+const char *
+denstostring(int d)
+{
+ static char buf[20];
+ struct densities *sd;
+
+ for (sd = dens; sd->dens; sd++)
+ if (sd->dens == d)
+ break;
+ if (sd->dens == 0) {
+ sprintf(buf, "0x%02x", d);
+ return buf;
+ } else
+ return sd->name;
+}
+
+int
+stringtodens(const char *s)
+{
+ struct densities *sd;
+ size_t l = strlen(s);
+
+ for (sd = dens; sd->dens; sd++)
+ if (strncasecmp(sd->name, s, l) == 0)
+ break;
+ return sd->dens;
+}
+
+
+const char *
+getblksiz(int bs)
+{
+ static char buf[25];
+ if (bs == 0)
+ return "variable";
+ else {
+ sprintf(buf, "= %d bytes", bs);
+ return buf;
+ }
+}
+
+
+void
+st_status(struct mtget *bp)
+{
+ printf("Present Mode: Density = %-12s Blocksize %s\n",
+ denstostring(bp->mt_density), getblksiz(bp->mt_blksiz));
+ printf("---------available modes---------\n");
+ printf("Mode 0: Density = %-12s Blocksize %s\n",
+ denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0));
+ printf("Mode 1: Density = %-12s Blocksize %s\n",
+ denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1));
+ printf("Mode 2: Density = %-12s Blocksize %s\n",
+ denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2));
+ printf("Mode 3: Density = %-12s Blocksize %s\n",
+ denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3));
+}
+
+void
+warn_eof(void)
+{
+ fprintf(stderr,
+ "The \"eof\" command has been disabled.\n"
+ "Use \"weof\" if you really want to write end-of-file marks,\n"
+ "or \"eom\" if you rather want to skip to the end of "
+ "recorded medium.\n");
+ exit(1);
+}
+
+#endif /* defined (__FreeBSD__) */
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index 51fc9fa..adf1916 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -1,13 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/12/93
PROG= netstat
-SRCS= if.c inet.c iso.c main.c mbuf.c mroute.c ns.c route.c \
- tp_astring.c unix.c
-CFLAGS+=-I/sys
-.PATH: ${.CURDIR}/../../sys/netiso
+SRCS= if.c inet.c main.c mbuf.c mroute.c ipx.c route.c \
+ unix.c atalk.c # iso.c ns.c tp_astring.c
+
+CFLAGS+=-I/sys # -g
+#.PATH: ${.CURDIR}/../../sys/netiso
BINGRP= kmem
BINMODE=2555
-LDADD= -lkvm
-DPADD= ${LIBKVM}
+DPADD= ${LIBKVM} ${LIBIPX}
+LDADD= -lkvm -lipx
.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/atalk.c b/usr.bin/netstat/atalk.c
new file mode 100644
index 0000000..e1fe34d
--- /dev/null
+++ b/usr.bin/netstat/atalk.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)atalk.c 1.1 (Whistle) 6/6/96";
+*/
+static const char rcsid[] =
+ "$Id$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+
+#include <netatalk/at.h>
+#include <netatalk/ddp_var.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "netstat.h"
+
+struct ddpcb ddpcb;
+struct socket sockb;
+
+static void atalk_erputil __P((int, int));
+
+static int first = 1;
+
+/*
+ * Print a summary of connections related to a Network Systems
+ * protocol. For XXX, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+static char *
+at_pr_net(struct sockaddr_at *sat, int numeric)
+{
+static char mybuf[50];
+
+ if (!numeric) {
+ switch(sat->sat_addr.s_net) {
+ case 0xffff:
+ return "????";
+ case ATADDR_ANYNET:
+ return("*");
+ }
+ }
+ sprintf(mybuf,"%hu",ntohs(sat->sat_addr.s_net));
+ return mybuf;
+}
+
+static char *
+at_pr_host(struct sockaddr_at *sat, int numeric)
+{
+static char mybuf[50];
+
+ if (!numeric) {
+ switch(sat->sat_addr.s_node) {
+ case ATADDR_BCAST:
+ return "bcast";
+ case ATADDR_ANYNODE:
+ return("*");
+ }
+ }
+ sprintf(mybuf,"%d",(unsigned int)sat->sat_addr.s_node);
+ return mybuf;
+}
+
+char *
+at_pr_port(struct sockaddr_at *sat)
+{
+static char mybuf[50];
+
+ switch(sat->sat_port) {
+ case ATADDR_ANYPORT:
+ return("*");
+ case 0xff:
+ return "????";
+ default:
+ sprintf(mybuf,"%d",(unsigned int)sat->sat_port);
+ }
+ return mybuf;
+}
+
+static char *
+at_pr_range(struct sockaddr_at *sat)
+{
+static char mybuf[50];
+
+ if(sat->sat_range.r_netrange.nr_firstnet
+ != sat->sat_range.r_netrange.nr_lastnet) {
+ sprintf(mybuf,"%d-%d",
+ ntohs(sat->sat_range.r_netrange.nr_firstnet),
+ ntohs(sat->sat_range.r_netrange.nr_lastnet));
+ } else {
+ sprintf(mybuf,"%d",
+ ntohs(sat->sat_range.r_netrange.nr_firstnet));
+ }
+ return mybuf;
+}
+
+
+/* what == 0 for addr only == 3 */
+/* 1 for net */
+/* 2 for host */
+/* 4 for port */
+/* 8 for numeric only */
+char *
+atalk_print(sa,what)
+ register struct sockaddr *sa;
+{
+ struct sockaddr_at *sat = (struct sockaddr_at *)sa;
+ static char mybuf[50];
+ int numeric = (what & 0x08);
+
+ mybuf[0] = 0;
+ switch (what & 0x13) {
+ case 0:
+ mybuf[0] = 0;
+ break;
+ case 1:
+ sprintf(mybuf,"%s",at_pr_net(sat, numeric));
+ break;
+ case 2:
+ sprintf(mybuf,"%s",at_pr_host(sat, numeric));
+ break;
+ case 3:
+ sprintf(mybuf,"%s.%s",
+ at_pr_net(sat, numeric),
+ at_pr_host(sat, numeric));
+ break;
+ case 0x10:
+ sprintf(mybuf,"%s", at_pr_range(sat));
+ }
+ if (what & 4) {
+ sprintf(mybuf+strlen(mybuf),".%s",at_pr_port(sat));
+ }
+ return mybuf;
+}
+
+char *
+atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what)
+{
+ int n;
+ static char buf[100];
+ struct sockaddr_at *sat1, *sat2;
+ struct sockaddr_at thesockaddr;
+ struct sockaddr *sa2;
+
+ sat1 = (struct sockaddr_at *)sa;
+ sat2 = (struct sockaddr_at *)mask;
+ sa2 = (struct sockaddr *)&thesockaddr;
+
+ thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net & sat2->sat_addr.s_net;
+ n = snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 |(what & 8)));
+ if(sat2->sat_addr.s_net != 0xFFFF) {
+ thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net | ~sat2->sat_addr.s_net;
+ n += snprintf(buf + n, sizeof(buf) - n,
+ "-%s", atalk_print(sa2, 1 |(what & 8)));
+ }
+ if(what & 2)
+ n += snprintf(buf + n, sizeof(buf) - n, ".%s", atalk_print(sa, what&(~1)));
+ return(buf);
+}
+
+void
+atalkprotopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct ddpcb cb;
+ register struct ddpcb *prev, *next;
+ struct ddpcb *initial;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&initial, sizeof (struct ddpcb *));
+ ddpcb = cb;
+ prev = (struct ddpcb *)off;
+ for (next = initial ;next != NULL; prev = next) {
+ u_long ppcb;
+
+ kread((u_long)next, (char *)&ddpcb, sizeof (ddpcb));
+ next = ddpcb.ddp_next;
+#if 0
+ if (!aflag && atalk_nullhost(ddpcb.ddp_lsat) ) {
+ continue;
+ }
+#endif
+ kread((u_long)ddpcb.ddp_socket,
+ (char *)&sockb, sizeof (sockb));
+ if (first) {
+ printf("Active ATALK connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8x ", ppcb);
+ printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
+ (struct sockaddr *)&ddpcb.ddp_lsat,7));
+ printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
+ (struct sockaddr *)&ddpcb.ddp_fsat,7));
+ putchar('\n');
+ }
+}
+#define ANY(x,y,z) \
+ ((x) ? printf("\t%d %s%s%s\n",x,y,plural(x),z) : 0)
+
+/*
+ * Dump DDP statistics structure.
+ */
+void
+ddp_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ddpstat ddpstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ddpstat, sizeof (ddpstat));
+ printf("%s:\n", name);
+ ANY(ddpstat.ddps_short, "packet", " with short headers ");
+ ANY(ddpstat.ddps_long, "packet", " with long headers ");
+ ANY(ddpstat.ddps_nosum, "packet", " with no checksum ");
+ ANY(ddpstat.ddps_tooshort, "packet", " too short ");
+ ANY(ddpstat.ddps_badsum, "packet", " with bad checksum ");
+ ANY(ddpstat.ddps_toosmall, "packet", " with not enough data ");
+ ANY(ddpstat.ddps_forward, "packet", " forwarded ");
+ ANY(ddpstat.ddps_encap, "packet", " encapsulated ");
+ ANY(ddpstat.ddps_cantforward, "packet", " rcvd for unreachable dest ");
+ ANY(ddpstat.ddps_nosockspace, "packet", " dropped due to no socket space ");
+}
+#undef ANY
+
+
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 90719bd..ca12cda 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -32,21 +32,35 @@
*/
#ifndef lint
+/*
static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95";
+*/
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <sys/types.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
+#endif
+#ifdef ISO
#include <netiso/iso.h>
#include <netiso/iso_var.h>
+#endif
#include <arpa/inet.h>
#include <signal.h>
@@ -71,15 +85,23 @@ intpr(interval, ifnetaddr)
u_long ifnetaddr;
{
struct ifnet ifnet;
+ struct ifnethead ifnethead;
union {
struct ifaddr ifa;
struct in_ifaddr in;
+ struct ipx_ifaddr ipx;
+#ifdef NS
struct ns_ifaddr ns;
+#endif
+#ifdef ISO
struct iso_ifaddr iso;
+#endif
} ifaddr;
u_long ifaddraddr;
+ u_long ifaddrfound;
+ u_long ifnetfound;
struct sockaddr *sa;
- char name[16];
+ char name[32], tname[16];
if (ifnetaddr == 0) {
printf("ifnet: symbol not defined\n");
@@ -89,11 +111,19 @@ intpr(interval, ifnetaddr)
sidewaysintpr((unsigned)interval, ifnetaddr);
return;
}
- if (kread(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr))
+ if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
return;
- printf("%-5.5s %-5.5s %-11.11s %-15.15s %8.8s %5.5s %8.8s %5.5s",
- "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs",
- "Opkts", "Oerrs");
+ ifnetaddr = (u_long)ifnethead.tqh_first;
+ if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
+ return;
+
+ printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ if (bflag)
+ printf(" %10.10s","Ibytes");
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (bflag)
+ printf(" %10.10s","Obytes");
printf(" %5s", "Coll");
if (tflag)
printf(" %s", "Time");
@@ -107,24 +137,25 @@ intpr(interval, ifnetaddr)
int n, m;
if (ifaddraddr == 0) {
+ ifnetfound = ifnetaddr;
if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) ||
- kread((u_long)ifnet.if_name, name, 16))
+ kread((u_long)ifnet.if_name, tname, 16))
return;
- name[15] = '\0';
- ifnetaddr = (u_long)ifnet.if_next;
- if (interface != 0 && (strcmp(name, interface) != 0 ||
- unit != ifnet.if_unit))
+ tname[15] = '\0';
+ ifnetaddr = (u_long)ifnet.if_link.tqe_next;
+ snprintf(name, 32, "%s%d", tname, ifnet.if_unit);
+ if (interface != 0 && (strcmp(name, interface) != 0))
continue;
cp = index(name, '\0');
- cp += sprintf(cp, "%d", ifnet.if_unit);
if ((ifnet.if_flags&IFF_UP) == 0)
*cp++ = '*';
*cp = '\0';
- ifaddraddr = (u_long)ifnet.if_addrlist;
+ ifaddraddr = (u_long)ifnet.if_addrhead.tqh_first;
}
- printf("%-5.5s %-5d ", name, ifnet.if_mtu);
+ printf("%-5.5s %-5lu ", name, ifnet.if_mtu);
+ ifaddrfound = ifaddraddr;
if (ifaddraddr == 0) {
- printf("%-11.11s ", "none");
+ printf("%-13.13s ", "none");
printf("%-15.15s ", "none");
} else {
if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
@@ -136,7 +167,7 @@ intpr(interval, ifnetaddr)
CP(&ifaddr); sa = (struct sockaddr *)cp;
switch (sa->sa_family) {
case AF_UNSPEC:
- printf("%-11.11s ", "none");
+ printf("%-13.13s ", "none");
printf("%-15.15s ", "none");
break;
case AF_INET:
@@ -147,31 +178,53 @@ intpr(interval, ifnetaddr)
*/
in = inet_makeaddr(ifaddr.in.ia_subnet,
INADDR_ANY);
- printf("%-11.11s ", netname(in.s_addr,
+ printf("%-13.13s ", netname(in.s_addr,
ifaddr.in.ia_subnetmask));
#else
- printf("%-11.11s ",
+ printf("%-13.13s ",
netname(htonl(ifaddr.in.ia_subnet),
ifaddr.in.ia_subnetmask));
#endif
printf("%-15.15s ",
routename(sin->sin_addr.s_addr));
break;
+ case AF_IPX:
+ {
+ struct sockaddr_ipx *sipx =
+ (struct sockaddr_ipx *)sa;
+ u_long net;
+ char netnum[10];
+
+ *(union ipx_net *) &net = sipx->sipx_addr.x_net;
+ sprintf(netnum, "%lx", ntohl(net));
+ printf("ipx:%-8s ", netnum);
+/* printf("ipx:%-8s ", netname(net, 0L)); */
+ printf("%-15s ",
+ ipx_phost((struct sockaddr *)sipx));
+ }
+ break;
+
+ case AF_APPLETALK:
+ printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
+ printf("%-9.9s ",atalk_print(sa,0x0b) );
+ break;
+#ifdef NS
case AF_NS:
{
struct sockaddr_ns *sns =
(struct sockaddr_ns *)sa;
u_long net;
- char netnum[8];
+ char netnum[10];
*(union ns_net *) &net = sns->sns_addr.x_net;
- sprintf(netnum, "%lxH", ntohl(net));
+ sprintf(netnum, "%lxH", ntohl(net));
upHex(netnum);
printf("ns:%-8s ", netnum);
printf("%-15s ",
ns_phost((struct sockaddr *)sns));
}
break;
+#endif
case AF_LINK:
{
struct sockaddr_dl *sdl =
@@ -189,36 +242,89 @@ intpr(interval, ifnetaddr)
cp = sa->sa_data;
hexprint:
while (--n >= 0)
- m += printf("%x%c", *cp++ & 0xff,
+ m += printf("%02x%c", *cp++ & 0xff,
n > 0 ? '.' : ' ');
- m = 28 - m;
+ m = 30 - m;
while (m-- > 0)
putchar(' ');
break;
}
- ifaddraddr = (u_long)ifaddr.ifa.ifa_next;
+ ifaddraddr = (u_long)ifaddr.ifa.ifa_link.tqe_next;
}
- printf("%8d %5d %8d %5d %5d",
- ifnet.if_ipackets, ifnet.if_ierrors,
- ifnet.if_opackets, ifnet.if_oerrors,
- ifnet.if_collisions);
+ printf("%8lu %5lu ",
+ ifnet.if_ipackets, ifnet.if_ierrors);
+ if (bflag)
+ printf("%10lu ", ifnet.if_ibytes);
+ printf("%8lu %5lu ",
+ ifnet.if_opackets, ifnet.if_oerrors);
+ if (bflag)
+ printf("%10lu ", ifnet.if_obytes);
+ printf("%5lu", ifnet.if_collisions);
if (tflag)
printf(" %3d", ifnet.if_timer);
if (dflag)
printf(" %3d", ifnet.if_snd.ifq_drops);
putchar('\n');
+ if (aflag && ifaddrfound) {
+ /*
+ * Print family's multicast addresses
+ */
+ u_long multiaddr;
+ struct ifmultiaddr ifma;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ struct sockaddr_dl dl;
+ } msa;
+ const char *fmt;
+
+ for(multiaddr = (u_long)ifnet.if_multiaddrs.lh_first;
+ multiaddr;
+ multiaddr = (u_long)ifma.ifma_link.le_next) {
+ if (kread(multiaddr, (char *)&ifma,
+ sizeof ifma))
+ break;
+ if (kread((u_long)ifma.ifma_addr, (char *)&msa,
+ sizeof msa))
+ break;
+ if (msa.sa.sa_family != sa->sa_family)
+ continue;
+
+ fmt = 0;
+ switch (msa.sa.sa_family) {
+ case AF_INET:
+ fmt = routename(msa.in.sin_addr.s_addr);
+ break;
+
+ case AF_LINK:
+ switch (ifnet.if_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ fmt = ether_ntoa(
+ (struct ether_addr *)
+ LLADDR(&msa.dl));
+ break;
+ }
+ break;
+ }
+ if (fmt)
+ printf("%23s %s\n", "", fmt);
+ }
+ }
}
}
#define MAXIF 10
struct iftot {
char ift_name[16]; /* interface name */
- int ift_ip; /* input packets */
- int ift_ie; /* input errors */
- int ift_op; /* output packets */
- int ift_oe; /* output errors */
- int ift_co; /* collisions */
- int ift_dr; /* drops */
+ u_int ift_ip; /* input packets */
+ u_int ift_ie; /* input errors */
+ u_int ift_op; /* output packets */
+ u_int ift_oe; /* output errors */
+ u_int ift_co; /* collisions */
+ u_int ift_dr; /* drops */
+ u_int ift_ib; /* input bytes */
+ u_int ift_ob; /* output bytes */
} iftot[MAXIF];
u_char signalled; /* set if alarm goes off "early" */
@@ -228,6 +334,7 @@ u_char signalled; /* set if alarm goes off "early" */
* Repeat display every interval seconds, showing statistics
* collected over that interval. Assumes that interval is non-zero.
* First line printed at top of screen is always cumulative.
+ * XXX - should be rewritten to use ifmib(4).
*/
static void
sidewaysintpr(interval, off)
@@ -236,120 +343,136 @@ sidewaysintpr(interval, off)
{
struct ifnet ifnet;
u_long firstifnet;
+ struct ifnethead ifnethead;
register struct iftot *ip, *total;
register int line;
struct iftot *lastif, *sum, *interesting;
- int oldmask;
+ int oldmask, first;
+ u_long interesting_off;
- if (kread(off, (char *)&firstifnet, sizeof (u_long)))
+ if (kread(off, (char *)&ifnethead, sizeof ifnethead))
return;
+ firstifnet = (u_long)ifnethead.tqh_first;
+
lastif = iftot;
sum = iftot + MAXIF - 1;
total = sum - 1;
- interesting = iftot;
+ interesting = NULL;
+ interesting_off = 0;
for (off = firstifnet, ip = iftot; off;) {
- char *cp;
+ char name[16], tname[16];
if (kread(off, (char *)&ifnet, sizeof ifnet))
break;
- ip->ift_name[0] = '(';
- if (kread((u_long)ifnet.if_name, ip->ift_name + 1, 15))
+ if (kread((u_long)ifnet.if_name, tname, 16))
break;
- if (interface && strcmp(ip->ift_name + 1, interface) == 0 &&
- unit == ifnet.if_unit)
+ tname[15] = '\0';
+ snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
+ if (interface && strcmp(name, interface) == 0) {
interesting = ip;
- ip->ift_name[15] = '\0';
- cp = index(ip->ift_name, '\0');
- sprintf(cp, "%d)", ifnet.if_unit);
+ interesting_off = off;
+ }
+ snprintf(ip->ift_name, 16, "(%s)", name);;
ip++;
if (ip >= iftot + MAXIF - 2)
break;
- off = (u_long) ifnet.if_next;
+ off = (u_long) ifnet.if_link.tqe_next;
}
lastif = ip;
(void)signal(SIGALRM, catchalarm);
signalled = NO;
(void)alarm(interval);
-banner:
- printf(" input %-6.6s output ", interesting->ift_name);
- if (lastif - iftot > 0) {
- if (dflag)
- printf(" ");
- printf(" input (Total) output");
- }
for (ip = iftot; ip < iftot + MAXIF; ip++) {
ip->ift_ip = 0;
ip->ift_ie = 0;
+ ip->ift_ib = 0;
ip->ift_op = 0;
ip->ift_oe = 0;
+ ip->ift_ob = 0;
ip->ift_co = 0;
ip->ift_dr = 0;
}
+ first = 1;
+banner:
+ printf("%17s %14s %16s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
putchar('\n');
- printf("%8.8s %5.5s %8.8s %5.5s %5.5s ",
- "packets", "errs", "packets", "errs", "colls");
- if (dflag)
- printf("%5.5s ", "drops");
- if (lastif - iftot > 0)
- printf(" %8.8s %5.5s %8.8s %5.5s %5.5s",
- "packets", "errs", "packets", "errs", "colls");
+ printf("%10s %5s %10s %10s %5s %10s %5s",
+ "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
if (dflag)
printf(" %5.5s", "drops");
putchar('\n');
fflush(stdout);
line = 0;
loop:
- sum->ift_ip = 0;
- sum->ift_ie = 0;
- sum->ift_op = 0;
- sum->ift_oe = 0;
- sum->ift_co = 0;
- sum->ift_dr = 0;
- for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
- if (kread(off, (char *)&ifnet, sizeof ifnet)) {
- off = 0;
- continue;
- }
- if (ip == interesting) {
- printf("%8d %5d %8d %5d %5d",
+ if (interesting != NULL) {
+ ip = interesting;
+ if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
+ printf("???\n");
+ exit(1);
+ };
+ if (!first) {
+ printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
ifnet.if_ipackets - ip->ift_ip,
ifnet.if_ierrors - ip->ift_ie,
+ ifnet.if_ibytes - ip->ift_ib,
ifnet.if_opackets - ip->ift_op,
ifnet.if_oerrors - ip->ift_oe,
+ ifnet.if_obytes - ip->ift_ob,
ifnet.if_collisions - ip->ift_co);
if (dflag)
- printf(" %5d",
- ifnet.if_snd.ifq_drops - ip->ift_dr);
+ printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
}
ip->ift_ip = ifnet.if_ipackets;
ip->ift_ie = ifnet.if_ierrors;
+ ip->ift_ib = ifnet.if_ibytes;
ip->ift_op = ifnet.if_opackets;
ip->ift_oe = ifnet.if_oerrors;
+ ip->ift_ob = ifnet.if_obytes;
ip->ift_co = ifnet.if_collisions;
ip->ift_dr = ifnet.if_snd.ifq_drops;
- sum->ift_ip += ip->ift_ip;
- sum->ift_ie += ip->ift_ie;
- sum->ift_op += ip->ift_op;
- sum->ift_oe += ip->ift_oe;
- sum->ift_co += ip->ift_co;
- sum->ift_dr += ip->ift_dr;
- off = (u_long) ifnet.if_next;
- }
- if (lastif - iftot > 0) {
- printf(" %8d %5d %8d %5d %5d",
- sum->ift_ip - total->ift_ip,
- sum->ift_ie - total->ift_ie,
- sum->ift_op - total->ift_op,
- sum->ift_oe - total->ift_oe,
- sum->ift_co - total->ift_co);
- if (dflag)
- printf(" %5d", sum->ift_dr - total->ift_dr);
+ } else {
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_ib = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_ob = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
+ if (kread(off, (char *)&ifnet, sizeof ifnet)) {
+ off = 0;
+ continue;
+ }
+ sum->ift_ip += ifnet.if_ipackets;
+ sum->ift_ie += ifnet.if_ierrors;
+ sum->ift_ib += ifnet.if_ibytes;
+ sum->ift_op += ifnet.if_opackets;
+ sum->ift_oe += ifnet.if_oerrors;
+ sum->ift_ob += ifnet.if_obytes;
+ sum->ift_co += ifnet.if_collisions;
+ sum->ift_dr += ifnet.if_snd.ifq_drops;
+ off = (u_long) ifnet.if_link.tqe_next;
+ }
+ if (!first) {
+ printf("%10u %5u %10u %10u %5u %10u %5u",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_ib - total->ift_ib,
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_ob - total->ift_ob,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5u", sum->ift_dr - total->ift_dr);
+ }
+ *total = *sum;
}
- *total = *sum;
- putchar('\n');
+ if (!first)
+ putchar('\n');
fflush(stdout);
- line++;
oldmask = sigblock(sigmask(SIGALRM));
if (! signalled) {
sigpause(0);
@@ -357,9 +480,12 @@ loop:
sigsetmask(oldmask);
signalled = NO;
(void)alarm(interval);
+ line++;
+ first = 0;
if (line == 21)
goto banner;
- goto loop;
+ else
+ goto loop;
/*NOTREACHED*/
}
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index a1a89eb..cc9290e 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -32,13 +32,17 @@
*/
#ifndef lint
+/*
static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
+*/
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <net/route.h>
@@ -73,7 +77,7 @@ struct tcpcb tcpcb;
struct socket sockb;
char *inetname __P((struct in_addr *));
-void inetprint __P((struct in_addr *, int, char *));
+void inetprint __P((struct in_addr *, int, char *, int));
/*
* Print a summary of connections related to an Internet
@@ -86,23 +90,20 @@ protopr(off, name)
u_long off;
char *name;
{
- struct inpcb cb;
+ struct inpcbhead head;
register struct inpcb *prev, *next;
int istcp;
static int first = 1;
if (off == 0)
return;
+
istcp = strcmp(name, "tcp") == 0;
- kread(off, (char *)&cb, sizeof (struct inpcb));
- inpcb = cb;
+ kread(off, (char *)&head, sizeof (struct inpcbhead));
prev = (struct inpcb *)off;
- if (inpcb.inp_next == (struct inpcb *)off)
- return;
- while (inpcb.inp_next != (struct inpcb *)off) {
- next = inpcb.inp_next;
- kread((u_long)next, (char *)&inpcb, sizeof (inpcb));
- if (inpcb.inp_prev != prev) {
+
+ for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) {
+ if (kread((u_long)next, (char *)&inpcb, sizeof (inpcb))) {
printf("???\n");
break;
}
@@ -111,10 +112,16 @@ protopr(off, name)
prev = next;
continue;
}
- kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
+ if (kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb))) {
+ printf("???\n");
+ break;
+ };
if (istcp) {
- kread((u_long)inpcb.inp_ppcb,
- (char *)&tcpcb, sizeof (tcpcb));
+ if (kread((u_long)inpcb.inp_ppcb,
+ (char *)&tcpcb, sizeof (tcpcb))) {
+ printf("???\n");
+ break;
+ };
}
if (first) {
printf("Active Internet connections");
@@ -132,18 +139,38 @@ protopr(off, name)
}
if (Aflag)
if (istcp)
- printf("%8x ", inpcb.inp_ppcb);
+ printf("%8x ", (int)inpcb.inp_ppcb);
else
- printf("%8x ", next);
- printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
+ printf("%8x ", (int)next);
+ printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
sockb.so_snd.sb_cc);
- inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name);
- inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name);
+ if (nflag) {
+ inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
+ name, 1);
+ inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
+ name, 1);
+ } else if (inpcb.inp_flags & INP_ANONPORT) {
+ inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
+ name, 1);
+ inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
+ name, 0);
+ } else {
+ inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
+ name, 0);
+ inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
+ name, inpcb.inp_lport != inpcb.inp_fport);
+ }
if (istcp) {
if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
printf(" %d", tcpcb.t_state);
- else
+ else {
printf(" %s", tcpstates[tcpcb.t_state]);
+#if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
+ /* Show T/TCP `hidden state' */
+ if (tcpcb.t_flags & (TF_NEEDSYN|TF_NEEDFIN))
+ putchar('*');
+#endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
+ }
}
putchar('\n');
prev = next;
@@ -172,57 +199,63 @@ tcp_stats(off, name)
#define p3(f, m) if (tcpstat.f || sflag <= 1) \
printf(m, tcpstat.f, plurales(tcpstat.f))
- p(tcps_sndtotal, "\t%d packet%s sent\n");
+ p(tcps_sndtotal, "\t%lu packet%s sent\n");
p2(tcps_sndpack,tcps_sndbyte,
- "\t\t%d data packet%s (%d byte%s)\n");
+ "\t\t%lu data packet%s (%lu byte%s)\n");
p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
- "\t\t%d data packet%s (%d byte%s) retransmitted\n");
+ "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
+ p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
p2(tcps_sndacks, tcps_delack,
- "\t\t%d ack-only packet%s (%d delayed)\n");
- p(tcps_sndurg, "\t\t%d URG only packet%s\n");
- p(tcps_sndprobe, "\t\t%d window probe packet%s\n");
- p(tcps_sndwinup, "\t\t%d window update packet%s\n");
- p(tcps_sndctrl, "\t\t%d control packet%s\n");
- p(tcps_rcvtotal, "\t%d packet%s received\n");
- p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n");
- p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n");
- p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n");
+ "\t\t%lu ack-only packet%s (%lu delayed)\n");
+ p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%lu control packet%s\n");
+ p(tcps_rcvtotal, "\t%lu packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
p2(tcps_rcvpack, tcps_rcvbyte,
- "\t\t%d packet%s (%d byte%s) received in-sequence\n");
+ "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
p2(tcps_rcvduppack, tcps_rcvdupbyte,
- "\t\t%d completely duplicate packet%s (%d byte%s)\n");
- p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n");
+ "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
- "\t\t%d packet%s with some dup. data (%d byte%s duped)\n");
+ "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
p2(tcps_rcvoopack, tcps_rcvoobyte,
- "\t\t%d out-of-order packet%s (%d byte%s)\n");
+ "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
- "\t\t%d packet%s (%d byte%s) of data after window\n");
- p(tcps_rcvwinprobe, "\t\t%d window probe%s\n");
- p(tcps_rcvwinupd, "\t\t%d window update packet%s\n");
- p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n");
- p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n");
- p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n");
- p(tcps_rcvshort, "\t\t%d discarded because packet too short\n");
- p(tcps_connattempt, "\t%d connection request%s\n");
- p(tcps_accepts, "\t%d connection accept%s\n");
- p(tcps_badsyn, "\t%d bad connection attempt%s\n");
- p(tcps_connects, "\t%d connection%s established (including accepts)\n");
+ "\t\t%lu packet%s (%lu byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
+ p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
+ p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
+ p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
+ p(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
+ p(tcps_connattempt, "\t%lu connection request%s\n");
+ p(tcps_accepts, "\t%lu connection accept%s\n");
+ p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
+ p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
+ p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
p2(tcps_closed, tcps_drops,
- "\t%d connection%s closed (including %d drop%s)\n");
- p(tcps_conndrops, "\t%d embryonic connection%s dropped\n");
+ "\t%lu connection%s closed (including %lu drop%s)\n");
+ p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
+ p(tcps_cachedrttvar,
+ "\t\t%lu connection%s updated cached RTT variance on close\n");
+ p(tcps_cachedssthresh,
+ "\t\t%lu connection%s updated cached ssthresh on close\n");
+ p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
p2(tcps_rttupdated, tcps_segstimed,
- "\t%d segment%s updated rtt (of %d attempt%s)\n");
- p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n");
- p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n");
- p(tcps_persisttimeo, "\t%d persist timeout%s\n");
- p(tcps_persistdrop, "\t%d connection%s timed out in persist\n");
- p(tcps_keeptimeo, "\t%d keepalive timeout%s\n");
- p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n");
- p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n");
- p(tcps_predack, "\t%d correct ACK header prediction%s\n");
- p(tcps_preddat, "\t%d correct data packet header prediction%s\n");
- p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n");
+ "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
+ p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
+ p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
+ p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
+ p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
#undef p
#undef p2
#undef p3
@@ -245,13 +278,14 @@ udp_stats(off, name)
printf("%s:\n", name);
#define p(f, m) if (udpstat.f || sflag <= 1) \
printf(m, udpstat.f, plural(udpstat.f))
- p(udps_ipackets, "\t%u datagram%s received\n");
- p(udps_hdrops, "\t%u with incomplete header\n");
- p(udps_badlen, "\t%u with bad data length field\n");
- p(udps_badsum, "\t%u with bad checksum\n");
- p(udps_noport, "\t%u dropped due to no socket\n");
- p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
- p(udps_fullsock, "\t%u dropped due to full socket buffers\n");
+ p(udps_ipackets, "\t%lu datagram%s received\n");
+ p(udps_hdrops, "\t%lu with incomplete header\n");
+ p(udps_badlen, "\t%lu with bad data length field\n");
+ p(udps_badsum, "\t%lu with bad checksum\n");
+ p(udps_noport, "\t%lu dropped due to no socket\n");
+ p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
+ p(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
+ p(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
delivered = udpstat.udps_ipackets -
udpstat.udps_hdrops -
udpstat.udps_badlen -
@@ -260,8 +294,8 @@ udp_stats(off, name)
udpstat.udps_noportbcast -
udpstat.udps_fullsock;
if (delivered || sflag <= 1)
- printf("\t%u delivered\n", delivered);
- p(udps_opackets, "\t%u datagram%s output\n");
+ printf("\t%lu delivered\n", delivered);
+ p(udps_opackets, "\t%lu datagram%s output\n");
#undef p
}
@@ -283,30 +317,33 @@ ip_stats(off, name)
#define p(f, m) if (ipstat.f || sflag <= 1) \
printf(m, ipstat.f, plural(ipstat.f))
- p(ips_total, "\t%u total packet%s received\n");
- p(ips_badsum, "\t%u bad header checksum%s\n");
- p(ips_toosmall, "\t%u with size smaller than minimum\n");
- p(ips_tooshort, "\t%u with data size < data length\n");
- p(ips_badhlen, "\t%u with header length < data size\n");
- p(ips_badlen, "\t%u with data length < header length\n");
- p(ips_badoptions, "\t%u with bad options\n");
- p(ips_badvers, "\t%u with incorrect version number\n");
- p(ips_fragments, "\t%u fragment%s received\n");
- p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
- p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
- p(ips_reassembled, "\t%u packet%s reassembled ok\n");
- p(ips_delivered, "\t%u packet%s for this host\n");
- p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
- p(ips_forward, "\t%u packet%s forwarded\n");
- p(ips_cantforward, "\t%u packet%s not forwardable\n");
- p(ips_redirectsent, "\t%u redirect%s sent\n");
- p(ips_localout, "\t%u packet%s sent from this host\n");
- p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
- p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n");
- p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
- p(ips_fragmented, "\t%u output datagram%s fragmented\n");
- p(ips_ofragments, "\t%u fragment%s created\n");
- p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
+ p(ips_total, "\t%lu total packet%s received\n");
+ p(ips_badsum, "\t%lu bad header checksum%s\n");
+ p(ips_toosmall, "\t%lu with size smaller than minimum\n");
+ p(ips_tooshort, "\t%lu with data size < data length\n");
+ p(ips_badhlen, "\t%lu with header length < data size\n");
+ p(ips_badlen, "\t%lu with data length < header length\n");
+ p(ips_badoptions, "\t%lu with bad options\n");
+ p(ips_badvers, "\t%lu with incorrect version number\n");
+ p(ips_fragments, "\t%lu fragment%s received\n");
+ p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
+ p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
+ p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
+ p(ips_delivered, "\t%lu packet%s for this host\n");
+ p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t%lu packet%s forwarded\n");
+ p(ips_cantforward, "\t%lu packet%s not forwardable\n");
+ p(ips_notmember,
+ "\t%lu packet%s received for unknown multicast group\n");
+ p(ips_redirectsent, "\t%lu redirect%s sent\n");
+ p(ips_localout, "\t%lu packet%s sent from this host\n");
+ p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
+ p(ips_odropped,
+ "\t%lu output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
+ p(ips_ofragments, "\t%lu fragment%s created\n");
+ p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
#undef p
}
@@ -320,8 +357,8 @@ static char *icmpnames[] = {
"#6",
"#7",
"echo",
- "#9",
- "#10",
+ "router advertisement",
+ "router solicitation",
"time exceeded",
"parameter problem",
"time stamp",
@@ -351,32 +388,32 @@ icmp_stats(off, name)
#define p(f, m) if (icmpstat.f || sflag <= 1) \
printf(m, icmpstat.f, plural(icmpstat.f))
- p(icps_error, "\t%u call%s to icmp_error\n");
+ p(icps_error, "\t%lu call%s to icmp_error\n");
p(icps_oldicmp,
- "\t%u error%s not generated 'cuz old message was icmp\n");
+ "\t%lu error%s not generated 'cuz old message was icmp\n");
for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
if (icmpstat.icps_outhist[i] != 0) {
if (first) {
printf("\tOutput histogram:\n");
first = 0;
}
- printf("\t\t%s: %u\n", icmpnames[i],
+ printf("\t\t%s: %lu\n", icmpnames[i],
icmpstat.icps_outhist[i]);
}
- p(icps_badcode, "\t%u message%s with bad code fields\n");
- p(icps_tooshort, "\t%u message%s < minimum length\n");
- p(icps_checksum, "\t%u bad checksum%s\n");
- p(icps_badlen, "\t%u message%s with bad length\n");
+ p(icps_badcode, "\t%lu message%s with bad code fields\n");
+ p(icps_tooshort, "\t%lu message%s < minimum length\n");
+ p(icps_checksum, "\t%lu bad checksum%s\n");
+ p(icps_badlen, "\t%lu message%s with bad length\n");
for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
if (icmpstat.icps_inhist[i] != 0) {
if (first) {
printf("\tInput histogram:\n");
first = 0;
}
- printf("\t\t%s: %u\n", icmpnames[i],
+ printf("\t\t%s: %lu\n", icmpnames[i],
icmpstat.icps_inhist[i]);
}
- p(icps_reflect, "\t%u message response%s generated\n");
+ p(icps_reflect, "\t%lu message response%s generated\n");
#undef p
}
@@ -414,24 +451,24 @@ igmp_stats(off, name)
/*
* Pretty print an Internet address (net address + port).
- * If the nflag was specified, use numbers instead of names.
*/
void
-inetprint(in, port, proto)
+inetprint(in, port, proto,numeric)
register struct in_addr *in;
int port;
char *proto;
+ int numeric;
{
struct servent *sp = 0;
char line[80], *cp;
int width;
- sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in));
+ sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
cp = index(line, '\0');
- if (!nflag && port)
+ if (!numeric && port)
sp = getservbyport((int)port, proto);
if (sp || port == 0)
- sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+ sprintf(cp, "%.15s", sp ? sp->s_name : "*");
else
sprintf(cp, "%d", ntohs((u_short)port));
width = Aflag ? 18 : 22;
@@ -451,17 +488,7 @@ inetname(inp)
static char line[50];
struct hostent *hp;
struct netent *np;
- static char domain[MAXHOSTNAMELEN + 1];
- static int first = 1;
- if (first && !nflag) {
- first = 0;
- if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
- (cp = index(domain, '.')))
- (void) strcpy(domain, cp + 1);
- else
- domain[0] = 0;
- }
cp = 0;
if (!nflag && inp->s_addr != INADDR_ANY) {
int net = inet_netof(*inp);
@@ -475,10 +502,8 @@ inetname(inp)
if (cp == 0) {
hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
if (hp) {
- if ((cp = index(hp->h_name, '.')) &&
- !strcmp(cp + 1, domain))
- *cp = 0;
cp = hp->h_name;
+ trimdomain(cp);
}
}
}
@@ -489,7 +514,7 @@ inetname(inp)
else {
inp->s_addr = ntohl(inp->s_addr);
#define C(x) ((x) & 0xff)
- sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
+ sprintf(line, "%lu.%lu.%lu.%lu", C(inp->s_addr >> 24),
C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
}
return (line);
diff --git a/usr.bin/netstat/ipx.c b/usr.bin/netstat/ipx.c
new file mode 100644
index 0000000..0e8d34f
--- /dev/null
+++ b/usr.bin/netstat/ipx.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)ns.c 8.1 (Berkeley) 6/6/93";
+*/
+static const char rcsid[] =
+ "$Id: ipx.c,v 1.7 1997/02/22 19:56:22 peter Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+
+#include <netinet/tcp_fsm.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_var.h>
+#ifdef IPXERRORMSGS
+#include <netipx/ipx_error.h>
+#endif
+#include <netipx/spx.h>
+#include <netipx/spx_timer.h>
+#include <netipx/spx_var.h>
+#define SANAMES
+#include <netipx/spx_debug.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "netstat.h"
+
+struct ipxpcb ipxpcb;
+struct spxpcb spxpcb;
+struct socket sockb;
+
+static char *ipx_prpr __P((struct ipx_addr *));
+static void ipx_erputil __P((int, int));
+
+static int first = 1;
+
+/*
+ * Print a summary of connections related to a Network Systems
+ * protocol. For SPX, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+void
+ipxprotopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipxpcb cb;
+ register struct ipxpcb *prev, *next;
+ int isspx;
+
+ if (off == 0)
+ return;
+ isspx = strcmp(name, "spx") == 0;
+ kread(off, (char *)&cb, sizeof (struct ipxpcb));
+ ipxpcb = cb;
+ prev = (struct ipxpcb *)off;
+ if (ipxpcb.ipxp_next == (struct ipxpcb *)off)
+ return;
+ for (;ipxpcb.ipxp_next != (struct ipxpcb *)off; prev = next) {
+ u_long ppcb;
+
+ next = ipxpcb.ipxp_next;
+ kread((u_long)next, (char *)&ipxpcb, sizeof (ipxpcb));
+ if (ipxpcb.ipxp_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ if (!aflag && ipx_nullhost(ipxpcb.ipxp_faddr) ) {
+ continue;
+ }
+ kread((u_long)ipxpcb.ipxp_socket,
+ (char *)&sockb, sizeof (sockb));
+ ppcb = (u_long) ipxpcb.ipxp_pcb;
+ if (ppcb) {
+ if (isspx) {
+ kread(ppcb, (char *)&spxpcb, sizeof (spxpcb));
+ } else continue;
+ } else
+ if (isspx) continue;
+ if (first) {
+ printf("Active IPX connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8lx ", ppcb);
+ printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_laddr));
+ printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_faddr));
+ if (isspx) {
+ extern char *tcpstates[];
+ if (spxpcb.s_state >= TCP_NSTATES)
+ printf(" %d", spxpcb.s_state);
+ else
+ printf(" %s", tcpstates[spxpcb.s_state]);
+ }
+ putchar('\n');
+ prev = next;
+ }
+}
+
+#define ANY(x,y,z) (printf("\t%u %s%s%s\n",x,y,plural(x),z))
+
+/*
+ * Dump SPX statistics structure.
+ */
+void
+spx_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct spx_istat spx_istat;
+#define spxstat spx_istat.newstats
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&spx_istat, sizeof (spx_istat));
+ printf("%s:\n", name);
+ ANY(spx_istat.nonucn, "connection", " dropped due to no new sockets ");
+ ANY(spx_istat.gonawy, "connection", " terminated due to our end dying");
+ ANY(spx_istat.nonucn, "connection",
+ " dropped due to inability to connect");
+ ANY(spx_istat.noconn, "connection",
+ " dropped due to inability to connect");
+ ANY(spx_istat.notme, "connection",
+ " incompleted due to mismatched id's");
+ ANY(spx_istat.wrncon, "connection", " dropped due to mismatched id's");
+ ANY(spx_istat.bdreas, "packet", " dropped out of sequence");
+ ANY(spx_istat.lstdup, "packet", " duplicating the highest packet");
+ ANY(spx_istat.notyet, "packet", " refused as exceeding allocation");
+ ANY(spxstat.spxs_connattempt, "connection", " initiated");
+ ANY(spxstat.spxs_accepts, "connection", " accepted");
+ ANY(spxstat.spxs_connects, "connection", " established");
+ ANY(spxstat.spxs_drops, "connection", " dropped");
+ ANY(spxstat.spxs_conndrops, "embryonic connection", " dropped");
+ ANY(spxstat.spxs_closed, "connection", " closed (includes drops)");
+ ANY(spxstat.spxs_segstimed, "packet", " where we tried to get rtt");
+ ANY(spxstat.spxs_rttupdated, "time", " we got rtt");
+ ANY(spxstat.spxs_delack, "delayed ack", " sent");
+ ANY(spxstat.spxs_timeoutdrop, "connection", " dropped in rxmt timeout");
+ ANY(spxstat.spxs_rexmttimeo, "retransmit timeout", "");
+ ANY(spxstat.spxs_persisttimeo, "persist timeout", "");
+ ANY(spxstat.spxs_keeptimeo, "keepalive timeout", "");
+ ANY(spxstat.spxs_keepprobe, "keepalive probe", " sent");
+ ANY(spxstat.spxs_keepdrops, "connection", " dropped in keepalive");
+ ANY(spxstat.spxs_sndtotal, "total packet", " sent");
+ ANY(spxstat.spxs_sndpack, "data packet", " sent");
+ ANY(spxstat.spxs_sndbyte, "data byte", " sent");
+ ANY(spxstat.spxs_sndrexmitpack, "data packet", " retransmitted");
+ ANY(spxstat.spxs_sndrexmitbyte, "data byte", " retransmitted");
+ ANY(spxstat.spxs_sndacks, "ack-only packet", " sent");
+ ANY(spxstat.spxs_sndprobe, "window probe", " sent");
+ ANY(spxstat.spxs_sndurg, "packet", " sent with URG only");
+ ANY(spxstat.spxs_sndwinup, "window update-only packet", " sent");
+ ANY(spxstat.spxs_sndctrl, "control (SYN|FIN|RST) packet", " sent");
+ ANY(spxstat.spxs_sndvoid, "request", " to send a non-existant packet");
+ ANY(spxstat.spxs_rcvtotal, "total packet", " received");
+ ANY(spxstat.spxs_rcvpack, "packet", " received in sequence");
+ ANY(spxstat.spxs_rcvbyte, "byte", " received in sequence");
+ ANY(spxstat.spxs_rcvbadsum, "packet", " received with ccksum errs");
+ ANY(spxstat.spxs_rcvbadoff, "packet", " received with bad offset");
+ ANY(spxstat.spxs_rcvshort, "packet", " received too short");
+ ANY(spxstat.spxs_rcvduppack, "duplicate-only packet", " received");
+ ANY(spxstat.spxs_rcvdupbyte, "duplicate-only byte", " received");
+ ANY(spxstat.spxs_rcvpartduppack, "packet", " with some duplicate data");
+ ANY(spxstat.spxs_rcvpartdupbyte, "dup. byte", " in part-dup. packet");
+ ANY(spxstat.spxs_rcvoopack, "out-of-order packet", " received");
+ ANY(spxstat.spxs_rcvoobyte, "out-of-order byte", " received");
+ ANY(spxstat.spxs_rcvpackafterwin, "packet", " with data after window");
+ ANY(spxstat.spxs_rcvbyteafterwin, "byte", " rcvd after window");
+ ANY(spxstat.spxs_rcvafterclose, "packet", " rcvd after 'close'");
+ ANY(spxstat.spxs_rcvwinprobe, "rcvd window probe packet", "");
+ ANY(spxstat.spxs_rcvdupack, "rcvd duplicate ack", "");
+ ANY(spxstat.spxs_rcvacktoomuch, "rcvd ack", " for unsent data");
+ ANY(spxstat.spxs_rcvackpack, "rcvd ack packet", "");
+ ANY(spxstat.spxs_rcvackbyte, "byte", " acked by rcvd acks");
+ ANY(spxstat.spxs_rcvwinupd, "rcvd window update packet", "");
+}
+
+#undef ANY
+#define ANY(x,y,z) (printf("\t%u %s%s%s\n",x,y,plural(x),z))
+
+/*
+ * Dump IPX statistics structure.
+ */
+void
+ipx_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipxstat ipxstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ipxstat, sizeof (ipxstat));
+ printf("%s:\n", name);
+ ANY(ipxstat.ipxs_total, "total packet", " received");
+ ANY(ipxstat.ipxs_badsum, "packet", " with bad checksums");
+ ANY(ipxstat.ipxs_tooshort, "packet", " smaller than advertised");
+ ANY(ipxstat.ipxs_toosmall, "packet", " smaller than a header");
+ ANY(ipxstat.ipxs_forward, "packet", " forwarded");
+ ANY(ipxstat.ipxs_cantforward, "packet", " not forwardable");
+ ANY(ipxstat.ipxs_delivered, "packet", " for this host");
+ ANY(ipxstat.ipxs_localout, "packet", " sent from this host");
+ ANY(ipxstat.ipxs_odropped, "packet", " dropped due to no bufs, etc.");
+ ANY(ipxstat.ipxs_noroute, "packet", " discarded due to no route");
+ ANY(ipxstat.ipxs_mtutoosmall, "packet", " too big");
+}
+
+static struct {
+ u_short code;
+ char *name;
+ char *where;
+} ipx_errnames[] = {
+ {0, "Unspecified Error", " at Destination"},
+ {1, "Bad Checksum", " at Destination"},
+ {2, "No Listener", " at Socket"},
+ {3, "Packet", " Refused due to lack of space at Destination"},
+ {01000, "Unspecified Error", " while gatewayed"},
+ {01001, "Bad Checksum", " while gatewayed"},
+ {01002, "Packet", " forwarded too many times"},
+ {01003, "Packet", " too large to be forwarded"},
+ {-1, 0, 0},
+};
+
+#ifdef IPXERRORMSGS
+/*
+ * Dump IPX Error statistics structure.
+ */
+/*ARGSUSED*/
+void
+ipxerr_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipx_errstat ipx_errstat;
+ register int j;
+ register int histoprint = 1;
+ int z;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ipx_errstat, sizeof (ipx_errstat));
+ printf("IPX error statistics:\n");
+ ANY(ipx_errstat.ipx_es_error, "call", " to ipx_error");
+ ANY(ipx_errstat.ipx_es_oldshort, "error",
+ " ignored due to insufficient addressing");
+ ANY(ipx_errstat.ipx_es_oldipx_err, "error request",
+ " in response to error packets");
+ ANY(ipx_errstat.ipx_es_tooshort, "error packet",
+ " received incomplete");
+ ANY(ipx_errstat.ipx_es_badcode, "error packet",
+ " received of unknown type");
+ for(j = 0; j < IPX_ERR_MAX; j ++) {
+ z = ipx_errstat.ipx_es_outhist[j];
+ if (z && histoprint) {
+ printf("Output Error Histogram:\n");
+ histoprint = 0;
+ }
+ ipx_erputil(z, ipx_errstat.ipx_es_codes[j]);
+ }
+ histoprint = 1;
+ for(j = 0; j < IPX_ERR_MAX; j ++) {
+ z = ipx_errstat.ipx_es_inhist[j];
+ if (z && histoprint) {
+ printf("Input Error Histogram:\n");
+ histoprint = 0;
+ }
+ ipx_erputil(z, ipx_errstat.ipx_es_codes[j]);
+ }
+}
+
+static void
+ipx_erputil(z, c)
+ int z, c;
+{
+ int j;
+ char codebuf[30];
+ char *name, *where;
+
+ for(j = 0;; j ++) {
+ if ((name = ipx_errnames[j].name) == 0)
+ break;
+ if (ipx_errnames[j].code == c)
+ break;
+ }
+ if (name == 0) {
+ if (c > 01000)
+ where = "in transit";
+ else
+ where = "at destination";
+ sprintf(codebuf, "Unknown IPX error code 0%o", c);
+ name = codebuf;
+ } else
+ where = ipx_errnames[j].where;
+ ANY(z, name, where);
+}
+#endif /* IPXERRORMSGS */
+
+static struct sockaddr_ipx ssipx = {AF_IPX};
+
+static
+char *ipx_prpr(x)
+ struct ipx_addr *x;
+{
+ struct sockaddr_ipx *sipx = &ssipx;
+
+ sipx->sipx_addr = *x;
+ return(ipx_print((struct sockaddr *)sipx));
+}
diff --git a/usr.bin/netstat/iso.c b/usr.bin/netstat/iso.c
index 1eecf15..ade4144 100644
--- a/usr.bin/netstat/iso.c
+++ b/usr.bin/netstat/iso.c
@@ -36,8 +36,8 @@ static char sccsid[] = "@(#)iso.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
- * $Header: iso.c,v 1.5 92/06/04 00:36:32 leres Exp $
- * $Source: /usr/src/usr.bin/netstat/RCS/iso.c,v $
+ * $Header: /home/ncvs/src/usr.bin/netstat/iso.c,v 1.1.1.1 1994/05/27 12:32:25 rgrimes Exp $
+ * $Source: /home/ncvs/src/usr.bin/netstat/iso.c,v $
*/
/*******************************************************************************
Copyright IBM Corporation 1987
@@ -73,6 +73,7 @@ SOFTWARE.
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/queue.h>
#include <errno.h>
#include <net/if.h>
#include <net/route.h>
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 6d30186..08e15ee 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -59,6 +59,7 @@ static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <err.h>
#include "netstat.h"
struct nlist nl[] = {
@@ -83,7 +84,7 @@ struct nlist nl[] = {
#define N_RTSTAT 9
{ "_rtstat" },
#define N_UNIXSW 10
- { "_unixsw" },
+ { "_localsw" },
#define N_IDP 11
{ "_nspcb"},
#define N_IDPSTAT 12
@@ -120,11 +121,25 @@ struct nlist nl[] = {
{ "_ip_mrtproto" },
#define N_MRTSTAT 28
{ "_mrtstat" },
-#define N_MRTTABLE 29
- { "_mrttable" },
+#define N_MFCTABLE 29
+ { "_mfctable" },
#define N_VIFTABLE 30
{ "_viftable" },
- "",
+#define N_IPX 31
+ { "_ipxpcb"},
+#define N_IPXSTAT 32
+ { "_ipxstat"},
+#define N_SPXSTAT 33
+ { "_spx_istat"},
+#define N_DDPSTAT 34
+ { "_ddpstat"},
+#define N_DDPCB 35
+ { "_ddpcb"},
+#define N_DIVPCB 36
+ { "_divcb"},
+#define N_DIVSTAT 37
+ { "_divstat"},
+ { "" },
};
struct protox {
@@ -139,6 +154,8 @@ struct protox {
tcp_stats, "tcp" },
{ N_UDB, N_UDPSTAT, 1, protopr,
udp_stats, "udp" },
+ { N_DIVPCB, N_DIVSTAT, 1, protopr,
+ NULL, "divert" }, /* no stat structure yet */
{ -1, N_IPSTAT, 1, 0,
ip_stats, "ip" },
{ -1, N_ICMPSTAT, 1, 0,
@@ -149,6 +166,23 @@ struct protox {
0, 0 }
};
+struct protox atalkprotox[] = {
+ { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
+ ddp_stats, "ddp" },
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+
+struct protox ipxprotox[] = {
+ { N_IPX, N_IPXSTAT, 1, ipxprotopr,
+ ipx_stats, "ipx" },
+ { N_IPX, N_SPXSTAT, 1, ipxprotopr,
+ spx_stats, "spx" },
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+
+#ifdef NS
struct protox nsprotox[] = {
{ N_IDP, N_IDPSTAT, 1, nsprotopr,
idp_stats, "idp" },
@@ -159,7 +193,9 @@ struct protox nsprotox[] = {
{ -1, -1, 0, 0,
0, 0 }
};
+#endif
+#ifdef ISO
struct protox isoprotox[] = {
{ ISO_TP, N_TPSTAT, 1, iso_protopr,
tp_stats, "tp" },
@@ -172,8 +208,16 @@ struct protox isoprotox[] = {
{ -1, -1, 0, 0,
0, 0 }
};
+#endif
-struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
+struct protox *protoprotox[] = { protox, ipxprotox, atalkprotox,
+#ifdef NS
+ nsprotox,
+#endif
+#ifdef ISO
+ isoprotox,
+#endif
+ NULL };
static void printproto __P((struct protox *, char *));
static void usage __P((void));
@@ -196,13 +240,13 @@ main(argc, argv)
char *nlistf = NULL, *memf = NULL;
char buf[_POSIX2_LINE_MAX];
- if (cp = rindex(argv[0], '/'))
+ if ((cp = rindex(argv[0], '/')))
prog = cp + 1;
else
prog = argv[0];
af = AF_UNSPEC;
- while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
+ while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != -1)
switch(ch) {
case 'A':
Aflag = 1;
@@ -210,23 +254,32 @@ main(argc, argv)
case 'a':
aflag = 1;
break;
+ case 'b':
+ bflag = 1;
+ break;
case 'd':
dflag = 1;
break;
case 'f':
+#ifdef NS
if (strcmp(optarg, "ns") == 0)
af = AF_NS;
+ else
+#endif
+ if (strcmp(optarg, "ipx") == 0)
+ af = AF_IPX;
else if (strcmp(optarg, "inet") == 0)
af = AF_INET;
else if (strcmp(optarg, "unix") == 0)
af = AF_UNIX;
+ else if (strcmp(optarg, "atalk") == 0)
+ af = AF_APPLETALK;
+#ifdef ISO
else if (strcmp(optarg, "iso") == 0)
af = AF_ISO;
+#endif
else {
- (void)fprintf(stderr,
- "%s: %s: unknown address family\n",
- prog, optarg);
- exit(1);
+ errx(1, "%s: unknown address family", optarg);
}
break;
case 'g':
@@ -239,7 +292,6 @@ main(argc, argv)
for (cp = interface = optarg; isalpha(*cp); cp++)
continue;
unit = atoi(cp);
- *cp = '\0';
break;
}
case 'i':
@@ -259,10 +311,9 @@ main(argc, argv)
break;
case 'p':
if ((tp = name2protox(optarg)) == NULL) {
- (void)fprintf(stderr,
- "%s: %s: unknown or uninstrumented protocol\n",
- prog, optarg);
- exit(1);
+ errx(1,
+ "%s: unknown or uninstrumented protocol",
+ optarg);
}
pflag = 1;
break;
@@ -314,16 +365,22 @@ main(argc, argv)
if (nlistf != NULL || memf != NULL)
setgid(getgid());
- if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
- fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
- exit(1);
+ kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
+ if (kvmd == NULL) {
+ errx(1, "kvm_open: %s", buf);
+ }
+ if (kvm_nlist(kvmd, nl) < 0) {
+ if(nlistf)
+ errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd));
+ else
+ errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
}
- if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
- if (nlistf)
- fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
+
+ if (nl[0].n_type == 0) {
+ if(nlistf)
+ errx(1, "%s: no namelist", nlistf);
else
- fprintf(stderr, "%s: no namelist\n", prog);
- exit(1);
+ errx(1, "no namelist");
}
if (mflag) {
mbpr(nl[N_MBSTAT].n_value);
@@ -337,12 +394,20 @@ main(argc, argv)
printf("%s: no stats routine\n", tp->pr_name);
exit(0);
}
+#if 0
/*
* Keep file descriptors open to avoid overhead
* of open/close on each call to get* routines.
*/
sethostent(1);
setnetent(1);
+#else
+ /*
+ * This does not make sense any more with DNS being default over
+ * the files. Doing a setXXXXent(1) causes a tcp connection to be
+ * used for the queries, which is slower.
+ */
+#endif
if (iflag) {
intpr(interval, nl[N_IFNET].n_value);
exit(0);
@@ -360,7 +425,7 @@ main(argc, argv)
nl[N_MRTSTAT].n_value);
else
mroutepr(nl[N_MRTPROTO].n_value,
- nl[N_MRTTABLE].n_value,
+ nl[N_MFCTABLE].n_value,
nl[N_VIFTABLE].n_value);
exit(0);
}
@@ -368,7 +433,7 @@ main(argc, argv)
setprotoent(1);
setservent(1);
/* ugh, this is O(MN) ... why do we do this? */
- while (p = getprotoent()) {
+ while ((p = getprotoent())) {
for (tp = protox; tp->pr_name; tp++)
if (strcmp(tp->pr_name, p->p_name) == 0)
break;
@@ -378,12 +443,22 @@ main(argc, argv)
}
endprotoent();
}
+ if (af == AF_IPX || af == AF_UNSPEC)
+ for (tp = ipxprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ if (af == AF_APPLETALK || af == AF_UNSPEC)
+ for (tp = atalkprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef NS
if (af == AF_NS || af == AF_UNSPEC)
for (tp = nsprotox; tp->pr_name; tp++)
printproto(tp, tp->pr_name);
+#endif
+#ifdef ISO
if (af == AF_ISO || af == AF_UNSPEC)
for (tp = isoprotox; tp->pr_name; tp++)
printproto(tp, tp->pr_name);
+#endif
if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
unixpr(nl[N_UNIXSW].n_value);
exit(0);
@@ -424,9 +499,7 @@ kread(addr, buf, size)
{
if (kvm_read(kvmd, addr, buf, size) != size) {
- /* XXX this duplicates kvm_read's error printout */
- (void)fprintf(stderr, "%s: kvm_read %s\n", prog,
- kvm_geterr(kvmd));
+ warnx("%s", kvm_geterr(kvmd));
return (-1);
}
return (0);
@@ -477,11 +550,11 @@ name2protox(name)
* Try to find the name in the list of "well-known" names. If that
* fails, check if name is an alias for an Internet protocol.
*/
- if (tp = knownname(name))
+ if ((tp = knownname(name)))
return (tp);
setprotoent(1); /* make protocol lookup cheaper */
- while (p = getprotoent()) {
+ while ((p = getprotoent())) {
/* assert: name not same as p->name */
for (alias = p->p_aliases; *alias; alias++)
if (strcmp(name, *alias) == 0) {
@@ -499,10 +572,40 @@ usage()
(void)fprintf(stderr,
"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
(void)fprintf(stderr,
-" %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
+" %s [-bdghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
(void)fprintf(stderr,
-" %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
+" %s [-bdn] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
(void)fprintf(stderr,
" %s [-M core] [-N system] [-p protocol]\n", prog);
exit(1);
}
+
+void
+trimdomain(cp)
+ char *cp;
+{
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ char *s;
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (s = strchr(domain, '.')))
+ (void) strcpy(domain, s + 1);
+ else
+ domain[0] = 0;
+ }
+
+ if (domain[0]) {
+ while ((cp = strchr(cp, '.'))) {
+ if (!strcasecmp(cp + 1, domain)) {
+ *cp = 0; /* hit it */
+ break;
+ } else {
+ cp++;
+ }
+ }
+ }
+}
+
diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c
index dd60a0e..cfefa5e 100644
--- a/usr.bin/netstat/mbuf.c
+++ b/usr.bin/netstat/mbuf.c
@@ -36,9 +36,10 @@ static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
+#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
-#include <sys/mbuf.h>
+#include <sys/sysctl.h>
#include <stdio.h>
#include "netstat.h"
@@ -82,22 +83,32 @@ mbpr(mbaddr)
register int totmem, totfree, totmbufs;
register int i;
register struct mbtypes *mp;
+ int name[3];
+ size_t mbstatlen;
- if (nmbtypes != 256) {
- fprintf(stderr,
- "%s: unexpected change to mbstat; check source\n", prog);
+ name[0] = CTL_KERN;
+ name[1] = KERN_IPC;
+ name[2] = KIPC_MBSTAT;
+ mbstatlen = sizeof mbstat;
+
+ if (sysctl(name, 3, &mbstat, &mbstatlen, 0, 0) < 0) {
+ warn("sysctl: retrieving mbstat");
return;
}
- if (mbaddr == 0) {
- fprintf(stderr, "%s: mbstat: symbol not in namelist\n", prog);
+#undef MSIZE
+#define MSIZE (mbstat.m_msize)
+#undef MCLBYTES
+#define MCLBYTES (mbstat.m_mclbytes)
+
+ if (nmbtypes != 256) {
+ warnx("unexpected change to mbstat; check source");
return;
}
- if (kread(mbaddr, (char *)&mbstat, sizeof (mbstat)))
- return;
+
totmbufs = 0;
for (mp = mbtypes; mp->mt_name; mp++)
totmbufs += mbstat.m_mtypes[mp->mt_type];
- printf("%u mbufs in use:\n", totmbufs);
+ printf("%u/%u mbufs in use:\n", totmbufs, mbstat.m_mbufs);
for (mp = mbtypes; mp->mt_name; mp++)
if (mbstat.m_mtypes[mp->mt_type]) {
seen[mp->mt_type] = YES;
@@ -110,13 +121,14 @@ mbpr(mbaddr)
printf("\t%u mbufs allocated to <mbuf type %d>\n",
mbstat.m_mtypes[i], i);
}
- printf("%u/%u mapped pages in use\n",
+ printf("%lu/%lu mbuf clusters in use\n",
mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters);
- totmem = totmbufs * MSIZE + mbstat.m_clusters * MCLBYTES;
- totfree = mbstat.m_clfree * MCLBYTES;
+ totmem = mbstat.m_mbufs * MSIZE + mbstat.m_clusters * MCLBYTES;
+ totfree = mbstat.m_clfree * MCLBYTES +
+ MSIZE * (mbstat.m_mbufs - totmbufs);
printf("%u Kbytes allocated to network (%d%% in use)\n",
totmem / 1024, (totmem - totfree) * 100 / totmem);
- printf("%u requests for memory denied\n", mbstat.m_drops);
- printf("%u requests for memory delayed\n", mbstat.m_wait);
- printf("%u calls to protocol drain routines\n", mbstat.m_drain);
+ printf("%lu requests for memory denied\n", mbstat.m_drops);
+ printf("%lu requests for memory delayed\n", mbstat.m_wait);
+ printf("%lu calls to protocol drain routines\n", mbstat.m_drain);
}
diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c
index 53f08a9..e725d5d 100644
--- a/usr.bin/netstat/mroute.c
+++ b/usr.bin/netstat/mroute.c
@@ -44,35 +44,38 @@
*/
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#include <net/if.h>
#include <netinet/in.h>
#include <netinet/igmp.h>
-#define KERNEL 1
+#include <net/route.h>
#include <netinet/ip_mroute.h>
-#undef KERNEL
#include <stdio.h>
#include <stdlib.h>
#include "netstat.h"
void
-mroutepr(mrpaddr, mrtaddr, vifaddr)
- u_long mrpaddr, mrtaddr, vifaddr;
+mroutepr(mrpaddr, mfcaddr, vifaddr)
+ u_long mrpaddr, mfcaddr, vifaddr;
{
u_int mrtproto;
- struct mrt *mrttable[MRTHASHSIZ];
+ struct mbuf *mfctable[MFCTBLSIZ];
struct vif viftable[MAXVIFS];
- register struct mrt *mrt;
- struct mrt smrt;
+ struct mbuf mb, *m;
+ struct mfc smfc;
register struct vif *v;
register vifi_t vifi;
- register struct in_addr *grp;
- register int i, n;
+ register int i;
register int banner_printed;
register int saved_nflag;
+ vifi_t maxvif = 0;
if (mrpaddr == 0) {
printf("ip_mrtproto: symbol not in namelist\n");
@@ -94,8 +97,8 @@ mroutepr(mrpaddr, mrtaddr, vifaddr)
return;
}
- if (mrtaddr == 0) {
- printf("mrttable: symbol not in namelist\n");
+ if (mfcaddr == 0) {
+ printf("mfctable: symbol not in namelist\n");
return;
}
if (vifaddr == 0) {
@@ -112,56 +115,53 @@ mroutepr(mrpaddr, mrtaddr, vifaddr)
if (v->v_lcl_addr.s_addr == 0)
continue;
+ maxvif = vifi;
if (!banner_printed) {
- printf("\nVirtual Interface Table\n%s%s",
- " Vif Threshold Local-Address ",
- "Remote-Address Groups\n");
+ printf("\nVirtual Interface Table\n"
+ " Vif Thresh Rate Local-Address "
+ "Remote-Address Pkts-In Pkts-Out\n");
banner_printed = 1;
}
- printf(" %2u %3u %-15.15s",
- vifi, v->v_threshold, routename(v->v_lcl_addr.s_addr));
- printf(" %-15.15s\n", (v->v_flags & VIFF_TUNNEL) ?
+ printf(" %2u %6u %4d %-15.15s",
+ vifi, v->v_threshold, v->v_rate_limit,
+ routename(v->v_lcl_addr.s_addr));
+ printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
routename(v->v_rmt_addr.s_addr) : "");
- n = v->v_lcl_grps_n;
- grp = (struct in_addr *)malloc(n * sizeof(*grp));
- if (grp == NULL) {
- printf("v_lcl_grps_n: malloc failed\n");
- return;
- }
- kread((u_long)v->v_lcl_grps, (caddr_t)grp, n * sizeof(*grp));
- for (i = 0; i < n; ++i)
- printf("%51s %-15.15s\n",
- "", routename((grp++)->s_addr));
- free(grp);
+ printf(" %9lu %9lu\n", v->v_pkt_in, v->v_pkt_out);
}
if (!banner_printed)
printf("\nVirtual Interface Table is empty\n");
- kread(mrtaddr, (char *)&mrttable, sizeof(mrttable));
+ kread(mfcaddr, (char *)&mfctable, sizeof(mfctable));
banner_printed = 0;
- for (i = 0; i < MRTHASHSIZ; ++i) {
- for (mrt = mrttable[i]; mrt != NULL; mrt = mrt->mrt_next) {
+ for (i = 0; i < MFCTBLSIZ; ++i) {
+ m = mfctable[i];
+ while(m) {
+ kread((u_long)m, (char *)&mb, sizeof mb);
+ m = &mb;
+
if (!banner_printed) {
- printf("\nMulticast Routing Table\n%s",
- " Hash Origin-Subnet In-Vif Out-Vifs\n");
+ printf("\nMulticast Forwarding Cache\n"
+ " Origin Group "
+ " Packets In-Vif Out-Vifs:Ttls\n");
banner_printed = 1;
}
- kread((u_long)mrt, (char *)&smrt, sizeof(*mrt));
- mrt = &smrt;
- printf(" %3u %-15.15s %2u ",
- i, netname(mrt->mrt_origin.s_addr,
- ntohl(mrt->mrt_originmask.s_addr)),
- mrt->mrt_parent);
- for (vifi = 0; vifi < MAXVIFS; ++vifi)
- if (VIFM_ISSET(vifi, mrt->mrt_children))
- printf(" %u%c",
- vifi,
- VIFM_ISSET(vifi, mrt->mrt_leaves) ?
- '*' : ' ');
+ kread((u_long)mtod(m, char *),
+ (char *)&smfc, sizeof smfc);
+ printf(" %-15.15s", routename(smfc.mfc_origin.s_addr));
+ printf(" %-15.15s", routename(smfc.mfc_mcastgrp.s_addr));
+ printf(" %9lu", smfc.mfc_pkt_cnt);
+ printf(" %3d ", smfc.mfc_parent);
+ for (vifi = 0; vifi <= maxvif; vifi++) {
+ if (smfc.mfc_ttls[vifi] > 0)
+ printf(" %u:%u", vifi,
+ smfc.mfc_ttls[vifi]);
+ }
printf("\n");
+ m = m->m_act;
}
}
if (!banner_printed)
@@ -204,21 +204,31 @@ mrt_stats(mrpaddr, mstaddr)
}
kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
- printf("multicast routing:\n");
- printf(" %10u multicast route lookup%s\n",
- mrtstat.mrts_mrt_lookups, plural(mrtstat.mrts_mrt_lookups));
- printf(" %10u multicast route cache miss%s\n",
- mrtstat.mrts_mrt_misses, plurales(mrtstat.mrts_mrt_misses));
- printf(" %10u group address lookup%s\n",
- mrtstat.mrts_grp_lookups, plural(mrtstat.mrts_grp_lookups));
- printf(" %10u group address cache miss%s\n",
- mrtstat.mrts_grp_misses, plurales(mrtstat.mrts_grp_misses));
- printf(" %10u datagram%s with no route for origin\n",
+ printf("multicast forwarding:\n");
+ printf(" %10lu multicast forwarding cache lookup%s\n",
+ mrtstat.mrts_mfc_lookups, plural(mrtstat.mrts_mfc_lookups));
+ printf(" %10lu multicast forwarding cache miss%s\n",
+ mrtstat.mrts_mfc_misses, plurales(mrtstat.mrts_mfc_misses));
+ printf(" %10lu upcall%s to mrouted\n",
+ mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls));
+ printf(" %10lu upcall queue overflow%s\n",
+ mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw));
+ printf(" %10lu upcall%s dropped due to full socket buffer\n",
+ mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull));
+ printf(" %10lu cache cleanup%s\n",
+ mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups));
+ printf(" %10lu datagram%s with no route for origin\n",
mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route));
- printf(" %10u datagram%s with malformed tunnel options\n",
+ printf(" %10lu datagram%s arrived with bad tunneling\n",
mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel));
- printf(" %10u datagram%s with no room for tunnel options\n",
+ printf(" %10lu datagram%s could not be tunneled\n",
mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel));
- printf(" %10u datagram%s arrived on the wrong interface\n",
+ printf(" %10lu datagram%s arrived on wrong interface\n",
mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if));
+ printf(" %10lu datagram%s selectively dropped\n",
+ mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel));
+ printf(" %10lu datagram%s dropped due to queue overflow\n",
+ mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow));
+ printf(" %10lu datagram%s dropped for being too large\n",
+ mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large));
}
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index fc0d303..f9afb7a 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -44,12 +44,12 @@
.Op Fl M Ar core
.Op Fl N Ar system
.Nm netstat
-.Op Fl dghimnrs
+.Op Fl bdghimnrs
.Op Fl f Ar address_family
.Op Fl M Ar core
.Op Fl N Ar system
.Nm netstat
-.Op Fl dn
+.Op Fl bdn
.Op Fl I Ar interface
.Op Fl M Ar core
.Op Fl N Ar system
@@ -87,6 +87,11 @@ for debugging.
With the default display,
show the state of all sockets; normally sockets used by
server processes are not shown.
+.It Fl b
+With the interface display (option
+.Fl i
+, as described below),
+show the number of bytes in and out.
.It Fl d
With either interface display (option
.Fl i
@@ -101,12 +106,18 @@ are recognized:
.Ar inet ,
for
.Dv AF_INET ,
-.Ar ns ,
+.Ar ipx ,
for
-.Dv AF_NS ,
-.Ar iso ,
+.Dv AF_IPX ,
+.Ar atalk ,
for
-.Dv AF_ISO ,
+.Dv AF_APPLETALK (ddp) ,
+.\".Ar ns ,
+.\"for
+.\".Dv AF_NS ,
+.\".Ar iso ,
+.\"for
+.\".Dv AF_ISO ,
and
.Ar unix ,
for
@@ -145,7 +156,7 @@ Show statistics recorded by the memory management routines
(the network manages a private pool of memory buffers).
.It Fl N
Extract the name list from the specified system instead of the default
-.Pa /vmunix .
+.Pa /kernel .
.It Fl n
Show network addresses as numbers (normally
.Nm netstat
@@ -218,16 +229,20 @@ The mapping between letters and flags is:
.Bl -column XXXX RTF_BLACKHOLE
1 RTF_PROTO2 Protocol specific routing flag #1
2 RTF_PROTO1 Protocol specific routing flag #2
+3 RTF_PROTO3 Protocol specific routing flag #3
B RTF_BLACKHOLE Just discard pkts (during updates)
+b RTF_BROADCAST The route represents a broadcast address
C RTF_CLONING Generate new routes on use
+c RTF_PRCLONING Protocol-specified generate new routes on use
D RTF_DYNAMIC Created dynamically (by redirect)
G RTF_GATEWAY Destination requires forwarding by intermediary
H RTF_HOST Host entry (net otherwise)
-L RTF_LLINFO Valid protocol to link address translation.
+L RTF_LLINFO Valid protocol to link address translation
M RTF_MODIFIED Modified dynamically (by redirect)
R RTF_REJECT Host or net unreachable
S RTF_STATIC Manually added
U RTF_UP Route usable
+W RTF_WASCLONED Route was generated as a result of cloning
X RTF_XRESOLVE External daemon translates proto to link address
.El
.Pp
@@ -253,26 +268,21 @@ interval argument, it displays a running count of statistics related to
network interfaces.
An obsolescent version of this option used a numeric parameter
with no option, and is currently supported for backward compatibility.
-This display consists of a column for the primary interface (the first
-interface found during autoconfiguration) and a column summarizing
-information for all interfaces.
-The primary interface may be replaced with another interface with the
+By default, this display summarizes information for all interfaces.
+Information for a specific interface may be displayed with the
.Fl I
option.
-The first line of each screen of information contains a summary since the
-system was last rebooted. Subsequent lines of output show values
-accumulated over the preceding interval.
.Sh SEE ALSO
-.Xr iostat 1 ,
.Xr nfsstat 1 ,
.Xr ps 1 ,
-.Xr vmstat 1 ,
.Xr hosts 5 ,
.Xr networks 5 ,
.Xr protocols 5 ,
.Xr services 5 ,
+.Xr iostat 8 ,
.Xr trpt 8 ,
-.Xr trsp 8
+.Xr trsp 8 ,
+.Xr vmstat 8
.Sh HISTORY
The
.Nm netstat
@@ -280,7 +290,7 @@ command appeared in
.Bx 4.2 .
.\" .Sh FILES
.\" .Bl -tag -width /dev/kmem -compact
-.\" .It Pa /vmunix
+.\" .It Pa /kernel
.\" default kernel namelist
.\" .It Pa /dev/kmem
.\" default memory file
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 8f2aa1f..708094f 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -37,6 +37,7 @@
int Aflag; /* show addresses of protocol control block */
int aflag; /* show all sockets (including servers) */
+int bflag; /* show i/f total bytes in/out */
int dflag; /* show i/f dropped packets */
int gflag; /* show group (multicast) routing or stats */
int iflag; /* show interfaces */
@@ -60,6 +61,7 @@ char *prog; /* program name */
int kread __P((u_long addr, char *buf, int size));
char *plural __P((int));
char *plurales __P((int));
+void trimdomain __P((char *));
void protopr __P((u_long, char *));
void tcp_stats __P((u_long, char *));
@@ -69,7 +71,7 @@ void icmp_stats __P((u_long, char *));
void igmp_stats __P((u_long, char *));
void protopr __P((u_long, char *));
-void mbpr(u_long);
+void mbpr __P((u_long));
void hostpr __P((u_long, u_long));
void impstats __P((u_long, u_long));
@@ -79,19 +81,32 @@ void intpr __P((int, u_long));
void pr_rthdr __P(());
void pr_family __P((int));
void rt_stats __P((u_long));
+char *ipx_pnet __P((struct sockaddr *));
+char *ipx_phost __P((struct sockaddr *));
char *ns_phost __P((struct sockaddr *));
void upHex __P((char *));
char *routename __P((u_long));
char *netname __P((u_long, u_long));
+char *atalk_print __P((struct sockaddr *, int));
+char *atalk_print2 __P((struct sockaddr *, struct sockaddr *, int));
+char *ipx_print __P((struct sockaddr *));
char *ns_print __P((struct sockaddr *));
void routepr __P((u_long));
+void ipxprotopr __P((u_long, char *));
+void spx_stats __P((u_long, char *));
+void ipx_stats __P((u_long, char *));
+void ipxerr_stats __P((u_long, char *));
+
void nsprotopr __P((u_long, char *));
void spp_stats __P((u_long, char *));
void idp_stats __P((u_long, char *));
void nserr_stats __P((u_long, char *));
+void atalkprotopr __P((u_long, char *));
+void ddp_stats __P((u_long, char *));
+
void intpr __P((int, u_long));
void unixpr __P((u_long));
@@ -107,3 +122,4 @@ void tp_stats __P((caddr_t, caddr_t));
void mroutepr __P((u_long, u_long, u_long));
void mrt_stats __P((u_long, u_long));
+
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index ee98f07..e920aaa 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -32,23 +32,31 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
+#if 0
+static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$Id: route.c,v 1.26 1997/05/10 10:03:43 jhay Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/protosw.h>
#include <sys/socket.h>
-#include <sys/mbuf.h>
+#include <sys/time.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#define KERNEL
#include <net/route.h>
-#undef KERNEL
+
#include <netinet/in.h>
+#include <netipx/ipx.h>
+#include <netatalk/at.h>
+#ifdef NS
#include <netns/ns.h>
+#endif
#include <sys/sysctl.h>
@@ -57,6 +65,8 @@ static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <err.h>
+#include <time.h>
#include "netstat.h"
#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
@@ -65,7 +75,7 @@ static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
* Definitions for showing gateway flags.
*/
struct bits {
- short b_mask;
+ u_long b_mask;
char b_val;
} bits[] = {
{ RTF_UP, 'U' },
@@ -75,13 +85,17 @@ struct bits {
{ RTF_DYNAMIC, 'D' },
{ RTF_MODIFIED, 'M' },
{ RTF_DONE, 'd' }, /* Completed -- for routing messages only */
- { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */
{ RTF_CLONING, 'C' },
{ RTF_XRESOLVE, 'X' },
{ RTF_LLINFO, 'L' },
{ RTF_STATIC, 'S' },
{ RTF_PROTO1, '1' },
{ RTF_PROTO2, '2' },
+ { RTF_WASCLONED,'W' },
+ { RTF_PRCLONING,'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BLACKHOLE,'B' },
+ { RTF_BROADCAST,'b' },
{ 0 }
};
@@ -94,6 +108,7 @@ int do_rtent = 0;
struct rtentry rtentry;
struct radix_node rnode;
struct radix_mask rmask;
+struct radix_node_head *rt_tables[AF_MAX+1];
int NewTree = 0;
@@ -159,12 +174,20 @@ pr_family(af)
case AF_INET:
afname = "Internet";
break;
+ case AF_IPX:
+ afname = "IPX";
+ break;
+#ifdef NS
case AF_NS:
afname = "XNS";
break;
+#endif
case AF_ISO:
afname = "ISO";
break;
+ case AF_APPLETALK:
+ afname = "AppleTalk";
+ break;
case AF_CCITT:
afname = "X.25";
break;
@@ -179,7 +202,7 @@ pr_family(af)
}
/* column widths; each followed by one space */
-#define WID_DST 16 /* width of destination column */
+#define WID_DST 18 /* width of destination column */
#define WID_GW 18 /* width of gateway column */
/*
@@ -188,13 +211,12 @@ pr_family(af)
void
pr_rthdr()
{
-
if (Aflag)
printf("%-8.8s ","Address");
- printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %s\n",
+ printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
WID_DST, WID_DST, "Destination",
WID_GW, WID_GW, "Gateway",
- "Flags", "Refs", "Use", "Interface");
+ "Flags", "Refs", "Use", "Netif", "Expire");
}
static struct sockaddr *
@@ -217,7 +239,7 @@ again:
kget(rn, rnode);
if (rnode.rn_b < 0) {
if (Aflag)
- printf("%-8.8x ", rn);
+ printf("%-8.8x ", (int)rn);
if (rnode.rn_flags & RNF_ROOT) {
if (Aflag)
printf("(root node)%s",
@@ -232,11 +254,11 @@ again:
NULL, 0, 44);
putchar('\n');
}
- if (rn = rnode.rn_dupedkey)
+ if ((rn = rnode.rn_dupedkey))
goto again;
} else {
if (Aflag && do_rtent) {
- printf("%-8.8x ", rn);
+ printf("%-8.8x ", (int)rn);
p_rtnode();
}
rn = rnode.rn_r;
@@ -261,13 +283,13 @@ p_rtnode()
return;
} else {
sprintf(nbuf, "(%d)", rnode.rn_b);
- printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r);
+ printf("%6.6s %8.8x : %8.8x", nbuf, (int)rnode.rn_l, (int)rnode.rn_r);
}
while (rm) {
kget(rm, rmask);
sprintf(nbuf, " %d refs, ", rmask.rm_refs);
printf(" mk = %8.8x {(%d),%s",
- rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
+ (int)rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
if (rmask.rm_flags & RNF_NORMAL) {
struct radix_node rnode_aux;
printf(" <normal>, ");
@@ -278,7 +300,7 @@ p_rtnode()
p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
NULL, 0, -1);
putchar('}');
- if (rm = rmask.rm_mklist)
+ if ((rm = rmask.rm_mklist))
printf(" ->");
}
putchar('\n');
@@ -298,12 +320,16 @@ ntreestuff()
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
- { perror("route-sysctl-estimate"); exit(1);}
- if ((buf = malloc(needed)) == 0)
- { printf("out of space\n"); exit(1);}
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
- { perror("sysctl of routing table"); exit(1);}
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump estimate");
+ }
+
+ if ((buf = malloc(needed)) == 0) {
+ err(2, "malloc(%lu)", (unsigned long)needed);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump");
+ }
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
@@ -379,9 +405,28 @@ p_sockaddr(sa, mask, flags, width)
break;
}
+ case AF_IPX:
+ {
+ struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
+ if (ipx_nullnet(satoipx_addr(work)))
+ cp = "default";
+ else
+ cp = ipx_print(sa);
+ break;
+ }
+ case AF_APPLETALK:
+ {
+ if (!(flags & RTF_HOST) && mask)
+ cp = atalk_print2(sa,mask,9);
+ else
+ cp = atalk_print(sa,11);
+ break;
+ }
+#ifdef NS
case AF_NS:
cp = ns_print(sa);
break;
+#endif
case AF_LINK:
{
@@ -458,9 +503,16 @@ p_rtentry(rt)
{
static struct ifnet ifnet, *lastif;
static char name[16];
- register struct sockaddr *sa;
+ static char prettyname[9];
+ struct sockaddr *sa;
struct sockaddr addr, mask;
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if(rt->rt_parent && !aflag)
+ return;
+
if (!(sa = kgetsa(rt_key(rt))))
bzero(&addr, sizeof addr);
else
@@ -472,15 +524,28 @@ p_rtentry(rt)
p_sockaddr(&addr, &mask, rt->rt_flags, WID_DST);
p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
p_flags(rt->rt_flags, "%-6.6s ");
- printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
+ printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
if (rt->rt_ifp) {
if (rt->rt_ifp != lastif) {
kget(rt->rt_ifp, ifnet);
kread((u_long)ifnet.if_name, name, 16);
lastif = rt->rt_ifp;
+ snprintf(prettyname, sizeof prettyname,
+ "%.6s%d", name, ifnet.if_unit);
+ }
+ if(rt->rt_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time
+ =rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
+ printf(" %8.8s %6d%s", prettyname,
+ (int)expire_time,
+ rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
+ } else {
+ printf(" %8.8s%s", prettyname,
+ rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
}
- printf(" %.15s%d%s", name, ifnet.if_unit,
- rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
+
}
putchar('\n');
}
@@ -492,26 +557,14 @@ routename(in)
register char *cp;
static char line[MAXHOSTNAMELEN + 1];
struct hostent *hp;
- static char domain[MAXHOSTNAMELEN + 1];
- static int first = 1;
-
- if (first) {
- first = 0;
- if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
- (cp = index(domain, '.')))
- (void) strcpy(domain, cp + 1);
- else
- domain[0] = 0;
- }
+
cp = 0;
if (!nflag) {
hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
AF_INET);
if (hp) {
- if ((cp = index(hp->h_name, '.')) &&
- !strcmp(cp + 1, domain))
- *cp = 0;
cp = hp->h_name;
+ trimdomain(cp);
}
}
if (cp)
@@ -519,7 +572,7 @@ routename(in)
else {
#define C(x) ((x) & 0xff)
in = ntohl(in);
- sprintf(line, "%u.%u.%u.%u",
+ sprintf(line, "%lu.%lu.%lu.%lu",
C(in >> 24), C(in >> 16), C(in >> 8), C(in));
}
return (line);
@@ -581,53 +634,32 @@ netname(in, mask)
char *cp = 0;
static char line[MAXHOSTNAMELEN + 1];
struct netent *np = 0;
- u_long net, omask;
+ u_long net, omask, dmask;
register u_long i;
int subnetshift;
i = ntohl(in);
omask = mask;
if (!nflag && i) {
- if (mask == 0) {
- switch (mask = forgemask(i)) {
- case IN_CLASSA_NET:
- subnetshift = 8;
- break;
- case IN_CLASSB_NET:
- subnetshift = 8;
- break;
- case IN_CLASSC_NET:
- subnetshift = 4;
- break;
- default:
- abort();
- }
- /*
- * If there are more bits than the standard mask
- * would suggest, subnets must be in use.
- * Guess at the subnet mask, assuming reasonable
- * width subnet fields.
- */
- while (i &~ mask)
- mask = (long)mask >> subnetshift;
- }
- net = i & mask;
- while ((mask & 1) == 0)
- mask >>= 1, net >>= 1;
- np = getnetbyaddr(net, AF_INET);
- if (np)
+ dmask = forgemask(i);
+ net = i & dmask;
+ if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
+ np = getnetbyaddr(net, AF_INET);
+ if (np) {
cp = np->n_name;
+ trimdomain(cp);
+ }
}
if (cp)
strncpy(line, cp, sizeof(line) - 1);
else if ((i & 0xffffff) == 0)
- sprintf(line, "%u", C(i >> 24));
+ sprintf(line, "%lu", C(i >> 24));
else if ((i & 0xffff) == 0)
- sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
+ sprintf(line, "%lu.%lu", C(i >> 24) , C(i >> 16));
else if ((i & 0xff) == 0)
- sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
+ sprintf(line, "%lu.%lu.%lu", C(i >> 24), C(i >> 16), C(i >> 8));
else
- sprintf(line, "%u.%u.%u.%u", C(i >> 24),
+ sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24),
C(i >> 16), C(i >> 8), C(i));
domask(line+strlen(line), i, omask);
return (line);
@@ -659,6 +691,94 @@ rt_stats(off)
printf("\t%u use%s of a wildcard route\n",
rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
}
+
+char *
+ipx_print(sa)
+ register struct sockaddr *sa;
+{
+ u_short port;
+ struct netent *np = 0;
+ struct hostent *hp = 0;
+ struct servent *sp = 0;
+ char *net = "", *host = "";
+ register char *p; register u_char *q;
+ struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
+static char mybuf[50];
+ char cport[10], chost[15], cnet[15];
+
+ port = ntohs(work.x_port);
+
+ if (ipx_nullnet(work) && ipx_nullhost(work)) {
+
+ if (port) {
+ if (sp) sprintf(mybuf, "*.%s", sp->s_name);
+ else sprintf(mybuf, "*.%x", port);
+ } else
+ sprintf(mybuf, "*.*");
+
+ return (mybuf);
+ }
+
+ if (ipx_wildnet(work))
+ net = "any";
+ else if (ipx_nullnet(work))
+ net = "*";
+ else {
+ q = work.x_net.c_net;
+ sprintf(cnet, "%02x%02x%02x%02x",
+ q[0], q[1], q[2], q[3]);
+ for (p = cnet; *p == '0' && p < cnet + 8; p++)
+ continue;
+ net = p;
+ }
+
+ if (ipx_wildhost(work))
+ host = "any";
+ else if (ipx_nullhost(work))
+ host = "*";
+ else {
+ q = work.x_host.c_host;
+ sprintf(chost, "%02x%02x%02x%02x%02x%02x",
+ q[0], q[1], q[2], q[3], q[4], q[5]);
+ for (p = chost; *p == '0' && p < chost + 12; p++)
+ continue;
+ host = p;
+ }
+
+ if (port) {
+ if (strcmp(host, "*") == 0) host = "";
+ if (sp) sprintf(cport, "%s%s", *host ? "." : "", sp->s_name);
+ else sprintf(cport, "%s%x", *host ? "." : "", port);
+ } else
+ *cport = 0;
+
+ sprintf(mybuf,"%s.%s%s", net, host, cport);
+ return(mybuf);
+}
+
+char *
+ipx_phost(sa)
+ struct sockaddr *sa;
+{
+ register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
+ struct sockaddr_ipx work;
+static union ipx_net ipx_zeronet;
+ char *p;
+ struct ipx_addr in;
+ struct hostent *hp;
+
+ work = *sipx;
+ in = work.sipx_addr;
+
+ work.sipx_addr.x_port = 0;
+ work.sipx_addr.x_net = ipx_zeronet;
+ p = ipx_print((struct sockaddr *)&work);
+ if (strncmp("*.", p, 2) == 0) p += 2;
+
+ return(p);
+}
+
+#ifdef NS
short ns_nullh[] = {0,0,0};
short ns_bh[] = {-1,-1,-1};
@@ -726,6 +846,7 @@ ns_phost(sa)
if (strncmp("0H.", p, 3) == 0) p += 3;
return(p);
}
+#endif
void
upHex(p0)
diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c
index 0310b68..0309d1c 100644
--- a/usr.bin/netstat/unix.c
+++ b/usr.bin/netstat/unix.c
@@ -40,6 +40,7 @@ static char sccsid[] = "@(#)unix.c 8.1 (Berkeley) 6/6/93";
*/
#include <kvm.h>
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -102,7 +103,7 @@ unixdomainpr(so, soaddr)
{
struct unpcb unpcb, *unp = &unpcb;
struct mbuf mbuf, *m;
- struct sockaddr_un *sa;
+ struct sockaddr_un *sa = NULL;
static int first = 1;
if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp)))
@@ -122,10 +123,10 @@ unixdomainpr(so, soaddr)
"Inode", "Conn", "Refs", "Nextref");
first = 0;
}
- printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x",
- soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc,
- unp->unp_vnode, unp->unp_conn,
- unp->unp_refs, unp->unp_nextref);
+ printf("%8x %-6.6s %6ld %6ld %8x %8x %8x %8x",
+ (int)soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc,
+ (int)unp->unp_vnode, (int)unp->unp_conn,
+ (int)unp->unp_refs, (int)unp->unp_nextref);
if (m)
printf(" %.*s",
m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)),
diff --git a/usr.bin/newkey/Makefile b/usr.bin/newkey/Makefile
new file mode 100644
index 0000000..bd62ecb
--- /dev/null
+++ b/usr.bin/newkey/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+
+PROG= newkey
+SRCS= newkey.c update.c generic.c
+
+MAN8= newkey.8
+
+# Later
+#CFLAGS+= -DYP
+
+LDADD+= -lrpcsvc -lmp -lgmp
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/newkey/generic.c b/usr.bin/newkey/generic.c
new file mode 100644
index 0000000..4d15185
--- /dev/null
+++ b/usr.bin/newkey/generic.c
@@ -0,0 +1,135 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)generic.c 1.2 91/03/11 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <sys/file.h>
+#include <mp.h>
+#include <rpc/key_prot.h>
+
+static int adjust __P(( char[], char * ));
+/*
+ * Generate a seed
+ */
+static
+getseed(seed, seedsize, pass)
+ char *seed;
+ int seedsize;
+ unsigned char *pass;
+{
+ int i;
+ int rseed;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, (struct timezone *)NULL);
+ rseed = tv.tv_sec + tv.tv_usec;
+ for (i = 0; i < 8; i++) {
+ rseed ^= (rseed << 8) | pass[i];
+ }
+ srand(rseed);
+
+ for (i = 0; i < seedsize; i++) {
+ seed[i] = (rand() & 0xff) ^ pass[i % 8];
+ }
+}
+
+/*
+ * Generate a random public/secret key pair
+ */
+genkeys(public, secret, pass)
+ char *public;
+ char *secret;
+ char *pass;
+{
+ int i;
+
+# define BASEBITS (8*sizeof (short) - 1)
+# define BASE (1 << BASEBITS)
+
+ MINT *pk = itom(0);
+ MINT *sk = itom(0);
+ MINT *tmp;
+ MINT *base = itom(BASE);
+ MINT *root = itom(PROOT);
+ MINT *modulus = xtom(HEXMODULUS);
+ short r;
+ unsigned short seed[KEYSIZE/BASEBITS + 1];
+ char *xkey;
+
+ getseed((char *)seed, sizeof (seed), (u_char *)pass);
+ for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
+ r = seed[i] % BASE;
+ tmp = itom(r);
+ mult(sk, base, sk);
+ madd(sk, tmp, sk);
+ mfree(tmp);
+ }
+ tmp = itom(0);
+ mdiv(sk, modulus, tmp, sk);
+ mfree(tmp);
+ pow(root, sk, modulus, pk);
+ xkey = mtox(sk);
+ adjust(secret, xkey);
+ xkey = mtox(pk);
+ adjust(public, xkey);
+ mfree(sk);
+ mfree(base);
+ mfree(pk);
+ mfree(root);
+ mfree(modulus);
+}
+
+/*
+ * Adjust the input key so that it is 0-filled on the left
+ */
+static
+adjust(keyout, keyin)
+ char keyout[HEXKEYBYTES+1];
+ char *keyin;
+{
+ char *p;
+ char *s;
+
+ for (p = keyin; *p; p++)
+ ;
+ for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
+ *s = *p;
+ }
+ while (s >= keyout) {
+ *s-- = '0';
+ }
+}
diff --git a/usr.bin/newkey/newkey.8 b/usr.bin/newkey/newkey.8
new file mode 100644
index 0000000..8029751
--- /dev/null
+++ b/usr.bin/newkey/newkey.8
@@ -0,0 +1,57 @@
+.\" @(#)newkey.8 1.3 91/03/11 TIRPC 1.0; from 1.12 90/02/03 SMI;
+.TH NEWKEY 8 "12 October 1987"
+.SH NAME
+newkey \- create a new key in the publickey database
+.SH SYNOPSIS
+.B "newkey \-h"
+.I hostname
+.br
+.B "newkey \-u"
+.I username
+.SH DESCRIPTION
+.IX "newkey command" "" "\fLnewkey\fP command"
+.LP
+.B newkey
+is normally run by the network administrator on the
+Network Interface Service
+(\s-1NIS\s0)
+master machine in order to establish public keys for
+users and super-users on the network.
+These keys are needed for using secure
+.SM RPC
+or secure
+.SM NFS\s0.
+.LP
+.B newkey
+will prompt for the login password of the given username and then
+create a new public/secret key pair in
+.B /etc/publickey
+encrypted with the login password of the given user.
+.LP
+Use of this program is
+not required: users may create their own keys using
+.BR chkey (1).
+.SH OPTIONS
+.TP 12
+.BI \-h " hostname"
+Create a new public key for the super-user at the given hostname.
+Prompts for the root password of the given hostname.
+.TP
+.BI \-u " username"
+Create a new public key for the given username.
+Prompts for the
+.SM NIS
+password of the given username.
+.SH "SEE ALSO"
+.BR chkey (1),
+.BR keylogin (1),
+.BR publickey (5),
+.BR keyserv (8C)
+.SH NOTES
+.LP
+The Network Information Service
+(\s-1NIS\s0)
+was formerly known as Sun Yellow Pages
+(\s-1YP\s0).
+The functionality of the two remains the same;
+only the name has changed.
diff --git a/usr.bin/newkey/newkey.c b/usr.bin/newkey/newkey.c
new file mode 100644
index 0000000..489324d
--- /dev/null
+++ b/usr.bin/newkey/newkey.c
@@ -0,0 +1,235 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)newkey.c 1.8 91/03/11 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Administrative tool to add a new user to the publickey database
+ */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#endif /* YP */
+#include <pwd.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#ifdef YP
+#define MAXMAPNAMELEN 256
+#else
+#define YPOP_CHANGE 1 /* change, do not add */
+#define YPOP_INSERT 2 /* add, do not change */
+#define YPOP_DELETE 3 /* delete this entry */
+#define YPOP_STORE 4 /* add, or change */
+#define ERR_ACCESS 1
+#define ERR_MALLOC 2
+#define ERR_READ 3
+#define ERR_WRITE 4
+#define ERR_DBASE 5
+#define ERR_KEY 6
+#endif
+
+extern char *getpass();
+extern char *malloc();
+
+#ifdef YP
+static char *basename();
+static char SHELL[] = "/bin/sh";
+static char YPDBPATH[]="/var/yp";
+static char PKMAP[] = "publickey.byname";
+static char UPDATEFILE[] = "updaters";
+#else
+static char PKFILE[] = "/etc/publickey";
+static char *err_string();
+#endif /* YP */
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char name[MAXNETNAMELEN + 1];
+ char public[HEXKEYBYTES + 1];
+ char secret[HEXKEYBYTES + 1];
+ char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
+ char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
+ int status;
+ char *pass;
+ struct passwd *pw;
+#ifdef undef
+ struct hostent *h;
+#endif
+
+ if (argc != 3 || !(strcmp(argv[1], "-u") == 0 ||
+ strcmp(argv[1], "-h") == 0)) {
+ (void)fprintf(stderr, "usage: %s [-u username]\n",
+ argv[0]);
+ (void)fprintf(stderr, "usage: %s [-h hostname]\n",
+ argv[0]);
+ exit(1);
+ }
+ if (geteuid() != 0) {
+ (void)fprintf(stderr, "must be superuser to run %s\n", argv[0]);
+ exit(1);
+ }
+
+#ifdef YP
+ if (chdir(YPDBPATH) < 0) {
+ (void)fprintf(stderr, "cannot chdir to ");
+ perror(YPDBPATH);
+ }
+#endif /* YP */
+ if (strcmp(argv[1], "-u") == 0) {
+ pw = getpwnam(argv[2]);
+ if (pw == NULL) {
+ (void)fprintf(stderr, "unknown user: %s\n", argv[2]);
+ exit(1);
+ }
+ (void)user2netname(name, (int)pw->pw_uid, (char *)NULL);
+ } else {
+#ifdef undef
+ h = gethostbyname(argv[2]);
+ if (h == NULL) {
+ (void)fprintf(stderr, "unknown host: %s\n", argv[1]);
+ exit(1);
+ }
+ (void)host2netname(name, h->h_name, (char *)NULL);
+#else
+ (void)host2netname(name, argv[2], (char *)NULL);
+#endif
+ }
+
+ (void)printf("Adding new key for %s.\n", name);
+ pass = getpass("New password:");
+ genkeys(public, secret, pass);
+
+ memcpy(crypt1, secret, HEXKEYBYTES);
+ memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
+ crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
+ xencrypt(crypt1, pass);
+
+ memcpy(crypt2, crypt1, HEXKEYBYTES + KEYCHECKSUMSIZE + 1);
+ xdecrypt(crypt2, getpass("Retype password:"));
+ if (memcmp(crypt2, crypt2 + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0 ||
+ memcmp(crypt2, secret, HEXKEYBYTES) != 0) {
+ (void)fprintf(stderr, "Password incorrect.\n");
+ exit(1);
+ }
+
+#ifdef YP
+ (void)printf("Please wait for the database to get updated...\n");
+#endif
+ if (status = setpublicmap(name, public, crypt1)) {
+#ifdef YP
+ (void)fprintf(stderr,
+ "%s: unable to update NIS database (%u): %s\n",
+ argv[0], status, yperr_string(status));
+#else
+ (void)fprintf(stderr,
+ "%s: unable to update publickey database (%u): %s\n",
+ argv[0], status, err_string(status));
+#endif
+ exit(1);
+ }
+ (void)printf("Your new key has been successfully stored away.\n");
+ exit(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Set the entry in the public key file
+ */
+setpublicmap(name, public, secret)
+ char *name;
+ char *public;
+ char *secret;
+{
+ char pkent[1024];
+
+ (void)sprintf(pkent, "%s:%s", public, secret);
+#ifdef YP
+ return (mapupdate(name, PKMAP, YPOP_STORE,
+ strlen(name), name, strlen(pkent), pkent));
+#else
+ return (localupdate(name, PKFILE, YPOP_STORE,
+ strlen(name), name, strlen(pkent), pkent));
+#endif
+ }
+
+#ifndef YP
+ /*
+ * This returns a pointer to an error message string appropriate
+ * to an input error code. An input value of zero will return
+ * a success message.
+ */
+static char *
+err_string(code)
+ int code;
+{
+ char *pmesg;
+
+ switch (code) {
+ case 0:
+ pmesg = "update operation succeeded";
+ break;
+ case ERR_KEY:
+ pmesg = "no such key in file";
+ break;
+ case ERR_READ:
+ pmesg = "cannot read the database";
+ break;
+ case ERR_WRITE:
+ pmesg = "cannot write to the database";
+ break;
+ case ERR_DBASE:
+ pmesg = "cannot update database";
+ break;
+ case ERR_ACCESS:
+ pmesg = "permission denied";
+ break;
+ case ERR_MALLOC:
+ pmesg = "malloc failed";
+ break;
+ default:
+ pmesg = "unknown error";
+ break;
+ }
+ return (pmesg);
+}
+#endif
diff --git a/usr.bin/newkey/update.c b/usr.bin/newkey/update.c
new file mode 100644
index 0000000..e6bc9a6
--- /dev/null
+++ b/usr.bin/newkey/update.c
@@ -0,0 +1,356 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#ifndef lint
+static char sccsid[] = "@(#)update.c 1.2 91/03/11 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * Copyright (C) 1986, 1989, Sun Microsystems, Inc.
+ */
+
+/*
+ * Administrative tool to add a new user to the publickey database
+ */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#endif /* YP */
+#include <pwd.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#ifdef YP
+#define MAXMAPNAMELEN 256
+#else
+#define YPOP_CHANGE 1 /* change, do not add */
+#define YPOP_INSERT 2 /* add, do not change */
+#define YPOP_DELETE 3 /* delete this entry */
+#define YPOP_STORE 4 /* add, or change */
+#endif
+
+extern char *getpass();
+extern char *malloc();
+
+#ifdef YP
+static char *basename();
+static char SHELL[] = "/bin/sh";
+static char YPDBPATH[]="/var/yp"; /* This is defined but not used! */
+static char PKMAP[] = "publickey.byname";
+static char UPDATEFILE[] = "updaters";
+#else
+static char PKFILE[] = "/etc/publickey";
+#endif /* YP */
+
+#ifdef YP
+static int _openchild __P(( char *, FILE **, FILE ** ));
+
+/*
+ * Determine if requester is allowed to update the given map,
+ * and update it if so. Returns the yp status, which is zero
+ * if there is no access violation.
+ */
+mapupdate(requester, mapname, op, keylen, key, datalen, data)
+ char *requester;
+ char *mapname;
+ u_int op;
+ u_int keylen;
+ char *key;
+ u_int datalen;
+ char *data;
+{
+ char updater[MAXMAPNAMELEN + 40];
+ FILE *childargs;
+ FILE *childrslt;
+#ifdef WEXITSTATUS
+ int status;
+#else
+ union wait status;
+#endif
+ pid_t pid;
+ u_int yperrno;
+
+
+#ifdef DEBUG
+ printf("%s %s\n", key, data);
+#endif
+ (void)sprintf(updater, "make -s -f %s/%s %s", YPDBPATH, /* !!! */
+ UPDATEFILE, mapname);
+ pid = _openchild(updater, &childargs, &childrslt);
+ if (pid < 0) {
+ return (YPERR_YPERR);
+ }
+
+ /*
+ * Write to child
+ */
+ (void)fprintf(childargs, "%s\n", requester);
+ (void)fprintf(childargs, "%u\n", op);
+ (void)fprintf(childargs, "%u\n", keylen);
+ (void)fwrite(key, (int)keylen, 1, childargs);
+ (void)fprintf(childargs, "\n");
+ (void)fprintf(childargs, "%u\n", datalen);
+ (void)fwrite(data, (int)datalen, 1, childargs);
+ (void)fprintf(childargs, "\n");
+ (void)fclose(childargs);
+
+ /*
+ * Read from child
+ */
+ (void)fscanf(childrslt, "%d", &yperrno);
+ (void)fclose(childrslt);
+
+ (void)wait(&status);
+#ifdef WEXITSTATUS
+ if (WEXITSTATUS(status) != 0) {
+#else
+ if (status.w_retcode != 0) {
+#endif
+ return (YPERR_YPERR);
+ }
+ return (yperrno);
+}
+
+/*
+ * returns pid, or -1 for failure
+ */
+static
+_openchild(command, fto, ffrom)
+ char *command;
+ FILE **fto;
+ FILE **ffrom;
+{
+ int i;
+ pid_t pid;
+ int pdto[2];
+ int pdfrom[2];
+ char *com;
+ struct rlimit rl;
+
+ if (pipe(pdto) < 0) {
+ goto error1;
+ }
+ if (pipe(pdfrom) < 0) {
+ goto error2;
+ }
+#ifdef VFORK
+ switch (pid = vfork()) {
+#else
+ switch (pid = fork()) {
+#endif
+ case -1:
+ goto error3;
+
+ case 0:
+ /*
+ * child: read from pdto[0], write into pdfrom[1]
+ */
+ (void)close(0);
+ (void)dup(pdto[0]);
+ (void)close(1);
+ (void)dup(pdfrom[1]);
+ getrlimit(RLIMIT_NOFILE, &rl);
+ for (i = rl.rlim_max - 1; i >= 3; i--) {
+ (void) close(i);
+ }
+ com = malloc((unsigned) strlen(command) + 6);
+ if (com == NULL) {
+ _exit(~0);
+ }
+ (void)sprintf(com, "exec %s", command);
+ execl(SHELL, basename(SHELL), "-c", com, NULL);
+ _exit(~0);
+
+ default:
+ /*
+ * parent: write into pdto[1], read from pdfrom[0]
+ */
+ *fto = fdopen(pdto[1], "w");
+ (void)close(pdto[0]);
+ *ffrom = fdopen(pdfrom[0], "r");
+ (void)close(pdfrom[1]);
+ break;
+ }
+ return (pid);
+
+ /*
+ * error cleanup and return
+ */
+error3:
+ (void)close(pdfrom[0]);
+ (void)close(pdfrom[1]);
+error2:
+ (void)close(pdto[0]);
+ (void)close(pdto[1]);
+error1:
+ return (-1);
+}
+
+static char *
+basename(path)
+ char *path;
+{
+ char *p;
+
+ p = strrchr(path, '/');
+ if (p == NULL) {
+ return (path);
+ } else {
+ return (p + 1);
+ }
+}
+
+#else /* YP */
+
+#define ERR_ACCESS 1
+#define ERR_MALLOC 2
+#define ERR_READ 3
+#define ERR_WRITE 4
+#define ERR_DBASE 5
+#define ERR_KEY 6
+extern char *malloc();
+
+static int match __P(( char * , char * ));
+
+/*
+ * Determine if requester is allowed to update the given map,
+ * and update it if so. Returns the status, which is zero
+ * if there is no access violation. This function updates
+ * the local file and then shuts up.
+ */
+localupdate(name, filename, op, keylen, key, datalen, data)
+ char *name; /* Name of the requestor */
+ char *filename;
+ u_int op;
+ u_int keylen; /* Not used */
+ char *key;
+ u_int datalen; /* Not used */
+ char *data;
+{
+ char line[256];
+ FILE *rf;
+ FILE *wf;
+ char *tmpname;
+ int err;
+
+ /*
+ * Check permission
+ */
+ if (strcmp(name, key) != 0) {
+ return (ERR_ACCESS);
+ }
+ if (strcmp(name, "nobody") == 0) {
+ /*
+ * Can't change "nobody"s key.
+ */
+ return (ERR_ACCESS);
+ }
+
+ /*
+ * Open files
+ */
+ tmpname = malloc(strlen(filename) + 4);
+ if (tmpname == NULL) {
+ return (ERR_MALLOC);
+ }
+ sprintf(tmpname, "%s.tmp", filename);
+ rf = fopen(filename, "r");
+ if (rf == NULL) {
+ return (ERR_READ);
+ }
+ wf = fopen(tmpname, "w");
+ if (wf == NULL) {
+ return (ERR_WRITE);
+ }
+ err = -1;
+ while (fgets(line, sizeof (line), rf)) {
+ if (err < 0 && match(line, name)) {
+ switch (op) {
+ case YPOP_INSERT:
+ err = ERR_KEY;
+ break;
+ case YPOP_STORE:
+ case YPOP_CHANGE:
+ fprintf(wf, "%s %s\n", key, data);
+ err = 0;
+ break;
+ case YPOP_DELETE:
+ /* do nothing */
+ err = 0;
+ break;
+ }
+ } else {
+ fputs(line, wf);
+ }
+ }
+ if (err < 0) {
+ switch (op) {
+ case YPOP_CHANGE:
+ case YPOP_DELETE:
+ err = ERR_KEY;
+ break;
+ case YPOP_INSERT:
+ case YPOP_STORE:
+ err = 0;
+ fprintf(wf, "%s %s\n", key, data);
+ break;
+ }
+ }
+ fclose(wf);
+ fclose(rf);
+ if (err == 0) {
+ if (rename(tmpname, filename) < 0) {
+ return (ERR_DBASE);
+ }
+ } else {
+ if (unlink(tmpname) < 0) {
+ return (ERR_DBASE);
+ }
+ }
+ return (err);
+}
+
+static
+match(line, name)
+ char *line;
+ char *name;
+{
+ int len;
+
+ len = strlen(name);
+ return (strncmp(line, name, len) == 0 &&
+ (line[len] == ' ' || line[len] == '\t'));
+}
+#endif /* !YP */
+
diff --git a/usr.bin/nfsstat/nfsstat.1 b/usr.bin/nfsstat/nfsstat.1
index 3acda6c..4d29692 100644
--- a/usr.bin/nfsstat/nfsstat.1
+++ b/usr.bin/nfsstat/nfsstat.1
@@ -29,7 +29,8 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)nfsstat.1 8.1 (Berkeley) 6/6/93
+.\" From: @(#)nfsstat.1 8.1 (Berkeley) 6/6/93
+.\" $Id: nfsstat.1,v 1.6 1997/02/22 19:56:24 peter Exp $
.\"
.Dd June 6, 1993
.Dt NFSSTAT 1
@@ -40,13 +41,14 @@
.Tn NFS
statistics
.Sh SYNOPSIS
-.Nm nfsstat
+.Nm
.Op Fl M Ar core
.Op Fl N Ar system
.Op Fl w Ar wait
.Sh DESCRIPTION
-.Nm Nfsstat
-displays statistics kept about
+The
+.Nm
+command displays statistics kept about
.Tn NFS
client and server activity.
.Pp
@@ -58,7 +60,7 @@ instead of the default
.Pa /dev/kmem .
.It Fl N
Extract the name list from the specified system instead of the default
-.Pa /vmunix .
+.Pa /kernel .
.It Fl w
Display a shorter summary of
.Tn NFS
@@ -68,7 +70,7 @@ second intervals.
.El
.Sh FILES
.Bl -tag -width /dev/kmem -compact
-.It Pa /vmunix
+.It Pa /kernel
default kernel namelist
.It Pa /dev/kmem
default memory file
@@ -78,11 +80,12 @@ default memory file
.Xr netstat 1 ,
.Xr ps 1 ,
.Xr systat 1 ,
-.Xr vmstat 1 ,
+.Xr sysctl 3 ,
.Xr iostat 8 ,
.Xr pstat 8 ,
+.Xr vmstat 8
.Sh HISTORY
The
-.Nm nfsstat
-command appears in
+.Nm
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/nfsstat/nfsstat.c b/usr.bin/nfsstat/nfsstat.c
index c7ef75d..a53991a 100644
--- a/usr.bin/nfsstat/nfsstat.c
+++ b/usr.bin/nfsstat/nfsstat.c
@@ -41,11 +41,14 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)nfsstat.c 8.2 (Berkeley) 3/31/95";
+/*static char sccsid[] = "From: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93";*/
+static const char rcsid[] =
+ "$Id: nfsstat.c,v 1.8 1997/02/22 19:56:25 peter Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/time.h>
#include <sys/sysctl.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
@@ -90,7 +93,7 @@ main(argc, argv)
interval = 0;
memf = nlistf = NULL;
- while ((ch = getopt(argc, argv, "M:N:w:")) != EOF)
+ while ((ch = getopt(argc, argv, "M:N:w:")) != -1)
switch(ch) {
case 'M':
memf = optarg;
@@ -159,14 +162,12 @@ readstats(stp)
} else {
int name[3];
size_t buflen = sizeof *stp;
- struct vfsconf vfc;
- if (getvfsbyname("nfs", &vfc) < 0)
- err(1, "getvfsbyname: NFS not compiled into kernel");
name[0] = CTL_VFS;
- name[1] = vfc.vfc_typenum;
+ name[1] = MOUNT_NFS;
name[2] = NFS_NFSSTATS;
- if (sysctl(name, 3, stp, &buflen, (void *)0, (size_t)0) < 0) {
+
+ if(sysctl(name, 3, stp, &buflen, (void *)0, (size_t)0) < 0) {
err(1, "sysctl");
}
}
diff --git a/usr.bin/nice/nice.1 b/usr.bin/nice/nice.1
index 67b8471..fad8f6c 100644
--- a/usr.bin/nice/nice.1
+++ b/usr.bin/nice/nice.1
@@ -1,7 +1,6 @@
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
-.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -31,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)nice.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt NICE 1
@@ -51,26 +51,47 @@ at a low priority.
(Think of low and slow).
If
.Fl Ns Ar number
-is specified, and if it is greater than or equal
-to 10 (the default),
-.Nm nice
+is not given
+.Nm
+assumed the value 10.
+The priority is a value in the range -20 to 20. The default priority
+is 0, priority 20 is the lowest possible.
+.Nm Nice
will execute
.Ar command
-at that priority.
-The upper bound, or lowest priority that
-.Nm nice
-will run a command is 20.
-The lower bounds or
-higher priorities (integers less than 10)
-can only be requested by the super-user.
+at priority
+.Ar number
+relative to the priority
+of
+.Nm nice .
+Higher priorities than the
+current process priority can only requested by the
+super-user.
Negative numbers are expressed as
.Fl - Ns Ar number .
.Pp
The returned exit status is the exit value from the
command executed by
.Nm nice .
+.Sh EXAMPLES
+.Pp
+$ nice -5 date
+.Pp
+Execute command
+.Sq date
+at priority 5 assuming the priority of the
+shell is 0.
+.Pp
+# nice -16 nice --35 date
+.Pp
+Execute command
+.Sq date
+at priority -19 assuming the priority of the
+shell is 0 and you are the super-user.
.Sh SEE ALSO
.Xr csh 1 ,
+.Xr getpriority 2 ,
+.Xr setpriority 2 ,
.Xr renice 8
.Sh HISTORY
A
diff --git a/usr.bin/nice/nice.c b/usr.bin/nice/nice.c
index 9805bfa..300dc87 100644
--- a/usr.bin/nice/nice.c
+++ b/usr.bin/nice/nice.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)nice.c 8.3 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)nice.c 8.2 (Berkeley) 4/16/94";
#endif /* not lint */
#include <sys/types.h>
@@ -64,17 +64,19 @@ main(argc, argv)
{
int niceness = DEFNICE;
- if (argv[1] == NULL)
+ if (argc < 2)
usage();
+
if (argv[1][0] == '-')
if (argv[1][1] == '-' || isdigit(argv[1][1])) {
niceness = atoi(argv[1] + 1);
++argv;
- if (argv[1] == NULL)
- usage();
} else
errx(1, "illegal option -- %s", argv[1]);
+ if (argv[1] == NULL)
+ usage();
+
errno = 0;
niceness += getpriority(PRIO_PROCESS, 0);
if (errno)
@@ -88,7 +90,6 @@ main(argc, argv)
void
usage()
{
- (void)fprintf(stderr,
- "nice [ -# ] command [ options ] [ operands ]\n");
+ (void)fprintf(stderr, "usage: nice [-number] command [arguments]\n");
exit(1);
}
diff --git a/usr.bin/nm/nm.1 b/usr.bin/nm/nm.1
index ff7cdb2..0ebeb98 100644
--- a/usr.bin/nm/nm.1
+++ b/usr.bin/nm/nm.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)nm.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt NM 1
@@ -39,7 +40,7 @@
.Nd display name list (symbol table)
.Sh SYNOPSIS
.Nm nm
-.Op Fl agnopruw
+.Op Fl agnoprtuwW
.Ar
.Sh DESCRIPTION
The symbol table (name list) of each object in
@@ -71,12 +72,16 @@ Display full path or library name of object on every line.
Do not sort at all.
.It Fl r
Reverse order sort.
+.It Fl t
+Output in tabular format more suitable for other programs digestive system.
.It Fl u
Display undefined symbols only.
.It Fl w
Warn about non-object archive members.
Normally, nm will silently ignore all archive members which are not
object files.
+.It Fl W
+Include an extra column in the output with a ``W'' indicating weak symbols.
.El
.Pp
Each symbol name is preceded by its value (a blank field if the symbol
@@ -97,21 +102,25 @@ common symbol
data segment symbol
.It Li f
file name
+.It Li I
+indirect reference symbol
.It Li T
text segment symbol
.It Li U
undefined
+.It Li W
+warn if next symbol is referenced
.El
.Pp
If the symbol is local (non-external) the type letter is in lower case.
The output is sorted alphabetically.
.Sh SEE ALSO
.Xr ar 1 ,
-.Xr ar 5 ,
.Xr a.out 5 ,
+.Xr ar 5 ,
.Xr stab 5
.Sh HISTORY
An
.Nm nm
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/nm/nm.1aout b/usr.bin/nm/nm.1aout
new file mode 100644
index 0000000..0ebeb98
--- /dev/null
+++ b/usr.bin/nm/nm.1aout
@@ -0,0 +1,126 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nm.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
+.\"
+.Dd June 6, 1993
+.Dt NM 1
+.Os BSD 4
+.Sh NAME
+.Nm nm
+.Nd display name list (symbol table)
+.Sh SYNOPSIS
+.Nm nm
+.Op Fl agnoprtuwW
+.Ar
+.Sh DESCRIPTION
+The symbol table (name list) of each object in
+.Ar file(s)
+is displayed.
+If a library (archive) is given,
+.Nm
+displays a list for each
+object archive member.
+If
+.Ar file
+is not present,
+.Nm
+searches for the file
+.Pa a.out
+and if present, displays the symbol
+table for
+.Pa a.out .
+.Bl -tag -width flag
+.It Fl a
+Display symbol table entries inserted for use by debuggers.
+.It Fl g
+Restrict display to external (global) symbols.
+.It Fl n
+Present results in numerical order.
+.It Fl o
+Display full path or library name of object on every line.
+.It Fl p
+Do not sort at all.
+.It Fl r
+Reverse order sort.
+.It Fl t
+Output in tabular format more suitable for other programs digestive system.
+.It Fl u
+Display undefined symbols only.
+.It Fl w
+Warn about non-object archive members.
+Normally, nm will silently ignore all archive members which are not
+object files.
+.It Fl W
+Include an extra column in the output with a ``W'' indicating weak symbols.
+.El
+.Pp
+Each symbol name is preceded by its value (a blank field if the symbol
+is undefined) and one of the following letters:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Fl
+debugger symbol table entries (see the
+.Fl a
+option).
+.It Li A
+absolute
+.It Li B
+bss segment symbol
+.It Li C
+common symbol
+.It Li D
+data segment symbol
+.It Li f
+file name
+.It Li I
+indirect reference symbol
+.It Li T
+text segment symbol
+.It Li U
+undefined
+.It Li W
+warn if next symbol is referenced
+.El
+.Pp
+If the symbol is local (non-external) the type letter is in lower case.
+The output is sorted alphabetically.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr a.out 5 ,
+.Xr ar 5 ,
+.Xr stab 5
+.Sh HISTORY
+An
+.Nm nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/nm/nm.c b/usr.bin/nm/nm.c
index 6744cf6..9ee4b6e 100644
--- a/usr.bin/nm/nm.c
+++ b/usr.bin/nm/nm.c
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 6/6/93";
#include <a.out.h>
#include <stab.h>
#include <ar.h>
+#include <dirent.h>
#include <ranlib.h>
#include <unistd.h>
#include <errno.h>
@@ -61,9 +62,10 @@ int print_only_external_symbols;
int print_only_undefined_symbols;
int print_all_symbols;
int print_file_each_line;
+int print_weak_symbols;
int fcount;
-int rev;
+int rev, table;
int fname(), rname(), value();
int (*sfunc)() = fname;
@@ -71,14 +73,22 @@ int (*sfunc)() = fname;
#define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
#define IS_EXTERNAL(x) ((x) & N_EXT)
#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
+#define SYMBOL_BIND(x) (((x) >> 4) & 0xf)
void *emalloc();
+void usage __P(( void ));
+int process_file __P(( char * ));
+int show_archive __P(( char *, FILE * ));
+int show_objfile __P(( char *, FILE * ));
+void print_symbol __P(( char *, struct nlist * ));
+char typeletter __P((u_char));
/*
* main()
* parse command line, execute process_file() for each file
* specified on the command line.
*/
+int
main(argc, argv)
int argc;
char **argv;
@@ -86,7 +96,7 @@ main(argc, argv)
extern int optind;
int ch, errors;
- while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
+ while ((ch = getopt(argc, argv, "agnoprtuwW")) != -1) {
switch (ch) {
case 'a':
print_all_symbols = 1;
@@ -106,12 +116,18 @@ main(argc, argv)
case 'r':
rev = 1;
break;
+ case 't':
+ table = 1;
+ break;
case 'u':
print_only_undefined_symbols = 1;
break;
case 'w':
ignore_bad_archive_entries = 0;
break;
+ case 'W':
+ print_weak_symbols = 1;
+ break;
case '?':
default:
usage();
@@ -139,6 +155,7 @@ main(argc, argv)
* show symbols in the file given as an argument. Accepts archive and
* object files as input.
*/
+int
process_file(fname)
char *fname;
{
@@ -146,15 +163,15 @@ process_file(fname)
FILE *fp;
int retval;
char magic[SARMAG];
-
+
if (!(fp = fopen(fname, "r"))) {
(void)fprintf(stderr, "nm: cannot read %s.\n", fname);
return(1);
}
- if (fcount > 1)
+ if (fcount > 1 && !table)
(void)printf("\n%s:\n", fname);
-
+
/*
* first check whether this is an object file - read a object
* header, and skip back to the beginning
@@ -182,10 +199,26 @@ process_file(fname)
return(retval);
}
+/* scat: concatenate strings, returning new concatenation point
+ * and permitting overlap.
+ */
+static char *scat(char *dest, char *src)
+{
+ char *end;
+ int l1 = strlen(dest), l2 = strlen(src);
+
+ memmove(dest + l1, src, l2);
+ end = dest + l1 + l2;
+ *end = 0;
+
+ return end;
+}
+
/*
* show_archive()
* show symbols in the given archive file
*/
+int
show_archive(fname, fp)
char *fname;
FILE *fp;
@@ -194,9 +227,11 @@ show_archive(fname, fp)
struct exec exec_head;
int i, rval;
long last_ar_off;
- char *p, *name;
+ char *p, *name, *ar_name;
+ int extra = strlen(fname) + 3;
- name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
+ name = emalloc(MAXNAMLEN + extra);
+ ar_name = name + extra;
rval = 0;
@@ -214,25 +249,53 @@ show_archive(fname, fp)
last_ar_off = ftell(fp);
/* skip ranlib entries */
- if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
+ if (!bcmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
goto skip;
+ /* handle long names. If one is present, read it in at the
+ * end of the "name" buffer.
+ */
+ if (!bcmp(ar_head.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1))
+ {
+ size_t len = atoi(ar_head.ar_name + sizeof(AR_EFMT1) - 1);
+
+ if (len <= 0 || len > MAXNAMLEN)
+ {
+ fprintf(stderr, "nm: Illegal length for format 1 long name.\n");
+ goto skip;
+ }
+ if (fread(ar_name, 1, len, fp) != len)
+ {
+ (void)fprintf(stderr, "nm: EOF reading format 1 long name.\n");
+ (void)free(name);
+ return(1);
+ }
+ ar_name[len] = 0;
+ }
+ else
+ {
+ p = ar_head.ar_name;
+ for (i = 0; i < sizeof(ar_head.ar_name) && p[i] && p[i] != ' '; i++)
+ ar_name[i] = p[i];
+ ar_name[i] = 0;
+ }
+
/*
* construct a name of the form "archive.a:obj.o:" for the
* current archive entry if the object name is to be printed
* on each output line
*/
p = name;
- if (print_file_each_line)
- p += sprintf(p, "%s:", fname);
- for (i = 0; i < sizeof(ar_head.ar_name); ++i)
- if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
- *p++ = ar_head.ar_name[i];
- *p++ = '\0';
+ *p = 0;
+ if (print_file_each_line && !table)
+ {
+ p = scat(p, fname);
+ p = scat(p, ":");
+ }
+ p = scat(p, ar_name);
/* get and check current object's header */
- if (fread((char *)&exec_head, sizeof(exec_head),
- (size_t)1, fp) != 1) {
+ if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
(void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
(void)free(name);
return(1);
@@ -247,7 +310,7 @@ show_archive(fname, fp)
} else {
(void)fseek(fp, (long)-sizeof(exec_head),
SEEK_CUR);
- if (!print_file_each_line)
+ if (!print_file_each_line && !table)
(void)printf("\n%s:\n", name);
rval |= show_objfile(name, fp);
}
@@ -275,6 +338,7 @@ skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
* file pointer for fp is expected to be at the beginning of an a.out
* header.
*/
+int
show_objfile(objname, fp)
char *objname;
FILE *fp;
@@ -408,12 +472,32 @@ show_objfile(objname, fp)
* print_symbol()
* show one symbol
*/
+void
print_symbol(objname, sym)
char *objname;
register struct nlist *sym;
{
- char *typestring(), typeletter();
+ char *typestring();
+
+ if (table) {
+ printf("%s|", objname);
+ if (SYMBOL_TYPE(sym->n_type) != N_UNDF)
+ (void)printf("%08lx", sym->n_value);
+ (void)printf("|");
+ if (IS_DEBUGGER_SYMBOL(sym->n_type))
+ (void)printf("-|%02x %04x %5s|", sym->n_other,
+ sym->n_desc&0xffff, typestring(sym->n_type));
+ else {
+ putchar(typeletter(sym->n_type));
+ if (print_weak_symbols && SYMBOL_BIND(sym->n_other)== 2)
+ putchar('W');
+ putchar('|');
+ }
+ /* print the symbol's name */
+ (void)printf("%s\n",sym->n_un.n_name);
+ return;
+ }
if (print_file_each_line)
(void)printf("%s:", objname);
@@ -436,8 +520,17 @@ print_symbol(objname, sym)
if (IS_DEBUGGER_SYMBOL(sym->n_type))
(void)printf(" - %02x %04x %5s ", sym->n_other,
sym->n_desc&0xffff, typestring(sym->n_type));
- else
- (void)printf(" %c ", typeletter(sym->n_type));
+ else {
+ putchar(' ');
+ putchar(typeletter(sym->n_type));
+ if (print_weak_symbols) {
+ if (SYMBOL_BIND(sym->n_other) == 2)
+ putchar('W');
+ else
+ putchar(' ');
+ }
+ putchar(' ');
+ }
/* print the symbol's name */
(void)puts(sym->n_un.n_name);
@@ -516,7 +609,10 @@ typeletter(type)
case N_DATA:
return(IS_EXTERNAL(type) ? 'D' : 'd');
case N_FN:
- return(IS_EXTERNAL(type) ? 'F' : 'f');
+ /* This one is overloaded. EXT = Filename, INT = warn refs */
+ return(IS_EXTERNAL(type) ? 'F' : 'w');
+ case N_INDR:
+ return(IS_EXTERNAL(type) ? 'I' : 'i');
case N_TEXT:
return(IS_EXTERNAL(type) ? 'T' : 't');
case N_UNDF:
@@ -525,6 +621,7 @@ typeletter(type)
return('?');
}
+int
fname(a0, b0)
void *a0, *b0;
{
@@ -533,6 +630,7 @@ fname(a0, b0)
return(strcmp(a->n_un.n_name, b->n_un.n_name));
}
+int
rname(a0, b0)
void *a0, *b0;
{
@@ -541,6 +639,7 @@ rname(a0, b0)
return(strcmp(b->n_un.n_name, a->n_un.n_name));
}
+int
value(a0, b0)
void *a0, *b0;
{
@@ -571,13 +670,14 @@ emalloc(size)
char *p;
/* NOSTRICT */
- if (p = malloc(size))
+ if ( (p = malloc(size)) )
return(p);
(void)fprintf(stderr, "nm: %s\n", strerror(errno));
exit(1);
}
-usage()
+void
+usage(void)
{
(void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
exit(1);
diff --git a/usr.bin/opieinfo/Makefile b/usr.bin/opieinfo/Makefile
new file mode 100644
index 0000000..1e3f977
--- /dev/null
+++ b/usr.bin/opieinfo/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+#
+OPIE_DIST?= ${.CURDIR}/../../contrib/opie
+
+PROG= opieinfo
+SRCS= opieinfo.c
+MAN1= opieinfo.1
+
+CFLAGS+=-I${OPIE_DIST}
+
+DPADD= ${LIBOPIE} ${LIBMD}
+LDADD= -lopie -lmd
+
+.PATH: ${OPIE_DIST}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/opiekey/Makefile b/usr.bin/opiekey/Makefile
new file mode 100644
index 0000000..de04e8d
--- /dev/null
+++ b/usr.bin/opiekey/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+#
+OPIE_DIST?= ${.CURDIR}/../../contrib/opie
+
+PROG= opiekey
+SRCS= opiekey.c
+MAN1= opiekey.1
+
+CFLAGS+=-I${OPIE_DIST}
+
+DPADD= ${LIBOPIE} ${LIBMD}
+LDADD= -lopie -lmd
+
+.PATH: ${OPIE_DIST}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/opiepasswd/Makefile b/usr.bin/opiepasswd/Makefile
new file mode 100644
index 0000000..bb52c82
--- /dev/null
+++ b/usr.bin/opiepasswd/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+#
+OPIE_DIST?= ${.CURDIR}/../../contrib/opie
+
+PROG= opiepasswd
+SRCS= opiepasswd.c
+MAN1= opiepasswd.1
+
+CFLAGS+=-I${OPIE_DIST}
+
+DPADD= ${LIBOPIE} ${LIBMD}
+LDADD= -lopie -lmd
+
+.PATH: ${OPIE_DIST}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/pagesize/Makefile b/usr.bin/pagesize/Makefile
index 0a4d652..c66eae7 100644
--- a/usr.bin/pagesize/Makefile
+++ b/usr.bin/pagesize/Makefile
@@ -1,17 +1,9 @@
# @(#)Makefile 8.2 (Berkeley) 4/3/94
-MAN1= pagesize.0
+MAN1= pagesize.1
-all pagesize: ${MAN1}
-
-clean depend lint tags:
-
-cleandir:
- rm -f ${MAN1}
-
-install: maninstall
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/pagesize.sh ${DESTDIR}/${BINDIR}/pagesize
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/pagesize.sh ${DESTDIR}${BINDIR}/pagesize
.include <bsd.prog.mk>
-.include <bsd.man.mk>
diff --git a/usr.bin/pagesize/pagesize.1 b/usr.bin/pagesize/pagesize.1
index 4beec29..500f4e8 100644
--- a/usr.bin/pagesize/pagesize.1
+++ b/usr.bin/pagesize/pagesize.1
@@ -43,11 +43,11 @@
.Nm Pagesize
prints the size of a page of memory in bytes, as
returned by
-.Xr getpagesize 2 .
+.Xr getpagesize 3 .
This program is useful in constructing portable
shell scripts.
.Sh SEE ALSO
-.Xr getpagesize 2
+.Xr getpagesize 3
.Sh HISTORY
The
.Nm pagesize
diff --git a/usr.bin/pagesize/pagesize.sh b/usr.bin/pagesize/pagesize.sh
index da22179..4c7aeea 100644
--- a/usr.bin/pagesize/pagesize.sh
+++ b/usr.bin/pagesize/pagesize.sh
@@ -32,9 +32,9 @@
# SUCH DAMAGE.
#
# @(#)pagesize.sh 8.1 (Berkeley) 4/3/94
+# $Id$
#
-PATH=/bin:/usr/bin:/usr/sbin
-export PATH
+PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH
-sysctl -n hw.pagesize
+exec sysctl -n hw.pagesize
diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile
index 8681573..49c303c 100644
--- a/usr.bin/passwd/Makefile
+++ b/usr.bin/passwd/Makefile
@@ -1,15 +1,79 @@
-# @(#)Makefile 8.3 (Berkeley) 4/2/94
+# From: @(#)Makefile 8.3 (Berkeley) 4/2/94
+# $Id: Makefile,v 1.23 1997/02/22 19:56:34 peter Exp $
PROG= passwd
-SRCS= des_rw.c krb_passwd.c local_passwd.c passwd.c pw_copy.c pw_util.c
-DPADD= ${LIBKRB} ${LIBDES}
+SRCS= local_passwd.c yppasswd_private_xdr.c yppasswd_comm.c yp_passwd.c \
+ passwd.c pw_copy.c pw_util.c pw_yp.c
+
+DPADD= ${LIBCRYPT} ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lcrypt -lrpcsvc -lutil
.PATH: ${.CURDIR}/../../usr.bin/chpass ${.CURDIR}/../../usr.sbin/vipw \
- ${.CURDIR}/../rlogin
-CFLAGS+=-DKERBEROS -DCRYPT -I${.CURDIR} -I${.CURDIR}/../../usr.sbin/vipw \
- -I${.CURDIR}/../../usr.bin/chpass
-LDADD= -lkrb -ldes
+ ${.CURDIR}/../rlogin ${.CURDIR}/../../libexec/ypxfr \
+ ${.CURDIR}/../../usr.sbin/rpc.yppasswdd
+
+CFLAGS+= -DLOGIN_CAP -DCRYPT -DYP -I. -I${.CURDIR} \
+ -I${.CURDIR}/../../usr.sbin/vipw \
+ -I${.CURDIR}/../../usr.bin/chpass \
+ -I${.CURDIR}/../../libexec/ypxfr \
+ -I${.CURDIR}/../../usr.sbin/rpc.yppasswdd \
+ -Dyp_error=warnx -DLOGGING
+
+SRCS+= ypxfr_misc.c yp_clnt.c yppasswd_clnt.c
+
+CLEANFILES= yp.h yp_clnt.c yppasswd.h yppasswd_clnt.c \
+ yppasswd_private.h yppasswd_private_xdr.c
+
+RPCGEN= rpcgen -C
+RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCSRC_PW= ${DESTDIR}/usr/include/rpcsvc/yppasswd.x
+RPCSRC_PRIV= ${.CURDIR}/../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC} yp.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
+
+yppasswd.h: ${RPCSRC_PW}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_clnt.c: ${RPCSRC_PW} yppasswd.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_xdr.c: ${RPCSRC_PRIV} yppasswd_private.h
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
+
BINOWN= root
BINMODE=4555
-INSTALLFLAGS=-fschg
+MAN1=passwd.1
+LINKS=${BINDIR}/passwd ${BINDIR}/yppasswd
+MLINKS=passwd.1 yppasswd.1
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_EBONES))
+SRCS+= kpasswd.c
+.PATH: ${.CURDIR}/../../usr.bin/chpass ${.CURDIR}/../../usr.sbin/vipw \
+ ${.CURDIR}/../../usr.bin/rlogin ${.CURDIR}/../../usr.bin/passwd \
+ ${.CURDIR}/../../eBones/usr.bin/passwd
+
+CFLAGS+= -DKERBEROS \
+ -I${.CURDIR}/../../eBones/include \
+ -I${.CURDIR}/../../eBones/lib/libkadm
+# XXX not defined: ${LIBKADM}, ${LIBCOM_ERR}
+DPADD= ${LIBKADM} ${LIBKRB} ${LIBDES} ${LIBCRYPT} ${LIBRPCSVC} ${LIBCOM_ERR} ${LIBUTIL}
+LDADD= -lkadm -lkrb -ldes -lcrypt -lrpcsvc -lcom_err -lutil
+DISTRIBUTION= krb
+.endif
+
+beforeinstall:
+.for i in passwd yppasswd
+ [ ! -e ${DESTDIR}${BINDIR}/$i ] || \
+ chflags noschg ${DESTDIR}${BINDIR}/$i
+.endfor
+
+afterinstall:
+ chflags schg ${DESTDIR}${BINDIR}/passwd
.include <bsd.prog.mk>
diff --git a/usr.bin/passwd/extern.h b/usr.bin/passwd/extern.h
index 67d6dee..7a4bd12 100644
--- a/usr.bin/passwd/extern.h
+++ b/usr.bin/passwd/extern.h
@@ -30,8 +30,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)extern.h 8.1 (Berkeley) 4/2/94
+ * From: @(#)extern.h 8.1 (Berkeley) 4/2/94
+ * $Id$
*/
-int krb_passwd __P((void));
+int krb_passwd __P((char *, char *, char *, char *));
int local_passwd __P((char *));
diff --git a/usr.bin/passwd/local_passwd.c b/usr.bin/passwd/local_passwd.c
index 804c48e..5e8a4bc 100644
--- a/usr.bin/passwd/local_passwd.c
+++ b/usr.bin/passwd/local_passwd.c
@@ -29,13 +29,16 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: local_passwd.c,v 1.17 1997/05/10 19:02:38 davidn Exp $
*/
#ifndef lint
-static char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94";
+static const char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/types.h>
+#include <sys/time.h>
#include <ctype.h>
#include <err.h>
@@ -49,10 +52,25 @@ static char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94";
#include <pw_copy.h>
#include <pw_util.h>
+#ifdef YP
+#include <pw_yp.h>
+#endif
+
+#ifdef LOGGING
+#include <syslog.h>
+#endif
+
+#ifdef LOGIN_CAP
+#ifdef AUTH_NONE /* multiple defs :-( */
+#undef AUTH_NONE
+#endif
+#include <login_cap.h>
+#endif
#include "extern.h"
static uid_t uid;
+int randinit;
char *tempname;
@@ -72,14 +90,20 @@ to64(s, v, n)
}
char *
-getnewpasswd(pw)
+getnewpasswd(pw, nis)
struct passwd *pw;
+ int nis;
{
- int tries;
+ int tries, min_length = 6;
char *p, *t;
- char buf[_PASSWORD_LEN+1], salt[9];
+#ifdef LOGIN_CAP
+ login_cap_t * lc;
+#endif
+ char buf[_PASSWORD_LEN+1], salt[10];
+ struct timeval tv;
- (void)printf("Changing local password for %s.\n", pw->pw_name);
+ if (!nis)
+ (void)printf("Changing local password for %s.\n", pw->pw_name);
if (uid && pw->pw_passwd[0] &&
strcmp(crypt(getpass("Old password:"), pw->pw_passwd),
@@ -88,14 +112,34 @@ getnewpasswd(pw)
pw_error(NULL, 1, 1);
}
+#ifdef LOGIN_CAP
+ /*
+ * Determine minimum password length and next password change date.
+ * Note that even for NIS passwords, login_cap is still used.
+ */
+ if ((lc = login_getpwclass(pw)) != NULL) {
+ time_t period;
+
+ /* minpasswordlen capablity */
+ min_length = (int)login_getcapnum(lc, "minpasswordlen",
+ min_length, min_length);
+ /* passwordperiod capability */
+ period = login_getcaptime(lc, "passwordperiod", 0, 0);
+ if (period > (time_t)0) {
+ pw->pw_change = time(NULL) + period;
+ }
+ login_close(lc);
+ }
+#endif
+
for (buf[0] = '\0', tries = 0;;) {
p = getpass("New password:");
if (!*p) {
(void)printf("Password unchanged.\n");
pw_error(NULL, 0, 0);
}
- if (strlen(p) <= 5 && (uid != 0 || ++tries < 2)) {
- (void)printf("Please enter a longer password.\n");
+ if (strlen(p) < min_length && (uid != 0 || ++tries < 2)) {
+ (void)printf("Please enter a password at least %d characters in length.\n", min_length);
continue;
}
for (t = p; *t && islower(*t); ++t);
@@ -109,13 +153,32 @@ getnewpasswd(pw)
(void)printf("Mismatch; try again, EOF to quit.\n");
}
/* grab a random printable character that isn't a colon */
- (void)srandom((int)time((time_t *)NULL));
+ if (!randinit) {
+ randinit = 1;
+ srandomdev();
+ }
#ifdef NEWSALT
salt[0] = _PASSWORD_EFMT1;
to64(&salt[1], (long)(29 * 25), 4);
to64(&salt[5], random(), 4);
+ salt[9] = '\0';
#else
- to64(&salt[0], random(), 2);
+ /* Make a good size salt for algoritms that can use it. */
+ gettimeofday(&tv,0);
+ if (strncmp(pw->pw_passwd, "$1$", 3)) {
+ /* DES Salt */
+ to64(&salt[0], random(), 3);
+ to64(&salt[3], tv.tv_usec, 3);
+ to64(&salt[6], tv.tv_sec, 2);
+ salt[8] = '\0';
+ }
+ else {
+ /* MD5 Salt */
+ strncpy(&salt[0], "$1$", 3);
+ to64(&salt[3], random(), 3);
+ to64(&salt[6], tv.tv_usec, 3);
+ salt[8] = '\0';
+ }
#endif
return (crypt(buf, salt));
}
@@ -130,6 +193,10 @@ local_passwd(uname)
if (!(pw = getpwnam(uname)))
errx(1, "unknown user %s", uname);
+#ifdef YP
+ /* Use the right password information. */
+ pw = (struct passwd *)&local_password;
+#endif
uid = getuid();
if (uid && uid != pw->pw_uid)
errx(1, "%s", strerror(EACCES));
@@ -139,15 +206,20 @@ local_passwd(uname)
tfd = pw_tmp();
/*
- * Get the new password. Reset passwd change time to zero; when
- * classes are implemented, go and get the "offset" value for this
- * class and reset the timer.
+ * Get the new password. Reset passwd change time to zero by
+ * default. If the user has a valid login class (or the default
+ * fallback exists), then the next password change date is set
+ * by getnewpasswd() according to the "passwordperiod" capability
+ * if one has been specified.
*/
- pw->pw_passwd = getnewpasswd(pw);
pw->pw_change = 0;
+ pw->pw_passwd = getnewpasswd(pw, 0);
pw_copy(pfd, tfd, pw);
- if (!pw_mkdb())
+ if (!pw_mkdb(uname))
pw_error((char *)NULL, 0, 1);
+#ifdef LOGGING
+ syslog(LOG_DEBUG, "user %s changed their local password\n", uname);
+#endif
return (0);
}
diff --git a/usr.bin/passwd/passwd.1 b/usr.bin/passwd/passwd.1
index 4b07f93..a595bfa 100644
--- a/usr.bin/passwd/passwd.1
+++ b/usr.bin/passwd/passwd.1
@@ -35,22 +35,30 @@
.Dt PASSWD 1
.Os BSD 4
.Sh NAME
-.Nm passwd
+.Nm passwd, yppasswd
.Nd modify a user's password
.Sh SYNOPSIS
.Nm passwd
.Op Fl l
.Op Ar user
+.Nm yppasswd
+.Op Fl l
+.Op Fl y
+.Op Fl d Ar domain
+.Op Fl s Ar host
+.Op Fl o
.Sh DESCRIPTION
.Nm Passwd
-changes the user's Kerberos password. First, the user is prompted for their
+changes the user's local, Kerberos, or NIS password. First, the user is prompted for their
current password.
If the current password is correctly typed, a new password is
requested.
The new password must be entered twice to avoid typing errors.
.Pp
-The new password should be at least six characters long and not
-purely alphabetic.
+The new password should be at least six characters long (which
+may be overridden using the
+.Xr login.cap 5
+"minpasswordlen" setting for a user's login class) and not purely alphabetic.
Its total length must be less than
.Dv _PASSWORD_LEN
(currently 128 characters).
@@ -68,7 +76,11 @@ password file, and not with the Kerberos database.
When changing only the local password,
.Xr pwd_mkdb 8
is used to update the password databases.
+.Pp
.El
+When changing local or NIS password, the next password change date
+is set according to "passwordperiod" capability in the user's
+login class.
.Pp
To change another user's Kerberos password, one must first
run
@@ -77,6 +89,89 @@ followed by
.Xr passwd 1 .
The super-user is not required to provide a user's current password
if only the local password is modified.
+.Sh NIS INTERACTION
+.Nm Passwd
+has built-in support for NIS. If a user exists in the NIS password
+database but does not exist locally,
+.Nm passwd
+automatically switches into ``yppasswd'' mode. If the specified
+user does not exist in either the local password database of the
+NIS password maps,
+.Nm passwd
+returns an error.
+.Pp
+When changing an NIS password, unprivileged users are required to provide
+their old password for authentication (the
+.Xr rpc.yppasswdd 8
+daemon requires the original password before
+it will allow any changes to the NIS password maps).
+This restriction applies even to the
+super-user, with one important exception: the password authentication is
+bypassed for the super-user on the NIS master server. This means that
+the super-user on the NIS master server can make unrestricted changes to
+anyone's NIS password. The super-user on NIS client systems and NIS slave
+servers still needs to provide a password before the update will be processed.
+.Pp
+The following additional options are supported for use with NIS:
+.Bl -tag -width flag
+.It Fl y
+The
+.Fl y
+flag overrides
+.Nm passwd 's
+checking heuristics and forces
+it into NIS mode.
+.It Fl l
+When NIS is enabled, the
+.Fl l
+flag can be used to force
+.Nm passwd
+into ``local only'' mode. This flag can be used to change the entry
+for a local user when an NIS user exists when the same login name.
+For example, you will sometimes find entries for system ``placeholder''
+users such as
+.Pa bin
+or
+.Pa daemon
+in both the NIS password maps and the local user database. By
+default,
+.Nm passwd
+will try to change the NIS password. The
+.Fl l
+flag can be used to change the local password instead.
+.It Fl d Ar domain
+Specify what domain to use when changing an NIS password. By default,
+.Nm passwd
+assumes that the system default domain should be used. This flag is
+primarily for use by the superuser on the NIS master server: a single
+NIS server can support multiple domains. It is also possible that the
+domainname on the NIS master may not be set (it is not necessary for
+an NIS server to also be a client) in which case the
+.Nm passwd
+command needs to be told what domain to operate on.
+.It Fl s Ar host
+Specify the name of an NIS server. This option, in conjunction
+with the
+.Fl d
+option, can be used to change an NIS password on a non-local NIS
+server. When a domain is specified with the
+.Fl d
+option and
+.Nm passwd
+is unable to determine the name of the NIS master server (possibly because
+the local domainname isn't set), the name of the NIS master is assumed to
+be ``localhost''. This can be overriden with the
+.Fl s
+flag. The specified hostname need not be the name of an NIS master: the
+name of the NIS master for a given map can be determined by querying any
+NIS server (master or slave) in a domain, so specifying the name of a
+slave server will work equally well.
+.Pp
+.It Fl o
+Do not automatically override the password authentication checks for the
+super-user on the NIS master server; assume 'old' mode instead. This
+flag is of limited practical use but is useful for testing.
+.El
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/master.passwd
@@ -85,12 +180,15 @@ The user database
A Version 7 format password file
.It Pa /etc/passwd.XXXXXX
Temporary copy of the password file
+.It Pa /etc/login.conf
+Login class capabilities database
.El
.Sh SEE ALSO
.Xr chpass 1 ,
.Xr kerberos 1 ,
.Xr kinit 1 ,
.Xr login 1 ,
+.Xr login.conf 5 ,
.Xr passwd 5 ,
.Xr kpasswdd 8 ,
.Xr pwd_mkdb 8 ,
@@ -100,6 +198,11 @@ Temporary copy of the password file
.%A Ken Thompson
.%T "UNIX password security"
.Re
+.Sh NOTES
+The
+.Xr yppasswd 1
+command is really only a link to
+.Nm passwd .
.Sh HISTORY
A
.Nm passwd
diff --git a/usr.bin/passwd/passwd.c b/usr.bin/passwd/passwd.c
index 8615ab5..46562c6 100644
--- a/usr.bin/passwd/passwd.c
+++ b/usr.bin/passwd/passwd.c
@@ -29,16 +29,21 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $id$
+ *
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1988, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)passwd.c 8.3 (Berkeley) 4/2/94";
+static const char sccsid[] = "From: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
+static const char rcsid[] =
+ "$Id: passwd.c,v 1.11 1997/02/22 19:56:35 peter Exp $";
#endif /* not lint */
#include <err.h>
@@ -46,14 +51,26 @@ static char sccsid[] = "@(#)passwd.c 8.3 (Berkeley) 4/2/94";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
+
+#ifdef YP
+#include <pwd.h>
+#include <pw_yp.h>
+#include <rpcsvc/yp.h>
+int __use_yp = 0;
+int yp_errno = YP_TRUE;
+extern int yp_passwd __P(( char * ));
+#endif
+
+#ifdef KERBEROS
+#include "krb.h"
+#endif
#include "extern.h"
void usage __P((void));
-#ifdef KERBEROS
-int use_kerberos = 1;
-#endif
+int use_local_passwd = 0;
int
main(argc, argv)
@@ -62,18 +79,83 @@ main(argc, argv)
{
int ch;
char *uname;
+ char *iflag = 0, *rflag = 0, *uflag = 0;
- while ((ch = getopt(argc, argv, "l")) != EOF)
- switch (ch) {
+#ifdef YP
+#ifdef KERBEROS
+ char realm[REALM_SZ];
+#define OPTIONS "d:h:lysfoi:r:u:"
+#else
+#define OPTIONS "d:h:lysfo"
+#endif
+#else
#ifdef KERBEROS
+ char realm[REALM_SZ];
+#define OPTIONS "li:r:u:"
+#else
+#define OPTIONS "l"
+#endif
+#endif
+
+#ifdef YP
+ int res = 0;
+
+ if (strstr(argv[0], "yppasswd")) __use_yp = 1;
+#endif
+
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
+ switch (ch) {
case 'l': /* change local password file */
- use_kerberos = 0;
+ use_local_passwd = 1;
+ break;
+#ifdef KERBEROS
+ case 'i':
+ iflag = optarg;
+ break;
+ case 'r':
+ rflag = optarg;
+ break;
+ case 'u':
+ uflag = optarg;
+ break;
+#endif /* KERBEROS */
+#ifdef YP
+ case 'y': /* Change NIS password */
+ __use_yp = 1;
+ break;
+ case 'd': /* Specify NIS domain. */
+#ifdef PARANOID
+ if (!getuid()) {
+#endif
+ yp_domain = optarg;
+ if (yp_server == NULL)
+ yp_server = "localhost";
+#ifdef PARANOID
+ } else {
+ warnx("Only the super-user may use the -d flag.");
+ }
+#endif
+ break;
+ case 'h': /* Specify NIS server. */
+#ifdef PARANOID
+ if (!getuid()) {
+#endif
+ yp_server = optarg;
+#ifdef PARANOID
+ } else {
+ warnx("Only the super-user may use the -h flag.");
+ }
+#endif
+ break;
+ case 'o':
+ force_old++;
break;
#endif
default:
case '?':
usage();
}
+ }
argc -= optind;
argv += optind;
@@ -85,23 +167,53 @@ main(argc, argv)
case 0:
break;
case 1:
-#ifdef KERBEROS
- if (use_kerberos && strcmp(argv[0], uname))
- errx(1,"%s\n\t%s\n%s\n",
- "to change another user's Kerberos password, do",
- "\"kinit user; passwd; kdestroy\";",
- "to change a user's local passwd, use \"passwd -l user\"");
-#endif
uname = argv[0];
break;
default:
usage();
}
+#ifdef YP
+ /*
+ * If NIS is turned on in the password database, use it, else punt.
+ */
+#ifdef KERBEROS
+ if (__use_yp || (iflag == NULL && rflag == NULL && uflag == NULL)) {
+#endif
+ res = use_yp(uname, 0, 0);
+ if (res == USER_YP_ONLY) {
+ if (!use_local_passwd) {
+ exit(yp_passwd(uname));
+ } else {
+ /*
+ * Reject -l flag if NIS is turned on and the user
+ * doesn't exist in the local password database.
+ */
+ errx(1, "unknown local user: %s.", uname);
+ }
+ } else if (res == USER_LOCAL_ONLY) {
+ /*
+ * Reject -y flag if user only exists locally.
+ */
+ if (__use_yp)
+ errx(1, "unknown NIS user: %s.", uname);
+ } else if (res == USER_YP_AND_LOCAL) {
+ if (!use_local_passwd && (yp_in_pw_file || __use_yp))
+ exit(yp_passwd(uname));
+ }
+#ifdef KERBEROS
+ }
+#endif
+#endif
+
+ if (!use_local_passwd) {
#ifdef KERBEROS
- if (use_kerberos)
- exit(krb_passwd());
+ if(krb_get_lrealm(realm, 0) == KSUCCESS) {
+ fprintf(stderr, "realm %s\n", realm);
+ exit(krb_passwd(argv[0], iflag, rflag, uflag));
+ }
#endif
+ }
exit(local_passwd(uname));
}
@@ -109,10 +221,23 @@ void
usage()
{
+#ifdef YP
+#ifdef KERBEROS
+ fprintf(stderr,
+ "usage: passwd [-l] [-i instance] [-r realm] [-u fullname]\n");
+ fprintf(stderr,
+ " [-l] [-y] [-o] [-d domain [-h host]] [user]\n");
+#else
+ (void)fprintf(stderr, "usage: passwd [-l] [-y] [-o] [-d domain \
+[-h host]] [user] \n");
+#endif
+#else
#ifdef KERBEROS
- (void)fprintf(stderr, "usage: passwd [-l] user\n");
+ fprintf(stderr,
+ "usage: passwd [-l] [-i instance] [-r realm] [-u fullname] [user]\n");
#else
(void)fprintf(stderr, "usage: passwd user\n");
#endif
+#endif
exit(1);
}
diff --git a/usr.bin/passwd/yp_passwd.c b/usr.bin/passwd/yp_passwd.c
new file mode 100644
index 0000000..3eab43a
--- /dev/null
+++ b/usr.bin/passwd/yp_passwd.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1994 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef YP
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <pw_yp.h>
+#include "yppasswd_comm.h"
+
+extern char *getnewpasswd __P(( struct passwd * , int ));
+
+int
+yp_passwd(char *user)
+{
+ struct timeval timeout;
+ struct yppasswd yppasswd;
+ struct master_yppasswd master_yppasswd;
+ struct passwd *pw;
+ CLIENT *clnt;
+ struct rpc_err err;
+ char *master;
+ int *status = NULL;
+ uid_t uid;
+
+ _use_yp = 1;
+
+ uid = getuid();
+
+ if ((master = get_yp_master(1)) == NULL) {
+ warnx("failed to find NIS master server");
+ return(1);
+ }
+
+ /*
+ * It is presumed that by the time we get here, use_yp()
+ * has been called and that we have verified that the user
+ * actually exists. This being the case, the yp_password
+ * stucture has already been filled in for us.
+ */
+
+ /* Use the correct password */
+ pw = (struct passwd *)&yp_password;
+
+ if (pw->pw_uid != uid && uid != 0) {
+ warnx("Only the super-user may change account information \
+for other users");
+ return(1);
+ }
+
+ pw->pw_change = 0;
+
+ /* Initialize password information */
+ if (suser_override) {
+ master_yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ master_yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ master_yppasswd.newpw.pw_uid = pw->pw_uid;
+ master_yppasswd.newpw.pw_gid = pw->pw_gid;
+ master_yppasswd.newpw.pw_expire = pw->pw_expire;
+ master_yppasswd.newpw.pw_change = pw->pw_change;
+ master_yppasswd.newpw.pw_fields = pw->pw_fields;
+ master_yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ master_yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ master_yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ master_yppasswd.newpw.pw_class = pw->pw_class != NULL ?
+ strdup(pw->pw_class) : "";
+ master_yppasswd.oldpass = "";
+ master_yppasswd.domain = yp_domain;
+ } else {
+ yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ yppasswd.newpw.pw_uid = pw->pw_uid;
+ yppasswd.newpw.pw_gid = pw->pw_gid;
+ yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ yppasswd.oldpass = "";
+ }
+
+ if (suser_override)
+ printf("Changing NIS password for %s on %s in domain %s.\n",
+ pw->pw_name, master, yp_domain);
+ else
+ printf("Changing NIS password for %s on %s.\n",
+ pw->pw_name, master);
+
+ /* Get old password */
+
+ if(pw->pw_passwd[0] && !suser_override) {
+ yppasswd.oldpass = strdup(getpass("Old Password: "));
+ if (strcmp(crypt(yppasswd.oldpass, pw->pw_passwd),
+ pw->pw_passwd)) {
+ errx(1, "Sorry.");
+ }
+
+ }
+
+ if (suser_override) {
+ if ((master_yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
+ return(1);
+ } else {
+ if ((yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
+ return(1);
+ }
+
+ if (suser_override) {
+ if (senddat(&master_yppasswd)) {
+ warnx("failed to send request to rpc.yppasswdd");
+ return(1);
+ }
+ status = getresp();
+ } else {
+ if ((clnt = clnt_create(master, YPPASSWDPROG,
+ YPPASSWDVERS, "udp")) == NULL) {
+ warnx("failed to contact rpc.yppasswdd on host %s: %s",
+ master, clnt_spcreateerror(""));
+ return(1);
+ }
+ /*
+ * The yppasswd.x file said `unix authentication required',
+ * so I added it. This is the only reason it is in here.
+ * My yppasswdd doesn't use it, but maybe some others out there
+ * do. --okir
+ */
+ clnt->cl_auth = authunix_create_default();
+
+ status = yppasswdproc_update_1(&yppasswd, clnt);
+ clnt_geterr(clnt, &err);
+
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ if ((!suser_override && err.re_status != RPC_SUCCESS) ||
+ status == NULL || *status) {
+ errx(1, "Failed to change NIS password: %s",
+ (err.re_status != RPC_SUCCESS && !suser_override) ?
+ clnt_sperrno(err.re_status) :
+ "rpc.yppasswdd returned error status");
+ }
+
+ printf("\nNIS password has%s been changed on %s.\n",
+ ((err.re_status != RPC_SUCCESS && !suser_override)
+ || status == NULL || *status) ?
+ " not" : "", master);
+
+ return ((err.re_status || status == NULL || *status));
+}
+#endif /* YP */
diff --git a/usr.bin/paste/paste.c b/usr.bin/paste/paste.c
index 7f17e1d..4155855 100644
--- a/usr.bin/paste/paste.c
+++ b/usr.bin/paste/paste.c
@@ -62,7 +62,7 @@ main(argc, argv)
int ch, seq;
seq = 0;
- while ((ch = getopt(argc, argv, "d:s")) != EOF)
+ while ((ch = getopt(argc, argv, "d:s")) != -1)
switch(ch) {
case 'd':
delimcnt = tr(delim = optarg);
diff --git a/usr.bin/patch/Makefile b/usr.bin/patch/Makefile
new file mode 100644
index 0000000..d6db9f7
--- /dev/null
+++ b/usr.bin/patch/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= patch
+SRCS= patch.c pch.c inp.c version.c util.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/patch/README b/usr.bin/patch/README
new file mode 100644
index 0000000..017b1a0
--- /dev/null
+++ b/usr.bin/patch/README
@@ -0,0 +1,79 @@
+
+The Makefile and config.h files in this directory work with the current
+BSD release. Don't run the Configure script, you'll get wrong results.
+
+Keith Bostic 1/10/88
+-----------------------------------------------------------------------------
+
+ Patch Kit, Version 2.0
+
+ Copyright (c) 1986, Larry Wall
+
+You may copy the patch kit in whole or in part as long as you don't try to
+make money off it, or pretend that you wrote it.
+--------------------------------------------------------------------------
+
+Please read all the directions below before you proceed any further, and
+then follow them carefully. Failure to do so may void your warranty. :-)
+
+After you have unpacked your kit, you should have all the files listed
+in MANIFEST.
+
+Installation
+
+1) Run Configure. This will figure out various things about your system.
+ Some things Configure will figure out for itself, other things it will
+ ask you about. It will then proceed to make config.h, config.sh, and
+ Makefile.
+
+ You might possibly have to trim # comments from the front of Configure
+ if your sh doesn't handle them, but all other # comments will be taken
+ care of.
+
+ If you don't have sh, you'll have to rip the prototype of config.h out
+ of Configure and generate the defines by hand.
+
+2) Glance through config.h to make sure system dependencies are correct.
+ Most of them should have been taken care of by running the Configure script.
+
+ If you have any additional changes to make to the C definitions, they
+ can be done in the Makefile, or in config.h. Bear in mind that they may
+ get undone next time you run Configure.
+
+3) make
+
+ This will attempt to make patch in the current directory.
+
+4) make install
+
+ This will put patch into a public directory (normally /usr/local/bin).
+ It will also try to put the man pages in a reasonable place. It will not
+ nroff the man page, however.
+
+5) Read the manual entry before running patch.
+
+6) IMPORTANT! Help save the world! Communicate any problems and
+ suggested patches to me, lwall@sdcrdcf.UUCP (Larry Wall), so we can
+ keep the world in sync. If you have a problem, there's someone else
+ out there who either has had or will have the same problem.
+
+ If possible, send in patches such that the patch program will apply them.
+ Context diffs are the best, then normal diffs. Don't send ed scripts--
+ I've probably changed my copy since the version you have.
+
+ Watch for patch patches in net.sources.bugs. Patches will generally be
+ in a form usable by the patch program. If you are just now bringing up
+ patch and aren't sure how many patches there are, write to me and I'll
+ send any you don't have. Your current patch level is shown in patchlevel.h.
+
+
+NEW FEATURES IN THIS RELEASE
+
+(Correct) support for 4.3bsd-style context diffs.
+Files can be created from scratch.
+You can specify a fuzz-factor for context matching.
+You can force patch to ask no questions.
+You can specify how much of the leading pathname to strip off filenames.
+Uses a Configure script for greater portability.
+You are now asked if you want to apply a reversed patch.
+No limit (apart from memory) on the size of hunks.
diff --git a/usr.bin/patch/common.h b/usr.bin/patch/common.h
new file mode 100644
index 0000000..42d6883
--- /dev/null
+++ b/usr.bin/patch/common.h
@@ -0,0 +1,138 @@
+/* $Header: common.h,v 2.0 86/09/17 15:36:39 lwall Exp $
+ *
+ * $Log: common.h,v $
+ * Revision 2.0 86/09/17 15:36:39 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#define DEBUGGING
+
+#include "config.h"
+
+/* shut lint up about the following when return value ignored */
+
+#define Signal (void)signal
+#define Unlink (void)unlink
+#define Lseek (void)lseek
+#define Fseek (void)fseek
+#define Fstat (void)fstat
+#define Pclose (void)pclose
+#define Close (void)close
+#define Fclose (void)fclose
+#define Fflush (void)fflush
+#define Sprintf (void)sprintf
+#define Mktemp (void)mktemp
+#define Strcpy (void)strcpy
+#define Strcat (void)strcat
+
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <signal.h>
+
+/* constants */
+
+#define TRUE (1)
+#define FALSE (0)
+
+#define MAXHUNKSIZE 100000 /* is this enough lines? */
+#define INITHUNKMAX 125 /* initial dynamic allocation size */
+#define MAXLINELEN 1024
+#define BUFFERSIZE 1024
+#define ORIGEXT ".orig"
+#define SCCSPREFIX "s."
+#define GET "get -e %s"
+#define RCSSUFFIX ",v"
+#define CHECKOUT "co -l %s"
+
+/* handy definitions */
+
+#define Null(t) ((t)0)
+#define Nullch Null(char *)
+#define Nullfp Null(FILE *)
+#define Nulline Null(LINENUM)
+
+#define Ctl(ch) ((ch) & 037)
+
+#define strNE(s1,s2) (strcmp(s1, s2))
+#define strEQ(s1,s2) (!strcmp(s1, s2))
+#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
+#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
+
+/* typedefs */
+
+typedef char bool;
+typedef long LINENUM; /* must be signed */
+typedef unsigned MEM; /* what to feed malloc */
+
+/* globals */
+
+EXT int Argc; /* guess */
+EXT char **Argv;
+EXT int Argc_last; /* for restarting plan_b */
+EXT char **Argv_last;
+
+EXT struct stat filestat; /* file statistics area */
+EXT int filemode INIT(0644);
+
+EXT char buf[MAXLINELEN]; /* general purpose buffer */
+EXT FILE *ofp INIT(Nullfp); /* output file pointer */
+EXT FILE *rejfp INIT(Nullfp); /* reject file pointer */
+
+EXT bool using_plan_a INIT(TRUE); /* try to keep everything in memory */
+EXT bool out_of_mem INIT(FALSE); /* ran out of memory in plan a */
+
+#define MAXFILEC 2
+EXT int filec INIT(0); /* how many file arguments? */
+EXT char *filearg[MAXFILEC];
+EXT bool ok_to_create_file INIT(FALSE);
+EXT char *bestguess INIT(Nullch); /* guess at correct filename */
+
+EXT char *outname INIT(Nullch);
+EXT char rejname[128];
+
+EXT char *origext INIT(Nullch);
+
+EXT char TMPOUTNAME[] INIT("/tmp/patchoXXXXXX");
+EXT char TMPINNAME[] INIT("/tmp/patchiXXXXXX"); /* might want /usr/tmp here */
+EXT char TMPREJNAME[] INIT("/tmp/patchrXXXXXX");
+EXT char TMPPATNAME[] INIT("/tmp/patchpXXXXXX");
+EXT bool toutkeep INIT(FALSE);
+EXT bool trejkeep INIT(FALSE);
+
+EXT LINENUM last_offset INIT(0);
+#ifdef DEBUGGING
+EXT int debug INIT(0);
+#endif
+EXT LINENUM maxfuzz INIT(2);
+EXT bool force INIT(FALSE);
+EXT bool verbose INIT(TRUE);
+EXT bool reverse INIT(FALSE);
+EXT bool noreverse INIT(FALSE);
+EXT bool skip_rest_of_patch INIT(FALSE);
+EXT int strippath INIT(957);
+EXT bool canonicalize INIT(FALSE);
+
+#define CONTEXT_DIFF 1
+#define NORMAL_DIFF 2
+#define ED_DIFF 3
+#define NEW_CONTEXT_DIFF 4
+EXT int diff_type INIT(0);
+
+EXT bool do_defines INIT(FALSE); /* patch using ifdef, ifndef, etc. */
+EXT char if_defined[128]; /* #ifdef xyzzy */
+EXT char not_defined[128]; /* #ifndef xyzzy */
+EXT char else_defined[] INIT("#else\n");/* #else */
+EXT char end_defined[128]; /* #endif xyzzy */
+
+EXT char *revision INIT(Nullch); /* prerequisite revision, if any */
+
+char *malloc();
+char *realloc();
+char *strcpy();
+char *strcat();
+long atol();
+char *mktemp();
diff --git a/usr.bin/patch/inp.c b/usr.bin/patch/inp.c
new file mode 100644
index 0000000..a3eeb90
--- /dev/null
+++ b/usr.bin/patch/inp.c
@@ -0,0 +1,313 @@
+/* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
+ *
+ * $Log: inp.c,v $
+ * Revision 2.0 86/09/17 15:37:02 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "pch.h"
+#include "INTERN.h"
+#include "inp.h"
+
+/* Input-file-with-indexable-lines abstract type */
+
+static long i_size; /* size of the input file */
+static char *i_womp; /* plan a buffer for entire file */
+static char **i_ptr; /* pointers to lines in i_womp */
+
+static int tifd = -1; /* plan b virtual string array */
+static char *tibuf[2]; /* plan b buffers */
+static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
+static LINENUM lines_per_buf; /* how many lines per buffer */
+static int tireclen; /* length of records in tmp file */
+
+/* New patch--prepare to edit another file. */
+
+void
+re_input()
+{
+ if (using_plan_a) {
+ i_size = 0;
+#ifndef lint
+ if (i_ptr != Null(char**))
+ free((char *)i_ptr);
+#endif
+ if (i_womp != Nullch)
+ free(i_womp);
+ i_womp = Nullch;
+ i_ptr = Null(char **);
+ }
+ else {
+ using_plan_a = TRUE; /* maybe the next one is smaller */
+ Close(tifd);
+ tifd = -1;
+ free(tibuf[0]);
+ free(tibuf[1]);
+ tibuf[0] = tibuf[1] = Nullch;
+ tiline[0] = tiline[1] = -1;
+ tireclen = 0;
+ }
+}
+
+/* Constuct the line index, somehow or other. */
+
+void
+scan_input(filename)
+char *filename;
+{
+ if (!plan_a(filename))
+ plan_b(filename);
+ if (verbose) {
+ say3("Patching file %s using Plan %s...\n", filename,
+ (using_plan_a ? "A" : "B") );
+ }
+}
+
+/* Try keeping everything in memory. */
+
+bool
+plan_a(filename)
+char *filename;
+{
+ int ifd;
+ Reg1 char *s;
+ Reg2 LINENUM iline;
+
+ if (ok_to_create_file && stat(filename, &filestat) < 0) {
+ if (verbose)
+ say2("(Creating file %s...)\n",filename);
+ makedirs(filename, TRUE);
+ close(creat(filename, 0666));
+ }
+ if (stat(filename, &filestat) < 0) {
+ Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
+ if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
+ Sprintf(buf, CHECKOUT, filename);
+ if (verbose)
+ say2("Can't find %s--attempting to check it out from RCS.\n",
+ filename);
+ if (system(buf) || stat(filename, &filestat))
+ fatal2("Can't check out %s.\n", filename);
+ }
+ else {
+ Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
+ if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
+ Sprintf(buf, GET, filename);
+ if (verbose)
+ say2("Can't find %s--attempting to get it from SCCS.\n",
+ filename);
+ if (system(buf) || stat(filename, &filestat))
+ fatal2("Can't get %s.\n", filename);
+ }
+ else
+ fatal2("Can't find %s.\n", filename);
+ }
+ }
+ filemode = filestat.st_mode;
+ if ((filemode & S_IFMT) & ~S_IFREG)
+ fatal2("%s is not a normal file--can't patch.\n", filename);
+ i_size = filestat.st_size;
+ if (out_of_mem) {
+ set_hunkmax(); /* make sure dynamic arrays are allocated */
+ out_of_mem = FALSE;
+ return FALSE; /* force plan b because plan a bombed */
+ }
+#ifdef lint
+ i_womp = Nullch;
+#else
+ i_womp = malloc((MEM)(i_size+2)); /* lint says this may alloc less than */
+ /* i_size, but that's okay, I think. */
+#endif
+ if (i_womp == Nullch)
+ return FALSE;
+ if ((ifd = open(filename, 0)) < 0)
+ fatal2("Can't open file %s\n", filename);
+#ifndef lint
+ if (read(ifd, i_womp, (int)i_size) != i_size) {
+ Close(ifd); /* probably means i_size > 15 or 16 bits worth */
+ free(i_womp); /* at this point it doesn't matter if i_womp was */
+ return FALSE; /* undersized. */
+ }
+#endif
+ Close(ifd);
+ if (i_size && i_womp[i_size-1] != '\n')
+ i_womp[i_size++] = '\n';
+ i_womp[i_size] = '\0';
+
+ /* count the lines in the buffer so we know how many pointers we need */
+
+ iline = 0;
+ for (s=i_womp; *s; s++) {
+ if (*s == '\n')
+ iline++;
+ }
+#ifdef lint
+ i_ptr = Null(char**);
+#else
+ i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
+#endif
+ if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
+ free((char *)i_womp);
+ return FALSE;
+ }
+
+ /* now scan the buffer and build pointer array */
+
+ iline = 1;
+ i_ptr[iline] = i_womp;
+ for (s=i_womp; *s; s++) {
+ if (*s == '\n')
+ i_ptr[++iline] = s+1; /* these are NOT null terminated */
+ }
+ input_lines = iline - 1;
+
+ /* now check for revision, if any */
+
+ if (revision != Nullch) {
+ if (!rev_in_string(i_womp)) {
+ if (force) {
+ if (verbose)
+ say2("\
+Warning: this file doesn't appear to be the %s version--patching anyway.\n",
+ revision);
+ }
+ else {
+ ask2("\
+This file doesn't appear to be the %s version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal1("Aborted.\n");
+ }
+ }
+ else if (verbose)
+ say2("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ return TRUE; /* plan a will work */
+}
+
+/* Keep (virtually) nothing in memory. */
+
+void
+plan_b(filename)
+char *filename;
+{
+ Reg3 FILE *ifp;
+ Reg1 int i = 0;
+ Reg2 int maxlen = 1;
+ Reg4 bool found_revision = (revision == Nullch);
+
+ using_plan_a = FALSE;
+ if ((ifp = fopen(filename, "r")) == Nullfp)
+ fatal2("Can't open file %s\n", filename);
+ if ((tifd = creat(TMPINNAME, 0666)) < 0)
+ fatal2("Can't open file %s\n", TMPINNAME);
+ while (fgets(buf, sizeof buf, ifp) != Nullch) {
+ if (revision != Nullch && !found_revision && rev_in_string(buf))
+ found_revision = TRUE;
+ if ((i = strlen(buf)) > maxlen)
+ maxlen = i; /* find longest line */
+ }
+ if (revision != Nullch) {
+ if (!found_revision) {
+ if (force) {
+ if (verbose)
+ say2("\
+Warning: this file doesn't appear to be the %s version--patching anyway.\n",
+ revision);
+ }
+ else {
+ ask2("\
+This file doesn't appear to be the %s version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal1("Aborted.\n");
+ }
+ }
+ else if (verbose)
+ say2("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ Fseek(ifp, 0L, 0); /* rewind file */
+ lines_per_buf = BUFFERSIZE / maxlen;
+ tireclen = maxlen;
+ tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
+ tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
+ if (tibuf[1] == Nullch)
+ fatal1("Can't seem to get enough memory.\n");
+ for (i=1; ; i++) {
+ if (! (i % lines_per_buf)) /* new block */
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ fatal1("patch: can't write temp file.\n");
+ if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
+ == Nullch) {
+ input_lines = i - 1;
+ if (i % lines_per_buf)
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ fatal1("patch: can't write temp file.\n");
+ break;
+ }
+ }
+ Fclose(ifp);
+ Close(tifd);
+ if ((tifd = open(TMPINNAME, 0)) < 0) {
+ fatal2("Can't reopen file %s\n", TMPINNAME);
+ }
+}
+
+/* Fetch a line from the input file, \n terminated, not necessarily \0. */
+
+char *
+ifetch(line,whichbuf)
+Reg1 LINENUM line;
+int whichbuf; /* ignored when file in memory */
+{
+ if (line < 1 || line > input_lines)
+ return "";
+ if (using_plan_a)
+ return i_ptr[line];
+ else {
+ LINENUM offline = line % lines_per_buf;
+ LINENUM baseline = line - offline;
+
+ if (tiline[0] == baseline)
+ whichbuf = 0;
+ else if (tiline[1] == baseline)
+ whichbuf = 1;
+ else {
+ tiline[whichbuf] = baseline;
+#ifndef lint /* complains of long accuracy */
+ Lseek(tifd, (off_t)baseline / lines_per_buf * BUFFERSIZE, 0);
+#endif
+ if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+ fatal2("Error reading tmp file %s.\n", TMPINNAME);
+ }
+ return tibuf[whichbuf] + (tireclen*offline);
+ }
+}
+
+/* True if the string argument contains the revision number we want. */
+
+bool
+rev_in_string(string)
+char *string;
+{
+ Reg1 char *s;
+ Reg2 int patlen;
+
+ if (revision == Nullch)
+ return TRUE;
+ patlen = strlen(revision);
+ for (s = string; *s; s++) {
+ if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
+ isspace(s[patlen+1] )) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
diff --git a/usr.bin/patch/inp.h b/usr.bin/patch/inp.h
new file mode 100644
index 0000000..c6d2a91
--- /dev/null
+++ b/usr.bin/patch/inp.h
@@ -0,0 +1,18 @@
+/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
+ *
+ * $Log: inp.h,v $
+ * Revision 2.0 86/09/17 15:37:25 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT LINENUM input_lines INIT(0); /* how long is input file in lines */
+EXT LINENUM last_frozen_line INIT(0); /* how many input lines have been */
+ /* irretractibly output */
+
+bool rev_in_string();
+void scan_input();
+bool plan_a(); /* returns false if insufficient memory */
+void plan_b();
+char *ifetch();
+
diff --git a/usr.bin/patch/patch.1 b/usr.bin/patch/patch.1
new file mode 100644
index 0000000..3e4a12e
--- /dev/null
+++ b/usr.bin/patch/patch.1
@@ -0,0 +1,446 @@
+''' $Header: patch.man,v 2.0 86/09/17 15:39:09 lwall Exp $
+'''
+''' $Log: patch.man,v $
+''' Revision 2.0 86/09/17 15:39:09 lwall
+''' Baseline for netwide release.
+'''
+''' Revision 1.4 86/08/01 19:23:22 lwall
+''' Documented -v, -p, -F.
+''' Added notes to patch senders.
+'''
+''' Revision 1.3 85/03/26 15:11:06 lwall
+''' Frozen.
+'''
+''' Revision 1.2.1.4 85/03/12 16:14:27 lwall
+''' Documented -p.
+'''
+''' Revision 1.2.1.3 85/03/12 16:09:41 lwall
+''' Documented -D.
+'''
+''' Revision 1.2.1.2 84/12/05 11:06:55 lwall
+''' Added -l switch, and noted bistability bug.
+'''
+''' Revision 1.2.1.1 84/12/04 17:23:39 lwall
+''' Branch for sdcrdcf changes.
+'''
+''' Revision 1.2 84/12/04 17:22:02 lwall
+''' Baseline version.
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Bell System Logo is used as a dummy character.
+'''
+.ie n \{\
+.tr \(bs-\*(Tr
+.ds -- \(bs-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+.ds L' '
+.ds R' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds L' `
+.ds R' '
+'br\}
+.TH PATCH 1 "June 30, 1993"
+.SH NAME
+patch \- a program for applying a diff file to an original
+.SH SYNOPSIS
+.B patch
+[options] orig patchfile [+ [options] orig]
+.sp
+but usually just
+.sp
+.B patch
+<patchfile
+.SH DESCRIPTION
+.I Patch
+will take a patch file containing any of the three forms of difference
+listing produced by the
+.I diff
+program and apply those differences to an original file, producing a patched
+version.
+By default, the patched version is put in place of the original, with
+the original file backed up to the same name with the
+extension \*(L".orig\*(R", or as specified by the
+.B -b
+switch.
+You may also specify where you want the output to go with a
+.B -o
+switch.
+If
+.I patchfile
+is omitted, or is a hyphen, the patch will be read from standard input.
+.PP
+Upon startup, patch will attempt to determine the type of the diff listing,
+unless over-ruled by a
+.BR -c ,
+.BR -e ,
+or
+.B -n
+switch.
+Context diffs and normal diffs are applied by the
+.I patch
+program itself, while ed diffs are simply fed to the
+.I ed
+editor via a pipe.
+.PP
+.I Patch
+will try to skip any leading garbage, apply the diff,
+and then skip any trailing garbage.
+Thus you could feed an article or message containing a
+diff listing to
+.IR patch ,
+and it should work.
+If the entire diff is indented by a consistent amount,
+this will be taken into account.
+.PP
+With context diffs, and to a lesser extent with normal diffs,
+.I patch
+can detect when the line numbers mentioned in the patch are incorrect,
+and will attempt to find the correct place to apply each hunk of the patch.
+As a first guess, it takes the line number mentioned for the hunk, plus or
+minus any offset used in applying the previous hunk.
+If that is not the correct place,
+.I patch
+will scan both forwards and backwards for a set of lines matching the context
+given in the hunk.
+First
+.I patch
+looks for a place where all lines of the context match.
+If no such place is found, and it's a context diff, and the maximum fuzz factor
+is set to 1 or more, then another scan takes place ignoring the first and last
+line of context.
+If that fails, and the maximum fuzz factor is set to 2 or more,
+the first two and last two lines of context are ignored,
+and another scan is made.
+(The default maximum fuzz factor is 2.)
+If
+.I patch
+cannot find a place to install that hunk of the patch, it will put the
+hunk out to a reject file, which normally is the name of the output file
+plus \*(L".rej\*(R".
+(Note that the rejected hunk will come out in context diff form whether the
+input patch was a context diff or a normal diff.
+If the input was a normal diff, many of the contexts will simply be null.)
+The line numbers on the hunks in the reject file may be different than
+in the patch file: they reflect the approximate location patch thinks the
+failed hunks belong in the new file rather than the old one.
+.PP
+As each hunk is completed, you will be told whether the hunk succeeded or
+failed, and which line (in the new file)
+.I patch
+thought the hunk should go on.
+If this is different from the line number specified in the diff you will
+be told the offset.
+A single large offset MAY be an indication that a hunk was installed in the
+wrong place.
+You will also be told if a fuzz factor was used to make the match, in which
+case you should also be slightly suspicious.
+.PP
+If no original file is specified on the command line,
+.I patch
+will try to figure out from the leading garbage what the name of the file
+to edit is.
+In the header of a context diff, the filename is found from lines beginning
+with \*(L"***\*(R" or \*(L"---\*(R", with the shortest name of an existing
+file winning.
+Only context diffs have lines like that, but if there is an \*(L"Index:\*(R"
+line in the leading garbage,
+.I patch
+will try to use the filename from that line.
+The context diff header takes precedence over an Index line.
+If no filename can be intuited from the leading garbage, you will be asked
+for the name of the file to patch.
+.PP
+(If the original file cannot be found, but a suitable SCCS or RCS file is
+handy,
+.I patch
+will attempt to get or check out the file.)
+.PP
+Additionally, if the leading garbage contains a \*(L"Prereq: \*(R" line,
+.I patch
+will take the first word from the prerequisites line (normally a version
+number) and check the input file to see if that word can be found.
+If not,
+.I patch
+will ask for confirmation before proceeding.
+.PP
+The upshot of all this is that you should be able to say, while in a news
+interface, the following:
+.Sp
+ | patch -d /usr/src/local/blurfl
+.Sp
+and patch a file in the blurfl directory directly from the article containing
+the patch.
+.PP
+If the patch file contains more than one patch,
+.I patch
+will try to apply each of them as if they came from separate patch files.
+This means, among other things, that it is assumed that the name of the file
+to patch must be determined for each diff listing,
+and that the garbage before each diff listing will
+be examined for interesting things such as filenames and revision level, as
+mentioned previously.
+You can give switches (and another original file name) for the second and
+subsequent patches by separating the corresponding argument lists
+by a \*(L'+\*(R'.
+(The argument list for a second or subsequent patch may not specify a new
+patch file, however.)
+.PP
+.I Patch
+recognizes the following switches:
+.TP 5
+.B \-b
+causes the next argument to be interpreted as the backup extension, to be
+used in place of \*(L".orig\*(R".
+.TP 5
+.B \-c
+forces
+.I patch
+to interpret the patch file as a context diff.
+.TP 5
+.B \-d
+causes
+.I patch
+to interpret the next argument as a directory, and cd to it before doing
+anything else.
+.TP 5
+.B \-D
+causes
+.I patch
+to use the "#ifdef...#endif" construct to mark changes.
+The argument following will be used as the differentiating symbol.
+Note that, unlike the C compiler, there must be a space between the
+.B \-D
+and the argument.
+.TP 5
+.B \-e
+forces
+.I patch
+to interpret the patch file as an ed script.
+.TP 5
+.B \-f
+forces
+.I patch
+to assume that the user knows exactly what he or she is doing, and to not
+ask any questions.
+It does not suppress commentary, however.
+Use
+.B \-s
+for that.
+.TP 5
+.B \-F<number>
+sets the maximum fuzz factor.
+This switch only applied to context diffs, and causes
+.I patch
+to ignore up to that many lines in looking for places to install a hunk.
+Note that a larger fuzz factor increases the odds of a faulty patch.
+The default fuzz factor is 2, and it may not be set to more than
+the number of lines of context in the context diff, ordinarily 3.
+.TP 5
+.B \-l
+causes the pattern matching to be done loosely, in case the tabs and
+spaces have been munged in your input file.
+Any sequence of whitespace in the pattern line will match any sequence
+in the input file.
+Normal characters must still match exactly.
+Each line of the context must still match a line in the input file.
+.TP 5
+.B \-n
+forces
+.I patch
+to interpret the patch file as a normal diff.
+.TP 5
+.B \-N
+causes
+.I patch
+to ignore patches that it thinks are reversed or already applied.
+See also
+.B \-R .
+.TP 5
+.B \-o
+causes the next argument to be interpreted as the output file name.
+.TP 5
+.B \-p<number>
+sets the pathname strip count,
+which controls how pathnames found in the patch file are treated, in case
+the you keep your files in a different directory than the person who sent
+out the patch.
+The strip count specifies how many backslashes are to be stripped from
+the front of the pathname.
+(Any intervening directory names also go away.)
+For example, supposing the filename in the patch file was
+.sp
+ /u/howard/src/blurfl/blurfl.c
+.sp
+setting
+.B \-p
+or
+.B \-p0
+gives the entire pathname unmodified,
+.B \-p1
+gives
+.sp
+ u/howard/src/blurfl/blurfl.c
+.sp
+without the leading slash,
+.B \-p4
+gives
+.sp
+ blurfl/blurfl.c
+.sp
+and not specifying
+.B \-p
+at all just gives you "blurfl.c".
+Whatever you end up with is looked for either in the current directory,
+or the directory specified by the
+.B \-d
+switch.
+.TP 5
+.B \-r
+causes the next argument to be interpreted as the reject file name.
+.TP 5
+.B \-R
+tells
+.I patch
+that this patch was created with the old and new files swapped.
+(Yes, I'm afraid that does happen occasionally, human nature being what it
+is.)
+.I Patch
+will attempt to swap each hunk around before applying it.
+Rejects will come out in the swapped format.
+The
+.B \-R
+switch will not work with ed diff scripts because there is too little
+information to reconstruct the reverse operation.
+.Sp
+If the first hunk of a patch fails,
+.I patch
+will reverse the hunk to see if it can be applied that way.
+If it can, you will be asked if you want to have the
+.B \-R
+switch set.
+If it can't, the patch will continue to be applied normally.
+(Note: this method cannot detect a reversed patch if it is a normal diff
+and if the first command is an append (i.e. it should have been a delete)
+since appends always succeed, due to the fact that a null context will match
+anywhere.
+Luckily, most patches add or change lines rather than delete them, so most
+reversed normal diffs will begin with a delete, which will fail, triggering
+the heuristic.)
+.TP 5
+.B \-s
+makes
+.I patch
+do its work silently, unless an error occurs.
+.TP 5
+.B \-S
+causes
+.I patch
+to ignore this patch from the patch file, but continue on looking
+for the next patch in the file.
+Thus
+.sp
+ patch -S + -S + <patchfile
+.sp
+will ignore the first and second of three patches.
+.TP 5
+.B \-v
+causes
+.I patch
+to print out it's revision header and patch level.
+.TP 5
+.B \-x<number>
+sets internal debugging flags, and is of interest only to
+.I patch
+patchers.
+.SH ENVIRONMENT
+No environment variables are used by
+.IR patch .
+.SH FILES
+/tmp/patch*
+.SH SEE ALSO
+diff(1)
+.SH NOTES FOR PATCH SENDERS
+There are several things you should bear in mind if you are going to
+be sending out patches.
+First, you can save people a lot of grief by keeping a patchlevel.h file
+which is patched to increment the patch level as the first diff in the
+patch file you send out.
+If you put a Prereq: line in with the patch, it won't let them apply
+patches out of order without some warning.
+Second, make sure you've specified the filenames right, either in a
+context diff header, or with an Index: line.
+If you are patching something in a subdirectory, be sure to tell the patch
+user to specify a
+.B \-p
+switch as needed.
+Third, you can create a file by sending out a diff that compares a
+null file to the file you want to create.
+This will only work if the file you want to create doesn't exist already in
+the target directory.
+Fourth, take care not to send out reversed patches, since it makes people wonder
+whether they already applied the patch.
+Fifth, while you may be able to get away with putting 582 diff listings into
+one file, it is probably wiser to group related patches into separate files in
+case something goes haywire.
+.SH DIAGNOSTICS
+Too many to list here, but generally indicative that
+.I patch
+couldn't parse your patch file.
+.PP
+The message \*(L"Hmm...\*(R" indicates that there is unprocessed text in
+the patch file and that
+.I patch
+is attempting to intuit whether there is a patch in that text and, if so,
+what kind of patch it is.
+.SH CAVEATS
+.I Patch
+cannot tell if the line numbers are off in an ed script, and can only detect
+bad line numbers in a normal diff when it finds a \*(L"change\*(R" or
+a \*(L"delete\*(R" command.
+A context diff using fuzz factor 3 may have the same problem.
+Until a suitable interactive interface is added, you should probably do
+a context diff in these cases to see if the changes made sense.
+Of course, compiling without errors is a pretty good indication that the patch
+worked, but not always.
+.PP
+.I Patch
+usually produces the correct results, even when it has to do a lot of
+guessing.
+However, the results are guaranteed to be correct only when the patch is
+applied to exactly the same version of the file that the patch was
+generated from.
+.SH BUGS
+Could be smarter about partial matches, excessively \&deviant offsets and
+swapped code, but that would take an extra pass.
+.PP
+If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
+#endif),
+.I patch
+is incapable of patching both versions, and, if it works at all, will likely
+patch the wrong one, and tell you that it succeeded to boot.
+.PP
+If you apply a patch you've already applied,
+.I patch
+will think it is a reversed patch, and offer to un-apply the patch.
+This could be construed as a feature.
diff --git a/usr.bin/patch/patch.c b/usr.bin/patch/patch.c
new file mode 100644
index 0000000..0f91c5c
--- /dev/null
+++ b/usr.bin/patch/patch.c
@@ -0,0 +1,800 @@
+#ifndef lint
+static char sccsid[] = "@(#)patch.c 8.1 (Berkeley) 6/6/93";
+#endif not lint
+
+char rcsid[] =
+ "$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $";
+
+/* patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * This program may be copied as long as you don't try to make any
+ * money off of it, or pretend that you wrote it.
+ *
+ * $Log: patch.c,v $
+ * Revision 2.0.1.4 87/02/16 14:00:04 lwall
+ * Short replacement caused spurious "Out of sync" message.
+ *
+ * Revision 2.0.1.3 87/01/30 22:45:50 lwall
+ * Improved diagnostic on sync error.
+ * Moved do_ed_script() to pch.c.
+ *
+ * Revision 2.0.1.2 86/11/21 09:39:15 lwall
+ * Fuzz factor caused offset of installed lines.
+ *
+ * Revision 2.0.1.1 86/10/29 13:10:22 lwall
+ * Backwards search could terminate prematurely.
+ *
+ * Revision 2.0 86/09/17 15:37:32 lwall
+ * Baseline for netwide release.
+ *
+ * Revision 1.5 86/08/01 20:53:24 lwall
+ * Changed some %d's to %ld's.
+ * Linted.
+ *
+ * Revision 1.4 86/08/01 19:17:29 lwall
+ * Fixes for machines that can't vararg.
+ * Added fuzz factor.
+ * Generalized -p.
+ * General cleanup.
+ *
+ * 85/08/15 van%ucbmonet@berkeley
+ * Changes for 4.3bsd diff -c.
+ *
+ * Revision 1.3 85/03/26 15:07:43 lwall
+ * Frozen.
+ *
+ * Revision 1.2.1.9 85/03/12 17:03:35 lwall
+ * Changed pfp->_file to fileno(pfp).
+ *
+ * Revision 1.2.1.8 85/03/12 16:30:43 lwall
+ * Check i_ptr and i_womp to make sure they aren't null before freeing.
+ * Also allow ed output to be suppressed.
+ *
+ * Revision 1.2.1.7 85/03/12 15:56:13 lwall
+ * Added -p option from jromine@uci-750a.
+ *
+ * Revision 1.2.1.6 85/03/12 12:12:51 lwall
+ * Now checks for normalness of file to patch.
+ *
+ * Revision 1.2.1.5 85/03/12 11:52:12 lwall
+ * Added -D (#ifdef) option from joe@fluke.
+ *
+ * Revision 1.2.1.4 84/12/06 11:14:15 lwall
+ * Made smarter about SCCS subdirectories.
+ *
+ * Revision 1.2.1.3 84/12/05 11:18:43 lwall
+ * Added -l switch to do loose string comparison.
+ *
+ * Revision 1.2.1.2 84/12/04 09:47:13 lwall
+ * Failed hunk count not reset on multiple patch file.
+ *
+ * Revision 1.2.1.1 84/12/04 09:42:37 lwall
+ * Branch for sdcrdcf changes.
+ *
+ * Revision 1.2 84/11/29 13:29:51 lwall
+ * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
+ * multiple calls to mktemp(). Will now work on machines that can only
+ * read 32767 chars. Added -R option for diffs with new and old swapped.
+ * Various cosmetic changes.
+ *
+ * Revision 1.1 84/11/09 17:03:58 lwall
+ * Initial revision
+ *
+ */
+
+#include "INTERN.h"
+#include "common.h"
+#include "EXTERN.h"
+#include "version.h"
+#include "util.h"
+#include "pch.h"
+#include "inp.h"
+
+/* procedures */
+
+void reinitialize_almost_everything();
+void get_some_switches();
+LINENUM locate_hunk();
+void abort_hunk();
+void apply_hunk();
+void init_output();
+void init_reject();
+void copy_till();
+void spew_output();
+void dump_line();
+bool patch_match();
+bool similar();
+void re_input();
+void my_exit();
+
+/* Apply a set of diffs as appropriate. */
+
+main(argc,argv)
+int argc;
+char **argv;
+{
+ LINENUM where;
+ LINENUM newwhere;
+ LINENUM fuzz;
+ LINENUM mymaxfuzz;
+ int hunk = 0;
+ int failed = 0;
+ int i;
+
+ setbuf(stderr, serrbuf);
+ for (i = 0; i<MAXFILEC; i++)
+ filearg[i] = Nullch;
+ Mktemp(TMPOUTNAME);
+ Mktemp(TMPINNAME);
+ Mktemp(TMPREJNAME);
+ Mktemp(TMPPATNAME);
+
+ /* parse switches */
+ Argc = argc;
+ Argv = argv;
+ get_some_switches();
+
+ /* make sure we clean up /tmp in case of disaster */
+ set_signals();
+
+ for (
+ open_patch_file(filearg[1]);
+ there_is_another_patch();
+ reinitialize_almost_everything()
+ ) { /* for each patch in patch file */
+
+ if (outname == Nullch)
+ outname = savestr(filearg[0]);
+
+ /* initialize the patched file */
+ if (!skip_rest_of_patch)
+ init_output(TMPOUTNAME);
+
+ /* for ed script just up and do it and exit */
+ if (diff_type == ED_DIFF) {
+ do_ed_script();
+ continue;
+ }
+
+ /* initialize reject file */
+ init_reject(TMPREJNAME);
+
+ /* find out where all the lines are */
+ if (!skip_rest_of_patch)
+ scan_input(filearg[0]);
+
+ /* from here on, open no standard i/o files, because malloc */
+ /* might misfire and we can't catch it easily */
+
+ /* apply each hunk of patch */
+ hunk = 0;
+ failed = 0;
+ out_of_mem = FALSE;
+ while (another_hunk()) {
+ hunk++;
+ fuzz = Nulline;
+ mymaxfuzz = pch_context();
+ if (maxfuzz < mymaxfuzz)
+ mymaxfuzz = maxfuzz;
+ if (!skip_rest_of_patch) {
+ do {
+ where = locate_hunk(fuzz);
+ if (hunk == 1 && where == Nulline && !force) {
+ /* dwim for reversed patch? */
+ if (!pch_swap()) {
+ if (fuzz == Nulline)
+ say1("\
+Not enough memory to try swapped hunk! Assuming unswapped.\n");
+ continue;
+ }
+ reverse = !reverse;
+ where = locate_hunk(fuzz); /* try again */
+ if (where == Nulline) { /* didn't find it swapped */
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("Lost hunk on alloc error!\n");
+ reverse = !reverse;
+ }
+ else if (noreverse) {
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("Lost hunk on alloc error!\n");
+ reverse = !reverse;
+ say1("\
+Ignoring previously applied (or reversed) patch.\n");
+ skip_rest_of_patch = TRUE;
+ }
+ else {
+ ask3("\
+%seversed (or previously applied) patch detected! %s -R? [y] ",
+ reverse ? "R" : "Unr",
+ reverse ? "Assume" : "Ignore");
+ if (*buf == 'n') {
+ ask1("Apply anyway? [n] ");
+ if (*buf != 'y')
+ skip_rest_of_patch = TRUE;
+ where = Nulline;
+ reverse = !reverse;
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("Lost hunk on alloc error!\n");
+ }
+ }
+ }
+ } while (!skip_rest_of_patch && where == Nulline &&
+ ++fuzz <= mymaxfuzz);
+
+ if (skip_rest_of_patch) { /* just got decided */
+ Fclose(ofp);
+ ofp = Nullfp;
+ }
+ }
+
+ newwhere = pch_newfirst() + last_offset;
+ if (skip_rest_of_patch) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
+ }
+ else if (where == Nulline) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
+ }
+ else {
+ apply_hunk(where);
+ if (verbose) {
+ say3("Hunk #%d succeeded at %ld", hunk, newwhere);
+ if (fuzz)
+ say2(" with fuzz %ld", fuzz);
+ if (last_offset)
+ say3(" (offset %ld line%s)",
+ last_offset, last_offset==1L?"":"s");
+ say1(".\n");
+ }
+ }
+ }
+
+ if (out_of_mem && using_plan_a) {
+ Argc = Argc_last;
+ Argv = Argv_last;
+ say1("\n\nRan out of memory using Plan A--trying again...\n\n");
+ continue;
+ }
+
+ assert(hunk);
+
+ /* finish spewing out the new file */
+ if (!skip_rest_of_patch)
+ spew_output();
+
+ /* and put the output where desired */
+ ignore_signals();
+ if (!skip_rest_of_patch) {
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = TRUE;
+ chmod(TMPOUTNAME, filemode);
+ }
+ else
+ chmod(outname, filemode);
+ }
+ Fclose(rejfp);
+ rejfp = Nullfp;
+ if (failed) {
+ if (!*rejname) {
+ Strcpy(rejname, outname);
+ Strcat(rejname, ".rej");
+ }
+ if (skip_rest_of_patch) {
+ say4("%d out of %d hunks ignored--saving rejects to %s\n",
+ failed, hunk, rejname);
+ }
+ else {
+ say4("%d out of %d hunks failed--saving rejects to %s\n",
+ failed, hunk, rejname);
+ }
+ if (move_file(TMPREJNAME, rejname) < 0)
+ trejkeep = TRUE;
+ }
+ set_signals();
+ }
+ my_exit(0);
+}
+
+/* Prepare to find the next patch to do in the patch file. */
+
+void
+reinitialize_almost_everything()
+{
+ re_patch();
+ re_input();
+
+ input_lines = 0;
+ last_frozen_line = 0;
+
+ filec = 0;
+ if (filearg[0] != Nullch && !out_of_mem) {
+ free(filearg[0]);
+ filearg[0] = Nullch;
+ }
+
+ if (outname != Nullch) {
+ free(outname);
+ outname = Nullch;
+ }
+
+ last_offset = 0;
+
+ diff_type = 0;
+
+ if (revision != Nullch) {
+ free(revision);
+ revision = Nullch;
+ }
+
+ reverse = FALSE;
+ skip_rest_of_patch = FALSE;
+
+ get_some_switches();
+
+ if (filec >= 2)
+ fatal1("You may not change to a different patch file.\n");
+}
+
+/* Process switches and filenames up to next '+' or end of list. */
+
+void
+get_some_switches()
+{
+ Reg1 char *s;
+
+ rejname[0] = '\0';
+ Argc_last = Argc;
+ Argv_last = Argv;
+ if (!Argc)
+ return;
+ for (Argc--,Argv++; Argc; Argc--,Argv++) {
+ s = Argv[0];
+ if (strEQ(s, "+")) {
+ return; /* + will be skipped by for loop */
+ }
+ if (*s != '-' || !s[1]) {
+ if (filec == MAXFILEC)
+ fatal1("Too many file arguments.\n");
+ filearg[filec++] = savestr(s);
+ }
+ else {
+ switch (*++s) {
+ case 'b':
+ origext = savestr(Argv[1]);
+ Argc--,Argv++;
+ break;
+ case 'c':
+ diff_type = CONTEXT_DIFF;
+ break;
+ case 'd':
+ if (!*++s) {
+ Argc--,Argv++;
+ s = Argv[0];
+ }
+ if (chdir(s) < 0)
+ fatal2("Can't cd to %s.\n", s);
+ break;
+ case 'D':
+ do_defines = TRUE;
+ if (!*++s) {
+ Argc--,Argv++;
+ s = Argv[0];
+ }
+ Sprintf(if_defined, "#ifdef %s\n", s);
+ Sprintf(not_defined, "#ifndef %s\n", s);
+ Sprintf(end_defined, "#endif /* %s */\n", s);
+ break;
+ case 'e':
+ diff_type = ED_DIFF;
+ break;
+ case 'f':
+ force = TRUE;
+ break;
+ case 'F':
+ if (*++s == '=')
+ s++;
+ maxfuzz = atoi(s);
+ break;
+ case 'l':
+ canonicalize = TRUE;
+ break;
+ case 'n':
+ diff_type = NORMAL_DIFF;
+ break;
+ case 'N':
+ noreverse = TRUE;
+ break;
+ case 'o':
+ outname = savestr(Argv[1]);
+ Argc--,Argv++;
+ break;
+ case 'p':
+ if (*++s == '=')
+ s++;
+ strippath = atoi(s);
+ break;
+ case 'r':
+ Strcpy(rejname, Argv[1]);
+ Argc--,Argv++;
+ break;
+ case 'R':
+ reverse = TRUE;
+ break;
+ case 's':
+ verbose = FALSE;
+ break;
+ case 'S':
+ skip_rest_of_patch = TRUE;
+ break;
+ case 'v':
+ version();
+ break;
+#ifdef DEBUGGING
+ case 'x':
+ debug = atoi(s+1);
+ break;
+#endif
+ default:
+ fatal2("Unrecognized switch: %s\n", Argv[0]);
+ }
+ }
+ }
+}
+
+/* Attempt to find the right place to apply this hunk of patch. */
+
+LINENUM
+locate_hunk(fuzz)
+LINENUM fuzz;
+{
+ Reg1 LINENUM first_guess = pch_first() + last_offset;
+ Reg2 LINENUM offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ Reg3 LINENUM max_pos_offset = input_lines - first_guess
+ - pat_lines + 1;
+ Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
+ + pch_context();
+
+ if (!pat_lines) /* null range matches always */
+ return first_guess;
+ if (max_neg_offset >= first_guess) /* do not try lines < 0 */
+ max_neg_offset = first_guess - 1;
+ if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
+ return first_guess;
+ for (offset = 1; ; offset++) {
+ Reg5 bool check_after = (offset <= max_pos_offset);
+ Reg6 bool check_before = (offset <= max_neg_offset);
+
+ if (check_after && patch_match(first_guess, offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say3("Offset changing from %ld to %ld\n", last_offset, offset);
+#endif
+ last_offset = offset;
+ return first_guess+offset;
+ }
+ else if (check_before && patch_match(first_guess, -offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say3("Offset changing from %ld to %ld\n", last_offset, -offset);
+#endif
+ last_offset = -offset;
+ return first_guess-offset;
+ }
+ else if (!check_before && !check_after)
+ return Nulline;
+ }
+}
+
+/* We did not find the pattern, dump out the hunk so they can handle it. */
+
+void
+abort_hunk()
+{
+ Reg1 LINENUM i;
+ Reg2 LINENUM pat_end = pch_end();
+ /* add in last_offset to guess the same as the previous successful hunk */
+ LINENUM oldfirst = pch_first() + last_offset;
+ LINENUM newfirst = pch_newfirst() + last_offset;
+ LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
+ LINENUM newlast = newfirst + pch_repl_lines() - 1;
+ char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
+ char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
+
+ fprintf(rejfp, "***************\n");
+ for (i=0; i<=pat_end; i++) {
+ switch (pch_char(i)) {
+ case '*':
+ if (oldlast < oldfirst)
+ fprintf(rejfp, "*** 0%s\n", stars);
+ else if (oldlast == oldfirst)
+ fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
+ else
+ fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
+ break;
+ case '=':
+ if (newlast < newfirst)
+ fprintf(rejfp, "--- 0%s\n", minuses);
+ else if (newlast == newfirst)
+ fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
+ else
+ fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
+ break;
+ case '\n':
+ fprintf(rejfp, "%s", pfetch(i));
+ break;
+ case ' ': case '-': case '+': case '!':
+ fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
+ break;
+ default:
+ say1("Fatal internal error in abort_hunk().\n");
+ abort();
+ }
+ }
+}
+
+/* We found where to apply it (we hope), so do it. */
+
+void
+apply_hunk(where)
+LINENUM where;
+{
+ Reg1 LINENUM old = 1;
+ Reg2 LINENUM lastline = pch_ptrn_lines();
+ Reg3 LINENUM new = lastline+1;
+#define OUTSIDE 0
+#define IN_IFNDEF 1
+#define IN_IFDEF 2
+#define IN_ELSE 3
+ Reg4 int def_state = OUTSIDE;
+ Reg5 bool R_do_defines = do_defines;
+ Reg6 LINENUM pat_end = pch_end();
+
+ where--;
+ while (pch_char(new) == '=' || pch_char(new) == '\n')
+ new++;
+
+ while (old <= lastline) {
+ if (pch_char(old) == '-') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ }
+ else if (def_state == IN_IFDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ else if (new > pat_end)
+ break;
+ else if (pch_char(new) == '+') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ else if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ }
+ }
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ else {
+ if (pch_char(new) != pch_char(old)) {
+ say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
+ pch_hunk_beg() + old,
+ pch_hunk_beg() + new);
+#ifdef DEBUGGING
+ say3("oldchar = '%c', newchar = '%c'\n",
+ pch_char(old), pch_char(new));
+#endif
+ my_exit(1);
+ }
+ if (pch_char(new) == '!') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ }
+ while (pch_char(old) == '!') {
+ if (R_do_defines) {
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ if (R_do_defines) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ while (pch_char(new) == '!') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ if (R_do_defines) {
+ fputs(end_defined, ofp);
+ def_state = OUTSIDE;
+ }
+ }
+ else {
+ assert(pch_char(new) == ' ');
+ old++;
+ new++;
+ }
+ }
+ }
+ if (new <= pat_end && pch_char(new) == '+') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ }
+ else if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ }
+ while (new <= pat_end && pch_char(new) == '+') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ }
+ if (R_do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ }
+}
+
+/* Open the new file. */
+
+void
+init_output(name)
+char *name;
+{
+ ofp = fopen(name, "w");
+ if (ofp == Nullfp)
+ fatal2("patch: can't create %s.\n", name);
+}
+
+/* Open a file to put hunks we can't locate. */
+
+void
+init_reject(name)
+char *name;
+{
+ rejfp = fopen(name, "w");
+ if (rejfp == Nullfp)
+ fatal2("patch: can't create %s.\n", name);
+}
+
+/* Copy input file to output, up to wherever hunk is to be applied. */
+
+void
+copy_till(lastline)
+Reg1 LINENUM lastline;
+{
+ Reg2 LINENUM R_last_frozen_line = last_frozen_line;
+
+ if (R_last_frozen_line > lastline)
+ say1("patch: misordered hunks! output will be garbled.\n");
+ while (R_last_frozen_line < lastline) {
+ dump_line(++R_last_frozen_line);
+ }
+ last_frozen_line = R_last_frozen_line;
+}
+
+/* Finish copying the input file to the output file. */
+
+void
+spew_output()
+{
+#ifdef DEBUGGING
+ if (debug & 256)
+ say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
+#endif
+ if (input_lines)
+ copy_till(input_lines); /* dump remainder of file */
+ Fclose(ofp);
+ ofp = Nullfp;
+}
+
+/* Copy one line from input to output. */
+
+void
+dump_line(line)
+LINENUM line;
+{
+ Reg1 char *s;
+ Reg2 char R_newline = '\n';
+
+ /* Note: string is not null terminated. */
+ for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
+}
+
+/* Does the patch pattern match at line base+offset? */
+
+bool
+patch_match(base, offset, fuzz)
+LINENUM base;
+LINENUM offset;
+LINENUM fuzz;
+{
+ Reg1 LINENUM pline = 1 + fuzz;
+ Reg2 LINENUM iline;
+ Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
+
+ for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
+ if (canonicalize) {
+ if (!similar(ifetch(iline, (offset >= 0)),
+ pfetch(pline),
+ pch_line_len(pline) ))
+ return FALSE;
+ }
+ else if (strnNE(ifetch(iline, (offset >= 0)),
+ pfetch(pline),
+ pch_line_len(pline) ))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Do two lines match with canonicalized white space? */
+
+bool
+similar(a,b,len)
+Reg1 char *a;
+Reg2 char *b;
+Reg3 int len;
+{
+ while (len) {
+ if (isspace(*b)) { /* whitespace (or \n) to match? */
+ if (!isspace(*a)) /* no corresponding whitespace? */
+ return FALSE;
+ while (len && isspace(*b) && *b != '\n')
+ b++,len--; /* skip pattern whitespace */
+ while (isspace(*a) && *a != '\n')
+ a++; /* skip target whitespace */
+ if (*a == '\n' || *b == '\n')
+ return (*a == *b); /* should end in sync */
+ }
+ else if (*a++ != *b++) /* match non-whitespace chars */
+ return FALSE;
+ else
+ len--; /* probably not necessary */
+ }
+ return TRUE; /* actually, this is not reached */
+ /* since there is always a \n */
+}
+
+/* Exit with cleanup. */
+
+void
+my_exit(status)
+int status;
+{
+ Unlink(TMPINNAME);
+ if (!toutkeep) {
+ Unlink(TMPOUTNAME);
+ }
+ if (!trejkeep) {
+ Unlink(TMPREJNAME);
+ }
+ Unlink(TMPPATNAME);
+ exit(status);
+}
diff --git a/usr.bin/patch/pch.c b/usr.bin/patch/pch.c
new file mode 100644
index 0000000..8837212
--- /dev/null
+++ b/usr.bin/patch/pch.c
@@ -0,0 +1,1108 @@
+/* $Header: pch.c,v 2.0.1.6 87/06/04 16:18:13 lwall Exp $
+ *
+ * $Log: pch.c,v $
+ * Revision 2.0.1.6 87/06/04 16:18:13 lwall
+ * pch_swap didn't swap p_bfake and p_efake.
+ *
+ * Revision 2.0.1.5 87/01/30 22:47:42 lwall
+ * Improved responses to mangled patches.
+ *
+ * Revision 2.0.1.4 87/01/05 16:59:53 lwall
+ * New-style context diffs caused double call to free().
+ *
+ * Revision 2.0.1.3 86/11/14 10:08:33 lwall
+ * Fixed problem where a long pattern wouldn't grow the hunk.
+ * Also restored p_input_line when backtracking so error messages are right.
+ *
+ * Revision 2.0.1.2 86/11/03 17:49:52 lwall
+ * New-style delete triggers spurious assertion error.
+ *
+ * Revision 2.0.1.1 86/10/29 15:52:08 lwall
+ * Could falsely report new-style context diff.
+ *
+ * Revision 2.0 86/09/17 15:39:37 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "INTERN.h"
+#include "pch.h"
+
+/* Patch (diff listing) abstract type. */
+
+static long p_filesize; /* size of the patch file */
+static LINENUM p_first; /* 1st line number */
+static LINENUM p_newfirst; /* 1st line number of replacement */
+static LINENUM p_ptrn_lines; /* # lines in pattern */
+static LINENUM p_repl_lines; /* # lines in replacement text */
+static LINENUM p_end = -1; /* last line in hunk */
+static LINENUM p_max; /* max allowed value of p_end */
+static LINENUM p_context = 3; /* # of context lines */
+static LINENUM p_input_line = 0; /* current line # from patch file */
+static char **p_line = Null(char**); /* the text of the hunk */
+static short *p_len = Null(short*); /* length of each line */
+static char *p_char = Nullch; /* +, -, and ! */
+static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */
+static int p_indent; /* indent to patch */
+static LINENUM p_base; /* where to intuit this time */
+static LINENUM p_bline; /* line # of p_base */
+static LINENUM p_start; /* where intuit found a patch */
+static LINENUM p_sline; /* and the line number for it */
+static LINENUM p_hunk_beg; /* line number of current hunk */
+static LINENUM p_efake = -1; /* end of faked up lines--don't free */
+static LINENUM p_bfake = -1; /* beg of faked up lines */
+
+/* Prepare to look for the next patch in the patch file. */
+
+void
+re_patch()
+{
+ p_first = Nulline;
+ p_newfirst = Nulline;
+ p_ptrn_lines = Nulline;
+ p_repl_lines = Nulline;
+ p_end = (LINENUM)-1;
+ p_max = Nulline;
+ p_indent = 0;
+}
+
+/* Open the patch file at the beginning of time. */
+
+void
+open_patch_file(filename)
+char *filename;
+{
+ if (filename == Nullch || !*filename || strEQ(filename, "-")) {
+ pfp = fopen(TMPPATNAME, "w");
+ if (pfp == Nullfp)
+ fatal2("patch: can't create %s.\n", TMPPATNAME);
+ while (fgets(buf, sizeof buf, stdin) != Nullch)
+ fputs(buf, pfp);
+ Fclose(pfp);
+ filename = TMPPATNAME;
+ }
+ pfp = fopen(filename, "r");
+ if (pfp == Nullfp)
+ fatal2("patch file %s not found\n", filename);
+ Fstat(fileno(pfp), &filestat);
+ p_filesize = filestat.st_size;
+ next_intuit_at(0L,1L); /* start at the beginning */
+ set_hunkmax();
+}
+
+/* Make sure our dynamically realloced tables are malloced to begin with. */
+
+void
+set_hunkmax()
+{
+#ifndef lint
+ if (p_line == Null(char**))
+ p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
+ if (p_len == Null(short*))
+ p_len = (short*) malloc((MEM)hunkmax * sizeof(short));
+#endif
+ if (p_char == Nullch)
+ p_char = (char*) malloc((MEM)hunkmax * sizeof(char));
+}
+
+/* Enlarge the arrays containing the current hunk of patch. */
+
+void
+grow_hunkmax()
+{
+ hunkmax *= 2;
+ /*
+ * Note that on most systems, only the p_line array ever gets fresh memory
+ * since p_len can move into p_line's old space, and p_char can move into
+ * p_len's old space. Not on PDP-11's however. But it doesn't matter.
+ */
+ assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch);
+#ifndef lint
+ p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
+ p_len = (short*) realloc((char*)p_len, (MEM)hunkmax * sizeof(short));
+ p_char = (char*) realloc((char*)p_char, (MEM)hunkmax * sizeof(char));
+#endif
+ if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)
+ return;
+ if (!using_plan_a)
+ fatal1("patch: out of memory (grow_hunkmax)\n");
+ out_of_mem = TRUE; /* whatever is null will be allocated again */
+ /* from within plan_a(), of all places */
+}
+
+/* True if the remainder of the patch file contains a diff of some sort. */
+
+bool
+there_is_another_patch()
+{
+ if (p_base != 0L && p_base >= p_filesize) {
+ if (verbose)
+ say1("done\n");
+ return FALSE;
+ }
+ if (verbose)
+ say1("Hmm...");
+ diff_type = intuit_diff_type();
+ if (!diff_type) {
+ if (p_base != 0L) {
+ if (verbose)
+ say1(" Ignoring the trailing garbage.\ndone\n");
+ }
+ else
+ say1(" I can't seem to find a patch in there anywhere.\n");
+ return FALSE;
+ }
+ if (verbose)
+ say3(" %sooks like %s to me...\n",
+ (p_base == 0L ? "L" : "The next patch l"),
+ diff_type == CONTEXT_DIFF ? "a context diff" :
+ diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
+ diff_type == NORMAL_DIFF ? "a normal diff" :
+ "an ed script" );
+ if (p_indent && verbose)
+ say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
+ skip_to(p_start,p_sline);
+ while (filearg[0] == Nullch) {
+ if (force) {
+ say1("No file to patch. Skipping...\n");
+ filearg[0] = savestr(bestguess);
+ return TRUE;
+ }
+ ask1("File to patch: ");
+ if (*buf != '\n') {
+ if (bestguess)
+ free(bestguess);
+ bestguess = savestr(buf);
+ filearg[0] = fetchname(buf, 0, FALSE);
+ }
+ if (filearg[0] == Nullch) {
+ ask1("No file found--skip this patch? [n] ");
+ if (*buf != 'y') {
+ continue;
+ }
+ if (verbose)
+ say1("Skipping patch...\n");
+ filearg[0] = fetchname(bestguess, 0, TRUE);
+ skip_rest_of_patch = TRUE;
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
+/* Determine what kind of diff is in the remaining part of the patch file. */
+
+int
+intuit_diff_type()
+{
+ Reg4 long this_line = 0;
+ Reg5 long previous_line;
+ Reg6 long first_command_line = -1;
+ long fcl_line;
+ Reg7 bool last_line_was_command = FALSE;
+ Reg8 bool this_is_a_command = FALSE;
+ Reg9 bool stars_last_line = FALSE;
+ Reg10 bool stars_this_line = FALSE;
+ Reg3 int indent;
+ Reg1 char *s;
+ Reg2 char *t;
+ char *indtmp = Nullch;
+ char *oldtmp = Nullch;
+ char *newtmp = Nullch;
+ char *indname = Nullch;
+ char *oldname = Nullch;
+ char *newname = Nullch;
+ Reg11 int retval;
+ bool no_filearg = (filearg[0] == Nullch);
+
+ ok_to_create_file = FALSE;
+ Fseek(pfp, p_base, 0);
+ p_input_line = p_bline - 1;
+ for (;;) {
+ previous_line = this_line;
+ last_line_was_command = this_is_a_command;
+ stars_last_line = stars_this_line;
+ this_line = ftell(pfp);
+ indent = 0;
+ p_input_line++;
+ if (fgets(buf, sizeof buf, pfp) == Nullch) {
+ if (first_command_line >= 0L) {
+ /* nothing but deletes!? */
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ else {
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = 0;
+ goto scan_exit;
+ }
+ }
+ for (s = buf; *s == ' ' || *s == '\t'; s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 8);
+ else
+ indent++;
+ }
+ for (t=s; isdigit(*t) || *t == ','; t++) ;
+ this_is_a_command = (isdigit(*s) &&
+ (*t == 'd' || *t == 'c' || *t == 'a') );
+ if (first_command_line < 0L && this_is_a_command) {
+ first_command_line = this_line;
+ fcl_line = p_input_line;
+ p_indent = indent; /* assume this for now */
+ }
+ if (!stars_last_line && strnEQ(s, "*** ", 4))
+ oldtmp = savestr(s+4);
+ else if (strnEQ(s, "--- ", 4))
+ newtmp = savestr(s+4);
+ else if (strnEQ(s, "Index:", 6))
+ indtmp = savestr(s+6);
+ else if (strnEQ(s, "Prereq:", 7)) {
+ for (t=s+7; isspace(*t); t++) ;
+ revision = savestr(t);
+ for (t=revision; *t && !isspace(*t); t++) ;
+ *t = '\0';
+ if (!*revision) {
+ free(revision);
+ revision = Nullch;
+ }
+ }
+ if ((!diff_type || diff_type == ED_DIFF) &&
+ first_command_line >= 0L &&
+ strEQ(s, ".\n") ) {
+ p_indent = indent;
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ stars_this_line = strnEQ(s, "********", 8);
+ if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
+ strnEQ(s, "*** ", 4)) {
+ if (!atol(s+4))
+ ok_to_create_file = TRUE;
+ /* if this is a new context diff the character just before */
+ /* the newline is a '*'. */
+ while (*s != '\n')
+ s++;
+ p_indent = indent;
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
+ goto scan_exit;
+ }
+ if ((!diff_type || diff_type == NORMAL_DIFF) &&
+ last_line_was_command &&
+ (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ p_indent = indent;
+ retval = NORMAL_DIFF;
+ goto scan_exit;
+ }
+ }
+ scan_exit:
+ if (no_filearg) {
+ if (indtmp != Nullch)
+ indname = fetchname(indtmp, strippath, ok_to_create_file);
+ if (oldtmp != Nullch)
+ oldname = fetchname(oldtmp, strippath, ok_to_create_file);
+ if (newtmp != Nullch)
+ newname = fetchname(newtmp, strippath, ok_to_create_file);
+ if (oldname && newname) {
+ if (strlen(oldname) < strlen(newname))
+ filearg[0] = savestr(oldname);
+ else
+ filearg[0] = savestr(newname);
+ }
+ else if (oldname)
+ filearg[0] = savestr(oldname);
+ else if (newname)
+ filearg[0] = savestr(newname);
+ else if (indname)
+ filearg[0] = savestr(indname);
+ }
+ if (bestguess) {
+ free(bestguess);
+ bestguess = Nullch;
+ }
+ if (filearg[0] != Nullch)
+ bestguess = savestr(filearg[0]);
+ else if (indtmp != Nullch)
+ bestguess = fetchname(indtmp, strippath, TRUE);
+ else {
+ if (oldtmp != Nullch)
+ oldname = fetchname(oldtmp, strippath, TRUE);
+ if (newtmp != Nullch)
+ newname = fetchname(newtmp, strippath, TRUE);
+ if (oldname && newname) {
+ if (strlen(oldname) < strlen(newname))
+ bestguess = savestr(oldname);
+ else
+ bestguess = savestr(newname);
+ }
+ else if (oldname)
+ bestguess = savestr(oldname);
+ else if (newname)
+ bestguess = savestr(newname);
+ }
+ if (indtmp != Nullch)
+ free(indtmp);
+ if (oldtmp != Nullch)
+ free(oldtmp);
+ if (newtmp != Nullch)
+ free(newtmp);
+ if (indname != Nullch)
+ free(indname);
+ if (oldname != Nullch)
+ free(oldname);
+ if (newname != Nullch)
+ free(newname);
+ return retval;
+}
+
+/* Remember where this patch ends so we know where to start up again. */
+
+void
+next_intuit_at(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ p_base = file_pos;
+ p_bline = file_line;
+}
+
+/* Basically a verbose fseek() to the actual diff listing. */
+
+void
+skip_to(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ char *ret;
+
+ assert(p_base <= file_pos);
+ if (verbose && p_base < file_pos) {
+ Fseek(pfp, p_base, 0);
+ say1("The text leading up to this was:\n--------------------------\n");
+ while (ftell(pfp) < file_pos) {
+ ret = fgets(buf, sizeof buf, pfp);
+ assert(ret != Nullch);
+ say2("|%s", buf);
+ }
+ say1("--------------------------\n");
+ }
+ else
+ Fseek(pfp, file_pos, 0);
+ p_input_line = file_line - 1;
+}
+
+/* True if there is more of the current diff listing to process. */
+
+bool
+another_hunk()
+{
+ Reg1 char *s;
+ Reg8 char *ret;
+ Reg2 int context = 0;
+
+ while (p_end >= 0) {
+ if (p_end == p_efake)
+ p_end = p_bfake; /* don't free twice */
+ else
+ free(p_line[p_end]);
+ p_end--;
+ }
+ assert(p_end == -1);
+ p_efake = -1;
+
+ p_max = hunkmax; /* gets reduced when --- found */
+ if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
+ long line_beginning = ftell(pfp);
+ /* file pos of the current line */
+ LINENUM repl_beginning = 0; /* index of --- line */
+ Reg4 LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */
+ Reg5 LINENUM fillsrc; /* index of first line to copy */
+ Reg6 LINENUM filldst; /* index of first missing line */
+ bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */
+ Reg9 bool repl_could_be_missing = TRUE;
+ /* no + or ! lines in this hunk */
+ bool repl_missing = FALSE; /* we are now backtracking */
+ long repl_backtrack_position = 0;
+ /* file pos of first repl line */
+ LINENUM repl_patch_line; /* input line number for same */
+ Reg7 LINENUM ptrn_copiable = 0;
+ /* # of copiable lines in ptrn */
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || strnNE(buf, "********", 8)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ p_context = 100;
+ p_hunk_beg = p_input_line + 1;
+ while (p_end < p_max) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch) {
+ if (p_max - p_end < 4)
+ Strcpy(buf, " \n"); /* assume blank lines got chopped */
+ else {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal1("Unexpected end of file in patch.\n");
+ }
+ }
+ p_end++;
+ assert(p_end < hunkmax);
+ p_char[p_end] = *buf;
+ p_line[p_end] = Nullch;
+ switch (*buf) {
+ case '*':
+ if (strnEQ(buf, "********", 8)) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ else
+ fatal2("Unexpected end of hunk at line %ld.\n",
+ p_input_line);
+ }
+ if (p_end != 0) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal3("Unexpected *** at line %ld: %s", p_input_line, buf);
+ }
+ context = 0;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ for (s=buf; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ goto malformed;
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ goto malformed;
+ p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
+ }
+ else if (p_first)
+ p_ptrn_lines = 1;
+ else {
+ p_ptrn_lines = 0;
+ p_first = 1;
+ }
+ p_max = p_ptrn_lines + 6; /* we need this much at least */
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ p_max = hunkmax;
+ break;
+ case '-':
+ if (buf[1] == '-') {
+ if (repl_beginning ||
+ (p_end != p_ptrn_lines + 1 + (p_char[p_end-1] == '\n')))
+ {
+ if (p_end == 1) {
+ /* `old' lines were omitted - set up to fill */
+ /* them in from 'new' context lines. */
+ p_end = p_ptrn_lines + 1;
+ fillsrc = p_end + 1;
+ filldst = 1;
+ fillcnt = p_ptrn_lines;
+ }
+ else {
+ if (repl_beginning) {
+ if (repl_could_be_missing){
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal3(
+"Duplicate \"---\" at line %ld--check line numbers at line %ld.\n",
+ p_input_line, p_hunk_beg + repl_beginning);
+ }
+ else {
+ fatal4(
+"%s \"---\" at line %ld--check line numbers at line %ld.\n",
+ (p_end <= p_ptrn_lines
+ ? "Premature"
+ : "Overdue" ),
+ p_input_line, p_hunk_beg);
+ }
+ }
+ }
+ repl_beginning = p_end;
+ repl_backtrack_position = ftell(pfp);
+ repl_patch_line = p_input_line;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ p_char[p_end] = '=';
+ for (s=buf; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ goto malformed;
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ goto malformed;
+ p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
+ }
+ else if (p_newfirst)
+ p_repl_lines = 1;
+ else {
+ p_repl_lines = 0;
+ p_newfirst = 1;
+ }
+ p_max = p_repl_lines + p_end;
+ if (p_max > MAXHUNKSIZE)
+ fatal4("Hunk too large (%ld lines) at line %ld: %s",
+ p_max, p_input_line, buf);
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ if (p_repl_lines != ptrn_copiable)
+ repl_could_be_missing = FALSE;
+ break;
+ }
+ goto change_line;
+ case '+': case '!':
+ repl_could_be_missing = FALSE;
+ change_line:
+ if (!isspace(buf[1]) && buf[1] != '>' && buf[1] != '<' &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ if (context > 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ p_line[p_end] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ break;
+ case '\t': case '\n': /* assume the 2 spaces got eaten */
+ if (repl_beginning && repl_could_be_missing &&
+ (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ if (p_end != p_ptrn_lines + 1) {
+ ptrn_spaces_eaten |= (repl_beginning != 0);
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_char[p_end] = ' ';
+ }
+ break;
+ case ' ':
+ if (!isspace(buf[1]) &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_line[p_end] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ break;
+ default:
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ goto malformed;
+ }
+ /* set up p_len for strncmp() so we don't have to */
+ /* assume null termination */
+ if (p_line[p_end])
+ p_len[p_end] = strlen(p_line[p_end]);
+ else
+ p_len[p_end] = 0;
+ }
+
+ hunk_done:
+ if (p_end >=0 && !repl_beginning)
+ fatal2("No --- found in patch at line %ld\n", pch_hunk_beg());
+
+ if (repl_missing) {
+
+ /* reset state back to just after --- */
+ p_input_line = repl_patch_line;
+ for (p_end--; p_end > repl_beginning; p_end--)
+ free(p_line[p_end]);
+ Fseek(pfp, repl_backtrack_position, 0);
+
+ /* redundant 'new' context lines were omitted - set */
+ /* up to fill them in from the old file context */
+ fillsrc = 1;
+ filldst = repl_beginning+1;
+ fillcnt = p_repl_lines;
+ p_end = p_max;
+ }
+
+ if (diff_type == CONTEXT_DIFF &&
+ (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {
+ if (verbose)
+ say1("\
+(Fascinating--this is really a new-style context diff but without the telltale\n\
+extra asterisks on the *** line that usually indicate the new style...)\n");
+ diff_type = NEW_CONTEXT_DIFF;
+ }
+
+ /* if there were omitted context lines, fill them in now */
+ if (fillcnt) {
+ p_bfake = filldst; /* remember where not to free() */
+ p_efake = filldst + fillcnt - 1;
+ while (fillcnt-- > 0) {
+ while (fillsrc <= p_end && p_char[fillsrc] != ' ')
+ fillsrc++;
+ if (fillsrc > p_end)
+ fatal2("Replacement text or line numbers mangled in hunk at line %ld\n",
+ p_hunk_beg);
+ p_line[filldst] = p_line[fillsrc];
+ p_char[filldst] = p_char[fillsrc];
+ p_len[filldst] = p_len[fillsrc];
+ fillsrc++; filldst++;
+ }
+ while (fillsrc <= p_end && fillsrc != repl_beginning &&
+ p_char[fillsrc] != ' ')
+ fillsrc++;
+#ifdef DEBUGGING
+ if (debug & 64)
+ printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
+ fillsrc,filldst,repl_beginning,p_end+1);
+#endif
+ assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
+ assert(filldst==p_end+1 || filldst==repl_beginning);
+ }
+ }
+ else { /* normal diff--fake it up */
+ char hunk_type;
+ Reg3 int i;
+ LINENUM min, max;
+ long line_beginning = ftell(pfp);
+
+ p_context = 0;
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || !isdigit(*buf)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ p_first = (LINENUM)atol(buf);
+ for (s=buf; isdigit(*s); s++) ;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
+ while (isdigit(*s)) s++;
+ }
+ else
+ p_ptrn_lines = (*s != 'a');
+ hunk_type = *s;
+ if (hunk_type == 'a')
+ p_first++; /* do append rather than insert */
+ min = (LINENUM)atol(++s);
+ for (; isdigit(*s); s++) ;
+ if (*s == ',')
+ max = (LINENUM)atol(++s);
+ else
+ max = min;
+ if (hunk_type == 'd')
+ min++;
+ p_end = p_ptrn_lines + 1 + max - min + 1;
+ if (p_end > MAXHUNKSIZE)
+ fatal4("Hunk too large (%ld lines) at line %ld: %s",
+ p_end, p_input_line, buf);
+ while (p_end >= hunkmax)
+ grow_hunkmax();
+ p_newfirst = min;
+ p_repl_lines = max - min + 1;
+ Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
+ p_line[0] = savestr(buf);
+ if (out_of_mem) {
+ p_end = -1;
+ return FALSE;
+ }
+ p_char[0] = '*';
+ for (i=1; i<=p_ptrn_lines; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("Unexpected end of file in patch at line %ld.\n",
+ p_input_line);
+ if (*buf != '<')
+ fatal2("< expected at line %ld of patch.\n", p_input_line);
+ p_line[i] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '-';
+ }
+ if (hunk_type == 'c') {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("Unexpected end of file in patch at line %ld.\n",
+ p_input_line);
+ if (*buf != '-')
+ fatal2("--- expected at line %ld of patch.\n", p_input_line);
+ }
+ Sprintf(buf, "--- %ld,%ld\n", min, max);
+ p_line[i] = savestr(buf);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_char[i] = '=';
+ for (i++; i<=p_end; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("Unexpected end of file in patch at line %ld.\n",
+ p_input_line);
+ if (*buf != '>')
+ fatal2("> expected at line %ld of patch.\n", p_input_line);
+ p_line[i] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '+';
+ }
+ }
+ if (reverse) /* backwards patch? */
+ if (!pch_swap())
+ say1("Not enough memory to swap next hunk!\n");
+#ifdef DEBUGGING
+ if (debug & 2) {
+ int i;
+ char special;
+
+ for (i=0; i <= p_end; i++) {
+ if (i == p_ptrn_lines)
+ special = '^';
+ else
+ special = ' ';
+ fprintf(stderr, "%3d %c %c %s", i, p_char[i], special, p_line[i]);
+ Fflush(stderr);
+ }
+ }
+#endif
+ if (p_end+1 < hunkmax) /* paranoia reigns supreme... */
+ p_char[p_end+1] = '^'; /* add a stopper for apply_hunk */
+ return TRUE;
+
+malformed:
+ fatal3("Malformed patch at line %ld: %s", p_input_line, buf);
+ /* about as informative as "Syntax error" in C */
+ return FALSE; /* for lint */
+}
+
+/* Input a line from the patch file, worrying about indentation. */
+
+char *
+pgets(bf,sz,fp)
+char *bf;
+int sz;
+FILE *fp;
+{
+ char *ret = fgets(bf, sz, fp);
+ Reg1 char *s;
+ Reg2 int indent = 0;
+
+ if (p_indent && ret != Nullch) {
+ for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 7);
+ else
+ indent++;
+ }
+ if (buf != s)
+ Strcpy(buf, s);
+ }
+ return ret;
+}
+
+/* Reverse the old and new portions of the current hunk. */
+
+bool
+pch_swap()
+{
+ char **tp_line; /* the text of the hunk */
+ short *tp_len; /* length of each line */
+ char *tp_char; /* +, -, and ! */
+ Reg1 LINENUM i;
+ Reg2 LINENUM n;
+ bool blankline = FALSE;
+ Reg3 char *s;
+
+ i = p_first;
+ p_first = p_newfirst;
+ p_newfirst = i;
+
+ /* make a scratch copy */
+
+ tp_line = p_line;
+ tp_len = p_len;
+ tp_char = p_char;
+ p_line = Null(char**); /* force set_hunkmax to allocate again */
+ p_len = Null(short*);
+ p_char = Nullch;
+ set_hunkmax();
+ if (p_line == Null(char**) || p_len == Null(short*) || p_char == Nullch) {
+#ifndef lint
+ if (p_line == Null(char**))
+ free((char*)p_line);
+ p_line = tp_line;
+ if (p_len == Null(short*))
+ free((char*)p_len);
+ p_len = tp_len;
+#endif
+ if (p_char == Nullch)
+ free((char*)p_char);
+ p_char = tp_char;
+ return FALSE; /* not enough memory to swap hunk! */
+ }
+
+ /* now turn the new into the old */
+
+ i = p_ptrn_lines + 1;
+ if (tp_char[i] == '\n') { /* account for possible blank line */
+ blankline = TRUE;
+ i++;
+ }
+ if (p_efake >= 0) { /* fix non-freeable ptr range */
+ n = p_end - i + 1;
+ if (p_efake > i)
+ n = -n;
+ p_efake += n;
+ p_bfake += n;
+ }
+ for (n=0; i <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '+')
+ p_char[n] = '-';
+ p_len[n] = tp_len[i];
+ }
+ if (blankline) {
+ i = p_ptrn_lines + 1;
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ p_len[n] = tp_len[i];
+ n++;
+ }
+ assert(p_char[0] == '=');
+ p_char[0] = '*';
+ for (s=p_line[0]; *s; s++)
+ if (*s == '-')
+ *s = '*';
+
+ /* now turn the old into the new */
+
+ assert(tp_char[0] == '*');
+ tp_char[0] = '=';
+ for (s=tp_line[0]; *s; s++)
+ if (*s == '*')
+ *s = '-';
+ for (i=0; n <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '-')
+ p_char[n] = '+';
+ p_len[n] = tp_len[i];
+ }
+ assert(i == p_ptrn_lines + 1);
+ i = p_ptrn_lines;
+ p_ptrn_lines = p_repl_lines;
+ p_repl_lines = i;
+#ifndef lint
+ if (tp_line == Null(char**))
+ free((char*)tp_line);
+ if (tp_len == Null(short*))
+ free((char*)tp_len);
+#endif
+ if (tp_char == Nullch)
+ free((char*)tp_char);
+ return TRUE;
+}
+
+/* Return the specified line position in the old file of the old context. */
+
+LINENUM
+pch_first()
+{
+ return p_first;
+}
+
+/* Return the number of lines of old context. */
+
+LINENUM
+pch_ptrn_lines()
+{
+ return p_ptrn_lines;
+}
+
+/* Return the probable line position in the new file of the first line. */
+
+LINENUM
+pch_newfirst()
+{
+ return p_newfirst;
+}
+
+/* Return the number of lines in the replacement text including context. */
+
+LINENUM
+pch_repl_lines()
+{
+ return p_repl_lines;
+}
+
+/* Return the number of lines in the whole hunk. */
+
+LINENUM
+pch_end()
+{
+ return p_end;
+}
+
+/* Return the number of context lines before the first changed line. */
+
+LINENUM
+pch_context()
+{
+ return p_context;
+}
+
+/* Return the length of a particular patch line. */
+
+short
+pch_line_len(line)
+LINENUM line;
+{
+ return p_len[line];
+}
+
+/* Return the control character (+, -, *, !, etc) for a patch line. */
+
+char
+pch_char(line)
+LINENUM line;
+{
+ return p_char[line];
+}
+
+/* Return a pointer to a particular patch line. */
+
+char *
+pfetch(line)
+LINENUM line;
+{
+ return p_line[line];
+}
+
+/* Return where in the patch file this hunk began, for error messages. */
+
+LINENUM
+pch_hunk_beg()
+{
+ return p_hunk_beg;
+}
+
+/* Apply an ed script by feeding ed itself. */
+
+void
+do_ed_script()
+{
+ Reg1 char *t;
+ Reg2 long beginning_of_this_line;
+ Reg3 bool this_line_is_command = FALSE;
+ Reg4 FILE *pipefp;
+ FILE *popen();
+
+ if (!skip_rest_of_patch) {
+ Unlink(TMPOUTNAME);
+ copy_file(filearg[0], TMPOUTNAME);
+ if (verbose)
+ Sprintf(buf, "/bin/ed %s", TMPOUTNAME);
+ else
+ Sprintf(buf, "/bin/ed - %s", TMPOUTNAME);
+ pipefp = popen(buf, "w");
+ }
+ for (;;) {
+ beginning_of_this_line = ftell(pfp);
+ if (pgets(buf, sizeof buf, pfp) == Nullch) {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ p_input_line++;
+ for (t=buf; isdigit(*t) || *t == ','; t++) ;
+ this_line_is_command = (isdigit(*buf) &&
+ (*t == 'd' || *t == 'c' || *t == 'a') );
+ if (this_line_is_command) {
+ if (!skip_rest_of_patch)
+ fputs(buf, pipefp);
+ if (*t != 'd') {
+ while (pgets(buf, sizeof buf, pfp) != Nullch) {
+ p_input_line++;
+ if (!skip_rest_of_patch)
+ fputs(buf, pipefp);
+ if (strEQ(buf, ".\n"))
+ break;
+ }
+ }
+ }
+ else {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ }
+ if (skip_rest_of_patch)
+ return;
+ fprintf(pipefp, "w\n");
+ fprintf(pipefp, "q\n");
+ Fflush(pipefp);
+ Pclose(pipefp);
+ ignore_signals();
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = TRUE;
+ chmod(TMPOUTNAME, filemode);
+ }
+ else
+ chmod(outname, filemode);
+ set_signals();
+}
diff --git a/usr.bin/patch/pch.h b/usr.bin/patch/pch.h
new file mode 100644
index 0000000..97a5b28
--- /dev/null
+++ b/usr.bin/patch/pch.h
@@ -0,0 +1,36 @@
+/* $Header: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $
+ *
+ * $Log: pch.h,v $
+ * Revision 2.0.1.1 87/01/30 22:47:16 lwall
+ * Added do_ed_script().
+ *
+ * Revision 2.0 86/09/17 15:39:57 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT FILE *pfp INIT(Nullfp); /* patch file pointer */
+
+void re_patch();
+void open_patch_file();
+void set_hunkmax();
+void grow_hunkmax();
+bool there_is_another_patch();
+int intuit_diff_type();
+void next_intuit_at();
+void skip_to();
+bool another_hunk();
+bool pch_swap();
+char *pfetch();
+short pch_line_len();
+LINENUM pch_first();
+LINENUM pch_ptrn_lines();
+LINENUM pch_newfirst();
+LINENUM pch_repl_lines();
+LINENUM pch_end();
+LINENUM pch_context();
+LINENUM pch_hunk_beg();
+char pch_char();
+char *pfetch();
+char *pgets();
+void do_ed_script();
diff --git a/usr.bin/patch/util.c b/usr.bin/patch/util.c
new file mode 100644
index 0000000..5582d18
--- /dev/null
+++ b/usr.bin/patch/util.c
@@ -0,0 +1,339 @@
+#include "EXTERN.h"
+#include "common.h"
+#include "INTERN.h"
+#include "util.h"
+
+/* Rename a file, copying it if necessary. */
+
+int
+move_file(from,to)
+char *from, *to;
+{
+ char bakname[512];
+ Reg1 char *s;
+ Reg2 int i;
+ Reg3 int fromfd;
+
+ /* to stdout? */
+
+ if (strEQ(to, "-")) {
+#ifdef DEBUGGING
+ if (debug & 4)
+ say2("Moving %s to stdout.\n", from);
+#endif
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ fatal2("patch: internal error, can't reopen %s\n", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(1, buf, i) != 1)
+ fatal1("patch: write failed\n");
+ Close(fromfd);
+ return 0;
+ }
+
+ Strcpy(bakname, to);
+ Strcat(bakname, origext?origext:ORIGEXT);
+ if (stat(to, &filestat) >= 0) { /* output file exists */
+ dev_t to_device = filestat.st_dev;
+ ino_t to_inode = filestat.st_ino;
+ char *simplename = bakname;
+
+ for (s=bakname; *s; s++) {
+ if (*s == '/')
+ simplename = s+1;
+ }
+ /* find a backup name that is not the same file */
+ while (stat(bakname, &filestat) >= 0 &&
+ to_device == filestat.st_dev && to_inode == filestat.st_ino) {
+ for (s=simplename; *s && !islower(*s); s++) ;
+ if (*s)
+ *s = toupper(*s);
+ else
+ Strcpy(simplename, simplename+1);
+ }
+ while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", to, bakname);
+#endif
+ if (link(to, bakname) < 0) {
+ say3("patch: can't backup %s, output is in %s\n",
+ to, from);
+ return -1;
+ }
+ while (unlink(to) >= 0) ;
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", from, to);
+#endif
+ if (link(from, to) < 0) { /* different file system? */
+ Reg4 int tofd;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0) {
+ say3("patch: can't create %s, output is in %s.\n",
+ to, from);
+ return -1;
+ }
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ fatal2("patch: internal error, can't reopen %s\n", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ fatal1("patch: write failed\n");
+ Close(fromfd);
+ Close(tofd);
+ }
+ Unlink(from);
+ return 0;
+}
+
+/* Copy a file. */
+
+void
+copy_file(from,to)
+char *from, *to;
+{
+ Reg3 int tofd;
+ Reg2 int fromfd;
+ Reg1 int i;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0)
+ fatal2("patch: can't create %s.\n", to);
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ fatal2("patch: internal error, can't reopen %s\n", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ fatal2("patch: write (%s) failed\n", to);
+ Close(fromfd);
+ Close(tofd);
+}
+
+/* Allocate a unique area for a string. */
+
+char *
+savestr(s)
+Reg1 char *s;
+{
+ Reg3 char *rv;
+ Reg2 char *t;
+
+ if (!s)
+ s = "Oops";
+ t = s;
+ while (*t++);
+ rv = malloc((MEM) (t - s));
+ if (rv == Nullch) {
+ if (using_plan_a)
+ out_of_mem = TRUE;
+ else
+ fatal1("patch: out of memory (savestr)\n");
+ }
+ else {
+ t = rv;
+ while (*t++ = *s++);
+ }
+ return rv;
+}
+
+#if defined(lint) && defined(CANVARARG)
+
+/*VARARGS ARGSUSED*/
+say(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+fatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+ask(pat) char *pat; { ; }
+
+#else
+
+/* Vanilla terminal output (buffered). */
+
+void
+say(pat,arg1,arg2,arg3)
+char *pat;
+int arg1,arg2,arg3;
+{
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ Fflush(stderr);
+}
+
+/* Terminal output, pun intended. */
+
+void /* very void */
+fatal(pat,arg1,arg2,arg3)
+char *pat;
+int arg1,arg2,arg3;
+{
+ void my_exit();
+
+ say(pat, arg1, arg2, arg3);
+ my_exit(1);
+}
+
+/* Get a response from the user, somehow or other. */
+
+void
+ask(pat,arg1,arg2,arg3)
+char *pat;
+int arg1,arg2,arg3;
+{
+ int ttyfd;
+ int r;
+ bool tty2 = isatty(2);
+
+ Sprintf(buf, pat, arg1, arg2, arg3);
+ Fflush(stderr);
+ write(2, buf, strlen(buf));
+ if (tty2) { /* might be redirected to a file */
+ r = read(2, buf, sizeof buf);
+ }
+ else if (isatty(1)) { /* this may be new file output */
+ Fflush(stdout);
+ write(1, buf, strlen(buf));
+ r = read(1, buf, sizeof buf);
+ }
+ else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
+ /* might be deleted or unwriteable */
+ write(ttyfd, buf, strlen(buf));
+ r = read(ttyfd, buf, sizeof buf);
+ Close(ttyfd);
+ }
+ else if (isatty(0)) { /* this is probably patch input */
+ Fflush(stdin);
+ write(0, buf, strlen(buf));
+ r = read(0, buf, sizeof buf);
+ }
+ else { /* no terminal at all--default it */
+ buf[0] = '\n';
+ r = 1;
+ }
+ if (r <= 0)
+ buf[0] = 0;
+ else
+ buf[r] = '\0';
+ if (!tty2)
+ say1(buf);
+}
+#endif lint
+
+/* How to handle certain events when not in a critical region. */
+
+void
+set_signals()
+{
+ void my_exit();
+
+#ifndef lint
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ Signal(SIGHUP, my_exit);
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ Signal(SIGINT, my_exit);
+#endif
+}
+
+/* How to handle certain events when in a critical region. */
+
+void
+ignore_signals()
+{
+#ifndef lint
+ Signal(SIGHUP, SIG_IGN);
+ Signal(SIGINT, SIG_IGN);
+#endif
+}
+
+/* Make sure we'll have the directories to create a file. */
+
+void
+makedirs(filename,striplast)
+Reg1 char *filename;
+bool striplast;
+{
+ char tmpbuf[256];
+ Reg2 char *s = tmpbuf;
+ char *dirv[20];
+ Reg3 int i;
+ Reg4 int dirvp = 0;
+
+ while (*filename) {
+ if (*filename == '/') {
+ filename++;
+ dirv[dirvp++] = s;
+ *s++ = '\0';
+ }
+ else {
+ *s++ = *filename++;
+ }
+ }
+ *s = '\0';
+ dirv[dirvp] = s;
+ if (striplast)
+ dirvp--;
+ if (dirvp < 0)
+ return;
+ strcpy(buf, "mkdir");
+ s = buf;
+ for (i=0; i<=dirvp; i++) {
+ while (*s) s++;
+ *s++ = ' ';
+ strcpy(s, tmpbuf);
+ *dirv[i] = '/';
+ }
+ system(buf);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname(at,strip_leading,assume_exists)
+char *at;
+int strip_leading;
+int assume_exists;
+{
+ char *s;
+ char *name;
+ Reg1 char *t;
+ char tmpbuf[200];
+
+ if (!at)
+ return Nullch;
+ s = savestr(at);
+ for (t=s; isspace(*t); t++) ;
+ name = t;
+#ifdef DEBUGGING
+ if (debug & 128)
+ say4("fetchname %s %d %d\n",name,strip_leading,assume_exists);
+#endif
+ if (strnEQ(name, "/dev/null", 9)) /* so files can be created by diffing */
+ return Nullch; /* against /dev/null. */
+ for (; *t && !isspace(*t); t++)
+ if (*t == '/')
+ if (--strip_leading >= 0)
+ name = t+1;
+ *t = '\0';
+ if (name != s && *s != '/') {
+ name[-1] = '\0';
+ if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) {
+ name[-1] = '/';
+ name=s;
+ }
+ }
+ name = savestr(name);
+ Sprintf(tmpbuf, "RCS/%s", name);
+ free(s);
+ if (stat(name, &filestat) < 0 && !assume_exists) {
+ Strcat(tmpbuf, RCSSUFFIX);
+ if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) {
+ Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name);
+ if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) {
+ free(name);
+ name = Nullch;
+ }
+ }
+ }
+ return name;
+}
diff --git a/usr.bin/patch/util.h b/usr.bin/patch/util.h
new file mode 100644
index 0000000..9896c63
--- /dev/null
+++ b/usr.bin/patch/util.h
@@ -0,0 +1,74 @@
+/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
+ *
+ * $Log: util.h,v $
+ * Revision 2.0 86/09/17 15:40:06 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+/* and for those machine that can't handle a variable argument list */
+
+#ifdef CANVARARG
+
+#define say1 say
+#define say2 say
+#define say3 say
+#define say4 say
+#define ask1 ask
+#define ask2 ask
+#define ask3 ask
+#define ask4 ask
+#define fatal1 fatal
+#define fatal2 fatal
+#define fatal3 fatal
+#define fatal4 fatal
+
+#else /* hope they allow multi-line macro actual arguments */
+
+#ifdef lint
+
+#define say1(a) say(a, 0, 0, 0)
+#define say2(a,b) say(a, (b)==(b), 0, 0)
+#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0)
+#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d))
+#define ask1(a) ask(a, 0, 0, 0)
+#define ask2(a,b) ask(a, (b)==(b), 0, 0)
+#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0)
+#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d))
+#define fatal1(a) fatal(a, 0, 0, 0)
+#define fatal2(a,b) fatal(a, (b)==(b), 0, 0)
+#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0)
+#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d))
+
+#else /* lint */
+ /* if this doesn't work, try defining CANVARARG above */
+#define say1(a) say(a, Nullch, Nullch, Nullch)
+#define say2(a,b) say(a, b, Nullch, Nullch)
+#define say3(a,b,c) say(a, b, c, Nullch)
+#define say4 say
+#define ask1(a) ask(a, Nullch, Nullch, Nullch)
+#define ask2(a,b) ask(a, b, Nullch, Nullch)
+#define ask3(a,b,c) ask(a, b, c, Nullch)
+#define ask4 ask
+#define fatal1(a) fatal(a, Nullch, Nullch, Nullch)
+#define fatal2(a,b) fatal(a, b, Nullch, Nullch)
+#define fatal3(a,b,c) fatal(a, b, c, Nullch)
+#define fatal4 fatal
+
+#endif /* lint */
+
+/* if neither of the above work, join all multi-line macro calls. */
+#endif
+
+EXT char serrbuf[BUFSIZ]; /* buffer for stderr */
+
+char *fetchname();
+int move_file();
+void copy_file();
+void say();
+void fatal();
+void ask();
+char *savestr();
+void set_signals();
+void ignore_signals();
+void makedirs();
diff --git a/usr.bin/pr/pr.1 b/usr.bin/pr/pr.1
index d8d55be..88eeeed 100644
--- a/usr.bin/pr/pr.1
+++ b/usr.bin/pr/pr.1
@@ -34,6 +34,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)pr.1 8.3 (Berkeley) 4/18/94
+.\" $Id$
.\"
.Dd April 18, 1994
.Dt PR 1
@@ -345,3 +346,8 @@ The
utility is
.St -p1003.2
compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/pr/pr.c b/usr.bin/pr/pr.c
index 0c2b6f3..ed729d8 100644
--- a/usr.bin/pr/pr.c
+++ b/usr.bin/pr/pr.c
@@ -42,7 +42,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)pr.c 8.3 (Berkeley) 10/9/94";
+static char sccsid[] = "@(#)pr.c 8.2 (Berkeley) 4/16/94";
#endif /* not lint */
#include <sys/types.h>
@@ -99,7 +99,7 @@ char *timefrmt; /* time conversion string */
/*
* misc globals
*/
-FILE *errf; /* error message file pointer */
+FILE *err; /* error message file pointer */
int addone; /* page length is odd with double space */
int errcnt; /* error count on file processing */
char digs[] = "0123456789"; /* page number translation map */
@@ -429,7 +429,7 @@ vertcol(argc, argv)
if (!i) {
ptbf = buf + indy[j];
lstdat[j] = ptbf;
- } else
+ } else
ptbf = lstdat[j];
vc[cvc].pt = ptbf;
@@ -824,7 +824,7 @@ mulfile(argc, argv)
pgwd = ((colwd + 1) * clcnt) - 1;
}
if (colwd < 1) {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: page width too small for %d columns\n", clcnt);
return(1);
}
@@ -958,7 +958,7 @@ mulfile(argc, argv)
* buf: buffer
* lim: buffer length
* cps: column positon 1st char in buffer (large line support)
- * trnc: throw away data more than lim up to \n
+ * trnc: throw away data more than lim up to \n
* mor: set if more data in line (not truncated)
*/
int
@@ -1069,7 +1069,7 @@ inln(inf, buf, lim, cps, trnc, mor)
* cnt: number of chars of valid data in buf
* svips: buffer input column position (for large lines)
* svops: buffer output column position (for large lines)
- * mor: output line not complete in this buf; more data to come.
+ * mor: output line not complete in this buf; more data to come.
* 1 is more, 0 is complete, -1 is no \n's
*/
int
@@ -1277,7 +1277,7 @@ nxtfile(argc, argv, fname, buf, dt)
return(inf);
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(errf, "pr: cannot get time of day, %s\n",
+ (void)fprintf(err, "pr: cannot get time of day, %s\n",
strerror(errno));
eoptind = argc - 1;
return(NULL);
@@ -1300,7 +1300,7 @@ nxtfile(argc, argv, fname, buf, dt)
return(inf);
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
@@ -1314,7 +1314,7 @@ nxtfile(argc, argv, fname, buf, dt)
++errcnt;
if (nodiag)
continue;
- (void)fprintf(errf, "pr: Cannot open %s, %s\n",
+ (void)fprintf(err, "pr: Cannot open %s, %s\n",
argv[eoptind], strerror(errno));
continue;
}
@@ -1331,7 +1331,7 @@ nxtfile(argc, argv, fname, buf, dt)
if (dt) {
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
@@ -1341,7 +1341,7 @@ nxtfile(argc, argv, fname, buf, dt)
if (fstat(fileno(inf), &statbuf) < 0) {
++errcnt;
(void)fclose(inf);
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: Cannot stat %s, %s\n",
argv[eoptind], strerror(errno));
return(NULL);
@@ -1361,7 +1361,7 @@ nxtfile(argc, argv, fname, buf, dt)
++errcnt;
if (inf != stdin)
(void)fclose(inf);
- (void)fputs("pr: time conversion failed\n", errf);
+ (void)fputs("pr: time conversion failed\n", err);
return(NULL);
}
return(inf);
@@ -1457,16 +1457,23 @@ prtail(cnt, incomp)
/*
* only pad with no headers when incomplete last line
*/
- if (!incomp)
- return(0);
- if ((dspace && (putchar('\n') == EOF)) ||
- (putchar('\n') == EOF)) {
+ if (incomp &&
+ ((dspace && (putchar('\n') == EOF)) ||
+ (putchar('\n') == EOF))) {
pfail();
return(1);
}
+ /*
+ * but honor the formfeed request
+ */
+ if (formfeed) {
+ if (putchar('\f') == EOF) {
+ pfail();
+ return(1);
+ }
+ }
return(0);
}
-
/*
* if double space output two \n
*/
@@ -1483,13 +1490,13 @@ prtail(cnt, incomp)
* pad page
*/
if (formfeed) {
- if ((incomp && (putchar('\n') == EOF)) ||
+ if ((incomp && (putchar('\n') == EOF)) ||
(putchar('\f') == EOF)) {
pfail();
return(1);
}
return(0);
- }
+ }
cnt += TAILLEN;
while (--cnt >= 0) {
if (putchar('\n') == EOF) {
@@ -1522,41 +1529,39 @@ flsh_errs()
char buf[BUFSIZ];
(void)fflush(stdout);
- (void)fflush(errf);
- if (errf == stderr)
+ (void)fflush(err);
+ if (err == stderr)
return;
- rewind(errf);
- while (fgets(buf, BUFSIZ, errf) != NULL)
+ rewind(err);
+ while (fgets(buf, BUFSIZ, err) != NULL)
(void)fputs(buf, stderr);
}
void
mfail()
{
- (void)fputs("pr: memory allocation failed\n", errf);
+ (void)fputs("pr: memory allocation failed\n", err);
}
void
pfail()
{
- (void)fprintf(errf, "pr: write failure, %s\n", strerror(errno));
+ (void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
}
void
usage()
{
(void)fputs(
- "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",
- errf);
+ "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err);
(void)fputs(
- " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",
- errf);
+ " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
(void)fputs(
- " [-s[ch]] [-w width] [-] [file ...]\n", errf);
+ " [-s[ch]] [-w width] [-] [file ...]\n", err);
}
/*
- * setup: Validate command args, initialize and perform sanity
+ * setup: Validate command args, initialize and perform sanity
* checks on options
*/
int
@@ -1574,25 +1579,24 @@ setup(argc, argv)
/*
* defer diagnostics until processing is done
*/
- if ((errf = tmpfile()) == NULL) {
+ if ((err = tmpfile()) == NULL) {
(void)fputs("Cannot defer diagnostic messages\n",stderr);
return(1);
}
} else
- errf = stderr;
- while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != EOF) {
+ err = stderr;
+ while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != -1) {
switch (c) {
case '+':
if ((pgnm = atoi(eoptarg)) < 1) {
(void)fputs("pr: +page number must be 1 or more\n",
- errf);
+ err);
return(1);
}
break;
case '-':
if ((clcnt = atoi(eoptarg)) < 1) {
- (void)fputs("pr: -columns must be 1 or more\n",
- errf);
+ (void)fputs("pr: -columns must be 1 or more\n",err);
return(1);
}
if (clcnt > 1)
@@ -1613,13 +1617,13 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((ingap = atoi(eoptarg)) < 0) {
(void)fputs(
- "pr: -e gap must be 0 or more\n", errf);
+ "pr: -e gap must be 0 or more\n", err);
return(1);
}
if (ingap == 0)
ingap = INGAP;
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: invalid value for -e %s\n", eoptarg);
return(1);
} else
@@ -1640,13 +1644,13 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((ogap = atoi(eoptarg)) < 0) {
(void)fputs(
- "pr: -i gap must be 0 or more\n", errf);
+ "pr: -i gap must be 0 or more\n", err);
return(1);
}
if (ogap == 0)
ogap = OGAP;
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: invalid value for -i %s\n", eoptarg);
return(1);
} else
@@ -1655,7 +1659,7 @@ setup(argc, argv)
case 'l':
if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
(void)fputs(
- "pr: Number of lines must be 1 or more\n",errf);
+ "pr: Number of lines must be 1 or more\n",err);
return(1);
}
break;
@@ -1670,11 +1674,11 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((nmwd = atoi(eoptarg)) < 1) {
(void)fputs(
- "pr: -n width must be 1 or more\n",errf);
+ "pr: -n width must be 1 or more\n",err);
return(1);
}
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: invalid value for -n %s\n", eoptarg);
return(1);
} else
@@ -1683,7 +1687,7 @@ setup(argc, argv)
case 'o':
if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){
(void)fputs("pr: -o offset must be 1 or more\n",
- errf);
+ err);
return(1);
}
break;
@@ -1697,7 +1701,7 @@ setup(argc, argv)
else
schar = *eoptarg++;
if (*eoptarg != '\0') {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: invalid value for -s %s\n", eoptarg);
return(1);
}
@@ -1709,7 +1713,7 @@ setup(argc, argv)
++wflag;
if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){
(void)fputs(
- "pr: -w width must be 1 or more \n",errf);
+ "pr: -w width must be 1 or more \n",err);
return(1);
}
break;
@@ -1734,11 +1738,11 @@ setup(argc, argv)
if (across) {
if (clcnt == 1) {
(void)fputs("pr: -a flag requires multiple columns\n",
- errf);
+ err);
return(1);
}
if (merge) {
- (void)fputs("pr: -m cannot be used with -a\n", errf);
+ (void)fputs("pr: -m cannot be used with -a\n", err);
return(1);
}
}
@@ -1761,7 +1765,7 @@ setup(argc, argv)
if (cflag) {
if (merge) {
(void)fputs(
- "pr: -m cannot be used with multiple columns\n", errf);
+ "pr: -m cannot be used with multiple columns\n", err);
return(1);
}
if (nmwd) {
@@ -1772,7 +1776,7 @@ setup(argc, argv)
pgwd = ((colwd + 1) * clcnt) - 1;
}
if (colwd < 1) {
- (void)fprintf(errf,
+ (void)fprintf(err,
"pr: page width is too small for %d columns\n",clcnt);
return(1);
}
@@ -1784,7 +1788,7 @@ setup(argc, argv)
* make sure long enough for headers. if not disable
*/
if (lines <= HEADLEN + TAILLEN)
- ++nohead;
+ ++nohead;
else if (!nohead)
lines -= HEADLEN + TAILLEN;
@@ -1801,7 +1805,6 @@ setup(argc, argv)
}
}
- if ((timefrmt = getenv("LC_TIME")) == NULL)
- timefrmt = TIMEFMT;
+ timefrmt = TIMEFMT;
return(0);
}
diff --git a/usr.bin/printenv/printenv.c b/usr.bin/printenv/printenv.c
index fc40e3d..cf33837 100644
--- a/usr.bin/printenv/printenv.c
+++ b/usr.bin/printenv/printenv.c
@@ -66,7 +66,7 @@ main(argc, argv)
register size_t len;
int ch;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/printf/printf.1 b/usr.bin/printf/printf.1
index 4954158..bdf9fa2 100644
--- a/usr.bin/printf/printf.1
+++ b/usr.bin/printf/printf.1
@@ -202,7 +202,7 @@ The format characters and their meanings are:
.It Cm diouXx
The
.Ar argument
-is printed as a signed decimal (d or i), unsigned decimal, unsigned octal,
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
or unsigned hexadecimal (X or x), respectively.
.It Cm f
The
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index 82ffbda..3444c20 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -33,14 +33,14 @@
#if !defined(BUILTIN) && !defined(SHELL)
#ifndef lint
-static char copyright[] =
+static char const copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#endif
#ifndef lint
-static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
+static char const sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
#endif /* not lint */
#include <sys/types.h>
@@ -48,38 +48,30 @@ static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
#include <err.h>
#include <errno.h>
#include <limits.h>
-#ifdef SHELL
-#define EOF -1
-#else
#include <stdio.h>
-#endif
#include <stdlib.h>
#include <string.h>
-/*
- * XXX
- * This *has* to go away. TK.
- */
#ifdef SHELL
#define main printfcmd
-#define warnx(a, b, c) { \
- char buf[64]; \
- (void)sprintf(buf, sizeof(buf), a, b, c); \
- error(buf); \
-}
-#include "../../bin/sh/bltin/bltin.h"
+#include "bltin/bltin.h"
#endif
#define PF(f, func) { \
+ char *b = NULL; \
if (fieldwidth) \
if (precision) \
- (void)printf(f, fieldwidth, precision, func); \
+ (void)asprintf(&b, f, fieldwidth, precision, func); \
else \
- (void)printf(f, fieldwidth, func); \
+ (void)asprintf(&b, f, fieldwidth, func); \
else if (precision) \
- (void)printf(f, precision, func); \
+ (void)asprintf(&b, f, precision, func); \
else \
- (void)printf(f, func); \
+ (void)asprintf(&b, f, func); \
+ if (b) { \
+ (void)fputs(b, stdout); \
+ free(b); \
+ } \
}
static int asciicode __P((void));
@@ -108,7 +100,7 @@ main(argc, argv)
int ch, end, fieldwidth, precision;
char convch, nextch, *format, *fmt, *start;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch (ch) {
case '?':
default:
@@ -132,7 +124,7 @@ main(argc, argv)
* up the format string.
*/
skip1 = "#-+ 0";
- skip2 = "*0123456789";
+ skip2 = "0123456789";
escape(fmt = format = *argv); /* backslash interpretation */
gargv = ++argv;
@@ -170,21 +162,28 @@ next: for (start = fmt;; ++fmt) {
if (*fmt == '*') {
if (getint(&fieldwidth))
return (1);
- } else
+ ++fmt;
+ } else {
fieldwidth = 0;
- /* skip to possible '.', get following precision */
- for (; strchr(skip2, *fmt); ++fmt);
- if (*fmt == '.')
+ /* skip to possible '.', get following precision */
+ for (; strchr(skip2, *fmt); ++fmt);
+ }
+ if (*fmt == '.') {
+ /* precision present? */
++fmt;
- if (*fmt == '*') {
- if (getint(&precision))
- return (1);
+ if (*fmt == '*') {
+ if (getint(&precision))
+ return (1);
+ ++fmt;
+ } else {
+ precision = 0;
+
+ /* skip to conversion char */
+ for (; strchr(skip2, *fmt); ++fmt);
+ }
} else
precision = 0;
-
- /* skip to conversion char */
- for (; strchr(skip2, *fmt); ++fmt);
if (!*fmt) {
warnx("missing format character", NULL, NULL);
return (1);
@@ -211,7 +210,7 @@ next: for (start = fmt;; ++fmt) {
case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
long p;
char *f;
-
+
if ((f = mklong(start, convch)) == NULL)
return (1);
if (getlong(&p))
@@ -227,7 +226,7 @@ next: for (start = fmt;; ++fmt) {
break;
}
default:
- warnx("illegal format character", NULL, NULL);
+ warnx("illegal format character %c", convch, NULL);
return (1);
}
*fmt = nextch;
@@ -258,7 +257,7 @@ escape(fmt)
register char *store;
register int value, c;
- for (store = fmt; (c = *fmt) != '\0'; ++fmt, ++store) {
+ for (store = fmt; (c = *fmt); ++fmt, ++store) {
if (c != '\\') {
*store = c;
continue;
@@ -372,7 +371,7 @@ getlong(lp)
warnx("%s: %s", *gargv, strerror(ERANGE));
return (1);
}
-
+
*lp = val;
++gargv;
return (0);
diff --git a/usr.bin/quota/Makefile b/usr.bin/quota/Makefile
index 2ee365e..de2b4a8 100644
--- a/usr.bin/quota/Makefile
+++ b/usr.bin/quota/Makefile
@@ -4,4 +4,7 @@ PROG= quota
BINOWN= root
BINMODE=4555
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
.include <bsd.prog.mk>
diff --git a/usr.bin/quota/quota.1 b/usr.bin/quota/quota.1
index e87a3a4..b82cced 100644
--- a/usr.bin/quota/quota.1
+++ b/usr.bin/quota/quota.1
@@ -32,7 +32,8 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)quota.1 8.1 (Berkeley) 6/6/93
+.\" from: @(#)quota.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt QUOTA 1
@@ -89,7 +90,7 @@ Only the super-user may use the
flag and the optional
.Ar user
argument to view the limits of other users.
-Non-super-users can use the the
+Non-super-users can use the
.Fl g
flag and optional
.Ar group
@@ -102,7 +103,17 @@ flag takes precedence over the
flag.
.Pp
.Nm Quota
-reports the quotas of all the filesystems listed in
+tries to report the quotas of all mounted filesystems.
+If the filesystem is mounted via
+.Nm NFS ,
+it will attempt to contact the
+.Xr rpc.rquotad 8
+daemon on the
+.Nm NFS
+server.
+For
+.Nm UFS
+filesystems, quotas must be turned on in
.Pa /etc/fstab .
If
.Nm quota
@@ -128,4 +139,5 @@ command appeared in
.Xr edquota 8 ,
.Xr quotacheck 8 ,
.Xr quotaon 8 ,
-.Xr repquota 8
+.Xr repquota 8 ,
+.Xr rpc.rquotad 8
diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c
index f7fadc2..77a165c 100644
--- a/usr.bin/quota/quota.c
+++ b/usr.bin/quota/quota.c
@@ -41,25 +41,33 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95";
+static char sccsid[] = "from: @(#)quota.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Disk quota reporting program.
*/
#include <sys/param.h>
+#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
-#include <sys/queue.h>
-
+#include <sys/mount.h>
+#include <sys/socket.h>
#include <ufs/ufs/quota.h>
-
-#include <ctype.h>
-#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <fstab.h>
-#include <grp.h>
+#include <ctype.h>
+#include <string.h>
#include <pwd.h>
-#include <stdio.h>
+#include <grp.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpcsvc/rquota.h>
char *qfname = QUOTAFILENAME;
char *qfextension[] = INITQFNAMES;
@@ -69,27 +77,46 @@ struct quotause {
long flags;
struct dqblk dqblk;
char fsname[MAXPATHLEN + 1];
-} *getprivs();
+};
#define FOUND 0x01
+static char *timeprt __P((time_t seconds));
+static struct quotause *getprivs __P((long id, int quotatype));
+static void usage ();
+static void showuid(u_long uid);
+static void showgid(u_long gid);
+static int alldigits(char *s);
+static void showusrname(char *name);
+static void showgrpname(char *name);
+static void showquotas(int type, u_long id, char *name);
+static void heading(int type, u_long id, char *name, char *tag);
+static char *timeprt(time_t seconds);
+static struct quotause *getprivs(long id, int quotatype);
+static int ufshasquota(struct fstab *fs, int type, char **qfnamep);
+static int getufsquota(struct statfs *fst, struct fstab *fs,
+ struct quotause *qup, long id, int quotatype);
+static int getnfsquota(struct statfs *fst, struct fstab *fs,
+ struct quotause *qup, long id, int quotatype);
+static int callaurpc(char *host, int prognum, int versnum, int procnum,
+ xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
+static int alldigits(char *s);
+
int qflag;
int vflag;
+int
main(argc, argv)
+ int argc;
char *argv[];
{
int ngroups;
- gid_t gidset[NGROUPS];
+ gid_t mygid, gidset[NGROUPS];
int i, gflag = 0, uflag = 0;
char ch;
extern char *optarg;
extern int optind, errno;
- if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) {
- fprintf(stderr, "There are no quotas on this system\n");
- exit(0);
- }
- while ((ch = getopt(argc, argv, "ugvq")) != EOF) {
+ while ((ch = getopt(argc, argv, "ugvq")) != -1) {
switch(ch) {
case 'g':
gflag++;
@@ -115,15 +142,18 @@ main(argc, argv)
if (uflag)
showuid(getuid());
if (gflag) {
+ mygid = getgid();
ngroups = getgroups(NGROUPS, gidset);
if (ngroups < 0) {
perror("quota: getgroups");
- exit(1);
+ return(1);
}
- for (i = 1; i < ngroups; i++)
- showgid(gidset[i]);
+ showgid(mygid);
+ for (i = 0; i < ngroups; i++)
+ if (gidset[i] != mygid)
+ showgid(gidset[i]);
}
- exit(0);
+ return(0);
}
if (uflag && gflag)
usage();
@@ -134,7 +164,7 @@ main(argc, argv)
else
showusrname(*argv);
}
- exit(0);
+ return(0);
}
if (gflag) {
for (; argc > 0; argc--, argv++) {
@@ -143,10 +173,11 @@ main(argc, argv)
else
showgrpname(*argv);
}
- exit(0);
}
+ return(0);
}
+static void
usage()
{
@@ -160,6 +191,7 @@ usage()
/*
* Print out quotas for a specified user identifier.
*/
+static void
showuid(uid)
u_long uid;
{
@@ -173,7 +205,7 @@ showuid(uid)
name = pwd->pw_name;
myuid = getuid();
if (uid != myuid && myuid != 0) {
- printf("quota: %s (uid %d): permission denied\n", name, uid);
+ printf("quota: %s (uid %lu): permission denied\n", name, uid);
return;
}
showquotas(USRQUOTA, uid, name);
@@ -182,6 +214,7 @@ showuid(uid)
/*
* Print out quotas for a specifed user name.
*/
+static void
showusrname(name)
char *name;
{
@@ -194,7 +227,7 @@ showusrname(name)
}
myuid = getuid();
if (pwd->pw_uid != myuid && myuid != 0) {
- fprintf(stderr, "quota: %s (uid %d): permission denied\n",
+ fprintf(stderr, "quota: %s (uid %u): permission denied\n",
name, pwd->pw_uid);
return;
}
@@ -204,12 +237,13 @@ showusrname(name)
/*
* Print out quotas for a specified group identifier.
*/
+static void
showgid(gid)
u_long gid;
{
struct group *grp = getgrgid(gid);
int ngroups;
- gid_t gidset[NGROUPS];
+ gid_t mygid, gidset[NGROUPS];
register int i;
char *name;
@@ -217,18 +251,22 @@ showgid(gid)
name = "(no entry)";
else
name = grp->gr_name;
+ mygid = getgid();
ngroups = getgroups(NGROUPS, gidset);
if (ngroups < 0) {
perror("quota: getgroups");
return;
}
- for (i = 1; i < ngroups; i++)
- if (gid == gidset[i])
- break;
- if (i >= ngroups && getuid() != 0) {
- fprintf(stderr, "quota: %s (gid %d): permission denied\n",
- name, gid);
- return;
+ if (gid != mygid) {
+ for (i = 0; i < ngroups; i++)
+ if (gid == gidset[i])
+ break;
+ if (i >= ngroups && getuid() != 0) {
+ fprintf(stderr,
+ "quota: %s (gid %lu): permission denied\n",
+ name, gid);
+ return;
+ }
}
showquotas(GRPQUOTA, gid, name);
}
@@ -236,44 +274,49 @@ showgid(gid)
/*
* Print out quotas for a specifed group name.
*/
+static void
showgrpname(name)
char *name;
{
struct group *grp = getgrnam(name);
int ngroups;
- gid_t gidset[NGROUPS];
+ gid_t mygid, gidset[NGROUPS];
register int i;
if (grp == NULL) {
fprintf(stderr, "quota: %s: unknown group\n", name);
return;
}
+ mygid = getgid();
ngroups = getgroups(NGROUPS, gidset);
if (ngroups < 0) {
perror("quota: getgroups");
return;
}
- for (i = 1; i < ngroups; i++)
- if (grp->gr_gid == gidset[i])
- break;
- if (i >= ngroups && getuid() != 0) {
- fprintf(stderr, "quota: %s (gid %d): permission denied\n",
- name, grp->gr_gid);
- return;
+ if (grp->gr_gid != mygid) {
+ for (i = 0; i < ngroups; i++)
+ if (grp->gr_gid == gidset[i])
+ break;
+ if (i >= ngroups && getuid() != 0) {
+ fprintf(stderr,
+ "quota: %s (gid %u): permission denied\n",
+ name, grp->gr_gid);
+ return;
+ }
}
showquotas(GRPQUOTA, grp->gr_gid, name);
}
+static void
showquotas(type, id, name)
int type;
u_long id;
char *name;
{
register struct quotause *qup;
- struct quotause *quplist, *getprivs();
- char *msgi, *msgb, *timeprt();
- int myuid, fd, lines = 0;
- static int first;
+ struct quotause *quplist;
+ char *msgi, *msgb, *nam;
+ int lines = 0;
static time_t now;
if (now == 0)
@@ -321,15 +364,23 @@ showquotas(type, id, name)
qup->dqblk.dqb_curinodes) {
if (lines++ == 0)
heading(type, id, name, "");
- printf("%15s%8d%c%7d%8d%8s"
- , qup->fsname
- , dbtob(qup->dqblk.dqb_curblocks) / 1024
+ nam = qup->fsname;
+ if (strlen(qup->fsname) > 15) {
+ printf("%s\n", qup->fsname);
+ nam = "";
+ }
+ printf("%15s%8lu%c%7lu%8lu%8s"
+ , nam
+ , (u_long) (dbtob(qup->dqblk.dqb_curblocks)
+ / 1024)
, (msgb == (char *)0) ? ' ' : '*'
- , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024
- , dbtob(qup->dqblk.dqb_bhardlimit) / 1024
+ , (u_long) (dbtob(qup->dqblk.dqb_bsoftlimit)
+ / 1024)
+ , (u_long) (dbtob(qup->dqblk.dqb_bhardlimit)
+ / 1024)
, (msgb == (char *)0) ? ""
- : timeprt(qup->dqblk.dqb_btime));
- printf("%8d%c%7d%8d%8s\n"
+ :timeprt(qup->dqblk.dqb_btime));
+ printf("%8lu%c%7lu%8lu%8s\n"
, qup->dqblk.dqb_curinodes
, (msgi == (char *)0) ? ' ' : '*'
, qup->dqblk.dqb_isoftlimit
@@ -344,13 +395,14 @@ showquotas(type, id, name)
heading(type, id, name, "none");
}
+static void
heading(type, id, name, tag)
int type;
u_long id;
char *name, *tag;
{
- printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type],
+ printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type],
name, *qfextension[type], id, tag);
if (!qflag && tag[0] == '\0') {
printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
@@ -370,7 +422,7 @@ heading(type, id, name, tag)
/*
* Calculate the grace period and return a printable string for it.
*/
-char *
+static char *
timeprt(seconds)
time_t seconds;
{
@@ -386,80 +438,77 @@ timeprt(seconds)
minutes = (seconds + 30) / 60;
hours = (minutes + 30) / 60;
if (hours >= 36) {
- sprintf(buf, "%ddays", (hours + 12) / 24);
+ sprintf(buf, "%lddays", (hours + 12) / 24);
return (buf);
}
if (minutes >= 60) {
- sprintf(buf, "%2d:%d", minutes / 60, minutes % 60);
+ sprintf(buf, "%2ld:%ld", minutes / 60, minutes % 60);
return (buf);
}
- sprintf(buf, "%2d", minutes);
+ sprintf(buf, "%2ld", minutes);
return (buf);
}
/*
* Collect the requested quota information.
*/
-struct quotause *
+static struct quotause *
getprivs(id, quotatype)
register long id;
int quotatype;
{
- register struct fstab *fs;
register struct quotause *qup, *quptail;
+ register struct fstab *fs;
struct quotause *quphead;
- char *qfpathname;
- int qcmd, fd;
+ struct statfs *fst;
+ int nfst, i;
+
+ qup = quphead = (struct quotause *)0;
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst == 0) {
+ fprintf(stderr, "quota: no filesystems mounted!\n");
+ exit(2);
+ }
setfsent();
- quphead = (struct quotause *)0;
- qcmd = QCMD(Q_GETQUOTA, quotatype);
- while (fs = getfsent()) {
- if (strcmp(fs->fs_vfstype, "ufs"))
- continue;
- if (!hasquota(fs, quotatype, &qfpathname))
- continue;
- if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
- fprintf(stderr, "quota: out of memory\n");
- exit(2);
+ for (i=0; i<nfst; i++) {
+ if (qup == NULL) {
+ if ((qup = (struct quotause *)malloc(sizeof *qup))
+ == NULL) {
+ fprintf(stderr, "quota: out of memory\n");
+ exit(2);
+ }
}
- if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
- if ((fd = open(qfpathname, O_RDONLY)) < 0) {
- perror(qfpathname);
- free(qup);
+ if (fst[i].f_type == MOUNT_NFS) {
+ if (getnfsquota(&fst[i], NULL, qup, id, quotatype)
+ == 0)
continue;
- }
- lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
- switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
- case 0: /* EOF */
- /*
- * Convert implicit 0 quota (EOF)
- * into an explicit one (zero'ed dqblk)
- */
- bzero((caddr_t)&qup->dqblk,
- sizeof(struct dqblk));
- break;
-
- case sizeof(struct dqblk): /* OK */
- break;
-
- default: /* ERROR */
- fprintf(stderr, "quota: read error");
- perror(qfpathname);
- close(fd);
- free(qup);
+ } else if (fst[i].f_type == MOUNT_UFS) {
+ /*
+ * XXX
+ * UFS filesystems must be in /etc/fstab, and must
+ * indicate that they have quotas on (?!) This is quite
+ * unlike SunOS where quotas can be enabled/disabled
+ * on a filesystem independent of /etc/fstab, and it
+ * will still print quotas for them.
+ */
+ if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL)
continue;
- }
- close(fd);
- }
- strcpy(qup->fsname, fs->fs_file);
+ if (getufsquota(&fst[i], fs, qup, id, quotatype) == 0)
+ continue;
+ } else
+ continue;
+ strcpy(qup->fsname, fst[i].f_mntonname);
if (quphead == NULL)
quphead = qup;
else
quptail->next = qup;
quptail = qup;
- qup->next = 0;
+ quptail->next = 0;
+ qup = NULL;
}
+ if (qup)
+ free(qup);
endfsent();
return (quphead);
}
@@ -467,15 +516,15 @@ getprivs(id, quotatype)
/*
* Check to see if a particular quota is to be enabled.
*/
-hasquota(fs, type, qfnamep)
+static int
+ufshasquota(fs, type, qfnamep)
register struct fstab *fs;
int type;
char **qfnamep;
{
- register char *opt;
- char *cp, *index(), *strtok();
static char initname, usrname[100], grpname[100];
static char buf[BUFSIZ];
+ char *opt, *cp;
if (!initname) {
sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
@@ -484,7 +533,7 @@ hasquota(fs, type, qfnamep)
}
strcpy(buf, fs->fs_mntops);
for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
- if (cp = index(opt, '='))
+ if ((cp = index(opt, '=')))
*cp++ = '\0';
if (type == USRQUOTA && strcmp(opt, usrname) == 0)
break;
@@ -502,6 +551,175 @@ hasquota(fs, type, qfnamep)
return (1);
}
+static int
+getufsquota(fst, fs, qup, id, quotatype)
+ struct statfs *fst;
+ struct fstab *fs;
+ struct quotause *qup;
+ long id;
+ int quotatype;
+{
+ char *qfpathname;
+ int fd, qcmd;
+
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+ if (!ufshasquota(fs, quotatype, &qfpathname))
+ return (0);
+
+ if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) {
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ perror(qfpathname);
+ return (0);
+ }
+ (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
+ switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
+ case 0: /* EOF */
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk));
+ break;
+ case sizeof(struct dqblk): /* OK */
+ break;
+ default: /* ERROR */
+ fprintf(stderr, "quota: read error");
+ perror(qfpathname);
+ close(fd);
+ return (0);
+ }
+ close(fd);
+ }
+ return (1);
+}
+
+static int
+getnfsquota(fst, fs, qup, id, quotatype)
+ struct statfs *fst;
+ struct fstab *fs;
+ struct quotause *qup;
+ long id;
+ int quotatype;
+{
+ struct getquota_args gq_args;
+ struct getquota_rslt gq_rslt;
+ struct dqblk *dqp = &qup->dqblk;
+ struct timeval tv;
+ char *cp;
+
+ if (fst->f_flags & MNT_LOCAL)
+ return (0);
+
+ /*
+ * rpc.rquotad does not support group quotas
+ */
+ if (quotatype != USRQUOTA)
+ return (0);
+
+ /*
+ * must be some form of "hostname:/path"
+ */
+ cp = strchr(fst->f_mntfromname, ':');
+ if (cp == NULL) {
+ fprintf(stderr, "cannot find hostname for %s\n",
+ fst->f_mntfromname);
+ return (0);
+ }
+
+ *cp = '\0';
+ if (*(cp+1) != '/') {
+ *cp = ':';
+ return (0);
+ }
+
+ gq_args.gqa_pathp = cp + 1;
+ gq_args.gqa_uid = id;
+ if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS,
+ RQUOTAPROC_GETQUOTA, xdr_getquota_args, (char *)&gq_args,
+ xdr_getquota_rslt, (char *)&gq_rslt) != 0) {
+ *cp = ':';
+ return (0);
+ }
+
+ switch (gq_rslt.status) {
+ case Q_NOQUOTA:
+ break;
+ case Q_EPERM:
+ fprintf(stderr, "quota permission error, host: %s\n",
+ fst->f_mntfromname);
+ break;
+ case Q_OK:
+ gettimeofday(&tv, NULL);
+ /* blocks*/
+ dqp->dqb_bhardlimit =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit *
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
+ dqp->dqb_bsoftlimit =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit *
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
+ dqp->dqb_curblocks =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks *
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
+ /* inodes */
+ dqp->dqb_ihardlimit =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit;
+ dqp->dqb_isoftlimit =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit;
+ dqp->dqb_curinodes =
+ gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles;
+ /* grace times */
+ dqp->dqb_btime =
+ tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft;
+ dqp->dqb_itime =
+ tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft;
+ *cp = ':';
+ return (1);
+ default:
+ fprintf(stderr, "bad rpc result, host: %s\n",
+ fst->f_mntfromname);
+ break;
+ }
+ *cp = ':';
+ return (0);
+}
+
+static int
+callaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
+ char *host;
+ xdrproc_t inproc, outproc;
+ char *in, *out;
+ int prognum, versnum, procnum;
+{
+ struct sockaddr_in server_addr;
+ enum clnt_stat clnt_stat;
+ struct hostent *hp;
+ struct timeval timeout, tottimeout;
+
+ CLIENT *client = NULL;
+ int socket = RPC_ANYSOCK;
+
+ if ((hp = gethostbyname(host)) == NULL)
+ return ((int) RPC_UNKNOWNHOST);
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 6;
+ bcopy(hp->h_addr, &server_addr.sin_addr, hp->h_length);
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = 0;
+
+ if ((client = clntudp_create(&server_addr, prognum,
+ versnum, timeout, &socket)) == NULL)
+ return ((int) rpc_createerr.cf_stat);
+
+ client->cl_auth = authunix_create_default();
+ tottimeout.tv_sec = 25;
+ tottimeout.tv_usec = 0;
+ clnt_stat = clnt_call(client, procnum, inproc, in,
+ outproc, out, tottimeout);
+
+ return ((int) clnt_stat);
+}
+
+static int
alldigits(s)
register char *s;
{
@@ -511,6 +729,6 @@ alldigits(s)
do {
if (!isdigit(c))
return (0);
- } while (c = *s++);
+ } while ((c = *s++));
return (1);
}
diff --git a/usr.bin/ranlib/Makefile b/usr.bin/ranlib/Makefile
index 4acf99e..a6382a6 100644
--- a/usr.bin/ranlib/Makefile
+++ b/usr.bin/ranlib/Makefile
@@ -3,14 +3,8 @@
PROG= ranlib
SRCS= archive.c build.c misc.c ranlib.c touch.c
CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../ar
-MAN1= ranlib.0
+MAN1= ranlib.1
+MAN5= ranlib.5
VPATH= ${.CURDIR}/../ar
-CLEANFILES=ranlib.5.0
-
-ranlib.0: ranlib.5.0
-
-afterinstall:
- install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} ranlib.5.0 \
- ${DESTDIR}${MANDIR}5/ranlib.0
.include <bsd.prog.mk>
diff --git a/usr.bin/ranlib/build.c b/usr.bin/ranlib/build.c
index 12a6dc6..3b70630 100644
--- a/usr.bin/ranlib/build.c
+++ b/usr.bin/ranlib/build.c
@@ -48,10 +48,17 @@ static char sccsid[] = "@(#)build.c 8.1 (Berkeley) 6/6/93";
#include <fcntl.h>
#include <ranlib.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "archive.h"
+extern int tmp __P(( void ));
+extern void error __P(( char * ));
+extern void badfmt __P(( void ));
+extern void settime __P(( int ));
+
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
extern char *tname; /* temporary file "name" */
@@ -72,7 +79,8 @@ long tsymlen; /* total string length */
static void rexec __P((int, int));
static void symobj __P((void));
-build()
+int
+build(void)
{
CF cf;
int afd, tfd;
@@ -103,7 +111,7 @@ build()
/* Copy the saved objects into the archive. */
size = lseek(tfd, (off_t)0, SEEK_CUR);
(void)lseek(tfd, (off_t)0, SEEK_SET);
- SETCF(tfd, tname, afd, archive, RPAD|WPAD);
+ SETCF(tfd, tname, afd, archive, WPAD);
copy_ar(&cf, size);
(void)ftruncate(afd, lseek(afd, (off_t)0, SEEK_CUR));
(void)close(tfd);
@@ -127,7 +135,7 @@ rexec(rfd, wfd)
register RLIB *rp;
register long nsyms;
register int nr, symlen;
- register char *strtab, *sym;
+ register char *strtab = 0, *sym;
struct exec ebuf;
struct nlist nl;
off_t r_off, w_off;
@@ -220,7 +228,7 @@ bad1: (void)lseek(rfd, r_off, SEEK_SET);
static void
symobj()
{
- register RLIB *rp;
+ register RLIB *rp, *rpnext;
struct ranlib rn;
off_t ransize;
long size, stroff;
@@ -272,9 +280,14 @@ symobj()
error(tname);
/* Write out the string table. */
- for (rp = rhead; rp; rp = rp->next)
+ for (rp = rhead; rp; rp = rpnext) {
if (!fwrite(rp->sym, rp->symlen, 1, fp))
error(tname);
+ rpnext = rp->next;
+ free(rp->sym);
+ free(rp);
+ }
+ rhead = NULL;
if (pad && !fwrite(&pad, sizeof(pad), 1, fp))
error(tname);
diff --git a/usr.bin/ranlib/misc.c b/usr.bin/ranlib/misc.c
index d1c8076..600e49e 100644
--- a/usr.bin/ranlib/misc.c
+++ b/usr.bin/ranlib/misc.c
@@ -42,6 +42,7 @@ static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
#include <sys/signal.h>
#include <errno.h>
#include <unistd.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -50,7 +51,10 @@ static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
extern char *archive; /* archive name */
char *tname = "temporary file"; /* temporary file "name" */
-tmp()
+void error __P(( char * ));
+
+int
+tmp(void)
{
sigset_t set, oset;
int fd;
@@ -60,7 +64,7 @@ tmp()
(void)sprintf(path, "%s%s", envtmp, strrchr(_PATH_RANTMP, '/'));
else
bcopy(_PATH_RANTMP, path, sizeof(_PATH_RANTMP));
-
+
sigfillset(&set);
(void)sigprocmask(SIG_BLOCK, &set, &oset);
if ((fd = mkstemp(path)) == -1)
@@ -90,12 +94,14 @@ rname(path)
return((ind = rindex(path, '/')) ? ind + 1 : path);
}
-badfmt()
+void
+badfmt(void)
{
errno = EFTYPE;
error(archive);
}
+void
error(name)
char *name;
{
diff --git a/usr.bin/ranlib/ranlib.1 b/usr.bin/ranlib/ranlib.1
index bd95cd2..bb419d6 100644
--- a/usr.bin/ranlib/ranlib.1
+++ b/usr.bin/ranlib/ranlib.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ranlib.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt RANLIB 1
@@ -46,7 +47,7 @@
creates a table of external references for archive libraries,
normally used by the loader,
.Xr ld 1 .
-This table is is named ``__.SYMDEF'' and is prepended to the archive.
+This table is named ``__.SYMDEF'' and is prepended to the archive.
Files in the archive which are not executable and symbols which are
uninteresting to the loader are ignored.
.Pp
@@ -54,7 +55,8 @@ The options are as follows:
.Bl -tag -width indent
.It Fl t
Set the modification time of the __.SYMDEF file.
-This time is compared by the loader with the modification time of the
+Some loaders (but not the FreeBSD one)
+compared this time with the modification time of the
archive to verify that the table is up-to-date with respect to the
archive.
If the modification time has been changed without any change to the
diff --git a/usr.bin/ranlib/ranlib.1aout b/usr.bin/ranlib/ranlib.1aout
new file mode 100644
index 0000000..bb419d6
--- /dev/null
+++ b/usr.bin/ranlib/ranlib.1aout
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ranlib.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
+.\"
+.Dd June 6, 1993
+.Dt RANLIB 1
+.Os
+.Sh NAME
+.Nm ranlib
+.Nd table-of-contents for archive libraries
+.Sh SYNOPSIS
+.Nm ranlib
+.Op Fl t
+.Ar file ...
+.Sh DESCRIPTION
+.Nm Ranlib
+creates a table of external references for archive libraries,
+normally used by the loader,
+.Xr ld 1 .
+This table is named ``__.SYMDEF'' and is prepended to the archive.
+Files in the archive which are not executable and symbols which are
+uninteresting to the loader are ignored.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl t
+Set the modification time of the __.SYMDEF file.
+Some loaders (but not the FreeBSD one)
+compared this time with the modification time of the
+archive to verify that the table is up-to-date with respect to the
+archive.
+If the modification time has been changed without any change to the
+archive (for example, by a
+.Xr cp 1 ) ,
+the
+.Fl t
+option can be used to ``touch'' the modification time so that it
+appears that the table is up-to-date.
+This is also useful after using the
+.Fl t
+option of
+.Xr make 1 .
+.El
+.Sh FILES
+.Bl -tag -width /tmp/ranlib.XXXXXX -compact
+.It Pa /tmp/ranlib.XXXXXX
+Temporary file names.
+.El
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr ld 1 ,
+.Xr lorder 1 ,
+.Xr nm 1 ,
+.Xr ranlib 5
+.Sh HISTORY
+A
+.Nm ranlib
+command appeared in
+.At v7 .
diff --git a/usr.bin/ranlib/ranlib.5 b/usr.bin/ranlib/ranlib.5
new file mode 100644
index 0000000..e953c51
--- /dev/null
+++ b/usr.bin/ranlib/ranlib.5
@@ -0,0 +1,70 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ranlib.5.5 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt RANLIB 5
+.Os
+.Sh NAME
+.Nm ranlib
+.Nd archive (library) table-of-contents format
+.Sh SYNOPSIS
+.Fd #include <ranlib.h>
+.Sh DESCRIPTION
+The archive table-of-contents command
+.Nm ranlib
+creates a table of contents for archives, containing object files, to
+be used by the link-editor
+.Xr ld 1 .
+It operates on archives created with the utility
+.Xr ar 1 .
+.Pp
+The
+.Nm Ranlib
+function
+prepends a new file to the archive which has three separate parts.
+The first part is a standard archive header, which has a special name
+field, "__.SYMDEF".
+.Pp
+The second part is a ``long'' followed by a list of ranlib structures.
+The long is the size, in bytes, of the list of ranlib structures.
+Each of the ranlib structures consists of a zero based offset into the
+next section (a string table of symbols) and an offset from the beginning
+of the archive to the start of the archive file which defines the symbol.
+The actual number of ranlib structures is this number divided by the size
+of an individual ranlib structure.
+.Pp
+The third part is a ``long'' followed by a string table.
+The long is the size, in bytes of the string table.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr ranlib 1
diff --git a/usr.bin/ranlib/ranlib.c b/usr.bin/ranlib/ranlib.c
index 9d1d8a1..d58a4cf 100644
--- a/usr.bin/ranlib/ranlib.c
+++ b/usr.bin/ranlib/ranlib.c
@@ -50,10 +50,15 @@ static char sccsid[] = "@(#)ranlib.c 8.1 (Berkeley) 6/6/93";
#include <stdlib.h>
#include <archive.h>
+extern int build __P(( void ));
+extern int touch __P(( void ));
+void usage __P((void));
+
CHDR chdr;
u_int options; /* UNUSED -- keep open_archive happy */
char *archive;
+int
main(argc, argv)
int argc;
char **argv;
@@ -62,7 +67,7 @@ main(argc, argv)
int ch, eval, tflag;
tflag = 0;
- while ((ch = getopt(argc, argv, "t")) != EOF)
+ while ((ch = getopt(argc, argv, "t")) != -1)
switch(ch) {
case 't':
tflag = 1;
@@ -77,13 +82,15 @@ main(argc, argv)
if (!*argv)
usage();
- for (eval = 0; archive = *argv++;)
+ for (eval = 0; (archive = *argv++); )
eval |= tflag ? touch() : build();
exit(eval);
}
-usage()
+void
+usage(void)
{
(void)fprintf(stderr, "usage: ranlib [-t] archive ...\n");
exit(1);
}
+
diff --git a/usr.bin/ranlib/touch.c b/usr.bin/ranlib/touch.c
index 4cf4b12..68a86a4 100644
--- a/usr.bin/ranlib/touch.c
+++ b/usr.bin/ranlib/touch.c
@@ -52,7 +52,12 @@ static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
-touch()
+extern void error __P(( char * ));
+void settime __P(( int ));
+int touch __P(( void ));
+
+int
+touch(void)
{
int afd;
@@ -65,9 +70,11 @@ touch()
return(1);
}
settime(afd);
+ close_archive(afd);
return(0);
}
+void
settime(afd)
int afd;
{
diff --git a/usr.bin/rdist/Makefile b/usr.bin/rdist/Makefile
index 4b60c6b..637418b 100644
--- a/usr.bin/rdist/Makefile
+++ b/usr.bin/rdist/Makefile
@@ -2,13 +2,15 @@
PROG= rdist
CFLAGS+=-I${.CURDIR}
-SRCS= docmd.c expand.c lookup.c main.c server.c
-OBJS+= gram.o
-BINOWN= root
-BINMODE=4555
-INSTALLFLAGS=-fschg
-DPADD= ${LIBCOMPAT}
-LDADD= -lcompat
-CLEANFILES=y.tab.h
+SRCS= docmd.c expand.c lookup.c main.c rshrcmd.c server.c
+SRCS+= gram.c
+CLEANFILES=y.tab.h gram.c
+
+# To use the old method, which requires setuid-root and all the baggage and
+# security holes that goes with it, uncomment:
+# CFLAGS+= -DDIRECT_RCMD
+# BINOWN= root
+# BINMODE=4555
+# INSTALLFLAGS=-fschg
.include <bsd.prog.mk>
diff --git a/usr.bin/rdist/defs.h b/usr.bin/rdist/defs.h
index 08bf8d6..cc484a2 100644
--- a/usr.bin/rdist/defs.h
+++ b/usr.bin/rdist/defs.h
@@ -34,13 +34,13 @@
*/
#include <sys/param.h>
-#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/file.h>
#include <netinet/in.h>
+#include <dirent.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
@@ -105,6 +105,13 @@
#define ALLOC(x) (struct x *) malloc(sizeof(struct x))
+/*
+ * RSH Time Out interval (in seconds).
+ * Should be long enough to allow rsh to even the slowest hosts.
+ */
+#define RTIMEOUT 180
+
+
struct namelist { /* for making lists of strings */
char *n_name;
struct namelist *n_next;
@@ -149,7 +156,9 @@ extern struct linkbuf *ihead; /* list of files with more than one link */
extern struct passwd *pw; /* pointer to static area used by getpwent */
extern struct group *gr; /* pointer to static area used by getgrent */
extern char host[]; /* host name of master copy */
-extern char buf[]; /* general purpose buffer */
+extern char buf[BUFSIZ]; /* general purpose buffer */
+extern char target[BUFSIZ]; /* target/source directory name */
+extern char *path_rsh; /* rsh command to use */
int any __P((int, char *));
char *colon __P((char *));
@@ -160,7 +169,7 @@ void error __P((const char *, ...));
int except __P((char *));
struct namelist *
expand __P((struct namelist *, int));
-char *exptilde __P((char [], char *));
+char *exptilde __P((char [], char *, int));
void fatal __P((const char *, ...));
int inlist __P((struct namelist *, char *));
void insert __P((char *,
@@ -178,3 +187,4 @@ void prnames __P((struct namelist *));
void server __P((void));
void yyerror __P((char *));
int yyparse __P((void));
+int rshrcmd __P((char **, u_short, char *, char *, char *, int *));
diff --git a/usr.bin/rdist/docmd.c b/usr.bin/rdist/docmd.c
index 0422a37..a5dc82c 100644
--- a/usr.bin/rdist/docmd.c
+++ b/usr.bin/rdist/docmd.c
@@ -32,12 +32,15 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)docmd.c 8.1 (Berkeley) 6/9/93";
+/*static char sccsid[] = "From: @(#)docmd.c 8.1 (Berkeley) 6/9/93";*/
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include "defs.h"
#include <setjmp.h>
#include <netdb.h>
+#include <regex.h>
FILE *lfp; /* log file for recording files updated */
struct subcmd *subcmds; /* list of sub-commands for current cmd */
@@ -53,6 +56,7 @@ static void dodcolon __P((char **,
struct namelist *, char *, struct subcmd *));
static void notify __P((char *, char *, struct namelist *, time_t));
static void rcmptime __P((struct stat *));
+static int remotecmd __P((char *, char *, char *, char *));
/*
* Do the commands in cmds (initialized by yyparse).
@@ -126,7 +130,7 @@ doarrow(filev, files, rhost, cmds)
int n, ddir, opts = options;
if (debug)
- printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
+ printf("doarrow(%p, %s, %p)\n", files, rhost, cmds);
if (files == NULL) {
error("no files to be updated\n");
@@ -191,6 +195,54 @@ done:
}
}
+static int remotecmd(rhost, luser, ruser, cmd)
+ char *rhost;
+ char *luser, *ruser;
+ char *cmd;
+{
+ int desc;
+ static int port = -1;
+
+ if (debug) {
+ printf("local user = %s remote user = %s\n", luser, ruser);
+ printf("Remote command = '%s'\n", cmd);
+ }
+
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+ (void) signal(SIGALRM, cleanup);
+ (void) alarm(RTIMEOUT);
+
+ if (geteuid() == 0 && strcmp(path_rsh, _PATH_RSH) == 0) {
+ if (debug)
+ printf("I am root, therefore direct rcmd\n");
+
+ (void) signal(SIGPIPE, cleanup);
+
+ if (port < 0) {
+ struct servent *sp;
+
+ if ((sp = getservbyname("shell", "tcp")) == NULL)
+ fatal("shell/tcp: unknown service");
+ port = sp->s_port;
+ }
+
+ desc = rcmd(&rhost, port, luser, ruser, cmd, 0);
+ } else {
+ if (debug)
+ printf("Remote shell command = '%s'\n", path_rsh);
+ (void) signal(SIGPIPE, SIG_IGN);
+ desc = rshrcmd(&rhost, -1, luser, ruser, cmd, 0);
+ if (desc > 0)
+ (void) signal(SIGPIPE, cleanup);
+ }
+
+ (void) alarm(0);
+
+ return(desc);
+}
+
+
/*
* Create a connection to the rdist server on the machine rhost.
*/
@@ -204,7 +256,9 @@ makeconn(rhost)
char tuser[20];
int n;
extern char user[];
+#if defined(DIRECT_RCMD)
extern int userid;
+#endif
if (debug)
printf("makeconn(%s)\n", rhost);
@@ -232,7 +286,8 @@ makeconn(rhost)
ruser = user;
if (!qflag)
printf("updating host %s\n", rhost);
- (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : "");
+ (void) snprintf(buf, sizeof(buf), "%s -Server%s",
+ _PATH_RDIST, qflag ? " -q" : "");
if (port < 0) {
struct servent *sp;
@@ -247,9 +302,13 @@ makeconn(rhost)
}
fflush(stdout);
+#if defined(DIRECT_RCMD)
seteuid(0);
rem = rcmd(&rhost, port, user, ruser, buf, 0);
seteuid(userid);
+#else
+ rem = remotecmd(rhost, user, ruser, buf);
+#endif
if (rem < 0)
return(0);
cp = buf;
@@ -420,7 +479,7 @@ cmptime(name)
* first time cmptime() is called?
*/
if (tp == NULL) {
- if (exptilde(target, name) == NULL)
+ if (exptilde(target, name, sizeof(target)) == NULL)
return;
tp = name = target;
while (*tp)
@@ -453,13 +512,13 @@ rcmptime(st)
struct stat *st;
{
register DIR *d;
- register struct direct *dp;
+ register struct dirent *dp;
register char *cp;
char *otp;
int len;
if (debug)
- printf("rcmptime(%x)\n", st);
+ printf("rcmptime(%p)\n", st);
if ((d = opendir(target)) == NULL) {
error("%s: %s\n", target, strerror(errno));
@@ -467,7 +526,7 @@ rcmptime(st)
}
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -477,7 +536,7 @@ rcmptime(st)
tp = otp;
*tp++ = '/';
cp = dp->d_name;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
cmptime(target);
@@ -529,7 +588,7 @@ notify(file, rhost, to, lmod)
/*
* Create a pipe to mailling program.
*/
- (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL);
+ (void) snprintf(buf, sizeof(buf), "%s -oi -t", _PATH_SENDMAIL);
pf = popen(buf, "w");
if (pf == NULL) {
error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
@@ -592,6 +651,8 @@ except(file)
{
register struct subcmd *sc;
register struct namelist *nl;
+ regex_t rx;
+ int val;
if (debug)
printf("except(%s)\n", file);
@@ -605,9 +666,13 @@ except(file)
return(1);
continue;
}
- re_comp(nl->n_name);
- if (re_exec(file) > 0)
- return(1);
+ val = regcomp(&rx, nl->n_name,
+ REG_EXTENDED | REG_NOSUB);
+ if (!regexec(&rx, file, 0, 0, 0)) {
+ regfree(&rx);
+ return 1;
+ }
+ regfree(&rx);
}
}
return(0);
diff --git a/usr.bin/rdist/expand.c b/usr.bin/rdist/expand.c
index 6b5fd17..497a551 100644
--- a/usr.bin/rdist/expand.c
+++ b/usr.bin/rdist/expand.c
@@ -91,7 +91,7 @@ expand(list, wh)
char *argvbuf[GAVSIZ];
if (debug) {
- printf("expand(%x, %d)\nlist = ", list, wh);
+ printf("expand(%p, %d)\nlist = ", list, wh);
prnames(list);
}
@@ -180,12 +180,13 @@ expstr(s)
*tail = savec;
if (tp != NULL) {
for (; tp != NULL; tp = tp->n_next) {
- sprintf(buf, "%s%s%s", s, tp->n_name, tail);
+ snprintf(buf, sizeof(buf),
+ "%s%s%s", s, tp->n_name, tail);
expstr(buf);
}
return;
}
- sprintf(buf, "%s%s", s, tail);
+ snprintf(buf, sizeof(buf), "%s%s", s, tail);
expstr(buf);
return;
}
@@ -216,7 +217,7 @@ expstr(s)
cp1 = pw->pw_dir;
s = cp;
}
- for (cp = path; *cp++ = *cp1++; )
+ for (cp = path; (*cp++ = *cp1++); )
;
tpathp = pathp = cp - 1;
} else {
@@ -295,7 +296,7 @@ matchdir(pattern)
char *pattern;
{
struct stat stb;
- register struct direct *dp;
+ register struct dirent *dp;
DIR *dirp;
dirp = opendir(path);
@@ -450,7 +451,7 @@ amatch(s, p)
case '[':
ok = 0;
lc = 077777;
- while (cc = *p++) {
+ while ((cc = *p++)) {
if (cc == ']') {
if (ok)
break;
@@ -533,7 +534,7 @@ smatch(s, p)
case '[':
ok = 0;
lc = 077777;
- while (cc = *p++) {
+ while ((cc = *p++)) {
if (cc == ']') {
if (ok)
break;
@@ -591,10 +592,10 @@ Cat(s1, s2)
eargv[eargc - 1] = s = malloc(len);
if (s == NULL)
fatal("ran out of memory\n");
- while (*s++ = *s1++ & TRIM)
+ while ((*s++ = *s1++ & TRIM))
;
s--;
- while (*s++ = *s2++ & TRIM)
+ while ((*s++ = *s2++ & TRIM))
;
}
@@ -617,13 +618,16 @@ addpath(c)
* part corresponding to `file'.
*/
char *
-exptilde(buf, file)
+exptilde(buf, file, maxlen)
char buf[];
register char *file;
+ int maxlen;
{
register char *s1, *s2, *s3;
extern char homedir[];
+ if (strlen(file) >= maxlen)
+ return(NULL);
if (*file != '~') {
strcpy(buf, file);
return(buf);
@@ -654,13 +658,15 @@ exptilde(buf, file)
*s3 = '/';
s2 = pw->pw_dir;
}
- for (s1 = buf; *s1++ = *s2++; )
+ for (s1 = buf; (*s1++ = *s2++) && s1 < buf+maxlen; )
;
s2 = --s1;
- if (s3 != NULL) {
+ if (s3 != NULL && s1 < buf+maxlen) {
s2++;
- while (*s1++ = *s3++)
+ while ((*s1++ = *s3++) && s1 < buf+maxlen)
;
}
+ if (s1 == buf+maxlen)
+ return(NULL);
return(s2);
}
diff --git a/usr.bin/rdist/gram.y b/usr.bin/rdist/gram.y
index 7f40f87..09f6f68 100644
--- a/usr.bin/rdist/gram.y
+++ b/usr.bin/rdist/gram.y
@@ -37,6 +37,9 @@ static char sccsid[] = "@(#)gram.y 8.1 (Berkeley) 6/9/93";
#endif /* not lint */
#include "defs.h"
+#include <sys/types.h>
+#include <regex.h>
+#include <limits.h>
struct cmd *cmds = NULL;
struct cmd *last_cmd;
@@ -163,11 +166,19 @@ cmd: INSTALL options opt_namelist SM = {
}
| PATTERN namelist SM = {
struct namelist *nl;
- char *cp, *re_comp();
-
- for (nl = $2; nl != NULL; nl = nl->n_next)
- if ((cp = re_comp(nl->n_name)) != NULL)
- yyerror(cp);
+ regex_t rx;
+ int val;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ for (nl = $2; nl != NULL; nl = nl->n_next) {
+ if ((val = regcomp(&rx, nl->n_name,
+ REG_EXTENDED))) {
+ regerror(val, &rx, errbuf,
+ sizeof errbuf);
+ yyerror(errbuf);
+ }
+ regfree(&rx);
+ }
$1->sc_args = expand($2, E_VARS);
$$ = $1;
}
@@ -372,11 +383,11 @@ insert(label, files, hosts, subcmds)
struct subcmd *subcmds;
{
register struct cmd *c, *prev, *nc;
- register struct namelist *h;
+ register struct namelist *h, *next_h;
files = expand(files, E_VARS|E_SHELL);
hosts = expand(hosts, E_ALL);
- for (h = hosts; h != NULL; free(h), h = h->n_next) {
+ for (h = hosts; h != NULL; next_h = h->n_next, free(h), h = next_h) {
/*
* Search command list for an update to the same host.
*/
@@ -466,7 +477,7 @@ makestr(str)
str = cp = malloc(strlen(s = str) + 1);
if (cp == NULL)
fatal("ran out of memory\n");
- while (*cp++ = *s++)
+ while ((*cp++ = *s++))
;
return(str);
}
diff --git a/usr.bin/rdist/lookup.c b/usr.bin/rdist/lookup.c
index 9819e68..dc2f134 100644
--- a/usr.bin/rdist/lookup.c
+++ b/usr.bin/rdist/lookup.c
@@ -59,7 +59,7 @@ define(name)
{
register char *cp, *s;
register struct namelist *nl;
- struct namelist *value;
+ struct namelist *value = NULL;
if (debug)
printf("define(%s)\n", name);
@@ -129,7 +129,7 @@ lookup(name, action, value)
char buf[256];
if (debug)
- printf("lookup(%s, %d, %x)\n", name, action, value);
+ printf("lookup(%s, %d, %p)\n", name, action, value);
n = 0;
for (cp = name; *cp; )
@@ -141,7 +141,8 @@ lookup(name, action, value)
continue;
if (action != LOOKUP) {
if (action != INSERT || s->s_type != CONST) {
- (void)sprintf(buf, "%s redefined", name);
+ (void)snprintf(buf, sizeof(buf),
+ "%s redefined", name);
yyerror(buf);
}
}
@@ -149,7 +150,7 @@ lookup(name, action, value)
}
if (action == LOOKUP) {
- (void)sprintf(buf, "%s undefined", name);
+ (void)snprintf(buf, sizeof(buf), "%s undefined", name);
yyerror(buf);
return(NULL);
}
diff --git a/usr.bin/rdist/main.c b/usr.bin/rdist/main.c
index 44b3279a..3badde7 100644
--- a/usr.bin/rdist/main.c
+++ b/usr.bin/rdist/main.c
@@ -68,6 +68,7 @@ char user[10]; /* user's name */
char homedir[128]; /* user's home directory */
int userid; /* user's user ID */
int groupid; /* user's group ID */
+char *path_rsh = _PATH_RSH; /* rsh (or equiv command) path */
struct passwd *pw; /* pointer to static area used by getpwent */
struct group *gr; /* pointer to static area used by getgrent */
@@ -107,6 +108,12 @@ main(argc, argv)
iamremote++;
else while (*++arg)
switch (*arg) {
+ case 'P':
+ if (--argc <= 0)
+ usage();
+ path_rsh = *++argv;
+ break;
+
case 'f':
if (--argc <= 0)
usage();
@@ -222,8 +229,9 @@ main(argc, argv)
static void
usage()
{
- printf("Usage: rdist [-nqbhirvwyD] [-f distfile] [-d var=value] [-m host] [file ...]\n");
- printf("or: rdist [-nqbhirvwyD] -c source [...] machine[:dest]\n");
+ printf("Usage: rdist [-nqbhirvwyD] [-P /path/to/rsh ] [-f distfile] [-d var=value]\n");
+ printf(" [-m host] [file ...]\n");
+ printf("or: rdist [-nqbhirvwyD] [-P /path/to/rsh ] -c source [...] machine[:dest]\n");
exit(1);
}
@@ -237,7 +245,7 @@ docmdargs(nargs, args)
{
register struct namelist *nl, *prev;
register char *cp;
- struct namelist *files, *hosts;
+ struct namelist *files = NULL, *hosts;
struct subcmd *cmds;
char *dest;
static struct namelist tnl = { NULL, NULL };
diff --git a/usr.bin/rdist/pathnames.h b/usr.bin/rdist/pathnames.h
index 2e1b067..c772539 100644
--- a/usr.bin/rdist/pathnames.h
+++ b/usr.bin/rdist/pathnames.h
@@ -36,3 +36,4 @@
#include <paths.h>
#define _PATH_RDIST "rdist"
+#define _PATH_RSH "/usr/bin/rsh"
diff --git a/usr.bin/rdist/rdist.1 b/usr.bin/rdist/rdist.1
index 9ae17e9..087690a 100644
--- a/usr.bin/rdist/rdist.1
+++ b/usr.bin/rdist/rdist.1
@@ -40,12 +40,14 @@
.Sh SYNOPSIS
.Nm rdist
.Op Fl nqbRhivwy
+.Op Fl P Ar rshcmd
.Op Fl f Ar distfile
.Op Fl d Ar var=value
.Op Fl m Ar host
.Op Ar name ...
.Nm rdist
.Op Fl nqbRhivwy
+.Op Fl P Ar rshcmd
.Fl c
.Ar name ...
.Oo login@ Oc Ns Ar host Ns Op :dest
@@ -118,9 +120,13 @@ The equivalent distfile is as follows.
Options common to both forms:
.Pp
.Bl -tag -width Ic
-.It Fl b
-Binary comparison. Perform a binary comparison and update files if they differ
-rather than comparing dates and sizes.
+.It Fl P Ar rshcmd
+Alternative program to provide
+.Xr rsh 1 -like
+transport to the remote server. It must provide a binary-transparent path
+to the remote server, and must have a command argument syntax that is
+compatable with
+.Xr rsh 1 .
.It Fl d Ar var=value
Define
.Ar var
@@ -308,7 +314,7 @@ command except that
.Ar pattern list
is a list of regular expressions
(see
-.Xr ed 1
+.Xr re_format 7
for details).
If one of the patterns matches some string within a file name, that file will
be ignored.
@@ -382,9 +388,10 @@ input command file
temporary file for update lists
.El
.Sh SEE ALSO
-.Xr sh 1 ,
.Xr csh 1 ,
-.Xr stat 2
+.Xr sh 1 ,
+.Xr stat 2 ,
+.Xr re_format 7
.Sh HISTORY
The
.Nm rdist
diff --git a/usr.bin/rdist/rshrcmd.c b/usr.bin/rdist/rshrcmd.c
new file mode 100644
index 0000000..6d2986b
--- /dev/null
+++ b/usr.bin/rdist/rshrcmd.c
@@ -0,0 +1,124 @@
+
+/*
+ * This is an rcmd() replacement originally by
+ * Chris Siebenmann <cks@utcc.utoronto.ca>.
+ */
+
+#ifndef lint
+static char RCSid[] =
+"$Id$";
+#endif
+
+#include "defs.h"
+
+#if !defined(DIRECT_RCMD)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static char *
+xbasename(s)
+ char *s;
+{
+ char *ret;
+
+ ret = strrchr(s, '/');
+ if (ret && ret[1])
+ return (ret + 1);
+ return s;
+}
+
+
+/*
+ * This is a replacement rcmd() function that uses the rsh(1c)
+ * program in place of a direct rcmd() function call so as to
+ * avoid having to be root.
+ */
+int
+rshrcmd(ahost, port, luser, ruser, cmd, fd2p)
+ char **ahost;
+ u_short port;
+ char *luser, *ruser, *cmd;
+ int *fd2p;
+{
+ int cpid;
+ struct hostent *hp;
+ int sp[2];
+
+ /* insure that we are indeed being used as we thought. */
+ if (fd2p != 0)
+ return -1;
+ /* validate remote hostname. */
+ hp = gethostbyname(*ahost);
+ if (hp == 0) {
+ error("%s: unknown host", *ahost);
+ return -1;
+ }
+ /* *ahost = hp->h_name; *//* This makes me nervous. */
+
+ /* get a socketpair we'll use for stdin and stdout. */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+ error("socketpair(AF_UNIX, SOCK_STREAM, 0) failed: %s.",
+ strerror(errno));
+ return -1;
+ }
+
+ cpid = fork();
+ if (cpid < 0) {
+ error("fork failed: %s.", strerror(errno));
+ return -1; /* error. */
+ }
+ if (cpid == 0) {
+ /* child. we use sp[1] to be stdin/stdout, and close
+ sp[0]. */
+ (void) close(sp[0]);
+ if (dup2(sp[1], 0) < 0 || dup2(0,1) < 0) {
+ error("dup2 failed: %s.", strerror(errno));
+ _exit(255);
+ }
+ /* fork again to lose parent. */
+ cpid = fork();
+ if (cpid < 0) {
+ error("fork to lose parent failed: %s.", strerror(errno));
+ _exit(255);
+ }
+ if (cpid > 0)
+ _exit(0);
+ /* in grandchild here. */
+
+ /*
+ * If we are rdist'ing to "localhost" as the same user
+ * as we are, then avoid running remote shell for efficiency.
+ */
+ if (strcmp(*ahost, "localhost") == 0 &&
+ strcmp(luser, ruser) == 0) {
+ execlp(_PATH_BSHELL, xbasename(_PATH_BSHELL), "-c",
+ cmd, (char *) NULL);
+ error("execlp %s failed: %s.", _PATH_BSHELL, strerror(errno));
+ } else {
+ execlp(path_rsh, xbasename(path_rsh),
+ *ahost, "-l", ruser, cmd, (char *) NULL);
+ error("execlp %s failed: %s.", path_rsh,
+ strerror(errno));
+ }
+ _exit(255);
+ }
+ if (cpid > 0) {
+ /* parent. close sp[1], return sp[0]. */
+ (void) close(sp[1]);
+ /* reap child. */
+ (void) wait(0);
+ return sp[0];
+ }
+ /*NOTREACHED*/
+ return (-1);
+}
+
+#endif /* !DIRECT_RCMD */
diff --git a/usr.bin/rdist/server.c b/usr.bin/rdist/server.c
index aa33936..37ae9c5 100644
--- a/usr.bin/rdist/server.c
+++ b/usr.bin/rdist/server.c
@@ -90,7 +90,7 @@ server()
rem = 0;
oumask = umask(0);
- (void) sprintf(buf, "V%d\n", VERSION);
+ (void) snprintf(buf, sizeof(buf), "V%d\n", VERSION);
(void) write(rem, buf, strlen(buf));
for (;;) {
@@ -115,7 +115,7 @@ server()
case 't': /* init target file/directory name */
catname = 0;
dotarget:
- if (exptilde(target, cp) == NULL)
+ if (exptilde(target, cp, sizeof(target)) == NULL)
continue;
tp = target;
while (*tp)
@@ -176,7 +176,7 @@ server()
continue;
}
if (*cp == '~') {
- if (exptilde(buf, cp) == NULL)
+ if (exptilde(buf, cp, sizeof(buf)) == NULL)
continue;
cp = buf;
}
@@ -248,7 +248,7 @@ install(src, dest, destdir, opts)
return;
}
- rname = exptilde(target, src);
+ rname = exptilde(target, src, sizeof(target));
if (rname == NULL)
return;
tp = target;
@@ -275,7 +275,7 @@ install(src, dest, destdir, opts)
/*
* Pass the destination file/directory name to remote.
*/
- (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest);
+ (void) snprintf(buf, sizeof(buf), "%c%s\n", destdir ? 'T' : 't', dest);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -306,7 +306,7 @@ sendf(rname, opts)
int sizerr, f, u, len;
off_t i;
DIR *d;
- struct direct *dp;
+ struct dirent *dp;
char *otp, *cp;
extern struct subcmd *subcmds;
static char user[15], group[15];
@@ -331,14 +331,14 @@ sendf(rname, opts)
log(lfp, "%s: no password entry for uid %d \n",
target, stb.st_uid);
pw = NULL;
- (void)sprintf(user, ":%lu", stb.st_uid);
+ (void)snprintf(user, sizeof(user), ":%lu", stb.st_uid);
}
if (gr == NULL || gr->gr_gid != stb.st_gid)
if ((gr = getgrgid(stb.st_gid)) == NULL) {
log(lfp, "%s: no name for group %d\n",
target, stb.st_gid);
gr = NULL;
- (void)sprintf(group, ":%lu", stb.st_gid);
+ (void)snprintf(group, sizeof(group), ":%lu", stb.st_gid);
}
if (u == 1) {
if (opts & VERIFY) {
@@ -355,8 +355,9 @@ sendf(rname, opts)
error("%s: %s\n", target, strerror(errno));
return;
}
- (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts,
- stb.st_mode & 07777, protoname(), protogroup(), rname);
+ (void) snprintf(buf, sizeof(buf), "D%o %04o 0 0 %s %s %s\n",
+ opts, stb.st_mode & 07777, protoname(), protogroup(),
+ rname);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -370,7 +371,7 @@ sendf(rname, opts)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") ||
!strcmp(dp->d_name, ".."))
continue;
@@ -382,7 +383,7 @@ sendf(rname, opts)
tp = otp;
*tp++ = '/';
cp = dp->d_name;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
sendf(dp->d_name, opts);
@@ -403,11 +404,12 @@ sendf(rname, opts)
if ((lp = savelink(&stb)) != NULL) {
/* install link */
if (*lp->target == 0)
- (void) sprintf(buf, "k%o %s %s\n", opts,
- lp->pathname, rname);
+ (void) snprintf(buf, sizeof(buf), "k%o %s %s\n",
+ opts, lp->pathname, rname);
else
- (void) sprintf(buf, "k%o %s/%s %s\n", opts,
- lp->target, lp->pathname, rname);
+ (void) snprintf(buf, sizeof(buf),
+ "k%o %s/%s %s\n", opts, lp->target,
+ lp->pathname, rname);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -415,7 +417,8 @@ sendf(rname, opts)
return;
}
}
- (void) sprintf(buf, "K%o %o %qd %ld %s %s %s\n", opts,
+ (void) snprintf(buf, sizeof(buf),
+ "K%o %o %qd %ld %s %s %s\n", opts,
stb.st_mode & 07777, stb.st_size, stb.st_mtime,
protoname(), protogroup(), rname);
if (debug)
@@ -451,11 +454,11 @@ sendf(rname, opts)
if ((lp = savelink(&stb)) != NULL) {
/* install link */
if (*lp->target == 0)
- (void) sprintf(buf, "k%o %s %s\n", opts,
+ (void) snprintf(buf, sizeof(buf), "k%o %s %s\n", opts,
lp->pathname, rname);
else
- (void) sprintf(buf, "k%o %s/%s %s\n", opts,
- lp->target, lp->pathname, rname);
+ (void) snprintf(buf, sizeof(buf), "k%o %s/%s %s\n",
+ opts, lp->target, lp->pathname, rname);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -468,7 +471,7 @@ sendf(rname, opts)
error("%s: %s\n", target, strerror(errno));
return;
}
- (void) sprintf(buf, "R%o %o %qd %ld %s %s %s\n", opts,
+ (void) snprintf(buf, sizeof(buf), "R%o %o %qd %ld %s %s %s\n", opts,
stb.st_mode & 07777, stb.st_size, stb.st_mtime,
protoname(), protogroup(), rname);
if (debug)
@@ -495,7 +498,7 @@ done:
} else
ack();
f = response();
- if (f < 0 || f == 0 && (opts & COMPARE))
+ if (f < 0 || (f == 0 && (opts & COMPARE)))
return;
dospecial:
for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
@@ -506,7 +509,8 @@ dospecial:
log(lfp, "special \"%s\"\n", sc->sc_name);
if (opts & VERIFY)
continue;
- (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name);
+ (void) snprintf(buf, sizeof(buf), "SFILE=%s;%s\n", target,
+ sc->sc_name);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -559,13 +563,13 @@ update(rname, opts, stp)
register off_t size;
register time_t mtime;
- if (debug)
- printf("update(%s, %x, %x)\n", rname, opts, stp);
+ if (debug)
+ printf("update(%s, %x, %p)\n", rname, opts, stp);
/*
* Check to see if the file exists on the remote machine.
*/
- (void) sprintf(buf, "Q%s\n", rname);
+ (void) snprintf(buf, sizeof(buf), "Q%s\n", rname);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -597,7 +601,7 @@ again:
case '\3':
*--cp = '\0';
- if (lfp != NULL)
+ if (lfp != NULL)
log(lfp, "update: note: %s\n", s);
goto again;
@@ -656,7 +660,8 @@ query(name)
struct stat stb;
if (catname)
- (void) sprintf(tp, "/%s", name);
+ (void) snprintf(tp, sizeof(target) - (tp - target), "/%s",
+ name);
if (lstat(target, &stb) < 0) {
if (errno == ENOENT)
@@ -669,7 +674,8 @@ query(name)
switch (stb.st_mode & S_IFMT) {
case S_IFREG:
- (void) sprintf(buf, "Y%qd %ld\n", stb.st_size, stb.st_mtime);
+ (void) snprintf(buf, sizeof(buf), "Y%qd %ld\n", stb.st_size,
+ stb.st_mtime);
(void) write(rem, buf, strlen(buf));
break;
@@ -691,7 +697,7 @@ recvf(cmd, type)
int type;
{
register char *cp;
- int f, mode, opts, wrerr, olderrno;
+ int f = -1, mode, opts, wrerr, olderrno;
off_t i, size;
time_t mtime;
struct stat stb;
@@ -755,7 +761,7 @@ recvf(cmd, type)
stp[catname] = tp;
if (catname++) {
*tp++ = '/';
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
}
@@ -770,15 +776,15 @@ recvf(cmd, type)
return;
}
buf[0] = '\0';
- (void) sprintf(buf + 1,
+ (void) snprintf(buf + 1, sizeof(buf) - 1,
"%s: Warning: remote mode %o != local mode %o\n",
target, stb.st_mode & 07777, mode);
(void) write(rem, buf, strlen(buf + 1) + 1);
return;
}
errno = ENOTDIR;
- } else if (errno == ENOENT && (mkdir(target, mode) == 0 ||
- chkparent(target) == 0 && mkdir(target, mode) == 0)) {
+ } else if ((errno == ENOENT && mkdir(target, mode) == 0) ||
+ (chkparent(target) == 0 && mkdir(target, mode) == 0)) {
if (fchog(-1, target, owner, group, mode) == 0)
ack();
return;
@@ -790,15 +796,15 @@ recvf(cmd, type)
}
if (catname)
- (void) sprintf(tp, "/%s", cp);
+ (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
cp = rindex(target, '/');
if (cp == NULL)
strcpy(new, tempname);
else if (cp == target)
- (void) sprintf(new, "/%s", tempname);
+ (void) snprintf(new, sizeof(new), "/%s", tempname);
else {
*cp = '\0';
- (void) sprintf(new, "%s/%s", target, tempname);
+ (void) snprintf(new, sizeof(new), "%s/%s", target, tempname);
*cp = '/';
}
@@ -898,7 +904,8 @@ badnew1: error("%s:%s: %s\n", host, new, strerror(errno));
(void) fclose(f2);
if (opts & VERIFY) {
differ: buf[0] = '\0';
- (void) sprintf(buf + 1, "need to update: %s\n",target);
+ (void) snprintf(buf + 1, sizeof(buf) - 1,
+ "need to update: %s\n",target);
(void) write(rem, buf, strlen(buf + 1) + 1);
goto badnew2;
}
@@ -915,7 +922,7 @@ differ: buf[0] = '\0';
note("%s: utimes failed %s: %s\n", host, new, strerror(errno));
if (fchog(f, new, owner, group, mode) < 0) {
-badnew2: (void) close(f);
+badnew2: if (f != -1) (void) close(f);
(void) unlink(new);
return;
}
@@ -929,7 +936,8 @@ badtarget: error("%s:%s: %s\n", host, target, strerror(errno));
if (opts & COMPARE) {
buf[0] = '\0';
- (void) sprintf(buf + 1, "updated %s\n", target);
+ (void) snprintf(buf + 1, sizeof(buf) - 1,
+ "updated %s\n", target);
(void) write(rem, buf, strlen(buf + 1) + 1);
} else
ack();
@@ -965,7 +973,7 @@ hardlink(cmd)
*cp++ = '\0';
if (catname) {
- (void) sprintf(tp, "/%s", cp);
+ (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
}
if (lstat(target, &stb) == 0) {
int mode = stb.st_mode & S_IFMT;
@@ -1076,10 +1084,10 @@ fchog(fd, file, owner, group, mode)
mode &= ~02000;
gid = -1;
}
-ok: if (fd != -1 && fchown(fd, uid, gid) < 0 || chown(file, uid, gid) < 0)
+ok: if ((fd != -1 && fchown(fd, uid, gid) < 0) || chown(file, uid, gid) < 0)
note("%s: %s chown: %s", host, file, strerror(errno));
else if (mode & 07000 &&
- (fd != -1 && fchmod(fd, mode) < 0 || chmod(file, mode) < 0))
+ ((fd != -1 && fchmod(fd, mode) < 0) || chmod(file, mode) < 0))
note("%s: %s chmod: %s", host, file, strerror(errno));
return(0);
}
@@ -1101,7 +1109,7 @@ rmchk(opts)
/*
* Tell the remote to clean the files from the last directory sent.
*/
- (void) sprintf(buf, "C%o\n", opts & VERIFY);
+ (void) snprintf(buf, sizeof(buf), "C%o\n", opts & VERIFY);
if (debug)
printf("buf = %s", buf);
(void) write(rem, buf, strlen(buf));
@@ -1122,7 +1130,8 @@ rmchk(opts)
* Y\n -- file doesn't exist - REMOVE.
*/
*--cp = '\0';
- (void) sprintf(tp, "/%s", s);
+ (void) snprintf(tp, sizeof(target) - (tp - target),
+ "/%s", s);
if (debug)
printf("check %s\n", target);
if (except(target))
@@ -1175,7 +1184,7 @@ clean(cp)
register char *cp;
{
DIR *d;
- register struct direct *dp;
+ register struct dirent *dp;
struct stat stb;
char *otp;
int len, opts;
@@ -1195,7 +1204,7 @@ clean(cp)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -1206,14 +1215,14 @@ clean(cp)
tp = otp;
*tp++ = '/';
cp = dp->d_name;;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
if (lstat(target, &stb) < 0) {
error("%s:%s: %s\n", host, target, strerror(errno));
continue;
}
- (void) sprintf(buf, "Q%s\n", dp->d_name);
+ (void) snprintf(buf, sizeof(buf), "Q%s\n", dp->d_name);
(void) write(rem, buf, strlen(buf));
cp = buf;
do {
@@ -1227,7 +1236,8 @@ clean(cp)
if (opts & VERIFY) {
cp = buf;
*cp++ = '\0';
- (void) sprintf(cp, "need to remove: %s\n", target);
+ (void) snprintf(cp, sizeof(buf) - 1,
+ "need to remove: %s\n", target);
(void) write(rem, buf, strlen(cp) + 1);
} else
removeit(&stb);
@@ -1248,7 +1258,7 @@ removeit(stp)
struct stat *stp;
{
DIR *d;
- struct direct *dp;
+ struct dirent *dp;
register char *cp;
struct stat stb;
char *otp;
@@ -1274,7 +1284,7 @@ removeit(stp)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -1285,7 +1295,7 @@ removeit(stp)
tp = otp;
*tp++ = '/';
cp = dp->d_name;;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
if (lstat(target, &stb) < 0) {
@@ -1305,7 +1315,7 @@ bad:
removed:
cp = buf;
*cp++ = '\0';
- (void) sprintf(cp, "removed %s\n", target);
+ (void) snprintf(cp, sizeof(buf) - 1, "removed %s\n", target);
(void) write(rem, buf, strlen(cp) + 1);
}
diff --git a/usr.bin/renice/Makefile b/usr.bin/renice/Makefile
index 67cfd8f..1042921 100644
--- a/usr.bin/renice/Makefile
+++ b/usr.bin/renice/Makefile
@@ -1,5 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/9/93
PROG= renice
+MAN8= renice.8
.include <bsd.prog.mk>
diff --git a/usr.bin/renice/renice.c b/usr.bin/renice/renice.c
index 6deba6b..37dd913 100644
--- a/usr.bin/renice/renice.c
+++ b/usr.bin/renice/renice.c
@@ -86,7 +86,7 @@ main(argc, argv)
}
if (which == PRIO_USER) {
register struct passwd *pwd = getpwnam(*argv);
-
+
if (pwd == NULL) {
fprintf(stderr, "renice: %s: unknown user\n",
*argv);
diff --git a/usr.bin/rev/rev.c b/usr.bin/rev/rev.c
index 2fe272e..2f8241f 100644
--- a/usr.bin/rev/rev.c
+++ b/usr.bin/rev/rev.c
@@ -62,7 +62,7 @@ main(argc, argv)
size_t len;
int ch, rval;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/rlogin/Makefile b/usr.bin/rlogin/Makefile
index 72a77b4..38cf030 100644
--- a/usr.bin/rlogin/Makefile
+++ b/usr.bin/rlogin/Makefile
@@ -1,10 +1,17 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
PROG= rlogin
-SRCS= rlogin.c krcmd.c kcmd.c des_rw.c
+SRCS= rlogin.c
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
+ || defined(MAKE_EBONES))
+SRCS+= krcmd.c kcmd.c
DPADD= ${LIBKRB} ${LIBDES}
CFLAGS+=-DKERBEROS -DCRYPT
LDADD= -lkrb -ldes
+DISTRIBUTION= krb
+.endif
+
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
diff --git a/usr.bin/rlogin/kcmd.c b/usr.bin/rlogin/kcmd.c
index 3f6a138..9a2f5a3 100644
--- a/usr.bin/rlogin/kcmd.c
+++ b/usr.bin/rlogin/kcmd.c
@@ -44,7 +44,7 @@ static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93";
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#include <kerberosIV/kparse.h>
@@ -106,7 +106,11 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
return (-1);
}
- host_save = malloc(strlen(hp->h_name) + 1);
+ if (!(host_save = malloc(strlen(hp->h_name) + 1))) {
+ perror("malloc");
+ return -1;
+ }
+
strcpy(host_save, hp->h_name);
*ahost = host_save;
@@ -131,9 +135,9 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
fcntl(s, F_SETOWN, pid);
sin.sin_family = hp->h_addrtype;
#if defined(ultrix) || defined(sun)
- bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, sizeof sin.sin_addr);
#else
- bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, sizeof sin.sin_addr);
#endif
sin.sin_port = rport;
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
@@ -162,7 +166,7 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
perror(NULL);
hp->h_addr_list++;
bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
- hp->h_length);
+ sizeof sin.sin_addr);
fprintf(stderr, "Trying %s...\n",
inet_ntoa(sin.sin_addr));
continue;
@@ -278,11 +282,14 @@ getport(alport)
int *alport;
{
struct sockaddr_in sin;
- int s;
+ int s, retval;
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
s = socket(AF_INET, SOCK_STREAM, 0);
+ if ((retval = krb_get_local_addr(&sin)) != KSUCCESS) {
+ fprintf(stderr, "krb_get_local_addr: %s\n",krb_err_txt[retval]);
+ close(s);
+ return (-1);
+ }
if (s < 0)
return (-1);
for (;;) {
diff --git a/usr.bin/rlogin/krb.h b/usr.bin/rlogin/krb.h
index 469af1c..07213f4 100644
--- a/usr.bin/rlogin/krb.h
+++ b/usr.bin/rlogin/krb.h
@@ -33,19 +33,6 @@
* @(#)krb.h 8.1 (Berkeley) 6/6/93
*/
-/*
- * XXX
- * These should be in a kerberos include file.
- */
-void des_clear_key __P(());
-int des_read __P((int, char *, int));
-void des_set_key __P((C_Block, Key_schedule));
-int des_write __P((int, char *, int));
-int krb_net_read __P((int, char *, int));
-char *krb_realmofhost __P((char *));
-int krb_sendauth __P((long, int, KTEXT, char *, char *, char *,
- u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
- struct sockaddr_in *, struct sockaddr_in *, char *));
int krcmd __P((char **, u_short, char *, char *, int *, char *));
int krcmd_mutual __P((char **, u_short, char *, char *, int *,
char *, CREDENTIALS *, Key_schedule));
diff --git a/usr.bin/rlogin/krcmd.c b/usr.bin/rlogin/krcmd.c
index ee06d6a..cb9c98f 100644
--- a/usr.bin/rlogin/krcmd.c
+++ b/usr.bin/rlogin/krcmd.c
@@ -36,7 +36,7 @@ static char sccsid[] = "@(#)krcmd.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
- * $Source: /usr/src/usr.bin/rlogin/RCS/krcmd.c,v $
+ * $Source: /home/ncvs/src/usr.bin/rlogin/krcmd.c,v $
* $Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1
* 89/07/25 15:38:44 kfall Exp Locker: kfall $
* static char *rcsid_kcmd_c =
@@ -52,7 +52,7 @@ static char sccsid[] = "@(#)krcmd.c 8.1 (Berkeley) 6/6/93";
#include <netinet/in.h>
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#include <stdio.h>
@@ -65,7 +65,7 @@ int kcmd __P((int *, char **, u_short, char *, char *, char *, int *,
/*
* krcmd: simplified version of Athena's "kcmd"
- * returns a socket attached to the destination, -1 or krb error on error
+ * returns a socket attached to the destination, -1 or krb error on error
* if fd2p is non-NULL, another socket is filled in for it
*/
@@ -93,7 +93,7 @@ krcmd(ahost, rport, remuser, cmd, fd2p, realm)
SERVICE_NAME,
realm,
(CREDENTIALS *) NULL, /* credentials not used */
- (bit_64 *) NULL, /* key schedule not used */
+ 0, /* key schedule not used */
(MSG_DAT *) NULL, /* MSG_DAT not used */
(struct sockaddr_in *) NULL, /* local addr not used */
(struct sockaddr_in *) NULL, /* foreign addr not used */
diff --git a/usr.bin/rlogin/rlogin.1 b/usr.bin/rlogin/rlogin.1
index 979658a..eea0c59 100644
--- a/usr.bin/rlogin/rlogin.1
+++ b/usr.bin/rlogin/rlogin.1
@@ -29,26 +29,21 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)rlogin.1 8.2 (Berkeley) 4/29/95
+.\" @(#)rlogin.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd April 29, 1995
+.Dd June 6, 1993
.Dt RLOGIN 1
.Os BSD 4.2
.Sh NAME
.Nm rlogin
.Nd remote login
.Sh SYNOPSIS
-.Nm rlogin
-.Op Fl 8EKLdx
+.Ar rlogin
+.Op Fl 8DEKLdx
.Op Fl e Ar char
.Op Fl k Ar realm
.Op Fl l Ar username
.Ar host
-.Nm rlogin
-.Op Fl 8EKLdx
-.Op Fl e Ar char
-.Op Fl k Ar realm
-.Ar username@host
.Sh DESCRIPTION
.Nm Rlogin
starts a terminal session on a remote host
@@ -68,6 +63,11 @@ option allows an eight-bit input data path at all times; otherwise
parity bits are stripped except when the remote side's stop and start
characters are other than
^S/^Q .
+.It Fl D
+The
+.Fl D
+option sets the TCP_NODELAY socket option which can improve interactive response
+at the expense of increased network load.
.It Fl E
The
.Fl E
@@ -170,10 +170,27 @@ The following environment variable is utilized by
Determines the user's terminal type.
.El
.Sh SEE ALSO
+.Xr login ,
.Xr rsh 1 ,
+.Xr telnet 1 ,
+.Xr setsockopt 2 ,
.Xr kerberos 3 ,
+.Xr krb_realmofhost 3 ,
.Xr krb_sendauth 3 ,
-.Xr krb_realmofhost 3
+.Xr ruserok 3 ,
+.Xr tty 4 ,
+.Xr hosts 5 ,
+.Xr rlogind 8 ,
+.Xr rshd 8
+
+.Sh FILES
+.Bl -tag -width /etc/hosts -compact
+.It Pa /etc/hosts
+.It Pa /etc/hosts.equiv
+.It Pa $HOME/.rhosts
+.It Pa $HOME/.klogin
+.El
+
.Sh HISTORY
The
.Nm rlogin
diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c
index 4aee20e..2ddc2b8 100644
--- a/usr.bin/rlogin/rlogin.c
+++ b/usr.bin/rlogin/rlogin.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 4/29/95";
+static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
@@ -49,18 +49,18 @@ static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 4/29/95";
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
-#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netinet/tcp.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
-#include <termios.h>
+#include <sgtty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -74,7 +74,7 @@ static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 4/29/95";
#endif
#ifdef KERBEROS
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#include "krb.h"
@@ -99,6 +99,12 @@ int eight, litout, rem;
int noescape;
u_char escapechar = '~';
+char *speeds[] = {
+ "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
+ "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
+#define MAX_SPEED_LENGTH (sizeof("115200") - 1)
+};
+
#ifdef OLDSUN
struct winsize {
unsigned short ws_row, ws_col;
@@ -111,21 +117,20 @@ struct winsize winsize;
void catch_child __P((int));
void copytochild __P((int));
-__dead void doit __P((sigset_t *));
-__dead void done __P((int));
+void doit __P((long)) __dead2;
+void done __P((int)) __dead2;
void echo __P((char));
u_int getescape __P((char *));
void lostpeer __P((int));
void mode __P((int));
void msg __P((char *));
void oob __P((int));
-int reader __P((sigset_t *));
+int reader __P((int));
void sendwindow __P((void));
void setsignal __P((int));
-int speed __P((int));
void sigwinch __P((int));
void stop __P((char));
-__dead void usage __P((void));
+void usage __P((void)) __dead2;
void writer __P((void));
void writeroob __P((int));
@@ -141,24 +146,25 @@ main(argc, argv)
int argc;
char *argv[];
{
+ extern char *optarg;
+ extern int optind;
struct passwd *pw;
struct servent *sp;
- sigset_t smask;
- uid_t uid;
- int argoff, ch, dflag, one;
+ struct sgttyb ttyb;
+ long omask;
+ int argoff, ch, dflag, Dflag, one, uid;
char *host, *p, *user, term[1024];
- struct sigaction sa;
- argoff = dflag = 0;
+ argoff = dflag = Dflag = 0;
one = 1;
host = user = NULL;
- if (p = strrchr(argv[0], '/'))
+ if (p = rindex(argv[0], '/'))
++p;
else
p = argv[0];
- if (strcmp(p, "rlogin") != 0)
+ if (strcmp(p, "rlogin"))
host = p;
/* handle "rlogin host flags" */
@@ -168,15 +174,18 @@ main(argc, argv)
}
#ifdef KERBEROS
-#define OPTIONS "8EKLde:k:l:x"
+#define OPTIONS "8DEKLde:k:l:x"
#else
-#define OPTIONS "8EKLde:l:"
+#define OPTIONS "8DEKLde:l:"
#endif
- while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
+ while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
switch(ch) {
case '8':
eight = 1;
break;
+ case 'D':
+ Dflag = 1;
+ break;
case 'E':
noescape = 1;
break;
@@ -208,7 +217,6 @@ main(argc, argv)
#ifdef KERBEROS
case 'x':
doencrypt = 1;
- des_set_key(cred.session, schedule);
break;
#endif
#endif
@@ -227,17 +235,9 @@ main(argc, argv)
if (*argv)
usage();
- if (!(pw = getpwuid(uid = getuid())))
- errx(1, "unknown user id.");
- /* Accept user1@host format, though "-l user2" overrides user1 */
- p = strchr(host, '@');
- if (p) {
- *p = '\0';
- if (!user && p > host)
- user = host;
- host = p + 1;
- if (*host == '\0')
- usage();
+ if (!(pw = getpwuid(uid = getuid()))) {
+ (void)fprintf(stderr, "rlogin: unknown user id.\n");
+ exit(1);
}
if (!user)
user = pw->pw_name;
@@ -255,34 +255,34 @@ main(argc, argv)
#endif
if (sp == NULL)
sp = getservbyname("login", "tcp");
- if (sp == NULL)
- errx(1, "login/tcp: unknown service.");
+ if (sp == NULL) {
+ (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
+ exit(1);
+ }
+
+#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1)
- (void)snprintf(term, sizeof(term), "%s/%d",
- ((p = getenv("TERM")) ? p : "network"),
- speed(0));
+ (void)strncpy(term, (p = getenv("TERM")) ? p : "network",
+ MAX_TERM_LENGTH);
+ term[MAX_TERM_LENGTH] = '\0';
+ if (ioctl(0, TIOCGETP, &ttyb) == 0) {
+ (void)strcat(term, "/");
+ (void)strcat(term, speeds[(int)ttyb.sg_ospeed]);
+ }
(void)get_window_size(0, &winsize);
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = lostpeer;
- (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
+ (void)signal(SIGPIPE, lostpeer);
/* will use SIGUSR1 for window size hack, so hold it off */
- sigemptyset(&smask);
- sigaddset(&smask, SIGURG);
- sigaddset(&smask, SIGUSR1);
- (void)sigprocmask(SIG_SETMASK, &smask, &smask);
+ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
/*
* We set SIGURG and SIGUSR1 below so that an
* incoming signal will be held pending rather than being
* discarded. Note that these routines will be ready to get
* a signal by the time that they are unblocked below.
*/
- sa.sa_handler = copytochild;
- (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
- sa.sa_handler = writeroob;
- (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0);
+ (void)signal(SIGURG, copytochild);
+ (void)signal(SIGUSR1, writeroob);
#ifdef KERBEROS
try_connect:
@@ -291,8 +291,11 @@ try_connect:
/* Fully qualify hostname (needed for krb_realmofhost). */
hp = gethostbyname(host);
- if (hp != NULL && !(host = strdup(hp->h_name)))
- errx(1, "%s", strerror(ENOMEM));
+ if (hp != NULL && !(host = strdup(hp->h_name))) {
+ (void)fprintf(stderr, "rlogin: %s\n",
+ strerror(ENOMEM));
+ exit(1);
+ }
rem = KSUCCESS;
errno = 0;
@@ -300,18 +303,22 @@ try_connect:
dest_realm = krb_realmofhost(host);
#ifdef CRYPT
- if (doencrypt)
+ if (doencrypt) {
rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
dest_realm, &cred, schedule);
- else
+ des_set_key_krb(&cred.session, schedule);
+ } else
#endif /* CRYPT */
rem = krcmd(&host, sp->s_port, user, term, 0,
dest_realm);
if (rem < 0) {
use_kerberos = 0;
sp = getservbyname("login", "tcp");
- if (sp == NULL)
- errx(1, "unknown service login/tcp.");
+ if (sp == NULL) {
+ (void)fprintf(stderr,
+ "rlogin: unknown service login/tcp.\n");
+ exit(1);
+ }
if (errno == ECONNREFUSED)
warning("remote host doesn't support Kerberos");
if (errno == ENOENT)
@@ -320,8 +327,11 @@ try_connect:
}
} else {
#ifdef CRYPT
- if (doencrypt)
- errx(1, "the -x flag requires Kerberos authentication.");
+ if (doencrypt) {
+ (void)fprintf(stderr,
+ "rlogin: the -x flag requires Kerberos authentication.\n");
+ exit(1);
+ }
#endif /* CRYPT */
rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
}
@@ -334,77 +344,56 @@ try_connect:
if (dflag &&
setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
- warn("setsockopt DEBUG (ignored)");
+ (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
+ strerror(errno));
+ if (Dflag &&
+ setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
+ perror("rlogin: setsockopt NODELAY (ignored)");
+
one = IPTOS_LOWDELAY;
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
- warn("setsockopt TOS (ignored)");
+ perror("rlogin: setsockopt TOS (ignored)");
(void)setuid(uid);
- doit(&smask);
+ doit(omask);
/*NOTREACHED*/
}
-#if BSD >= 198810
-int
-speed(fd)
- int fd;
-{
- struct termios tt;
-
- (void)tcgetattr(fd, &tt);
-
- return ((int) cfgetispeed(&tt));
-}
-#else
-int speeds[] = { /* for older systems, B0 .. EXTB */
- 0, 50, 75, 110,
- 134, 150, 200, 300,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400
-};
-
-int
-speed(fd)
- int fd;
-{
- struct termios tt;
-
- (void)tcgetattr(fd, &tt);
-
- return (speeds[(int)cfgetispeed(&tt)]);
-}
-#endif
-
-pid_t child;
-struct termios deftt;
-struct termios nott;
+int child, defflags, deflflags, tabflag;
+char deferase, defkill;
+struct tchars deftc;
+struct ltchars defltc;
+struct tchars notc = { -1, -1, -1, -1, -1, -1 };
+struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
void
-doit(smask)
- sigset_t *smask;
+doit(omask)
+ long omask;
{
- int i;
- struct sigaction sa;
-
- for (i = 0; i < NCCS; i++)
- nott.c_cc[i] = _POSIX_VDISABLE;
- tcgetattr(0, &deftt);
- nott.c_cc[VSTART] = deftt.c_cc[VSTART];
- nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = SIG_IGN;
- (void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ struct sgttyb sb;
+
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ defflags = sb.sg_flags;
+ tabflag = defflags & TBDELAY;
+ defflags &= ECHO | CRMOD;
+ deferase = sb.sg_erase;
+ defkill = sb.sg_kill;
+ (void)ioctl(0, TIOCLGET, &deflflags);
+ (void)ioctl(0, TIOCGETC, &deftc);
+ notc.t_startc = deftc.t_startc;
+ notc.t_stopc = deftc.t_stopc;
+ (void)ioctl(0, TIOCGLTC, &defltc);
+ (void)signal(SIGINT, SIG_IGN);
setsignal(SIGHUP);
setsignal(SIGQUIT);
child = fork();
if (child == -1) {
- warn("fork");
+ (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
done(1);
}
if (child == 0) {
mode(1);
- if (reader(smask) == 0) {
+ if (reader(omask) == 0) {
msg("connection closed.");
exit(0);
}
@@ -420,9 +409,8 @@ doit(smask)
* signals to the child. We can now unblock SIGURG and SIGUSR1
* that were set above.
*/
- (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
- sa.sa_handler = catch_child;
- (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
+ (void)sigsetmask(omask);
+ (void)signal(SIGCHLD, catch_child);
writer();
msg("closed connection.");
done(0);
@@ -433,41 +421,25 @@ void
setsignal(sig)
int sig;
{
- struct sigaction sa;
- sigset_t sigs;
-
- sigemptyset(&sigs);
- sigaddset(&sigs, sig);
- sigprocmask(SIG_BLOCK, &sigs, &sigs);
-
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = exit;
- sa.sa_flags = SA_RESTART;
- (void)sigaction(sig, &sa, &sa);
- if (sa.sa_handler == SIG_IGN)
- (void)sigaction(sig, &sa, (struct sigaction *) 0);
+ int omask = sigblock(sigmask(sig));
- (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
+ if (signal(sig, exit) == SIG_IGN)
+ (void)signal(sig, SIG_IGN);
+ (void)sigsetmask(omask);
}
-__dead void
+void
done(status)
int status;
{
- pid_t w;
- int wstatus;
- struct sigaction sa;
+ int w, wstatus;
mode(0);
if (child > 0) {
/* make sure catch_child does not snap it up */
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = 0;
- (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
+ (void)signal(SIGCHLD, SIG_DFL);
if (kill(child, SIGKILL) >= 0)
- while ((w = wait(&wstatus)) > 0 && w != child)
- continue;
+ while ((w = wait(&wstatus)) > 0 && w != child);
}
exit(status);
}
@@ -482,14 +454,9 @@ void
writeroob(signo)
int signo;
{
- struct sigaction sa;
-
if (dosigwinch == 0) {
sendwindow();
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = sigwinch;
- sa.sa_flags = SA_RESTART;
- (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
+ (void)signal(SIGWINCH, sigwinch);
}
dosigwinch = 1;
}
@@ -498,16 +465,16 @@ void
catch_child(signo)
int signo;
{
- int status;
- pid_t pid;
+ union wait status;
+ int pid;
for (;;) {
- pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
+ pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
if (pid == 0)
return;
/* if the child (reader) dies, just quit */
if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
- done(WEXITSTATUS(status) | WTERMSIG(status));
+ done((int)(status.w_termsig | status.w_retcode));
}
/* NOTREACHED */
}
@@ -548,11 +515,11 @@ writer()
}
} else if (local) {
local = 0;
- if (c == '.' || c == deftt.c_cc[VEOF]) {
+ if (c == '.' || c == deftc.t_eofc) {
echo(c);
break;
}
- if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) {
+ if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
bol = 1;
echo(c);
stop(c);
@@ -584,8 +551,8 @@ writer()
msg("line gone");
break;
}
- bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] ||
- c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] ||
+ bol = c == defkill || c == deftc.t_eofc ||
+ c == deftc.t_intrc || c == defltc.t_suspc ||
c == '\r' || c == '\n';
}
}
@@ -625,16 +592,10 @@ stop(cmdc)
char cmdc;
#endif
{
- struct sigaction sa;
-
mode(0);
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = SA_RESTART;
- (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
- (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
- sa.sa_handler = catch_child;
- (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
+ (void)signal(SIGCHLD, SIG_IGN);
+ (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
+ (void)signal(SIGCHLD, catch_child);
mode(1);
sigwinch(0); /* check for size changes */
}
@@ -646,7 +607,7 @@ sigwinch(signo)
struct winsize ws;
if (dosigwinch && get_window_size(0, &ws) == 0 &&
- memcmp(&ws, &winsize, sizeof(ws))) {
+ bcmp(&ws, &winsize, sizeof(ws))) {
winsize = ws;
sendwindow();
}
@@ -688,15 +649,14 @@ sendwindow()
#define WRITING 2
jmp_buf rcvtop;
-pid_t ppid;
-int rcvcnt, rcvstate;
+int ppid, rcvcnt, rcvstate;
char rcvbuf[8 * 1024];
void
oob(signo)
int signo;
{
- struct termios tt;
+ struct sgttyb sb;
int atmark, n, out, rcvd;
char waste[BUFSIZ], mark;
@@ -731,24 +691,29 @@ oob(signo)
(void)kill(ppid, SIGUSR1);
}
if (!eight && (mark & TIOCPKT_NOSTOP)) {
- tcgetattr(0, &tt);
- tt.c_iflag &= ~(IXON | IXOFF);
- tt.c_cc[VSTOP] = _POSIX_VDISABLE;
- tt.c_cc[VSTART] = _POSIX_VDISABLE;
- tcsetattr(0, TCSANOW, &tt);
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~CBREAK;
+ sb.sg_flags |= RAW;
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ notc.t_stopc = -1;
+ notc.t_startc = -1;
+ (void)ioctl(0, TIOCSETC, (char *)&notc);
}
if (!eight && (mark & TIOCPKT_DOSTOP)) {
- tcgetattr(0, &tt);
- tt.c_iflag |= (IXON|IXOFF);
- tt.c_cc[VSTOP] = deftt.c_cc[VSTOP];
- tt.c_cc[VSTART] = deftt.c_cc[VSTART];
- tcsetattr(0, TCSANOW, &tt);
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~RAW;
+ sb.sg_flags |= CBREAK;
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ notc.t_stopc = deftc.t_stopc;
+ notc.t_startc = deftc.t_startc;
+ (void)ioctl(0, TIOCSETC, (char *)&notc);
}
if (mark & TIOCPKT_FLUSHWRITE) {
(void)ioctl(1, TIOCFLUSH, (char *)&out);
for (;;) {
if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
- warn("ioctl SIOCATMARK (ignored)");
+ (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
+ strerror(errno));
break;
}
if (atmark)
@@ -780,29 +745,23 @@ oob(signo)
/* reader: read from remote: line -> 1 */
int
-reader(smask)
- sigset_t *smask;
+reader(omask)
+ int omask;
{
- pid_t pid;
- int n, remaining;
+ int pid, n, remaining;
char *bufp;
- struct sigaction sa;
#if BSD >= 43 || defined(SUNOS4)
pid = getpid(); /* modern systems use positives for pid */
#else
pid = -getpid(); /* old broken systems use negatives */
#endif
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = SIG_IGN;
- (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
- sa.sa_handler = oob;
- (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
+ (void)signal(SIGTTOU, SIG_IGN);
+ (void)signal(SIGURG, oob);
ppid = getppid();
(void)fcntl(rem, F_SETOWN, pid);
(void)setjmp(rcvtop);
- (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
+ (void)sigsetmask(omask);
bufp = rcvbuf;
for (;;) {
while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
@@ -832,7 +791,8 @@ reader(smask)
if (rcvcnt < 0) {
if (errno == EINTR)
continue;
- warn("read");
+ (void)fprintf(stderr, "rlogin: read: %s.\n",
+ strerror(errno));
return (-1);
}
}
@@ -842,44 +802,49 @@ void
mode(f)
int f;
{
- struct termios tt;
-
- switch (f) {
+ struct ltchars *ltc;
+ struct sgttyb sb;
+ struct tchars *tc;
+ int lflags;
+
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ (void)ioctl(0, TIOCLGET, (char *)&lflags);
+ switch(f) {
case 0:
- tcsetattr(0, TCSADRAIN, &deftt);
+ sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
+ sb.sg_flags |= defflags|tabflag;
+ tc = &deftc;
+ ltc = &defltc;
+ sb.sg_kill = defkill;
+ sb.sg_erase = deferase;
+ lflags = deflflags;
break;
case 1:
- tt = deftt;
- tt.c_oflag &= ~(OPOST);
- tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
- tt.c_iflag &= ~(ICRNL);
- tt.c_cc[VMIN] = 1;
- tt.c_cc[VTIME] = 0;
- if (eight) {
- tt.c_iflag &= ~(IXON | IXOFF | ISTRIP);
- tt.c_cc[VSTOP] = _POSIX_VDISABLE;
- tt.c_cc[VSTART] = _POSIX_VDISABLE;
- }
- /*if (litout)
- lflags |= LLITOUT;*/
- tcsetattr(0, TCSADRAIN, &tt);
+ sb.sg_flags |= (eight ? RAW : CBREAK);
+ sb.sg_flags &= ~defflags;
+ /* preserve tab delays, but turn off XTABS */
+ if ((sb.sg_flags & TBDELAY) == XTABS)
+ sb.sg_flags &= ~TBDELAY;
+ tc = &notc;
+ ltc = &noltc;
+ sb.sg_kill = sb.sg_erase = -1;
+ if (litout)
+ lflags |= LLITOUT;
break;
-
default:
return;
}
+ (void)ioctl(0, TIOCSLTC, (char *)ltc);
+ (void)ioctl(0, TIOCSETC, (char *)tc);
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ (void)ioctl(0, TIOCLSET, (char *)&lflags);
}
void
lostpeer(signo)
int signo;
{
- struct sigaction sa;
-
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = SIG_IGN;
- (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
+ (void)signal(SIGPIPE, SIG_IGN);
msg("\007connection closed.");
done(1);
}
@@ -889,7 +854,6 @@ void
copytochild(signo)
int signo;
{
-
(void)kill(child, SIGURG);
}
@@ -897,7 +861,6 @@ void
msg(str)
char *str;
{
-
(void)fprintf(stderr, "rlogin: %s\r\n", str);
}
@@ -926,19 +889,19 @@ warning(fmt, va_alist)
}
#endif
-__dead void
+void
usage()
{
(void)fprintf(stderr,
- "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
+ "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
#ifdef KERBEROS
#ifdef CRYPT
- "8EKLx", " [-k realm] ");
+ "8DEKLx", " [-k realm] ");
#else
- "8EKL", " [-k realm] ");
+ "8DEKL", " [-k realm] ");
#endif
#else
- "8EL", " ");
+ "8DEL", " ");
#endif
exit(1);
}
diff --git a/usr.bin/rpcgen/Makefile b/usr.bin/rpcgen/Makefile
new file mode 100644
index 0000000..d0e4c14
--- /dev/null
+++ b/usr.bin/rpcgen/Makefile
@@ -0,0 +1,13 @@
+SRCS= rpc_main.c rpc_clntout.c rpc_cout.c rpc_hout.c rpc_parse.c \
+ rpc_sample.c rpc_scan.c rpc_svcout.c rpc_tblout.c rpc_util.c
+
+PROG= rpcgen
+MAN1= rpcgen.1
+
+#
+# This is a kludge to work around the fact that this program
+# uses 'inline' as a variable name.
+#
+CFLAGS+=-Dinline=rpcgen_inline
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rpcgen/rpc_clntout.c b/usr.bin/rpcgen/rpc_clntout.c
new file mode 100644
index 0000000..e4a9db7
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_clntout.c
@@ -0,0 +1,330 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_clntout.c 1.15 94/04/25 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_clntout.c 1.11 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsytsems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rpc/types.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+extern void pdeclaration __P(( char *, declaration *, int, char * ));
+void printarglist __P(( proc_list *, char *, char *, char *));
+static void write_program __P(( definition * ));
+static void printbody __P(( proc_list * ));
+
+static char RESULT[] = "clnt_res";
+
+
+#define DEFAULT_TIMEOUT 25 /* in seconds */
+
+
+void
+write_stubs()
+{
+ list *l;
+ definition *def;
+
+ f_print(fout,
+ "\n/* Default timeout can be changed using clnt_control() */\n");
+ f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n",
+ DEFAULT_TIMEOUT);
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_program(def);
+ }
+ }
+}
+
+static void
+write_program(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+ if (mtflag == 0) {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*\n");
+ pvname(proc->proc_name, vp->vers_num);
+ printarglist(proc, RESULT, "clnt", "CLIENT *");
+ } else {
+ f_print(fout, "enum clnt_stat \n");
+ pvname(proc->proc_name, vp->vers_num);
+ printarglist(proc, RESULT, "clnt", "CLIENT *");
+
+ }
+ f_print(fout, "{\n");
+ printbody(proc);
+
+ f_print(fout, "}\n");
+ }
+ }
+}
+
+/*
+ * Writes out declarations of procedure's argument list.
+ * In either ANSI C style, in one of old rpcgen style (pass by reference),
+ * or new rpcgen style (multiple arguments, pass by value);
+ */
+
+/* sample addargname = "clnt"; sample addargtype = "CLIENT * " */
+
+void printarglist(proc, result, addargname, addargtype)
+ proc_list *proc;
+ char *result;
+ char* addargname, * addargtype;
+{
+
+ decl_list *l;
+
+ if (!newstyle) {
+ /* old style: always pass argument by reference */
+ if (Cflag) { /* C++ style heading */
+ f_print(fout, "(");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 1);
+
+ if (mtflag) {/* Generate result field */
+ f_print(fout, "*argp, ");
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*%s, %s%s)\n",
+ result, addargtype, addargname);
+ } else
+ f_print(fout, "*argp, %s%s)\n", addargtype, addargname);
+ } else {
+ if (!mtflag)
+ f_print(fout, "(argp, %s)\n", addargname);
+ else
+ f_print(fout, "(argp, %s, %s)\n",
+ result, addargname);
+ f_print(fout, "\t");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 1);
+ f_print(fout, "*argp;\n");
+ if (mtflag) {
+ f_print(fout, "\t");
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*%s;\n", result);
+ }
+ }
+ } else if (streq(proc->args.decls->decl.type, "void")) {
+ /* newstyle, 0 argument */
+ if (mtflag) {
+ f_print(fout, "(");
+
+
+ if (Cflag) {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*%s, %s%s)\n",
+ result, addargtype, addargname);
+ }
+ else
+ f_print(fout, "(%s)\n", addargname);
+
+ } else
+ if (Cflag)
+ f_print(fout, "(%s%s)\n", addargtype, addargname);
+ else
+ f_print(fout, "(%s)\n", addargname);
+ } else {
+ /* new style, 1 or multiple arguments */
+ if (!Cflag) {
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next)
+ f_print(fout, "%s, ", l->decl.name);
+ if (mtflag)
+ f_print(fout, "%s, ", result);
+
+ f_print(fout, "%s)\n", addargname);
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pdeclaration(proc->args.argname,
+ &l->decl, 1, ";\n");
+ }
+ if (mtflag) {
+ f_print(fout, "\t");
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*%s;\n", result);
+ }
+
+ } else { /* C++ style header */
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pdeclaration(proc->args.argname, &l->decl, 0,
+ ", ");
+ }
+ if (mtflag) {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*%s, ", result);
+
+ }
+ f_print(fout, "%s%s)\n", addargtype, addargname);
+ }
+ }
+
+ if (!Cflag)
+ f_print(fout, "\t%s%s;\n", addargtype, addargname);
+}
+
+
+
+static char *
+ampr(type)
+ char *type;
+{
+ if (isvectordef(type, REL_ALIAS)) {
+ return ("");
+ } else {
+ return ("&");
+ }
+}
+
+static void
+printbody(proc)
+ proc_list *proc;
+{
+ decl_list *l;
+ bool_t args2 = (proc->arg_num > 1);
+
+ /*
+ * For new style with multiple arguments, need a structure in which
+ * to stuff the arguments.
+ */
+
+
+ if (newstyle && args2) {
+ f_print(fout, "\t%s", proc->args.argname);
+ f_print(fout, " arg;\n");
+ }
+ if (!mtflag) {
+ f_print(fout, "\tstatic ");
+ if (streq(proc->res_type, "void")) {
+ f_print(fout, "char ");
+ } else {
+ ptype(proc->res_prefix, proc->res_type, 0);
+ }
+ f_print(fout, "%s;\n", RESULT);
+ f_print(fout, "\n");
+ f_print(fout, "\tmemset((char *)%s%s, 0, sizeof (%s));\n",
+ ampr(proc->res_type), RESULT, RESULT);
+
+ }
+ if (newstyle && !args2 &&
+ (streq(proc->args.decls->decl.type, "void"))) {
+ /* newstyle, 0 arguments */
+
+ if (mtflag)
+ f_print(fout, "\t return ");
+ else
+ f_print(fout, "\t if ");
+
+ f_print(fout,
+ "(clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_void, ",
+ proc->proc_name);
+ f_print(fout,
+ "(caddr_t) NULL,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,",
+ stringfix(proc->res_type), (mtflag)?"":ampr(proc->res_type),
+ RESULT);
+
+ if (mtflag)
+ f_print(fout, "\n\t\tTIMEOUT));\n}\n");
+ else
+ f_print(fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
+
+ } else if (newstyle && args2) {
+ /*
+ * Newstyle, multiple arguments
+ * stuff arguments into structure
+ */
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ f_print(fout, "\targ.%s = %s;\n",
+ l->decl.name, l->decl.name);
+ }
+ if (mtflag)
+ f_print(fout, "\treturn ");
+ else
+ f_print(fout, "\tif ");
+ f_print(fout,
+ "(clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_%s",
+ proc->proc_name,proc->args.argname);
+ f_print(fout,
+ ", (caddr_t) &arg,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,",
+ stringfix(proc->res_type), (mtflag)?"":ampr(proc->res_type),
+ RESULT);
+ if (mtflag)
+ f_print(fout, "\n\t\tTIMEOUT));\n");
+ else
+ f_print(fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
+ } else { /* single argument, new or old style */
+ if (!mtflag)
+ f_print(fout,
+ "\tif (clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\tTIMEOUT) != RPC_SUCCESS) {\n",
+ proc->proc_name,
+ stringfix(proc->args.decls->decl.type),
+ (newstyle ? "&" : ""),
+ (newstyle ? proc->args.decls->decl.name : "argp"),
+ stringfix(proc->res_type), ampr(proc->res_type),
+ RESULT);
+ else
+
+ f_print(fout,
+ "\treturn (clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\tTIMEOUT));\n",
+ proc->proc_name,
+ stringfix(proc->args.decls->decl.type),
+ (newstyle ? "&" : ""),
+ (newstyle ? proc->args.decls->decl.name : "argp"),
+ stringfix(proc->res_type), "",
+ RESULT);
+ }
+ if (!mtflag) {
+ f_print(fout, "\t\treturn (NULL);\n");
+ f_print(fout, "\t}\n");
+
+ if (streq(proc->res_type, "void")) {
+ f_print(fout, "\treturn ((void *)%s%s);\n",
+ ampr(proc->res_type), RESULT);
+ } else {
+ f_print(fout, "\treturn (%s%s);\n",
+ ampr(proc->res_type), RESULT);
+ }
+ }
+}
diff --git a/usr.bin/rpcgen/rpc_cout.c b/usr.bin/rpcgen/rpc_cout.c
new file mode 100644
index 0000000..7445fd7
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_cout.c
@@ -0,0 +1,758 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_cout.c 1.14 93/07/05 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_cout.c 1.13 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_cout.c, XDR routine outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static void print_header __P(( definition * ));
+static void print_trailer __P(( void ));
+static void print_stat __P(( int , declaration * ));
+static void emit_enum __P(( definition * ));
+static void emit_program __P(( definition * ));
+static void emit_union __P(( definition * ));
+static void emit_struct __P(( definition * ));
+static void emit_typedef __P(( definition * ));
+static void emit_inline __P(( int, declaration *, int ));
+static void emit_single_in_line __P(( int, declaration *, int, relation ));
+
+/*
+ * Emit the C-routine for the given definition
+ */
+void
+emit(def)
+ definition *def;
+{
+ if (def->def_kind == DEF_CONST) {
+ return;
+ }
+ if (def->def_kind == DEF_PROGRAM) {
+ emit_program(def);
+ return;
+ }
+ if (def->def_kind == DEF_TYPEDEF) {
+ /*
+ * now we need to handle declarations like
+ * struct typedef foo foo;
+ * since we dont want this to be expanded into 2 calls to xdr_foo
+ */
+
+ if (strcmp(def->def.ty.old_type, def->def_name) == 0)
+ return;
+ };
+ print_header(def);
+ switch (def->def_kind) {
+ case DEF_UNION:
+ emit_union(def);
+ break;
+ case DEF_ENUM:
+ emit_enum(def);
+ break;
+ case DEF_STRUCT:
+ emit_struct(def);
+ break;
+ case DEF_TYPEDEF:
+ emit_typedef(def);
+ break;
+ /* DEF_CONST and DEF_PROGRAM have already been handled */
+ default:
+ }
+ print_trailer();
+}
+
+static int
+findtype(def, type)
+ definition *def;
+ char *type;
+{
+
+ if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) {
+ return (0);
+ } else {
+ return (streq(def->def_name, type));
+ }
+}
+
+static int
+undefined(type)
+ char *type;
+{
+ definition *def;
+
+ def = (definition *) FINDVAL(defined, type, findtype);
+ return (def == NULL);
+}
+
+
+static void
+print_generic_header(procname, pointerp)
+ char* procname;
+ int pointerp;
+{
+ f_print(fout, "\n");
+ f_print(fout, "bool_t\n");
+ if (Cflag) {
+ f_print(fout, "xdr_%s(", procname);
+ f_print(fout, "register XDR *xdrs, ");
+ f_print(fout, "%s ", procname);
+ if (pointerp)
+ f_print(fout, "*");
+ f_print(fout, "objp)\n{\n\n");
+ } else {
+ f_print(fout, "xdr_%s(xdrs, objp)\n", procname);
+ f_print(fout, "\tregister XDR *xdrs;\n");
+ f_print(fout, "\t%s ", procname);
+ if (pointerp)
+ f_print(fout, "*");
+ f_print(fout, "objp;\n{\n\n");
+ }
+}
+
+static void
+print_header(def)
+ definition *def;
+{
+ print_generic_header(def->def_name,
+ def->def_kind != DEF_TYPEDEF ||
+ !isvectordef(def->def.ty.old_type,
+ def->def.ty.rel));
+ /* Now add Inline support */
+
+ if (inline == 0)
+ return;
+ /* May cause lint to complain. but ... */
+ f_print(fout, "\tregister long *buf;\n\n");
+}
+
+static void
+print_prog_header(plist)
+ proc_list *plist;
+{
+ print_generic_header(plist->args.argname, 1);
+}
+
+static void
+print_trailer()
+{
+ f_print(fout, "\treturn (TRUE);\n");
+ f_print(fout, "}\n");
+}
+
+
+static void
+print_ifopen(indent, name)
+ int indent;
+ char *name;
+{
+ tabify(fout, indent);
+ f_print(fout, "if (!xdr_%s(xdrs", name);
+}
+
+static void
+print_ifarg(arg)
+ char *arg;
+{
+ f_print(fout, ", %s", arg);
+}
+
+static void
+print_ifsizeof(indent, prefix, type)
+ int indent;
+ char *prefix;
+ char *type;
+{
+ if (indent) {
+ f_print(fout, ",\n");
+ tabify(fout, indent);
+ } else {
+ f_print(fout, ", ");
+ }
+ if (streq(type, "bool")) {
+ f_print(fout, "sizeof (bool_t), (xdrproc_t) xdr_bool");
+ } else {
+ f_print(fout, "sizeof (");
+ if (undefined(type) && prefix) {
+ f_print(fout, "%s ", prefix);
+ }
+ f_print(fout, "%s), (xdrproc_t) xdr_%s", type, type);
+ }
+}
+
+static void
+print_ifclose(indent)
+ int indent;
+{
+ f_print(fout, "))\n");
+ tabify(fout, indent);
+ f_print(fout, "\treturn (FALSE);\n");
+}
+
+static void
+print_ifstat(indent, prefix, type, rel, amax, objname, name)
+ int indent;
+ char *prefix;
+ char *type;
+ relation rel;
+ char *amax;
+ char *objname;
+ char *name;
+{
+ char *alt = NULL;
+
+ switch (rel) {
+ case REL_POINTER:
+ print_ifopen(indent, "pointer");
+ print_ifarg("(char **)");
+ f_print(fout, "%s", objname);
+ print_ifsizeof(0, prefix, type);
+ break;
+ case REL_VECTOR:
+ if (streq(type, "string")) {
+ alt = "string";
+ } else if (streq(type, "opaque")) {
+ alt = "opaque";
+ }
+ if (alt) {
+ print_ifopen(indent, alt);
+ print_ifarg(objname);
+ } else {
+ print_ifopen(indent, "vector");
+ print_ifarg("(char *)");
+ f_print(fout, "%s", objname);
+ }
+ print_ifarg(amax);
+ if (!alt) {
+ print_ifsizeof(indent + 1, prefix, type);
+ }
+ break;
+ case REL_ARRAY:
+ if (streq(type, "string")) {
+ alt = "string";
+ } else if (streq(type, "opaque")) {
+ alt = "bytes";
+ }
+ if (streq(type, "string")) {
+ print_ifopen(indent, alt);
+ print_ifarg(objname);
+ } else {
+ if (alt) {
+ print_ifopen(indent, alt);
+ } else {
+ print_ifopen(indent, "array");
+ }
+ print_ifarg("(char **)");
+ if (*objname == '&') {
+ f_print(fout, "%s.%s_val, (u_int *) %s.%s_len",
+ objname, name, objname, name);
+ } else {
+ f_print(fout,
+ "&%s->%s_val, (u_int *) &%s->%s_len",
+ objname, name, objname, name);
+ }
+ }
+ print_ifarg(amax);
+ if (!alt) {
+ print_ifsizeof(indent + 1, prefix, type);
+ }
+ break;
+ case REL_ALIAS:
+ print_ifopen(indent, type);
+ print_ifarg(objname);
+ break;
+ }
+ print_ifclose(indent);
+}
+
+/* ARGSUSED */
+static void
+emit_enum(def)
+ definition *def;
+{
+ print_ifopen(1, "enum");
+ print_ifarg("(enum_t *)objp");
+ print_ifclose(1);
+}
+
+static void
+emit_program(def)
+ definition *def;
+{
+ decl_list *dl;
+ version_list *vlist;
+ proc_list *plist;
+
+ for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next)
+ for (plist = vlist->procs; plist != NULL; plist = plist->next) {
+ if (!newstyle || plist->arg_num < 2)
+ continue; /* old style, or single argument */
+ print_prog_header(plist);
+ for (dl = plist->args.decls; dl != NULL;
+ dl = dl->next)
+ print_stat(1, &dl->decl);
+ print_trailer();
+ }
+}
+
+
+static void
+emit_union(def)
+ definition *def;
+{
+ declaration *dflt;
+ case_list *cl;
+ declaration *cs;
+ char *object;
+ char *vecformat = "objp->%s_u.%s";
+ char *format = "&objp->%s_u.%s";
+
+ print_stat(1, &def->def.un.enum_decl);
+ f_print(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name);
+ for (cl = def->def.un.cases; cl != NULL; cl = cl->next) {
+
+ f_print(fout, "\tcase %s:\n", cl->case_name);
+ if (cl->contflag == 1) /* a continued case statement */
+ continue;
+ cs = &cl->case_decl;
+ if (!streq(cs->type, "void")) {
+ object = alloc(strlen(def->def_name) + strlen(format) +
+ strlen(cs->name) + 1);
+ if (isvectordef (cs->type, cs->rel)) {
+ s_print(object, vecformat, def->def_name,
+ cs->name);
+ } else {
+ s_print(object, format, def->def_name,
+ cs->name);
+ }
+ print_ifstat(2, cs->prefix, cs->type, cs->rel,
+ cs->array_max, object, cs->name);
+ free(object);
+ }
+ f_print(fout, "\t\tbreak;\n");
+ }
+ dflt = def->def.un.default_decl;
+ if (dflt != NULL) {
+ if (!streq(dflt->type, "void")) {
+ f_print(fout, "\tdefault:\n");
+ object = alloc(strlen(def->def_name) + strlen(format) +
+strlen(dflt->name) + 1);
+ if (isvectordef (dflt->type, dflt->rel)) {
+ s_print(object, vecformat, def->def_name,
+ dflt->name);
+ } else {
+ s_print(object, format, def->def_name,
+ dflt->name);
+ }
+
+ print_ifstat(2, dflt->prefix, dflt->type, dflt->rel,
+ dflt->array_max, object, dflt->name);
+ free(object);
+ f_print(fout, "\t\tbreak;\n");
+ } else {
+ f_print(fout, "\tdefault:\n");
+ f_print(fout, "\t\tbreak;\n");
+ }
+ } else {
+ f_print(fout, "\tdefault:\n");
+ f_print(fout, "\t\treturn (FALSE);\n");
+ }
+
+ f_print(fout, "\t}\n");
+}
+
+static void
+inline_struct(def, flag)
+definition *def;
+int flag;
+{
+ decl_list *dl;
+ int i, size;
+ decl_list *cur, *psav;
+ bas_type *ptr;
+ char *sizestr, *plus;
+ char ptemp[256];
+ int indent = 1;
+
+ if (flag == PUT)
+ f_print(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n");
+ else
+ f_print(fout, "\t\treturn (TRUE);\n\t} else if (xdrs->x_op == XDR_DECODE) {\n");
+
+ i = 0;
+ size = 0;
+ sizestr = NULL;
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { /* xxx */
+ /* now walk down the list and check for basic types */
+ if ((dl->decl.prefix == NULL) &&
+ ((ptr = find_type(dl->decl.type)) != NULL) &&
+ ((dl->decl.rel == REL_ALIAS) ||
+ (dl->decl.rel == REL_VECTOR))){
+ if (i == 0)
+ cur = dl;
+ i++;
+
+ if (dl->decl.rel == REL_ALIAS)
+ size += ptr->length;
+ else {
+ /* this code is required to handle arrays */
+ if (sizestr == NULL)
+ plus = "";
+ else
+ plus = " + ";
+
+ if (ptr->length != 1)
+ s_print(ptemp, "%s%s * %d",
+ plus, dl->decl.array_max,
+ ptr->length);
+ else
+ s_print(ptemp, "%s%s", plus,
+ dl->decl.array_max);
+
+ /* now concatenate to sizestr !!!! */
+ if (sizestr == NULL)
+ sizestr = strdup(ptemp);
+ else{
+ sizestr = realloc(sizestr,
+ strlen(sizestr)
+ +strlen(ptemp)+1);
+ if (sizestr == NULL){
+ f_print(stderr,
+ "Fatal error : no memory\n");
+ crash();
+ };
+ sizestr = strcat(sizestr, ptemp);
+ /* build up length of array */
+ }
+ }
+ } else {
+ if (i > 0)
+ if (sizestr == NULL && size < inline){
+ /*
+ * don't expand into inline code
+ * if size < inline
+ */
+ while (cur != dl){
+ print_stat(indent + 1, &cur->decl);
+ cur = cur->next;
+ }
+ } else {
+ /* were already looking at a xdr_inlineable structure */
+ tabify(fout, indent + 1);
+ if (sizestr == NULL)
+ f_print(fout, "buf = XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);",
+ size);
+ else
+ if (size == 0)
+ f_print(fout,
+ "buf = XDR_INLINE(xdrs, (%s) * BYTES_PER_XDR_UNIT);",
+ sizestr);
+ else
+ f_print(fout,
+ "buf = XDR_INLINE(xdrs, (%d + (%s)) * BYTES_PER_XDR_UNIT);",
+ size, sizestr);
+
+ f_print(fout, "\n");
+ tabify(fout, indent + 1);
+ f_print(fout,
+ "if (buf == NULL) {\n");
+
+ psav = cur;
+ while (cur != dl){
+ print_stat(indent + 2, &cur->decl);
+ cur = cur->next;
+ }
+
+ f_print(fout, "\n\t\t} else {\n");
+
+ cur = psav;
+ while (cur != dl){
+ emit_inline(indent + 2, &cur->decl, flag);
+ cur = cur->next;
+ }
+
+ tabify(fout, indent + 1);
+ f_print(fout, "}\n");
+ }
+ size = 0;
+ i = 0;
+ sizestr = NULL;
+ print_stat(indent + 1, &dl->decl);
+ }
+ }
+
+ if (i > 0)
+ if (sizestr == NULL && size < inline){
+ /* don't expand into inline code if size < inline */
+ while (cur != dl){
+ print_stat(indent + 1, &cur->decl);
+ cur = cur->next;
+ }
+ } else {
+ /* were already looking at a xdr_inlineable structure */
+ if (sizestr == NULL)
+ f_print(fout, "\t\tbuf = XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);",
+ size);
+ else
+ if (size == 0)
+ f_print(fout,
+ "\t\tbuf = XDR_INLINE(xdrs, (%s) * BYTES_PER_XDR_UNIT);",
+ sizestr);
+ else
+ f_print(fout,
+ "\t\tbuf = XDR_INLINE(xdrs, (%d + (%s)) * BYTES_PER_XDR_UNIT);",
+ size, sizestr);
+
+ f_print(fout, "\n\t\tif (buf == NULL) {\n");
+ psav = cur;
+ while (cur != NULL){
+ print_stat(indent + 2, &cur->decl);
+ cur = cur->next;
+ }
+ f_print(fout, "\t\t} else {\n");
+
+ cur = psav;
+ while (cur != dl){
+ emit_inline(indent + 2, &cur->decl, flag);
+ cur = cur->next;
+ }
+ f_print(fout, "\t\t}\n");
+ }
+}
+
+static void
+emit_struct(def)
+ definition *def;
+{
+ decl_list *dl;
+ int j, size, flag;
+ bas_type *ptr;
+ int can_inline;
+
+ if (inline == 0) {
+ /* No xdr_inlining at all */
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(1, &dl->decl);
+ return;
+ }
+
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ if (dl->decl.rel == REL_VECTOR){
+ f_print(fout, "\tint i;\n");
+ break;
+ }
+
+ size = 0;
+ can_inline = 0;
+ /*
+ * Make a first pass and see if inling is possible.
+ */
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ if ((dl->decl.prefix == NULL) &&
+ ((ptr = find_type(dl->decl.type)) != NULL) &&
+ ((dl->decl.rel == REL_ALIAS)||
+ (dl->decl.rel == REL_VECTOR))){
+ if (dl->decl.rel == REL_ALIAS)
+ size += ptr->length;
+ else {
+ can_inline = 1;
+ break; /* can be inlined */
+ }
+ } else {
+ if (size >= inline){
+ can_inline = 1;
+ break; /* can be inlined */
+ }
+ size = 0;
+ }
+ if (size >= inline)
+ can_inline = 1;
+
+ if (can_inline == 0){ /* can not inline, drop back to old mode */
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(1, &dl->decl);
+ return;
+ }
+
+ flag = PUT;
+ for (j = 0; j < 2; j++){
+ inline_struct(def, flag);
+ if (flag == PUT)
+ flag = GET;
+ }
+
+ f_print(fout, "\t\treturn (TRUE);\n\t}\n\n");
+
+ /* now take care of XDR_FREE case */
+
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(1, &dl->decl);
+
+}
+
+static void
+emit_typedef(def)
+ definition *def;
+{
+ char *prefix = def->def.ty.old_prefix;
+ char *type = def->def.ty.old_type;
+ char *amax = def->def.ty.array_max;
+ relation rel = def->def.ty.rel;
+
+ print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name);
+}
+
+static void
+print_stat(indent, dec)
+ int indent;
+ declaration *dec;
+{
+ char *prefix = dec->prefix;
+ char *type = dec->type;
+ char *amax = dec->array_max;
+ relation rel = dec->rel;
+ char name[256];
+
+ if (isvectordef(type, rel)) {
+ s_print(name, "objp->%s", dec->name);
+ } else {
+ s_print(name, "&objp->%s", dec->name);
+ }
+ print_ifstat(indent, prefix, type, rel, amax, name, dec->name);
+}
+
+
+char *upcase ();
+
+static void
+emit_inline(indent, decl, flag)
+int indent;
+declaration *decl;
+int flag;
+{
+ switch (decl->rel) {
+ case REL_ALIAS :
+ emit_single_in_line(indent, decl, flag, REL_ALIAS);
+ break;
+ case REL_VECTOR :
+ tabify(fout, indent);
+ f_print(fout, "{\n");
+ tabify(fout, indent + 1);
+ f_print(fout, "register %s *genp;\n\n", decl->type);
+ tabify(fout, indent + 1);
+ f_print(fout,
+ "for (i = 0, genp = objp->%s;\n", decl->name);
+ tabify(fout, indent + 2);
+ f_print(fout, "i < %s; i++) {\n", decl->array_max);
+ emit_single_in_line(indent + 2, decl, flag, REL_VECTOR);
+ tabify(fout, indent + 1);
+ f_print(fout, "}\n");
+ tabify(fout, indent);
+ f_print(fout, "}\n");
+ default:
+ }
+}
+
+static void
+emit_single_in_line(indent, decl, flag, rel)
+int indent;
+declaration *decl;
+int flag;
+relation rel;
+{
+ char *upp_case;
+ int freed = 0;
+
+ tabify(fout, indent);
+ if (flag == PUT)
+ f_print(fout, "IXDR_PUT_");
+ else
+ if (rel == REL_ALIAS)
+ f_print(fout, "objp->%s = IXDR_GET_", decl->name);
+ else
+ f_print(fout, "*genp++ = IXDR_GET_");
+
+ upp_case = upcase(decl->type);
+
+ /* hack - XX */
+ if (strcmp(upp_case, "INT") == 0)
+ {
+ free(upp_case);
+ freed = 1;
+ upp_case = "LONG";
+ }
+
+ if (strcmp(upp_case, "U_INT") == 0)
+ {
+ free(upp_case);
+ freed = 1;
+ upp_case = "U_LONG";
+ }
+ if (flag == PUT)
+ if (rel == REL_ALIAS)
+ f_print(fout,
+ "%s(buf, objp->%s);\n", upp_case, decl->name);
+ else
+ f_print(fout, "%s(buf, *genp++);\n", upp_case);
+
+ else
+ f_print(fout, "%s(buf);\n", upp_case);
+ if (!freed)
+ free(upp_case);
+}
+
+char *upcase(str)
+char *str;
+{
+ char *ptr, *hptr;
+
+ ptr = (char *)malloc(strlen(str)+1);
+ if (ptr == (char *) NULL)
+ {
+ f_print(stderr, "malloc failed\n");
+ exit(1);
+ };
+
+ hptr = ptr;
+ while (*str != '\0')
+ *ptr++ = toupper(*str++);
+
+ *ptr = '\0';
+ return (hptr);
+}
diff --git a/usr.bin/rpcgen/rpc_hout.c b/usr.bin/rpcgen/rpc_hout.c
new file mode 100644
index 0000000..8dce77de
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_hout.c
@@ -0,0 +1,599 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_hout.c 1.16 94/04/25 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_hout.c 1.12 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_hout.c, Header file outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+void storexdrfuncdecl __P(( char *, int ));
+static void pconstdef __P(( definition * ));
+static void pstructdef __P(( definition * ));
+static void puniondef __P(( definition * ));
+static void pprogramdef __P(( definition * ));
+static void pstructdef __P(( definition * ));
+static void penumdef __P(( definition * ));
+static void ptypedef __P(( definition * ));
+static void pdefine __P(( char *, char * ));
+static int undefined2 __P(( char *, char * ));
+static void parglist __P(( proc_list *, char * ));
+static void pprocdef __P(( proc_list *, version_list *, char *, int, int ));
+void pdeclaration __P(( char *, declaration *, int, char * ));
+
+static char RESULT[] = "clnt_res";
+
+
+/*
+ * Print the C-version of an xdr definition
+ */
+void
+print_datadef(def)
+ definition *def;
+{
+
+ if (def->def_kind == DEF_PROGRAM) /* handle data only */
+ return;
+
+ if (def->def_kind != DEF_CONST) {
+ f_print(fout, "\n");
+ }
+ switch (def->def_kind) {
+ case DEF_STRUCT:
+ pstructdef(def);
+ break;
+ case DEF_UNION:
+ puniondef(def);
+ break;
+ case DEF_ENUM:
+ penumdef(def);
+ break;
+ case DEF_TYPEDEF:
+ ptypedef(def);
+ break;
+ case DEF_PROGRAM:
+ pprogramdef(def);
+ break;
+ case DEF_CONST:
+ pconstdef(def);
+ break;
+ }
+ if (def->def_kind != DEF_PROGRAM && def->def_kind != DEF_CONST) {
+ storexdrfuncdecl(def->def_name,
+ def->def_kind != DEF_TYPEDEF ||
+ !isvectordef(def->def.ty.old_type,
+ def->def.ty.rel));
+ }
+}
+
+
+void
+print_funcdef(def)
+ definition *def;
+{
+ switch (def->def_kind) {
+ case DEF_PROGRAM:
+ f_print(fout, "\n");
+ pprogramdef(def);
+ break;
+ default:
+ }
+}
+
+/* store away enough information to allow the XDR functions to be spat
+ out at the end of the file */
+
+void
+storexdrfuncdecl(name, pointerp)
+char *name;
+int pointerp;
+{
+ xdrfunc * xdrptr;
+
+ xdrptr = (xdrfunc *) malloc(sizeof (struct xdrfunc));
+
+ xdrptr->name = name;
+ xdrptr->pointerp = pointerp;
+ xdrptr->next = NULL;
+
+ if (xdrfunc_tail == NULL){
+ xdrfunc_head = xdrptr;
+ xdrfunc_tail = xdrptr;
+ } else {
+ xdrfunc_tail->next = xdrptr;
+ xdrfunc_tail = xdrptr;
+ }
+
+
+}
+
+void
+print_xdr_func_def(name, pointerp, i)
+char* name;
+int pointerp;
+int i;
+{
+ if (i == 2) {
+ f_print(fout, "extern bool_t xdr_%s();\n", name);
+ return;
+ }
+ else
+ f_print(fout, "extern bool_t xdr_%s(XDR *, %s%s);\n", name,
+ name, pointerp ? "*" : "");
+
+
+}
+
+
+static void
+pconstdef(def)
+ definition *def;
+{
+ pdefine(def->def_name, def->def.co);
+}
+
+/* print out the definitions for the arguments of functions in the
+ header file
+*/
+static void
+pargdef(def)
+ definition *def;
+{
+ decl_list *l;
+ version_list *vers;
+ char *name;
+ proc_list *plist;
+
+
+ for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) {
+ for (plist = vers->procs; plist != NULL;
+ plist = plist->next) {
+
+ if (!newstyle || plist->arg_num < 2) {
+ continue; /* old style or single args */
+ }
+ name = plist->args.argname;
+ f_print(fout, "struct %s {\n", name);
+ for (l = plist->args.decls;
+ l != NULL; l = l->next) {
+ pdeclaration(name, &l->decl, 1,
+ ";\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n",
+ name, name);
+ storexdrfuncdecl(name, 1);
+ f_print(fout, "\n");
+ }
+ }
+}
+
+
+static void
+pstructdef(def)
+ definition *def;
+{
+ decl_list *l;
+ char *name = def->def_name;
+
+ f_print(fout, "struct %s {\n", name);
+ for (l = def->def.st.decls; l != NULL; l = l->next) {
+ pdeclaration(name, &l->decl, 1, ";\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n", name, name);
+}
+
+static void
+puniondef(def)
+ definition *def;
+{
+ case_list *l;
+ char *name = def->def_name;
+ declaration *decl;
+
+ f_print(fout, "struct %s {\n", name);
+ decl = &def->def.un.enum_decl;
+ if (streq(decl->type, "bool")) {
+ f_print(fout, "\tbool_t %s;\n", decl->name);
+ } else {
+ f_print(fout, "\t%s %s;\n", decl->type, decl->name);
+ }
+ f_print(fout, "\tunion {\n");
+ for (l = def->def.un.cases; l != NULL; l = l->next) {
+ if (l->contflag == 0)
+ pdeclaration(name, &l->case_decl, 2, ";\n");
+ }
+ decl = def->def.un.default_decl;
+ if (decl && !streq(decl->type, "void")) {
+ pdeclaration(name, decl, 2, ";\n");
+ }
+ f_print(fout, "\t} %s_u;\n", name);
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n", name, name);
+}
+
+static void
+pdefine(name, num)
+ char *name;
+ char *num;
+{
+ f_print(fout, "#define\t%s %s\n", name, num);
+}
+
+static void
+puldefine(name, num)
+ char *name;
+ char *num;
+{
+ f_print(fout, "#define\t%s ((unsigned long)(%s))\n", name, num);
+}
+
+static int
+define_printed(stop, start)
+ proc_list *stop;
+ version_list *start;
+{
+ version_list *vers;
+ proc_list *proc;
+
+ for (vers = start; vers != NULL; vers = vers->next) {
+ for (proc = vers->procs; proc != NULL; proc = proc->next) {
+ if (proc == stop) {
+ return (0);
+ } else if (streq(proc->proc_name, stop->proc_name)) {
+ return (1);
+ }
+ }
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+static void
+pfreeprocdef(char * name, char *vers, int mode)
+{
+ f_print(fout, "extern int ");
+ pvname(name, vers);
+ if (mode == 1)
+ f_print(fout,"_freeresult(SVCXPRT *, xdrproc_t, caddr_t);\n");
+ else
+ f_print(fout,"_freeresult();\n");
+
+
+}
+
+static void
+pprogramdef(def)
+ definition *def;
+{
+ version_list *vers;
+ proc_list *proc;
+ int i;
+ char *ext;
+
+ pargdef(def);
+
+ puldefine(def->def_name, def->def.pr.prog_num);
+ for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) {
+ if (tblflag) {
+ f_print(fout,
+ "extern struct rpcgen_table %s_%s_table[];\n",
+ locase(def->def_name), vers->vers_num);
+ f_print(fout,
+ "extern %s_%s_nproc;\n",
+ locase(def->def_name), vers->vers_num);
+ }
+ puldefine(vers->vers_name, vers->vers_num);
+
+ /*
+ * Print out 2 definitions, one for ANSI-C, another for
+ * old K & R C
+ */
+
+ if(!Cflag){
+ ext = "extern ";
+ for (proc = vers->procs; proc != NULL;
+ proc = proc->next) {
+ if (!define_printed(proc,
+ def->def.pr.versions)) {
+ puldefine(proc->proc_name,
+ proc->proc_num);
+ }
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, NULL, 0, 2);
+
+ if (mtflag) {
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, NULL, 1, 2);
+ }
+ }
+ pfreeprocdef(def->def_name, vers->vers_num, 2);
+
+ } else {
+ for (i = 1; i < 3; i++){
+ if (i == 1){
+ f_print(fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
+ ext = "extern ";
+ }else{
+ f_print(fout, "\n#else /* K&R C */\n");
+ ext = "extern ";
+ }
+
+ for (proc = vers->procs; proc != NULL;
+ proc = proc->next) {
+ if (!define_printed(proc,
+ def->def.pr.versions)) {
+ puldefine(proc->proc_name,
+ proc->proc_num);
+ }
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, "CLIENT *", 0, i);
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, "struct svc_req *", 1, i);
+ }
+ pfreeprocdef(def->def_name, vers->vers_num, i);
+ }
+ f_print(fout, "#endif /* K&R C */\n");
+ }
+ }
+}
+
+static void
+pprocdef(proc, vp, addargtype, server_p, mode)
+ proc_list *proc;
+ version_list *vp;
+ char* addargtype;
+ int server_p;
+ int mode;
+{
+ if (mtflag) {/* Print MT style stubs */
+ if (server_p)
+ f_print(fout, "bool_t ");
+ else
+ f_print(fout, "enum clnt_stat ");
+ } else {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "* ");
+ }
+ if (server_p)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+
+ /*
+ * mode 1 = ANSI-C, mode 2 = K&R C
+ */
+ if ( mode == 1)
+ parglist(proc, addargtype);
+ else
+ f_print(fout, "();\n");
+}
+
+
+
+/* print out argument list of procedure */
+static void
+parglist(proc, addargtype)
+ proc_list *proc;
+ char* addargtype;
+{
+ decl_list *dl;
+
+ f_print(fout, "(");
+ if (proc->arg_num < 2 && newstyle &&
+ streq(proc->args.decls->decl.type, "void")) {
+ /* 0 argument in new style: do nothing*/
+ }
+ else {
+ for (dl = proc->args.decls; dl != NULL; dl = dl->next) {
+ ptype(dl->decl.prefix, dl->decl.type, 1);
+ if (!newstyle)
+ f_print(fout, "*");
+ /* old style passes by reference */
+ f_print(fout, ", ");
+ }
+ }
+
+ if (mtflag) {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*, ");
+ }
+
+ f_print(fout, "%s);\n", addargtype);
+
+}
+
+static void
+penumdef(def)
+ definition *def;
+{
+ char *name = def->def_name;
+ enumval_list *l;
+ char *last = NULL;
+ int count = 0;
+
+ f_print(fout, "enum %s {\n", name);
+ for (l = def->def.en.vals; l != NULL; l = l->next) {
+ f_print(fout, "\t%s", l->name);
+ if (l->assignment) {
+ f_print(fout, " = %s", l->assignment);
+ last = l->assignment;
+ count = 1;
+ } else {
+ if (last == NULL) {
+ f_print(fout, " = %d", count++);
+ } else {
+ f_print(fout, " = %s + %d", last, count++);
+ }
+ }
+ if (l->next)
+ f_print(fout, ",\n");
+ else
+ f_print(fout, "\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef enum %s %s;\n", name, name);
+}
+
+static void
+ptypedef(def)
+ definition *def;
+{
+ char *name = def->def_name;
+ char *old = def->def.ty.old_type;
+ char prefix[8]; /* enough to contain "struct ", including NUL */
+ relation rel = def->def.ty.rel;
+
+
+ if (!streq(name, old)) {
+ if (streq(old, "string")) {
+ old = "char";
+ rel = REL_POINTER;
+ } else if (streq(old, "opaque")) {
+ old = "char";
+ } else if (streq(old, "bool")) {
+ old = "bool_t";
+ }
+ if (undefined2(old, name) && def->def.ty.old_prefix) {
+ s_print(prefix, "%s ", def->def.ty.old_prefix);
+ } else {
+ prefix[0] = 0;
+ }
+ f_print(fout, "typedef ");
+ switch (rel) {
+ case REL_ARRAY:
+ f_print(fout, "struct {\n");
+ f_print(fout, "\tu_int %s_len;\n", name);
+ f_print(fout, "\t%s%s *%s_val;\n", prefix, old, name);
+ f_print(fout, "} %s", name);
+ break;
+ case REL_POINTER:
+ f_print(fout, "%s%s *%s", prefix, old, name);
+ break;
+ case REL_VECTOR:
+ f_print(fout, "%s%s %s[%s]", prefix, old, name,
+ def->def.ty.array_max);
+ break;
+ case REL_ALIAS:
+ f_print(fout, "%s%s %s", prefix, old, name);
+ break;
+ }
+ f_print(fout, ";\n");
+ }
+}
+
+void
+pdeclaration(name, dec, tab, separator)
+ char *name;
+ declaration *dec;
+ int tab;
+ char *separator;
+{
+ char buf[8]; /* enough to hold "struct ", include NUL */
+ char *prefix;
+ char *type;
+
+ if (streq(dec->type, "void")) {
+ return;
+ }
+ tabify(fout, tab);
+ if (streq(dec->type, name) && !dec->prefix) {
+ f_print(fout, "struct ");
+ }
+ if (streq(dec->type, "string")) {
+ f_print(fout, "char *%s", dec->name);
+ } else {
+ prefix = "";
+ if (streq(dec->type, "bool")) {
+ type = "bool_t";
+ } else if (streq(dec->type, "opaque")) {
+ type = "char";
+ } else {
+ if (dec->prefix) {
+ s_print(buf, "%s ", dec->prefix);
+ prefix = buf;
+ }
+ type = dec->type;
+ }
+ switch (dec->rel) {
+ case REL_ALIAS:
+ f_print(fout, "%s%s %s", prefix, type, dec->name);
+ break;
+ case REL_VECTOR:
+ f_print(fout, "%s%s %s[%s]", prefix, type, dec->name,
+ dec->array_max);
+ break;
+ case REL_POINTER:
+ f_print(fout, "%s%s *%s", prefix, type, dec->name);
+ break;
+ case REL_ARRAY:
+ f_print(fout, "struct {\n");
+ tabify(fout, tab);
+ f_print(fout, "\tu_int %s_len;\n", dec->name);
+ tabify(fout, tab);
+ f_print(fout,
+ "\t%s%s *%s_val;\n", prefix, type, dec->name);
+ tabify(fout, tab);
+ f_print(fout, "} %s", dec->name);
+ break;
+ }
+ }
+ f_print(fout, separator);
+}
+
+static int
+undefined2(type, stop)
+ char *type;
+ char *stop;
+{
+ list *l;
+ definition *def;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ if (streq(def->def_name, stop)) {
+ return (1);
+ } else if (streq(def->def_name, type)) {
+ return (0);
+ }
+ }
+ }
+ return (1);
+}
diff --git a/usr.bin/rpcgen/rpc_main.c b/usr.bin/rpcgen/rpc_main.c
new file mode 100644
index 0000000..59431c3
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_main.c
@@ -0,0 +1,1388 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+
+#ident "@(#)rpc_main.c 1.21 94/04/25 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_main.c, Top level of the RPC protocol compiler.
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+#include "rpc_scan.h"
+
+extern void write_sample_svc __P(( definition * ));
+extern int write_sample_clnt __P(( definition * ));
+extern void write_sample_clnt_main __P(( void ));
+extern void add_sample_msg __P(( void ));
+static void c_output __P(( char *, char *, int, char * ));
+static void h_output __P(( char *, char *, int, char * ));
+static void l_output __P(( char *, char *, int, char * ));
+static void t_output __P(( char *, char *, int, char * ));
+static void clnt_output __P(( char *, char *, int, char * ));
+
+void c_initialize __P(( void ));
+
+#ifndef __FreeBSD__
+char * rindex();
+#endif
+
+static void usage __P(( void ));
+static void options_usage __P (( void ));
+static int do_registers __P(( int, char ** ));
+static int parseargs __P(( int, char **, struct commandline * ));
+static void svc_output __P(( char *, char *, int, char * ));
+static void mkfile_output __P(( struct commandline * ));
+static void s_output __P(( int, char **, char *, char *, int, char *, int, int ));
+
+#define EXTEND 1 /* alias for TRUE */
+#define DONT_EXTEND 0 /* alias for FALSE */
+
+#define SVR4_CPP "/usr/ccs/lib/cpp"
+#ifdef __FreeBSD__
+#define SUNOS_CPP "/usr/libexec/cpp"
+#else
+#define SUNOS_CPP "/usr/lib/cpp"
+#endif
+
+static int cppDefined = 0; /* explicit path for C preprocessor */
+
+
+static char *cmdname;
+
+static char *svcclosetime = "120";
+static char *CPP = SVR4_CPP;
+static char CPPFLAGS[] = "-C";
+static char pathbuf[MAXPATHLEN + 1];
+static char *allv[] = {
+ "rpcgen", "-s", "udp", "-s", "tcp",
+};
+static int allc = sizeof (allv)/sizeof (allv[0]);
+static char *allnv[] = {
+ "rpcgen", "-s", "netpath",
+};
+static int allnc = sizeof (allnv)/sizeof (allnv[0]);
+
+/*
+ * machinations for handling expanding argument list
+ */
+static void addarg(); /* add another argument to the list */
+static void putarg(); /* put argument at specified location */
+static void clear_args(); /* clear argument list */
+static void checkfiles(); /* check if out file already exists */
+
+
+
+#define ARGLISTLEN 20
+#define FIXEDARGS 2
+
+static char *arglist[ARGLISTLEN];
+static int argcount = FIXEDARGS;
+
+
+int nonfatalerrors; /* errors */
+#ifdef __FreeBSD__
+int inetdflag = 0; /* Support for inetd is now the default */
+#else
+int inetdflag; /* Support for inetd is now the default */
+#endif
+int pmflag; /* Support for port monitors */
+int logflag; /* Use syslog instead of fprintf for errors */
+int tblflag; /* Support for dispatch table file */
+int mtflag = 0; /* Support for MT */
+#ifdef __FreeBSD__
+#define INLINE 0
+#else
+#define INLINE 5
+#endif
+/* length at which to start doing an inline */
+
+int inline = INLINE;
+/*
+ * Length at which to start doing an inline. INLINE = default
+ * if 0, no xdr_inline code
+ */
+
+int indefinitewait; /* If started by port monitors, hang till it wants */
+int exitnow; /* If started by port monitors, exit after the call */
+int timerflag; /* TRUE if !indefinite && !exitnow */
+int newstyle; /* newstyle of passing arguments (by value) */
+int Cflag = 0; /* ANSI C syntax */
+int CCflag = 0; /* C++ files */
+static int allfiles; /* generate all files */
+#ifdef __FreeBSD__
+int tirpcflag = 0; /* generating code for tirpc, by default */
+#else
+int tirpcflag = 1; /* generating code for tirpc, by default */
+#endif
+xdrfunc *xdrfunc_head = NULL; /* xdr function list */
+xdrfunc *xdrfunc_tail = NULL; /* xdr function list */
+pid_t childpid;
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct commandline cmd;
+
+ (void) memset((char *)&cmd, 0, sizeof (struct commandline));
+ clear_args();
+ if (!parseargs(argc, argv, &cmd))
+ usage();
+ /*
+ * Only the client and server side stubs are likely to be customized,
+ * so in that case only, check if the outfile exists, and if so,
+ * print an error message and exit.
+ */
+ if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag) {
+ checkfiles(cmd.infile, cmd.outfile);
+ }
+ else
+ checkfiles(cmd.infile, NULL);
+
+ if (cmd.cflag) {
+ c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
+ } else if (cmd.hflag) {
+ h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile);
+ } else if (cmd.lflag) {
+ l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
+ } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
+ s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
+ cmd.outfile, cmd.mflag, cmd.nflag);
+ } else if (cmd.tflag) {
+ t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
+ } else if (cmd.Ssflag) {
+ svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND,
+ cmd.outfile);
+ } else if (cmd.Scflag) {
+ clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND,
+ cmd.outfile);
+ } else if (cmd.makefileflag) {
+ mkfile_output(&cmd);
+ } else {
+ /* the rescans are required, since cpp may effect input */
+ c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
+ reinitialize();
+ h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h");
+ reinitialize();
+ l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
+ reinitialize();
+ if (inetdflag || !tirpcflag)
+ s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
+ "_svc.c", cmd.mflag, cmd.nflag);
+ else
+ s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
+ EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
+ if (tblflag) {
+ reinitialize();
+ t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
+ }
+
+ if (allfiles) {
+ reinitialize();
+ svc_output(cmd.infile, "-DRPC_SERVER", EXTEND,
+ "_server.c");
+ reinitialize();
+ clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND,
+ "_client.c");
+
+ }
+ if (allfiles || (cmd.makefileflag == 1)){
+ reinitialize();
+ mkfile_output(&cmd);
+ }
+
+ }
+ exit(nonfatalerrors);
+ /* NOTREACHED */
+}
+
+
+/*
+ * add extension to filename
+ */
+static char *
+#ifdef __FreeBSD__
+extendfile(path, ext)
+ char *path;
+#else
+extendfile(file, ext)
+ char *file;
+#endif
+ char *ext;
+{
+ char *res;
+ char *p;
+#ifdef __FreeBSD__
+ char *file;
+
+ if ((file = rindex(path, '/')) == NULL)
+ file = path;
+ else
+ file++;
+#endif
+ res = alloc(strlen(file) + strlen(ext) + 1);
+ if (res == NULL) {
+ abort();
+ }
+ p = strrchr(file, '.');
+ if (p == NULL) {
+ p = file + strlen(file);
+ }
+ (void) strcpy(res, file);
+ (void) strcpy(res + (p - file), ext);
+ return (res);
+}
+
+/*
+ * Open output file with given extension
+ */
+static void
+open_output(infile, outfile)
+ char *infile;
+ char *outfile;
+{
+
+ if (outfile == NULL) {
+ fout = stdout;
+ return;
+ }
+
+ if (infile != NULL && streq(outfile, infile)) {
+ f_print(stderr, "%s: %s already exists. No output generated.\n",
+ cmdname, infile);
+ crash();
+ }
+ fout = fopen(outfile, "w");
+ if (fout == NULL) {
+ f_print(stderr, "%s: unable to open ", cmdname);
+ perror(outfile);
+ crash();
+ }
+ record_open(outfile);
+
+ return;
+}
+
+static void
+add_warning()
+{
+ f_print(fout, "/*\n");
+ f_print(fout, " * Please do not edit this file.\n");
+ f_print(fout, " * It was generated using rpcgen.\n");
+ f_print(fout, " */\n\n");
+}
+
+/* clear list of arguments */
+static void clear_args()
+{
+ int i;
+ for (i = FIXEDARGS; i < ARGLISTLEN; i++)
+ arglist[i] = NULL;
+ argcount = FIXEDARGS;
+}
+
+/* make sure that a CPP exists */
+static void find_cpp()
+{
+ struct stat buf;
+
+ if (stat(CPP, &buf) < 0) { /* SVR4 or explicit cpp does not exist */
+ if (cppDefined) {
+ fprintf(stderr,
+ "cannot find C preprocessor: %s \n", CPP);
+ crash();
+ } else { /* try the other one */
+ CPP = SUNOS_CPP;
+ if (stat(CPP, &buf) < 0) { /* can't find any cpp */
+ fprintf(stderr,
+ "cannot find any C preprocessor (cpp)\n");
+ crash();
+ }
+ }
+ }
+}
+
+/*
+ * Open input file with given define for C-preprocessor
+ */
+static void
+open_input(infile, define)
+ char *infile;
+ char *define;
+{
+ int pd[2];
+
+ infilename = (infile == NULL) ? "<stdin>" : infile;
+ (void) pipe(pd);
+ switch (childpid = fork()) {
+ case 0:
+ find_cpp();
+ putarg(0, CPP);
+ putarg(1, CPPFLAGS);
+ addarg(define);
+ if (infile)
+ addarg(infile);
+ addarg((char *)NULL);
+ (void) close(1);
+ (void) dup2(pd[1], 1);
+ (void) close(pd[0]);
+ execv(arglist[0], arglist);
+ perror("execv");
+ exit(1);
+ case -1:
+ perror("fork");
+ exit(1);
+ }
+ (void) close(pd[1]);
+ fin = fdopen(pd[0], "r");
+ if (fin == NULL) {
+ f_print(stderr, "%s: ", cmdname);
+ perror(infilename);
+ crash();
+ }
+}
+
+/* valid tirpc nettypes */
+static char* valid_ti_nettypes[] =
+{
+ "netpath",
+ "visible",
+ "circuit_v",
+ "datagram_v",
+ "circuit_n",
+ "datagram_n",
+ "udp",
+ "tcp",
+ "raw",
+ NULL
+ };
+
+/* valid inetd nettypes */
+static char* valid_i_nettypes[] =
+{
+ "udp",
+ "tcp",
+ NULL
+ };
+
+static int check_nettype(name, list_to_check)
+char* name;
+char* list_to_check[];
+{
+ int i;
+ for (i = 0; list_to_check[i] != NULL; i++) {
+ if (strcmp(name, list_to_check[i]) == 0) {
+ return (1);
+ }
+ }
+ f_print(stderr, "illegal nettype :\'%s\'\n", name);
+ return (0);
+}
+
+static char *
+file_name(file, ext)
+char *file;
+char *ext;
+{
+ char *temp;
+ temp = extendfile(file, ext);
+
+ if (access(temp, F_OK) != -1)
+ return (temp);
+ else
+ return ((char *)" ");
+
+}
+
+
+static void
+c_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+
+ c_initialize();
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ /* .h file already contains rpc/rpc.h */
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ tell = ftell(fout);
+ while ( (def = get_definition()) ) {
+ emit(def);
+ }
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+
+
+void
+c_initialize()
+{
+
+ /* add all the starting basic types */
+ add_type(1, "int");
+ add_type(1, "long");
+ add_type(1, "short");
+ add_type(1, "bool");
+ add_type(1, "u_int");
+ add_type(1, "u_long");
+ add_type(1, "u_short");
+
+}
+
+char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
+ char *(*proc)(); \n\
+ xdrproc_t xdr_arg; \n\
+ unsigned len_arg; \n\
+ xdrproc_t xdr_res; \n\
+ unsigned len_res; \n\
+}; \n";
+
+
+char *generate_guard(pathname)
+ char* pathname;
+{
+ char* filename, *guard, *tmp;
+
+ filename = strrchr(pathname, '/'); /* find last component */
+ filename = ((filename == 0) ? pathname : filename+1);
+ guard = strdup(filename);
+ /* convert to upper case */
+ tmp = guard;
+ while (*tmp) {
+ if (islower(*tmp))
+ *tmp = toupper(*tmp);
+ tmp++;
+ }
+ guard = extendfile(guard, "_H_RPCGEN");
+ return (guard);
+}
+
+/*
+ * Compile into an XDR header file
+ */
+
+
+static void
+h_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *outfilename;
+ long tell;
+ char *guard;
+ list *l;
+ xdrfunc *xdrfuncp;
+ int i;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (outfilename || infile){
+ guard = generate_guard(outfilename ? outfilename: infile);
+ } else
+ guard = "STDIN_";
+
+ f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard,
+ guard);
+
+ f_print(fout, "#include <rpc/rpc.h>\n");
+
+ if (mtflag) {
+ f_print(fout, "#include <synch.h>\n");
+ f_print(fout, "#include <thread.h>\n");
+ };
+
+ /* put the C++ support */
+ if (Cflag && !CCflag){
+ f_print(fout, "\n#ifdef __cplusplus\n");
+ f_print(fout, "extern \"C\" {\n");
+ f_print(fout, "#endif\n\n");
+ }
+
+ /* put in a typedef for quadprecision. Only with Cflag */
+
+ tell = ftell(fout);
+
+ /* print data definitions */
+ while ( (def = get_definition()) ) {
+ print_datadef(def);
+ }
+
+ /*
+ * print function declarations.
+ * Do this after data definitions because they might be used as
+ * arguments for functions
+ */
+ for (l = defined; l != NULL; l = l->next) {
+ print_funcdef(l->val);
+ }
+ /* Now print all xdr func declarations */
+ if (xdrfunc_head != NULL){
+
+ f_print(fout,
+ "\n/* the xdr functions */\n");
+
+ if (CCflag){
+ f_print(fout, "\n#ifdef __cplusplus\n");
+ f_print(fout, "extern \"C\" {\n");
+ f_print(fout, "#endif\n");
+ }
+
+ if (!Cflag){
+ xdrfuncp = xdrfunc_head;
+ while (xdrfuncp != NULL){
+ print_xdr_func_def(xdrfuncp->name,
+ xdrfuncp->pointerp, 2);
+ xdrfuncp = xdrfuncp->next;
+ }
+ } else {
+
+ for (i = 1; i < 3; i++){
+ if (i == 1)
+ f_print(fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
+
+ else
+ f_print(fout, "\n#else /* K&R C */\n");
+
+ xdrfuncp = xdrfunc_head;
+ while (xdrfuncp != NULL){
+ print_xdr_func_def(xdrfuncp->name,
+ xdrfuncp->pointerp, i);
+ xdrfuncp = xdrfuncp->next;
+ }
+ }
+ f_print(fout, "\n#endif /* K&R C */\n");
+ }
+ }
+
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ } else if (tblflag) {
+ f_print(fout, rpcgen_table_dcl);
+ }
+
+ if (Cflag){
+ f_print(fout, "\n#ifdef __cplusplus\n");
+ f_print(fout, "}\n");
+ f_print(fout, "#endif\n");
+ }
+
+ f_print(fout, "\n#endif /* !_%s */\n", guard);
+}
+
+/*
+ * Compile into an RPC service
+ */
+static void
+s_output(argc, argv, infile, define, extend, outfile, nomain, netflag)
+ int argc;
+ char *argv[];
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+ int nomain;
+ int netflag;
+{
+ char *include;
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+
+ f_print(fout, "#include <stdio.h>\n");
+ f_print(fout, "#include <stdlib.h> /* getenv, exit */\n");
+ if (Cflag) {
+ f_print (fout,
+ "#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
+ f_print (fout, "#include <string.h> /* strcmp */\n");
+ }
+ if (strcmp(svcclosetime, "-1") == 0)
+ indefinitewait = 1;
+ else if (strcmp(svcclosetime, "0") == 0)
+ exitnow = 1;
+ else if (inetdflag || pmflag) {
+ f_print(fout, "#include <signal.h>\n");
+ timerflag = 1;
+ }
+
+ if (!tirpcflag && inetdflag)
+ f_print(fout, "#include <sys/ttycom.h> /* TIOCNOTTY */\n");
+ if (Cflag && (inetdflag || pmflag)) {
+ f_print(fout, "#ifdef __cplusplus\n");
+ f_print(fout,
+ "#include <sysent.h> /* getdtablesize, open */\n");
+ f_print(fout, "#endif /* __cplusplus */\n");
+ if (tirpcflag)
+ f_print(fout, "#include <unistd.h> /* setsid */\n");
+ }
+ if (tirpcflag)
+ f_print(fout, "#include <sys/types.h>\n");
+
+ f_print(fout, "#include <memory.h>\n");
+#ifdef __FreeBSD__
+ if (tirpcflag)
+#endif
+ f_print(fout, "#include <stropts.h>\n");
+ if (inetdflag || !tirpcflag) {
+ f_print(fout, "#include <sys/socket.h>\n");
+ f_print(fout, "#include <netinet/in.h>\n");
+ }
+
+ if ((netflag || pmflag) && tirpcflag && !nomain) {
+ f_print(fout, "#include <netconfig.h>\n");
+ }
+ if (tirpcflag)
+ f_print(fout, "#include <sys/resource.h> /* rlimit */\n");
+ if (logflag || inetdflag || pmflag)
+ f_print(fout, "#include <syslog.h>\n");
+
+ /* for ANSI-C */
+ if (Cflag)
+ f_print(fout,
+ "\n#ifndef SIG_PF\n#define SIG_PF void(*)\
+(int)\n#endif\n");
+
+ f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n");
+ if (timerflag)
+ f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n",
+ svcclosetime);
+ while ( (def = get_definition()) ) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ write_most(infile, netflag, nomain);
+ if (!nomain) {
+ if (!do_registers(argc, argv)) {
+ if (outfilename)
+ (void) unlink(outfilename);
+ usage();
+ }
+ write_rest();
+ }
+}
+
+/*
+ * generate client side stubs
+ */
+static void
+l_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ char *include;
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (Cflag)
+ f_print (fout, "#include <memory.h> /* for memset */\n");
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ while ( (def = get_definition()) ) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ write_stubs();
+}
+
+/*
+ * generate the dispatch table
+ */
+static void
+t_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ while ( (def = get_definition()) ) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ write_tables();
+}
+
+/* sample routine for the server template */
+static void
+svc_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ checkfiles(infile, outfilename);
+ /*
+ * Check if outfile already exists.
+ * if so, print an error message and exit
+ */
+ open_output(infile, outfilename);
+ add_sample_msg();
+
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+
+ tell = ftell(fout);
+ while ( (def = get_definition()) ) {
+ write_sample_svc(def);
+ }
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+
+/* sample main routine for client */
+static void
+clnt_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+ int has_program = 0;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ checkfiles(infile, outfilename);
+ /*
+ * Check if outfile already exists.
+ * if so, print an error message and exit
+ */
+
+ open_output(infile, outfilename);
+ add_sample_msg();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ tell = ftell(fout);
+ while ( (def = get_definition()) ) {
+ has_program += write_sample_clnt(def);
+ }
+
+ if (has_program)
+ write_sample_clnt_main();
+
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+
+
+static void mkfile_output(cmd)
+struct commandline *cmd;
+{
+ char *mkfilename, *clientname, *clntname, *xdrname, *hdrname;
+ char *servername, *svcname, *servprogname, *clntprogname;
+ char *temp;
+
+ svcname = file_name(cmd->infile, "_svc.c");
+ clntname = file_name(cmd->infile, "_clnt.c");
+ xdrname = file_name(cmd->infile, "_xdr.c");
+ hdrname = file_name(cmd->infile, ".h");
+
+
+ if (allfiles){
+ servername = extendfile(cmd->infile, "_server.c");
+ clientname = extendfile(cmd->infile, "_client.c");
+ }else{
+ servername = " ";
+ clientname = " ";
+ }
+ servprogname = extendfile(cmd->infile, "_server");
+ clntprogname = extendfile(cmd->infile, "_client");
+
+ if (allfiles){
+ mkfilename = alloc(strlen("makefile.") +
+ strlen(cmd->infile) + 1);
+ temp = (char *)rindex(cmd->infile, '.');
+ strcat(mkfilename, "makefile.");
+ (void) strncat(mkfilename, cmd->infile,
+ (temp - cmd->infile));
+ } else
+ mkfilename = cmd->outfile;
+
+
+ checkfiles(NULL, mkfilename);
+ open_output(NULL, mkfilename);
+
+ f_print(fout, "\n# This is a template makefile generated\
+ by rpcgen \n");
+
+ f_print(fout, "\n# Parameters \n\n");
+
+ f_print(fout, "CLIENT = %s\nSERVER = %s\n\n",
+ clntprogname, servprogname);
+ f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
+ f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
+ f_print(fout, "SOURCES.x = %s\n\n", cmd->infile);
+ f_print(fout, "TARGETS_SVC.c = %s %s %s \n",
+ svcname, servername, xdrname);
+ f_print(fout, "TARGETS_CLNT.c = %s %s %s \n",
+ clntname, clientname, xdrname);
+ f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n",
+ hdrname, xdrname, clntname,
+ svcname, clientname, servername);
+
+ f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \
+$(TARGETS_CLNT.c:%%.c=%%.o) ");
+
+ f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \
+$(TARGETS_SVC.c:%%.c=%%.o) ");
+
+
+ f_print(fout, "\n# Compiler flags \n");
+ if (mtflag)
+ f_print(fout, "\nCPPFLAGS += -D_REENTRANT\nCFLAGS += -g \nLDLIBS += -lnsl -lthread\n");
+ else
+#ifdef __FreeBSD__
+ f_print(fout, "\nCFLAGS += -g \nLDLIBS +=\n");
+#else
+ f_print(fout, "\nCFLAGS += -g \nLDLIBS += -lnsl\n");
+#endif
+ f_print(fout, "RPCGENFLAGS = \n");
+
+ f_print(fout, "\n# Targets \n\n");
+
+ f_print(fout, "all : $(CLIENT) $(SERVER)\n\n");
+ f_print(fout, "$(TARGETS) : $(SOURCES.x) \n");
+ f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
+ f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \
+$(TARGETS_CLNT.c) \n\n");
+
+ f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \
+$(TARGETS_SVC.c) \n\n");
+ f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
+#ifdef __FreeBSD__
+ f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) \
+$(LDLIBS) \n\n");
+#else
+ f_print(fout, "\t$(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) \
+$(LDLIBS) \n\n");
+#endif
+ f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n");
+#ifdef __FreeBSD__
+ f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
+ f_print(fout, "clean:\n\t $(RM) -f core $(TARGETS) $(OBJECTS_CLNT) \
+$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
+#else
+ f_print(fout, "\t$(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
+ f_print(fout, "clean:\n\t $(RM) core $(TARGETS) $(OBJECTS_CLNT) \
+$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
+#endif
+}
+
+
+
+/*
+ * Perform registrations for service output
+ * Return 0 if failed; 1 otherwise.
+ */
+static int
+do_registers(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+ if (inetdflag || !tirpcflag) {
+ for (i = 1; i < argc; i++) {
+ if (streq(argv[i], "-s")) {
+ if (!check_nettype(argv[i + 1],
+ valid_i_nettypes))
+ return (0);
+ write_inetd_register(argv[i + 1]);
+ i++;
+ }
+ }
+ } else {
+ for (i = 1; i < argc; i++)
+ if (streq(argv[i], "-s")) {
+ if (!check_nettype(argv[i + 1],
+ valid_ti_nettypes))
+ return (0);
+ write_nettype_register(argv[i + 1]);
+ i++;
+ } else if (streq(argv[i], "-n")) {
+ write_netid_register(argv[i + 1]);
+ i++;
+ }
+ }
+ return (1);
+}
+
+/*
+ * Add another argument to the arg list
+ */
+static void
+addarg(cp)
+ char *cp;
+{
+ if (argcount >= ARGLISTLEN) {
+ f_print(stderr, "rpcgen: too many defines\n");
+ crash();
+ /*NOTREACHED*/
+ }
+ arglist[argcount++] = cp;
+
+}
+
+static void
+putarg(where, cp)
+ char *cp;
+ int where;
+{
+ if (where >= ARGLISTLEN) {
+ f_print(stderr, "rpcgen: arglist coding error\n");
+ crash();
+ /*NOTREACHED*/
+ }
+ arglist[where] = cp;
+}
+
+/*
+ * if input file is stdin and an output file is specified then complain
+ * if the file already exists. Otherwise the file may get overwritten
+ * If input file does not exist, exit with an error
+ */
+
+static void
+checkfiles(infile, outfile)
+char *infile;
+char *outfile;
+{
+
+ struct stat buf;
+
+ if (infile) /* infile ! = NULL */
+ if (stat(infile, &buf) < 0)
+ {
+ perror(infile);
+ crash();
+ };
+ if (outfile) {
+ if (stat(outfile, &buf) < 0)
+ return; /* file does not exist */
+ else {
+ f_print(stderr,
+ "file '%s' already exists and may be overwritten\n",
+ outfile);
+ crash();
+ }
+ }
+}
+
+/*
+ * Parse command line arguments
+ */
+static int
+parseargs(argc, argv, cmd)
+ int argc;
+ char *argv[];
+ struct commandline *cmd;
+{
+ int i;
+ int j;
+ char c, ch;
+ char flag[(1 << 8 * sizeof (char))];
+ int nflags;
+
+ cmdname = argv[0];
+ cmd->infile = cmd->outfile = NULL;
+ if (argc < 2) {
+ return (0);
+ }
+ allfiles = 0;
+ flag['c'] = 0;
+ flag['h'] = 0;
+ flag['l'] = 0;
+ flag['m'] = 0;
+ flag['o'] = 0;
+ flag['s'] = 0;
+ flag['n'] = 0;
+ flag['t'] = 0;
+ flag['S'] = 0;
+ flag['C'] = 0;
+ flag['M'] = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ if (cmd->infile) {
+ f_print(stderr,
+ "Cannot specify more than one input file.\n");
+
+ return (0);
+ }
+ cmd->infile = argv[i];
+ } else {
+ for (j = 1; argv[i][j] != 0; j++) {
+ c = argv[i][j];
+ switch (c) {
+ case 'a':
+ allfiles = 1;
+ break;
+ case 'c':
+ case 'h':
+ case 'l':
+ case 'm':
+ case 't':
+ if (flag[(int)c]) {
+ return (0);
+ }
+ flag[(int)c] = 1;
+ break;
+ case 'S':
+ /*
+ * sample flag: Ss or Sc.
+ * Ss means set flag['S'];
+ * Sc means set flag['C'];
+ * Sm means set flag['M'];
+ */
+ ch = argv[i][++j]; /* get next char */
+ if (ch == 's')
+ ch = 'S';
+ else if (ch == 'c')
+ ch = 'C';
+ else if (ch == 'm')
+ ch = 'M';
+ else
+ return (0);
+
+ if (flag[(int)ch]) {
+ return (0);
+ }
+ flag[(int)ch] = 1;
+ break;
+ case 'C': /* ANSI C syntax */
+ Cflag = 1;
+ ch = argv[i][j+1]; /* get next char */
+
+ if (ch != 'C')
+ break;
+ CCflag = 1;
+ break;
+ case 'b':
+ /*
+ * Turn TIRPC flag off for
+ * generating backward compatible
+ * code
+ */
+#ifdef __FreeBSD__
+ tirpcflag = 1;
+#else
+ tirpcflag = 0;
+#endif
+ break;
+
+ case 'I':
+ inetdflag = 1;
+ break;
+ case 'N':
+ newstyle = 1;
+ break;
+ case 'L':
+ logflag = 1;
+ break;
+ case 'K':
+ if (++i == argc) {
+ return (0);
+ }
+ svcclosetime = argv[i];
+ goto nextarg;
+ case 'T':
+ tblflag = 1;
+ break;
+ case 'M':
+ mtflag = 1;
+ break;
+ case 'i' :
+ if (++i == argc) {
+ return (0);
+ }
+ inline = atoi(argv[i]);
+ goto nextarg;
+ case 'n':
+ case 'o':
+ case 's':
+ if (argv[i][j - 1] != '-' ||
+ argv[i][j + 1] != 0) {
+ return (0);
+ }
+ flag[(int)c] = 1;
+ if (++i == argc) {
+ return (0);
+ }
+ if (c == 'o') {
+ if (cmd->outfile) {
+ return (0);
+ }
+ cmd->outfile = argv[i];
+ }
+ goto nextarg;
+ case 'D':
+ if (argv[i][j - 1] != '-') {
+ return (0);
+ }
+ (void) addarg(argv[i]);
+ goto nextarg;
+ case 'Y':
+ if (++i == argc) {
+ return (0);
+ }
+ (void) strcpy(pathbuf, argv[i]);
+ (void) strcat(pathbuf, "/cpp");
+ CPP = pathbuf;
+ cppDefined = 1;
+ goto nextarg;
+
+
+
+ default:
+ return (0);
+ }
+ }
+ nextarg:
+ ;
+ }
+ }
+
+ cmd->cflag = flag['c'];
+ cmd->hflag = flag['h'];
+ cmd->lflag = flag['l'];
+ cmd->mflag = flag['m'];
+ cmd->nflag = flag['n'];
+ cmd->sflag = flag['s'];
+ cmd->tflag = flag['t'];
+ cmd->Ssflag = flag['S'];
+ cmd->Scflag = flag['C'];
+ cmd->makefileflag = flag['M'];
+
+ if (tirpcflag) {
+ pmflag = inetdflag ? 0 : 1;
+ /* pmflag or inetdflag is always TRUE */
+ if ((inetdflag && cmd->nflag)) {
+ /* netid not allowed with inetdflag */
+ f_print(stderr, "Cannot use netid flag with inetd flag.\n");
+ return (0);
+ }
+ } else { /* 4.1 mode */
+ pmflag = 0; /* set pmflag only in tirpcmode */
+#ifndef __FreeBSD__
+ inetdflag = 1; /* inetdflag is TRUE by default */
+#endif
+ if (cmd->nflag) { /* netid needs TIRPC */
+ f_print(stderr, "Cannot use netid flag without TIRPC.\n");
+ return (0);
+ }
+ }
+
+ if (newstyle && (tblflag || cmd->tflag)) {
+ f_print(stderr, "Cannot use table flags with newstyle.\n");
+ return (0);
+ }
+
+ /* check no conflicts with file generation flags */
+ nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
+ cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag +
+ cmd->Scflag + cmd->makefileflag;
+
+ if (nflags == 0) {
+ if (cmd->outfile != NULL || cmd->infile == NULL) {
+ return (0);
+ }
+ } else if (cmd->infile == NULL &&
+ (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) {
+ f_print(stderr,
+ "\"infile\" is required for template generation flags.\n");
+ return (0);
+ } if (nflags > 1) {
+ f_print(stderr,
+ "Cannot have more than one file generation flag.\n");
+ return (0);
+ }
+ return (1);
+}
+
+static void
+usage()
+{
+ f_print(stderr, "usage: %s infile\n", cmdname);
+ f_print(stderr,
+ "\t%s [-abCLNTM] [-Dname[=value]] [-i size]\
+[-I [-K seconds]] [-Y path] infile\n",
+ cmdname);
+ f_print(stderr,
+ "\t%s [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]\
+[-o outfile] [infile]\n",
+ cmdname);
+ f_print(stderr, "\t%s [-s nettype]* [-o outfile] [infile]\n", cmdname);
+ f_print(stderr, "\t%s [-n netid]* [-o outfile] [infile]\n", cmdname);
+ options_usage();
+ exit(1);
+}
+
+static void
+options_usage()
+{
+ f_print(stderr, "options:\n");
+ f_print(stderr, "-a\t\tgenerate all files, including samples\n");
+ f_print(stderr, "-b\t\tbackward compatibility mode (generates code\
+for SunOS 4.X)\n");
+ f_print(stderr, "-c\t\tgenerate XDR routines\n");
+ f_print(stderr, "-C\t\tANSI C mode\n");
+ f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
+ f_print(stderr, "-h\t\tgenerate header file\n");
+ f_print(stderr, "-i size\t\tsize at which to start generating\
+inline code\n");
+ f_print(stderr, "-I\t\tgenerate code for inetd support in server\
+(for SunOS 4.X)\n");
+ f_print(stderr, "-K seconds\tserver exits after K seconds of\
+inactivity\n");
+ f_print(stderr, "-l\t\tgenerate client side stubs\n");
+ f_print(stderr, "-L\t\tserver errors will be printed to syslog\n");
+ f_print(stderr, "-m\t\tgenerate server side stubs\n");
+ f_print(stderr, "-M\t\tgenerate MT-safe code\n");
+ f_print(stderr, "-n netid\tgenerate server code that supports\
+named netid\n");
+ f_print(stderr, "-N\t\tsupports multiple arguments and\
+call-by-value\n");
+ f_print(stderr, "-o outfile\tname of the output file\n");
+ f_print(stderr, "-s nettype\tgenerate server code that supports named\
+nettype\n");
+ f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote\
+procedures\n");
+ f_print(stderr, "-Ss\t\tgenerate sample server code that defines\
+remote procedures\n");
+ f_print(stderr, "-Sm \t\tgenerate makefile template \n");
+
+ f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
+ f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
+ f_print(stderr, "-Y path\t\tpath where cpp is found\n");
+ exit(1);
+}
+
+#ifndef __FreeBSD__
+char *
+rindex(sp, c)
+ register char *sp, c;
+{
+ register char *r;
+
+ r = NULL;
+ do {
+ if (*sp == c)
+ r = sp;
+ } while (*sp++);
+ return (r);
+}
+#endif
diff --git a/usr.bin/rpcgen/rpc_parse.c b/usr.bin/rpcgen/rpc_parse.c
new file mode 100644
index 0000000..5431520
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_parse.c
@@ -0,0 +1,656 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_parse.c 1.12 93/07/05 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_parse.c 1.8 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_parse.c, Parser for the RPC protocol compiler
+ * Copyright (C) 1987 Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define ARGNAME "arg"
+
+extern char *make_argname __P(( char *, char * ));
+static void isdefined __P(( definition * ));
+static void def_struct __P(( definition * ));
+static void def_program __P(( definition * ));
+static void def_enum __P(( definition * ));
+static void def_const __P(( definition * ));
+static void def_union __P(( definition * ));
+static void def_typedef __P(( definition * ));
+static void get_declaration __P(( declaration *, defkind ));
+static void get_prog_declaration __P(( declaration *, defkind, int ));
+static void get_type __P(( char **, char **, defkind ));
+static void unsigned_dec __P(( char ** ));
+
+#ifndef __FreeBSD__
+extern char *strdup();
+#endif
+
+/*
+ * return the next definition you see
+ */
+definition *
+get_definition()
+{
+ definition *defp;
+ token tok;
+
+ defp = ALLOC(definition);
+ get_token(&tok);
+ switch (tok.kind) {
+ case TOK_STRUCT:
+ def_struct(defp);
+ break;
+ case TOK_UNION:
+ def_union(defp);
+ break;
+ case TOK_TYPEDEF:
+ def_typedef(defp);
+ break;
+ case TOK_ENUM:
+ def_enum(defp);
+ break;
+ case TOK_PROGRAM:
+ def_program(defp);
+ break;
+ case TOK_CONST:
+ def_const(defp);
+ break;
+ case TOK_EOF:
+ return (NULL);
+ default:
+ error("definition keyword expected");
+ }
+ scan(TOK_SEMICOLON, &tok);
+ isdefined(defp);
+ return (defp);
+}
+
+static void
+isdefined(defp)
+ definition *defp;
+{
+ STOREVAL(&defined, defp);
+}
+
+static void
+def_struct(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ decl_list *decls;
+ decl_list **tailp;
+
+ defp->def_kind = DEF_STRUCT;
+
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ tailp = &defp->def.st.decls;
+ do {
+ get_declaration(&dec, DEF_STRUCT);
+ decls = ALLOC(decl_list);
+ decls->decl = dec;
+ *tailp = decls;
+ tailp = &decls->next;
+ scan(TOK_SEMICOLON, &tok);
+ peek(&tok);
+ } while (tok.kind != TOK_RBRACE);
+ get_token(&tok);
+ *tailp = NULL;
+}
+
+static void
+def_program(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ decl_list *decls;
+ decl_list **tailp;
+ version_list *vlist;
+ version_list **vtailp;
+ proc_list *plist;
+ proc_list **ptailp;
+ int num_args;
+ bool_t isvoid = FALSE; /* whether first argument is void */
+ defp->def_kind = DEF_PROGRAM;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ vtailp = &defp->def.pr.versions;
+ tailp = &defp->def.st.decls;
+ scan(TOK_VERSION, &tok);
+ do {
+ scan(TOK_IDENT, &tok);
+ vlist = ALLOC(version_list);
+ vlist->vers_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ ptailp = &vlist->procs;
+ do {
+ /* get result type */
+ plist = ALLOC(proc_list);
+ get_type(&plist->res_prefix, &plist->res_type,
+ DEF_PROGRAM);
+ if (streq(plist->res_type, "opaque")) {
+ error("illegal result type");
+ }
+ scan(TOK_IDENT, &tok);
+ plist->proc_name = tok.str;
+ scan(TOK_LPAREN, &tok);
+ /* get args - first one */
+ num_args = 1;
+ isvoid = FALSE;
+ /*
+ * type of DEF_PROGRAM in the first
+ * get_prog_declaration and DEF_STURCT in the next
+ * allows void as argument if it is the only argument
+ */
+ get_prog_declaration(&dec, DEF_PROGRAM, num_args);
+ if (streq(dec.type, "void"))
+ isvoid = TRUE;
+ decls = ALLOC(decl_list);
+ plist->args.decls = decls;
+ decls->decl = dec;
+ tailp = &decls->next;
+ /* get args */
+ while (peekscan(TOK_COMMA, &tok)) {
+ num_args++;
+ get_prog_declaration(&dec, DEF_STRUCT,
+ num_args);
+ decls = ALLOC(decl_list);
+ decls->decl = dec;
+ *tailp = decls;
+ if (streq(dec.type, "void"))
+ isvoid = TRUE;
+ tailp = &decls->next;
+ }
+ /* multiple arguments are only allowed in newstyle */
+ if (!newstyle && num_args > 1) {
+ error("only one argument is allowed");
+ }
+ if (isvoid && num_args > 1) {
+ error("illegal use of void in program definition");
+ }
+ *tailp = NULL;
+ scan(TOK_RPAREN, &tok);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ scan(TOK_SEMICOLON, &tok);
+ plist->proc_num = tok.str;
+ plist->arg_num = num_args;
+ *ptailp = plist;
+ ptailp = &plist->next;
+ peek(&tok);
+ } while (tok.kind != TOK_RBRACE);
+ *ptailp = NULL;
+ *vtailp = vlist;
+ vtailp = &vlist->next;
+ scan(TOK_RBRACE, &tok);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ vlist->vers_num = tok.str;
+ /* make the argument structure name for each arg */
+ for (plist = vlist->procs; plist != NULL;
+ plist = plist->next) {
+ plist->args.argname = make_argname(plist->proc_name,
+ vlist->vers_num);
+ /* free the memory ?? */
+ }
+ scan(TOK_SEMICOLON, &tok);
+ scan2(TOK_VERSION, TOK_RBRACE, &tok);
+ } while (tok.kind == TOK_VERSION);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ defp->def.pr.prog_num = tok.str;
+ *vtailp = NULL;
+}
+
+
+static void
+def_enum(defp)
+ definition *defp;
+{
+ token tok;
+ enumval_list *elist;
+ enumval_list **tailp;
+
+ defp->def_kind = DEF_ENUM;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ tailp = &defp->def.en.vals;
+ do {
+ scan(TOK_IDENT, &tok);
+ elist = ALLOC(enumval_list);
+ elist->name = tok.str;
+ elist->assignment = NULL;
+ scan3(TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok);
+ if (tok.kind == TOK_EQUAL) {
+ scan_num(&tok);
+ elist->assignment = tok.str;
+ scan2(TOK_COMMA, TOK_RBRACE, &tok);
+ }
+ *tailp = elist;
+ tailp = &elist->next;
+ } while (tok.kind != TOK_RBRACE);
+ *tailp = NULL;
+}
+
+static void
+def_const(defp)
+ definition *defp;
+{
+ token tok;
+
+ defp->def_kind = DEF_CONST;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_EQUAL, &tok);
+ scan2(TOK_IDENT, TOK_STRCONST, &tok);
+ defp->def.co = tok.str;
+}
+
+static void
+def_union(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ case_list *cases;
+ case_list **tailp;
+ int flag;
+
+ defp->def_kind = DEF_UNION;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_SWITCH, &tok);
+ scan(TOK_LPAREN, &tok);
+ get_declaration(&dec, DEF_UNION);
+ defp->def.un.enum_decl = dec;
+ tailp = &defp->def.un.cases;
+ scan(TOK_RPAREN, &tok);
+ scan(TOK_LBRACE, &tok);
+ scan(TOK_CASE, &tok);
+ while (tok.kind == TOK_CASE) {
+ scan2(TOK_IDENT, TOK_CHARCONST, &tok);
+ cases = ALLOC(case_list);
+ cases->case_name = tok.str;
+ scan(TOK_COLON, &tok);
+ /* now peek at next token */
+ flag = 0;
+ if (peekscan(TOK_CASE, &tok)){
+ do {
+ scan2(TOK_IDENT, TOK_CHARCONST, &tok);
+ cases->contflag = 1;
+ /* continued case statement */
+ *tailp = cases;
+ tailp = &cases->next;
+ cases = ALLOC(case_list);
+ cases->case_name = tok.str;
+ scan(TOK_COLON, &tok);
+ } while (peekscan(TOK_CASE, &tok));
+ }
+ else
+ if (flag)
+ {
+
+ *tailp = cases;
+ tailp = &cases->next;
+ cases = ALLOC(case_list);
+ };
+
+ get_declaration(&dec, DEF_UNION);
+ cases->case_decl = dec;
+ cases->contflag = 0; /* no continued case statement */
+ *tailp = cases;
+ tailp = &cases->next;
+ scan(TOK_SEMICOLON, &tok);
+
+ scan3(TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok);
+ }
+ *tailp = NULL;
+ if (tok.kind == TOK_DEFAULT) {
+ scan(TOK_COLON, &tok);
+ get_declaration(&dec, DEF_UNION);
+ defp->def.un.default_decl = ALLOC(declaration);
+ *defp->def.un.default_decl = dec;
+ scan(TOK_SEMICOLON, &tok);
+ scan(TOK_RBRACE, &tok);
+ } else {
+ defp->def.un.default_decl = NULL;
+ }
+}
+
+static char* reserved_words[] =
+{
+ "array",
+ "bytes",
+ "destroy",
+ "free",
+ "getpos",
+ "inline",
+ "pointer",
+ "reference",
+ "setpos",
+ "sizeof",
+ "union",
+ "vector",
+ NULL
+ };
+
+static char* reserved_types[] =
+{
+ "opaque",
+ "string",
+ NULL
+ };
+
+/*
+ * check that the given name is not one that would eventually result in
+ * xdr routines that would conflict with internal XDR routines.
+ */
+static void
+check_type_name(name, new_type)
+int new_type;
+char* name;
+{
+ int i;
+ char tmp[100];
+
+ for (i = 0; reserved_words[i] != NULL; i++) {
+ if (strcmp(name, reserved_words[i]) == 0) {
+ sprintf(tmp,
+ "illegal (reserved) name :\'%s\' in type definition",
+ name);
+ error(tmp);
+ }
+ }
+ if (new_type) {
+ for (i = 0; reserved_types[i] != NULL; i++) {
+ if (strcmp(name, reserved_types[i]) == 0) {
+ sprintf(tmp,
+ "illegal (reserved) name :\'%s\' in type definition",
+ name);
+ error(tmp);
+ }
+ }
+ }
+}
+
+
+
+static void
+def_typedef(defp)
+ definition *defp;
+{
+ declaration dec;
+
+ defp->def_kind = DEF_TYPEDEF;
+ get_declaration(&dec, DEF_TYPEDEF);
+ defp->def_name = dec.name;
+ check_type_name(dec.name, 1);
+ defp->def.ty.old_prefix = dec.prefix;
+ defp->def.ty.old_type = dec.type;
+ defp->def.ty.rel = dec.rel;
+ defp->def.ty.array_max = dec.array_max;
+}
+
+static void
+get_declaration(dec, dkind)
+ declaration *dec;
+ defkind dkind;
+{
+ token tok;
+
+ get_type(&dec->prefix, &dec->type, dkind);
+ dec->rel = REL_ALIAS;
+ if (streq(dec->type, "void")) {
+ return;
+ }
+
+ check_type_name(dec->type, 0);
+ scan2(TOK_STAR, TOK_IDENT, &tok);
+ if (tok.kind == TOK_STAR) {
+ dec->rel = REL_POINTER;
+ scan(TOK_IDENT, &tok);
+ }
+ dec->name = tok.str;
+ if (peekscan(TOK_LBRACKET, &tok)) {
+ if (dec->rel == REL_POINTER) {
+ error("no array-of-pointer declarations -- use typedef");
+ }
+ dec->rel = REL_VECTOR;
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RBRACKET, &tok);
+ } else if (peekscan(TOK_LANGLE, &tok)) {
+ if (dec->rel == REL_POINTER) {
+ error("no array-of-pointer declarations -- use typedef");
+ }
+ dec->rel = REL_ARRAY;
+ if (peekscan(TOK_RANGLE, &tok)) {
+ dec->array_max = "~0"; /* unspecified size, use max */
+ } else {
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RANGLE, &tok);
+ }
+ }
+ if (streq(dec->type, "opaque")) {
+ if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) {
+ error("array declaration expected");
+ }
+ } else if (streq(dec->type, "string")) {
+ if (dec->rel != REL_ARRAY) {
+ error("variable-length array declaration expected");
+ }
+ }
+}
+
+
+static void
+get_prog_declaration(dec, dkind, num)
+ declaration *dec;
+ defkind dkind;
+ int num; /* arg number */
+{
+ token tok;
+ char name[10]; /* argument name */
+
+ if (dkind == DEF_PROGRAM) {
+ peek(&tok);
+ if (tok.kind == TOK_RPAREN) { /* no arguments */
+ dec->rel = REL_ALIAS;
+ dec->type = "void";
+ dec->prefix = NULL;
+ dec->name = NULL;
+ return;
+ }
+ }
+ get_type(&dec->prefix, &dec->type, dkind);
+ dec->rel = REL_ALIAS;
+ if (peekscan(TOK_IDENT, &tok)) /* optional name of argument */
+ strcpy(name, tok.str);
+ else
+ sprintf(name, "%s%d", ARGNAME, num);
+ /* default name of argument */
+
+ dec->name = (char *) strdup(name);
+ if (streq(dec->type, "void")) {
+ return;
+ }
+
+ if (streq(dec->type, "opaque")) {
+ error("opaque -- illegal argument type");
+ }
+ if (peekscan(TOK_STAR, &tok)) {
+ if (streq(dec->type, "string")) {
+ error("pointer to string not allowed in program arguments\n");
+ }
+ dec->rel = REL_POINTER;
+ if (peekscan(TOK_IDENT, &tok))
+ /* optional name of argument */
+ dec->name = strdup(tok.str);
+ }
+ if (peekscan(TOK_LANGLE, &tok)) {
+ if (!streq(dec->type, "string")) {
+ error("arrays cannot be declared as arguments to procedures -- use typedef");
+ }
+ dec->rel = REL_ARRAY;
+ if (peekscan(TOK_RANGLE, &tok)) {
+ dec->array_max = "~0";
+ /* unspecified size, use max */
+ } else {
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RANGLE, &tok);
+ }
+ }
+ if (streq(dec->type, "string")) {
+ if (dec->rel != REL_ARRAY) {
+ /*
+ * .x specifies just string as
+ * type of argument
+ * - make it string<>
+ */
+ dec->rel = REL_ARRAY;
+ dec->array_max = "~0"; /* unspecified size, use max */
+ }
+ }
+}
+
+
+
+static void
+get_type(prefixp, typep, dkind)
+ char **prefixp;
+ char **typep;
+ defkind dkind;
+{
+ token tok;
+
+ *prefixp = NULL;
+ get_token(&tok);
+ switch (tok.kind) {
+ case TOK_IDENT:
+ *typep = tok.str;
+ break;
+ case TOK_STRUCT:
+ case TOK_ENUM:
+ case TOK_UNION:
+ *prefixp = tok.str;
+ scan(TOK_IDENT, &tok);
+ *typep = tok.str;
+ break;
+ case TOK_UNSIGNED:
+ unsigned_dec(typep);
+ break;
+ case TOK_SHORT:
+ *typep = "short";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_LONG:
+ *typep = "long";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_HYPER:
+ *typep = "longlong_t";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+
+ case TOK_VOID:
+ if (dkind != DEF_UNION && dkind != DEF_PROGRAM) {
+ error("voids allowed only inside union and program definitions with one argument");
+ }
+ *typep = tok.str;
+ break;
+ case TOK_STRING:
+ case TOK_OPAQUE:
+ case TOK_CHAR:
+ case TOK_INT:
+ case TOK_FLOAT:
+ case TOK_DOUBLE:
+ case TOK_BOOL:
+ case TOK_QUAD:
+ *typep = tok.str;
+ break;
+ default:
+ error("expected type specifier");
+ }
+}
+
+static void
+unsigned_dec(typep)
+ char **typep;
+{
+ token tok;
+
+ peek(&tok);
+ switch (tok.kind) {
+ case TOK_CHAR:
+ get_token(&tok);
+ *typep = "u_char";
+ break;
+ case TOK_SHORT:
+ get_token(&tok);
+ *typep = "u_short";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_LONG:
+ get_token(&tok);
+ *typep = "u_long";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_HYPER:
+ get_token(&tok);
+ *typep = "ulonglong_t";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_INT:
+ get_token(&tok);
+ *typep = "u_int";
+ break;
+ default:
+ *typep = "u_int";
+ break;
+ }
+}
diff --git a/usr.bin/rpcgen/rpc_parse.h b/usr.bin/rpcgen/rpc_parse.h
new file mode 100644
index 0000000..b61db9d
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_parse.h
@@ -0,0 +1,197 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#pragma ident "@(#)rpc_parse.h 1.10 94/05/15 SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+* PROPRIETARY NOTICE (Combined)
+*
+* This source code is unpublished proprietary information
+* constituting, or derived under license from AT&T's UNIX(r) System V.
+* In addition, portions of such source code were derived from Berkeley
+* 4.3 BSD under license from the Regents of the University of
+* California.
+*
+*
+*
+* Copyright Notice
+*
+* Notice of copyright on this source code product does not indicate
+* publication.
+*
+* (c) 1986,1987,1988.1989 Sun Microsystems, Inc
+* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+* All rights reserved.
+*/
+
+/* @(#)rpc_parse.h 1.3 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_parse.h, Definitions for the RPCL parser
+ */
+
+enum defkind {
+ DEF_CONST,
+ DEF_STRUCT,
+ DEF_UNION,
+ DEF_ENUM,
+ DEF_TYPEDEF,
+ DEF_PROGRAM
+};
+typedef enum defkind defkind;
+
+typedef char *const_def;
+
+enum relation {
+ REL_VECTOR, /* fixed length array */
+ REL_ARRAY, /* variable length array */
+ REL_POINTER, /* pointer */
+ REL_ALIAS, /* simple */
+};
+typedef enum relation relation;
+
+struct typedef_def {
+ char *old_prefix;
+ char *old_type;
+ relation rel;
+ char *array_max;
+};
+typedef struct typedef_def typedef_def;
+
+struct enumval_list {
+ char *name;
+ char *assignment;
+ struct enumval_list *next;
+};
+typedef struct enumval_list enumval_list;
+
+struct enum_def {
+ enumval_list *vals;
+};
+typedef struct enum_def enum_def;
+
+struct declaration {
+ char *prefix;
+ char *type;
+ char *name;
+ relation rel;
+ char *array_max;
+};
+typedef struct declaration declaration;
+
+struct decl_list {
+ declaration decl;
+ struct decl_list *next;
+};
+typedef struct decl_list decl_list;
+
+struct struct_def {
+ decl_list *decls;
+};
+typedef struct struct_def struct_def;
+
+struct case_list {
+ char *case_name;
+ int contflag;
+ declaration case_decl;
+ struct case_list *next;
+};
+typedef struct case_list case_list;
+
+struct union_def {
+ declaration enum_decl;
+ case_list *cases;
+ declaration *default_decl;
+};
+typedef struct union_def union_def;
+
+struct arg_list {
+ char *argname; /* name of struct for arg*/
+ decl_list *decls;
+};
+
+typedef struct arg_list arg_list;
+
+struct proc_list {
+ char *proc_name;
+ char *proc_num;
+ arg_list args;
+ int arg_num;
+ char *res_type;
+ char *res_prefix;
+ struct proc_list *next;
+};
+typedef struct proc_list proc_list;
+
+struct version_list {
+ char *vers_name;
+ char *vers_num;
+ proc_list *procs;
+ struct version_list *next;
+};
+typedef struct version_list version_list;
+
+struct program_def {
+ char *prog_num;
+ version_list *versions;
+};
+typedef struct program_def program_def;
+
+struct definition {
+ char *def_name;
+ defkind def_kind;
+ union {
+ const_def co;
+ struct_def st;
+ union_def un;
+ enum_def en;
+ typedef_def ty;
+ program_def pr;
+ } def;
+};
+typedef struct definition definition;
+
+definition *get_definition();
+
+
+struct bas_type
+{
+ char *name;
+ int length;
+ struct bas_type *next;
+};
+
+typedef struct bas_type bas_type;
diff --git a/usr.bin/rpcgen/rpc_sample.c b/usr.bin/rpcgen/rpc_sample.c
new file mode 100644
index 0000000..1de374c
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_sample.c
@@ -0,0 +1,312 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#pragma ident "@(#)rpc_sample.c 1.9 94/04/25 SMI"
+
+/*
+ * rpc_sample.c, Sample client-server code outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+
+static char RQSTP[] = "rqstp";
+
+extern void printarglist __P(( proc_list *, char *, char *, char *));
+static void write_sample_client __P(( char *, version_list * ));
+static void write_sample_server __P(( definition * ));
+static void return_type __P(( proc_list * ));
+
+void
+write_sample_svc(def)
+ definition *def;
+{
+
+ if (def->def_kind != DEF_PROGRAM)
+ return;
+ write_sample_server(def);
+}
+
+
+int
+write_sample_clnt(def)
+ definition *def;
+{
+ version_list *vp;
+ int count = 0;
+
+ if (def->def_kind != DEF_PROGRAM)
+ return(0);
+ /* generate sample code for each version */
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ write_sample_client(def->def_name, vp);
+ ++count;
+ }
+ return(count);
+}
+
+
+static void
+write_sample_client(program_name, vp)
+ char *program_name;
+ version_list *vp;
+{
+ proc_list *proc;
+ int i;
+ decl_list *l;
+
+ f_print(fout, "\n\nvoid\n");
+ pvname(program_name, vp->vers_num);
+ if(Cflag)
+ f_print(fout,"(char *host)\n{\n");
+ else
+ f_print(fout, "(host)\n\tchar *host;\n{\n");
+ f_print(fout, "\tCLIENT *clnt;\n");
+
+ i = 0;
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\t");
+ if (mtflag) {
+ f_print(fout, "enum clnt_stat retval_%d;\n\t", ++i);
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "result_%d;\n", i);
+ } else {
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, " *result_%d;\n",++i);
+ }
+ /* print out declarations for arguments */
+ if(proc->arg_num < 2 && !newstyle) {
+ f_print(fout, "\t");
+ if(!streq(proc->args.decls->decl.type, "void"))
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 1);
+ else
+ f_print(fout, "char * "); /* cannot have "void" type */
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+ } else if (!streq(proc->args.decls->decl.type, "void")) {
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ f_print(fout, "\t");
+ ptype(l->decl.prefix, l->decl.type, 1);
+ if (strcmp(l->decl.type,"string") == 1)
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_%s;\n", l->decl.name);
+ }
+ }
+ }
+
+ /* generate creation of client handle */
+ f_print(fout, "\n#ifndef\tDEBUG\n");
+ f_print(fout, "\tclnt = clnt_create(host, %s, %s, \"%s\");\n",
+ program_name, vp->vers_name, tirpcflag? "netpath" : "udp");
+ f_print(fout, "\tif (clnt == (CLIENT *) NULL) {\n");
+ f_print(fout, "\t\tclnt_pcreateerror(host);\n");
+ f_print(fout, "\t\texit(1);\n\t}\n");
+ f_print(fout, "#endif\t/* DEBUG */\n\n");
+
+ /* generate calls to procedures */
+ i = 0;
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ if (mtflag)
+ f_print(fout, "\tretval_%d = ",++i);
+ else
+ f_print(fout, "\tresult_%d = ",++i);
+ pvname(proc->proc_name, vp->vers_num);
+ if (proc->arg_num < 2 && !newstyle) {
+ f_print(fout, "(");
+ if(streq(proc->args.decls->decl.type, "void"))
+ /* cast to void * */
+ f_print(fout, "(void *)");
+ f_print(fout, "&");
+ pvname(proc->proc_name, vp->vers_num);
+ if (mtflag)
+ f_print(fout, "_arg, &result_%d, clnt);\n",
+ i);
+ else
+ f_print(fout, "_arg, clnt);\n");
+
+ } else if (streq(proc->args.decls->decl.type, "void")) {
+ if (mtflag)
+ f_print(fout, "(&result_%d, clnt);\n", i);
+ else
+ f_print(fout, "(clnt);\n");
+ }
+ else {
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_%s, ", l->decl.name);
+ }
+ if (mtflag)
+ f_print(fout, "&result_%d, ", i);
+
+ f_print(fout, "clnt);\n");
+ }
+ if (mtflag) {
+ f_print(fout, "\tif (retval_%d != RPC_SUCCESS) {\n", i);
+
+ } else {
+ f_print(fout, "\tif (result_%d == (", i);
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*) NULL) {\n");
+ }
+ f_print(fout, "\t\tclnt_perror(clnt, \"call failed\");\n");
+ f_print(fout, "\t}\n");
+ }
+
+ f_print(fout, "#ifndef\tDEBUG\n");
+ f_print(fout, "\tclnt_destroy(clnt);\n");
+ f_print(fout, "#endif\t /* DEBUG */\n");
+ f_print(fout, "}\n");
+}
+
+static void
+write_sample_server(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+ if (!mtflag) {
+ return_type(proc);
+ f_print(fout, "*\n");
+ } else
+ f_print(fout, "bool_t\n");
+ if (Cflag || mtflag)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+ printarglist(proc, "result", RQSTP, "struct svc_req *");
+
+ f_print(fout, "{\n");
+ if (!mtflag) {
+ f_print(fout, "\tstatic ");
+ if(!streq(proc->res_type, "void"))
+ return_type(proc);
+ else
+ f_print(fout, "char *");
+ /* cannot have void type */
+ f_print(fout, " result;\n", proc->res_type);
+ }
+ else
+ f_print(fout, "\tbool_t retval;\n");
+ f_print(fout,
+ "\n\t/*\n\t * insert server code here\n\t */\n\n");
+
+ if (!mtflag)
+ if(!streq(proc->res_type, "void"))
+ f_print(fout, "\treturn (&result);\n}\n");
+ else /* cast back to void * */
+ f_print(fout, "\treturn((void *) &result);\n}\n");
+ else
+ f_print(fout, "\treturn (retval);\n}\n");
+ }
+ /* put in sample freeing routine */
+ if (mtflag) {
+ f_print(fout, "\nint\n");
+ pvname(def->def_name, vp->vers_num);
+ if (Cflag)
+ f_print(fout,"_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)\n");
+ else {
+ f_print(fout,"_freeresult(transp, xdr_result, result)\n");
+ f_print(fout,"\tSVCXPRT *transp;\n");
+ f_print(fout,"\txdrproc_t xdr_result;\n");
+ f_print(fout,"\tcaddr_t result;\n");
+ }
+ f_print(fout, "{\n");
+ f_print(fout, "\t(void) xdr_free(xdr_result, result);\n");
+ f_print(fout,
+ "\n\t/*\n\t * Insert additional freeing code here, if needed\n\t */\n");
+ f_print(fout, "\n}\n");
+
+
+ }
+ }
+}
+
+
+
+static void
+return_type(plist)
+ proc_list *plist;
+{
+ ptype(plist->res_prefix, plist->res_type, 1);
+}
+
+void
+add_sample_msg()
+{
+ f_print(fout, "/*\n");
+ f_print(fout, " * This is sample code generated by rpcgen.\n");
+ f_print(fout, " * These are only templates and you can use them\n");
+ f_print(fout, " * as a guideline for developing your own functions.\n");
+ f_print(fout, " */\n\n");
+}
+
+void
+write_sample_clnt_main()
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ f_print(fout, "\n\n");
+ if(Cflag)
+ f_print(fout,"main(int argc, char *argv[])\n{\n");
+ else
+ f_print(fout, "main(argc, argv)\n\tint argc;\n\tchar *argv[];\n{\n");
+
+ f_print(fout, "\tchar *host;");
+ f_print(fout, "\n\n\tif (argc < 2) {");
+ f_print(fout, "\n\t\tprintf(\"usage: %%s server_host\\n\", argv[0]);\n");
+ f_print(fout, "\t\texit(1);\n\t}");
+ f_print(fout, "\n\thost = argv[1];\n");
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "\t");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, "(host);\n");
+ }
+ }
+ f_print(fout, "}\n");
+}
diff --git a/usr.bin/rpcgen/rpc_scan.c b/usr.bin/rpcgen/rpc_scan.c
new file mode 100644
index 0000000..d1d03aa
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_scan.c
@@ -0,0 +1,517 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_scan.c 1.13 93/07/05 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_scan.c, Scanner for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+
+#include <sys/wait.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define startcomment(where) (where[0] == '/' && where[1] == '*')
+#define endcomment(where) (where[-1] == '*' && where[0] == '/')
+
+static int pushed = 0; /* is a token pushed */
+static token lasttok; /* last token, if pushed */
+
+static void unget_token __P(( token * ));
+static void findstrconst __P(( char **, char **));
+static void findchrconst __P(( char **, char **));
+static void findconst __P(( char **, char **));
+static void findkind __P(( char **, token * ));
+static int cppline __P(( char * ));
+static int directive __P(( char * ));
+static void printdirective __P(( char * ));
+static void docppline __P(( char *, int *, char ** ));
+
+/*
+ * scan expecting 1 given token
+ */
+void
+scan(expect, tokp)
+ tok_kind expect;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect) {
+ expected1(expect);
+ }
+}
+
+/*
+ * scan expecting any of the 2 given tokens
+ */
+void
+scan2(expect1, expect2, tokp)
+ tok_kind expect1;
+ tok_kind expect2;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect1 && tokp->kind != expect2) {
+ expected2(expect1, expect2);
+ }
+}
+
+/*
+ * scan expecting any of the 3 given token
+ */
+void
+scan3(expect1, expect2, expect3, tokp)
+ tok_kind expect1;
+ tok_kind expect2;
+ tok_kind expect3;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect1 && tokp->kind != expect2
+ && tokp->kind != expect3) {
+ expected3(expect1, expect2, expect3);
+ }
+}
+
+/*
+ * scan expecting a constant, possibly symbolic
+ */
+void
+scan_num(tokp)
+ token *tokp;
+{
+ get_token(tokp);
+ switch (tokp->kind) {
+ case TOK_IDENT:
+ break;
+ default:
+ error("constant or identifier expected");
+ }
+}
+
+/*
+ * Peek at the next token
+ */
+void
+peek(tokp)
+ token *tokp;
+{
+ get_token(tokp);
+ unget_token(tokp);
+}
+
+/*
+ * Peek at the next token and scan it if it matches what you expect
+ */
+int
+peekscan(expect, tokp)
+ tok_kind expect;
+ token *tokp;
+{
+ peek(tokp);
+ if (tokp->kind == expect) {
+ get_token(tokp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Get the next token, printing out any directive that are encountered.
+ */
+void
+get_token(tokp)
+ token *tokp;
+{
+ int commenting;
+ int stat = 0;
+
+
+ if (pushed) {
+ pushed = 0;
+ *tokp = lasttok;
+ return;
+ }
+ commenting = 0;
+ for (;;) {
+ if (*where == 0) {
+ for (;;) {
+ if (!fgets(curline, MAXLINESIZE, fin)) {
+ tokp->kind = TOK_EOF;
+ /* now check if cpp returned non NULL value */
+ waitpid(childpid, &stat, WUNTRACED);
+ if (stat > 0) {
+ /* Set return value from rpcgen */
+ nonfatalerrors = stat >> 8;
+ }
+ *where = 0;
+ return;
+ }
+ linenum++;
+ if (commenting) {
+ break;
+ } else if (cppline(curline)) {
+ docppline(curline, &linenum,
+ &infilename);
+ } else if (directive(curline)) {
+ printdirective(curline);
+ } else {
+ break;
+ }
+ }
+ where = curline;
+ } else if (isspace(*where)) {
+ while (isspace(*where)) {
+ where++; /* eat */
+ }
+ } else if (commenting) {
+ for (where++; *where; where++) {
+ if (endcomment(where)) {
+ where++;
+ commenting--;
+ break;
+ }
+ }
+ } else if (startcomment(where)) {
+ where += 2;
+ commenting++;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * 'where' is not whitespace, comment or directive Must be a token!
+ */
+ switch (*where) {
+ case ':':
+ tokp->kind = TOK_COLON;
+ where++;
+ break;
+ case ';':
+ tokp->kind = TOK_SEMICOLON;
+ where++;
+ break;
+ case ',':
+ tokp->kind = TOK_COMMA;
+ where++;
+ break;
+ case '=':
+ tokp->kind = TOK_EQUAL;
+ where++;
+ break;
+ case '*':
+ tokp->kind = TOK_STAR;
+ where++;
+ break;
+ case '[':
+ tokp->kind = TOK_LBRACKET;
+ where++;
+ break;
+ case ']':
+ tokp->kind = TOK_RBRACKET;
+ where++;
+ break;
+ case '{':
+ tokp->kind = TOK_LBRACE;
+ where++;
+ break;
+ case '}':
+ tokp->kind = TOK_RBRACE;
+ where++;
+ break;
+ case '(':
+ tokp->kind = TOK_LPAREN;
+ where++;
+ break;
+ case ')':
+ tokp->kind = TOK_RPAREN;
+ where++;
+ break;
+ case '<':
+ tokp->kind = TOK_LANGLE;
+ where++;
+ break;
+ case '>':
+ tokp->kind = TOK_RANGLE;
+ where++;
+ break;
+
+ case '"':
+ tokp->kind = TOK_STRCONST;
+ findstrconst(&where, &tokp->str);
+ break;
+ case '\'':
+ tokp->kind = TOK_CHARCONST;
+ findchrconst(&where, &tokp->str);
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tokp->kind = TOK_IDENT;
+ findconst(&where, &tokp->str);
+ break;
+
+ default:
+ if (!(isalpha(*where) || *where == '_')) {
+ char buf[100];
+ char *p;
+
+ s_print(buf, "illegal character in file: ");
+ p = buf + strlen(buf);
+ if (isprint(*where)) {
+ s_print(p, "%c", *where);
+ } else {
+ s_print(p, "%d", *where);
+ }
+ error(buf);
+ }
+ findkind(&where, tokp);
+ break;
+ }
+}
+
+static void
+unget_token(tokp)
+ token *tokp;
+{
+ lasttok = *tokp;
+ pushed = 1;
+}
+
+static void
+findstrconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ do {
+ p++;
+ } while (*p && *p != '"');
+ if (*p == 0) {
+ error("unterminated string constant");
+ }
+ p++;
+ size = p - *str;
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static void
+findchrconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ do {
+ p++;
+ } while (*p && *p != '\'');
+ if (*p == 0) {
+ error("unterminated string constant");
+ }
+ p++;
+ size = p - *str;
+ if (size != 3) {
+ error("empty char string");
+ }
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static void
+findconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ if (*p == '0' && *(p + 1) == 'x') {
+ p++;
+ do {
+ p++;
+ } while (isxdigit(*p));
+ } else {
+ do {
+ p++;
+ } while (isdigit(*p));
+ }
+ size = p - *str;
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static token symbols[] = {
+ {TOK_CONST, "const"},
+ {TOK_UNION, "union"},
+ {TOK_SWITCH, "switch"},
+ {TOK_CASE, "case"},
+ {TOK_DEFAULT, "default"},
+ {TOK_STRUCT, "struct"},
+ {TOK_TYPEDEF, "typedef"},
+ {TOK_ENUM, "enum"},
+ {TOK_OPAQUE, "opaque"},
+ {TOK_BOOL, "bool"},
+ {TOK_VOID, "void"},
+ {TOK_CHAR, "char"},
+ {TOK_INT, "int"},
+ {TOK_UNSIGNED, "unsigned"},
+ {TOK_SHORT, "short"},
+ {TOK_LONG, "long"},
+ {TOK_HYPER, "hyper"},
+ {TOK_FLOAT, "float"},
+ {TOK_DOUBLE, "double"},
+ {TOK_QUAD, "quadruple"},
+ {TOK_STRING, "string"},
+ {TOK_PROGRAM, "program"},
+ {TOK_VERSION, "version"},
+ {TOK_EOF, "??????"},
+};
+
+static void
+findkind(mark, tokp)
+ char **mark;
+ token *tokp;
+{
+ int len;
+ token *s;
+ char *str;
+
+ str = *mark;
+ for (s = symbols; s->kind != TOK_EOF; s++) {
+ len = strlen(s->str);
+ if (strncmp(str, s->str, len) == 0) {
+ if (!isalnum(str[len]) && str[len] != '_') {
+ tokp->kind = s->kind;
+ tokp->str = s->str;
+ *mark = str + len;
+ return;
+ }
+ }
+ }
+ tokp->kind = TOK_IDENT;
+ for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
+ tokp->str = alloc(len + 1);
+ (void) strncpy(tokp->str, str, len);
+ tokp->str[len] = 0;
+ *mark = str + len;
+}
+
+static int
+cppline(line)
+ char *line;
+{
+ return (line == curline && *line == '#');
+}
+
+static int
+directive(line)
+ char *line;
+{
+ return (line == curline && *line == '%');
+}
+
+static void
+printdirective(line)
+ char *line;
+{
+ f_print(fout, "%s", line + 1);
+}
+
+static void
+docppline(line, lineno, fname)
+ char *line;
+ int *lineno;
+ char **fname;
+{
+ char *file;
+ int num;
+ char *p;
+
+ line++;
+ while (isspace(*line)) {
+ line++;
+ }
+ num = atoi(line);
+ while (isdigit(*line)) {
+ line++;
+ }
+ while (isspace(*line)) {
+ line++;
+ }
+ if (*line != '"') {
+ error("preprocessor error");
+ }
+ line++;
+ p = file = alloc(strlen(line) + 1);
+ while (*line && *line != '"') {
+ *p++ = *line++;
+ }
+ if (*line == 0) {
+ error("preprocessor error");
+ }
+ *p = 0;
+ if (*file == 0) {
+ *fname = NULL;
+ } else {
+ *fname = file;
+ }
+ *lineno = num - 1;
+}
diff --git a/usr.bin/rpcgen/rpc_scan.h b/usr.bin/rpcgen/rpc_scan.h
new file mode 100644
index 0000000..cf042d0
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_scan.h
@@ -0,0 +1,133 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#pragma ident "@(#)rpc_scan.h 1.11 94/05/15 SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+* PROPRIETARY NOTICE (Combined)
+*
+* This source code is unpublished proprietary information
+* constituting, or derived under license from AT&T's UNIX(r) System V.
+* In addition, portions of such source code were derived from Berkeley
+* 4.3 BSD under license from the Regents of the University of
+* California.
+*
+*
+*
+* Copyright Notice
+*
+* Notice of copyright on this source code product does not indicate
+* publication.
+*
+* (c) 1986,1987,1988.1989 Sun Microsystems, Inc
+* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+* All rights reserved.
+*/
+
+/* @(#)rpc_scan.h 1.3 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_scan.h, Definitions for the RPCL scanner
+ */
+
+/*
+ * kinds of tokens
+ */
+enum tok_kind {
+ TOK_IDENT,
+ TOK_CHARCONST,
+ TOK_STRCONST,
+ TOK_LPAREN,
+ TOK_RPAREN,
+ TOK_LBRACE,
+ TOK_RBRACE,
+ TOK_LBRACKET,
+ TOK_RBRACKET,
+ TOK_LANGLE,
+ TOK_RANGLE,
+ TOK_STAR,
+ TOK_COMMA,
+ TOK_EQUAL,
+ TOK_COLON,
+ TOK_SEMICOLON,
+ TOK_CONST,
+ TOK_STRUCT,
+ TOK_UNION,
+ TOK_SWITCH,
+ TOK_CASE,
+ TOK_DEFAULT,
+ TOK_ENUM,
+ TOK_TYPEDEF,
+ TOK_INT,
+ TOK_SHORT,
+ TOK_LONG,
+ TOK_HYPER,
+ TOK_UNSIGNED,
+ TOK_FLOAT,
+ TOK_DOUBLE,
+ TOK_QUAD,
+ TOK_OPAQUE,
+ TOK_CHAR,
+ TOK_STRING,
+ TOK_BOOL,
+ TOK_VOID,
+ TOK_PROGRAM,
+ TOK_VERSION,
+ TOK_EOF
+};
+typedef enum tok_kind tok_kind;
+
+/*
+ * a token
+ */
+struct token {
+ tok_kind kind;
+ char *str;
+};
+typedef struct token token;
+
+
+/*
+ * routine interface
+ */
+void scan();
+void scan2();
+void scan3();
+void scan_num();
+void peek();
+int peekscan();
+void get_token();
diff --git a/usr.bin/rpcgen/rpc_svcout.c b/usr.bin/rpcgen/rpc_svcout.c
new file mode 100644
index 0000000..cb26f22
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_svcout.c
@@ -0,0 +1,1086 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_svcout.c 1.4 90/04/13 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_svcout.c 1.29 89/03/30 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_svcout.c, Server-skeleton outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static char RQSTP[] = "rqstp";
+static char TRANSP[] = "transp";
+static char ARG[] = "argument";
+static char RESULT[] = "result";
+static char ROUTINE[] = "local";
+static char RETVAL[] = "retval";
+
+char _errbuf[256]; /* For all messages */
+
+void internal_proctype __P(( proc_list * ));
+static void write_real_program __P(( definition * ));
+static void write_program __P(( definition *, char * ));
+static void printerr __P(( char *, char * ));
+static void printif __P(( char *, char *, char *, char * ));
+static void write_inetmost __P(( char * ));
+static void print_return __P(( char * ));
+static void print_pmapunset __P(( char * ));
+static void print_err_message __P(( char * ));
+static void write_timeout_func __P(( void ));
+static void write_pm_most __P(( char *, int ));
+static void write_rpc_svc_fg __P(( char *, char * ));
+static void open_log_file __P(( char *, char * ));
+static void write_msg_out __P(( void ));
+int nullproc __P(( proc_list * ));
+
+
+static void
+p_xdrfunc(rname, typename)
+char* rname;
+char* typename;
+{
+ if (Cflag)
+ f_print(fout, "\t\txdr_%s = (xdrproc_t) xdr_%s;\n",
+ rname, stringfix(typename));
+ else
+ f_print(fout, "\t\txdr_%s = xdr_%s;\n",
+ rname, stringfix(typename));
+}
+
+void
+internal_proctype(plist)
+ proc_list *plist;
+{
+ f_print(fout, "static ");
+ ptype(plist->res_prefix, plist->res_type, 1);
+ f_print(fout, "*");
+}
+
+
+/*
+ * write most of the service, that is, everything but the registrations.
+ */
+void
+write_most(infile, netflag, nomain)
+ char *infile; /* our name */
+ int netflag;
+ int nomain;
+{
+ if (inetdflag || pmflag) {
+ char* var_type;
+ var_type = (nomain? "extern" : "static");
+ f_print(fout, "%s int _rpcpmstart;", var_type);
+ f_print(fout, "\t\t/* Started by a port monitor ? */\n");
+ if (!tirpcflag) {
+ f_print(fout, "%s int _rpcfdtype;", var_type);
+ f_print(fout, "\n\t\t /* Whether Stream or \
+Datagram ? */\n");
+ }
+
+ if (timerflag) {
+ f_print(fout, " /* States a server can be in \
+wrt request */\n\n");
+ f_print(fout, "#define\t_IDLE 0\n");
+ f_print(fout, "#define\t_SERVED 1\n");
+ f_print(fout, "#define\t_SERVING 2\n\n");
+ f_print(fout, "static int _rpcsvcstate = _IDLE;");
+ f_print(fout, "\t /* Set when a request is \
+serviced */\n");
+
+ if (mtflag) {
+ f_print(fout, "mutex_t _svcstate_lock;");
+ f_print(fout, "\t\t\t/* Mutex lock for variable _rpcsvcstate */\n");
+
+ }
+
+ }
+
+ write_svc_aux(nomain);
+ }
+ /* write out dispatcher and stubs */
+ write_programs(nomain? (char *)NULL : "static");
+
+ if (nomain)
+ return;
+
+ f_print(fout, "\nmain()\n");
+ f_print(fout, "{\n");
+ if (inetdflag) {
+ write_inetmost(infile);
+ /* Includes call to write_rpc_svc_fg() */
+ } else {
+ if (tirpcflag) {
+ if (netflag) {
+ f_print(fout,
+ "\tregister SVCXPRT *%s;\n", TRANSP);
+ f_print(fout,
+ "\tstruct netconfig *nconf = NULL;\n");
+ }
+ f_print(fout, "\tpid_t pid;\n");
+ f_print(fout, "\tint i;\n");
+ f_print(fout, "\tchar mname[FMNAMESZ + 1];\n\n");
+
+ if (mtflag & timerflag)
+ f_print(fout, "\tmutex_init(&_svcstate_lock, USYNC_THREAD, NULL);\n");
+
+ write_pm_most(infile, netflag);
+ f_print(fout, "\telse {\n");
+ write_rpc_svc_fg(infile, "\t\t");
+ f_print(fout, "\t}\n");
+ } else {
+ f_print(fout, "\tregister SVCXPRT *%s;\n", TRANSP);
+ f_print(fout, "\n");
+ print_pmapunset("\t");
+ }
+ }
+
+ if (logflag && !inetdflag) {
+ open_log_file(infile, "\t");
+ }
+}
+
+/*
+ * write a registration for the given transport
+ */
+void
+write_netid_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+ char *sp;
+ char tmpbuf[32];
+
+ sp = "";
+ f_print(fout, "\n");
+ f_print(fout, "%s\tnconf = getnetconfigent(\"%s\");\n", sp, transp);
+ f_print(fout, "%s\tif (nconf == NULL) {\n", sp);
+ (void) sprintf(_errbuf, "cannot find %s netid.", transp);
+ sprintf(tmpbuf, "%s\t\t", sp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ f_print(fout, "%s\t%s = svc_tli_create(RPC_ANYFD, nconf, 0, 0, 0);\n",
+ sp, TRANSP, transp);
+ f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP);
+ (void) sprintf(_errbuf, "cannot create %s service.", transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout,
+ "%s\t(void) rpcb_unset(%s, %s, nconf);\n",
+ sp, def->def_name, vp->vers_name);
+ f_print(fout,
+ "%s\tif (!svc_reg(%s, %s, %s, ",
+ sp, TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", nconf)) {\n");
+ (void) sprintf(_errbuf,
+ "unable to register (%s, %s, %s).",
+ def->def_name, vp->vers_name, transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ }
+ }
+ f_print(fout, "%s\tfreenetconfigent(nconf);\n", sp);
+}
+
+/*
+ * write a registration for the given transport for TLI
+ */
+void
+write_nettype_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "\tif (!svc_create(");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", %s, %s, \"%s\")) {\n",
+ def->def_name, vp->vers_name, transp);
+ (void) sprintf(_errbuf,
+ "unable to create (%s, %s) for %s.",
+ def->def_name, vp->vers_name, transp);
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ }
+ }
+}
+
+/*
+ * write the rest of the service
+ */
+void
+write_rest()
+{
+ f_print(fout, "\n");
+ if (inetdflag) {
+ f_print(fout, "\tif (%s == (SVCXPRT *)NULL) {\n", TRANSP);
+ (void) sprintf(_errbuf, "could not create a handle");
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ if (timerflag) {
+ f_print(fout, "\tif (_rpcpmstart) {\n");
+ f_print(fout,
+ "\t\t(void) signal(SIGALRM, %s closedown);\n",
+ Cflag? "(SIG_PF)":"(void(*)())");
+ f_print(fout, "\t\t(void) \
+alarm(_RPCSVC_CLOSEDOWN/2);\n");
+ f_print(fout, "\t}\n");
+ }
+ }
+ f_print(fout, "\tsvc_run();\n");
+ (void) sprintf(_errbuf, "svc_run returned");
+ print_err_message("\t");
+ f_print(fout, "\texit(1);\n");
+ f_print(fout, "\t/* NOTREACHED */\n");
+ f_print(fout, "}\n");
+}
+
+void
+write_programs(storage)
+ char *storage;
+{
+ list *l;
+ definition *def;
+
+ /* write out stubs for procedure definitions */
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_real_program(def);
+ }
+ }
+
+ /* write out dispatcher for each program */
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_program(def, storage);
+ }
+ }
+
+
+}
+
+/*
+ * write out definition of internal function (e.g. _printmsg_1(...))
+ * which calls server's defintion of actual function (e.g. printmsg_1(...)).
+ * Unpacks single user argument of printmsg_1 to call-by-value format
+ * expected by printmsg_1.
+ */
+static void
+write_real_program(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+ decl_list *l;
+
+ if (!newstyle) return; /* not needed for old style */
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+ if (!mtflag)
+ internal_proctype(proc);
+ else
+ f_print(fout, "int");
+ f_print(fout, "\n_");
+ pvname(proc->proc_name, vp->vers_num);
+ if (Cflag) {
+ f_print(fout, "(");
+ /* arg name */
+ if (proc->arg_num > 1)
+ f_print(fout, proc->args.argname);
+ else
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ if (mtflag) {
+ f_print(fout, " *argp, void *%s, struct svc_req *%s)\n",
+ RESULT, RQSTP);
+
+
+ }
+ else
+ f_print(fout, " *argp, struct svc_req *%s)\n",
+ RQSTP);
+
+ } else {
+ if (mtflag)
+ f_print(fout, "(argp, %s, %s)\n", RESULT, RQSTP);
+ else
+ f_print(fout, "(argp, %s)\n", RQSTP);
+ /* arg name */
+ if (proc->arg_num > 1)
+ f_print(fout, "\t%s *argp;\n",
+ proc->args.argname);
+ else {
+ f_print(fout, "\t");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ f_print(fout, " *argp;\n");
+ }
+ if (mtflag)
+ f_print(fout, "\tvoid *%s;\n", RESULT);
+ f_print(fout, "\tstruct svc_req *%s;\n", RQSTP);
+ }
+
+ f_print(fout, "{\n");
+ f_print(fout, "\treturn (");
+ if (Cflag || mtflag) /* for mtflag, arguments are different */
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "(");
+ if (proc->arg_num < 2) { /* single argument */
+ if (!streq(proc->args.decls->decl.type, "void"))
+ f_print(fout, "*argp, "); /* non-void */
+ } else {
+ for (l = proc->args.decls; l != NULL;
+ l = l->next)
+ f_print(fout, "argp->%s, ",
+ l->decl.name);
+ }
+ if (mtflag)
+ f_print(fout, "%s, ",RESULT);
+ f_print(fout, "%s));\n}\n", RQSTP);
+ }
+ }
+}
+
+static void
+write_program(def, storage)
+ definition *def;
+ char *storage;
+{
+ version_list *vp;
+ proc_list *proc;
+ int filled;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "\n");
+ if (storage != NULL) {
+ f_print(fout, "%s ", storage);
+ }
+ f_print(fout, "void\n");
+ pvname(def->def_name, vp->vers_num);
+
+ if (Cflag) {
+ f_print(fout, "(struct svc_req *%s, ", RQSTP);
+ f_print(fout, "register SVCXPRT *%s)\n", TRANSP);
+ } else {
+ f_print(fout, "(%s, %s)\n", RQSTP, TRANSP);
+ f_print(fout, " struct svc_req *%s;\n", RQSTP);
+ f_print(fout, " register SVCXPRT *%s;\n", TRANSP);
+ }
+
+ f_print(fout, "{\n");
+
+ filled = 0;
+ f_print(fout, "\tunion {\n");
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ if (proc->arg_num < 2) { /* single argument */
+ if (streq(proc->args.decls->decl.type,
+ "void")) {
+ continue;
+ }
+ filled = 1;
+ f_print(fout, "\t\t");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+
+ } else {
+ filled = 1;
+ f_print(fout, "\t\t%s", proc->args.argname);
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+ }
+ }
+ if (!filled) {
+ f_print(fout, "\t\tint fill;\n");
+ }
+ f_print(fout, "\t} %s;\n", ARG);
+
+ if (mtflag) {
+ f_print(fout, "\tunion {\n");
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\t\t");
+ ptype(proc->res_prefix, proc->res_type, 0);
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_res;\n");
+ }
+ f_print(fout, "\t} %s;\n", RESULT);
+ f_print(fout, "\tbool_t %s;\n", RETVAL);
+
+ } else
+ f_print(fout, "\tchar *%s;\n", RESULT);
+
+ if (Cflag) {
+ f_print(fout, "\txdrproc_t xdr_%s, xdr_%s;\n",
+ ARG, RESULT);
+ if (mtflag)
+ f_print(fout,
+ "\tbool_t (*%s)(char *, void *, struct svc_req *);\n",
+ ROUTINE);
+ else
+ f_print(fout,
+ "\tchar *(*%s)(char *, struct svc_req *);\n",
+ ROUTINE);
+ } else {
+ f_print(fout,
+ "\tbool_t (*xdr_%s)(), (*xdr_%s)();\n",
+ ARG, RESULT);
+ if (mtflag)
+ f_print(fout, "\tbool_t (*%s)();\n", ROUTINE);
+ else
+ f_print(fout, "\tchar *(*%s)();\n", ROUTINE);
+ }
+ f_print(fout, "\n");
+
+ if (timerflag) {
+ if (mtflag)
+ f_print(fout, "\tmutex_lock(&_svcstate_lock);\n");
+
+ f_print(fout, "\t_rpcsvcstate = _SERVING;\n");
+ if (mtflag)
+ f_print(fout, "\tmutex_unlock(&_svcstate_lock);\n");
+ }
+
+ f_print(fout, "\tswitch (%s->rq_proc) {\n", RQSTP);
+ if (!nullproc(vp->procs)) {
+ f_print(fout, "\tcase NULLPROC:\n");
+ f_print(fout,
+ Cflag
+ ? "\t\t(void) svc_sendreply(%s,\n\t\t\t\
+(xdrproc_t) xdr_void, (char *)NULL);\n"
+ : "\t\t(void) svc_sendreply(%s, xdr_void,\n\t\t\t\
+(char *)NULL);\n",
+ TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\n");
+ }
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\tcase %s:\n", proc->proc_name);
+ if (proc->arg_num < 2) { /* single argument */
+ p_xdrfunc(ARG, proc->args.decls->decl.type);
+ } else {
+ p_xdrfunc(ARG, proc->args.argname);
+ }
+ p_xdrfunc(RESULT, proc->res_type);
+
+ if (Cflag)
+ if (mtflag)
+ f_print(fout,
+ "\t\t%s = (bool_t (*) (char *, void *, struct svc_req *))",
+ ROUTINE);
+ else
+ f_print(fout,
+ "\t\t%s = (char *(*)(char *, struct svc_req *)) ",
+ ROUTINE);
+ else
+ if (mtflag)
+ f_print(fout, "\t\t%s = (bool_t (*)()) ",
+ ROUTINE);
+ else
+
+ f_print(fout, "\t\t%s = (char *(*)()) ",
+ ROUTINE);
+ if (newstyle) { /* new style: calls internal routine */
+ f_print(fout, "_");
+ }
+ if ((Cflag || mtflag) && !newstyle)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, ";\n");
+ f_print(fout, "\t\tbreak;\n\n");
+ }
+ f_print(fout, "\tdefault:\n");
+ printerr("noproc", TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\t}\n");
+
+ f_print(fout,
+ "\t(void) memset((char *)&%s, 0, sizeof (%s));\n",
+ ARG, ARG);
+ if (Cflag)
+ printif("getargs", TRANSP, "(caddr_t) &", ARG);
+ else
+ printif("getargs", TRANSP, "&", ARG);
+ printerr("decode", TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\t}\n");
+
+ if (!mtflag)
+ if (Cflag)
+ f_print(fout, "\t%s = (*%s)((char *)&%s, %s);\n",
+ RESULT, ROUTINE, ARG, RQSTP);
+ else
+ f_print(fout, "\t%s = (*%s)(&%s, %s);\n",
+ RESULT, ROUTINE, ARG, RQSTP);
+ else
+ if (Cflag)
+ f_print(fout, "\t%s = (bool_t) (*%s)((char *)&%s, (void *)&%s, %s);\n",
+ RETVAL, ROUTINE, ARG, RESULT, RQSTP);
+ else
+ f_print(fout, "\t%s = (bool_t) (*%s)(&%s, &%s, %s);\n",
+ RETVAL, ROUTINE, ARG, RESULT, RQSTP);
+
+
+
+
+ if (mtflag)
+ f_print(fout,
+ "\tif (%s > 0 && !svc_sendreply(%s, xdr_%s, (char *)&%s)) {\n",
+ RETVAL, TRANSP, RESULT, RESULT);
+ else
+ f_print(fout,
+ "\tif (%s != NULL && !svc_sendreply(%s, xdr_%s, %s)) {\n",
+ RESULT, TRANSP, RESULT, RESULT);
+
+ printerr("systemerr", TRANSP);
+ f_print(fout, "\t}\n");
+
+ if (Cflag)
+ printif("freeargs", TRANSP, "(caddr_t) &", ARG);
+ else
+ printif("freeargs", TRANSP, "&", ARG);
+ (void) sprintf(_errbuf, "unable to free arguments");
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ /* print out free routine */
+ if (mtflag) {
+ f_print(fout,"\tif (!");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout,"_freeresult(%s, xdr_%s, (caddr_t) &%s))\n",
+ TRANSP, RESULT, RESULT);
+ (void) sprintf(_errbuf, "unable to free results");
+ print_err_message("\t\t");
+ f_print(fout, "\n");
+ };
+ print_return("\t");
+ f_print(fout, "}\n");
+ }
+}
+
+static void
+printerr(err, transp)
+ char *err;
+ char *transp;
+{
+ f_print(fout, "\t\tsvcerr_%s(%s);\n", err, transp);
+}
+
+static void
+printif(proc, transp, prefix, arg)
+ char *proc;
+ char *transp;
+ char *prefix;
+ char *arg;
+{
+ f_print(fout, "\tif (!svc_%s(%s, xdr_%s, %s%s)) {\n",
+ proc, transp, arg, prefix, arg);
+}
+
+int
+nullproc(proc)
+ proc_list *proc;
+{
+ for (; proc != NULL; proc = proc->next) {
+ if (streq(proc->proc_num, "0")) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void
+write_inetmost(infile)
+ char *infile;
+{
+ f_print(fout, "\tregister SVCXPRT *%s;\n", TRANSP);
+ f_print(fout, "\tint sock;\n");
+ f_print(fout, "\tint proto;\n");
+ f_print(fout, "\tstruct sockaddr_in saddr;\n");
+ f_print(fout, "\tint asize = sizeof (saddr);\n");
+ f_print(fout, "\n");
+ f_print(fout,
+ "\tif (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {\n");
+ f_print(fout, "\t\tint ssize = sizeof (int);\n\n");
+ f_print(fout, "\t\tif (saddr.sin_family != AF_INET)\n");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\tif (getsockopt(0, SOL_SOCKET, SO_TYPE,\n");
+ f_print(fout, "\t\t\t\t(char *)&_rpcfdtype, &ssize) == -1)\n");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\tsock = 0;\n");
+ f_print(fout, "\t\t_rpcpmstart = 1;\n");
+ f_print(fout, "\t\tproto = 0;\n");
+ open_log_file(infile, "\t\t");
+ f_print(fout, "\t} else {\n");
+ write_rpc_svc_fg(infile, "\t\t");
+ f_print(fout, "\t\tsock = RPC_ANYSOCK;\n");
+ print_pmapunset("\t\t");
+ f_print(fout, "\t}\n");
+}
+
+static void
+print_return(space)
+ char *space;
+{
+ if (exitnow)
+ f_print(fout, "%sexit(0);\n", space);
+ else {
+ if (timerflag) {
+ if (mtflag)
+ f_print(fout, "%smutex_lock(&_svcstate_lock);\n", space);
+ f_print(fout, "%s_rpcsvcstate = _SERVED;\n", space);
+ if (mtflag)
+ f_print(fout, "%smutex_unlock(&_svcstate_lock);\n", space);
+ }
+ f_print(fout, "%sreturn;\n", space);
+ }
+}
+
+static void
+print_pmapunset(space)
+ char *space;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ for (vp = def->def.pr.versions; vp != NULL;
+ vp = vp->next) {
+ f_print(fout, "%s(void) pmap_unset(%s, %s);\n",
+ space, def->def_name, vp->vers_name);
+ }
+ }
+ }
+}
+
+static void
+print_err_message(space)
+ char *space;
+{
+ if (logflag)
+ f_print(fout, "%ssyslog(LOG_ERR, \"%s\");\n", space, _errbuf);
+ else if (inetdflag || pmflag)
+ f_print(fout, "%s_msgout(\"%s\");\n", space, _errbuf);
+ else
+ f_print(fout, "%sfprintf(stderr, \"%s\");\n", space, _errbuf);
+}
+
+/*
+ * Write the server auxiliary function (_msgout, timeout)
+ */
+void
+write_svc_aux(nomain)
+ int nomain;
+{
+ if (!logflag)
+ write_msg_out();
+ if (!nomain)
+ write_timeout_func();
+}
+
+/*
+ * Write the _msgout function
+ */
+
+static void
+write_msg_out(void)
+{
+ f_print(fout, "\n");
+/*
+ * Avoid making _msgout() static -- it's useful to have it visible
+ * in the toplevel RPC server code.
+ */
+ f_print(fout, "static\n");
+
+ if (!Cflag) {
+ f_print(fout, "void _msgout(msg)\n");
+ f_print(fout, "\tchar *msg;\n");
+ } else {
+ f_print(fout, "void _msgout(char* msg)\n");
+ }
+ f_print(fout, "{\n");
+ f_print(fout, "#ifdef RPC_SVC_FG\n");
+ if (inetdflag || pmflag)
+ f_print(fout, "\tif (_rpcpmstart)\n");
+ f_print(fout, "\t\tsyslog(LOG_ERR, msg);\n");
+ f_print(fout, "\telse\n");
+ f_print(fout,
+ "\t\t(void) fprintf(stderr, \"%%s\\n\", msg);\n");
+ f_print(fout, "#else\n");
+ f_print(fout, "\tsyslog(LOG_ERR, msg);\n");
+ f_print(fout, "#endif\n");
+ f_print(fout, "}\n");
+}
+
+/*
+ * Write the timeout function
+ */
+static void
+write_timeout_func(void)
+{
+ if (!timerflag)
+ return;
+
+ f_print(fout, "\n");
+ f_print(fout, "static void\n");
+ if (!Cflag) {
+ f_print(fout, "closedown(sig)\n");
+ f_print(fout, "\tint sig;\n");
+ } else
+ f_print(fout, "closedown(int sig)\n");
+ f_print(fout, "{\n");
+ if (mtflag)
+ f_print(fout, "\tmutex_lock(&_svcstate_lock);\n");
+ f_print(fout, "\tif (_rpcsvcstate == _IDLE) {\n");
+ f_print(fout, "\t\textern fd_set svc_fdset;\n");
+ f_print(fout, "\t\tstatic int size;\n");
+ f_print(fout, "\t\tint i, openfd;\n");
+ if (tirpcflag && pmflag) {
+ f_print(fout, "\t\tstruct t_info tinfo;\n\n");
+ f_print(fout,
+ "\t\tif (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))\n");
+ } else {
+ f_print(fout, "\n\t\tif (_rpcfdtype == SOCK_DGRAM)\n");
+ }
+ f_print(fout, "\t\t\texit(0);\n");
+ f_print(fout, "\t\tif (size == 0) {\n");
+ if (tirpcflag) {
+ f_print(fout, "\t\t\tstruct rlimit rl;\n\n");
+ f_print(fout, "\t\t\trl.rlim_max = 0;\n");
+ f_print(fout, "\t\t\tgetrlimit(RLIMIT_NOFILE, &rl);\n");
+ f_print(fout, "\t\t\tif ((size = rl.rlim_max) == 0) {\n");
+
+ if (mtflag)
+ f_print(fout, "\t\t\t\tmutex_unlock(&_svcstate_lock);\n");
+
+ f_print(fout, "\t\t\t\treturn;\n\t\t\t}\n");
+ } else {
+ f_print(fout, "\t\t\tsize = getdtablesize();\n");
+ }
+ f_print(fout, "\t\t}\n");
+ f_print(fout,
+ "\t\tfor (i = 0, openfd = 0; i < size && openfd < 2; i++)\n");
+ f_print(fout, "\t\t\tif (FD_ISSET(i, &svc_fdset))\n");
+ f_print(fout, "\t\t\t\topenfd++;\n");
+ f_print(fout, "\t\tif (openfd <= 1)\n");
+ f_print(fout, "\t\t\texit(0);\n");
+ f_print(fout, "\t}\n");
+ f_print(fout, "\tif (_rpcsvcstate == _SERVED)\n");
+ f_print(fout, "\t\t_rpcsvcstate = _IDLE;\n\n");
+ if (mtflag)
+ f_print(fout, "\tmutex_unlock(&_svcstate_lock);\n");
+
+ f_print(fout, "\t(void) signal(SIGALRM, %s closedown);\n",
+ Cflag? "(SIG_PF)" : "(void(*)())");
+ f_print(fout, "\t(void) alarm(_RPCSVC_CLOSEDOWN/2);\n");
+ f_print(fout, "}\n");
+
+}
+
+/*
+ * Write the most of port monitor support
+ */
+static void
+write_pm_most(infile, netflag)
+ char *infile;
+ int netflag;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ f_print(fout, "\tif (!ioctl(0, I_LOOK, mname) &&\n");
+ f_print(fout, "\t\t(!strcmp(mname, \"sockmod\") ||");
+ f_print(fout, " !strcmp(mname, \"timod\"))) {\n");
+ f_print(fout, "\t\tchar *netid;\n");
+ if (!netflag) { /* Not included by -n option */
+ f_print(fout, "\t\tstruct netconfig *nconf = NULL;\n");
+ f_print(fout, "\t\tSVCXPRT *%s;\n", TRANSP);
+ }
+ if (timerflag)
+ f_print(fout, "\t\tint pmclose;\n");
+/*
+ * Not necessary, defined in /usr/include/stdlib
+ * f_print(fout, "\t\textern char *getenv();\n");
+ */
+ f_print(fout, "\n");
+ f_print(fout, "\t\t_rpcpmstart = 1;\n");
+ open_log_file(infile, "\t\t");
+ f_print(fout, "\n\t\tif ((netid = \
+getenv(\"NLSPROVIDER\")) == NULL) {\n");
+
+ if (timerflag) {
+ f_print(fout, "\t\t/* started from inetd */\n");
+ f_print(fout, "\t\t\tpmclose = 1;\n");
+ }
+ f_print(fout,
+ "\t\t} else {\n");
+ f_print(fout, "\t\t\tif ((nconf = getnetconfigent(netid)) == NULL)\n");
+ sprintf(_errbuf, "cannot get transport info");
+ print_err_message("\t\t\t\t");
+ if (timerflag)
+ f_print(fout, "\n\t\t\tpmclose = \
+(t_getstate(0) != T_DATAXFER);\n");
+ f_print(fout, "\t\t}\n");
+ /*
+ * A kludgy support for inetd services. Inetd only works with
+ * sockmod, and RPC works only with timod, hence all this jugglery
+ */
+ f_print(fout, "\t\tif (strcmp(mname, \"sockmod\") == 0) {\n");
+ f_print(fout,
+ "\t\t\tif (ioctl(0, I_POP, 0) || \
+ioctl(0, I_PUSH, \"timod\")) {\n");
+ sprintf(_errbuf, "could not get the right module");
+ print_err_message("\t\t\t\t");
+ f_print(fout, "\t\t\t\texit(1);\n");
+ f_print(fout, "\t\t\t}\n");
+ f_print(fout, "\t\t}\n");
+ f_print(fout,
+ "\t\tif ((%s = svc_tli_create(0, nconf, NULL, 0, 0)) \
+== NULL) {\n",
+ TRANSP);
+ sprintf(_errbuf, "cannot create server handle");
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\t}\n");
+ f_print(fout, "\t\tif (nconf)\n");
+ f_print(fout, "\t\t\tfreenetconfigent(nconf);\n");
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout,
+ "\t\tif (!svc_reg(%s, %s, %s, ",
+ TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", 0)) {\n");
+ (void) sprintf(_errbuf, "unable to register (%s, %s).",
+ def->def_name, vp->vers_name);
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\t}\n");
+ }
+ }
+ if (timerflag) {
+ f_print(fout, "\t\tif (pmclose) {\n");
+ f_print(fout, "\t\t\t(void) signal(SIGALRM, %s closedown);\n",
+ Cflag? "(SIG_PF)" : "(void(*)())");
+ f_print(fout, "\t\t\t(void) alarm(_RPCSVC_CLOSEDOWN/2);\n");
+ f_print(fout, "\t\t}\n");
+ }
+ f_print(fout, "\t\tsvc_run();\n");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t\t/* NOTREACHED */\n");
+ f_print(fout, "\t}");
+}
+
+/*
+ * Support for backgrounding the server if self started.
+ */
+static void
+write_rpc_svc_fg(infile, sp)
+ char *infile;
+ char *sp;
+{
+ f_print(fout, "#ifndef RPC_SVC_FG\n");
+ f_print(fout, "%sint size;\n", sp);
+ if (tirpcflag)
+ f_print(fout, "%sstruct rlimit rl;\n", sp);
+ if (inetdflag)
+ f_print(fout, "%sint pid, i;\n\n", sp);
+ f_print(fout, "%spid = fork();\n", sp);
+ f_print(fout, "%sif (pid < 0) {\n", sp);
+ f_print(fout, "%s\tperror(\"cannot fork\");\n", sp);
+ f_print(fout, "%s\texit(1);\n", sp);
+ f_print(fout, "%s}\n", sp);
+ f_print(fout, "%sif (pid)\n", sp);
+ f_print(fout, "%s\texit(0);\n", sp);
+ /* get number of file descriptors */
+ if (tirpcflag) {
+ f_print(fout, "%srl.rlim_max = 0;\n", sp);
+ f_print(fout, "%sgetrlimit(RLIMIT_NOFILE, &rl);\n", sp);
+ f_print(fout, "%sif ((size = rl.rlim_max) == 0)\n", sp);
+ f_print(fout, "%s\texit(1);\n", sp);
+ } else {
+ f_print(fout, "%ssize = getdtablesize();\n", sp);
+ }
+
+ f_print(fout, "%sfor (i = 0; i < size; i++)\n", sp);
+ f_print(fout, "%s\t(void) close(i);\n", sp);
+ /* Redirect stderr and stdout to console */
+ f_print(fout, "%si = open(\"/dev/console\", 2);\n", sp);
+ f_print(fout, "%s(void) dup2(i, 1);\n", sp);
+ f_print(fout, "%s(void) dup2(i, 2);\n", sp);
+ /* This removes control of the controlling terminal */
+ if (tirpcflag)
+ f_print(fout, "%ssetsid();\n", sp);
+ else {
+ f_print(fout, "%si = open(\"/dev/tty\", 2);\n", sp);
+ f_print(fout, "%sif (i >= 0) {\n", sp);
+ f_print(fout,
+ "%s\t(void) ioctl(i, TIOCNOTTY, (char *)NULL);\n", sp);
+ f_print(fout, "%s\t(void) close(i);\n", sp);
+ f_print(fout, "%s}\n", sp);
+ }
+ if (!logflag)
+ open_log_file(infile, sp);
+ f_print(fout, "#endif\n");
+ if (logflag)
+ open_log_file(infile, sp);
+}
+
+static void
+open_log_file(infile, sp)
+ char *infile;
+ char *sp;
+{
+ char *s;
+
+ s = strrchr(infile, '.');
+ if (s)
+ *s = '\0';
+ f_print(fout, "%sopenlog(\"%s\", LOG_PID, LOG_DAEMON);\n", sp, infile);
+ if (s)
+ *s = '.';
+}
+
+
+
+
+/*
+ * write a registration for the given transport for Inetd
+ */
+void
+write_inetd_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+ char *sp;
+ int isudp;
+ char tmpbuf[32];
+
+ if (inetdflag)
+ sp = "\t";
+ else
+ sp = "";
+ if (streq(transp, "udp"))
+ isudp = 1;
+ else
+ isudp = 0;
+ f_print(fout, "\n");
+ if (inetdflag) {
+ f_print(fout,
+ "\tif ((_rpcfdtype == 0) || (_rpcfdtype == %s)) {\n",
+ isudp ? "SOCK_DGRAM" : "SOCK_STREAM");
+ }
+ f_print(fout, "%s\t%s = svc%s_create(%s",
+ sp, TRANSP, transp, inetdflag? "sock": "RPC_ANYSOCK");
+ if (!isudp)
+ f_print(fout, ", 0, 0");
+ f_print(fout, ");\n");
+ f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP);
+ (void) sprintf(_errbuf, "cannot create %s service.", transp);
+ (void) sprintf(tmpbuf, "%s\t\t", sp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+
+ if (inetdflag) {
+ f_print(fout, "%s\tif (!_rpcpmstart)\n\t", sp);
+ f_print(fout, "%s\tproto = IPPROTO_%s;\n",
+ sp, isudp ? "UDP": "TCP");
+ }
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "%s\tif (!svc_register(%s, %s, %s, ",
+ sp, TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ if (inetdflag)
+ f_print(fout, ", proto)) {\n");
+ else
+ f_print(fout, ", IPPROTO_%s)) {\n",
+ isudp ? "UDP": "TCP");
+ (void) sprintf(_errbuf,
+ "unable to register (%s, %s, %s).",
+ def->def_name, vp->vers_name, transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ }
+ }
+ if (inetdflag)
+ f_print(fout, "\t}\n");
+}
diff --git a/usr.bin/rpcgen/rpc_tblout.c b/usr.bin/rpcgen/rpc_tblout.c
new file mode 100644
index 0000000..f8b56798
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_tblout.c
@@ -0,0 +1,172 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_tblout.c 1.11 93/07/05 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_tblout.c 1.4 89/02/22 (C) 1988 SMI";
+#endif
+
+/*
+ * rpc_tblout.c, Dispatch table outputter for the RPC protocol compiler
+ * Copyright (C) 1989, Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define TABSIZE 8
+#define TABCOUNT 5
+#define TABSTOP (TABSIZE*TABCOUNT)
+
+static char tabstr[TABCOUNT+1] = "\t\t\t\t\t";
+
+static char tbl_hdr[] = "struct rpcgen_table %s_table[] = {\n";
+static char tbl_end[] = "};\n";
+
+static char null_entry[] = "\n\t(char *(*)())0,\n\
+ \t(xdrproc_t) xdr_void,\t\t\t0,\n\
+ \t(xdrproc_t) xdr_void,\t\t\t0,\n";
+
+
+static char tbl_nproc[] = "int %s_nproc =\n\tsizeof(%s_table)/sizeof(%s_table[0]);\n\n";
+
+extern int nullproc __P(( proc_list * ));
+static void write_table __P(( definition * ));
+static void printit __P(( char *, char * ));
+
+void
+write_tables()
+{
+ list *l;
+ definition *def;
+
+ f_print(fout, "\n");
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_table(def);
+ }
+ }
+}
+
+static void
+write_table(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+ int current;
+ int expected;
+ char progvers[100];
+ int warning;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ warning = 0;
+ s_print(progvers, "%s_%s",
+ locase(def->def_name), vp->vers_num);
+ /* print the table header */
+ f_print(fout, tbl_hdr, progvers);
+
+ if (nullproc(vp->procs)) {
+ expected = 0;
+ } else {
+ expected = 1;
+ f_print(fout, null_entry);
+ }
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ current = atoi(proc->proc_num);
+ if (current != expected++) {
+ f_print(fout,
+ "\n/*\n * WARNING: table out of order\n */\n");
+ if (warning == 0) {
+ f_print(stderr,
+ "WARNING %s table is out of order\n",
+ progvers);
+ warning = 1;
+ nonfatalerrors = 1;
+ }
+ expected = current + 1;
+ }
+ f_print(fout, "\n\t(char *(*)())RPCGEN_ACTION(");
+
+ /* routine to invoke */
+ if( Cflag && !newstyle )
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else {
+ if( newstyle )
+ f_print( fout, "_"); /* calls internal func */
+ pvname(proc->proc_name, vp->vers_num);
+ }
+ f_print(fout, "),\n");
+
+ /* argument info */
+ if( proc->arg_num > 1 )
+ printit((char*) NULL, proc->args.argname );
+ else
+ /* do we have to do something special for newstyle */
+ printit( proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type );
+ /* result info */
+ printit(proc->res_prefix, proc->res_type);
+ }
+
+ /* print the table trailer */
+ f_print(fout, tbl_end);
+ f_print(fout, tbl_nproc, progvers, progvers, progvers);
+ }
+}
+
+static void
+printit(prefix, type)
+ char *prefix;
+ char *type;
+{
+ int len;
+ int tabs;
+
+
+ len = fprintf(fout, "\txdr_%s,", stringfix(type));
+ /* account for leading tab expansion */
+ len += TABSIZE - 1;
+ /* round up to tabs required */
+ tabs = (TABSTOP - len + TABSIZE - 1)/TABSIZE;
+ f_print(fout, "%s", &tabstr[TABCOUNT-tabs]);
+
+ if (streq(type, "void")) {
+ f_print(fout, "0");
+ } else {
+ f_print(fout, "sizeof ( ");
+ /* XXX: should "follow" be 1 ??? */
+ ptype(prefix, type, 0);
+ f_print(fout, ")");
+ }
+ f_print(fout, ",\n");
+}
diff --git a/usr.bin/rpcgen/rpc_util.c b/usr.bin/rpcgen/rpc_util.c
new file mode 100644
index 0000000..1ade911
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_util.c
@@ -0,0 +1,517 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ident "@(#)rpc_util.c 1.14 93/07/05 SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc_util.c 1.11 89/02/22 (C) 1987 SMI";
+#endif
+
+/*
+ * rpc_util.c, Utility routines for the RPC protocol compiler
+ * Copyright (C) 1989, Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define ARGEXT "argument"
+
+char curline[MAXLINESIZE]; /* current read line */
+char *where = curline; /* current point in line */
+int linenum = 0; /* current line number */
+
+char *infilename; /* input filename */
+
+#define NFILES 7
+char *outfiles[NFILES]; /* output file names */
+int nfiles;
+
+FILE *fout; /* file pointer of current output */
+FILE *fin; /* file pointer of current input */
+
+list *defined; /* list of defined things */
+
+static void printwhere __P(( void ));
+
+/*
+ * Reinitialize the world
+ */
+void
+reinitialize()
+{
+ memset(curline, 0, MAXLINESIZE);
+ where = curline;
+ linenum = 0;
+ defined = NULL;
+}
+
+/*
+ * string equality
+ */
+int
+streq(a, b)
+ char *a;
+ char *b;
+{
+ return (strcmp(a, b) == 0);
+}
+
+/*
+ * find a value in a list
+ */
+definition *
+findval(lst, val, cmp)
+ list *lst;
+ char *val;
+ int (*cmp) ();
+
+{
+ for (; lst != NULL; lst = lst->next) {
+ if ((*cmp) (lst->val, val)) {
+ return (lst->val);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * store a value in a list
+ */
+void
+storeval(lstp, val)
+ list **lstp;
+ definition *val;
+{
+ list **l;
+ list *lst;
+
+ for (l = lstp; *l != NULL; l = (list **) & (*l)->next);
+ lst = ALLOC(list);
+ lst->val = val;
+ lst->next = NULL;
+ *l = lst;
+}
+
+static int
+findit(def, type)
+ definition *def;
+ char *type;
+{
+ return (streq(def->def_name, type));
+}
+
+static char *
+fixit(type, orig)
+ char *type;
+ char *orig;
+{
+ definition *def;
+
+ def = (definition *) FINDVAL(defined, type, findit);
+ if (def == NULL || def->def_kind != DEF_TYPEDEF) {
+ return (orig);
+ }
+ switch (def->def.ty.rel) {
+ case REL_VECTOR:
+ if (streq(def->def.ty.old_type, "opaque"))
+ return ("char");
+ else
+ return (def->def.ty.old_type);
+
+ case REL_ALIAS:
+ return (fixit(def->def.ty.old_type, orig));
+ default:
+ return (orig);
+ }
+}
+
+char *
+fixtype(type)
+ char *type;
+{
+ return (fixit(type, type));
+}
+
+char *
+stringfix(type)
+ char *type;
+{
+ if (streq(type, "string")) {
+ return ("wrapstring");
+ } else {
+ return (type);
+ }
+}
+
+void
+ptype(prefix, type, follow)
+ char *prefix;
+ char *type;
+ int follow;
+{
+ if (prefix != NULL) {
+ if (streq(prefix, "enum")) {
+ f_print(fout, "enum ");
+ } else {
+ f_print(fout, "struct ");
+ }
+ }
+ if (streq(type, "bool")) {
+ f_print(fout, "bool_t ");
+ } else if (streq(type, "string")) {
+ f_print(fout, "char *");
+ } else {
+ f_print(fout, "%s ", follow ? fixtype(type) : type);
+ }
+}
+
+static int
+typedefed(def, type)
+ definition *def;
+ char *type;
+{
+ if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix != NULL) {
+ return (0);
+ } else {
+ return (streq(def->def_name, type));
+ }
+}
+
+int
+isvectordef(type, rel)
+ char *type;
+ relation rel;
+{
+ definition *def;
+
+ for (;;) {
+ switch (rel) {
+ case REL_VECTOR:
+ return (!streq(type, "string"));
+ case REL_ARRAY:
+ return (0);
+ case REL_POINTER:
+ return (0);
+ case REL_ALIAS:
+ def = (definition *) FINDVAL(defined, type, typedefed);
+ if (def == NULL) {
+ return (0);
+ }
+ type = def->def.ty.old_type;
+ rel = def->def.ty.rel;
+ }
+ }
+
+ return (0);
+}
+
+char *
+locase(str)
+ char *str;
+{
+ char c;
+ static char buf[100];
+ char *p = buf;
+
+ while ( (c = *str++) ) {
+ *p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
+ }
+ *p = 0;
+ return (buf);
+}
+
+void
+pvname_svc(pname, vnum)
+ char *pname;
+ char *vnum;
+{
+ f_print(fout, "%s_%s_svc", locase(pname), vnum);
+}
+
+void
+pvname(pname, vnum)
+ char *pname;
+ char *vnum;
+{
+ f_print(fout, "%s_%s", locase(pname), vnum);
+}
+
+/*
+ * print a useful (?) error message, and then die
+ */
+void
+error(msg)
+ char *msg;
+{
+ printwhere();
+ f_print(stderr, "%s, line %d: ", infilename, linenum);
+ f_print(stderr, "%s\n", msg);
+ crash();
+}
+
+/*
+ * Something went wrong, unlink any files that we may have created and then
+ * die.
+ */
+void
+crash()
+{
+ int i;
+
+ for (i = 0; i < nfiles; i++) {
+ (void) unlink(outfiles[i]);
+ }
+ exit(1);
+}
+
+void
+record_open(file)
+ char *file;
+{
+ if (nfiles < NFILES) {
+ outfiles[nfiles++] = file;
+ } else {
+ f_print(stderr, "too many files!\n");
+ crash();
+ }
+}
+
+static char expectbuf[100];
+static char *toktostr();
+
+/*
+ * error, token encountered was not the expected one
+ */
+void
+expected1(exp1)
+ tok_kind exp1;
+{
+ s_print(expectbuf, "expected '%s'",
+ toktostr(exp1));
+ error(expectbuf);
+}
+
+/*
+ * error, token encountered was not one of two expected ones
+ */
+void
+expected2(exp1, exp2)
+ tok_kind exp1, exp2;
+{
+ s_print(expectbuf, "expected '%s' or '%s'",
+ toktostr(exp1),
+ toktostr(exp2));
+ error(expectbuf);
+}
+
+/*
+ * error, token encountered was not one of 3 expected ones
+ */
+void
+expected3(exp1, exp2, exp3)
+ tok_kind exp1, exp2, exp3;
+{
+ s_print(expectbuf, "expected '%s', '%s' or '%s'",
+ toktostr(exp1),
+ toktostr(exp2),
+ toktostr(exp3));
+ error(expectbuf);
+}
+
+void
+tabify(f, tab)
+ FILE *f;
+ int tab;
+{
+ while (tab--) {
+ (void) fputc('\t', f);
+ }
+}
+
+
+static token tokstrings[] = {
+ {TOK_IDENT, "identifier"},
+ {TOK_CONST, "const"},
+ {TOK_RPAREN, ")"},
+ {TOK_LPAREN, "("},
+ {TOK_RBRACE, "}"},
+ {TOK_LBRACE, "{"},
+ {TOK_LBRACKET, "["},
+ {TOK_RBRACKET, "]"},
+ {TOK_STAR, "*"},
+ {TOK_COMMA, ","},
+ {TOK_EQUAL, "="},
+ {TOK_COLON, ":"},
+ {TOK_SEMICOLON, ";"},
+ {TOK_UNION, "union"},
+ {TOK_STRUCT, "struct"},
+ {TOK_SWITCH, "switch"},
+ {TOK_CASE, "case"},
+ {TOK_DEFAULT, "default"},
+ {TOK_ENUM, "enum"},
+ {TOK_TYPEDEF, "typedef"},
+ {TOK_INT, "int"},
+ {TOK_SHORT, "short"},
+ {TOK_LONG, "long"},
+ {TOK_UNSIGNED, "unsigned"},
+ {TOK_DOUBLE, "double"},
+ {TOK_FLOAT, "float"},
+ {TOK_CHAR, "char"},
+ {TOK_STRING, "string"},
+ {TOK_OPAQUE, "opaque"},
+ {TOK_BOOL, "bool"},
+ {TOK_VOID, "void"},
+ {TOK_PROGRAM, "program"},
+ {TOK_VERSION, "version"},
+ {TOK_EOF, "??????"}
+};
+
+static char *
+toktostr(kind)
+ tok_kind kind;
+{
+ token *sp;
+
+ for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++);
+ return (sp->str);
+}
+
+static void
+printbuf()
+{
+ char c;
+ int i;
+ int cnt;
+
+# define TABSIZE 4
+
+ for (i = 0; (c = curline[i]); i++) {
+ if (c == '\t') {
+ cnt = 8 - (i % TABSIZE);
+ c = ' ';
+ } else {
+ cnt = 1;
+ }
+ while (cnt--) {
+ (void) fputc(c, stderr);
+ }
+ }
+}
+
+static void
+printwhere()
+{
+ int i;
+ char c;
+ int cnt;
+
+ printbuf();
+ for (i = 0; i < where - curline; i++) {
+ c = curline[i];
+ if (c == '\t') {
+ cnt = 8 - (i % TABSIZE);
+ } else {
+ cnt = 1;
+ }
+ while (cnt--) {
+ (void) fputc('^', stderr);
+ }
+ }
+ (void) fputc('\n', stderr);
+}
+
+char *
+make_argname(pname, vname)
+ char *pname;
+ char *vname;
+{
+ char *name;
+
+ name = malloc(strlen(pname) + strlen(vname) + strlen(ARGEXT) + 3);
+ if (!name) {
+ fprintf(stderr, "failed in malloc");
+ exit(1);
+ }
+ sprintf(name, "%s_%s_%s", locase(pname), vname, ARGEXT);
+ return (name);
+}
+
+bas_type *typ_list_h;
+bas_type *typ_list_t;
+
+void
+add_type(len, type)
+int len;
+char *type;
+{
+ bas_type *ptr;
+
+ if ((ptr = (bas_type *) malloc(sizeof (bas_type))) ==
+ (bas_type *)NULL) {
+ fprintf(stderr, "failed in malloc");
+ exit(1);
+ }
+
+ ptr->name = type;
+ ptr->length = len;
+ ptr->next = NULL;
+ if (typ_list_t == NULL)
+ {
+
+ typ_list_t = ptr;
+ typ_list_h = ptr;
+ }
+ else
+ {
+ typ_list_t->next = ptr;
+ typ_list_t = ptr;
+ };
+}
+
+
+bas_type *find_type(type)
+char *type;
+{
+ bas_type * ptr;
+
+ ptr = typ_list_h;
+ while (ptr != NULL)
+ {
+ if (strcmp(ptr->name, type) == 0)
+ return (ptr);
+ else
+ ptr = ptr->next;
+ };
+ return (NULL);
+}
diff --git a/usr.bin/rpcgen/rpc_util.h b/usr.bin/rpcgen/rpc_util.h
new file mode 100644
index 0000000..f465bfc
--- /dev/null
+++ b/usr.bin/rpcgen/rpc_util.h
@@ -0,0 +1,213 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#pragma ident "@(#)rpc_util.h 1.16 94/05/15 SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+* PROPRIETARY NOTICE (Combined)
+*
+* This source code is unpublished proprietary information
+* constituting, or derived under license from AT&T's UNIX(r) System V.
+* In addition, portions of such source code were derived from Berkeley
+* 4.3 BSD under license from the Regents of the University of
+* California.
+*
+*
+*
+* Copyright Notice
+*
+* Notice of copyright on this source code product does not indicate
+* publication.
+*
+* (c) 1986,1987,1988.1989 Sun Microsystems, Inc
+* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+* All rights reserved.
+*/
+
+/* @(#)rpc_util.h 1.5 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_util.h, Useful definitions for the RPC protocol compiler
+ */
+#include <sys/types.h>
+#include <stdlib.h>
+
+#define alloc(size) malloc((unsigned)(size))
+#define ALLOC(object) (object *) malloc(sizeof(object))
+
+#define s_print (void) sprintf
+#define f_print (void) fprintf
+
+struct list {
+ definition *val;
+ struct list *next;
+};
+typedef struct list list;
+
+struct xdrfunc {
+ char *name;
+ int pointerp;
+ struct xdrfunc *next;
+};
+typedef struct xdrfunc xdrfunc;
+
+struct commandline {
+ int cflag; /* xdr C routines */
+ int hflag; /* header file */
+ int lflag; /* client side stubs */
+ int mflag; /* server side stubs */
+ int nflag; /* netid flag */
+ int sflag; /* server stubs for the given transport */
+ int tflag; /* dispatch Table file */
+ int Ssflag; /* produce server sample code */
+ int Scflag; /* produce client sample code */
+ int makefileflag; /* Generate a template Makefile */
+ char *infile; /* input module name */
+ char *outfile; /* output module name */
+};
+
+#define PUT 1
+#define GET 2
+
+/*
+ * Global variables
+ */
+#define MAXLINESIZE 1024
+extern char curline[MAXLINESIZE];
+extern char *where;
+extern int linenum;
+
+extern char *infilename;
+extern FILE *fout;
+extern FILE *fin;
+
+extern list *defined;
+
+
+extern bas_type *typ_list_h;
+extern bas_type *typ_list_t;
+extern xdrfunc *xdrfunc_head, *xdrfunc_tail;
+
+/*
+ * All the option flags
+ */
+extern int inetdflag;
+extern int pmflag;
+extern int tblflag;
+extern int logflag;
+extern int newstyle;
+extern int Cflag; /* ANSI-C/C++ flag */
+extern int CCflag; /* C++ flag */
+extern int tirpcflag; /* flag for generating tirpc code */
+extern int inline; /* if this is 0, then do not generate inline code */
+extern int mtflag;
+
+/*
+ * Other flags related with inetd jumpstart.
+ */
+extern int indefinitewait;
+extern int exitnow;
+extern int timerflag;
+
+extern int nonfatalerrors;
+
+extern pid_t childpid;
+
+/*
+ * rpc_util routines
+ */
+void reinitialize();
+void crash();
+void add_type(int len, char *type);
+
+void storeval();
+
+#define STOREVAL(list,item) \
+ storeval(list,item)
+
+definition *findval();
+
+#define FINDVAL(list,item,finder) \
+ findval(list, item, finder)
+
+char *fixtype();
+char *stringfix();
+char *locase();
+void pvname_svc();
+void pvname();
+void ptype();
+int isvectordef();
+int streq();
+void error();
+void expected1();
+void expected2();
+void expected3();
+void tabify();
+void record_open();
+bas_type *find_type();
+/*
+ * rpc_cout routines
+ */
+void cprint();
+void emit();
+
+/*
+ * rpc_hout routines
+ */
+void print_datadef();
+void print_funcdef();
+void print_xdr_func_def();
+
+/*
+ * rpc_svcout routines
+ */
+void write_most();
+void write_register();
+void write_rest();
+void write_programs();
+void write_svc_aux();
+void write_inetd_register();
+void write_netid_register();
+void write_nettype_register();
+/*
+ * rpc_clntout routines
+ */
+void write_stubs();
+
+/*
+ * rpc_tblout routines
+ */
+void write_tables();
diff --git a/usr.bin/rpcgen/rpcgen.1 b/usr.bin/rpcgen/rpcgen.1
new file mode 100644
index 0000000..52d64b6
--- /dev/null
+++ b/usr.bin/rpcgen/rpcgen.1
@@ -0,0 +1,552 @@
+.\" @(#)rpcgen.1 1.35 93/06/02 SMI
+'\"macro stdmacro
+.\" Copyright 1985-1993 Sun Microsystems, Inc.
+.nr X
+.TH rpcgen 1 "28 Mar 1993"
+.SH NAME
+rpcgen \- an RPC protocol compiler
+.SH SYNOPSIS
+.BI rpcgen " infile"
+.LP
+.B rpcgen
+[
+.B \-a
+] [
+.B \-b
+] [
+.B \-C
+] [
+.BI \-D name
+[ =
+.I value
+] ]
+.if n .ti +5n
+[
+.BI \-i " size"
+]
+[
+.B \-I
+[
+.BI \-K " seconds"
+] ]
+[
+.B \-L
+] [
+.B \-M
+]
+.if n .ti +5n
+.if t .ti +5n
+[
+.B \-N
+]
+[
+.B \-T
+] [
+.BI \-Y " pathname"
+]
+.I infile
+.LP
+.B rpcgen
+[
+.B \-c
+|
+.B \-h
+|
+.B \-l
+|
+.B \-m
+|
+.B \-t
+|
+.B \-Sc
+|
+.B \-Ss
+|
+.B \-Sm
+]
+.if n .ti +5n
+[
+.BI \-o " outfile"
+] [
+.I infile
+]
+.LP
+.B rpcgen
+[
+.BI \-s " nettype"
+] [
+.BI \-o " outfile"
+] [
+.I infile
+]
+.LP
+.B rpcgen
+[
+.BI \-n " netid"
+] [
+.BI \-o " outfile"
+] [
+.I infile
+]
+.\" .SH AVAILABILITY
+.\" .LP
+.\" SUNWcsu
+.SH DESCRIPTION
+.IX "rpcgen" "" "\fLrpcgen\fP \(em RPC protocol compiler"
+.IX "RPC" "protocol compiler" "" "protocol compiler \(em \fLrpcgen\fP"
+.IX "RPC Language" "RPC protocol compiler" "" "RPC protocol compiler \(em \fLrpcgen\fP"
+.IX "compilers" "RPC protocol compiler" "" "RPC protocol compiler \(em \fLrpcgen\fP"
+.IX "programming tools" "RPC protocol compiler" "" "RPC protocol compiler \(em \fLrpcgen\fP"
+.LP
+\f3rpcgen\f1
+is a tool that generates C code to implement an RPC protocol.
+The input to
+\f3rpcgen\f1
+is a language similar to C known as
+RPC Language (Remote Procedure Call Language).
+.LP
+\f3rpcgen\f1
+is normally used as in the first synopsis where
+it takes an input file and generates three output files.
+If the
+\f2infile\f1
+is named
+\f3proto.x\f1,
+then
+\f3rpcgen\f1
+generates a header in
+\f3proto.h\f1,
+XDR routines in
+\f3proto_xdr.c\f1,
+server-side stubs in
+\f3proto_svc.c\f1,
+and client-side stubs in
+\f3proto_clnt.c\f1.
+With the
+\f3\-T\f1
+option,
+it also generates the RPC dispatch table in
+\f3proto_tbl.i\f1.
+.LP
+.B rpcgen
+can also generate sample client and server files
+that can be customized to suit a particular application. The
+\f3\-Sc\f1,
+\f3\-Ss\f1
+and
+\f3\-Sm\f1
+options generate sample client, server and makefile, respectively.
+The
+\f3\-a\f1
+option generates all files, including sample files. If the infile
+is \f3proto.x\f1, then the client side sample file is written to
+\f3proto_client.c\f1, the server side sample file to \f3proto_server.c\f1
+and the sample makefile to \f3makefile.proto\f1.
+.LP
+The server created can be started both by the port monitors
+(for example, \f3inetd\f1)
+or by itself.
+When it is started by a port monitor,
+it creates servers only for the transport for which
+the file descriptor \f30\fP was passed.
+The name of the transport must be specified
+by setting up the environment variable
+\f3PM_TRANSPORT\f1.
+When the server generated by
+\f3rpcgen\f1
+is executed,
+it creates server handles for all the transports
+specified in
+\f3NETPATH\f1
+environment variable,
+or if it is unset,
+it creates server handles for all the visible transports from
+\f3/etc/netconfig\f1
+file.
+Note:
+the transports are chosen at run time and not at compile time.
+When the server is self-started,
+it backgrounds itself by default.
+A special define symbol
+\f3RPC_SVC_FG\f1
+can be used to run the server process in foreground.
+.LP
+The second synopsis provides special features which allow
+for the creation of more sophisticated RPC servers.
+These features include support for user provided
+\f3#defines\f1
+and RPC dispatch tables.
+The entries in the RPC dispatch table contain:
+.RS
+.PD 0
+.TP 3
+\(bu
+pointers to the service routine corresponding to that procedure,
+.TP
+\(bu
+a pointer to the input and output arguments
+.TP
+\(bu
+the size of these routines
+.PD
+.RE
+A server can use the dispatch table to check authorization
+and then to execute the service routine;
+a client library may use it to deal with the details of storage
+management and XDR data conversion.
+.LP
+The other three synopses shown above are used when
+one does not want to generate all the output files,
+but only a particular one.
+See the
+.SM EXAMPLES
+section below for examples of
+.B rpcgen
+usage.
+When
+\f3rpcgen\f1
+is executed with the
+\f3\-s\f1
+option,
+it creates servers for that particular class of transports.
+When
+executed with the
+\f3\-n\f1
+option,
+it creates a server for the transport specified by
+\f2netid\f1.
+If
+\f2infile\f1
+is not specified,
+\f3rpcgen\f1
+accepts the standard input.
+.LP
+The C preprocessor,
+\f3cc \-E\f1
+is run on the input file before it is actually interpreted by
+\f3rpcgen\f1.
+For each type of output file,
+\f3rpcgen\f1
+defines a special preprocessor symbol for use by the
+\f3rpcgen\f1
+programmer:
+.LP
+.PD 0
+.RS
+.TP 12
+\f3RPC_HDR\f1
+defined when compiling into headers
+.TP
+\f3RPC_XDR\f1
+defined when compiling into XDR routines
+.TP
+\f3RPC_SVC\f1
+defined when compiling into server-side stubs
+.TP
+\f3RPC_CLNT\f1
+defined when compiling into client-side stubs
+.TP
+\f3RPC_TBL\f1
+defined when compiling into RPC dispatch tables
+.RE
+.PD
+.LP
+Any line beginning with
+``\f3%\f1''
+is passed directly into the output file,
+uninterpreted by
+\f3rpcgen\f1.
+To specify the path name of the C preprocessor use \f3\-Y\f1 flag.
+.LP
+For every data type referred to in
+\f2infile\f1,
+\f3rpcgen\f1
+assumes that there exists a
+routine with the string
+\f3xdr_\f1
+prepended to the name of the data type.
+If this routine does not exist in the RPC/XDR
+library, it must be provided.
+Providing an undefined data type
+allows customization of XDR routines.
+.br
+.ne 10
+.SH OPTIONS
+.TP 15
+\f3\-a\f1
+Generate all files, including sample files.
+.TP
+\f3\-b\f1
+Backward compatibility mode.
+Generate transport specific RPC code for older versions
+of the operating system.
+.IP
+Note: in FreeBSD, this compatibility flag is turned on by
+default since FreeBSD supports only the older ONC RPC library.
+.TP
+\f3\-c\f1
+Compile into XDR routines.
+.TP
+\f3\-C\f1
+Generate header and stub files which can be used with
+.SM ANSI C
+compilers. Headers generated with this flag can also be
+used with C++ programs.
+.TP
+\f3\-D\f2name\f3[=\f2value\f3]\f1
+Define a symbol
+\f2name\f1.
+Equivalent to the
+\f3#define\f1
+directive in the source.
+If no
+\f2value\f1
+is given,
+\f2value\f1
+is defined as \f31\f1.
+This option may be specified more than once.
+.TP
+\f3\-h\f1
+Compile into
+\f3C\f1
+data-definitions (a header).
+\f3\-T\f1
+option can be used in conjunction to produce a
+header which supports RPC dispatch tables.
+.TP
+\f3\-i \f2size\f1
+Size at which to start generating inline code.
+This option is useful for optimization. The default size is 5.
+.IP
+Note: in order to provide backwards compatibility with the older
+.B rpcgen
+on the FreeBSD platform, the default is actually 0 (which means
+that inline code generation is disabled by default). You must specify
+a non-zero value explicitly to override this default.
+.TP
+\f3\-I\f1
+Compile support for
+.BR inetd (8)
+in the server side stubs.
+Such servers can be self-started or can be started by \f3inetd\f1.
+When the server is self-started, it backgrounds itself by default.
+A special define symbol \f3RPC_SVC_FG\f1 can be used to run the
+server process in foreground, or the user may simply compile without
+the \f3\-I\f1 option.
+.br
+.ne 5
+.IP
+If there are no pending client requests, the
+\f3inetd\f1 servers exit after 120 seconds (default).
+The default can be changed with the
+.B \-K
+option.
+All the error messages for \f3inetd\f1 servers
+are always logged with
+.BR syslog (3).
+.\" .IP
+.\" Note:
+.\" this option is supported for backward compatibility only.
+.\" By default,
+.\" .B rpcgen
+.\" generates servers that can be invoked through portmonitors.
+.TP
+.BI \-K " seconds"
+By default, services created using \f3rpcgen\fP and invoked through
+port monitors wait \f3120\fP seconds
+after servicing a request before exiting.
+That interval can be changed using the \f3\-K\fP flag.
+To create a server that exits immediately upon servicing a request,
+use
+.BR "\-K\ 0".
+To create a server that never exits, the appropriate argument is
+\f3\-K \-1\fP.
+.IP
+When monitoring for a server,
+some portmonitors
+.I always
+spawn a new process in response to a service request.
+If it is known that a server will be used with such a monitor, the
+server should exit immediately on completion.
+For such servers, \f3rpcgen\fP should be used with \f3\-K 0\fP.
+.TP
+\f3\-l\f1
+Compile into client-side stubs.
+.TP
+.B \-L
+When the servers are started in foreground, use
+.BR syslog (3)
+to log the server errors instead of printing them on the standard
+error.
+.TP
+\f3\-m\f1
+Compile into server-side stubs,
+but do not generate a \(lqmain\(rq routine.
+This option is useful for doing callback-routines
+and for users who need to write their own
+\(lqmain\(rq routine to do initialization.
+.TP
+\f3\-M\f1
+Generate multithread-safe stubs for passing arguments and results between
+rpcgen generated code and user written code. This option is useful
+for users who want to use threads in their code. However, the
+.BR rpc_svc_calls (3N)
+functions are not yet MT-safe, which means that rpcgen generated server-side
+code will not be MT-safe.
+.TP
+.B \-N
+This option allows procedures to have multiple arguments.
+It also uses the style of parameter passing that closely resembles C.
+So, when passing an argument to a remote procedure, you do not have to
+pass a pointer to the argument, but can pass the argument itself.
+This behavior is different from the old style of
+.B rpcgen
+generated code.
+To maintain backward compatibility,
+this option is not the default.
+.TP
+\f3\-n \f2netid\f1
+Compile into server-side stubs for the transport
+specified by
+\f2netid\f1.
+There should be an entry for
+\f2netid\f1
+in the
+netconfig database.
+This option may be specified more than once,
+so as to compile a server that serves multiple transports.
+.TP
+\f3\-o \f2outfile\f1
+Specify the name of the output file.
+If none is specified,
+standard output is used
+(\f3\-c\f1,
+\f3\-h\f1,
+\f3\-l\f1,
+\f3\-m\f1,
+\f3\-n\f1,
+\f3\-s\f1,
+\f3\-Sc\f1,
+\f3\-Sm\f1,
+\f3\-Ss\f1,
+and
+\f3\-t\f1
+modes only).
+.TP
+\f3\-s \f2nettype\f1
+Compile into server-side stubs for all the
+transports belonging to the class
+\f2nettype\f1.
+The supported classes are
+\f3netpath\f1,
+\f3visible\f1,
+\f3circuit_n\f1,
+\f3circuit_v\f1,
+\f3datagram_n\f1,
+\f3datagram_v\f1,
+\f3tcp\f1,
+and
+\f3udp\f1
+(see
+.BR rpc (3N)
+for the meanings associated with these classes).
+This option may be specified more than once.
+Note:
+the transports are chosen at run time and not at compile time.
+.TP
+\f3\-Sc\f1
+Generate sample client code that uses remote procedure calls.
+.br
+.ne 5
+.TP
+\f3\-Sm\f1
+Generate a sample Makefile which can be used for compiling the
+application.
+.TP
+\f3\-Ss\f1
+Generate sample server code that uses remote procedure calls.
+.TP
+\f3\-t\f1
+Compile into RPC dispatch table.
+.TP
+\f3\-T\f1
+Generate the code to support RPC dispatch tables.
+.IP
+The options
+\f3\-c\f1,
+\f3\-h\f1,
+\f3\-l\f1,
+\f3\-m\f1,
+\f3\-s\f1,
+\f3\-Sc\f1,
+\f3\-Sm\f1,
+\f3\-Ss\f1,
+and
+\f3\-t\f1
+are used exclusively to generate a particular type of file,
+while the options
+\f3\-D\f1
+and
+\f3\-T\f1
+are global and can be used with the other options.
+.TP
+\f3\-Y\f2 pathname\f1
+Give the name of the directory where
+.B rpcgen
+will start looking for the C-preprocessor.
+.br
+.ne 5
+.SH EXAMPLES
+The following example:
+.LP
+.RS
+.B example% rpcgen \-T prot.x
+.RE
+.LP
+generates all the five files:
+.BR prot.h ,
+.BR prot_clnt.c ,
+.BR prot_svc.c ,
+.B prot_xdr.c
+and
+.BR prot_tbl.i .
+.LP
+The following example sends the C data-definitions (header)
+to the standard output.
+.LP
+.RS
+.B example% rpcgen \-h prot.x
+.RE
+.LP
+To send the test version of the
+.BR -DTEST ,
+server side stubs for
+all the transport belonging to the class
+.B datagram_n
+to standard output, use:
+.LP
+.RS
+.B example% rpcgen \-s datagram_n \-DTEST prot.x
+.RE
+.LP
+To create the server side stubs for the transport indicated
+by
+\f2netid\f1
+\f3tcp\f1,
+use:
+.LP
+.RS
+.B example% rpcgen \-n tcp \-o prot_svc.c prot.x
+.RE
+.SH "SEE ALSO"
+.BR cc (1),
+.BR inetd (8),
+.BR syslog (3),
+.BR rpc (3),
+.\" .BR rpc_svc_calls (3)
+.LP
+The
+.B rpcgen
+chapter in the
+.TZ NETP
+manual.
diff --git a/usr.bin/rpcinfo/Makefile b/usr.bin/rpcinfo/Makefile
new file mode 100644
index 0000000..f9377c6
--- /dev/null
+++ b/usr.bin/rpcinfo/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.2 (Berkeley) 5/11/90
+# $Id$
+
+PROG= rpcinfo
+MAN8 = rpcinfo.8
+
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rpcinfo/rpcinfo.8 b/usr.bin/rpcinfo/rpcinfo.8
new file mode 100644
index 0000000..25662e3
--- /dev/null
+++ b/usr.bin/rpcinfo/rpcinfo.8
@@ -0,0 +1,166 @@
+.\" from: @(#)rpcinfo.8c 2.2 88/08/03 4.0 RPCSRC; from 1.24 88/02/25 SMI
+.\" $Id$
+.\"
+.Dd December 17, 1987
+.Dt RPCINFO 8
+.Os
+.Sh NAME
+.Nm rpcinfo
+.Nd report RPC information
+.Sh SYNOPSIS
+.Nm rpcinfo
+.Fl p
+.Op Ar host
+.Nm rpcinfo
+.Op Fl n Ar portnum
+.Fl u Ar host
+.Ar program
+.Op Ar version
+.Nm rpcinfo
+.Op Fl n Ar portnum
+.Fl t Ar host
+.Ar program
+.Op Ar version
+.Nm rpcinfo
+.Fl b
+.Ar program version
+.Nm rpcinfo
+.Fl d
+.Ar program version
+.Sh DESCRIPTION
+.Nm rpcinfo
+makes an
+.Tn RPC
+call to an
+.Tn RPC
+server and reports what it finds.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl p
+Probe the portmapper on
+.Ar host ,
+and print a list of all registered
+.Tn RPC
+programs. If
+.Ar host
+is not specified, it defaults to the value returned by
+.Xr hostname 1 .
+.It Fl u
+Make an
+.Tn RPC
+call to procedure 0 of
+.Ar program
+on the specified
+.Ar host
+using
+.Tn UDP ,
+and report whether a response was received.
+.It Fl t
+Make an
+.Tn RPC
+call to procedure 0 of
+.Ar program
+on the specified
+.Ar host
+using
+.Tn TCP ,
+and report whether a response was received.
+.It Fl n
+Use
+.Ar portnum
+as the port number for the
+.Fl t
+and
+.Fl u
+options instead of the port number given by the portmapper.
+.It Fl b
+Make an
+.Tn RPC
+broadcast to procedure 0 of the specified
+.Ar program
+and
+.Ar version
+using
+.Tn UDP
+and report all hosts that respond.
+.It Fl d
+Delete registration for the
+.Tn RPC
+service of the specified
+.Ar program
+and
+.Ar version .
+This option can be exercised only by the super-user.
+.El
+.Pp
+The
+.Ar program
+argument can be either a name or a number.
+.Pp
+If a
+.Ar version
+is specified,
+.Nm rpcinfo
+attempts to call that version of the specified
+.Ar program .
+Otherwise,
+.Nm rpcinfo
+attempts to find all the registered version
+numbers for the specified
+.Ar program
+by calling version 0 (which is presumed not
+to exist; if it does exist,
+.Ar rpcinfo
+attempts to obtain this information by calling
+an extremely high version
+number instead) and attempts to call each registered version.
+Note: the version number is required for
+.Fl b
+and
+.Fl d
+options.
+.Sh EXAMPLES
+To show all of the
+.Tn RPC
+services registered on the local machine use:
+.Pp
+.Dl example% rpcinfo -p
+.Pp
+To show all of the
+.Tn RPC
+services registered on the machine named
+.Ar klaxon
+use:
+.Pp
+.Dl example% rpcinfo -p klaxon
+.Pp
+To show all machines on the local net that are running the Yellow Pages
+service use:
+.Pp
+.Dl example% rpcinfo -b ypserv 'version' | uniq
+.Pp
+where 'version' is the current Yellow Pages version obtained from the
+results of the
+.Fl p
+switch above.
+.Pp
+To delete the registration for version 1 of the
+.Nm walld
+service use:
+.Pp
+.Dl example% rpcinfo -d walld 1
+.Sh SEE ALSO
+.Xr rpc 5 ,
+.Xr portmap 8
+.Rs
+.%T "RPC Programming Guide"
+.Re
+.Sh BUGS
+In releases prior to SunOS 3.0, the Network File System (NFS) did not
+register itself with the portmapper;
+.Nm rpcinfo
+cannot be used to make
+.Tn RPC
+calls to the
+.Tn NFS
+server on hosts running such releases.
diff --git a/usr.bin/rpcinfo/rpcinfo.c b/usr.bin/rpcinfo/rpcinfo.c
new file mode 100644
index 0000000..4a50531
--- /dev/null
+++ b/usr.bin/rpcinfo/rpcinfo.c
@@ -0,0 +1,666 @@
+#ifndef lint
+/*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/
+/*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/
+static char rcsid[] = "$Id: rpcinfo.c,v 1.4 1997/02/22 19:56:45 peter Exp $";
+#endif
+
+/*
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * rpcinfo: ping a particular rpc program
+ * or dump the portmapper
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <signal.h>
+#include <ctype.h>
+
+#define MAXHOSTLEN 256
+
+#define MIN_VERS ((u_long) 0)
+#define MAX_VERS ((u_long) 4294967295UL)
+
+static void udpping(/*u_short portflag, int argc, char **argv*/);
+static void tcpping(/*u_short portflag, int argc, char **argv*/);
+static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
+static void pmapdump(/*int argc, char **argv*/);
+static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/);
+static void brdcst(/*int argc, char **argv*/);
+static void deletereg(/* int argc, char **argv */) ;
+static void usage(/*void*/);
+static u_long getprognum(/*char *arg*/);
+static u_long getvers(/*char *arg*/);
+static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
+extern u_long inet_addr(); /* in 4.2BSD, arpa/inet.h called that a in_addr */
+extern char *inet_ntoa();
+
+/*
+ * Functions to be performed.
+ */
+#define NONE 0 /* no function */
+#define PMAPDUMP 1 /* dump portmapper registrations */
+#define TCPPING 2 /* ping TCP service */
+#define UDPPING 3 /* ping UDP service */
+#define BRDCST 4 /* ping broadcast UDP service */
+#define DELETES 5 /* delete registration for the service */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int c;
+ extern char *optarg;
+ extern int optind;
+ int errflg;
+ int function;
+ u_short portnum;
+
+ function = NONE;
+ portnum = 0;
+ errflg = 0;
+ while ((c = getopt(argc, argv, "ptubdn:")) != -1) {
+ switch (c) {
+
+ case 'p':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = PMAPDUMP;
+ break;
+
+ case 't':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = TCPPING;
+ break;
+
+ case 'u':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = UDPPING;
+ break;
+
+ case 'b':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = BRDCST;
+ break;
+
+ case 'n':
+ portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */
+ break;
+
+ case 'd':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = DELETES;
+ break;
+
+ case '?':
+ errflg = 1;
+ }
+ }
+
+ if (errflg || function == NONE) {
+ usage();
+ return (1);
+ }
+
+ switch (function) {
+
+ case PMAPDUMP:
+ if (portnum != 0) {
+ usage();
+ return (1);
+ }
+ pmapdump(argc - optind, argv + optind);
+ break;
+
+ case UDPPING:
+ udpping(portnum, argc - optind, argv + optind);
+ break;
+
+ case TCPPING:
+ tcpping(portnum, argc - optind, argv + optind);
+ break;
+
+ case BRDCST:
+ if (portnum != 0) {
+ usage();
+ return (1);
+ }
+ brdcst(argc - optind, argv + optind);
+ break;
+
+ case DELETES:
+ deletereg(argc - optind, argv + optind);
+ break;
+ }
+
+ return (0);
+}
+
+static void
+udpping(portnum, argc, argv)
+ u_short portnum;
+ int argc;
+ char **argv;
+{
+ struct timeval to;
+ struct sockaddr_in addr;
+ enum clnt_stat rpc_stat;
+ CLIENT *client;
+ u_long prognum, vers, minvers, maxvers;
+ int sock = RPC_ANYSOCK;
+ struct rpc_err rpcerr;
+ int failure;
+
+ if (argc < 2 || argc > 3) {
+ usage();
+ exit(1);
+ }
+ prognum = getprognum(argv[1]);
+ get_inet_address(&addr, argv[0]);
+ /* Open the socket here so it will survive calls to clnt_destroy */
+ sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0) {
+ perror("rpcinfo: socket");
+ exit(1);
+ }
+ failure = 0;
+ if (argc == 2) {
+ /*
+ * A call to version 0 should fail with a program/version
+ * mismatch, and give us the range of versions supported.
+ */
+ addr.sin_port = htons(portnum);
+ to.tv_sec = 5;
+ to.tv_usec = 0;
+ if ((client = clntudp_create(&addr, prognum, (u_long)0,
+ to, &sock)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu is not available\n",
+ prognum);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
+ xdr_void, (char *)NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH) {
+ clnt_geterr(client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ } else if (rpc_stat == RPC_SUCCESS) {
+ /*
+ * Oh dear, it DOES support version 0.
+ * Let's try version MAX_VERS.
+ */
+ addr.sin_port = htons(portnum);
+ to.tv_sec = 5;
+ to.tv_usec = 0;
+ if ((client = clntudp_create(&addr, prognum, MAX_VERS,
+ to, &sock)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, MAX_VERS);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, NULLPROC, xdr_void,
+ (char *)NULL, xdr_void, (char *)NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH) {
+ clnt_geterr(client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ } else if (rpc_stat == RPC_SUCCESS) {
+ /*
+ * It also supports version MAX_VERS.
+ * Looks like we have a wise guy.
+ * OK, we give them information on all
+ * 4 billion versions they support...
+ */
+ minvers = 0;
+ maxvers = MAX_VERS;
+ } else {
+ (void) pstatus(client, prognum, MAX_VERS);
+ exit(1);
+ }
+ } else {
+ (void) pstatus(client, prognum, (u_long)0);
+ exit(1);
+ }
+ clnt_destroy(client);
+ for (vers = minvers; vers <= maxvers; vers++) {
+ addr.sin_port = htons(portnum);
+ to.tv_sec = 5;
+ to.tv_usec = 0;
+ if ((client = clntudp_create(&addr, prognum, vers,
+ to, &sock)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, vers);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, NULLPROC, xdr_void,
+ (char *)NULL, xdr_void, (char *)NULL, to);
+ if (pstatus(client, prognum, vers) < 0)
+ failure = 1;
+ clnt_destroy(client);
+ }
+ }
+ else {
+ vers = getvers(argv[2]);
+ addr.sin_port = htons(portnum);
+ to.tv_sec = 5;
+ to.tv_usec = 0;
+ if ((client = clntudp_create(&addr, prognum, vers,
+ to, &sock)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, vers);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
+ xdr_void, (char *)NULL, to);
+ if (pstatus(client, prognum, vers) < 0)
+ failure = 1;
+ }
+ (void) close(sock); /* Close it up again */
+ if (failure)
+ exit(1);
+}
+
+static void
+tcpping(portnum, argc, argv)
+ u_short portnum;
+ int argc;
+ char **argv;
+{
+ struct timeval to;
+ struct sockaddr_in addr;
+ enum clnt_stat rpc_stat;
+ CLIENT *client;
+ u_long prognum, vers, minvers, maxvers;
+ int sock = RPC_ANYSOCK;
+ struct rpc_err rpcerr;
+ int failure;
+
+ if (argc < 2 || argc > 3) {
+ usage();
+ exit(1);
+ }
+ prognum = getprognum(argv[1]);
+ get_inet_address(&addr, argv[0]);
+ failure = 0;
+ if (argc == 2) {
+ /*
+ * A call to version 0 should fail with a program/version
+ * mismatch, and give us the range of versions supported.
+ */
+ addr.sin_port = htons(portnum);
+ if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
+ &sock, 0, 0)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu is not available\n",
+ prognum);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
+ xdr_void, (char *)NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH) {
+ clnt_geterr(client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ } else if (rpc_stat == RPC_SUCCESS) {
+ /*
+ * Oh dear, it DOES support version 0.
+ * Let's try version MAX_VERS.
+ */
+ addr.sin_port = htons(portnum);
+ if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
+ &sock, 0, 0)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, MAX_VERS);
+ exit(1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(client, NULLPROC, xdr_void,
+ (char *)NULL, xdr_void, (char *)NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH) {
+ clnt_geterr(client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ } else if (rpc_stat == RPC_SUCCESS) {
+ /*
+ * It also supports version MAX_VERS.
+ * Looks like we have a wise guy.
+ * OK, we give them information on all
+ * 4 billion versions they support...
+ */
+ minvers = 0;
+ maxvers = MAX_VERS;
+ } else {
+ (void) pstatus(client, prognum, MAX_VERS);
+ exit(1);
+ }
+ } else {
+ (void) pstatus(client, prognum, MIN_VERS);
+ exit(1);
+ }
+ clnt_destroy(client);
+ (void) close(sock);
+ sock = RPC_ANYSOCK; /* Re-initialize it for later */
+ for (vers = minvers; vers <= maxvers; vers++) {
+ addr.sin_port = htons(portnum);
+ if ((client = clnttcp_create(&addr, prognum, vers,
+ &sock, 0, 0)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, vers);
+ exit(1);
+ }
+ to.tv_usec = 0;
+ to.tv_sec = 10;
+ rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
+ xdr_void, (char *)NULL, to);
+ if (pstatus(client, prognum, vers) < 0)
+ failure = 1;
+ clnt_destroy(client);
+ (void) close(sock);
+ sock = RPC_ANYSOCK;
+ }
+ }
+ else {
+ vers = getvers(argv[2]);
+ addr.sin_port = htons(portnum);
+ if ((client = clnttcp_create(&addr, prognum, vers, &sock,
+ 0, 0)) == NULL) {
+ clnt_pcreateerror("rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, vers);
+ exit(1);
+ }
+ to.tv_usec = 0;
+ to.tv_sec = 10;
+ rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
+ xdr_void, (char *)NULL, to);
+ if (pstatus(client, prognum, vers) < 0)
+ failure = 1;
+ }
+ if (failure)
+ exit(1);
+}
+
+/*
+ * This routine should take a pointer to an "rpc_err" structure, rather than
+ * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
+ * a CLIENT structure rather than a pointer to an "rpc_err" structure.
+ * As such, we have to keep the CLIENT structure around in order to print
+ * a good error message.
+ */
+static int
+pstatus(client, prognum, vers)
+ register CLIENT *client;
+ u_long prognum;
+ u_long vers;
+{
+ struct rpc_err rpcerr;
+
+ clnt_geterr(client, &rpcerr);
+ if (rpcerr.re_status != RPC_SUCCESS) {
+ clnt_perror(client, "rpcinfo");
+ printf("program %lu version %lu is not available\n",
+ prognum, vers);
+ return (-1);
+ } else {
+ printf("program %lu version %lu ready and waiting\n",
+ prognum, vers);
+ return (0);
+ }
+}
+
+static void
+pmapdump(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct sockaddr_in server_addr;
+ register struct hostent *hp;
+ struct pmaplist *head = NULL;
+ int socket = RPC_ANYSOCK;
+ struct timeval minutetimeout;
+ register CLIENT *client;
+ struct rpcent *rpc;
+
+ if (argc > 1) {
+ usage();
+ exit(1);
+ }
+ if (argc == 1)
+ get_inet_address(&server_addr, argv[0]);
+ else {
+ bzero((char *)&server_addr, sizeof server_addr);
+ server_addr.sin_family = AF_INET;
+ if ((hp = gethostbyname("localhost")) != NULL)
+ bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
+ hp->h_length);
+ else
+ server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
+ }
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+ server_addr.sin_port = htons(PMAPPORT);
+ if ((client = clnttcp_create(&server_addr, PMAPPROG,
+ PMAPVERS, &socket, 50, 500)) == NULL) {
+ clnt_pcreateerror("rpcinfo: can't contact portmapper");
+ exit(1);
+ }
+ if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
+ xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
+ fprintf(stderr, "rpcinfo: can't contact portmapper: ");
+ clnt_perror(client, "rpcinfo");
+ exit(1);
+ }
+ if (head == NULL) {
+ printf("No remote programs registered.\n");
+ } else {
+ printf(" program vers proto port\n");
+ for (; head != NULL; head = head->pml_next) {
+ printf("%10ld%5ld",
+ head->pml_map.pm_prog,
+ head->pml_map.pm_vers);
+ if (head->pml_map.pm_prot == IPPROTO_UDP)
+ printf("%6s", "udp");
+ else if (head->pml_map.pm_prot == IPPROTO_TCP)
+ printf("%6s", "tcp");
+ else
+ printf("%6ld", head->pml_map.pm_prot);
+ printf("%7ld", head->pml_map.pm_port);
+ rpc = getrpcbynumber(head->pml_map.pm_prog);
+ if (rpc)
+ printf(" %s\n", rpc->r_name);
+ else
+ printf("\n");
+ }
+ }
+}
+
+/*
+ * reply_proc collects replies from the broadcast.
+ * to get a unique list of responses the output of rpcinfo should
+ * be piped through sort(1) and then uniq(1).
+ */
+
+/*ARGSUSED*/
+static bool_t
+reply_proc(res, who)
+ void *res; /* Nothing comes back */
+ struct sockaddr_in *who; /* Who sent us the reply */
+{
+ register struct hostent *hp;
+
+ hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
+ AF_INET);
+ printf("%s %s\n", inet_ntoa(who->sin_addr),
+ (hp == NULL) ? "(unknown)" : hp->h_name);
+ return(FALSE);
+}
+
+static void
+brdcst(argc, argv)
+ int argc;
+ char **argv;
+{
+ enum clnt_stat rpc_stat;
+ u_long prognum, vers;
+
+ if (argc != 2) {
+ usage();
+ exit(1);
+ }
+ prognum = getprognum(argv[0]);
+ vers = getvers(argv[1]);
+ rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
+ (char *)NULL, xdr_void, (char *)NULL, reply_proc);
+ if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
+ fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
+ clnt_sperrno(rpc_stat));
+ exit(1);
+ }
+ exit(0);
+}
+
+static void
+deletereg(argc, argv)
+ int argc;
+ char **argv;
+{ u_long prog_num, version_num ;
+
+ if (argc != 2) {
+ usage() ;
+ exit(1) ;
+ }
+ if (getuid()) { /* This command allowed only to root */
+ fprintf(stderr, "Sorry. You are not root\n") ;
+ exit(1) ;
+ }
+ prog_num = getprognum(argv[0]);
+ version_num = getvers(argv[1]);
+ if ((pmap_unset(prog_num, version_num)) == 0) {
+ fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n",
+ argv[0], argv[1]) ;
+ exit(1) ;
+ }
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
+ fprintf(stderr, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
+ fprintf(stderr, " rpcinfo -p [ host ]\n");
+ fprintf(stderr, " rpcinfo -b prognum versnum\n");
+ fprintf(stderr, " rpcinfo -d prognum versnum\n") ;
+}
+
+static u_long
+getprognum(arg)
+ char *arg;
+{
+ register struct rpcent *rpc;
+ register u_long prognum;
+
+ if (isalpha(*arg)) {
+ rpc = getrpcbyname(arg);
+ if (rpc == NULL) {
+ fprintf(stderr, "rpcinfo: %s is unknown service\n",
+ arg);
+ exit(1);
+ }
+ prognum = rpc->r_number;
+ } else {
+ prognum = (u_long) atoi(arg);
+ }
+
+ return (prognum);
+}
+
+static u_long
+getvers(arg)
+ char *arg;
+{
+ register u_long vers;
+
+ vers = (int) atoi(arg);
+ return (vers);
+}
+
+static void
+get_inet_address(addr, host)
+ struct sockaddr_in *addr;
+ char *host;
+{
+ register struct hostent *hp;
+
+ bzero((char *)addr, sizeof *addr);
+ addr->sin_addr.s_addr = (u_long) inet_addr(host);
+ if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
+ if ((hp = gethostbyname(host)) == NULL) {
+ fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
+ exit(1);
+ }
+ bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
+ }
+ addr->sin_family = AF_INET;
+}
diff --git a/usr.bin/rs/rs.c b/usr.bin/rs/rs.c
index 429dadc..2f5e92b 100644
--- a/usr.bin/rs/rs.c
+++ b/usr.bin/rs/rs.c
@@ -184,7 +184,7 @@ void
putfile()
{
register char **ep;
- register int i, j;
+ register int i, j, k;
ep = elem;
if (flags & TRANSPOSE)
@@ -194,9 +194,10 @@ putfile()
putchar('\n');
}
else
- for (i = 0; i < orows; i++) {
- for (j = 0; j < ocols; j++)
- prints(*ep++, j);
+ for (i = k = 0; i < orows; i++) {
+ for (j = 0; j < ocols; j++, k++)
+ if (k < nelem)
+ prints(ep[k], j);
putchar('\n');
}
}
diff --git a/usr.bin/rsh/Makefile b/usr.bin/rsh/Makefile
index d9e511e..ca63790 100644
--- a/usr.bin/rsh/Makefile
+++ b/usr.bin/rsh/Makefile
@@ -1,10 +1,17 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
PROG= rsh
+SRCS= rsh.c
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
+ || defined(MAKE_EBONES))
CFLAGS+=-DKERBEROS -DCRYPT
-SRCS= rsh.c krcmd.c kcmd.c des_rw.c
+SRCS+= krcmd.c kcmd.c
DPADD= ${LIBKRB} ${LIBDES}
LDADD= -lkrb -ldes
+DISTRIBUTION= krb
+.endif
+
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
diff --git a/usr.bin/rsh/rsh.1 b/usr.bin/rsh/rsh.1
index 78ec2f1..0fab930 100644
--- a/usr.bin/rsh/rsh.1
+++ b/usr.bin/rsh/rsh.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)rsh.1 8.2 (Berkeley) 4/29/95
+.\" @(#)rsh.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd April 29, 1995
+.Dd June 6, 1993
.Dt RSH 1
.Os BSD 4.2
.Sh NAME
@@ -40,13 +40,10 @@
.Sh SYNOPSIS
.Nm rsh
.Op Fl Kdnx
+.Op Fl t Ar timeout
.Op Fl k Ar realm
.Op Fl l Ar username
.Ar host
-.Nm rsh
-.Op Fl Kdnx
-.Op Fl k Ar realm
-.Ar username@host
.Op command
.Sh DESCRIPTION
.Nm Rsh
@@ -90,9 +87,7 @@ instead of the remote host's realm as determined by
By default, the remote username is the same as the local username.
The
.Fl l
-option or the
-.Pa username@host
-format allow the remote name to be specified.
+option allows the remote name to be specified.
Kerberos authentication is used, and authorization is determined
as in
.Xr rlogin 1 .
@@ -111,6 +106,11 @@ option turns on
.Tn DES
encryption for all data exchange.
This may introduce a significant delay in response time.
+.It Fl t
+The
+.Fl t
+option allows a timeout to be specified (in seconds). If no
+data is sent or received in this time, rsh will exit.
.El
.Pp
If no
@@ -147,9 +147,15 @@ to
.El
.Sh SEE ALSO
.Xr rlogin 1 ,
+.Xr setsockopt 2 ,
.Xr kerberos 3 ,
+.Xr krb_realmofhost 3 ,
.Xr krb_sendauth 3 ,
-.Xr krb_realmofhost 3
+.Xr rcmd 3 ,
+.Xr ruserok 3 ,
+.Xr hosts 5 ,
+.Xr rlogind 8 ,
+.Xr rshd 8
.Sh HISTORY
The
.Nm rsh
diff --git a/usr.bin/rsh/rsh.c b/usr.bin/rsh/rsh.c
index 7e3a530..70f311d 100644
--- a/usr.bin/rsh/rsh.c
+++ b/usr.bin/rsh/rsh.c
@@ -38,19 +38,17 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rsh.c 8.4 (Berkeley) 4/29/95";
+static char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94";
+static char rcsid[] =
+ "$Id: rsh.c,v 1.10 1997/02/22 19:56:46 peter Exp $";
#endif /* not lint */
-/*
- * $Source: mit/rsh/RCS/rsh.c,v $
- * $Header: mit/rsh/RCS/rsh.c,v 5.1 89/07/31 19:28:59 kfall Exp Locker: kfall $
- */
-
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/file.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
@@ -68,7 +66,7 @@ static char sccsid[] = "@(#)rsh.c 8.4 (Berkeley) 4/29/95";
#include "pathnames.h"
#ifdef KERBEROS
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
CREDENTIALS cred;
@@ -85,7 +83,7 @@ int rfd2;
char *copyargs __P((char **));
void sendsig __P((int));
-void talk __P((int, long, pid_t, int));
+void talk __P((int, long, pid_t, int, int));
void usage __P((void));
void warning __P(());
@@ -101,6 +99,7 @@ main(argc, argv)
pid_t pid;
uid_t uid;
char *args, *host, *p, *user;
+ int timeout = 0;
argoff = asrsh = dflag = nflag = 0;
one = 1;
@@ -124,14 +123,14 @@ main(argc, argv)
#ifdef KERBEROS
#ifdef CRYPT
-#define OPTIONS "8KLdek:l:nwx"
+#define OPTIONS "8KLde:k:l:nt:wx"
#else
-#define OPTIONS "8KLdek:l:nw"
+#define OPTIONS "8KLde:k:l:nt:w"
#endif
#else
-#define OPTIONS "8KLdel:nw"
+#define OPTIONS "8KLde:l:nt:w"
#endif
- while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
+ while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
switch(ch) {
case 'K':
#ifdef KERBEROS
@@ -162,10 +161,12 @@ main(argc, argv)
#ifdef CRYPT
case 'x':
doencrypt = 1;
- des_set_key(cred.session, schedule);
break;
#endif
#endif
+ case 't':
+ timeout = atoi(optarg);
+ break;
case '?':
default:
usage();
@@ -189,16 +190,6 @@ main(argc, argv)
if (!(pw = getpwuid(uid = getuid())))
errx(1, "unknown user id");
- /* Accept user1@host format, though "-l user2" overrides user1 */
- p = strchr(host, '@');
- if (p) {
- *p = '\0';
- if (!user && p > host)
- user = host;
- host = p + 1;
- if (*host == '\0')
- usage();
- }
if (!user)
user = pw->pw_name;
@@ -244,10 +235,11 @@ try_connect:
dest_realm = krb_realmofhost(host);
#ifdef CRYPT
- if (doencrypt)
+ if (doencrypt) {
rem = krcmd_mutual(&host, sp->s_port, user, args,
&rfd2, dest_realm, &cred, schedule);
- else
+ des_set_key_krb(&cred.session, schedule);
+ } else
#endif
rem = krcmd(&host, sp->s_port, user, args, &rfd2,
dest_realm);
@@ -310,7 +302,7 @@ try_connect:
(void)ioctl(rem, FIONBIO, &one);
}
- talk(nflag, omask, pid, rem);
+ talk(nflag, omask, pid, rem, timeout);
if (!nflag)
(void)kill(pid, SIGKILL);
@@ -318,7 +310,7 @@ try_connect:
}
void
-talk(nflag, omask, pid, rem)
+talk(nflag, omask, pid, rem, timeout)
int nflag;
long omask;
pid_t pid;
@@ -327,6 +319,8 @@ talk(nflag, omask, pid, rem)
int cc, wc;
fd_set readfrom, ready, rembits;
char *bp, buf[BUFSIZ];
+ struct timeval tvtimeout;
+ int srval;
if (!nflag && pid == 0) {
(void)close(rfd2);
@@ -336,7 +330,7 @@ reread: errno = 0;
goto done;
bp = buf;
-rewrite:
+rewrite:
FD_ZERO(&rembits);
FD_SET(rem, &rembits);
if (select(16, 0, &rembits, 0, 0) < 0) {
@@ -369,17 +363,28 @@ done:
exit(0);
}
+ tvtimeout.tv_sec = timeout;
+ tvtimeout.tv_usec = 0;
+
(void)sigsetmask(omask);
FD_ZERO(&readfrom);
FD_SET(rfd2, &readfrom);
FD_SET(rem, &readfrom);
do {
ready = readfrom;
- if (select(16, &ready, 0, 0, 0) < 0) {
+ if (timeout) {
+ srval = select(16, &ready, 0, 0, &tvtimeout);
+ } else {
+ srval = select(16, &ready, 0, 0, 0);
+ }
+
+ if (srval < 0) {
if (errno != EINTR)
err(1, "select");
continue;
}
+ if (srval == 0)
+ errx(1, "timeout reached (%d seconds)\n", timeout);
if (FD_ISSET(rfd2, &ready)) {
errno = 0;
#ifdef KERBEROS
@@ -476,7 +481,7 @@ usage()
{
(void)fprintf(stderr,
- "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
+ "usage: rsh [-nd%s]%s[-l login] [-t timeout] host [command]\n",
#ifdef KERBEROS
#ifdef CRYPT
"x", " [-k realm] ");
@@ -488,3 +493,4 @@ usage()
#endif
exit(1);
}
+
diff --git a/usr.bin/rup/Makefile b/usr.bin/rup/Makefile
new file mode 100644
index 0000000..ab50a8a
--- /dev/null
+++ b/usr.bin/rup/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG= rup
+MAN1= rup.1
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rup/rup.1 b/usr.bin/rup/rup.1
new file mode 100644
index 0000000..76e6c1f
--- /dev/null
+++ b/usr.bin/rup/rup.1
@@ -0,0 +1,94 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 7, 1993
+.Dt RUP 1
+.Os BSD 4.3
+.Sh NAME
+.Nm rup
+.Nd remote status display
+.Sh SYNOPSIS
+.Nm rup
+.Op Ar host ...
+.Sh DESCRIPTION
+.Nm rup
+displays a summary of the current system status of a particular
+.Em host
+or all hosts on the local network.
+The output shows the current time of day, how long the system has
+been up,
+and the load averages.
+The load average numbers give the number of jobs in the run queue
+averaged over 1, 5 and 15 minutes.
+.Pp
+The
+.Xr rpc.rstatd 8
+daemon must be running on the remote host for this command to
+work.
+.Nm rup
+uses an RPC protocol defined in /usr/include/rpcsvc/rstat.x.
+.Sh EXAMPLE
+.Bd -unfilled -offset indent -compact
+example% rup otherhost
+otherhost 7:36am up 6 days, 16:45, load average: 0.20, 0.23, 0.18
+example%
+.Ed
+.Sh DIAGNOSTICS
+.Bl -tag -width indent
+.It rup: RPC: Program not registered
+The
+.Xr rpc.rstatd 8
+daemon has not been started on the remote host.
+.It rup: RPC: Timed out
+A communication error occurred. Either the network is
+excessively congested, or the
+.Xr rpc.rstatd 8
+daemon has terminated on the remote host.
+.It rup: RPC: Port mapper failure - RPC: Timed out
+The remote host is not running the portmapper (see
+.Xr portmap 8 ),
+and cannot accommodate any RPC-based services. The host may be down.
+.El
+.Sh SEE ALSO
+.Xr portmap 8 ,
+.Xr rpc.rstatd 8
+.Sh HISTORY
+The
+.Nm rup
+command
+appeared in
+.Em Sun-OS .
+.Sh BUGS
+The sorting options are not implemented.
diff --git a/usr.bin/rup/rup.c b/usr.bin/rup/rup.c
new file mode 100644
index 0000000..ba9a67e
--- /dev/null
+++ b/usr.bin/rup/rup.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 1993, John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <arpa/inet.h>
+
+#undef FSHIFT /* Use protocol's shift and scale values */
+#undef FSCALE
+#include <rpcsvc/rstat.h>
+
+#define HOST_WIDTH 15
+
+char *argv0;
+
+struct host_list {
+ struct host_list *next;
+ struct in_addr addr;
+} *hosts;
+
+int search_host(struct in_addr addr)
+{
+ struct host_list *hp;
+
+ if (!hosts)
+ return(0);
+
+ for (hp = hosts; hp != NULL; hp = hp->next) {
+ if (hp->addr.s_addr == addr.s_addr)
+ return(1);
+ }
+ return(0);
+}
+
+void remember_host(struct in_addr addr)
+{
+ struct host_list *hp;
+
+ if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) {
+ fprintf(stderr, "%s: no memory.\n", argv0);
+ exit(1);
+ }
+ hp->addr.s_addr = addr.s_addr;
+ hp->next = hosts;
+ hosts = hp;
+}
+
+rstat_reply(char *replyp, struct sockaddr_in *raddrp)
+{
+ struct tm *tmp_time;
+ struct tm host_time;
+ struct tm host_uptime;
+ char days_buf[16];
+ char hours_buf[16];
+ struct hostent *hp;
+ char *host;
+ statstime *host_stat = (statstime *)replyp;
+
+ if (search_host(raddrp->sin_addr))
+ return(0);
+
+ hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (hp)
+ host = hp->h_name;
+ else
+ host = inet_ntoa(raddrp->sin_addr);
+
+ /* truncate hostname to fit nicely into field */
+ if (strlen(host) > HOST_WIDTH)
+ host[HOST_WIDTH] = '\0';
+
+ printf("%-*s\t", HOST_WIDTH, host);
+
+ tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec);
+ host_time = *tmp_time;
+
+ host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
+
+ tmp_time = gmtime((time_t *)&host_stat->curtime.tv_sec);
+ host_uptime = *tmp_time;
+
+ #define updays (host_stat->curtime.tv_sec / 86400)
+ if (host_uptime.tm_yday != 0)
+ sprintf(days_buf, "%3d day%s, ", updays,
+ (updays > 1) ? "s" : "");
+ else
+ days_buf[0] = '\0';
+
+ if (host_uptime.tm_hour != 0)
+ sprintf(hours_buf, "%2d:%02d, ",
+ host_uptime.tm_hour, host_uptime.tm_min);
+ else
+ if (host_uptime.tm_min != 0)
+ sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min);
+ else
+ hours_buf[0] = '\0';
+
+ printf(" %2d:%02d%cm up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
+ host_time.tm_hour % 12,
+ host_time.tm_min,
+ (host_time.tm_hour >= 12) ? 'p' : 'a',
+ days_buf,
+ hours_buf,
+ (double)host_stat->avenrun[0]/FSCALE,
+ (double)host_stat->avenrun[1]/FSCALE,
+ (double)host_stat->avenrun[2]/FSCALE);
+
+ remember_host(raddrp->sin_addr);
+ return(0);
+}
+
+onehost(char *host)
+{
+ CLIENT *rstat_clnt;
+ statstime host_stat;
+ struct sockaddr_in addr;
+ struct hostent *hp;
+ struct timeval tv;
+
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "%s: unknown host \"%s\"\n",
+ argv0, host);
+ return(-1);
+ }
+
+ rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
+ if (rstat_clnt == NULL) {
+ fprintf(stderr, "%s: %s %s", argv0, host, clnt_spcreateerror(""));
+ return(-1);
+ }
+
+ bzero((char *)&host_stat, sizeof(host_stat));
+ tv.tv_sec = 15; /* XXX ??? */
+ tv.tv_usec = 0;
+ if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL, xdr_statstime, &host_stat, tv) != RPC_SUCCESS) {
+ fprintf(stderr, "%s: %s: %s\n", argv0, host, clnt_sperror(rstat_clnt, host));
+ return(-1);
+ }
+
+ addr.sin_addr.s_addr = *(int *)hp->h_addr;
+ rstat_reply((char *)&host_stat, &addr);
+}
+
+allhosts()
+{
+ statstime host_stat;
+ enum clnt_stat clnt_stat;
+
+ clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
+ xdr_void, NULL,
+ xdr_statstime, &host_stat, rstat_reply);
+ if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
+ fprintf(stderr, "%s: %s\n", argv0, clnt_sperrno(clnt_stat));
+ exit(1);
+ }
+}
+
+usage()
+{
+ fprintf(stderr, "Usage: %s [hosts ...]\n", argv0);
+ exit(1);
+}
+
+main(int argc, char *argv[])
+{
+ int ch;
+ extern int optind;
+
+ if (!(argv0 = rindex(argv[0], '/')))
+ argv0 = argv[0];
+ else
+ argv0++;
+
+ while ((ch = getopt(argc, argv, "?")) != -1)
+ switch (ch) {
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+
+ setlinebuf(stdout);
+ if (argc == optind)
+ allhosts();
+ else {
+ for (; optind < argc; optind++)
+ (void) onehost(argv[optind]);
+ }
+ exit(0);
+}
diff --git a/usr.bin/ruptime/ruptime.1 b/usr.bin/ruptime/ruptime.1
index b3b0af8..3e48bce 100644
--- a/usr.bin/ruptime/ruptime.1
+++ b/usr.bin/ruptime/ruptime.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ruptime.1 8.2 (Berkeley) 4/5/94
+.\" $Id$
.\"
.Dd April 5, 1994
.Dt RUPTIME 1
@@ -73,7 +74,7 @@ The default listing is sorted by host name.
data files
.El
.Sh SEE ALSO
-.Xr rwho 1
+.Xr rwho 1 ,
.Xr uptime 1
.Sh HISTORY
.Nm Ruptime
diff --git a/usr.bin/ruptime/ruptime.c b/usr.bin/ruptime/ruptime.c
index b9c17a7..e075d92 100644
--- a/usr.bin/ruptime/ruptime.c
+++ b/usr.bin/ruptime/ruptime.c
@@ -31,6 +31,8 @@
* SUCH DAMAGE.
*/
+/* $Id: ruptime.c,v 1.10 1997/03/29 04:32:02 imp Exp $ */
+
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993, 1994\n\
@@ -53,7 +55,6 @@ static char sccsid[] = "@(#)ruptime.c 8.2 (Berkeley) 4/5/94";
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
struct hs {
@@ -61,7 +62,7 @@ struct hs {
int hs_nusers;
} *hs;
struct whod awhod;
-
+#define LEFTEARTH(h) (now - (h)->hs_wd->wd_recvtime > 4*24*60*60)
#define ISDOWN(h) (now - (h)->hs_wd->wd_recvtime > 11 * 60)
#define WHDRSIZE (sizeof (awhod) - sizeof (awhod.wd_we))
@@ -95,7 +96,7 @@ main(argc, argv)
aflg = 0;
cmp = hscmp;
- while ((ch = getopt(argc, argv, "alrut")) != EOF)
+ while ((ch = getopt(argc, argv, "alrut")) != -1)
switch (ch) {
case 'a':
aflg = 1;
@@ -112,7 +113,7 @@ main(argc, argv)
case 'u':
cmp = ucmp;
break;
- default:
+ default:
usage();
}
argc -= optind;
@@ -160,12 +161,14 @@ main(argc, argv)
++nhosts;
}
if (nhosts == 0)
- errx(0, "no hosts in %s.", _PATH_RWHODIR);
+ errx(1, "no hosts in %s.", _PATH_RWHODIR);
(void)time(&now);
qsort(hs, nhosts, sizeof(hs[0]), cmp);
for (i = 0; i < nhosts; i++) {
hsp = &hs[i];
+ if (LEFTEARTH(hsp))
+ continue;
if (ISDOWN(hsp)) {
(void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname,
interval(now - hsp->hs_wd->wd_recvtime, "down"));
@@ -196,22 +199,22 @@ interval(tval, updown)
static char resbuf[32];
int days, hours, minutes;
- if (tval < 0 || tval > DAYSPERNYEAR * SECSPERDAY) {
+ if (tval < 0) {
(void)snprintf(resbuf, sizeof(resbuf), " %s ??:??", updown);
return (resbuf);
}
/* round to minutes. */
- minutes = (tval + (SECSPERMIN - 1)) / SECSPERMIN;
- hours = minutes / MINSPERHOUR;
- minutes %= MINSPERHOUR;
- days = hours / HOURSPERDAY;
- hours %= HOURSPERDAY;
+ minutes = (tval + (60 - 1)) / 60;
+ hours = minutes / 60;
+ minutes %= 60;
+ days = hours / 24;
+ hours %= 24;
if (days)
(void)snprintf(resbuf, sizeof(resbuf),
- "%s %2d+%02d:%02d", updown, days, hours, minutes);
+ "%s %3d+%02d:%02d", updown, days, hours, minutes);
else
(void)snprintf(resbuf, sizeof(resbuf),
- "%s %2d:%02d", updown, hours, minutes);
+ "%s %2d:%02d", updown, hours, minutes);
return (resbuf);
}
diff --git a/usr.bin/rusers/Makefile b/usr.bin/rusers/Makefile
new file mode 100644
index 0000000..a6b753f
--- /dev/null
+++ b/usr.bin/rusers/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG = rusers
+MAN1 = rusers.1
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rusers/rusers.1 b/usr.bin/rusers/rusers.1
new file mode 100644
index 0000000..7cf6164
--- /dev/null
+++ b/usr.bin/rusers/rusers.1
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)rusers.1 6.7 (Berkeley) 4/23/91
+.\" $Id$
+.\"
+.Dd April 23, 1991
+.Dt RUSERS 1
+.Os BSD 4.2
+.Sh NAME
+.Nm rusers
+.Nd who is logged in to machines on local network
+.Sh SYNOPSIS
+.Nm rusers
+.Op Fl al
+.Op Ar host ...
+.Sh DESCRIPTION
+The
+.Nm rusers
+command produces output similar to
+.Xr who ,
+but for the list of hosts or all machines on the local
+network. For each host responding to the rusers query,
+the hostname with the names of the users currently logged
+on is printed on each line. The rusers command will wait for
+one minute to catch late responders.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Print all machines responding even if no one is currently logged in.
+.It Fl l
+Print a long format listing. This includes the user name, host name,
+tty that the user is logged in to, the date and time the user
+logged in, the amount of time since the user typed on the keyboard,
+and the remote host they logged in from (if applicable).
+.El
+.Sh DIAGNOSTICS
+.Bl -tag -width indent
+.It rusers: RPC: Program not registered
+The
+.Xr rpc.rusersd 8
+daemon has not been started on the remote host.
+.It rusers: RPC: Timed out
+A communication error occurred. Either the network is
+excessively congested, or the
+.Xr rpc.rusersd 8
+daemon has terminated on the remote host.
+.It rusers: RPC: Port mapper failure - RPC: Timed out
+The remote host is not running the portmapper (see
+.Xr portmap 8 ),
+and cannot accommodate any RPC-based services. The host may be down.
+.El
+.Sh SEE ALSO
+.Xr who 1 ,
+.Xr portmap 8 ,
+.Xr rpc.rusersd 8
+.Sh HISTORY
+The
+.Nm rusers
+command
+appeared in
+.Em Sun-OS .
+.Sh BUGS
+The sorting options are not implemented.
diff --git a/usr.bin/rusers/rusers.c b/usr.bin/rusers/rusers.c
new file mode 100644
index 0000000..3d7b9a5
--- /dev/null
+++ b/usr.bin/rusers/rusers.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 1993, John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <strings.h>
+#include <rpc/rpc.h>
+#include <arpa/inet.h>
+#include <rpcsvc/rnusers.h>
+
+#define MAX_INT 0x7fffffff
+#define HOST_WIDTH 20
+#define LINE_WIDTH 15
+char *argv0;
+
+int longopt;
+int allopt;
+
+struct host_list {
+ struct host_list *next;
+ struct in_addr addr;
+} *hosts;
+
+int search_host(struct in_addr addr)
+{
+ struct host_list *hp;
+
+ if (!hosts)
+ return(0);
+
+ for (hp = hosts; hp != NULL; hp = hp->next) {
+ if (hp->addr.s_addr == addr.s_addr)
+ return(1);
+ }
+ return(0);
+}
+
+void remember_host(struct in_addr addr)
+{
+ struct host_list *hp;
+
+ if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) {
+ fprintf(stderr, "%s: no memory.\n", argv0);
+ exit(1);
+ }
+ hp->addr.s_addr = addr.s_addr;
+ hp->next = hosts;
+ hosts = hp;
+}
+
+rusers_reply(char *replyp, struct sockaddr_in *raddrp)
+{
+ int x, idle;
+ char date[32], idle_time[64], remote[64];
+ struct hostent *hp;
+ utmpidlearr *up = (utmpidlearr *)replyp;
+ char *host;
+ int days, hours, minutes, seconds;
+
+ if (search_host(raddrp->sin_addr))
+ return(0);
+
+ if (!allopt && !up->utmpidlearr_len)
+ return(0);
+
+ hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (hp)
+ host = hp->h_name;
+ else
+ host = inet_ntoa(raddrp->sin_addr);
+
+ if (!longopt)
+ printf("%-*s ", HOST_WIDTH, host);
+
+ for (x = 0; x < up->utmpidlearr_len; x++) {
+ strncpy(date,
+ &(ctime((time_t *)&(up->utmpidlearr_val[x].ui_utmp.ut_time))[4]),
+ sizeof(date)-1);
+
+ idle = up->utmpidlearr_val[x].ui_idle;
+ sprintf(idle_time, " :%02d", idle);
+ if (idle == MAX_INT)
+ strcpy(idle_time, "??");
+ else if (idle == 0)
+ strcpy(idle_time, "");
+ else {
+ seconds = idle;
+ days = seconds/(60*60*24);
+ seconds %= (60*60*24);
+ hours = seconds/(60*60);
+ seconds %= (60*60);
+ minutes = seconds/60;
+ seconds %= 60;
+ if (idle > 60)
+ sprintf(idle_time, "%d:%02d",
+ minutes, seconds);
+ if (idle >= (60*60))
+ sprintf(idle_time, "%d:%02d:%02d",
+ hours, minutes, seconds);
+ if (idle >= (24*60*60))
+ sprintf(idle_time, "%d days, %d:%02d:%02d",
+ days, hours, minutes, seconds);
+ }
+
+ strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, sizeof(remote)-1);
+ if (strlen(remote) != 0)
+ sprintf(remote, "(%.16s)", up->utmpidlearr_val[x].ui_utmp.ut_host);
+
+ if (longopt)
+ printf("%-8.8s %*s:%-*.*s %-12.12s %6s %.18s\n",
+ up->utmpidlearr_val[x].ui_utmp.ut_name,
+ HOST_WIDTH, host,
+ LINE_WIDTH, LINE_WIDTH, up->utmpidlearr_val[x].ui_utmp.ut_line,
+ date,
+ idle_time,
+ remote
+ );
+ else
+ printf("%s ",
+ up->utmpidlearr_val[x].ui_utmp.ut_name);
+ }
+ if (!longopt)
+ putchar('\n');
+
+ remember_host(raddrp->sin_addr);
+ return(0);
+}
+
+onehost(char *host)
+{
+ utmpidlearr up;
+ CLIENT *rusers_clnt;
+ struct sockaddr_in addr;
+ struct hostent *hp;
+ struct timeval tv;
+
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "%s: unknown host \"%s\"\n",
+ argv0, host);
+ exit(1);
+ }
+
+ rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
+ if (rusers_clnt == NULL) {
+ clnt_pcreateerror(argv0);
+ exit(1);
+ }
+
+ bzero((char *)&up, sizeof(up));
+ tv.tv_sec = 15; /* XXX ?? */
+ tv.tv_usec = 0;
+ if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, &up, tv) != RPC_SUCCESS) {
+ clnt_perror(rusers_clnt, argv0);
+ exit(1);
+ }
+ addr.sin_addr.s_addr = *(int *)hp->h_addr;
+ rusers_reply((char *)&up, &addr);
+}
+
+allhosts()
+{
+ utmpidlearr up;
+ enum clnt_stat clnt_stat;
+
+ bzero((char *)&up, sizeof(up));
+ clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NAMES,
+ xdr_void, NULL,
+ xdr_utmpidlearr, &up, rusers_reply);
+ if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
+ fprintf(stderr, "%s: %s\n", argv0, clnt_sperrno(clnt_stat));
+ exit(1);
+ }
+}
+
+usage()
+{
+ fprintf(stderr, "Usage: %s [-la] [hosts ...]\n", argv0);
+ exit(1);
+}
+
+main(int argc, char *argv[])
+{
+ int ch;
+ extern int optind;
+
+ if (!(argv0 = rindex(argv[0], '/')))
+ argv0 = argv[0];
+ else
+ argv0++;
+
+
+ while ((ch = getopt(argc, argv, "al")) != -1)
+ switch (ch) {
+ case 'a':
+ allopt++;
+ break;
+ case 'l':
+ longopt++;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+
+ setlinebuf(stdout);
+ if (argc == optind)
+ allhosts();
+ else {
+ for (; optind < argc; optind++)
+ (void) onehost(argv[optind]);
+ }
+ exit(0);
+}
diff --git a/usr.bin/rwall/Makefile b/usr.bin/rwall/Makefile
new file mode 100644
index 0000000..e81c30a
--- /dev/null
+++ b/usr.bin/rwall/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG = rwall
+MAN1 = rwall.1
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rwall/rwall.1 b/usr.bin/rwall/rwall.1
new file mode 100644
index 0000000..1531503
--- /dev/null
+++ b/usr.bin/rwall/rwall.1
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)rwall.1 6.7 (Berkeley) 4/23/91
+.\" $Id$
+.\"
+.Dd April 23, 1991
+.Dt RWALL 1
+.Os BSD 4.2
+.Sh NAME
+.Nm rwall
+.Nd send a message to users logged on a host
+.Sh SYNOPSIS
+.Nm rwall
+.Ar host
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm rwall
+command sends a message to the users logged into the specified host. The
+message to be sent can be typed in and terminated with EOF or it can
+be in a
+.Ar file .
+.Sh DIAGNOSTICS
+.Bl -tag -width indent
+.It rwall: RPC: Program not registered
+The
+.Xr rpc.rwalld 8
+daemon has not been started on the remote host.
+.It rwall: RPC: Timed out
+A communication error occurred. Either the network is
+excessively congested, or the
+.Xr rpc.rwalld 8
+daemon has terminated on the remote host.
+.It rwall: RPC: Port mapper failure - RPC: Timed out
+The remote host is not running the portmapper (see
+.Xr portmap 8 ),
+and cannot accomodate any RPC-based services. The host may be down.
+.El
+.Sh SEE ALSO
+.Xr who 1 ,
+.Xr portmap 8 ,
+.Xr rpc.rwalld 8
+.Sh HISTORY
+The
+.Nm rwall
+command
+appeared in
+.Em Sun-OS .
+.Sh BUGS
+The sorting options are not implemented.
diff --git a/usr.bin/rwall/rwall.c b/usr.bin/rwall/rwall.c
new file mode 100644
index 0000000..fe0983a
--- /dev/null
+++ b/usr.bin/rwall/rwall.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * Copyright (c) 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)wall.c 5.14 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+/*
+ * This program is not related to David Wall, whose Stanford Ph.D. thesis
+ * is entitled "Mechanisms for Broadcast and Selective Broadcast".
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/rwall.h>
+
+int mbufsize;
+char *mbuf;
+
+/* ARGSUSED */
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *wallhost, res;
+ CLIENT *cl;
+ struct timeval tv;
+
+ if ((argc < 2) || (argc > 3)) {
+ fprintf(stderr, "usage: %s hostname [file]\n", argv[0]);
+ exit(1);
+ }
+
+ wallhost = argv[1];
+
+ makemsg(argv[2]);
+
+ /*
+ * Create client "handle" used for calling MESSAGEPROG on the
+ * server designated on the command line. We tell the rpc package
+ * to use the "tcp" protocol when contacting the server.
+ */
+ cl = clnt_create(wallhost, WALLPROG, WALLVERS, "udp");
+ if (cl == NULL) {
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+ clnt_pcreateerror(wallhost);
+ exit(1);
+ }
+
+ tv.tv_sec = 15; /* XXX ?? */
+ tv.tv_usec = 0;
+ if (clnt_call(cl, WALLPROC_WALL, xdr_wrapstring, &mbuf, xdr_void, &res, tv) != RPC_SUCCESS) {
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+ clnt_perror(cl, wallhost);
+ exit(1);
+ }
+
+ exit(0);
+}
+
+makemsg(fname)
+ char *fname;
+{
+ register int ch, cnt;
+ struct tm *lt;
+ struct passwd *pw;
+ struct stat sbuf;
+ time_t now, time();
+ FILE *fp;
+ int fd;
+ char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15];
+ char *getlogin(), *strcpy(), *ttyname();
+
+ (void)strcpy(tmpname, _PATH_TMP);
+ (void)strcat(tmpname, "/wall.XXXXXX");
+ if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) {
+ (void)fprintf(stderr, "wall: can't open temporary file.\n");
+ exit(1);
+ }
+ (void)unlink(tmpname);
+
+ if (!(whom = getlogin()))
+ whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+ (void)gethostname(hostname, sizeof(hostname));
+ (void)time(&now);
+ lt = localtime(&now);
+
+ /*
+ * all this stuff is to blank out a square for the message;
+ * we wrap message lines at column 79, not 80, because some
+ * terminals wrap after 79, some do not, and we can't tell.
+ * Which means that we may leave a non-blank character
+ * in column 80, but that can't be helped.
+ */
+ (void)fprintf(fp, "Remote Broadcast Message from %s@%s\n",
+ whom, hostname);
+ (void)fprintf(fp, " (%s) at %d:%02d ...\n", ttyname(2),
+ lt->tm_hour, lt->tm_min);
+
+ putc('\n', fp);
+
+ if (fname && !(freopen(fname, "r", stdin))) {
+ (void)fprintf(stderr, "wall: can't read %s.\n", fname);
+ exit(1);
+ }
+ while (fgets(lbuf, sizeof(lbuf), stdin))
+ fputs(lbuf, fp);
+ rewind(fp);
+
+ if (fstat(fd, &sbuf)) {
+ (void)fprintf(stderr, "wall: can't stat temporary file.\n");
+ exit(1);
+ }
+ mbufsize = sbuf.st_size;
+ if (!(mbuf = malloc((u_int)mbufsize))) {
+ (void)fprintf(stderr, "wall: out of memory.\n");
+ exit(1);
+ }
+ if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) {
+ (void)fprintf(stderr, "wall: can't read temporary file.\n");
+ exit(1);
+ }
+ (void)close(fd);
+}
diff --git a/usr.bin/rwho/rwho.1 b/usr.bin/rwho/rwho.1
index f039b01..898ccc7 100644
--- a/usr.bin/rwho/rwho.1
+++ b/usr.bin/rwho/rwho.1
@@ -62,7 +62,7 @@ unless the
.Fl a
flag is given.
.Sh FILES
-.Bl -tag -width /var/rwho/rhowd.* -compact
+.Bl -tag -width /var/rwho/whod.* -compact
.It Pa /var/rwho/whod.*
information about other machines
.El
diff --git a/usr.bin/rwho/rwho.c b/usr.bin/rwho/rwho.c
index ee9c76d..557e8fa 100644
--- a/usr.bin/rwho/rwho.c
+++ b/usr.bin/rwho/rwho.c
@@ -42,10 +42,14 @@ static char sccsid[] = "@(#)rwho.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
-#include <sys/dir.h>
#include <sys/file.h>
#include <protocols/rwhod.h>
+#include <dirent.h>
+#include <locale.h>
#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utmp.h>
DIR *dirp;
@@ -53,19 +57,18 @@ struct whod wd;
int utmpcmp();
#define NUSERS 1000
struct myutmp {
- char myhost[MAXHOSTNAMELEN];
+ char myhost[sizeof(wd.wd_hostname)];
int myidle;
struct outmp myutmp;
} myutmp[NUSERS];
int nusers;
#define WHDRSIZE (sizeof (wd) - sizeof (wd.wd_we))
-/*
+/*
* this macro should be shared with ruptime.
*/
#define down(w,now) ((now) - (w)->wd_recvtime > 11 * 60)
-char *ctime(), *strcpy();
time_t now;
int aflg;
@@ -76,15 +79,16 @@ main(argc, argv)
extern char *optarg;
extern int optind;
int ch;
- struct direct *dp;
+ struct dirent *dp;
int cc, width;
register struct whod *w = &wd;
register struct whoent *we;
register struct myutmp *mp;
int f, n, i;
- time_t time();
- while ((ch = getopt(argc, argv, "a")) != EOF)
+ (void) setlocale(LC_TIME, "");
+
+ while ((ch = getopt(argc, argv, "a")) != -1)
switch((char)ch) {
case 'a':
aflg = 1;
@@ -136,20 +140,24 @@ main(argc, argv)
mp = myutmp;
width = 0;
for (i = 0; i < nusers; i++) {
- int j = strlen(mp->myhost) + 1 + strlen(mp->myutmp.out_line);
+ /* append one for the blank and use 8 for the out_line */
+ int j = strlen(mp->myhost) + 1 + sizeof(mp->myutmp.out_line);
if (j > width)
width = j;
mp++;
}
mp = myutmp;
for (i = 0; i < nusers; i++) {
- char buf[BUFSIZ];
- (void)sprintf(buf, "%s:%s", mp->myhost, mp->myutmp.out_line);
- printf("%-8.8s %-*s %.12s",
+ char buf[BUFSIZ], cbuf[80];
+ strftime(cbuf, sizeof(cbuf), "%c", localtime((time_t *)&mp->myutmp.out_time));
+ (void)sprintf(buf, "%s:%-.*s", mp->myhost,
+ sizeof(mp->myutmp.out_line), mp->myutmp.out_line);
+ printf("%-*.*s %-*s %.12s",
+ UT_NAMESIZE, sizeof(mp->myutmp.out_name),
mp->myutmp.out_name,
width,
buf,
- ctime((time_t *)&mp->myutmp.out_time)+4);
+ cbuf + 4);
mp->myidle /= 60;
if (mp->myidle) {
if (aflg) {
@@ -174,11 +182,11 @@ utmpcmp(u1, u2)
{
int rc;
- rc = strncmp(u1->myutmp.out_name, u2->myutmp.out_name, 8);
+ rc = strncmp(u1->myutmp.out_name, u2->myutmp.out_name, sizeof(u2->myutmp.out_name));
if (rc)
return (rc);
- rc = strncmp(u1->myhost, u2->myhost, 8);
+ rc = strcmp(u1->myhost, u2->myhost);
if (rc)
return (rc);
- return (strncmp(u1->myutmp.out_line, u2->myutmp.out_line, 8));
+ return (strncmp(u1->myutmp.out_line, u2->myutmp.out_line, sizeof(u2->myutmp.out_line)));
}
diff --git a/usr.bin/sasc/INSTALL b/usr.bin/sasc/INSTALL
new file mode 100644
index 0000000..448a7a2
--- /dev/null
+++ b/usr.bin/sasc/INSTALL
@@ -0,0 +1,86 @@
+To install the device driver, please do the following steps:
+
+1. Install the files by copying them as listed in the following table:
+
+ asc.c /usr/sys/i386/isa/
+ ascreg.h /usr/sys/i386/isa/
+ asc_ioctl.h /usr/sys/i386/include/
+
+ Note that if you have copies of the system header directories
+ in /usr/include/ instead of symbolic links, you have to copy
+ `asc.h' to /usr/include/machine/ also. I recommend to replace
+ the copies by links though.
+
+[the following steps, 2..5, can be achieved by moving to
+ /sys/i386 and doing "patch < diffs.asc"]
+
+2. Make the driver source known to config(8) by editing the file
+ /usr/src/sys/i386/conf/files.i386. Just append the following line:
+
+ i386/isa/asc.c optional asc device-driver
+
+3. Include a driver access record in /usr/src/sys/i386/i386/conf.c
+ Append the following structure at the end of the array that
+ contains the *character* device drivers. Remember the major number
+ that will be used for the driver, i.e. the number following the
+ number af the preceeding record.
+
+ { ascopen, ascclose, ascread, nowrite, /*<major>*/
+ ascioctl, nostop, nullreset, nodevtotty, /* asc */
+ ascselect, nommap, NULL },
+
+4. Insert the definitions for the base port addresses of the device
+ into the file /usr/src/sys/i386/isa/isa.h:
+
+#define IO_ASC1 0x3EB /* AmiScan addr.grp. 1 */
+#define IO_ASC2 0x22B /* AmiScan addr.grp. 2 */
+#define IO_ASC3 0x26B /* AmiScan addr.grp. 3 */
+#define IO_ASC4 0x2AB /* AmiScan addr.grp. 4 */
+#define IO_ASC5 0x2EB /* AmiScan addr.grp. 5 */
+#define IO_ASC6 0x32B /* AmiScan addr.grp. 6 */
+#define IO_ASC7 0x36B /* AmiScan addr.grp. 7 */
+#define IO_ASC8 0x3AB /* AmiScan addr.grp. 8 */
+
+5. Patch /dev/MAKEDEV by adding the following lines in the switch to
+ create the device entries:
+
+ asc*)
+ rm -f asc0
+ mknod asc0 c 68 0
+ mknod asc0p c 68 8
+ chmod 666 asc0 asc0p
+ chown root.wheel asc0 asc0p
+ ;;
+
+
+
+6. Edit your kernel configuration file (in /usr/src/sys/i386/conf/)
+ by inserting the following line:
+
+ device asc0 at isa? port 0x2ab tty drq 3 irq 10 vector ascintr
+
+ This should usually work for you as it reflects the factory
+ settings of the AMI scanner. However, if this conflicts with
+ any other device on your system, you have the option to change
+ `drq 3' into `drq 1' or `drq 5' and the actual port value to
+ "IO_ASC1".. "IO_ASC8" as defined in isa.h
+
+7. Rebuild the kernel, don't forget to config(8) and `make depend' first.
+
+8. Make the following device nodes:
+
+ mknod /dev/asc0 c <major> 0
+ mknod /dev/asc0p c <major> 8
+
+ (or, cd /dev and do ./MAKEDEV asc0).
+
+ If you plan to modify the and debug the driver, add these (you
+ won't need these though, unless you know how to get this
+ information from elsewhere.
+
+ mknod /dev/asc0d c <major> 32
+ mknod /dev/asc0pd c <major> 40
+
+9. Install the new kernel and reboot. You can try the driver by
+ doing a simple "cat /dev/asc0p > myfile.pbm" and then trying
+ to display the PBM image with xv or some other tool.
diff --git a/usr.bin/sasc/Makefile b/usr.bin/sasc/Makefile
new file mode 100644
index 0000000..022cd27
--- /dev/null
+++ b/usr.bin/sasc/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sasc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sasc/README b/usr.bin/sasc/README
new file mode 100644
index 0000000..5436bd2
--- /dev/null
+++ b/usr.bin/sasc/README
@@ -0,0 +1,9 @@
+ASC - A device driver for a handy scanner
+
+This is a device driver for GI1904-based hand scanners, e.g. the Trust
+Amiscan Grey and possibly others. The driver is based on the "gsc"
+driver and, partly, on a Linux driver.
+
+The driver has a working select().
+
+-Luigi Rizzo (luigi@iet.unipi.it)
diff --git a/usr.bin/sasc/sasc.1 b/usr.bin/sasc/sasc.1
new file mode 100644
index 0000000..ab2275f
--- /dev/null
+++ b/usr.bin/sasc/sasc.1
@@ -0,0 +1,94 @@
+.\" sasc(1) - manual page for the `asc' scanner device driver utility
+.\"
+.\"
+.\" Copyright (c) 1995 Gunther Schadow. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Gunther Schadow.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.TH SASC 1 "January 6, 1995" FreeBSD "FreeBSD Reference Manual"
+.SH NAME
+\fBsasc\fP - set the options of the asc scanner device
+.SH SYNOPSIS
+.TP 5
+\fBsasc\fP
+[\fB-sq\fP]
+[\fB-b\fP\ \fIlen\fP]
+[\fB-f\fP\ \fIfile\fP]
+[\fB-h\fP\ \fIheight\fP]
+[\fB-r\fP\ \fIresolution\fP]
+[\fB-t\fP\ \fItimeout\fP]
+[\fB-w\fP\ \fIwidth\fP]
+.SH DESCRIPTION
+The \fBsasc\fP utility provides shell level access to the ioctl
+requests served by the handy scanner device driver asc. Please see
+asc(4) for the exact meaning of the requests. Generally they modify
+the output and behavior of the asc scanner device. When \fBsasc\fP is
+called with no option only the current settings are reported.
+.SH OPTIONS
+.TP 3
+\fB-s\fP [ASC_SRESSW]
+Set the scanner with the values of the resolution selector switch.
+.TP
+\fB-q\fP
+Operate in quiet mode, i.e. do not report any of the current settings.
+Normally the parameters are shown after the modifications have been
+performed.
+.TP
+\fB-f\fP \fIfile\fP
+Operate on a different scanner device node given by filename. Note
+that even though there may exist more than one node of scanner device
+several of them will refer the same device unit. The modifications are
+performed od the unit regardless of the device node by which it is
+accessed.
+.TP
+\fB-r\fP \fIresolution\fP [ASC_SRES]
+Set the resolution in dpi.
+.TP
+\fB-w\fP \fIwidth\fP [ASC_SWIDHT]
+Set the width of the bitmap in pixels.
+.TP
+\fB-h\fP \fIheight\fP [ASC_SHEIGHT]
+Set the height of the bitmap in lines of pixels.
+.TP
+\fB-b\fP \fIlen\fP [ASC_SBLEN]
+Set the internal dma buffer to be \fIlen\fP lines in size.
+.TP
+\fB-t\fP \fItimeout\fP [ASC_SBTIME]
+Set the timeout time for reading one dma buffer.
+.SH FILES
+.TP 15
+.BI /dev/asc0
+device node for \fIraw\fP output.
+.TP
+.BI /dev/asc0p
+device node for output in \fIpbm\fP file format.
+.PB
+.SH SEE ALSO
+asc(4)
+.SH AUTHOR
+Gunther Schadow <gusw@fub46.zedat.fu-berlin.de>
diff --git a/usr.bin/sasc/sasc.c b/usr.bin/sasc/sasc.c
new file mode 100644
index 0000000..b968f9e
--- /dev/null
+++ b/usr.bin/sasc/sasc.c
@@ -0,0 +1,197 @@
+/* sasc(1) - utility for the `asc' scanner device driver
+ *
+ *
+ * Copyright (c) 1995 Gunther Schadow. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gunther Schadow.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * $Id: sasc.c,v 1.4 1997/02/22 19:56:57 peter Exp $
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/asc_ioctl.h>
+
+#ifndef DEFAULT_FILE
+#define DEFAULT_FILE "/dev/asc0"
+#endif
+#ifdef FAIL
+#undef FAIL
+#endif
+#define FAIL -1
+
+usage(char *progn)
+{
+ fprintf(stderr, "usage: %s [-sq] [-f file] [-r dpi] "
+ "[-w width] [-h height] "
+ "[-b len] [-t time]\n", progn);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ char c;
+ int fd;
+
+ char *file = DEFAULT_FILE;
+
+ int show_dpi = 0;
+ int show_width = 0;
+ int show_height = 0;
+ int show_blen = 0;
+ int show_btime = 0;
+ int show_all = 1;
+
+ int set_blen = 0;
+ int set_dpi = 0;
+ int set_width = 0;
+ int set_height = 0;
+ int set_btime = 0;
+ int set_switch = 0;
+
+ char *progn = *argv;
+
+ if (argc == 0) usage(progn);
+
+ while( (c = getopt(argc, argv, "sqf:b:r:w:h:t:")) != FAIL)
+ {
+ switch(c) {
+ case 'f': file = optarg; break;
+ case 'r': set_dpi = atoi(optarg); break;
+ case 'w': set_width = atoi(optarg); break;
+ case 'h': set_height = atoi(optarg); break;
+ case 'b': set_blen = atoi(optarg); break;
+ case 't': set_btime = atoi(optarg); break;
+ case 's': set_switch = 1; break;
+ case 'q': show_all = 0; break;
+ default: usage(progn);
+ }
+ }
+
+ fd = open(file, O_RDONLY);
+ if ( fd == FAIL )
+ {
+ perror(file);
+ exit(1);
+ }
+
+ if (set_switch != 0)
+ {
+ if(ioctl(fd, ASC_SRESSW) == FAIL)
+ {
+ perror("ASC_SRESSW");
+ exit(1);
+ }
+ }
+
+ if (set_dpi != 0)
+ {
+ if(ioctl(fd, ASC_SRES, &set_dpi) == FAIL)
+ {
+ perror("ASC_SRES");
+ exit(1);
+ }
+ }
+
+ if (set_width != 0)
+ {
+ if(ioctl(fd, ASC_SWIDTH, &set_width) == FAIL)
+ {
+ perror("ASC_SWIDTH");
+ exit(1);
+ }
+ }
+
+ if (set_height != 0)
+ {
+ if(ioctl(fd, ASC_SHEIGHT, &set_height) == FAIL)
+ {
+ perror("ASC_SHEIGHT");
+ exit(1);
+ }
+ }
+
+ if (set_blen != 0)
+ {
+ if(ioctl(fd, ASC_SBLEN, &set_blen) == FAIL)
+ {
+ perror("ASC_SBLEN");
+ exit(1);
+ }
+ }
+
+ if (set_btime != 0)
+ {
+ if(ioctl(fd, ASC_SBTIME, &set_btime) == FAIL)
+ {
+ perror("ASC_SBTIME");
+ exit(1);
+ }
+ }
+
+ if (show_all != 0)
+ {
+ if(ioctl(fd, ASC_GRES, &show_dpi) == FAIL)
+ {
+ perror("ASC_GRES");
+ exit(1);
+ }
+ if(ioctl(fd, ASC_GWIDTH, &show_width) == FAIL)
+ {
+ perror("ASC_GWIDTH");
+ exit(1);
+ }
+ if(ioctl(fd, ASC_GHEIGHT, &show_height) == FAIL)
+ {
+ perror("ASC_GHEIGHT");
+ exit(1);
+ }
+ if(ioctl(fd, ASC_GBLEN, &show_blen) == FAIL)
+ {
+ perror("ASC_GBLEN");
+ exit(1);
+ }
+ if(ioctl(fd, ASC_GBTIME, &show_btime) == FAIL)
+ {
+ perror("ASC_GBTIME");
+ exit(1);
+ }
+
+ printf("%s:\n", file);
+ printf("resolution\t %d dpi\n", show_dpi);
+ printf("width\t\t %d\n", show_width);
+ printf("height\t\t %d\n",show_height);
+ printf("buffer length\t %d\n", show_blen);
+ printf("buffer timeout\t %d\n", show_btime);
+ }
+
+ return 0;
+}
diff --git a/usr.bin/script/script.c b/usr.bin/script/script.c
index e688d64..6c9ed08 100644
--- a/usr.bin/script/script.c
+++ b/usr.bin/script/script.c
@@ -55,7 +55,6 @@ static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
#include <stdlib.h>
#include <string.h>
#include <termios.h>
-#include <tzfile.h>
#include <unistd.h>
FILE *fscript;
@@ -66,13 +65,13 @@ char *fname;
struct termios tt;
-__dead void done __P((void));
- void dooutput __P((void));
- void doshell __P((void));
- void err __P((const char *, ...));
- void fail __P((void));
- void finish __P((int));
- void scriptflush __P((int));
+void done __P((void)) __dead2;
+void dooutput __P((void));
+void doshell __P((void));
+void err __P((const char *, ...));
+void fail __P((void));
+void finish __P((int));
+void scriptflush __P((int));
int
main(argc, argv)
@@ -86,7 +85,7 @@ main(argc, argv)
char ibuf[BUFSIZ];
aflg = 0;
- while ((ch = getopt(argc, argv, "a")) != EOF)
+ while ((ch = getopt(argc, argv, "a")) != -1)
switch(ch) {
case 'a':
aflg = 1;
@@ -171,7 +170,7 @@ dooutput()
(void)fprintf(fscript, "Script started on %s", ctime(&tvec));
(void)signal(SIGALRM, scriptflush);
- value.it_interval.tv_sec = SECSPERMIN / 2;
+ value.it_interval.tv_sec = 60 / 2;
value.it_interval.tv_usec = 0;
value.it_value = value.it_interval;
(void)setitimer(ITIMER_REAL, &value, NULL);
diff --git a/usr.bin/sed/TEST/sed.test b/usr.bin/sed/TEST/sed.test
index e91036f..71c7f20 100644
--- a/usr.bin/sed/TEST/sed.test
+++ b/usr.bin/sed/TEST/sed.test
@@ -43,9 +43,9 @@
main()
{
- BASE=/usr/old/bin/sed
+ BASE=/usr/bin/sed
BASELOG=sed.out
- TEST=../obj/sed
+ TEST=`cd ..; make whereobj`/sed
TESTLOG=nsed.out
DICT=/usr/share/dict/words
diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c
index 8ad1b2d..91bf843 100644
--- a/usr.bin/sed/compile.c
+++ b/usr.bin/sed/compile.c
@@ -36,7 +36,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)compile.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/types.h>
@@ -64,6 +64,7 @@ static struct labhash {
} *labels[LHSZ];
static char *compile_addr __P((char *, struct s_addr *));
+static char *compile_ccl __P((char **, char *));
static char *compile_delimited __P((char *, char *));
static char *compile_flags __P((char *, struct s_subst *));
static char *compile_re __P((char *, regex_t **));
@@ -71,7 +72,7 @@ static char *compile_subst __P((char *, struct s_subst *));
static char *compile_text __P((void));
static char *compile_tr __P((char *, char **));
static struct s_command
- **compile_stream __P((char *, struct s_command **, char *));
+ **compile_stream __P((struct s_command **));
static char *duptoeol __P((char *, char *));
static void enterlabel __P((struct s_command *));
static struct s_command
@@ -90,6 +91,7 @@ struct s_format {
static struct s_format cmd_fmts[] = {
{'{', 2, GROUP},
+ {'}', 0, ENDGROUP},
{'a', 1, TEXT},
{'b', 2, BRANCH},
{'c', 2, TEXT},
@@ -129,7 +131,7 @@ struct s_command *prog;
void
compile()
{
- *compile_stream(NULL, &prog, NULL) = NULL;
+ *compile_stream(&prog) = NULL;
fixuplabel(prog, NULL);
uselabel();
appends = xmalloc(sizeof(struct s_appends) * appendnum);
@@ -138,26 +140,24 @@ compile()
#define EATSPACE() do { \
if (p) \
- while (*p && isascii(*p) && isspace(*p)) \
+ while (*p && isspace((unsigned char)*p)) \
p++; \
} while (0)
static struct s_command **
-compile_stream(terminator, link, p)
- char *terminator;
+compile_stream(link)
struct s_command **link;
- register char *p;
{
+ register char *p;
static char lbuf[_POSIX2_LINE_MAX + 1]; /* To save stack */
- struct s_command *cmd, *cmd2;
+ struct s_command *cmd, *cmd2, *stack;
struct s_format *fp;
int naddr; /* Number of addresses */
- if (p != NULL)
- goto semicolon;
+ stack = 0;
for (;;) {
if ((p = cu_fgets(lbuf, sizeof(lbuf))) == NULL) {
- if (terminator != NULL)
+ if (stack != 0)
err(COMPILE, "unexpected EOF (pending }'s)");
return (link);
}
@@ -165,11 +165,6 @@ compile_stream(terminator, link, p)
semicolon: EATSPACE();
if (p && (*p == '#' || *p == '\0'))
continue;
- if (*p == '}') {
- if (terminator == NULL)
- err(COMPILE, "unexpected }");
- return (link);
- }
*link = cmd = xmalloc(sizeof(struct s_command));
link = &cmd->next;
cmd->nonsel = cmd->inrange = 0;
@@ -216,20 +211,24 @@ nonsel: /* Now parse the command */
case GROUP: /* { */
p++;
EATSPACE();
- if (!*p)
- p = NULL;
- cmd2 = xmalloc(sizeof(struct s_command));
- cmd2->code = '}';
- *compile_stream("}", &cmd->u.c, p) = cmd2;
- cmd->next = cmd2;
- link = &cmd2->next;
+ cmd->next = stack;
+ stack = cmd;
+ link = &cmd->u.c;
+ if (*p)
+ goto semicolon;
+ break;
+ case ENDGROUP:
/*
* Short-circuit command processing, since end of
* group is really just a noop.
*/
- cmd2->nonsel = 1;
- cmd2->a1 = cmd2->a2 = 0;
- break;
+ cmd->nonsel = 1;
+ if (stack == 0)
+ err(COMPILE, "unexpected }");
+ cmd2 = stack;
+ stack = cmd2->next;
+ cmd2->next = cmd;
+ /*FALLTHROUGH*/
case EMPTY: /* d D g G h H l n N p P q x = \0 */
p++;
EATSPACE();
@@ -353,7 +352,13 @@ compile_delimited(p, d)
else if (c == '\n')
err(COMPILE, "newline can not be used as a string delimiter");
while (*p) {
- if (*p == '\\' && p[1] == c)
+ if (*p == '[') {
+ if ((d = compile_ccl(&p, d)) == NULL)
+ err(COMPILE, "unbalanced brackets ([])");
+ continue;
+ } else if (*p == '\\' && p[1] == '[') {
+ *d++ = *p++;
+ } else if (*p == '\\' && p[1] == c)
p++;
else if (*p == '\\' && p[1] == 'n') {
*d++ = '\n';
@@ -370,6 +375,32 @@ compile_delimited(p, d)
return (NULL);
}
+
+/* compile_ccl: expand a POSIX character class */
+static char *
+compile_ccl(sp, t)
+ char **sp;
+ char *t;
+{
+ int c, d;
+ char *s = *sp;
+
+ *t++ = *s++;
+ if (*s == '^')
+ *t++ = *s++;
+ if (*s == ']')
+ *t++ = *s++;
+ for (; *s && (*t = *s) != ']'; s++, t++)
+ if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '=')) {
+ *++t = *++s, t++, s++;
+ for (c = *s; (*t = *s) != ']' || c != d; s++, t++)
+ if ((c = *s) == '\0')
+ return NULL;
+ } else if (*s == '\\' && s[1] == 'n')
+ *t = '\n', s++;
+ return (*s == ']') ? *sp = ++s, ++t : NULL;
+}
+
/*
* Get a regular expression. P points to the delimiter of the regular
* expression; repp points to the address of a regexp pointer. Newline
@@ -584,7 +615,7 @@ compile_tr(p, transtab)
static char *
compile_text()
{
- int asize, size;
+ int asize, esc_nl, size;
char *text, *p, *op, *s;
char lbuf[_POSIX2_LINE_MAX + 1];
@@ -595,13 +626,13 @@ compile_text()
op = s = text + size;
p = lbuf;
EATSPACE();
- for (; *p; p++) {
- if (*p == '\\')
- p++;
+ for (esc_nl = 0; *p != '\0'; p++) {
+ if (*p == '\\' && p[1] != '\0' && *++p == '\n')
+ esc_nl = 1;
*s++ = *p;
}
size += s - op;
- if (p[-2] != '\\') {
+ if (!esc_nl) {
*s = '\0';
break;
}
@@ -639,7 +670,7 @@ compile_addr(p, a)
a->type = AT_LAST;
return (p + 1);
/* Line number */
- case '0': case '1': case '2': case '3': case '4':
+ case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
a->type = AT_LINE;
a->u.l = strtol(p, &end, 10);
@@ -665,7 +696,7 @@ duptoeol(s, ctype)
ws = 0;
for (start = s; *s != '\0' && *s != '\n'; ++s)
- ws = isspace(*s);
+ ws = isspace((unsigned char)*s);
*s = '\0';
if (ws)
err(WARNING, "whitespace after %s", ctype);
@@ -757,7 +788,7 @@ findlabel(name)
return (NULL);
}
-/*
+/*
* Warn about any unused labels. As a side effect, release the label hash
* table space.
*/
diff --git a/usr.bin/sed/defs.h b/usr.bin/sed/defs.h
index 3cc580f..6e78e91 100644
--- a/usr.bin/sed/defs.h
+++ b/usr.bin/sed/defs.h
@@ -100,6 +100,7 @@ enum e_args {
TEXT, /* a c i */
NONSEL, /* ! */
GROUP, /* { */
+ ENDGROUP, /* } */
COMMENT, /* # */
BRANCH, /* b t */
LABEL, /* : */
diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c
index 14872fd..02cbfac 100644
--- a/usr.bin/sed/main.c
+++ b/usr.bin/sed/main.c
@@ -47,9 +47,9 @@ static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94";
#include <sys/types.h>
-#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <locale.h>
#include <regex.h>
#include <stddef.h>
#include <stdio.h>
@@ -109,8 +109,10 @@ main(argc, argv)
{
int c, fflag;
+ (void) setlocale(LC_ALL, "");
+
fflag = 0;
- while ((c = getopt(argc, argv, "ae:f:n")) != EOF)
+ while ((c = getopt(argc, argv, "ae:f:n")) != -1)
switch (c) {
case 'a':
aflag = 1;
@@ -129,7 +131,7 @@ main(argc, argv)
default:
case '?':
(void)fprintf(stderr,
-"usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n");
+"usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f script_file] ... [file ...]\n");
exit(1);
}
argc -= optind;
@@ -254,7 +256,8 @@ mf_fgets(sp, spflag)
{
static FILE *f; /* Current open file */
size_t len;
- char c, *p;
+ char *p;
+ int c;
if (f == NULL)
/* Advance to first non-empty file */
diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c
index 2ec8aac..3b0828c 100644
--- a/usr.bin/sed/process.c
+++ b/usr.bin/sed/process.c
@@ -89,11 +89,12 @@ process()
{
struct s_command *cp;
SPACE tspace;
- size_t len;
- char oldc, *p;
+ size_t len, oldpsl;
+ char *p;
for (linenum = 0; mf_fgets(&PS, REPLACE);) {
pd = 0;
+top:
cp = prog;
redirect:
while (cp != NULL) {
@@ -130,13 +131,14 @@ redirect:
case 'D':
if (pd)
goto new;
- if ((p = memchr(ps, '\n', psl)) == NULL)
+ if ((p = memchr(ps, '\n', psl - 1)) == NULL) {
pd = 1;
- else {
- psl -= (p - ps) + 1;
+ goto new;
+ } else {
+ psl -= (p + 1) - ps;
memmove(ps, p + 1, psl);
+ goto top;
}
- goto new;
case 'g':
cspace(&PS, hs, hsl, REPLACE);
break;
@@ -179,13 +181,13 @@ redirect:
case 'P':
if (pd)
break;
- if ((p = memchr(ps, '\n', psl)) != NULL) {
- oldc = *p;
- *p = '\0';
+ if ((p = memchr(ps, '\n', psl - 1)) != NULL) {
+ oldpsl = psl;
+ psl = (p + 1) - ps;
}
OUT(ps)
if (p != NULL)
- *p = oldc;
+ psl = oldpsl;
break;
case 'q':
if (!nflag && !pd)
@@ -226,7 +228,7 @@ redirect:
break;
case 'x':
if (hs == NULL)
- cspace(&HS, "", 0, REPLACE);
+ cspace(&HS, "\n", 1, REPLACE);
tspace = PS;
PS = HS;
HS = tspace;
@@ -345,18 +347,18 @@ substitute(cp)
regsub(&SS, s, cp->u.s->new);
}
- /* Move past this match. */
+ /* Move past this match. */
if (match[0].rm_so != match[0].rm_eo) {
s += match[0].rm_eo;
slen -= match[0].rm_eo;
lastempty = 0;
} else {
if (match[0].rm_so == 0)
- cspace(&SS,
- s, match[0].rm_so + 1, APPEND);
+ cspace(&SS, s, match[0].rm_so + 1,
+ APPEND);
else
- cspace(&SS,
- s + match[0].rm_so, 1, APPEND);
+ cspace(&SS, s + match[0].rm_so, 1,
+ APPEND);
s += match[0].rm_so + 1;
slen -= match[0].rm_so + 1;
lastempty = 1;
@@ -423,10 +425,10 @@ flush_appends()
int count, i;
char buf[8 * 1024];
- for (i = 0; i < appendx; i++)
+ for (i = 0; i < appendx; i++)
switch (appends[i].type) {
case AP_STRING:
- fwrite(appends[i].s, sizeof(char), appends[i].len,
+ fwrite(appends[i].s, sizeof(char), appends[i].len,
stdout);
break;
case AP_FILE:
@@ -468,12 +470,12 @@ lputs(s)
else
termwidth = 60;
- for (count = 0; *s; ++s) {
+ for (count = 0; *s; ++s) {
if (count >= termwidth) {
(void)printf("\\\n");
count = 0;
}
- if (isascii(*s) && isprint(*s) && *s != '\\') {
+ if (isprint((unsigned char)*s) && *s != '\\') {
(void)putchar(*s);
count++;
} else {
@@ -502,7 +504,7 @@ regexec_e(preg, string, eflags, nomatch, slen)
size_t slen;
{
int eval;
-
+
if (preg == NULL) {
if (defpreg == NULL)
err(FATAL, "first RE may not be empty");
@@ -514,7 +516,7 @@ regexec_e(preg, string, eflags, nomatch, slen)
slen--;
match[0].rm_so = 0;
match[0].rm_eo = slen;
-
+
eval = regexec(defpreg, string,
nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
switch(eval) {
@@ -550,7 +552,7 @@ regsub(sp, string, src)
while ((c = *src++) != '\0') {
if (c == '&')
no = 0;
- else if (c == '\\' && isdigit(*src))
+ else if (c == '\\' && isdigit((unsigned char)*src))
no = *src++ - '0';
else
no = -1;
diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1
index 63bcd32..a28efdb 100644
--- a/usr.bin/sed/sed.1
+++ b/usr.bin/sed/sed.1
@@ -34,7 +34,7 @@
.\"
.\" @(#)sed.1 8.2 (Berkeley) 12/30/93
.\"
-.Dd "December 30, 1993"
+.Dd December 30, 1993
.Dt SED 1
.Os
.Sh NAME
@@ -273,7 +273,7 @@ whether by executing the
.Dq N
function or by beginning a new cycle.
.sp
-.It [2addr]b[lable]
+.It [2addr]b[label]
Branch to the
.Dq \&:
function with the specified label.
@@ -325,7 +325,7 @@ This form is as follows:
.sp
.Bl -tag -width "carriage-returnXX" -offset indent -compact
.It backslash
-\e
+\e\e
.It alert
\ea
.It form-feed
diff --git a/usr.bin/sgmlfmt/Makefile b/usr.bin/sgmlfmt/Makefile
new file mode 100644
index 0000000..12e52d5
--- /dev/null
+++ b/usr.bin/sgmlfmt/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+MAN1= sgmlfmt.1
+
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/sgmlfmt.pl ${DESTDIR}${BINDIR}/sgmlfmt
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sgmlfmt/sgmlfmt.1 b/usr.bin/sgmlfmt/sgmlfmt.1
new file mode 100644
index 0000000..9b9016e
--- /dev/null
+++ b/usr.bin/sgmlfmt/sgmlfmt.1
@@ -0,0 +1,172 @@
+.Dd May 9, 1997
+.Os FreeBSD 2.2
+.Dt SGMLFMT 1
+.Sh NAME
+.Nm sgmlfmt
+.Nd Formats linuxdoc and DocBook SGML documents.
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar doctype
+.Fl f Ar format
+.Op Fl i Ar name ...
+.Op Fl links
+.Op Fl e Ar encoding
+.Op Fl hdr Ar file
+.Op Fl ftr Ar file
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+command reads SGML files tagged according to the linuxdoc or
+DocBook DTD,
+validates them using the
+.Xr sgmls 1
+parser and then converts them to the specified output format.
+Linuxdoc input files must include the following document type
+declaration before any uncommented text:
+.Bd -literal -offset indent
+<!DOCTYPE linuxdoc PUBLIC "-//FreeBSD//DTD linuxdoc//EN">
+.Ed
+.Pp
+Options for
+.Nm
+include the following:
+.Bl -tag -width Ds
+.It Fl d Ar doctype
+Specifies the SGML document type of the source file. Currently
+supported document types are
+.Ar linuxdoc
+and
+.Ar docbook .
+If no
+.Fl d
+option is specified, the default is
+.Ar linuxdoc .
+.It Fl f Ar format
+Determines the output format which can be one of the following:
+.Bl -tag -width Ds
+.It Ar ascii
+Generates a single output file with the extension
+.Pa .ascii
+suitable for viewing on an ASCII terminal.
+.It Ar html
+Generates a set of linked HTML files suitable for use with an
+HTML browser. A top level file,
+.Pa file.html ,
+contains the title, author, date, abstract and brief table of
+contents for the document. A file
+.Pa file_toc.html
+contains a complete table of contents. A series of files named
+.Pa file1.html ,
+.Pa file2.html ...
+.Pa filen.html
+contain the actual text of the document.
+.It Ar koi8-r
+Generates a single output file with the extension
+.Pa .koi8-r
+suitable for viewing on an terminal supporting the KOI8-R
+character encoding.
+.It Ar latin1
+Generates a single output file with the extension
+.Pa .latin1
+suitable for viewing on an terminal supporting the ISO8859-1
+character encoding.
+.It Ar ps
+Generates a single output file with the extension
+.Pa .ps
+suitable for printing or display on a PostScript compatible device.
+.It Ar roff
+Generates a single output file with the extension
+.Pa .roff
+suitable processing with
+.Xr groff 1 .
+This is actually an intermediate conversion used by the
+.Fl f Ar ascii ,
+.Fl f Ar latin1 ,
+.Fl f Ar koi8-r ,
+and
+.Fl f Ar ps
+format options.
+.El
+.It Fl i Ar name
+Pretend that
+.Dl <!ENTITY % name "INCLUDE">
+occurs at the start of the document type declaration subset in
+the document entity. Since repeated definitions of an entity are
+ignored, this definition will take precedence over any other
+definitions of this entity in the document type declaration.
+Multiple
+.Fl i
+options are allowed. If the declaration replaces the reserved
+name INCLUDE then the new reserved name will be the replacement
+text of the entity. Typically the document type declaration will
+contain
+.Dl <!ENTITY % name "IGNORE">
+and will use
+.Li %name;
+in the status keyword specification of a
+marked section declaration. In this case the effect of the
+option will be to cause the marked section not to be ignored.
+.It Fl links
+When used with the
+.Fl f Ar html
+option, this option generates a shell script named
+.Pa file.ln .
+For each
+.Li <label id="foo">
+in the document source,
+.Pa file.ln
+generates a symbolic link
+.Pa foo.html
+pointing to the numbered
+.Pa .html
+file containing the reference. Since the number of the file
+containing a particular section can change when a document
+is modified, this provides a convenient hook by which separate
+documents can provide links into another document without the
+links becoming invalid when the target document is modified.
+When creating a symbolic link, any occurrence of a slash (/) in label
+is replaced with percent (%), while any occurrence of a space is replaced
+with an underscore (_).
+.It Fl e Ar encoding
+When used with the
+.Fl f Ar html
+option, specifies document encoding to use for the generated
+HTML files. If this option is not specified, iso-8859-1 is used.
+.It Fl hdr Ar file
+When used with the
+.Fl f Ar html
+option, the specified file will be inserted at the beginning of the
+body element of each generated HTML file.
+.It Fl ftr Ar file
+When used with the
+.Fl f Ar html
+option, the specified file will be inserted at the end of the
+body element of each generated HTML file.
+.El
+.Pp
+In all cases, the output files are created in the current working
+directory.
+.Sh FILES
+.Pa /usr/share/sgml/transpec
+- directory containing translation specification files for
+.Xr instant 1 .
+.Pp
+.Sh SEE ALSO
+.Xr groff 1 ,
+.Xr instant 1 ,
+.Xr sgmls 1 ,
+.Xr transpec 5
+.Sh HISTORY
+The
+.Nm
+command appeared in Version 2.0.5 FreeBSD UNIX.
+.Sh AUTHORS
+The
+.Nm
+command was written by John Fieber
+.Aq jfieber@FreeBSD.org .
+The linuxdoc DTD was written by Matt Welsh
+.Aq mdw@cs.cornell.edu
+and based on the Qwertz DTD written by Tom Gordon
+.Aq thomas.gordon@gmd.de .
diff --git a/usr.bin/sgmlfmt/sgmlfmt.pl b/usr.bin/sgmlfmt/sgmlfmt.pl
new file mode 100755
index 0000000..5f9ab85
--- /dev/null
+++ b/usr.bin/sgmlfmt/sgmlfmt.pl
@@ -0,0 +1,749 @@
+#!/usr/bin/perl
+
+# $Id: sgmlfmt.pl,v 1.25 1997/05/10 20:41:11 jfieber Exp $
+
+# Copyright (C) 1996
+# John R. Fieber. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY JOHN R. FIEBER AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL JOHN R. FIEBER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+
+# Format an sgml document tagged according to the linuxdoc DTD.
+# by John Fieber <jfieber@freebsd.org> for the FreeBSD documentation
+# project.
+
+
+require 'newgetopt.pl';
+
+#
+# The SGML parser, and translation engine.
+#
+
+$sgmls = "sgmls";
+$instant = "instant";
+
+#
+# Things to clean up if we exit abnormally
+#
+
+@cleanfiles = ();
+
+#
+# Interrupt handler, remove scratch files.
+#
+
+sub sighandler {
+ local($sig) = @_;
+ unlink @cleanfiles;
+ exit(1);
+}
+
+$SIG{'HUP'} = 'sighandler';
+$SIG{'INT'} = 'sighandler';
+$SIG{'QUIT'} = 'sighandler';
+
+#
+# Display a usage message.
+#
+
+sub usage {
+ print "Usage:\n";
+ print "sgmlfmt [-d <doctype>] -f <format> [-i <namea> ...] [-links]\n";
+ print " [-e encoding] [-hdr file] [-ftr file] file\n";
+ print "where <doctype> is one of: linuxdoc (default), docbook.\n";
+ print "and <format> is one of: ascii, html, koi8-r, latin1, ps, roff\n";
+}
+
+#
+# Look for the file specified on the command line
+#
+
+sub getfile {
+ local($filearg) = @_;
+ if (-f "$filearg.sgml") {
+ $file = "$filearg.sgml";
+ }
+ elsif (-f $filearg) {
+ $file = $filearg;
+ }
+ else {
+ return 0;
+ }
+ $fileroot = $file;
+ $fileroot =~ s/.*\///; # drop the path
+ $fileroot =~ s/\.[^\.]*$//; # drop the extension
+ $filepath = $file;
+ $filepath =~ s/\/*[^\/]*$//;
+ if ($filepath ne "") {
+ $ENV{"SGML_PATH"} .= ":$filepath/%S:%S";
+ }
+ return 1;
+}
+
+#
+# A function to run sgmls and instant on the input file.
+#
+# Arguments:
+# 1. A file handle for the output
+# 2. A translation file
+#
+
+sub sgmlparse {
+ local($ifhandle, $replacement) = @_;
+ $defines = join(" -i ", @opt_i);
+ if ($defines ne "") {
+ $defines = "-i $defines";
+ }
+ open($ifhandle, "$sgmls $defines $decl $file | " .
+ "$instant -Dfilename=$fileroot $instantopts -t ${dtd}-${replacement}.ts |");
+}
+
+#
+# Generate roff output
+#
+
+sub gen_roff {
+ @cleanfiles = (@cleanfiles, "${fileroot}.roff");
+ open (outfile, ">$fileroot.roff");
+ &sgmlparse(infile, "roff");
+ while (<infile>) {
+ print outfile;
+ }
+ close(infile);
+ close(outfile);
+}
+
+#
+# Generate something from roff output
+#
+
+sub do_groff {
+ local($driver, $postproc) = @_;
+ @cleanfiles = (@cleanfiles, "${fileroot}.trf", "${fileroot}.tmp",
+ "${fileroot}.qrf", "${fileroot}.${driver}");
+ open (outfile, ">$fileroot.trf");
+ &sgmlparse(infile, "roff");
+ while (<infile>) {
+ print outfile;
+ }
+ close(infile);
+ close(outfile);
+ system("groff -T ${driver} -t ${fileroot}.trf ${postproc} > ${fileroot}.${driver}");
+
+ # If foo.tmp has been created, then there are cross references
+ # in the file and we need a second pass to resolve them correctly.
+
+ if (stat("${fileroot}.tmp")) {
+ system("groff -T ${driver} -t ${fileroot}.trf ${postproc} > ${fileroot}.${driver}");
+ unlink("${fileroot}.qrf");
+ }
+ unlink("${fileroot}.trf");
+}
+
+#
+# Generate HTML output.
+#
+# HTML is generated in two passes.
+#
+# The first pass takes the output from sgmlsasp and gathers information
+# about the structure of the document that is used in the sceond pass
+# for splitting the file into separate files. Targets for cross
+# references are also stored in this pass.
+#
+# Based on the information from the first pass, the second pass
+# generates a numbered series of HTML files, a "toplevel" file
+# containing the title, author, abstract and a brief table of
+# contents. A detailed table of contents is also generated. The
+# second pass generates links for cross references and URLs.
+
+#
+# Tunable parameters
+#
+$maxlevel = 3; # max section depth
+$num_depth = 4; # depth of numbering
+$m_depth = 2; # depth of menus
+
+
+$sc = 0; # section counter
+$filecount = 0; # file counter
+
+$doctype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">";
+$BODY = "<BODY text=\"#000000\" bgcolor=\"#ffffff\">";
+
+# Other variables:
+#
+# st_xxxx - Section Table. Arrays containing information about a
+# given section. To be accesssed via the section counter $sc.
+#
+# st_ol - The output level of the given section. I.E. how many
+# levels from the table of contents does it lie in terms
+# of HTML files which is distinct from <sect1>, <sect2> etc.
+# levels.
+#
+# st_sl - The absolute depth of a section. Contrast st_ol.
+#
+# st_num - The section number in the form X.Y.Z....
+#
+# st_file - The HTML file the section belongs to.
+#
+# st_header - The text of the section title.
+#
+# st_parent - The section number of the given sections parent.
+
+sub gen_html {
+ local($i, $sl);
+
+ # Remove any lingering link file
+ unlink("${fileroot}.ln");
+
+ $tmpfile = "/tmp/sgmlf.$$";
+ @cleanfiles = (@cleanfiles, "$tmpfile", "${fileroot}.html",
+ "${fileroot}_toc.html", "${fileroot}.ln");
+ open(bar, ">$tmpfile");
+# print STDERR "(Pass 1...";
+ &sgmlparse(foo, "html");
+ while (<foo>) {
+ print bar;
+ # count up the number of files to be generated
+ # and gather assorted info about the document structure
+ if (/^<\@\@sect>/) {
+ $sl++; # current section level
+ $sc++; # current section number
+ $st_sl[$sc] = $sl;
+
+ # In case this section has subsections, set the parent
+ # pointer for this level to point at this section.
+ $parent_pointer[$sl] = $sc;
+
+ # Figure out who is the parent if this section.
+ $st_parent[$sc] = $parent_pointer[$sl - 1];
+
+ # Per level counters
+ $counter[$sl]++;
+ $counter[$sl + 1] = 0;
+
+ # calculate the section number in the form x.y.z.
+ if ($sl <= $num_depth) {
+ $st_num[$sc] = $st_num[$st_parent[$sc]] . "$counter[$sl].";
+ }
+
+ # calculate the file number and output level
+ if ($sl <= $maxlevel) {
+ $filecount++;
+ $st_ol[$sc] = $sl;
+ @cleanfiles = (@cleanfiles, "${fileroot}${filecount}.html");
+ }
+ else {
+ $st_ol[$sc] = $maxlevel;
+ }
+
+ $st_file[$sc] = $filecount;
+
+ # Calculate the highest level node in which this
+ # node should appear as a menu item.
+ $st_pl[$sc] = $sl - $m_depth;
+ if ($st_pl[$sc] < 0) {
+ $st_pl[$sc] = 0;
+ }
+ if ($st_pl[$sc] > $maxlevel) {
+ $st_pl[$sc] = $maxlevel;
+ }
+ }
+ if (/^<\@\@endsect>/) {
+ $sl--;
+ }
+
+ # record section titles
+ if (/^<\@\@head>/) {
+ chop;
+ s/^<\@\@head>//;
+ $st_header[$sc] = $_;
+ }
+
+ # record the section number that a label occurs in
+ if (/^<\@\@label>/) {
+ chop;
+ s/^<\@\@label>//;
+ if ($references{$_} eq "") {
+ $references{$_} = "$filecount";
+ if ($opt_links) {
+ &extlink($_, "${fileroot}${filecount}.html");
+ }
+ }
+ else {
+ print STDERR "Warning: the label `$_' is multiply-defined.\n";
+ }
+ }
+ }
+ close(bar);
+
+ open(foofile, $tmpfile);
+ &html2html(foofile, "boo");
+
+ unlink($tmpfile);
+}
+
+#
+# HTML conversion, pass number 2
+#
+
+sub html2html {
+ local($infile, $outfile) = @_;
+ local($i);
+
+ $sc = 0;
+ push(@scs, $sc);
+
+ open(tocfile, ">${fileroot}_toc.html");
+ print tocfile "$doctype\n<HTML>\n";
+
+ while (<$infile>) {
+ # change `<' and `>' to `&lt;' and `&gt;' in <pre></pre>
+ if (/<pre>/.../<\/pre>/) {
+ s/</\&lt;/g;
+ s/\&lt;([\/]*)pre>/<\1pre>/g;
+ s/>/\&gt;/g;
+ s/<([\/]*)pre\&gt;/<\1pre>/g;
+ }
+
+ # remove extraneous empty paragraphs (it is arguable that this
+ # is really a bug with the DTD, but changing it would break
+ # almost every document written to this DTD.)
+ s/<p><\/p>//;
+
+ tagsw: {
+ # titles and headings
+ if (s/^<\@\@title>//) {
+ chop;
+ $st_header[0] = $_;
+ $st_parent[0] = -1;
+ $t = $st_header[0];
+ $t =~ s|<[a-zA-Z/][^>]*>||g;
+ print tocfile "<HEAD>\n$html_encoding\n<TITLE>$t</TITLE>\n" .
+ "</HEAD>\n";
+ print tocfile "<H1>$st_header[0]</H1>\n";
+
+ $header[$st_ol[$sc]] =
+ "$doctype\n<HTML>\n<HEAD>\n$html_encoding\n<TITLE>$t</TITLE>\n" .
+ "</HEAD>\n$BODY\n";
+ $header[$st_ol[$sc]] .= $html_header;
+ $header[$st_ol[$sc]] .= "\n<H1>$st_header[0]</H1>\n";
+
+ $footer[$st_ol[$sc]] = "\n";
+ $footer[$st_ol[$sc]] .= $html_footer;
+ $footer[$st_ol[$sc]] .= "\n</BODY>\n</HTML>\n";
+ last tagsw;
+ }
+
+ #
+ # HEADER begin
+ #
+ if (s/^<\@\@head>//) {
+ chop;
+
+ if ($part == 1) {
+ $text[0] .= "<H1>Part $partnum:<BR>$_";
+ last tagsw;
+ }
+
+ $href = "\"${fileroot}$st_file[$sc].html#$sc\"";
+
+ # set up headers and footers
+ if ($st_sl[$sc] > 0 && $st_sl[$sc] <= $maxlevel) {
+ $t = $_;
+ $t =~ s|<[a-zA-Z/][^>]*>||g;
+ $header[$st_ol[$sc]] =
+ "$doctype\n<HTML>\n<HEAD>\n$html_encoding\n<TITLE>$t</TITLE>\n" .
+ "</HEAD>\n$BODY\n";
+ $header[$st_ol[$sc]] .= $html_header;
+ $header[$st_ol[$sc]] .= "\n$navbar[$st_ol[$sc]]\n<HR NOSHADE>\n";
+ $footer[$st_ol[$sc]] = "<HR NOSHADE>\n$navbar[$st_ol[$sc]]\n";
+ $footer[$st_ol[$sc]] .= $html_footer;
+ $footer[$st_ol[$sc]] .= "\n</BODY>\n</HTML>\n";
+ }
+
+ # Add this to the master table of contents
+ print tocfile "<DD>$st_num[$sc] " .
+ "<A HREF=$href>$_";
+
+ # Calculate the <H?> level to use in the HTML file
+ $hlevel = $st_sl[$sc] - $st_ol[$sc] + 2;
+ $shlevel = $st_sl[$sc] - $st_ol[$sc] + 3;
+
+ $i = $st_ol[$sc];
+
+ # Add the section header
+ $text[$i] .= "<H$hlevel><A NAME=\"$sc\"></A>$st_num[$sc] $_";
+ $i--;
+
+ # And also to the parent
+ if ($st_sl[$sc] == $st_ol[$sc] && $i >= 0) {
+ $text[$i] .= "<H$shlevel>$st_num[$sc] " .
+ "<A HREF=$href>$_";
+ $i--;
+ }
+
+ # and to the grandparents
+ for (; $i >= $st_pl[$sc]; $i--) {
+ $text[$i] .= "<DD>$st_num[$sc] " .
+ "<A HREF=$href>$_";
+ }
+
+ last tagsw;
+ }
+
+ #
+ # HEADER end
+ #
+ if (s/^<\@\@endhead>//) {
+ if ($part == 1) {
+ $text[0] .= "</H1>\n";
+ $part = 0;
+ last tagsw;
+ }
+ print tocfile "</A>\n";
+
+ $i = $st_ol[$sc];
+
+ # Close the section header
+ $text[$i] .= "</H$hlevel>\n";
+ $i--;
+
+ # in the parent...
+ if ($st_sl[$sc] == $st_ol[$sc] && $i >= 0) {
+ $text[$i] .= "</A></H$shlevel>\n";
+ $i--;
+ }
+
+ # in the grandparent...
+ for (; $i >= $st_pl[$sc]; $i--) {
+ $text[$i] .= "</A></DD>\n";
+ }
+ last tagsw;
+ }
+
+ # sectioning
+ if (s/^<\@\@part>//) {
+ $part = 1;
+ $partnum++;
+ last tagsw;
+ }
+
+ #
+ # BEGINNING of a section
+ #
+ if (s/^<\@\@sect>//) {
+ # Increment the section counter and save it on a stack
+ # for future reference.
+ $sc++;
+ push(@scs, $sc);
+
+ # Set up the navigation bar
+ if ($st_file[$sc] > $st_file[$sc - 1]) {
+ &navbar($st_file[$sc], $filecount, $sc);
+ }
+
+ # Prepare for menu entries in the table of contents and
+ # parent file(s).
+ if ($st_sl[$sc - 1] < $st_sl[$sc]) {
+ print tocfile "<DL>\n";
+ $i = $st_ol[$sc] - 1 - ($st_sl[$sc] == $st_ol[$sc]);
+ for (; $i >= $st_pl[$sc]; $i--) {
+ $text[$i] .= "<DL>\n";
+ }
+ }
+ last tagsw;
+ }
+
+ #
+ # END of a section
+ #
+ if (s/^<\@\@endsect>//) {
+
+ # Remember the section number! Subsections may have
+ # altered the global $sc variable.
+ local ($lsc) = pop(@scs);
+
+ # Close off subsection menus we may have created in
+ # parent file(s).
+ if ($st_sl[$lsc] > $st_sl[$sc + 1]) {
+ print tocfile "</DL>\n";
+ if ($st_sl[$lsc] > 1) {
+ print tocfile "</DD>\n";
+ }
+ $i = $st_ol[$lsc] - 1 - ($st_sl[$lsc] == $st_ol[$lsc]);
+ for (; $i >= $st_pl[$lsc]; $i--) {
+ $text[$i] .= "</DL>\n";
+ }
+ }
+
+ # If this section is below $maxlevel, write it now.
+ if ($st_sl[$lsc] <= $maxlevel) {
+ open(SECOUT, ">${fileroot}$st_file[$lsc].html");
+ print SECOUT "$header[$st_ol[$lsc]] $text[$st_ol[$lsc]] " .
+ "$footer[$st_ol[$lsc]]";
+ $text[$st_ol[$lsc]] = "";
+ close(SECOUT);
+ }
+ last tagsw;
+ }
+
+ # cross references
+ if (s/^<\@\@label>//) {
+ chop;
+ $text[$st_ol[$sc]] .= "<A NAME=\"$_\"></A>";
+ last tagsw;
+ }
+ if (s/^<\@\@ref>//) {
+ chop;
+ $refname = $_;
+ if ($references{$_} eq "") {
+ print "Warning: Reference to $_ has no defined target\n";
+ }
+ else {
+ $text[$st_ol[$sc]] .=
+ "<A HREF=\"${fileroot}$references{$_}.html#$_\">";
+ }
+ last tagsw;
+ }
+ if (s/^<\@\@endref>//) {
+ $text[$st_ol[$sc]] .= "</A>";
+ last tagsw;
+ }
+ if (s/^<\@\@refnam>//) {
+ $text[$st_ol[$sc]] .= "$refname";
+ last tagsw;
+ }
+
+ # If nothing else did anything with this line, just print it.
+ $text[$st_ol[$sc]] .= "$_";
+ }
+ }
+
+ print tocfile "</HTML>\n";
+ open(SECOUT, ">$fileroot.html");
+ print SECOUT "$header[0] $text[0] $footer[0]";
+ close(SECOUT);
+ close tocfile;
+}
+
+# navbar
+#
+# Generate a navigation bar to go on the top and bottom of the page.
+
+sub navbar {
+ local ($fnum, $fmax, $sc) = @_;
+ local ($i, $itext, $prv, $nxt, $colon);
+
+ $colon = "<b>:</b>";
+
+ # Generate the section hierarchy
+
+ $navbar[$st_ol[$sc]] =
+ "<A HREF=\"${fileroot}.html\"><EM>$st_header[0]</EM></A>\n";
+ $i = $st_parent[$sc];
+ while ($i > 0) {
+ $itext = " $colon <A HREF=\"${fileroot}$st_file[$i].html\"><EM>$st_header[$i]</EM></A>\n$itext";
+ $i = $st_parent[$i];
+ }
+ $navbar[$st_ol[$sc]] .= "$itext $colon <EM>$st_header[$sc]</EM><BR>\n";
+
+ # Generate previous and next pointers
+
+ # Previous pointer must be in a different file AND must be at the
+ # same or higher section level. If the current node is the
+ # beginning of a chapter, then previous will go to the beginning
+ # of the previous chapter, not the end of the previous chapter.
+
+ $prv = $sc;
+ while ($prv >= 0 && $st_file[$prv] >= $st_file[$sc] - 1) {
+ $prv--;
+ }
+ $prv++;
+ $navbar[$st_ol[$sc]] .=
+ "<b>Previous:</b> <A HREF=\"${fileroot}$st_file[$prv].html\"><EM>$st_header[$prv]</EM></A><BR>\n";
+
+ # Then next pointer must be in a higher numbered file OR the home
+ # page of the document.
+
+ $nxt = $sc;
+ if ($st_file[$nxt] == $filecount) {
+ $nxt = 0;
+ }
+ else {
+ while ($st_file[$nxt] == $st_file[$sc]) {
+ $nxt++;
+ }
+ }
+
+ $navbar[$st_ol[$sc]] .=
+ "<b>Next:</b> <A HREF=\"${fileroot}$st_file[$nxt].html\"><EM>$st_header[$nxt]</EM></A>\n";
+
+ $navbar[$st_ol[$sc]] .= "\n";
+
+}
+
+#
+# Generate html output from docbook input
+#
+
+sub docbook_html {
+ @cleanfiles = (@cleanfiles, "${fileroot}.html");
+ open (outfile, ">$fileroot.html");
+ &sgmlparse(infile, "html");
+ while (<infile>) {
+ print outfile;
+ }
+ close(infile);
+ close(outfile);
+}
+
+# extlink
+#
+# Build a shell script to create symbolic links from the name in
+# a reference to the numbered
+# html file. Since the file number that any given section has is
+# subject to change as the document goes through revisions, this allows
+# for a fixed target that separate documents can hook into.
+#
+# Slashes (/) in the reference are converted to percents (%) while
+# spaces ( ) are converted to underscores (_);
+
+sub extlink {
+ local ($ref, $fn) = @_;
+
+ $ref =~ s/\//%/g;
+ $ref =~ s/ /_/g;
+
+ $file = "$ref.html";
+
+ if (!fileno(LINKFILE)) {
+ open(LINKFILE, ">${fileroot}.ln");
+ }
+
+ print LINKFILE "ln -fs $fn $file\n";
+}
+
+# Now, read the command line and take appropriate action
+
+sub main {
+ # Check arguments
+ if (!&NGetOpt('d=s', 'f=s', 'links', 'i:s@', 'hdr=s', 'ftr=s', 'e=s')) {
+ &usage;
+ exit 1;
+ }
+ if (@ARGV == 0) {
+ print "An input file must be specified.\n";
+ &usage;
+ exit 1;
+ }
+ if (&getfile($ARGV[0]) == 0) {
+ print "Cannot locate specified file: $ARGV[0]\n";
+ &usage;
+ exit 1;
+ }
+
+ # Figure out which DTD we are using
+ if ($opt_d eq "docbook") {
+ $dtd = "docbook";
+ $decl = "/usr/share/sgml/docbook/docbook.dcl";
+ }
+ else {
+ $dtd = "linuxdoc";
+ $decl = "/usr/share/sgml/FreeBSD/linuxdoc.dcl";
+ }
+
+ # Generate the output
+ if ($opt_f eq 'html') {
+ # Set the character encoding
+ if (! $opt_e) {
+ $opt_e = "iso-8859-1";
+ }
+ $html_encoding = "<META HTTP-EQUIV=\"Content-Type\" " .
+ "CONTENT=\"text/html; charset=" . $opt_e . "\">";
+
+ if ($dtd eq "docbook") {
+ if ($opt_hdr) {$instantopts .= " -D \"inchdr=${opt_hdr}\"";}
+ if ($opt_ftr) {$instantopts .= " -D \"incftr=${opt_ftr}\"";}
+ &docbook_html();
+ }
+ else {
+ if ($opt_hdr) {$html_header = &gethf($opt_hdr);}
+ if ($opt_ftr) {$html_footer = &gethf($opt_ftr);}
+ &gen_html();
+ }
+ }
+ elsif ($opt_f eq 'roff') {
+ &gen_roff();
+ }
+ elsif ($opt_f eq 'ascii') {
+ &do_groff("ascii", "| col");
+ }
+ elsif ($opt_f eq 'latin1') {
+ &do_groff("latin1", "| col");
+ }
+ elsif ($opt_f eq 'koi8-r') {
+ &do_groff("koi8-r", "| col");
+ }
+ elsif ($opt_f eq 'ps') {
+ &do_groff("ps", "");
+ }
+ else {
+ if ($opt_f eq "") {
+ print "An output format must be specified with the -f
+ option.\n";
+ }
+ else {
+ print "\"$opt_f\" is an unknown output format.\n";
+ }
+ &usage;
+ exit 1;
+ }
+}
+
+&main;
+
+exit 0;
+
+sub getdate {
+ @months = ("January", "February", "March", "April", "May","June",
+ "July", "August", "September", "October", "November", "December");
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+ $year += 1900;
+ return "$months[$mon] $mday, $year";
+}
+
+sub gethf {
+ local ($file) = @_;
+
+ $date = &getdate;
+ $data = "";
+
+ if (open(IN, $file)) {
+ while (<IN>) {
+ s/\@\@UPDATE\@\@/Updated $date/;
+ $data .= $_;
+ }
+ close(IN);
+ }
+ return $data;
+}
diff --git a/usr.bin/sgmls/LICENSE b/usr.bin/sgmls/LICENSE
new file mode 100644
index 0000000..576ca35
--- /dev/null
+++ b/usr.bin/sgmls/LICENSE
@@ -0,0 +1,43 @@
+ LICENSE AND DISCLAIMER OF WARRANTIES
+
+ Standard Generalized Markup Language Users' Group (SGMLUG)
+ SGML Parser Materials
+
+ 1. License
+
+SGMLUG hereby grants to any user: (1) an irrevocable royalty-free,
+worldwide, non-exclusive license to use, execute, reproduce, display,
+perform and distribute copies of, and to prepare derivative works
+based upon these materials; and (2) the right to authorize others to
+do any of the foregoing.
+
+ 2. Disclaimer of Warranties
+
+(a) The SGML Parser Materials are provided "as is" to any USER. USER
+assumes responsibility for determining the suitability of the SGML
+Parser Materials for its use and for results obtained. SGMLUG makes
+no warranty that any errors have been eliminated from the SGML Parser
+Materials or that they can be eliminated by USER. SGMLUG shall not
+provide any support maintenance or other aid to USER or its licensees
+with respect to SGML Parser Materials. SGMLUG shall not be
+responsible for losses of any kind resulting from use of the SGML
+Parser Materials including (without limitation) any liability for
+business expense, machine downtime, or damages caused to USER or third
+parties by any deficiency, defect, error, or malfunction.
+
+(b) SGMLUG DISCLAIMS ALL WARRANTIES, EXPRESSED OR IMPLIED, ARISING OUT
+OF OR RELATING TO THE SGML PARSER MATERIALS OR ANY USE THEREOF,
+INCLUDING (WITHOUT LIMITATION) ANY WARRANTY WHATSOEVER AS TO THE
+FITNESS FOR A PARTICULAR USE OR THE MERCHANTABILITY OF THE SGML PARSER
+MATERIALS.
+
+(c) In no event shall SGMLUG be liable to USER or third parties
+licensed by USER for any indirect, special, incidental, or
+consequential damages (including lost profits).
+(d) SGMLUG has no knowledge of any conditions that would impair its right
+to license the SGML Parser Materials. Notwithstanding the foregoing,
+SGMLUG does not make any warranties or representations that the
+SGML Parser Materials are free of claims by third parties of patent,
+copyright infringement or the like, nor does SGMLUG assume any
+liability in respect of any such infringement of rights of third
+parties due to USER's operation under this license.
diff --git a/usr.bin/sgmls/Makefile b/usr.bin/sgmls/Makefile
new file mode 100644
index 0000000..96ce820
--- /dev/null
+++ b/usr.bin/sgmls/Makefile
@@ -0,0 +1,9 @@
+#
+# Bmake file for sgmls
+# $Id$
+#
+
+SUBDIR= libsgmls sgmls instant
+
+.include <bsd.subdir.mk>
+
diff --git a/usr.bin/sgmls/Makefile.inc b/usr.bin/sgmls/Makefile.inc
new file mode 100644
index 0000000..7a78864
--- /dev/null
+++ b/usr.bin/sgmls/Makefile.inc
@@ -0,0 +1,16 @@
+#
+# Bmakefile for rast
+#
+# $Id$
+#
+
+.if exists(${.CURDIR}/../../Makefile.inc)
+.include "${.CURDIR}/../../Makefile.inc"
+.endif
+
+.if exists(${.OBJDIR}/../libsgmls)
+LIBSGMLS= ${.OBJDIR}/../libsgmls/libsgmls.a
+.else
+LIBSGMLS= ${.CURDIR}/../libsgmls/libsgmls.a
+.endif
+
diff --git a/usr.bin/sgmls/README b/usr.bin/sgmls/README
new file mode 100644
index 0000000..e2a8204
--- /dev/null
+++ b/usr.bin/sgmls/README
@@ -0,0 +1,138 @@
+$Id$
+
+This the sgmls release 1.1 SGML parser written by James Clark
+jjc@jclark.com, repackaged for FreeBSD. The original source may be
+obtained from ftp://ftp.jclark.com/.
+
+Pieces removed include:
+ * Test documents: Compiled on FreeBSD, sgmls passes all tests.
+ * sgml-mode.el: The sole file covered by the GNU GPL. This is not
+ installed anyway and anyone wishing to do serious SGML editing
+ would be best to get the psgml package.
+ * Makefiles and config files for other operating systems (vms, dos,
+ cms).
+ * Formatted versions of the man pages.
+
+
+20-Apr-1995 John Fieber <jfieber@freebsd.org>
+
+
+The original README and TODO follow.
+----------------------------------------------------------------------
+This is sgmls, an SGML parser derived from the ARCSGML parser
+materials which were written by Charles F. Goldfarb. (These are
+available for anonymous ftp from ftp.ifi.uio.no [128.240.88.1] in the
+directory SIGhyper/SGMLUG/distrib.)
+
+The version number is given in the file version.c.
+
+The file INSTALL contains installation instructions.
+
+The file NEWS describes recent user-visible changes.
+
+The file sgmls.man contains a Unix manual page; sgmls.txt is the
+formatted version of this.
+
+The file sgml-mode.el contains a very simple SGML mode for GNU Emacs.
+
+The files sgmls.c and sgmls.h contain a small library for parsing the
+output of sgmls. This is used by sgmlsasp, which translates the
+output of sgmls using an ASP replacement file, and by rast, which
+translates the output of sgmls to the format of a RAST result. The
+files sgmlsasp.man and rast.man contain Unix manual pages for sgmlsasp
+and rast; sgmlsasp.txt and rast.txt are the formatted versions of
+these.
+
+The file LICENSE contains the license which applies to arcsgml and
+accordingly to those parts of sgmls derived from arcsgml. See also
+the copyright notice at the beginning of sgmlxtrn.c. The parts that
+were written by me are in the public domain (any files that were
+written entirely by me contain a comment to that effect.) The file
+sgml-mode.el is covered by the GNU GPL.
+
+Please report any bugs to me. When reporting bugs, please include the
+version number, details of your machine, OS and compiler, and a
+complete self-contained file that will allow me to reproduce the bug.
+
+James Clark
+jjc@jclark.com
+
+----------------------------------------------------------------------
+Warn about mixed content models where #PCDATA can't occur everywhere.
+
+Perhaps there should be a configuration option saying what a control
+character is for the purpose of SHUNCHAR CONTROLS.
+
+Should the current character that is printed in error messages be
+taken from be taken from the file entity or the current entity?
+
+Refine SYS_ action. If we distinguish DELNONCH in lexmark, lexgrp,
+lexsd, we can have separate action that ignores the following
+character as well.
+
+Should RSs in CDATA/SDATA entities be ignored as specified in 322:1-2?
+Similarily, do the rules on REs in 322:3-11 apply to CDATA/SDATA
+entities? (I don't think they count as being `in content'.)
+
+What should the entity manager do when it encounters code 13 in an
+input file? (Currently it treats it as an RE.)
+
+Document when invalid exclusions are detected.
+
+Option not to perform capacity checking.
+
+Give a warning if the recommendation of 422:1-3 is contravened.
+
+Should an empty CDATA/RCDATA marked section be allowed in the document
+type declaration subset?
+
+Include example of use of SGML_PATH in documentation.
+
+Try to detect the situation in 310:8-10 (but see 282:1-2).
+
+Resize hash tables if they become too full.
+
+Say something in the man page about message catalogues.
+
+Consider whether support for SHORTREF NONE requires further changes
+(other than disallowing short reference mapping declaration).
+
+Fake /dev/fd/N and /dev/stdin for systems that don't provide it.
+
+Improve the effficiency of the entity manager by not closing and
+reopening files. If we run out of FILEs choose the stream with the
+fewest bytes remaining to be read, and read the rest of it into
+memory. Each entity level will have its own read buffer.
+
+Support multi-line error messages: automatically indent after
+newline. (We could output to a temporary file first, then copy to
+stderr replacing newlines by newline+indent).
+
+Option that says to output out of context things.
+
+Divide up formal public identifier errors. Give these errors their
+own type code.
+
+Consider whether, when OMITTAG is NO, we need to change interpretation
+of an empty start-tag (7.4.1.1).
+
+Possibly turn errors 70 and 136 into warnings.
+
+Make things work with NORMSEP > 2. Would need to keep track of number
+of CDATA and SDATA entities in CDATA attributes.
+
+Handle `SCOPE INSTANCE'.
+
+In entgen.c, truncate filenames for OSs that don't do this themselves.
+
+Provide an option that specifies that maximum number of errors; when
+this limit is exceeded sgmls would exit.
+
+Document non-portable assumptions in the code.
+
+Option to write out SGML declaration. In this case make it write out
+APPINFO parameter.
+
+Allow there to be catalogs mapping public ids to filenames.
+Environment variable SGML_CATALOG containing list of filenames of
+catalogs.
diff --git a/usr.bin/sgmls/configure b/usr.bin/sgmls/configure
new file mode 100755
index 0000000..7fd1968
--- /dev/null
+++ b/usr.bin/sgmls/configure
@@ -0,0 +1,617 @@
+#!/bin/sh
+# Generate config.h from unix.cfg.
+
+trap 'rm -f doit doit.c doit.o doit.log config.out; exit 1' 1 2 3 15
+
+on=
+off=
+CC=${CC-cc}
+
+# Normally we use VARARGS if __STDC__ is not defined.
+# Test whether this assumption is wrong.
+
+cat >doit.c <<\EOF
+#ifdef __STDC__
+#include <stdarg.h>
+int foo(char *s,...)
+{
+ va_list ap;
+
+ va_start(ap, s);
+ va_end(ap);
+ return 0;
+}
+#else
+int foo = 0;
+#endif
+EOF
+
+$CC $CFLAGS -c doit.c >/dev/null 2>&1
+if test $? -ne 0
+then
+ on="$on VARARGS"
+fi
+
+cat >doit.c <<\EOF
+#include <stddef.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ off="$off STDDEF_H_MISSING"
+else
+ on="$on STDDEF_H_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <stdlib.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ off="$off STDLIB_H_MISSING"
+else
+ on="$on STDLIB_H_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <limits.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ off="$off LIMITS_H_MISSING"
+else
+ on="$on LIMITS_H_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <vfork.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ on="$on HAVE_VFORK_H"
+else
+ off="$off HAVE_VFORK_H"
+fi
+
+cat >doit.c <<\EOF
+#include <unistd.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ on="$on HAVE_UNISTD_H"
+else
+ off="$off HAVE_UNISTD_H"
+fi
+
+cat >doit.c <<\EOF
+#include <sys/types.h>
+#include <sys/stat.h>
+int foo = 0;
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ on="$on HAVE_SYS_STAT_H"
+else
+ off="$off HAVE_SYS_STAT_H"
+fi
+
+cat >doit.c <<\EOF
+/* Exit normally unless we need to use isascii. */
+
+#include <ctype.h>
+#include <signal.h>
+
+static int whoops()
+{
+ _exit(1);
+}
+
+main()
+{
+ int c;
+#ifdef isascii
+#ifdef SIGSEGV
+ signal(SIGSEGV, whoops);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS, whoops);
+#endif
+#ifdef SIGIOT
+ signal(SIGIOT, whoops);
+#endif
+
+ for (c = 128; c < 256; c++) {
+ if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5'
+ || c == '6' || c == '7' || c == '8' || c == '9') {
+ if (!isdigit(c) || isalpha(c) || iscntrl(c) || isspace(c) || ispunct(c))
+ exit(1);
+ }
+ else if (isdigit(c))
+ exit(1);
+ else if (isalpha(c)) {
+ if (iscntrl(c) || isspace(c) || ispunct(c)
+ || (islower(c) && toupper(c) != c && !isupper(toupper(c)))
+ || (isupper(c) && tolower(c) != c && !islower(tolower(c))))
+ exit(1);
+ }
+ else if (islower(c) || isupper(c))
+ exit(1);
+ else if (iscntrl(c)) {
+ if (ispunct(c))
+ exit(1);
+ }
+ }
+#endif /* isascii */
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ # This tries to find the symbol that looks like the array
+ # used by <ctype.h>, and sees if its length appears to be 128
+ # rather than 256.
+ if test 1 = `(nm -n doit 2>/dev/null) | awk '
+BEGIN {
+ weight["0"] = 0;
+ weight["1"] = 1;
+ weight["2"] = 2;
+ weight["3"] = 3;
+ weight["4"] = 4;
+ weight["5"] = 5;
+ weight["6"] = 6;
+ weight["7"] = 7;
+ weight["8"] = 8;
+ weight["9"] = 9;
+ weight["a"] = weight["A"] = 10;
+ weight["b"] = weight["B"] = 11;
+ weight["c"] = weight["C"] = 12;
+ weight["d"] = weight["D"] = 13;
+ weight["e"] = weight["E"] = 14;
+ weight["f"] = weight["F"] = 15;
+}
+
+/^[0-9a-zA-Z]* D .*ctype/ && ctype_nr == 0 {
+ ctype_nr = NR;
+ addr = 0;
+ len = length($1);
+ for (i = 1; i <= len; i++)
+ addr = addr*16 + weight[substr($1, i, 1)];
+}
+
+/^[0-9a-zA-Z]* D / && NR == ctype_nr + 1 {
+ next_addr = 0;
+ len = length($1);
+ for (i = 1; i <= len; i++)
+ next_addr = next_addr*16 + weight[substr($1, i, 1)];
+}
+
+END {
+ size = next_addr - addr;
+ if (size >= 128 && size < 256)
+ print "1";
+ else
+ print "0";
+}'`
+ then
+ on="$on USE_ISASCII"
+ else
+ if ((yes | man 3 ctype) 2>/dev/null) \
+ | sed -e 's/.//g' -e 's/ *$//' -e '/de-$/N' \
+ -e 's/-\n//g' -e '/defined$/N' -e '/only$/N' \
+ -e '/where$/N' -e '/isascii$/N' -e '/is$/N' \
+ -e 's/\n/ /g' -e 's/ */ /g' \
+ | grep "defined only where isascii is true" >/dev/null
+ then
+ on="$on USE_ISASCII"
+ else
+ off="$off USE_ISASCII"
+ fi
+ fi
+else
+ on="$on USE_ISASCII"
+fi
+
+cat >doit.c <<\EOF
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ remove("foo");
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ off="$off REMOVE_MISSING"
+else
+ on="$on REMOVE_MISSING"
+fi
+
+cat >doit.c <<\EOF
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ getopt(argc, argv, "v");
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_GETOPT"
+else
+ off="$off HAVE_GETOPT"
+fi
+
+cat >doit.c <<\EOF
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ access("foo", 4);
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_ACCESS"
+else
+ off="$off HAVE_ACCESS"
+fi
+
+cat >doit.c <<\EOF
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ vfork();
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_VFORK"
+else
+ off="$off HAVE_VFORK"
+fi
+
+cat >doit.c <<\EOF
+main(argc, argv)
+int argc;
+char **argv;
+{
+
+ if (argc == 0) {
+ int status;
+ waitpid(-1, &status, 0);
+ }
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_WAITPID"
+else
+ off="$off HAVE_WAITPID"
+fi
+
+cat >doit.c <<\EOF
+#include <string.h>
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ strerror(0);
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ off="$off STRERROR_MISSING"
+else
+ on="$on STRERROR_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <strings.h>
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ bcopy((char *)0, (char *)0, 0);
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ # Only use BSD_STRINGS if ANSI string functions don't work.
+ cat >doit.c <<\EOF
+#include <string.h>
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ memcpy((char *)0, (char *)0, 0);
+ exit(0);
+}
+EOF
+
+ if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+ then
+ off="$off BSD_STRINGS"
+ else
+ on="$on BSD_STRINGS"
+ fi
+else
+ off="$off BSD_STRINGS"
+fi
+
+cat >doit.c <<\EOF
+#include <signal.h>
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0)
+ raise(SIGINT);
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ off="$off RAISE_MISSING"
+else
+ on="$on RAISE_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <stdio.h>
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0) {
+ fpos_t pos;
+ fsetpos(stdin, &pos);
+ fgetpos(stdin, &pos);
+ }
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ off="$off FPOS_MISSING"
+else
+ on="$on FPOS_MISSING"
+fi
+
+cat >doit.c <<\EOF
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0) {
+ pid_t pid;
+ int status;
+ long n = sysconf(_SC_OPEN_MAX);
+ pid = waitpid(-1, &status, 0);
+ WIFSTOPPED(status);
+ WIFSIGNALED(status);
+ WIFEXITED(status);
+ WEXITSTATUS(status);
+ WTERMSIG(status);
+ WSTOPSIG(status);
+ }
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on POSIX"
+else
+ off="$off POSIX"
+fi
+
+cat >doit.c <<\EOF
+#include <stdio.h>
+#include <signal.h>
+
+static int whoops()
+{
+ _exit(1);
+}
+
+main()
+{
+ char buf[30];
+#ifdef SIGSEGV
+ signal(SIGSEGV, whoops);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS, whoops);
+#endif
+#ifdef SIGIOT
+ signal(SIGIOT, whoops);
+#endif
+ sprintf(buf, "%2$s%2$s%1$s%1$s", "bar", "foo");
+ exit(!!strcmp(buf, "foofoobarbar"));
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_EXTENDED_PRINTF"
+else
+ off="$off HAVE_EXTENDED_PRINTF"
+fi
+
+cat >doit.c <<\EOF
+#include <nl_types.h>
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ if (argc == 0) {
+ nl_catd d = catopen("foo", 0);
+ catgets(d, 1, 1, "default");
+ catclose(d);
+ }
+ exit(0);
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ on="$on HAVE_CAT"
+else
+ off="$off HAVE_CAT"
+fi
+
+cat >doit.c <<\EOF
+#include <limits.h>
+
+char c = UCHAR_MAX;
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+#if CHAR_MIN < 0
+ exit(!(c < 0));
+#else
+ exit(!(c > 0));
+#endif
+}
+EOF
+
+if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+then
+ char_signed=
+else
+ cat >doit.c <<\EOF
+main()
+{
+ int i;
+
+ for (i = 0; i < 512; i++) {
+ char c = (char)i;
+ if (c < 0)
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+
+ if $CC $CFLAGS -o doit doit.c $LIBS >/dev/null 2>&1 && ./doit 2>/dev/null
+ then
+ char_signed=0
+ else
+ char_signed=1
+ fi
+fi
+
+cat >doit.c <<\EOF
+
+typedef void VOID;
+
+extern VOID bar();
+
+VOID foo()
+{
+}
+EOF
+
+if $CC $CFLAGS -c doit.c >/dev/null 2>&1
+then
+ void_ret=void
+else
+ void_ret=int
+fi
+
+
+cat >doit.c <<\EOF
+
+void *foo()
+{
+ static char *buf;
+ return buf;
+}
+EOF
+
+if $CC $CFLAGS -c doit.c >doit.log 2>&1
+then
+ if test -s doit.log
+ then
+ void_star="char \*"
+ else
+ void_star="void \*"
+ fi
+
+else
+ void_star="char \*"
+fi
+
+edit=
+
+rm -f doit.c doit doit.log doit.o
+
+for var in $on
+do
+ edit="$edit -e 's;^/\\* *\\(#define $var [^/]*\\) *\\*/;\\1;'"
+done
+for var in $off
+do
+ edit="$edit -e 's;^#define $var [^/]*;/* & */;'"
+done
+
+if test -n "$char_signed"
+then
+ edit="$edit -e 's;^/\\* *\\(#define CHAR_SIGNED $char_signed\\) *\\*/;\\1;'"
+fi
+
+edit="$edit -e 's/^typedef .*VOID;/typedef $void_ret VOID;/'"
+edit="$edit -e 's/^typedef .*UNIV;/typedef ${void_star}UNIV;/'"
+
+if test "X$(PREFIX)" != "X/usr/local"
+then
+ edit="$edit -e '/DEFAULT_PATH/s;/usr/local;$PREFIX;g'"
+fi
+
+eval sed $edit unix.cfg ">config.out"
+
+mv config.out config.h
+
+exit 0
diff --git a/usr.bin/sgmls/instant/Makefile b/usr.bin/sgmls/instant/Makefile
new file mode 100644
index 0000000..c004f87
--- /dev/null
+++ b/usr.bin/sgmls/instant/Makefile
@@ -0,0 +1,15 @@
+# $Id$
+
+PROG= instant
+SRCS= browse.c info.c main.c tables.c traninit.c translate.c
+SRCS+= tranvar.c util.c
+
+CFLAGS+= -I${.CURDIR}/../libsgmls -I${.CURDIR}/../sgmls
+
+LDADD= ${LIBSGMLS} -lcompat
+DPADD= ${LIBSGMLS} ${LIBCOMPAT}
+
+MAN1= instant.1
+MAN5= transpec.5
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sgmls/instant/README b/usr.bin/sgmls/instant/README
new file mode 100644
index 0000000..d04547c
--- /dev/null
+++ b/usr.bin/sgmls/instant/README
@@ -0,0 +1,150 @@
+#
+# Copyright (c) 1994
+# Open Software Foundation, Inc.
+#
+# Permission is hereby granted to use, copy, modify and freely distribute
+# the software in this file and its documentation for any purpose without
+# fee, provided that the above copyright notice appears in all copies and
+# that both the copyright notice and this permission notice appear in
+# supporting documentation. Further, provided that the name of Open
+# Software Foundation, Inc. ("OSF") not be used in advertising or
+# publicity pertaining to distribution of the software without prior
+# written permission from OSF. OSF makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+
+ instant - a formatting application for OSF SGML instances
+____________________________________________________________________________
+
+Requirements
+
+ ANSI C compiler (gcc is one)
+
+ sgmls 1.1 -- sgml parser from James Clark. Based on Goldfarb's ARC parser.
+
+ Vanilla unix make
+
+ POSIX C libraries
+
+
+Files for instant program
+
+ Module Function
+ ------ --------
+ browse.c interactive browser
+ general.h general definitions
+ info.c print information about the instances
+ main.c main entry, arg parsing, instance reading
+ tables.c table-specific formatting routines (TeX and tbl)
+ traninit.c translator initialization (read spec, etc.)
+ translate.c main translator
+ translate.h structure definitions for translation code
+ tranvar.c routines for handling "special variables"
+ util.c general utilities
+
+
+Also required
+
+ 1. Translation spec (transpec) files. (../transpecs/*.ts)
+ 2. SDATA mapping files for mapping sdata entities. (../transpecs/*.sdata)
+ 3. Character mapping files for mapping characters. (../transpecs/*.cmap)
+
+
+Platforms tried on
+
+ OSF1 1.3 (i486)
+ Ultrix 4.2 (mips)
+ HP-UX 9.01 (hp 9000/700)
+ AIX 3.2 (rs6000)
+ SunOS [missing strerror()]
+
+____________________________________________________________________________
+
+ General outline of program
+ ------- ------- -- -------
+
+To summarize in a sentence, instant reads the output of sgmls, builds a tree
+of the instnace in memory, then traverses the tree in in-order, processing
+the nodes according to a translation spec.
+
+Element tree storage
+------- ---- -------
+
+The first thing instant must do is read the ESIS (output of sgmls) from the
+specified file or stdin, forming a tree in memory. (Nothing makes sense
+without an instance...) Each element of the instance is a node in the tree,
+stored as a structure called Element_t. Elements contain content (what
+else?), which is a mixture of data (#PCDATA, #CDATA, #RCDATA - all the same
+in the ESIS), child elements, and PIs. Each 'chunk' of content is referred
+to by a Content_t structure. A Content_t contains an enum that can point to
+a string (data or PI), another Element_t. For example, if a <p> element
+contains some characters, an <emphasis> element, some more characters,
+a <function> element, then some more characters, it has 5 Content_t children
+as an array.
+
+Element_t's have pointers to their parents, and a next element in a linked
+list (they're stored as a linked list, for cases when you'd want to quickly
+travers all the nodes, in no particular order).
+For convenience, Element_t's have an array of pointers to it's child
+Element_t's. These are just pointers to the same thing contained in the
+Content_t array, without the intervening data or PIs. This makes it easier
+for the program to traverse the elements of the tree (it does not have to
+be concerned with skipping data, etc.). There is an analagous array of
+pointers for the data content, an array of (char *)'s. This makes it easier
+to consider the immediate character content of an element.
+
+Attributes are kept as an array of name-value mappings (using the typedef
+Mapping_t). ID attributes are also stored in a separate list of ID value -
+element pointer pairs so that it is quick to find an element by ID.
+
+Other information kept about each element (in the Element_t struct) includes
+the line number in the EISI where the element occurs, the input filename.
+(These depend on sgmls being run with the "-l" option.) Also stored is
+an element's order in its parent's collection of children and an element's
+depth in the tree.
+
+Translation specs
+----------- -----
+
+A translation spec is read into a linked list in memory. As the instance
+tree is traversed, the transpecs are searched in order for a match. As a
+rule, one should position the less specific transpecs later in the file.
+Also, specs for seldom-used element are best placed later in the file, since
+it takes cpu cycles to skip over them for each of the more-used elements.
+
+During translation of a particular element, the list of Content_t structures
+are processed in order. If a content 'chunk' is data, it is printed to
+the output stream. If it is an element, the translation routine is called
+for that elemen, recursively. Hence, in-order traversal.
+
+Miscellaneous information displays
+------------- ----------- --------
+
+There are several informational display options available. They include:
+ - a list of element usage (-u) -- lists each element in the instance,
+ it's attributes, number of children, parent, data content 'nodes'.
+ - statistics about elements (-S) -- lists elements, number of times
+ each is used, percent of elements that this is, total char content
+ in that element, average number of characters in they element.
+ - show context of each element (-x) -- lists each element and its
+ context, looking up the tree (this is the same context that
+ would match the Context field of a transpec).
+ - show the hierarchy of the instance (-h) -- show an ascii 'tree' of
+ the instance, where elements deeper in the tree are indented more.
+ Numbers after the element name in parentheses are the number of
+ element content nodes and the number of data content nodes.
+
+Interactive browser
+----------- -------
+
+Originally, the interactive browser was intended as a debugging aid for
+the code developer. It was a way to examine a particular node of the
+instance tree or process a subtree without being distracted by the rest
+of the instance. Many of the commands test functionality of the query
+and search code (such as testing whether a certain element has a given
+relationship to the current position in the tree).
+
+
+____________________________________________________________________________
+
diff --git a/usr.bin/sgmls/instant/browse.c b/usr.bin/sgmls/instant/browse.c
new file mode 100644
index 0000000..c904476
--- /dev/null
+++ b/usr.bin/sgmls/instant/browse.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+
+/* ________________________________________________________________________
+ *
+ * Module for interactive browsing.
+ *
+ * Entry points for this module:
+ * Browse() interactive browser
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/browse.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "general.h"
+
+static void PrElemPlusID(Element_t *);
+static void ls_node(Element_t *, int, char **);
+static void do_query(Element_t *, char *, char *);
+static void do_find(Element_t *, char **);
+
+/* ______________________________________________________________________ */
+
+static char *br_help_msg[] = {
+ " ls List info about current element in tree",
+ " (context, children, attributes, etc.)",
+ " cd N ... Change to Nth elememt child, where N is shown by 'ls'.",
+ " N may also be '/' (top) or '..' (up).",
+ " cd id I Change to elememt whose ID is I",
+ " data N Show data of Nth data node",
+ " where Show current position in the tree",
+ " id I Show path to element with id I",
+ " (using '?' for I will lists all IDs and their paths)",
+ " find S Find elements matching spec S. Recognized syntaxes:",
+ " find attr <name> <value>",
+ " find cont <string>",
+ " find parent <gi-name>",
+ " find child <gi-name>",
+ " find gi <gi-name>",
+ " q rel gi Query: report if elem 'gi' has relation to current elem",
+ " ('rel' is one of 'child parent ancestor descendant",
+ " sibling sibling+ sibling+1 sibling- sibling-1 cousin')",
+ "",
+ " tran [outfile]",
+ " Translate into 'outfile' (stdout)",
+ " stat Print statistics (how often elements occur, etc.)",
+ " sum Print elem usage summary (# of children, depth, etc.)",
+ " tree Print document hierarchy as a tree",
+ " cont Print context of each element",
+ NULL
+};
+
+/* ______________________________________________________________________ */
+
+void
+Browse()
+{
+ char buf[256], *cmd, **av, **sv;
+ char *Prompt;
+ Element_t *ce; /* current element */
+ Element_t *e;
+ int i, n, ac;
+
+ if (slave) Prompt = "=>\n";
+ else Prompt = "=> ";
+
+ ce = DocTree;
+ while (fputs(Prompt, stdout)) {
+ if (!fgets(buf, 256, stdin)) break;
+ stripNL(buf);
+ if (buf[0] == EOS) {
+ fputs(Prompt, stdout);
+ continue;
+ }
+ ac = 20;
+ av = Split(buf, &ac, S_ALVEC);
+ if (ac > 0) cmd = av[0];
+ if (!cmd || !(*cmd)) continue;
+
+ if (!strcmp(cmd, "ls")) ls_node(ce, ac, av);
+
+ else if (!strcmp(cmd, "cd")) {
+ if (av[1]) {
+ if (ac == 3 && !strcmp(av[1], "id")) {
+ if ((e = FindElemByID(av[2]))) ce = e;
+ else printf("Element with ID '%s' not found.\n", av[2]);
+ continue;
+ }
+ for (i=1; i<ac; i++) {
+ if (!strcmp(av[i], "..")) {
+ if (ce->parent) ce = ce->parent;
+ continue;
+ }
+ if (!strcmp(av[i], "/")) {
+ if (ce->parent) ce = DocTree;
+ continue;
+ }
+ if (!isdigit(*av[i])) {
+ printf("Expecting digit, '..', or '/', got '%s'.\n",
+ av[i]);
+ break;
+ }
+ n = atoi(av[i]);
+ if (n < ce->necont) ce = ce->econt[n];
+ else {
+ printf("Must be in range 0 - %d.\n", ce->necont);
+ break;
+ }
+ }
+ }
+ }
+
+ else if (!strcmp(cmd, "data")) {
+ if (av[1] && isdigit(*av[1])) {
+ n = atoi(av[1]);
+ if (n < ce->ndcont) {
+ printf(ce->dcont[n]);
+ fputs("\n", stdout);
+ }
+ else if (ce->ndcont == 0)
+ printf("No data at this node.\n");
+ else printf("Must be in range 0 - %d.\n", ce->ndcont);
+ }
+ }
+
+ /* show where we are in the tree */
+ else if (!strcmp(cmd, "where")) PrintLocation(ce, stdout);
+
+ /* show where we are in the tree */
+ else if (!strcmp(cmd, "pwd")) PrElemPlusID(ce);
+
+ /* perform query with yes/no answer */
+ else if (!strcmp(cmd, "q") && av[1] && av[2])
+ do_query(ce, av[1], av[2]);
+
+ /* perform query printing paths to matching elements */
+ else if (!strcmp(cmd, "find") && av[1] && av[2])
+ do_find(ce, av);
+
+ /* list locations where specified ID(s) occur */
+ else if (!strcmp(cmd, "id")) {
+ if (ac <= 1) continue;
+ if (*av[1] == '?') PrintIDList();
+ else {
+ /* short: "id i1 i2 ...", long: "id -l i1 i2 ..." */
+ if (!strcmp(av[1], "-l")) n = 2;
+ else n = 1;
+ for (i=n; i<ac; i++) {
+ if ((e = FindElemByID(av[i]))) {
+ if (n == 2) { /* long (multiline) format */
+ if (n != i) putchar('\n');
+ PrintLocation(e, stdout);
+ }
+ else PrElemPlusID(e);
+ }
+ else printf("Element with ID '%s' not found.\n", av[i]);
+ }
+ }
+ }
+
+ /* show and set variables */
+ else if (!strcmp(cmd, "show") && av[1]) {
+ printf("%s\n", FindMappingVal(Variables, av[1]));
+ }
+ else if (!strcmp(cmd, "set") && av[1] && av[2]) {
+ SetMappingNV(Variables, av[1], av[2]);
+ }
+
+ /* print summary of tag usage */
+ else if (!strcmp(cmd, "sum")) {
+ if (ac > 1) PrintElemSummary(ce);
+ else PrintElemSummary(DocTree);
+ }
+ /* print element tree */
+ else if (!strcmp(cmd, "tree")) {
+ if (ac > 1) PrintElemTree(ce);
+ else PrintElemTree(DocTree);
+ }
+ /* print statistics */
+ else if (!strcmp(cmd, "stat")) {
+ if (ac > 1) PrintStats(ce);
+ else PrintStats(DocTree);
+ }
+ /* print context of each element of tree */
+ else if (!strcmp(cmd, "cont")) {
+ if (ac > 1) PrintContext(ce);
+ else PrintContext(DocTree);
+ }
+ /* print translation, given transpec */
+ else if (!strcmp(cmd, "tran")) {
+ FILE *fp;
+ if (ac > 1){
+ if (!(fp = fopen(av[1], "w"))) {
+ perror("Can not open output file");
+ continue;
+ }
+ }
+ else fp = stdout;
+ DoTranslate(ce, fp);
+ if (ac > 1) fclose(fp);
+ }
+
+ else if (!strcmp(cmd, "help") || *cmd == '?') {
+ sv = br_help_msg;
+ while (*sv) puts(*sv++);
+ }
+
+ /* quit (control-D also works) */
+ else if (!strcmp(cmd, "quit")) break;
+
+ else
+ fprintf(stderr, "Unknown command '%s' - ingored.\n", cmd);
+ }
+ putc(NL, stdout);
+}
+
+/* ______________________________________________________________________ */
+/* Do the "ls" command.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Arg count from command line (this command, not the shell command).
+ * Arg vector.
+ */
+
+static void
+ls_node(
+ Element_t *e,
+ int ac,
+ char **av
+)
+{
+ int i;
+ char buf[LINESIZE];
+
+ if (ac > 1 && !strcmp(av[1], "-n")) {
+ for(i=0; i<e->ncont; i++) {
+ if (IsContElem(e,i)) printf("%s\n", ContElem(e,i)->gi);
+ else if (IsContData(e,i)) printf("#data %s\n", ContData(e,i));
+ else if (IsContPI(e,i)) printf("#pi %s\n", ContData(e,i));
+ }
+ return;
+ }
+
+ printf("Element: %s\tLineNumber: %d\n", e->gi, e->lineno);
+ if (e->parent)
+ printf("Context: %s\n", FindContext(e, 20, buf));
+
+ if (e->natts) {
+ printf("%d attributes:\n", e->natts);
+ for (i=0; i<e->natts; i++)
+ printf("\t%2d: %s = '%s'\n", i, e->atts[i].name, e->atts[i].sval);
+ }
+ if (e->entity) {
+ printf("Entity & notation information:\n");
+ if (e->entity->ename)
+ printf("Entity name: %s\n", e->entity->ename);
+ if (e->entity->nname)
+ printf("Notation name: %s\n", e->entity->nname);
+ if (e->entity->sysid)
+ printf("Sys id: %s\n", e->entity->sysid);
+ if (e->entity->pubid)
+ printf("Pub id: %s\n", e->entity->pubid);
+ if (e->entity->fname)
+ printf("Filename: %s\n", e->entity->fname);
+ }
+
+ if (e->my_eorder >= 0)
+ printf("My order among my siblings: %d\n", e->my_eorder);
+
+ if (e->necont) {
+ printf("%d child element nodes:\n", e->necont);
+ for(i=0; i<e->necont; i++) printf("\t%2d: %s\n", i, e->econt[i]->gi);
+ }
+
+ if (e->ndcont) {
+ printf("%d child data nodes:\n", e->ndcont);
+ for(i=0; i<e->ndcont; i++) {
+ if (strlen(e->dcont[i]) < 40)
+ printf("\t%2d: %s\n", i, e->dcont[i]);
+ else
+ printf("\t%2d: %-40.40s...\n", i, e->dcont[i]);
+ }
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Perform query. Syntax: find relationship gi. Tells whether gi has
+ * given relationship to current element. Result (message) sent to stdout.
+ * Args:
+ * Pointer to element under consideration.
+ * Pointer to name of relationship. (see FindRelByName() for names)
+ * Pointer to GI to look for.
+ */
+
+static void
+do_query(
+ Element_t *e,
+ char *rel,
+ char *gi
+)
+{
+ char *cp;
+ Relation_t r;
+ Element_t *ep;
+
+ for (cp=gi; *cp; cp++) if (islower(*cp)) *cp = toupper(*cp);
+
+ if ((r = FindRelByName(rel)) == REL_Unknown) {
+ return;
+ }
+ ep = QRelation(e, gi, r);
+ printf("%s, '%s' is%s %s of '%s'.\n", (ep ? "Yes" : "No"), gi,
+ (ep ? "" : " not"), rel, e->gi);
+}
+
+/* ______________________________________________________________________ */
+/* Print path to the element and its ID (if it has one) on a single line.
+ * Arguments:
+ * Pointer to element under consideration.
+ */
+static void
+PrElemPlusID(
+ Element_t *e
+)
+{
+ char buf[LINESIZE];
+
+ if (e->id) printf("%s -- ID=%s\n", FindElementPath(e, buf), e->id);
+ else printf("%s\n", FindElementPath(e, buf));
+}
+
+/* ______________________________________________________________________ */
+/* Print path to the element and its ID (if it has one) on a single line.
+ * Arguments:
+ * Pointer to element under consideration.
+ */
+
+static void
+match_gi(
+ Element_t *e,
+ char **av
+)
+{
+ if (!strcmp(av[1], e->gi)) PrElemPlusID(e);
+}
+
+/* Shorthand for defining simple finctions, which are just interfaces to
+ * calling QRelation(). DescendTree() only passes ptr to element. */
+#define MATCH(Fun,Rel) \
+ static void Fun(Element_t *e, char **av) \
+ { if (QRelation(e, av[1], Rel)) PrElemPlusID(e); }
+
+MATCH(match_parent, REL_Parent)
+MATCH(match_child, REL_Child)
+MATCH(match_anc, REL_Ancestor)
+MATCH(match_desc, REL_Descendant)
+MATCH(match_sib, REL_Sibling)
+
+static void
+match_attr(
+ Element_t *e,
+ char **av
+)
+{
+ char *atval;
+
+ if ((atval = FindAttValByName(e, av[1])) && !strcmp(av[2], atval))
+ PrElemPlusID(e);
+}
+
+static void
+match_cont(
+ Element_t *e,
+ char **av
+)
+{
+ int i;
+ for (i=0; i<e->ncont; i++) {
+ if (IsContData(e,i) && strstr(ContData(e,i), av[1])) {
+ PrElemPlusID(e);
+ return;
+ }
+ }
+}
+
+/* Find an element, given the criteria on its command line.
+ * Arguments:
+ * Pointer to element under consideration.
+ */
+static void
+do_find(
+ Element_t *e,
+ char **av
+)
+{
+ av++;
+ if (!strcmp(av[0], ".")) av++;
+ else e = DocTree;
+ if (!strcmp(av[0], "gi")) DescendTree(e, match_gi, 0, 0, av);
+ else if (!strcmp(av[0], "attr")) DescendTree(e, match_attr, 0, 0, av);
+ else if (!strcmp(av[0], "parent")) DescendTree(e, match_parent, 0, 0, av);
+ else if (!strcmp(av[0], "child")) DescendTree(e, match_child, 0, 0, av);
+ else if (!strcmp(av[0], "cont")) DescendTree(e, match_cont, 0, 0, av);
+ else if (!strcmp(av[0], "sib")) DescendTree(e, match_sib, 0, 0, av);
+ else if (!strcmp(av[0], "desc")) DescendTree(e, match_desc, 0, 0, av);
+ else if (!strcmp(av[0], "anc")) DescendTree(e, match_anc, 0, 0, av);
+ else fprintf(stderr, "Unknown find command: %s.\n", av[0]);
+}
+
+/* ______________________________________________________________________ */
diff --git a/usr.bin/sgmls/instant/general.h b/usr.bin/sgmls/instant/general.h
new file mode 100644
index 0000000..f6e6ea0
--- /dev/null
+++ b/usr.bin/sgmls/instant/general.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Common definitions for "instant" program.
+ * ________________________________________________________________________
+ */
+
+#ifdef STORAGE
+#ifndef lint
+static char *gen_h_RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/general.h,v 1.5 1996/06/11 20:25:03 fld Exp $";
+#endif
+#endif
+
+/* string/numeric/character definitions */
+
+#define EOS '\0'
+#define NL '\n'
+#define TAB '\t'
+#define CR '\r'
+#define ANCHOR '^'
+
+/* bigmask/flags for the Split() function */
+#define S_STRDUP 0x01
+#define S_ALVEC 0x02
+
+/* Command codes (1st char of esis lines) from sgmls. See its manpage. */
+#define CMD_DATA '-'
+#define CMD_OPEN '('
+#define CMD_CLOSE ')'
+#define CMD_ATT 'A'
+#define CMD_D_ATT 'D'
+#define CMD_NOTATION 'N'
+#define CMD_EXT_ENT 'E'
+#define CMD_INT_ENT 'I'
+#define CMD_SYSID 's'
+#define CMD_PUBID 'p'
+#define CMD_FILENAME 'f'
+#define CMD_LINE 'L'
+#define CMD_PI '?'
+#define CMD_SUBDOC 'S'
+#define CMD_SUBDOC_S '{'
+#define CMD_SUBDOC_E '}'
+#define CMD_EXT_REF '&'
+#define CMD_APPINFO '#'
+#define CMD_CONFORM 'C'
+
+/* Some sizes */
+#define MAX_DEPTH 40
+#define LINESIZE 60000
+
+/* Name of library env variable, and default value. */
+#ifndef TPT_LIB
+#define TPT_LIB "TPT_LIB"
+#endif
+#ifndef DEF_TPT_LIB
+#define DEF_TPT_LIB "/usr/share/sgml/transpec"
+#endif
+
+/* Relationships - for querying */
+typedef enum {
+ REL_None, REL_Parent, REL_Child, REL_Ancestor, REL_Descendant,
+ REL_Sibling, REL_Preceding, REL_ImmPreceding, REL_Following,
+ REL_ImmFollowing, REL_Cousin, REL_Unknown
+} Relation_t;
+
+/* Initial map sizes (IMS) */
+#define IMS_relations 3
+#define IMS_setvar 3
+#define IMS_incvar 3
+#define IMS_sdata 50
+#define IMS_sdatacache 30
+#define IMS_variables 20
+#define IMS_attnames 50
+#define IMS_elemnames 50
+
+/* ----- typedef and other misc definitions ----- */
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+
+#ifndef FALSE
+#define FALSE (1 == 0)
+#endif
+
+typedef short bool;
+
+
+/* ----- structure definitions ----- */
+
+/* We use this for variables, attributes, etc., so the caller only needs an
+ * opaque handle to the thing below, not worrying about array management. */
+typedef struct {
+ char *name; /* name of the thing */
+ char *sval; /* string value */
+} Mapping_t;
+
+typedef struct {
+ int n_alloc; /* number of elements allocated */
+ int n_used; /* number of elements used */
+ int slot_incr; /* increment for allocating slots */
+ int flags; /* info about this set of mappings */
+ Mapping_t *maps; /* array of mappings */
+} Map_t;
+
+/* ______________________________________________________________________ */
+
+/* Information about an entity reference. Not all fields will be used
+ * at once. */
+typedef struct _ent {
+ char *type; /* entity type */
+ char *ename; /* entity name */
+ char *nname; /* notation name */
+ char *sysid; /* sys id */
+ char *pubid; /* pub id */
+ char *fname; /* filename */
+ struct _ent *next; /* next in linked list */
+} Entity_t;
+
+/* Content (child nodes) of an element (node in the tree) -- both data
+ * and other elements. */
+typedef struct {
+ char type; /* element, data, or pi? */
+ union {
+ struct _elem *elem; /* direct children of this elem */
+ char *data; /* character data of this elem */
+ } ch;
+} Content_t;
+
+/* An element (node in the tree) */
+typedef struct _elem {
+ char *gi; /* element GI */
+ Content_t *cont; /* content - element & data children */
+ int ncont; /* # of content/children */
+ struct _elem **econt; /* element children */
+ int necont; /* # of element children */
+ char **dcont; /* character data children */
+ int ndcont; /* # of data children */
+ Mapping_t *atts; /* array of attributes */
+ int natts; /* # of attributes */
+ Entity_t *entity; /* ext entity & notation info */
+ char *id; /* for linking */
+ int index; /* an internal bookkeeping mechanism */
+ int depth; /* how deep in tree */
+ int lineno; /* line number */
+ char *infile; /* input filename */
+ int my_eorder; /* order of this elem of its parent */
+ struct _elem *parent; /* this elem's direct parent */
+ struct _elem *next; /* kept in linked list */
+ void *trans; /* pointer to translation spec */
+ /* I'm not crazy about this, but it works */
+ int gen_trans[2]; /* refs to generated trans specs */
+ int processed; /* was this node processed? */
+} Element_t;
+
+/* For mapping of element IDs to elements themselves. */
+typedef struct id_s {
+ char *id; /* ID of the element */
+ Element_t *elem; /* pointer to it */
+ struct id_s *next;
+} ID_t;
+
+/* ----- global variable declarations ----- */
+
+#ifdef STORAGE
+# define def
+#else
+# define def extern
+#endif
+
+def Element_t *DocTree; /* root of document tree */
+def char **UsedElem; /* a unique list of used elem names */
+def int nUsedElem; /* number of used elem names */
+def char **UsedAtt; /* a unique list of used attrib names */
+def int nUsedAtt; /* number of used attrib names */
+def ID_t *IDList; /* list of IDs used in the doc */
+def Map_t *Variables; /* general, global variables */
+def Map_t *SDATAmap; /* SDATA mappings */
+def Map_t *PImap; /* Processing Instruction mappings */
+def Entity_t *Entities; /* list of entities */
+
+def FILE *outfp; /* where output is written */
+def char *tpt_lib; /* TPT library directory */
+def int verbose; /* flag - verbose output? */
+def int warnings; /* flag - show warnings? */
+def int interactive; /* flag - interactive browsing? */
+def int slave; /* are we slave to another process? */
+def int fold_case; /* flag - fold case of GIs? */
+
+/* ----- some macros for convenience and ease of code reading ----- */
+
+#define stripNL(s) { char *_cp; if ((_cp=strchr(s, NL))) *_cp = EOS; }
+
+/* Similar to calloc(), malloc(), and realloc(), but check for success.
+ * Args to all:
+ * (1) number of 'elements' to allocate
+ * (2) variable to point at allocated space
+ * (3) type of 'element'
+ * Eg: Calloc(5, e, Element_t) replaces
+ * if (!(e = (Element_t *)calloc(5, sizeof(Element_t))) {
+ * ... handle error ... ;
+ * }
+ */
+#define Calloc(N,V,T) \
+ { if (!((V) = (T *)calloc((size_t)N, sizeof(T)))) { \
+ perror("Calloc failed -- out of memory. Bailing out."); exit(1); \
+ }; memset((void *) (V), 0, (size_t) sizeof(T)); }
+#define Malloc(N,V,T) \
+ { if (!((V) = (T *)malloc((size_t)N*sizeof(T)))) { \
+ perror("Malloc failed -- out of memory. Bailing out."); exit(1); \
+ }; memset((void *) (V), 0, (size_t) sizeof(T)); }
+#define Realloc(N,V,T) \
+ { if (!((V) = (T *)realloc(V,(size_t)N*sizeof(T)))) { \
+ perror("Realloc failed -- out of memory. Bailing out."); exit(1); \
+ } }
+
+/* similar to strcmp(), but check first chars first, for efficiency */
+#define StrEq(s1,s2) (s1[0] == s2[0] && !strcmp(s1,s2))
+
+/* similar to isspace(), but check for blank or tab - without overhead
+ * of procedure call */
+#define IsWhite(c) (c == ' ' || c == TAB || c == NL)
+
+#define ContType(e,i) (e->cont[i].type)
+#define ContData(e,i) (e->cont[i].ch.data)
+#define ContElem(e,i) (e->cont[i].ch.elem)
+#define IsContData(e,i) (e->cont[i].type == CMD_DATA)
+#define IsContElem(e,i) (e->cont[i].type == CMD_OPEN)
+#define IsContPI(e,i) (e->cont[i].type == CMD_PI)
+
+/* ----- function prototypes ----- */
+
+/* things defined in util.c */
+Element_t *QRelation(Element_t *, char *, Relation_t);
+Relation_t FindRelByName(char *);
+char *FindAttValByName(Element_t *, char *);
+char *FindContext(Element_t *, int, char *);
+char *AddElemName(char *);
+char *AddAttName(char *);
+char *ExpandString(char *);
+void OutputString(char *, FILE *, int);
+char *LookupSDATA(char *);
+FILE *OpenFile(char *);
+char *FilePath(char *);
+char *FindElementPath(Element_t *, char *);
+char *NearestOlderElem(Element_t *, char *);
+void PrintLocation(Element_t *, FILE *);
+char **Split(char *, int *, int);
+void DescendTree(Element_t *, void(*)(), void(*)(), void(*)(), void *);
+Map_t *NewMap(int);
+Mapping_t *FindMapping(Map_t *, const char *);
+char *FindMappingVal(Map_t *, const char *);
+void SetMapping(Map_t *, const char *);
+void SetMappingNV(Map_t *, const char *, const char *);
+void AddID(Element_t *, char *);
+Element_t *FindElemByID(char *);
+
+/* things defined in translate.c */
+void DoTranslate(Element_t*, FILE *);
+void ExpandVariables(char*, char*, Element_t*);
+
+/* things defined in traninit.c */
+void ReadTransSpec(char *);
+
+/* things defined in tranvar.c */
+char *Get_A_C_value(const char *);
+
+/* things defined in info.c */
+void PrintContext(Element_t *e);
+void PrintElemSummary(Element_t *);
+void PrintElemTree(Element_t *);
+void PrintStats(Element_t *);
+void PrintIDList();
+
+/* things defined in table.c */
+void CALStable(Element_t *, FILE *, char **, int);
+
+/* ----- other declarations ----- */
+
+#ifdef ultrix
+#define strdup(s) strcpy((char *)malloc(strlen(s)+1), s)
+#endif
+
diff --git a/usr.bin/sgmls/instant/hyper.c b/usr.bin/sgmls/instant/hyper.c
new file mode 100644
index 0000000..4f50b97
--- /dev/null
+++ b/usr.bin/sgmls/instant/hyper.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Hypermedia-related facilities.
+ *
+ * Entry points for this module:
+ * AddID(elem, idval) add elem-id pair to list of known ids
+ * FindElemByID(idval) find elem by id
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/hyper.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+
+#include "general.h"
+
+
+/* ______________________________________________________________________ */
+
+void
+AddID(Element *e, char *idval)
+{
+ static ID *id_last;
+ if (!IDList) {
+ Calloc(1, id_last, ID);
+ IDList = id_last;
+ }
+ else {
+ Calloc(1, id_last->next, ID);
+ id_last = id_last->next;
+ }
+ id_last->elem = e;
+ id_last->id = idval;
+}
+
+Element *
+FindElemByID(char *idval)
+{
+ ID *id;
+ for (id=IDList; id; id=id->next)
+ if (!strcmp(id->id, idval)) return id->elem;
+ return 0;
+}
+
+/* ______________________________________________________________________ */
+
diff --git a/usr.bin/sgmls/instant/info.c b/usr.bin/sgmls/instant/info.c
new file mode 100644
index 0000000..27ab1c7
--- /dev/null
+++ b/usr.bin/sgmls/instant/info.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Functions for printing information about an instance in the 'instant'
+ * program. Most of these are fairly short and simple.
+ *
+ * Entry points for this module:
+ * PrintElemSummary(elem) print summary info of each element
+ * PrintContext(elem) print context of each element
+ * PrintElemTree(elem) print tree of document
+ * PrintStats(elem) print statistics about doc tree
+ * PrintIDList(elem) print list of IDs and element context
+ * Most Print*() functions start at subtree pointed to by 'elem'.
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/info.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "general.h"
+
+/* ______________________________________________________________________ */
+/* Print a summary of each tag use in the instance. Things like depth in
+ * the tree, number of children, parent, attributes.
+ */
+
+/* Do the actual printing. Print the info about the node. If null,
+ * print a header for the columns.
+ * Arguments:
+ * Pointer to element structure of the node to print.
+ */
+static void
+print_summ(
+ Element_t *e
+)
+{
+ int i, n, dsize;
+ char *hfmt="%-18.18s %4s %5s %4s %4s %s\n";
+ char *fmt ="%-18.18s %4d %5d %4d %4d %s\n";
+
+ if (e == NULL) {
+ fprintf(outfp, hfmt, "Element", "Att", "Data", "Chd", "Dep", "Parent");
+ return;
+ }
+ for (i=0,n=0; i<e->ncont; i++) if (IsContElem(e,i)) n++;
+ for (i=0,dsize=0; i<e->ncont; i++)
+ if (IsContElem(e,i)) dsize += strlen(e->cont[i].ch.data);
+ fprintf(outfp, fmt, e->gi, e->natts, dsize, n, e->depth,
+ e->parent ? e->parent->gi : "-");
+
+ for (i=0; i<e->natts; i++) {
+ fprintf(outfp, "%45d: %s = %s\n", i, e->atts[i].name,
+ e->atts[i].sval ? e->atts[i].sval : "empty");
+ }
+}
+
+/* Descend the tree, calling processing routine.
+ * Arguments:
+ * Pointer to element structure at top of tree to traverse.
+ */
+void
+PrintElemSummary(
+ Element_t *e
+)
+{
+ print_summ(0);
+ DescendTree(e, print_summ, 0, 0, 0);
+}
+
+/* ______________________________________________________________________ */
+/* Print the context of each tag in the instance (i.e. the tag with its
+ * ancestors).
+ */
+
+/* Do the actual printing. Print the context of the node.
+ * Arguments:
+ * Pointer to element structure of the node to print.
+ */
+static void
+print_context(
+ Element_t *e
+)
+{
+ char buf[LINESIZE];
+
+ fprintf(outfp, "%-22s %s\n", e->gi, FindContext(e, 10, buf));
+}
+
+/* Descend the tree, calling processing routine.
+ * Arguments:
+ * Pointer to element structure at top of tree to traverse.
+ */
+void
+PrintContext(
+ Element_t *e
+)
+{
+ fprintf(outfp, "%-22s %s\n", "Element", "Context");
+ fprintf(outfp, "%-22s %s\n", "---------------", "-----------");
+ DescendTree(e, print_context, 0, 0, 0);
+
+ putc(NL, outfp);
+}
+
+/* ______________________________________________________________________ */
+/* Print tree of the instance. GI's are printed indented by their depth
+ * in the tree.
+ */
+
+/* Do the actual printing. Print the element name, indented the right amount.
+ * Arguments:
+ * Pointer to element structure of the node to print.
+ */
+static void
+print_indent(
+ Element_t *e
+)
+{
+ int i, ne, nd;
+ for(i=0; i<e->depth; i++) fputs(". ", outfp);
+ for(i=0,ne=0; i<e->ncont; i++) if (IsContElem(e,i)) ne++;
+ for(i=0,nd=0; i<e->ncont; i++) if IsContData(e,i) nd++;
+ fprintf(outfp, "%s (%d,%d)\n", e->gi, ne, nd);
+}
+
+/* Descend the tree, calling processing routine.
+ * Arguments:
+ * Pointer to element structure at top of tree to traverse.
+ */
+void
+PrintElemTree(
+ Element_t *e
+)
+{
+ DescendTree(e, print_indent, 0, 0, 0);
+ putc(NL, outfp);
+}
+
+/* ______________________________________________________________________ */
+/* Print some statistics about the instance.
+ */
+
+/* Accumulate the totals for the statistics.
+ * Arguments:
+ * Pointer to element structure of the node to print.
+ * Pointer to the total number of elements.
+ * Pointer to the total amount of content data.
+ * Pointer to the maximum depth of tree.
+ */
+static void
+acc_tots(
+ Element_t *e,
+ int *tot_el,
+ int *tot_data,
+ int *max_depth
+)
+{
+ int i;
+ for(i=0; i<e->necont; i++)
+ acc_tots(e->econt[i], tot_el, tot_data, max_depth);
+ for (i=0; i<e->necont; i++) (*tot_el)++;
+ for (i=0; i<e->ndcont; i++) (*tot_data) += strlen(e->dcont[i]);
+ if (e->depth > (*max_depth)) *max_depth = e->depth;
+}
+
+/* Descend the tree (recursively), collecting the statistics.
+ * Arguments:
+ * Pointer to element structure of the node to print.
+ * Pointer to the total number of elements.
+ * Pointer to the total amount of content data.
+ * Pointer to the maximum depth of tree.
+ */
+static void
+elem_usage(
+ Element_t *e,
+ char *name,
+ int *n_used,
+ int *nchars
+)
+{
+ int i;
+ if (!strcmp(name, e->gi)) {
+ (*n_used)++;
+ for (i=0; i<e->ncont; i++)
+ if (IsContData(e,i)) (*nchars) += strlen(ContData(e,i));
+ }
+ for(i=0; i<e->necont; i++)
+ elem_usage(e->econt[i], name, n_used, nchars);
+}
+
+/* Descend the tree, calling processing routine.
+ * Arguments:
+ * Pointer to element structure at top of tree to traverse.
+ */
+void
+PrintStats(
+ Element_t *top
+)
+{
+ int i, n;
+ int dif_el=0, tot_el=0, tot_data=0, nchars, max_depth=0;
+ float pct;
+
+ fprintf(outfp, "%-22s %s %s\n", "Element name", "Occurrances", "Character Content");
+ fprintf(outfp, "%-22s %s %s\n", "---------------", "-----------", "-----------------");
+
+ acc_tots(top, &tot_el, &tot_data, &max_depth);
+
+ for (i=0; i<nUsedElem; i++) {
+ n = 0;
+ nchars = 0;
+ elem_usage(top, UsedElem[i], &n, &nchars);
+ if (n > 0) {
+ pct = 100.0 * (float)n / (float)tot_el;
+ fprintf(outfp, "%-22s %4d %4.1f%% %6d %4d\n", UsedElem[i],
+ n, pct, nchars, (nchars/n));
+ dif_el++;
+ }
+ }
+
+ fprintf(outfp, "\nTotal of %d elements used, %d different ones.\n",
+ tot_el, dif_el);
+ fprintf(outfp, "Total character data: %d.\n", tot_data);
+ fprintf(outfp, "Maximum element depth: %d.\n", max_depth);
+ putc(NL, outfp);
+}
+
+/* ______________________________________________________________________ */
+/* Print list of: ID, GI, input file, line number, separated by colons.
+ * This is better for other programs to manipulate (like for keeping a
+ * database of IDs in documents) than humans to read.
+ */
+
+void
+PrintIDList()
+{
+ ID_t *id;
+ Element_t *ep;
+
+ for (id=IDList; id; id=id->next) {
+ ep = id->elem;
+ fprintf(outfp, "%s:%s:%s:%d\n", id->id, ep->gi,
+ ep->infile?ep->infile:"-", ep->lineno);
+ }
+}
+
+/* ______________________________________________________________________ */
+
diff --git a/usr.bin/sgmls/instant/instant.1 b/usr.bin/sgmls/instant/instant.1
new file mode 100644
index 0000000..513c84d
--- /dev/null
+++ b/usr.bin/sgmls/instant/instant.1
@@ -0,0 +1,183 @@
+...\"
+...\" Copyright (c) 1994
+...\" Open Software Foundation, Inc.
+...\"
+...\" Permission is hereby granted to use, copy, modify and freely distribute
+...\" the software in this file and its documentation for any purpose without
+...\" fee, provided that the above copyright notice appears in all copies and
+...\" that both the copyright notice and this permission notice appear in
+...\" supporting documentation. Further, provided that the name of Open
+...\" Software Foundation, Inc. ("OSF") not be used in advertising or
+...\" publicity pertaining to distribution of the software without prior
+...\" written permission from OSF. OSF makes no representations about the
+...\" suitability of this software for any purpose. It is provided "as is"
+...\" without express or implied warranty.
+...\"
+...\" Copyright (c) 1996 X Consortium
+...\" Copyright (c) 1996 Dalrymple Consulting
+...\"
+...\" Permission is hereby granted, free of charge, to any person obtaining a copy
+...\" of this software and associated documentation files (the "Software"), to deal
+...\" in the Software without restriction, including without limitation the rights
+...\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+...\" copies of the Software, and to permit persons to whom the Software is
+...\" furnished to do so, subject to the following conditions:
+...\"
+...\" The above copyright notice and this permission notice shall be included in
+...\" all copies or substantial portions of the Software.
+...\"
+...\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+...\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+...\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+...\" X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+...\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+...\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+...\" OTHER DEALINGS IN THE SOFTWARE.
+...\"
+...\" Except as contained in this notice, the names of the X Consortium and
+...\" Dalrymple Consulting shall not be used in advertising or otherwise to
+...\" promote the sale, use or other dealings in this Software without prior
+...\" written authorization.
+...\"
+...\" Translated with /usr/local/lib/tpt/ref-man.ts by fld on cord, Wed 07 Feb 1996, 21:59
+.Dd September 5, 1996
+.Os FreeBSD 2.2
+.Dt SGMLFMT 1
+.Sh "NAME"
+instant - manipulates ESIS from parsed SGML instance
+.Sh "Synopsis"
+.na
+.Pp
+\fBinstant\fP [ \fB-bhuvxHISW\fP ] [ \fB-t\fP \fIfile\fP] [ \fB-o\fP \fIfile\fP] [ \fB-D\fP \fIvariable\fP\fB=\fP\fIvalue\fP ...] [ \fB-i\fP \fIid\fP] [ \fB-l\fP \fIdirectory\fP] [\fIfile\fP]
+.ad
+.Sh "DESCRIPTION"
+.Pp
+The \fBinstant\fP program manipulates an SGML document instance in a variety of ways,
+including translating into a form suitable for a formatting application and printing information about this instance.
+Input to \fBinstant\fP is the output of \fBsgmls\fP, whose format is called Element Structure Information Set (ESIS).
+.Sh "FLAGS"
+.Pp
+The following are the possible command line options to \fBinstant\fP. Output is sent to the standard output, except where otherwise noted.
+.\"'br\" labeled list
+.Bl -tag -width Ds
+.It "\fB-t\fP \fIfile\fP"
+Translate the SGML instance to another form, usually suitable for a formatting application.
+The \fIfile\fP is called a translation spec, which specifies how the tags are to be translated. See \fBtranspec\fP(4).
+By convention, names for \fIfile\fP use the suffix \fB.ts\fP, for \fItranslation spec\fP.
+.It "\fB-d\fP"
+"Data hack" \(em strip newline at the beginning of data records
+.It "\fB-f \fIlength\fR"
+Set the threshold for the length, in characters,
+of an <Entry>, over which it is called a block of filled text, to \fIlength\fR.
+.It "\fB-o\fP \fIfile\fP "
+Write all output (except error and warning messages) to file \fIfile\fP. By default, output goes to stdout.
+.It "\fB-h\fP"
+Print a text representation of the hierarchy of the instance elements.
+The deeper an element is in the tree, the more it is indented. The data content is not printed.
+.It "\fB-u\fP"
+Print a summary of the usage of each element in the instance.
+Information given includes attributes, number of children, and depth in the hierarchy.
+.It "\fB-S\fP"
+Print some statistics about element usage in the instance, including how often each element is used
+and how much PCDATA is contained.
+.It "\fB-x\fP"
+Print the context of each element in the instance, from each element to the root of the document tree.
+.It "\fB-v\fP"
+Validate the SGML instance based on the set of constraints or descriptions in the transpec file.
+This flags tells \fBinstant\fP to turn off normal output, leaving only diagnostics.
+.It "\fB-l\fP \fIdirectory\fP"
+Try to read the translation specs or other files from in the directory \fIdirectory\fP
+if not found in the current directory.
+This is called the library directory.
+The environment variable \fITPT_LIB\fP may also be used to specify this.
+.It "\fB-b\fP"
+Interactive browser mode. The user is prompted for actions,
+which include moving among and examining the various nodes in the hierarchy of the instance, displaying information about them, etc.
+.It "\fB-I\fP"
+List the IDs of all elements in the instance that have an ID. The format is more suitable for other programs than humans.
+Lines show the ID, element GI, filename, and line, separated by colons.
+(This depends on the \fB-l\fP option to \fBsgmls\fP which provide filenames and line numbers.)
+.It "\fB-i\fP \fIid\fP"
+When translating the instance, begin processing at the element whose ID is \fIid\fP instead of the topmost element.
+.It "\fB-D\fP \fIvariable\fP\fB=\fP\fIvalue\fP"
+Define the variable \fIvariable\fP with value \fIvalue\fP.
+.It "\fB-W\fP"
+Do not print warning messages.
+.It "\fB-H\fP"
+Print a help message briefly describing the options.
+.It "\fIfile\fP"
+Read the instance from the file \fIfile\fP.
+This is expected to be the output of the program \fBsgmls\fP.
+If not specified, \fBinstant\fP reads the instance from its standard input.
+.El
+.\"'br\" labeled list end
+.Pp
+In some cases it makes no sense to combine options.
+This is especially true if one of the options is to perform a translation. No checking is done for this.
+.Sh "INTERACTIVE BROWSER"
+.Pp
+These are the commands to the interactive browser:
+.Bl -tag -width Ds
+.\"'br\" labeled list
+.It "\fBcd\fP \fIargs ...\fP"
+Change to a different element in the hierarchy.
+\fBcd\fP \fBid\fP \fIid\fP will change to the element whose ID is \fIid\fP.
+\fBcd\fP \fIN\fP will change to the \fIN\fPth child element of the current element.
+Several values of \fIN\fP may be specified, so the program will change to successively descending elements in the hierarchy.
+The string \fB..\fP may appear for \fIN\fP to move up a level in the hierarchy (like in a unix file system).
+A \fB/\fP may be specified for \fIN\fP to change to the top of the hierarchy.
+.It "\fBcont\fP"
+Print the context of each element.
+.It "\fBdata\fP \fIN\fP"
+Show the data content (PCDATA, RCDATA, and DATA) of child node N.
+.It "\fBfind\fP \fIspec\fP"
+Find paths to elements matching \fIspec\fP, where \fIspec\fP may be one of:
+.Bl -tag -width Ds
+.\".RS +\n(INu
+.It "\fBparent\fP \fIgi\fP"
+Find all elements whose parent element is \fIgi\fP.
+.It "\fBchild\fP \fIgi\fP"
+Find all elements which have a child element \fIgi\fP.
+.It "\fBgi\fP \fIgi\fP"
+Find all elements whose name is \fIgi\fP.
+.It "\fBattr\fP \fIname\fP \fIvalue\fP"
+Find all elements that have a attribute \fIname\fP that have a value \fIvalue\fP.
+.\".RE
+.El
+.It "\fBid\fP \fIID\fP"
+Show location of element whose ID is \fIID\fP.
+If \fIID\fP is \fB?\fP, it will list all IDs with the paths to them.
+.It "\fBls\fP"
+List information about the current element in the hierarchy.
+This includes element name, line number in instance, context, attributes and their values, child elements, data directly within this element,
+and the order of the current element among its siblings.
+.It "\fBq\fP \fIrelation\fP \fIelement\fP"
+Report whether or not the current element has the relation \fIrelation\fP to the named element \fIelement\fP.
+Values of \fIrelation\fP are the same as for \fB_followrel\fP in \fBtranspec\fP reference page.
+.It "\fBstat\fP"
+Show statistics about the hierarchy.
+.It "\fBsum\fP"
+Show a tag usage summary about the hierarchy.
+.It "\fBtran\fP \fIoutfile\fP"
+Write translated output to file \fIoutfile\fP.
+If \fIoutfile\fP is not specified, output is sent to stdout.
+.It "\fBtree\fP"
+Print a textual representation of the hierarchy of the instance, where deeper elements are indented more.
+.It "\fBwhere\fP"
+Show current position in the hierarchy.
+.It "<\fBcontrol-D\fP>"
+Exits the program.
+.El
+.Pp
+The \fBstat\fP, \fBsum\fP, \fBtree\fP, \fBcont\fP commands take an optional first argument (of any value),
+which means to only consider the entire instance instead of the hierarchy from the current element.
+.Sh "FILES"
+.Bl -tag -width Ds
+.It "\fIfile\fP\fB.ts\fP"
+Translation specification file.
+.El
+.Sh "SEE ALSO"
+.Pp
+.Xr transpec 5 ,
+.Xr sgmls 1 ,
+Standard Generalized Markup Language (SGML), ISO 8879.
diff --git a/usr.bin/sgmls/instant/main.c b/usr.bin/sgmls/instant/main.c
new file mode 100644
index 0000000..2f10537
--- /dev/null
+++ b/usr.bin/sgmls/instant/main.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Program to read an SGML document instance, creating any of several things:
+ *
+ * "translated" output for formatting applications (given a trans. spec)
+ * validation report (given a appropriate trans spec)
+ * tree of the document's structure
+ * statistics about the element usage
+ * summary of the elements used
+ * context of each element used
+ * IDs of each element
+ *
+ * A C structure is created for each element, which includes:
+ * name, attributes, parent, children, content
+ * The tree is descended, and the desired actions performed.
+ *
+ * Takes input from James Clark's "sgmls" program (v. 1.1).
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /home/ncvs/src/usr.bin/sgmls/instant/main.c,v 1.1.1.1 1996/09/08 01:55:10 jfieber Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <time.h>
+#include <locale.h>
+
+#define STORAGE
+#include "general.h"
+
+static int do_context, do_tree, do_summ, do_stats, do_validate, do_idlist;
+static int do_DATAhack = 0;
+static char *this_prog;
+static char *in_file, *out_file;
+static char *tranfile;
+static char *start_id;
+static char *last_file;
+static int last_lineno;
+
+extern int BOFTTextThresh;
+
+/* forward references */
+static void HandleArgs(int, char *[]);
+static void Initialize1();
+static void Initialize2();
+static void ReadInstance(char *);
+static void DoHelpMessage();
+extern void Browse();
+
+/* external reference to version number */
+char _HeadVeRsIoN_[] = "1.0 (FreeBSD)";
+
+/* ______________________________________________________________________ */
+/* Program entry point. Look at args, read instance, dispatch to the
+ * correct routines to do the work, and finish.
+ */
+
+int
+main(
+ int ac,
+ char *av[]
+)
+{
+ setlocale(LC_ALL, "");
+ Initialize1(av[0]);
+ HandleArgs(ac, av);
+ Initialize2();
+
+ if (tranfile) ReadTransSpec(tranfile);
+ ReadInstance(in_file);
+
+ if (interactive) {
+ Browse(); /* this will handle interactive commands */
+ }
+ else {
+ /* Perform tasks based on command line flags... */
+ if (tranfile) {
+ Element_t *e;
+ /* If user wants to start at a particular ID, point to that
+ * element. Else, point to the top of the tree. */
+ if (start_id) {
+ if (!(e=FindElemByID(start_id))) {
+ fprintf(stderr, "Error: Can not find element with ID %s\n",
+ start_id);
+ exit(1);
+ }
+ }
+ else e = DocTree;
+ /* If we're doing validation, make output file pointer null.
+ * This means that we generate no output, except error messages. */
+ if (do_validate) outfp = NULL;
+ if (tranfile)
+ DoTranslate(e, outfp);
+ else
+ fprintf(stderr, "Translation spec file not specified. Skipping translation.\n");
+ }
+ if (do_summ) PrintElemSummary(DocTree);
+ if (do_tree) PrintElemTree(DocTree);
+ if (do_stats) PrintStats(DocTree);
+ if (do_context) PrintContext(DocTree);
+ if (do_idlist) PrintIDList();
+ }
+ if (out_file && outfp) fclose(outfp);
+
+ return 0;
+}
+
+/* ______________________________________________________________________ */
+/* Initialization stuff done before dealing with args.
+ * Arguments:
+ * Name of program (string).
+ */
+
+static void
+Initialize1(
+ char *myname
+)
+{
+ time_t tnow;
+ struct tm *nowtm;
+ char *cp, buf[100];
+ extern int gethostname(char *, int); /* not in a system .h file... */
+
+ /* where we try to find data/library files */
+ if (!(tpt_lib=getenv(TPT_LIB))) tpt_lib = DEF_TPT_LIB;
+
+ /* set some global variables */
+ warnings = 1;
+ fold_case = 1;
+ this_prog = myname;
+
+ /* setup global variable mapping */
+ Variables = NewMap(IMS_variables);
+
+ /* set some pre-defined variables */
+ SetMappingNV(Variables, "user", (cp=getenv("USER")) ? cp : "UnknownUser" );
+ time(&tnow);
+ nowtm = localtime(&tnow);
+ strftime(buf, 100, "%a %d %b %Y, %R", nowtm);
+ SetMappingNV(Variables, "date", buf);
+ if (gethostname(buf, 100) < 0) strcpy(buf, "unknown-host");
+ SetMappingNV(Variables, "host", buf);
+ SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
+}
+
+/* Initialization stuff done after dealing with args. */
+
+static void
+Initialize2()
+{
+ SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
+
+ /* If user wants to send output to a file, open the file, and set
+ * the file pointer. Else we send output to standard out. */
+ if (out_file) {
+ if (!(outfp = fopen(out_file, "w"))) {
+ fprintf(stderr, "Could not open output '%s' file for writing.\n%s",
+ out_file, strerror(errno));
+ exit(1);
+ }
+ }
+ else outfp = stdout;
+}
+
+/* ______________________________________________________________________ */
+/* Set a variable. If it is one of the "known" variables, set the
+ * variable in the C code (this program).
+ * Arguments:
+ * Variable name/value string - separated by an '=' (eg, "myname=Sally").
+ */
+static void
+CmdLineSetVariable(
+ char *var
+)
+{
+ char *cp, buf[100], **tok;
+ int n;
+
+ /* Turn '=' into a space, to isolate the name. Then set variable. */
+ strcpy(buf, var);
+ if ((cp=strchr(buf, '='))) {
+ /* we have "var=value" */
+ *cp = ' ';
+ n = 2;
+ tok = Split(buf, &n, 0);
+ /* see if variable name matches one of our internal ones */
+ if (!strcmp(tok[0], "verbose")) verbose = atoi(tok[1]);
+ else if (!strcmp(tok[0], "warnings")) warnings = atoi(tok[1]);
+ else if (!strcmp(tok[0], "foldcase")) fold_case = atoi(tok[1]);
+ else SetMappingNV(Variables, tok[0], tok[1]);
+ }
+ else {
+ fprintf(stderr, "Expected an '=' in variable assignment: %s. Ignored\n",
+ var);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Bounce through arguments, setting variables and flags.
+ * Arguments:
+ * Argc and Argv, as passed to main().
+ */
+static void
+HandleArgs(
+ int ac,
+ char *av[]
+)
+{
+ int c, errflag=0;
+ extern char *optarg;
+ extern int optind;
+
+ while ((c=getopt(ac, av, "df:t:v:o:huSxIl:bHVWi:D:Z")) != -1) {
+ switch (c) {
+ case 't': tranfile = optarg; break;
+ case 'v': do_validate = 1; break;
+ case 'h': do_tree = 1; break;
+ case 'u': do_summ = 1; break;
+ case 'S': do_stats = 1; break;
+ case 'x': do_context = 1; break;
+ case 'I': do_idlist = 1; break;
+ case 'l': tpt_lib = optarg; break;
+ case 'i': start_id = optarg; break;
+ case 'o': out_file = optarg; break;
+ case 'd': do_DATAhack = 1; break;
+ case 'f': BOFTTextThresh = atoi(optarg); break;
+ case 'b': interactive = 1; break;
+ case 'W': warnings = 0; break;
+ case 'V': verbose = 1; break;
+ case 'Z': slave = 1; break;
+ case 'H': DoHelpMessage(); exit(0); break;
+ case 'D': CmdLineSetVariable(optarg); break;
+ case '?': errflag = 1; break;
+ }
+ if (errflag) {
+ fprintf(stderr, "Try '%s -H' for help.\n", this_prog);
+ exit(1);
+ }
+ }
+
+ /* input (ESIS) file name */
+ if (optind < ac) in_file = av[optind];
+
+ /* If doing interactive/browsing, we can't take ESIS from stdin. */
+ if (interactive && !in_file) {
+ fprintf(stderr,
+ "You must specify ESIS file on cmd line for browser mode.\n");
+ exit(1);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Simply print out a help/usage message.
+ */
+
+static char *help_msg[] = {
+ "",
+ " -t file Print translated output using translation spec in <file>",
+ " -v Validate using translation spec specified with -t",
+ " -i id Consider only subtree starting at element with ID <id>",
+ " -b Interactive browser",
+ " -S Print statistics (how often elements occur, etc.)",
+ " -u Print element usage summary (# of children, depth, etc.)",
+ " -x Print context of each element",
+ " -h Print document hierarchy as a tree",
+ " -o file Write output to <file>. Default is standard output.",
+ " -l dir Set library directory to <dir>. (or env. variable TPT_LIB)",
+ " -I List all IDs used in the instance",
+ " -W Do not print warning messages",
+ " -H Print this help message",
+ " -Dvar=val Set variable 'var' to value 'val'",
+ " file Take input from named file. If not specified, assume stdin.",
+ " File should be output from the 'sgmls' program (ESIS).",
+ NULL
+};
+
+static void
+DoHelpMessage()
+{
+ char **s = help_msg;
+ printf("usage: %s [option ...] [file]", this_prog);
+ while (*s) puts(*s++);
+ printf("\nVersion: %s\n", _HeadVeRsIoN_);
+}
+
+/* ______________________________________________________________________ */
+/* Remember an external entity for future reference.
+ * Arguments:
+ * Pointer to entity structure to remember.
+ */
+
+static void
+AddEntity(
+ Entity_t *ent
+)
+{
+ static Entity_t *last_ent;
+
+ if (!Entities) {
+ Malloc(1, Entities, Entity_t);
+ last_ent = Entities;
+ }
+ else {
+ Malloc(1, last_ent->next, Entity_t);
+ last_ent = last_ent->next;
+ }
+ *last_ent = *ent;
+
+}
+
+/* Find an entity, given its entity name.
+ * Arguments:
+ * Name of entity to retrieve.
+ */
+static Entity_t *
+FindEntity(
+ char *ename
+)
+{
+ Entity_t *n;
+ for (n=Entities; n; n=n->next)
+ if (StrEq(ename, n->ename)) return n;
+ return 0;
+}
+
+/* Accumulate lines up to the open tag. Attributes, line number,
+ * entity info, notation info, etc., all come before the open tag.
+ */
+static Element_t *
+AccumElemInfo(
+ FILE *fp
+)
+{
+ char buf[LINESIZE+1];
+ int c;
+ int i, na;
+ char *cp, *atval;
+ Mapping_t a[100];
+ Element_t *e;
+ Entity_t ent, *ent2;
+ char **tok;
+ static int Index=0;
+ static Element_t *last_e;
+
+
+ Calloc(1, e, Element_t);
+ memset(&ent, 0, sizeof ent); /* clean space for entity info */
+
+ /* Also, keep a linked list of elements, so we can easily scan through */
+ if (last_e) last_e->next = e;
+ last_e = e;
+
+ e->index = Index++; /* just a unique number for identification */
+
+ /* in case these are not set for this element in the ESIS */
+ e->lineno = last_lineno;
+ e->infile = last_file;
+
+ na = 0;
+ while (1) {
+ if ((c = getc(fp)) == EOF) break;
+ fgets(buf, LINESIZE, fp);
+ stripNL(buf);
+ switch (c) {
+ case EOF: /* End of input */
+ fprintf(stderr, "Error: Unexpectedly reached end of ESIS.\n");
+ exit(1);
+ break;
+
+ case CMD_OPEN: /* (gi */
+ e->gi = AddElemName(buf);
+ if (na > 0) {
+ Malloc(na, e->atts, Mapping_t);
+ memcpy(e->atts, a, na*sizeof(Mapping_t));
+ e->natts = na;
+ na = 0;
+ }
+ /* Check if this elem has a notation attr. If yes, and there
+ is no notation specified, recall the previous one. (feature
+ of sgmls - it does not repeat notation stuff if we the same
+ is used twice in a row) */
+ if (((atval=FindAttValByName(e, "NAME")) ||
+ (atval=FindAttValByName(e, "ENTITYREF")) ||
+ (atval=FindAttValByName(e, "EXTERNAL"))) && /* HACK */
+ (ent2=FindEntity(atval))) {
+ e->entity = ent2;
+ }
+
+ return e;
+ break;
+
+ case CMD_ATT: /* Aname val */
+ i = 3;
+ tok = Split(buf, &i, 0);
+ if (!strcmp(tok[1], "IMPLIED"))
+ break; /* skip IMPLIED atts. */
+ else if (!strcmp(tok[1], "CDATA"))
+ {
+ /* CDATA attributes must have ESIS escape
+ sequences and SDATA entities expanded. */
+ char *val = ExpandString(tok[2]);
+ a[na].name = AddAttName(tok[0]);
+ a[na].sval = AddAttName(val);
+ free(val);
+ na++;
+ }
+ else if (!strcmp(tok[1], "TOKEN") ||
+ !strcmp(tok[1], "ENTITY") ||!strcmp(tok[1], "NOTATION"))
+ {
+ a[na].name = AddAttName(tok[0]);
+ a[na].sval = AddAttName(tok[2]);
+ na++;
+ }
+ else {
+ fprintf(stderr, "Error: Bad attr line (%d): A%s %s...\n",
+ e->lineno, tok[0], tok[1]);
+ }
+ break;
+
+ case CMD_LINE: /* Llineno */
+ /* These lines come in 2 forms: "L123" and "L123 file.sgml".
+ * Filename is given only at 1st occurance. Remember it.
+ */
+ if ((cp = strchr(buf, ' '))) {
+ cp++;
+ last_file = strdup(cp);
+ }
+ last_lineno = e->lineno = atoi(buf);
+ e->infile = last_file;
+ break;
+
+ case CMD_DATA: /* -data */
+ fprintf(stderr, "Error: Data in AccumElemInfo, line %d:\n%c%s\n",
+ e->lineno, c,buf);
+ /*return e;*/
+ exit(1);
+ break;
+
+ case CMD_D_ATT: /* Dename name val */
+
+ case CMD_NOTATION: /* Nnname */
+ case CMD_PI: /* ?pi */
+ /* This should be reworked soon, as it
+ forces all PI's before the first GI
+ to be ignored. -CSS */
+ break;
+
+ case CMD_EXT_ENT: /* Eename typ nname */
+ i = 3;
+ tok = Split(buf, &i, 0);
+ ent.ename = strdup(tok[0]);
+ ent.type = strdup(tok[1]);
+ ent.nname = strdup(tok[2]);
+ AddEntity(&ent);
+ break;
+ case CMD_INT_ENT: /* Iename typ text */
+ fprintf(stderr, "Error: Got CMD_INT_ENT in AccumElemInfo: %s\n", buf);
+ break;
+ case CMD_SYSID: /* ssysid */
+ ent.sysid = strdup(buf);
+ break;
+ case CMD_PUBID: /* ppubid */
+ ent.pubid = strdup(buf);
+ break;
+ case CMD_FILENAME: /* ffilename */
+ ent.fname = strdup(buf);
+ break;
+
+ case CMD_CLOSE: /* )gi */
+ case CMD_SUBDOC: /* Sename */
+ case CMD_SUBDOC_S: /* {ename */
+ case CMD_SUBDOC_E: /* }ename */
+ case CMD_EXT_REF: /* &name */
+ case CMD_APPINFO: /* #text */
+ case CMD_CONFORM: /* C */
+ default:
+ fprintf(stderr, "Error: Unexpected input in AccumElemInfo, %d:\n%c%s\n",
+ e->lineno, c,buf);
+ exit(1);
+ break;
+ }
+ }
+ fprintf(stderr, "Error: End of AccumElemInfo - should not be here: %s\n",
+ e->gi);
+/* return e;*/
+ exit(1);
+}
+
+/* Read ESIS lines.
+ * Limitation? Max 5000 children per node. (done for efficiency --
+ * should do some malloc and bookkeeping games later).
+ */
+
+static Element_t *
+ReadESIS(
+ FILE *fp,
+ int depth
+)
+{
+ char *buf;
+ int i, c, ncont;
+ Element_t *e;
+ Content_t cont[5000];
+
+ Malloc( LINESIZE+1, buf, char );
+
+ /* Read input stream - the output of "sgmls", called "ESIS". */
+ e = AccumElemInfo(fp);
+ e->depth = depth;
+
+ ncont = 0;
+ while (1) {
+ if ((c = getc(fp)) == EOF) break;
+ switch (c) {
+ case EOF: /* End of input */
+ break;
+
+ case CMD_DATA: /* -data */
+ fgets(buf, LINESIZE, fp);
+ stripNL(buf);
+ if (do_DATAhack && (buf[0] == '\\') && (buf[1] == 'n')) {
+ if ( ! buf[2] )
+ break;
+ buf[0] = ' ';
+ memcpy(&buf[1], &buf[2], strlen(buf)-1);
+ }
+ cont[ncont].ch.data = ExpandString(buf);
+ cont[ncont].type = CMD_DATA;
+ ncont++;
+ break;
+
+ case CMD_PI: /* ?pi */
+ fgets(buf, LINESIZE, fp);
+ stripNL(buf);
+ cont[ncont].type = CMD_PI;
+ cont[ncont].ch.data = strdup(buf);
+ ncont++;
+ break;
+
+ case CMD_CLOSE: /* )gi */
+ fgets(buf, LINESIZE, fp);
+ stripNL(buf);
+ if (ncont) {
+ e->ncont = ncont;
+ Malloc(ncont, e->cont, Content_t);
+ for (i=0; i<ncont; i++) e->cont[i] = cont[i];
+ }
+ free(buf);
+ return e;
+ break;
+
+ case CMD_OPEN: /* (gi */
+/*fprintf(stderr, "+++++ OPEN +++\n");*/
+/* break;*/
+
+ case CMD_ATT: /* Aname val */
+ case CMD_D_ATT: /* Dename name val */
+ case CMD_NOTATION: /* Nnname */
+ case CMD_EXT_ENT: /* Eename typ nname */
+ case CMD_INT_ENT: /* Iename typ text */
+ case CMD_SYSID: /* ssysid */
+ case CMD_PUBID: /* ppubid */
+ case CMD_FILENAME: /* ffilename */
+ ungetc(c, fp);
+ cont[ncont].ch.elem = ReadESIS(fp, depth+1);
+ cont[ncont].type = CMD_OPEN;
+ cont[ncont].ch.elem->parent = e;
+ ncont++;
+ break;
+
+ case CMD_LINE: /* Llineno */
+ fgets(buf, LINESIZE, fp);
+ break; /* ignore these here */
+
+ case CMD_SUBDOC: /* Sename */
+ case CMD_SUBDOC_S: /* {ename */
+ case CMD_SUBDOC_E: /* }ename */
+ case CMD_EXT_REF: /* &name */
+ case CMD_APPINFO: /* #text */
+ case CMD_CONFORM: /* C */
+ default:
+ fgets(buf, LINESIZE, fp);
+ fprintf(stderr, "Error: Unexpected input at %d: '%c%s'\n",
+ e->lineno, c, buf);
+ exit(1);
+ break;
+ }
+ }
+ fprintf(stderr, "Error: End of ReadESIS - should not be here: %s\n", e->gi);
+ free(buf);
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Read input stream, creating a tree in memory of the elements and data.
+ * Arguments:
+ * Filename where instance's ESIS is.
+ */
+static void
+ReadInstance(
+ char *filename
+)
+{
+ int i, n;
+ FILE *fp;
+ Element_t *e;
+ char *idatt;
+
+ if (filename) { /* if we specified input file. else stdin */
+ if ((fp=fopen(filename, "r")) == NULL) {
+ perror(filename);
+ exit(1);
+ }
+ }
+ else fp = stdin;
+ last_file = filename;
+ DocTree = ReadESIS(fp, 0);
+ if (filename) fclose(fp);
+
+ /* Traverse tree, filling in econt and figuring out which child
+ * (ie. what birth order) each element is. */
+ DocTree->my_eorder = -1;
+ for (e=DocTree; e; e=e->next) {
+
+ /* count element children */
+ for (i=0,n=0; i<e->ncont; i++) if (IsContElem(e,i)) n++;
+ if (n > 0) Calloc(n, e->econt, Element_t *);
+ for (i=0; i<e->ncont; i++)
+ if (IsContElem(e,i)) e->econt[e->necont++] = ContElem(e,i);
+
+ /* count data children */
+ for (i=0,n=0; i<e->ncont; i++) if (IsContData(e,i)) n++;
+ if (n > 0) Calloc(n, e->dcont, char *);
+ for (i=0; i<e->ncont; i++)
+ if (IsContData(e,i)) e->dcont[e->ndcont++] = ContData(e,i);
+
+ /* where in child order order */
+ for (i=0; i<e->necont; i++)
+ e->econt[i]->my_eorder = i;
+
+ /* Does this element have an ID? */
+ for (i=0; i<e->natts; i++) {
+ if ((idatt=FindAttValByName(e, "ID"))) {
+ AddID(e, idatt);
+ /* remember ID value for quick reference */
+ e->id = idatt;
+ break;
+ }
+ }
+ }
+ return;
+}
+
+/* ______________________________________________________________________ */
diff --git a/usr.bin/sgmls/instant/tables.c b/usr.bin/sgmls/instant/tables.c
new file mode 100644
index 0000000..54fd211
--- /dev/null
+++ b/usr.bin/sgmls/instant/tables.c
@@ -0,0 +1,2013 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Program to manipulate SGML instances.
+ *
+ * Originally coded for OSF DTD tables, now recoded (fld 3/27/95)
+ * for CALS-type tables (fragment taken from the DocBook DTD). Then,
+ * *really* upgraded to CALS tables by FLD on 5/28/96.
+ *
+ * This module is for handling table markup, printing TeX or tbl
+ * (tbl) markup to the output stream. Also, table markup checking is
+ * done here. Yes, this depends on the DTD, but it makes translation
+ * specs much cleaner (and makes some things possible).
+ *
+ * Incomplete / not implemented / limitations / notes:
+ * vertical alignment (valign attr)
+ * vertical spanning
+ * row separators are for the whole line, not per cell (the prog looks
+ * at rowsep for the 1st cell and applies it to the whole row)
+ * trusts that units in colwidths are acceptable to LaTeX and tbl
+ * "s" is an acceptable shorthand for "span" in model attributes
+ *
+ * A note on use of OutputString(): Strings with backslashes (\) need lots
+ * of backslashes. You have to escape them for the C compiler, and escape
+ * them again for OutputString() itself.
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/tables.c,v 1.11 1996/06/15 03:45:02 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <regexp.h>
+#include "general.h"
+#include "translate.h"
+
+/* text width of page, in inches */
+#define TEXTWIDTH 5.5
+#define MAXCOLS 100
+#define SPAN_NOT 0
+#define SPAN_START 1
+#define SPAN_CONT 2
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+/*table parameters */
+
+#define TBLMAXCOL 30 /* max number of columns in tbl table */
+#define NAMELEN 40 /* max length of a name */
+#define BOFTTHRESHOLD 35 /* text length over which to consider
+ * generating a block of filled text */
+
+
+/* handy declarations */
+
+typedef enum { Left, Right, Center, Justify, Char, Span } tblalign;
+
+typedef enum { TGroup, THead, TFoot, TBody } tblsource; /* source of a spec */
+
+
+/* table line format information structures */
+
+struct tblcolspec {
+
+ char name[NAMELEN]; /* colspec's name */
+ short num; /* column number */
+ tblsource source; /* where defined */
+
+ tblalign align; /* column's alignment */
+ char alignchar; /* character for alignment */
+ short aligncharoff; /* offset for alignment */
+ char colwidth[10]; /* width for column */
+ char colpwidth[10]; /* proportional widths for column */
+ bool colsep; /* separator to right of column? */
+ bool rowsep; /* separator to bottom of column? */
+ short moreRows; /* value for Morerows */
+
+ struct tblcolspec * next; /* next colspec */
+};
+
+struct tblspanspec {
+
+ char name[NAMELEN]; /* spanspec's name */
+ tblsource source; /* where defined */
+
+ struct tblcolspec * start; /* start column */
+ struct tblcolspec * end; /* end column */
+ tblalign align; /* span's alignment */
+ char alignchar; /* character for alignment */
+ short aligncharoff; /* offset for alignment */
+ bool colsep; /* separator to right of column? */
+ bool rowsep; /* separator to bottom of column? */
+
+ struct tblspanspec * next; /* next spanspec */
+};
+
+struct tblformat {
+ short count; /* count of rows matching this spec */
+
+ short cols; /* # of columns */
+ short rowNum; /* row number */
+ char colformat[TBLMAXCOL]; /* per-column formats */
+ char colwidth[TBLMAXCOL][10]; /* per-column widths */
+ char colpwidth[TBLMAXCOL][10]; /* per-column proportional widths */
+ char font[TBLMAXCOL][3]; /* column fonts (headers) */
+ bool colsep[TBLMAXCOL]; /* column separators */
+ bool rowsep[TBLMAXCOL]; /* row separators */
+ short moreRows[TBLMAXCOL]; /* moreRows indicator */
+
+ struct tblformat * next; /* for the next row */
+};
+
+
+/* table state info */
+
+static short tblcols = 0; /* number of columns in the table */
+static short tblrow = 0; /* the current row in the table */
+
+static bool tblTGroupSeen = FALSE; /* seen a TGroup in this table yet? */
+
+static char * tblFrame; /* table frame info */
+static bool tblgcolsep; /* global colsep (in table) */
+static bool tblgrowsep; /* global rowsep (in table) */
+
+static int tblBOFTCount = 0; /* count of bofts that we've created
+ * (per table) */
+int BOFTTextThresh = BOFTTHRESHOLD;
+ /* length of text before we
+ * call it a BOFT */
+static bool tblboft = FALSE; /* within a block of filled text? */
+static bool tblinBOFT = FALSE; /* within a boft now? */
+
+static struct tblformat * formP = 0; /* THead/TBody format lines */
+
+static struct tblcolspec * tblColSpec = 0; /* colspec structure for table */
+static struct tblspanspec * tblSpanSpec = 0; /* spanspec structure for table */
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* these cover the attributes on the Table, TGroup, Colspec elements */
+typedef struct {
+ char *cols;
+ char *align, **align_v;
+ char *colwidth, **colwidth_v;
+ char *colsep, **colsep_v;
+ char *rowsep, **rowsep_v;
+ char *frame;
+ char *orient;
+ int pgwide;
+ int n_align, n_model, n_colwidth, n_colsep;
+ int nc;
+} TableInfo;
+
+
+/* some flags, set when the table tag is processed, used later */
+static int rowsep, siderules;
+static int frametop, framebot, frameall;
+static char basemodel[128]; /* model for table (in formatting language) */
+static int spaninfo[MAXCOLS]; /* 100 columns, max */
+static TableInfo TheTab;
+
+/* forward references */
+void SetTabAtts(Element_t *, TableInfo *, int);
+void FreeTabAtts(TableInfo *);
+void ClearTable(TableInfo *);
+void CheckTable(Element_t *);
+void TblTStart(Element_t *, FILE *);
+void TblTEnd(Element_t *, FILE *);
+void TblTGroup(Element_t *, FILE *);
+void TblTGroupEnd(Element_t *, FILE *);
+void TblTFoot(Element_t *, FILE *);
+void TblBuildFormat(Element_t *, struct tblformat **, tblsource);
+struct tblformat * TblBuild1Format(Element_t *, bool, tblsource);
+char TblGetAlign(short, Element_t *, tblsource);
+char * TblGetWidth(short, Element_t *, bool, tblsource);
+char * TblGetFont(short, Element_t *, tblsource);
+bool TblGetColSep(short, Element_t *, tblsource);
+bool TblGetRowSep(short, Element_t *, tblsource);
+short TblGetMoreRows(short, Element_t *, tblsource);
+bool TblColAdv(short, Element_t *, struct tblformat *, tblsource);
+struct tblcolspec * TblEntryColSpec(short, Element_t *, tblsource);
+struct tblspanspec * TblEntrySpanSpec(short, Element_t *, tblsource);
+bool TblFormatMatch(struct tblformat *, struct tblformat *);
+void TblPrintFormat(FILE *, struct tblformat *);
+void TblTRowStart(Element_t *, FILE *);
+void TblTRowEnd(Element_t *, FILE *);
+void TblTCellStart(Element_t *, FILE *);
+int TblCountContent(Element_t *);
+void TblTCellEnd(Element_t *, FILE *);
+struct tblcolspec * TblDoColSpec(short, Element_t *, struct tblcolspec *, tblsource);
+struct tblspanspec * TblDoSpanSpec(Element_t *, struct tblspanspec *, tblsource);
+struct tblcolspec * TblFindColSpec(char *, tblsource);
+struct tblcolspec * TblFindColNum(short, tblsource);
+struct tblspanspec * TblFindSpanSpec(char *, tblsource);
+void TexTable(Element_t *, FILE *);
+void TexTableCellStart(Element_t *, FILE *);
+void TexTableCellEnd(Element_t *, FILE *);
+void TexTableRowStart(Element_t *, FILE *);
+void TexTableRowEnd(Element_t *, FILE *);
+void TexTableTop(Element_t *, FILE *);
+void TexTableBottom(Element_t *, FILE *);
+
+/* ______________________________________________________________________ */
+/* Hard-coded stuff for CALS-style DTD tables.
+ * Here are the TABLE attributes (for handy reference):
+ *
+ * Table/InformalTable:
+ * Colsep NUMBER separate all columns in table?
+ * Frame (Top|Bottom|Topbot|All|Sides|None) frame style
+ * Orient (Port | Land) orientation
+ * Pgwide NUMBER wide table?
+ * Rowsep NUMBER separate all rows in the table?
+ * Tabstyle NMTOKEN FOSI table style
+ *
+ * TGroup:
+ * Align (Left|Right|Center|Justify|Char) alignment of cols
+ * Char CDATA Alignment specifier
+ * Charoff NUTOKEN "" ""
+ * Cols NUMBER number of columns
+ * Colsep NUMBER separate all columns in tgroup?
+ * Rowsep NUMBER separate all rows in tgroup?
+ * TGroupstyle NMTOKEN FOSI table group style
+ *
+ * Colspec:
+ * Align (Left|Right|Center|Justify|Char) entry align
+ * Char CDATA Alignment specifier
+ * Charoff NUTOKEN "" ""
+ * Colname NMTOKEN Column identifier
+ * Colnum NUMBER number of column
+ * Colsep NUMBER separate this col from next?
+ * Colwidth CDATA width spec
+ * Rowsep NUMBER serarate entry from following row?
+ *
+ * SpanSpec:
+ * Align (Left|Right|Center|Justify|Char) entry align
+ * Char CDATA Alignment specifier
+ * Charoff NUTOKEN "" ""
+ * Colsep NUMBER separate this col from next?
+ * Nameend NMTOKEN name of rightmost col of a span
+ * Namest NMTOKEN name of leftmost col of a span
+ * Rowsep NUMBER serarate entry from following row?
+ * Spanname NMTOKEN name of a horiz. span
+ *
+ * THead/TFoot/TBody:
+ * VAlign (Top | Middle | Bottom) group placement
+ *
+ * Row:
+ * Rowsep NUMBER separate this row from next?
+ * VAlign (Top | Middle | Bottom) row placement
+ *
+ * Entry:
+ * Align (Left|Right|Center|Justify|Char) entry align
+ * Char CDATA Alignment specifier
+ * Charoff NUTOKEN "" ""
+ * Colname NMTOKEN Column identifier
+ * Colsep NUMBER separate this col from next?
+ * Morerows NUMBER number of addn'l rows in vert straddle
+ * Nameend NMTOKEN name of rightmost col of a span
+ * Namest NMTOKEN name of leftmost col of a span
+ * Rotate NUMBER 90 degree rotation counterclockwise to table?
+ * Rowsep NUMBER serarate entry from following row?
+ * Spanname NMTOKEN name of a horiz. span
+ * VAlign (Top | Middle | Bottom) text vert alignment
+ *
+ *
+ ** OBSOLETE OSF DTD FORM (still used for TeX form):
+ ** Usage in transpec: _calstable [tex|check|clear] ['aspect']
+ ** where 'aspect' is:
+ ** rowstart stuff to do at start of a row (tests for spanning)
+ ** rowend stuff to do at end of a row (eg, rules, etc.)
+ ** cellstart stuff to do at start of a cell (eg, handle actual
+ ** spanning instructions, etc.)
+ ** cellend stuff to do at end of a cell (eg, cell separator)
+ ** top stuff to do at top of the table
+ ** (like whether or not it needs a starting horiz rule)
+ ** bottom stuff to do at bottom of the table
+ ** (like whether or not it needs an ending horiz rule)
+ ** (nothing) the 'cols' param to LaTeX's \begin{tabular}[pos]{cols}
+ ** or 'options' and 'formats' part in tbl
+ *
+ *
+ * New tbl form:
+ * Usage in transpec: _calstable [tbl] ['aspect']
+ * where 'aspect' is:
+ * tablestart start a table and do style info
+ * tableend end the table and clean up
+ * tablegroup table TGroup (.T& if not 1st, line format info)
+ * tablegroupend end a TGroup
+ * tablefoot TFoot within a TGroup
+ * rowstart start of a row
+ * rowend end of a row
+ * entrystart start of an entry (block of filled text, if
+ * appropriate)
+ * entryend end of a cell (eg, cell separator)
+ */
+
+/* Procedure to
+ * Arguments:
+ * Pointer to element under consideration.
+ * FILE pointer to where to write output.
+ * Vector of args to _osftable
+ * Count of args to _osftable
+ */
+void
+CALStable(
+ Element_t *e,
+ FILE *fp,
+ char **av,
+ int ac
+)
+{
+ /* Check params and dispatch to appropriate routine */
+
+ if (!strcmp(av[1], "tbl")) {
+
+ if (ac > 2) {
+ if (!strcmp(av[2], "tablestart")) TblTStart(e, fp);
+ else if (!strcmp(av[2], "tableend")) TblTEnd(e, fp);
+ else if (!strcmp(av[2], "tablegroup")) TblTGroup(e, fp);
+ else if (!strcmp(av[2], "tablegroupend")) TblTGroupEnd(e, fp);
+ else if (!strcmp(av[2], "tablefoot")) TblTFoot(e, fp);
+ else if (!strcmp(av[2], "rowstart")) TblTRowStart(e, fp);
+ else if (!strcmp(av[2], "rowend")) TblTRowEnd(e, fp);
+ else if (!strcmp(av[2], "entrystart")) TblTCellStart(e, fp);
+ else if (!strcmp(av[2], "entryend")) TblTCellEnd(e, fp);
+ else fprintf(stderr, "Unknown %s table instruction: %s\n",
+ av[1], av[2]);
+ }
+ else {
+ fprintf(stderr, "Incomplete %s table instruction\n");
+ }
+ }
+
+ else if (!strcmp(av[1], "tex")) {
+
+ if (ac > 1 && !strcmp(av[1], "check")) CheckTable(e);
+
+ else
+ if (ac > 1 && !strcmp(av[1], "clear")) ClearTable(&TheTab);
+
+ if (ac > 2) {
+ if (!strcmp(av[2], "cellstart")) TexTableCellStart(e, fp);
+ else if (!strcmp(av[2], "cellend")) TexTableCellEnd(e, fp);
+ else if (!strcmp(av[2], "rowstart")) TexTableRowStart(e, fp);
+ else if (!strcmp(av[2], "rowend")) TexTableRowEnd(e, fp);
+ else if (!strcmp(av[2], "top")) TexTableTop(e, fp);
+ else if (!strcmp(av[2], "bottom")) TexTableBottom(e, fp);
+ else fprintf(stderr, "Unknown %s table instruction: %s\n",
+ av[1], av[2]);
+ }
+ else TexTable(e, fp);
+ }
+
+ else fprintf(stderr, "Unknown table type: %s\n", av[1]);
+
+}
+
+/* ClearTable -- start a new table process
+ *
+ */
+
+
+void
+ClearTable( TableInfo * t )
+{
+ memset(t, 0, sizeof(TableInfo));
+}
+
+
+/* ______________________________________________________________________ */
+/* Set values of the our internal table structure based on the table's
+ * attributes. (This is called for tables, tgroups, colspecs, and rows,
+ * since tables and rows share many of the same attributes.)
+ * Arguments:
+ * Pointer to element under consideration.
+ * Pointer table info structure which will be filled in.
+ * Flag saying whether or not to set global variables based on attrs.
+ */
+void
+SetTabAtts(
+ Element_t *e,
+ TableInfo *t,
+ int set_globals
+)
+{
+ char *at;
+ Element_t * ep;
+
+ /* remember values of attributes */
+ if ((at = FindAttValByName(e, "ALIGN"))) t->align = at;
+ if ((at = FindAttValByName(e, "COLWIDTH"))) t->colwidth = at;
+ if ((at = FindAttValByName(e, "COLSEP"))) t->colsep = at;
+ if ((at = FindAttValByName(e, "FRAME"))) t->frame = at;
+ if ((at = FindAttValByName(e, "COLS"))) t->cols = at;
+
+ /* Set some things for later when processing this table */
+ if (set_globals) {
+
+ rowsep = 1;
+ frametop = framebot = 1; /* default style */
+
+ /* For now we look at the first number of rowsep - it controls the
+ * horiz rule for then entire row. (not easy to specify lines that
+ * span only some columns in tex or tbl. */
+ if ((at = FindAttValByName(e, "ROWSEP"))) rowsep = atoi(at);
+ }
+
+ if (t->frame) {
+ /* Top|Bottom|Topbot|All|Sides|None */
+ if (!strcmp(t->frame, "NONE") || !strcmp(t->frame, "SIDES"))
+ frametop = framebot = 0;
+ else if (!strcmp(t->frame, "TOP")) framebot = 0;
+ else if (!strcmp(t->frame, "BOTTOM")) frametop = 0;
+ }
+
+ /* tbl and tex like lower case for units. convert. */
+ if (t->colwidth) {
+ char *cp;
+ for (cp=t->colwidth; *cp; cp++)
+ if (isupper(*cp)) *cp = tolower(*cp);
+ }
+
+ /* Now, split (space-separated) strings into vectors. Hopefully, the
+ * number of elements in each vector matches the number of columns.
+ */
+ t->align_v = Split(t->align, &t->n_align, S_STRDUP|S_ALVEC);
+ t->colwidth_v = Split(t->colwidth, &t->n_colwidth, S_STRDUP|S_ALVEC);
+ t->colsep_v = Split(t->colsep, &t->n_colsep, S_STRDUP|S_ALVEC);
+
+ /* Determin the _numeric_ number of columns, "nc". MUST be specified
+ * in Cols attribute of TGroup element.
+ */
+ if (t->cols) t->nc = atoi(t->cols);
+}
+
+/* ______________________________________________________________________ */
+
+/* Free the storage of info use by the table info structure. (not the
+ * structure itself, but the strings its elements point to)
+ * Arguments:
+ * Pointer table info structure to be freed.
+ */
+void
+FreeTabAtts(
+ TableInfo *t
+)
+{
+ if (!t) return;
+ if (t->align_v) free(*t->align_v);
+ if (t->colwidth_v) free(*t->colwidth_v);
+ if (t->colsep_v) free(*t->colsep_v);
+}
+
+/* ______________________________________________________________________ */
+/* Check the attributes and children of the table pointed to by e.
+ * Report problems and inconsistencies to stderr.
+ * Arguments:
+ * Pointer to element (table) under consideration.
+ */
+
+void
+CheckTable(
+ Element_t *e
+)
+{
+ int pr_loc=0; /* flag to say if we printed location */
+ int i, r, c;
+ Element_t *ep, *ep2;
+ float wt;
+ char *tpref = "Table Check"; /* prefix for err messages */
+ char *ncolchk =
+ "Table Check: %s ('%s') has wrong number of tokens. Expecting %d.\n";
+
+ if (strcmp(e->gi, "TABLE") &&
+ strcmp(e->gi, "INFORMALTABLE") &&
+ strcmp(e->gi, "TGROUP") &&
+ strcmp(e->gi, "COLSPEC") &&
+ strcmp(e->gi, "ROW") ) {
+ fprintf(stderr, "%s: Not pointing to a table element(%s)!\n",
+ tpref, e->gi);
+ return;
+ }
+
+ FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
+ SetTabAtts(e, &TheTab, 1); /* look at attributes */
+
+#if FALSE
+ /* NCOLS attribute set? */
+ if (!TheTab.ncols) {
+ pr_loc++;
+ fprintf(stderr, "%s: NCOLS attribute missing. Inferred as %d.\n",
+ tpref, TheTab.nc);
+ }
+
+ /* ALIGN attribute set? */
+ if (!TheTab.align) {
+ pr_loc++;
+ fprintf(stderr, "%s: ALIGN attribute missing.\n", tpref);
+ }
+
+ /* See if the number of cells in each row matches */
+ for (r=0; r<e->necont && (ep=e->econt[r]); r++) { /* each TGroup */
+ for (i=0; i<ep->necont && (ep2=ep->econt[i]); i++) {
+ if ( strcmp(ep2->gi, "TBODY") ) /* only TBodys */
+ continue;
+
+ for (c=0; c<ep2->necont; c++) {
+ if (ep2->econt[c]->necont != TheTab.nc) {
+ pr_loc++;
+ fprintf(stderr, "%s: COLS (%d) differs from actual number of cells (%d) in row %d.\n",
+ tpref, TheTab.nc, ep2->econt[c]->necont, c);
+ }
+ }
+ }
+ }
+#endif
+
+ /* Check ALIGN */
+ if (TheTab.align) {
+ if (TheTab.nc != TheTab.n_align) { /* number of tokens OK? */
+ pr_loc++;
+ fprintf(stderr, ncolchk, "ALIGN", TheTab.align, TheTab.nc);
+ }
+ else { /* values OK? */
+ for (i=0; i<TheTab.nc; i++) {
+ if (*TheTab.align_v[i] != 'C' && *TheTab.align_v[i] != 'L' &&
+ *TheTab.align_v[i] != 'R') {
+ pr_loc++;
+ fprintf(stderr, "%s: ALIGN (%d) value wrong: %s\n",
+ tpref, i, TheTab.align_v[i]);
+ }
+ }
+ }
+ }
+
+ /* check COLWIDTH */
+ if (TheTab.colwidth) {
+ if (TheTab.nc != TheTab.n_colwidth) { /* number of tokens OK? */
+ pr_loc++;
+ fprintf(stderr, ncolchk, "COLWIDTH", TheTab.colwidth, TheTab.nc);
+ }
+ else { /* values OK? */
+ for (i=0; i<TheTab.nc; i++) {
+
+ /* check that the units after the numbers are OK
+ we want "in", "cm".
+ */
+ }
+ }
+ }
+
+ /* check COLSEP */
+ if (TheTab.colsep) {
+ if (TheTab.nc != TheTab.n_colsep) { /* number of tokens OK? */
+ pr_loc++;
+ fprintf(stderr, ncolchk, "COLSEP", TheTab.colsep, TheTab.nc);
+ }
+ else { /* values OK? */
+ for (i=0; i<TheTab.nc; i++) {
+ }
+ }
+ }
+
+ if (pr_loc) {
+ fprintf(stderr, "%s: Above problem in table located at:\n", tpref);
+ PrintLocation(e, stderr);
+ }
+}
+
+/* ______________________________________________________________________ */
+
+/* Look at colspec attribute for spanning. If set, remember info for when
+ * doing the cells. Called by TblTableRowStart() and TexTableRowStart().
+ * Arguments:
+ * Pointer to element (row) under consideration.
+ */
+int
+check_for_spans(
+ Element_t *e
+)
+{
+ char *at;
+ char **spans;
+ int n, i, inspan;
+
+#if FALSE /* NOT IMPLEMENTED RIGHT NOW */
+
+ /* See if COLSPEC element present */
+ for (i=0; i < e->necont; i++) {
+
+ }
+
+
+ if ((at = FindAttValByName(e, "MODEL"))) {
+
+ /* Split into tokens, then look at each for the word "span" */
+ n = TheTab.nc;
+ spans = Split(at, &n, S_STRDUP|S_ALVEC);
+
+ /* Mark columns as start-of-span, in-span, or not spanned. Remember
+ * in at list, "spaningo". (Span does not make sense in 1st column.)
+ */
+ for (i=1,inspan=0; i<n; i++) {
+ if (StrEq(spans[i], "span") || StrEq(spans[i], "s")) {
+ if (inspan == 0) spaninfo[i-1] = SPAN_START;
+ spaninfo[i] = SPAN_CONT;
+ inspan = 1;
+ }
+ else {
+ spaninfo[i] = SPAN_NOT;
+ inspan = 0;
+ }
+ }
+ free(*spans); /* free string */
+ free(spans); /* free vector */
+ spaninfo[TheTab.nc] = SPAN_NOT; /* after last cell */
+ return 1;
+ }
+ /* if model not set, mark all as not spanning */
+ else
+
+#endif /* NOT CURRENTLY IMPLEMENTED */
+
+ for (i=0; i<MAXCOLS; i++) spaninfo[i] = SPAN_NOT;
+ return 0;
+}
+
+/* ______________________________________________________________________ */
+/* Do the "right thing" for the table spec for TeX tables. This will
+ * generate the arg to \begin{tabular}[xxx].
+ * Arguments:
+ * Pointer to element (table) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTable(
+ Element_t *e,
+ FILE *fp
+)
+{
+ int i, n;
+ float tot;
+ char *cp, wbuf[1500], **widths=0, **widths_v=0;
+
+ FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
+ SetTabAtts(e, &TheTab, 1); /* look at attributes */
+ SetTabAtts(e->econt[0], &TheTab, 1); /* attrs of TGroup */
+
+ /* Figure out the widths, based either on "colwidth".
+ */
+ if (TheTab.colwidth && TheTab.nc == TheTab.n_colwidth) {
+ widths = TheTab.colwidth_v;
+ }
+
+ siderules = 1;
+ if (TheTab.frame)
+ if (strcmp(TheTab.frame, "ALL") && strcmp(TheTab.frame, "SIDES"))
+ siderules = 0;
+
+ if (siderules) OutputString("|", fp, 1);
+ for (i=0; i<TheTab.nc; i++) {
+ /* If width specified, use it; else if align set, use it; else left. */
+ if (widths && widths[i][0] != '0' && widths[i][1] != EOS) {
+ fprintf(fp, "%sp{%s}", (i?" ":""), widths[i]);
+ }
+ else if (TheTab.align && TheTab.nc == TheTab.n_align) {
+ fprintf(fp, "%s%s", (i?" ":""), TheTab.align_v[i]);
+ }
+ else
+ fprintf(fp, "%sl", (i?" ":""));
+ /* See if we want column separators. */
+ if (TheTab.colsep) {
+
+ if ( (i+1) < TheTab.nc ) {
+ if ( *TheTab.colsep_v[i] == '1' ) {
+ fprintf(fp, " |");
+ }
+ if ( *TheTab.colsep_v[i] == '2' ) {
+ fprintf(fp, " ||");
+ }
+ }
+
+ }
+ }
+ if (siderules) OutputString("|", fp, 1);
+
+ if (widths_v) free(widths_v);
+}
+
+/*
+ * Arguments:
+ * Pointer to element (cell) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTableCellStart(
+ Element_t *e,
+ FILE *fp
+)
+{
+ int n, i;
+ char buf[50], *at;
+
+ if (spaninfo[e->my_eorder] == SPAN_START) {
+ for (i=e->my_eorder+1,n=1; ; i++) {
+ if (spaninfo[i] == SPAN_CONT) n++;
+ else break;
+ }
+ sprintf(buf, "\\\\multicolumn{%d}{%sc%s}", n,
+ (siderules?"|":""), (siderules?"|":""));
+ OutputString(buf, fp, 1);
+ }
+#ifdef New
+ if ((at = FindAttValByName(e->parent, "ALIGN"))) {
+ /* no span, but user wants to change the alignment */
+ h_v = Split(wbuf, 0, S_ALVEC|S_STRDUP);
+ OutputString("\\\\multicolumn{1}{%sc%s}", n,
+ fp, 1);
+ }
+#endif
+
+ if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("{", fp, 1);
+}
+
+/*
+ * Arguments:
+ * Pointer to element (cell) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTableCellEnd(
+ Element_t *e,
+ FILE *fp
+)
+{
+ if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("} ", fp, 1);
+
+ /* do cell/col separators */
+ if (e->my_eorder < (TheTab.nc-1)) {
+ if (spaninfo[e->my_eorder] == SPAN_NOT ||
+ spaninfo[e->my_eorder+1] != SPAN_CONT)
+ OutputString("& ", fp, 1);
+ }
+}
+
+/* Look at model for spanning. If set, remember it for when doing the cells.
+ * Arguments:
+ * Pointer to element (row) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTableRowStart(
+ Element_t *e,
+ FILE *fp
+)
+{
+ check_for_spans(e);
+}
+
+/*
+ * Arguments:
+ * Pointer to element (row) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTableRowEnd(
+ Element_t *e,
+ FILE *fp
+)
+{
+ char *at;
+
+ /* check this row's attributes */
+ if ((at = FindAttValByName(e, "ROWSEP"))) {
+ if (at[0] == '1') OutputString("\\\\\\\\[2mm] \\\\hline ", fp, 1);
+ }
+ else if (rowsep) OutputString("\\\\\\\\ ", fp, 1);
+ else
+ OutputString("\\\\\\\\ ", fp, 1);
+
+}
+
+/*
+ * Arguments:
+ * Pointer to element (table) under consideration.
+ * FILE pointer to where to write output.
+ */
+void
+TexTableTop(Element_t *e, FILE *fp)
+{
+ if (frametop) OutputString("\\\\hline", fp, 1);
+}
+
+void
+TexTableBottom(Element_t *e, FILE *fp)
+{
+ if (framebot) OutputString("\\\\hline", fp, 1);
+}
+
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ___________________________| |____________________________ */
+/* ___________________________| TBL STUFF |____________________________ */
+/* ___________________________| |____________________________ */
+/* ___________________________|_____________|____________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+/* ______________________________________________________________________ */
+
+
+
+/* TblTStart() -- start a table and do style information
+ *
+ * TO DO:
+ *
+ * do .TS
+ * find global rowsep and colsep
+ */
+
+
+void
+TblTStart(Element_t * ep,
+ FILE * fP)
+{
+ register char * cp;
+ register struct Element_t * ep2;
+
+
+
+ OutputString("^.TS^", fP, 1);
+
+ tblTGroupSeen = FALSE;
+ tblinBOFT = FALSE; /* within a boft? */
+ tblBOFTCount = 0; /* count of Blocks of Filled Text that
+ * we've created */
+
+ tblgcolsep = (cp = FindAttValByName(ep, "COLSEP")) && !strcmp(cp, "1");
+ tblgrowsep = (cp = FindAttValByName(ep, "ROWSEP")) && !strcmp(cp, "1");
+}
+
+/* TblTEnd() -- end a table and do any cleanup
+ *
+ * TO DO:
+ *
+ * do .TE
+ *
+ * deallocate format line info
+ */
+
+
+
+void
+TblTEnd(Element_t * ep,
+ FILE * fP)
+{
+ register struct tblformat * ffp, * ffp2;
+
+
+ if ( tblBOFTCount > 31 ) {
+ fprintf(stderr, "# warning, line %d: created %d blocks of filled text in one table\n",
+ ep->lineno, tblBOFTCount);
+ fprintf(stderr, "#\t\t(31 is the limit in some systems)\n");
+ }
+
+ OutputString("^.TE^", fP, 1);
+
+ for ( ffp=formP; ffp; ffp=ffp2 ) {
+ ffp2 = ffp->next;
+ free(ffp); /* clear entire list */
+ }
+ formP = 0;
+}
+
+/* TblTTGroup() -- do body work (row format info)
+ *
+ * TO DO:
+ *
+ * set number of columns
+ *
+ * if this is the first TGroup of this table, do style info:
+ * a. alignment
+ * b. defaults: tab
+ * c. box vx allbox
+ *
+ * do format info:
+ * a. generate tableformat structure
+ * b. output it
+ *
+ * prepare structures for colspecs and spanspecs
+ *
+ */
+
+
+
+void
+TblTGroup(Element_t * ep,
+ FILE * fP)
+{
+ register int i, j, k;
+ register char * cp, * cp2;
+ register Element_t * ep2, ep3;
+ register struct tblcolspec * tcsp, * tcsp2;
+ register struct tblspanspec * tssp, * tssp2;
+
+
+ tblColSpec = 0; /* make sure they're clear */
+ tblSpanSpec = 0;
+
+ /* set the number of columns */
+
+ tblcols = atoi(FindAttValByName(ep, "COLS"));
+
+ /* do colspecs */
+
+ tblColSpec = tcsp = TblDoColSpec(0, ep, 0, TGroup);
+ /* do TGroup first -- it becomes the default */
+
+ for ( i=0, k=1; i < ep->necont; i++ ) {
+
+ if ( !strcmp(ep->econt[i]->gi, "COLSPEC") ) {
+ tcsp2 = TblDoColSpec(k, ep->econt[i], tblColSpec, TGroup);
+ tcsp->next = tcsp2; /* put into list */
+ tcsp = tcsp2;
+ k = tcsp2->num + 1; /* next column number */
+ }
+
+ if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
+ ep2 = ep->econt[i];
+ for ( j=0, k=1; j < ep2->necont; j++ ) {
+ if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
+ tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, THead);
+ tcsp->next = tcsp2; /* put into list */
+ tcsp = tcsp2;
+ k = tcsp2->num + 1; /* next column number */
+ }
+ }
+ }
+
+ if ( !strcmp(ep->econt[i]->gi, "TFOOT") ) {
+ ep2 = ep->econt[i];
+ for ( j=0, k=1; j < ep2->necont; j++ ) {
+ if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
+ tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TFoot);
+ tcsp->next = tcsp2; /* put into list */
+ tcsp = tcsp2;
+ k = tcsp2->num + 1; /* next column number */
+ }
+ }
+ }
+
+ if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
+ ep2 = ep->econt[i];
+ for ( j=0, k=1; j < ep2->necont; j++ ) {
+ if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
+ tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TBody);
+ tcsp->next = tcsp2; /* put into list */
+ tcsp = tcsp2;
+ k = tcsp2->num + 1; /* next column number */
+ }
+ }
+ }
+ }
+
+ /* do spanspecs */
+
+ tblSpanSpec = tssp = TblDoSpanSpec(ep, 0, TGroup);
+ /* do TGroup first -- it becomes the default */
+
+ for ( i=0; i < ep->necont; i++ ) {
+ if ( !strcmp(ep->econt[i]->gi, "SPANSPEC") ) {
+ tssp2 = TblDoSpanSpec(ep->econt[i], tblSpanSpec, TGroup);
+ tssp->next = tssp2; /* put into list */
+ tssp = tssp2;
+ }
+ }
+
+
+ /* if this is the first TGroup in this table, do style stuff */
+
+ if ( ! tblTGroupSeen ) {
+
+ OutputString("tab(\007)", fP, 1);
+
+ ep2 = ep->parent;
+ if ( ! (tblFrame = FindAttValByName(ep2, "FRAME")) )
+ tblFrame = "";
+
+ if ( !strcmp(tblFrame, "ALL") ) {
+ if ( tcsp->colsep && tcsp->rowsep )
+ OutputString(" allbox", fP, 1);
+ else
+ OutputString(" box", fP, 1);
+ }
+
+ if ( (cp = FindAttValByName(ep, "ALIGN")) &&
+ !strcmp(cp, "CENTER") ) {
+ OutputString(" center", fP, 1);
+ }
+
+ OutputString(";\n", fP, 1);
+
+ tblTGroupSeen = TRUE;
+ }
+
+
+ /* do format stuff -- step through all THead rows then all TBody
+ * rows. Build a list of tblformats that describe all of them.
+ * then output the resulting list.
+ */
+
+ for ( i=0; i < ep->necont; i++ ) {
+ if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
+ TblBuildFormat(ep->econt[i], &formP, THead);
+ /* add in those rows */
+ break;
+ }
+ }
+
+ for ( i=0; i < ep->necont; i++ ) {
+ if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
+ TblBuildFormat(ep->econt[i], &formP, TBody);
+ /* add in those rows */
+ break;
+ }
+ }
+
+ TblPrintFormat(fP, formP);
+
+ tblrow = 0; /* the current row within this format */
+}
+
+/* TblTGroupEnd() -- end a TGroup
+ *
+ * TO DO:
+ *
+ * deallocate colspecs and spanspecs
+ */
+
+
+void
+TblTGroupEnd(Element_t * ep,
+ FILE * fP)
+{
+ register struct tblcolspec * tcsp, * tcsp2;
+ register struct tblspanspec * tssp, * tssp2;
+
+
+ for ( tcsp=tblColSpec; tcsp; tcsp=tcsp2 ) {
+ tcsp2 = tcsp->next;
+ free(tcsp);
+ }
+ for ( tssp=tblSpanSpec; tssp; tssp=tssp2 ) {
+ tssp2 = tssp->next;
+ free(tssp);
+ }
+}
+
+/* TblTTFoot() -- do body foot work (row format info)
+ *
+ * TO DO:
+ *
+ * do format info:
+ * a. generate tableformat structure
+ * i. if it is only 1 line long and matches the
+ * prevailing format, just output rows.
+ * ii. else, output a .T& and the new format specs
+ */
+
+
+
+void
+TblTFoot(Element_t * ep,
+ FILE * fP)
+{
+ register struct tblformat * ffp, * ffp2;
+ static struct tblformat * tfp, * tfp2;
+
+
+ TblBuildFormat(ep, &tfp, TFoot); /* gen format for the foot */
+
+ for ( tfp2=formP; tfp2 && tfp2->next; tfp2=tfp2->next )
+ ;
+
+ if ( tfp->next || !TblFormatMatch(tfp, tfp2) ) {
+
+ for ( ffp=formP; ffp; ffp=ffp2 ) {
+ ffp2 = ffp->next;
+ free(ffp); /* clear entire list */
+ }
+
+ formP = tfp; /* this becomes the prevailing format */
+
+ OutputString("^.T&^", fP, 1);
+ TblPrintFormat(fP, formP);
+ }
+
+ tblrow = 0; /* the current row within this format */
+}
+
+/* TblBuildFormat() -- build a format structure out of a set of
+ * rows and columns
+ *
+ */
+
+
+void
+TblBuildFormat(Element_t * ep, /* parent of rows.. */
+ struct tblformat ** fp, /* pointer to head of struct we're
+ * building */
+ tblsource source) /* type of record */
+{
+ register int i;
+ register struct tblformat * lfp; /* "current" format */
+ register struct tblformat * nfp; /* the next format */
+
+
+ for ( lfp= *fp; lfp && lfp->next; lfp=lfp->next )
+ ; /* find end of format list */
+
+ for ( i=0; i < ep->necont; i++ )
+ if ( !strcmp(ep->econt[i]->gi, "ROW") )
+ break; /* find where rows start */
+
+ for ( ; i < ep->necont; i++ ) {
+
+ nfp = TblBuild1Format(ep->econt[i], FALSE, source);
+ /* do one row */
+
+ if ( !lfp )
+ lfp = *fp = nfp; /* first one */
+ else
+ if ( TblFormatMatch(lfp, nfp) )
+ lfp->count++; /* matches */
+ else {
+ lfp->count = 1; /* only 1 so far */
+ lfp->next = nfp; /* new one */
+ lfp = nfp;
+ }
+ }
+}
+
+/* TblBuild1Format() -- build one row's worth of format information
+ *
+ */
+
+
+
+struct tblformat *
+TblBuild1Format(Element_t * rp, /* the row to deal with */
+ bool addinRowsep, /* insert rowsep into model? */
+ tblsource source) /* type type of row */
+{
+ register int i;
+ register bool allProp;
+ float totalProp;
+ register struct tblformat * tfp;
+ register Element_t * ep; /* entry pointer */
+
+
+ Calloc(1, tfp, struct tblformat);
+ tfp->cols = tblcols;
+ ep = (rp->necont) ? rp->econt[0] : 0; /* first entry */
+ allProp = TRUE;
+ totalProp = 0;
+
+ for ( i=1; i <= tblcols; i++ ) {
+ tfp->colformat[i] = TblGetAlign(i, ep, source);
+ strcpy(tfp->colwidth[i], TblGetWidth(i, ep, TRUE, source));
+ strcpy(tfp->colpwidth[i], TblGetWidth(i, ep, FALSE, source));
+ if ( allProp ) {
+ allProp = tfp->colpwidth[i][0];
+ totalProp += atof(tfp->colpwidth[i]);
+ }
+ strcpy(tfp->font[i], TblGetFont(i, ep, source));
+ tfp->colsep[i] = tblgcolsep || TblGetColSep(i, ep, source);
+ if ( addinRowsep )
+ tfp->rowsep[i] = tblgrowsep || TblGetRowSep(i, ep, source);
+ tfp->moreRows[i] = TblGetMoreRows(i, ep, source);
+
+ if ( (i < rp->necont) && TblColAdv(i, ep, tfp, source) ) {
+ ep = rp->econt[i];
+ }
+ }
+
+ /* turn proportional widths into real widths */
+
+ if ( allProp ) {
+ for ( i=1; i <= tblcols; i++ ) {
+ sprintf(tfp->colwidth[i], "%fi",
+ (atof(tfp->colpwidth[i]) / totalProp) * TEXTWIDTH);
+ }
+ }
+
+ return tfp;
+}
+
+/* TblGetAlign() -- get alignment spec for a entry
+ *
+ */
+
+
+char
+TblGetAlign(short col, /* column number */
+ Element_t * entry, /* the entry */
+ tblsource source) /* context */
+{
+ register struct tblcolspec * tcsp;
+ register struct tblspanspec * tssp;
+ register tblalign talign;
+
+
+ if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
+ talign = tssp->align;
+ free(tssp);
+ } else
+ if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
+ talign = tcsp->align;
+ free(tcsp);
+ } else {
+ return 'l';
+ }
+
+ switch ( talign ) {
+ case Left: return 'l';
+ case Right: return 'r';
+ case Center: return 'c';
+ case Justify: return 'l';
+ case Char: return 'd';
+ case Span: return 's';
+ }
+}
+
+/* TblGetWidth() -- get width spec, if any, for a entry
+ *
+ */
+
+
+char *
+TblGetWidth(short col, /* column number */
+ Element_t * entry, /* the entry */
+ bool literal, /* literal (or proportional) */
+ tblsource source) /* context */
+{
+ register struct tblcolspec * tcsp;
+ register struct tblspanspec * tssp;
+ static char colWidth[10];
+
+
+ colWidth[0] = 0;
+
+ if ( entry &&
+ (tcsp = TblEntryColSpec(col, entry, source)) &&
+ tcsp->colwidth[0] ) {
+
+ if ( !strstr(tcsp->colwidth, "*") ) {
+ if ( literal )
+ strcpy(colWidth, tcsp->colwidth);
+ } else {
+ if ( ! literal )
+ strcpy(colWidth, tcsp->colwidth);
+ }
+ free(tcsp);
+ }
+
+ return colWidth;
+}
+
+/* TblGetFont() -- get font spec, if any, for a entry
+ *
+ */
+
+
+char *
+TblGetFont(short col, /* column number */
+ Element_t * entry, /* the entry */
+ tblsource source) /* context */
+{
+ register struct tblcolspec * tcsp;
+ register struct tblspanspec * tssp;
+
+
+ return "";
+}
+
+/* TblGetColSep() -- get column separater spec, if any, for a entry
+ *
+ */
+
+
+bool
+TblGetColSep(short col, /* column number */
+ Element_t * entry, /* the entry */
+ tblsource source) /* context */
+{
+ register struct tblcolspec * tcsp;
+ register struct tblspanspec * tssp;
+ register bool colsep;
+
+
+ if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
+ colsep = tssp->colsep;
+ free(tssp);
+ } else
+ if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
+ colsep = tcsp->colsep;
+ free(tcsp);
+ } else
+ colsep = FALSE;
+
+ return colsep;
+}
+
+/* TblGetRowSep() -- get row separater spec, if any, for a entry
+ *
+ */
+
+
+bool
+TblGetRowSep(short col, /* column number */
+ Element_t * entry, /* the entry */
+ tblsource source) /* context */
+{
+ register struct tblcolspec * tcsp;
+ register struct tblspanspec * tssp;
+ register bool rowsep;
+
+ if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
+ rowsep = tssp->rowsep;
+ free(tssp);
+ } else
+ if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
+ rowsep = tcsp->rowsep;
+ free(tcsp);
+ } else {
+ rowsep = FALSE;
+ }
+
+ return rowsep;
+}
+
+/* TblGetmoreRows() -- get moreRows value
+ *
+ */
+
+
+bool
+TblGetMoreRows(short col, /* column number */
+ Element_t * entry, /* the entry */
+ tblsource source) /* context */
+{
+ register char * cp;
+
+
+ if ( cp = FindAttValByName(entry, "MOREROWS") )
+ return atoi(cp);
+ else
+ return 0;
+}
+
+/* TblColAdv() -- advance pointer to next entry, if appropriate
+ *
+ */
+
+
+bool
+TblColAdv(short col, /* the current column */
+ Element_t *ep, /* pointer to entry */
+ struct tblformat * tfp, /* pointer to prevailing format */
+ tblsource source) /* context */
+{
+ register bool bump;
+ register struct tblspanspec * tssp;
+
+
+ bump = TRUE;
+
+ if ( tssp = TblEntrySpanSpec(col, ep, source) ) {
+ bump = tssp->align != Span;
+ free(tssp);
+ }
+
+ return bump;
+}
+
+/* TblEntryColSpec() -- get a completely localized colspec for an entry
+ *
+ */
+
+
+struct tblcolspec *
+TblEntryColSpec(short num, /* column number */
+ Element_t * ep, /* entry */
+ tblsource source) /* context */
+{
+ register int i;
+ register bool throwAway;
+ register char * cp;
+ register struct tblcolspec * tcsp, * tcsp2;
+
+
+ tcsp = tcsp2 = 0;
+ throwAway = FALSE;
+
+ if ( (cp = FindAttValByName(ep, "COLNAME")) ) {
+ if ( ! (tcsp = TblFindColSpec(cp, source)) ) {
+ fprintf(stderr, "? can't find column name '%s'\n", cp);
+ }
+ }
+
+ if ( tcsp2 = TblFindColNum(num, source) ) {
+ tcsp = TblDoColSpec(num, ep, tcsp2, source);
+ throwAway = TRUE;
+ }
+
+ tcsp2 = TblDoColSpec(num, ep, tcsp, source);
+
+ if ( throwAway )
+ free(tcsp);
+
+ return tcsp2;
+}
+
+/* TblEntrySpanSpec() -- get a completely localized spanspec for an entry
+ *
+ */
+
+
+struct tblspanspec *
+TblEntrySpanSpec(short num, /* column number */
+ Element_t * ep, /* entry */
+ tblsource source) /* context */
+{
+ register char * cp, * cp2;
+ register struct tblspanspec * tssp, * tssp2;
+
+
+ tssp2 = 0;
+
+ if ( !(cp = FindAttValByName(ep, "SPANNAME")) ||
+ !(tssp2 = TblFindSpanSpec(cp, source)) ) {
+
+ if ( !FindAttValByName(ep, "NAMEST") )
+ return 0;
+ }
+
+ tssp = TblDoSpanSpec(ep, tssp2, source);
+
+ if ( tssp->start && tssp->end &&
+ (tssp->start->num < num) && (tssp->end->num >= num) ) {
+ tssp->align = Span;
+ }
+
+ return tssp;
+}
+
+/* TblFormatMatch() -- compare two format rows for consistency
+ *
+ */
+
+
+bool
+TblFormatMatch(struct tblformat * tf1, /* one row */
+ struct tblformat * tf2) /* the other */
+{
+ register int i;
+
+ if ( tf1->cols != tf2->cols ) {
+ return FALSE;
+ }
+
+ for ( i=0; i < tf1->cols; i++ ) {
+
+ if ( tf1->colformat[i] != tf2->colformat[i] ) {
+ return FALSE;
+ }
+ if ( strcmp(tf1->colwidth[i], tf2->colwidth[i]) ) {
+ return FALSE;
+ }
+ if ( strcmp(tf1->font[i], tf2->font[i]) ) {
+ return FALSE;
+ }
+ if ( tf1->colsep[i] != tf2->colsep[i] ) {
+ return FALSE;
+ }
+ if ( tf1->rowsep[i] != tf2->rowsep[i] ) {
+ return FALSE;
+ }
+ if ( tf1->moreRows[i] || tf2->moreRows[i] ) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* TblPrintFormat() -- print a tbl format structure
+ *
+ */
+
+
+void
+TblPrintFormat(FILE * fP, /* where to print */
+ struct tblformat * tfp) /* the structure */
+{
+ register int i;
+ register struct tblformat * tfp2, * tfp3;
+ static char buf[3] = "\000\000";
+
+
+ for ( tfp2=tfp, tfp3=0; tfp2; tfp2=tfp2->next ) {
+ for ( i=1; i <= tfp->cols; i++ ) {
+ if ( i > 1 )
+ OutputString(" ", fP, 1);
+ if ( tfp3 && tfp3->moreRows[i] )
+ OutputString("\\^", fP, 1);
+ else {
+ buf[0] = tfp2->colformat[i];
+ OutputString(buf, fP, 1);
+ }
+ if ( tfp2->colwidth[i][0] ) {
+ OutputString("w(", fP, 1);
+ OutputString(tfp2->colwidth[i], fP, 1);
+ OutputString(")", fP, 1);
+ }
+ if ( tfp2->font[i][0] )
+ OutputString(tfp2->font[i], fP, 1);
+ if ( tfp2->colsep[i] )
+ OutputString("|", fP, 1);
+ }
+ if ( ! tfp2->next )
+ OutputString(".", fP, 1);
+ OutputString("^", fP, 1);
+ tfp3 = tfp2;
+ }
+}
+
+/* TblTRowStart() -- start a row (not much to do)
+ *
+ * TO DO:
+ *
+ * nothing..
+ *
+ */
+
+
+
+void
+TblTRowStart(Element_t * ep,
+ FILE * fP)
+{
+
+ /* nothing to do */
+
+ tblrow++; /* except note that we're within a new row */
+
+}
+
+/* TblTRowEnd() -- end a row
+ *
+ * TO DO:
+ *
+ * output a row end character (newline)
+ * if the current row had a rowsep, then output a "fake" row
+ * with underlines in the proper place(s).
+ */
+
+
+
+void
+TblTRowEnd(Element_t * ep,
+ FILE * fP)
+{
+ register int i, k;
+ register tblsource source;
+ register bool startedRow, didSep;
+ register struct tblformat * rfp;
+
+
+ OutputString("^", fP, 1);
+
+ /* get the format for this row */
+
+ if ( !strcmp(ep->parent->gi, "TFoot") )
+ source = TFoot;
+ else
+ if ( !strcmp(ep->parent->gi, "THead") )
+ source = THead;
+ else
+ source = TBody;
+
+ rfp = TblBuild1Format(ep, TRUE, source);
+ startedRow = FALSE;
+ didSep = FALSE;
+
+ for ( i=1; i <= formP->cols; i++ ) {
+ if ( rfp->rowsep[i] ||
+ (didSep && (rfp->colformat[i] == 's')) ) {
+ if ( ! startedRow ) {
+ OutputString("^", fP, 1);
+ for ( k=1; k < i; k++ )
+ OutputString("\007", fP, 1);
+ startedRow = TRUE;
+ }
+ OutputString("_\007", fP, 1);
+ didSep = TRUE;
+ } else {
+ if ( startedRow )
+ OutputString("\007", fP, 1);
+ }
+ didSep = FALSE;
+ }
+ free(rfp); /* clear that row.. */
+
+ if ( startedRow )
+ OutputString("^", fP, 1);
+}
+
+/* TblTEntryStart() -- start an entry (block of filled text if
+ * appropriate)
+ *
+ * TO DO:
+ *
+ * if text length > BOFTTextThresh or there is PI,
+ * then output "T{\n", else do nothing
+ *
+ */
+
+
+
+void
+TblTCellStart(Element_t * ep,
+ FILE * fP)
+{
+ register int i;
+ register Element_t * ep2;
+ register bool sawPI;
+
+
+ for ( i=0, sawPI=FALSE; (i < ep->ncont) && !sawPI; i++ )
+ if ( ep->cont[i].type == '?' )
+ sawPI = TRUE;
+
+ if ( sawPI || (TblCountContent(ep) > BOFTTextThresh) ) {
+ tblBOFTCount++;
+ OutputString("T{^", fP, 1);
+ tblinBOFT = TRUE; /* within a boft now */
+ }
+}
+
+/* TblCountContent() -- count all content below the given element
+ *
+ *
+ */
+
+
+
+int
+TblCountContent(Element_t * ep) /* the element to look under */
+{
+ register int i, count;
+
+
+ count = 0;
+
+ for ( i=0; i < ep->ncont; i++ ) {
+ if ( ep->cont[i].type == '-' ) {
+ count += strlen(ep->cont[i].ch.data);
+ } else
+ if ( ep->cont[i].type == '(' ) {
+ count += TblCountContent(ep->cont[i].ch.elem);
+ }
+ }
+
+ return count;
+}
+
+/* TblTEntryEnd() -- end an entry
+ *
+ * TO DO:
+ *
+ * if within BOFT, output "T}"
+ * if not last entry, output tab character
+ *
+ */
+
+
+
+void
+TblTCellEnd(Element_t * ep,
+ FILE * fP)
+{
+ register Element_t * ep2;
+
+
+ if ( tblinBOFT ) {
+ OutputString("^T}", fP, 1);
+ tblinBOFT = FALSE; /* back out again */
+ }
+
+ for ( ep2=ep->next; ep2; ep2=ep2->next ) {
+ if ( !strcmp(ep2->gi, "ENTRY") || !strcmp(ep2->gi, "ENTRYTBL") ) {
+ OutputString("\007", fP, 1);
+ break;
+ }
+ if ( !strcmp(ep2->gi, "ROW") )
+ break;
+ }
+}
+
+/* TblDoColSpec() -- process one element to create a new colspec
+ *
+ *
+ */
+
+
+
+struct tblcolspec *
+TblDoColSpec(short number, /* this column number */
+ Element_t * ep, /* element containing colspec stuff */
+ struct tblcolspec * pcsp, /* prevailing colspec (with defaults) */
+ tblsource source) /* precedence level of the resulting spec */
+{
+ register char * cp;
+ register struct tblcolspec * tcsp;
+
+
+ Calloc(1, tcsp, struct tblcolspec);
+
+ if ( cp = FindAttValByName(ep, "COLNAME") )
+ strcpy(tcsp->name, cp);
+
+ tcsp->num = number;
+ tcsp->source = source;
+
+ if ( cp = FindAttValByName(ep, "ALIGN") ) {
+ if ( !strcmp(cp, "LEFT") ) tcsp->align = Left;
+ else if ( !strcmp(cp, "RIGHT") ) tcsp->align = Right;
+ else if ( !strcmp(cp, "CENTER") ) tcsp->align = Center;
+ else if ( !strcmp(cp, "JUSTIFY") ) tcsp->align = Justify;
+ else if ( !strcmp(cp, "CHAR") ) tcsp->align = Char;
+ } else
+ tcsp->align = ( pcsp ) ? pcsp->align : Left;
+
+ if ( cp = FindAttValByName(ep, "CHAR") )
+ tcsp->alignchar = cp[0];
+ else
+ tcsp->alignchar = ( pcsp ) ? pcsp->alignchar : 0;
+
+ if ( cp = FindAttValByName(ep, "CHAROFF") )
+ tcsp->aligncharoff = atoi(cp);
+ else
+ tcsp->aligncharoff = ( pcsp ) ? pcsp->aligncharoff : 0;
+
+ if ( cp = FindAttValByName(ep, "COLWIDTH") )
+ strcpy(tcsp->colwidth, cp);
+ else
+ strcpy(tcsp->colwidth, ( pcsp ) ? pcsp->colwidth : "");
+
+ if ( cp = FindAttValByName(ep, "COLSEP") )
+ tcsp->colsep = !strcmp(cp, "1");
+ else
+ tcsp->colsep = ( pcsp ) ? pcsp->colsep : FALSE;
+
+ if ( cp = FindAttValByName(ep, "ROWSEP") )
+ tcsp->rowsep = !strcmp(cp, "1");
+ else
+ tcsp->rowsep = ( pcsp ) ? pcsp->rowsep : FALSE;
+
+ return tcsp;
+}
+
+/* TblDoSpanSpec() -- process one element to create a new spanspec
+ *
+ * Note that there's a hack inside here... NameSt and NameEnd are
+ * supposed to point at colnames, but if no colname is found, this
+ * code will look for a colnum by the same value.
+ */
+
+
+
+struct tblspanspec *
+TblDoSpanSpec(Element_t * ep, /* element containing spanspec stuff */
+ struct tblspanspec * pssp, /* prevailing spanspec (with defaults) */
+ tblsource source) /* precedence level of the resulting spec */
+{
+ register char * cp;
+ register struct tblspanspec * tssp;
+ register struct tblcolspec * tcsp;
+
+
+ Calloc(1, tssp, struct tblspanspec);
+
+ if ( cp = FindAttValByName(ep, "SPANNAME") ) strcpy(tssp->name, cp);
+ tssp->source = source;
+
+ if ( cp = FindAttValByName(ep, "NAMEST") ) {
+ if ( (tcsp = TblFindColSpec(cp, source)) ||
+ (tcsp = TblFindColNum(atoi(cp), source)) ) {
+ tssp->start = tcsp;
+ } else {
+ fprintf(stderr, "? spanspec namest points to unknown column '%s'\n", cp);
+ tssp->start = 0;
+ }
+ } else {
+ if ( pssp && pssp->start ) {
+ tssp->start = pssp->start;
+ }
+ }
+
+ if ( cp = FindAttValByName(ep, "NAMEEND") ) {
+ if ( (tcsp = TblFindColSpec(cp, source)) ||
+ (tcsp = TblFindColNum(atoi(cp), source)) ) {
+ tssp->end = tcsp;
+ } else {
+ fprintf(stderr, "? spanspec nameend points to unknown column '%s'\n", cp);
+ tssp->end = 0;
+ }
+ } else {
+ if ( pssp && pssp->end ) {
+ tssp->end = pssp->end;
+ }
+ }
+
+ if ( cp = FindAttValByName(ep, "ALIGN") ) {
+ if ( !strcmp(cp, "LEFT") ) tssp->align = Left;
+ else if ( !strcmp(cp, "RIGHT") ) tssp->align = Right;
+ else if ( !strcmp(cp, "CENTER") ) tssp->align = Center;
+ else if ( !strcmp(cp, "JUSTIFY") ) tssp->align = Justify;
+ else if ( !strcmp(cp, "CHAR") ) tssp->align = Char;
+ } else {
+ if ( pssp )
+ tssp->align = pssp->align;
+ }
+
+ if ( cp = FindAttValByName(ep, "CHAR") )
+ tssp->alignchar = cp[0];
+ else {
+ if ( pssp )
+ tssp->alignchar = pssp->alignchar;
+ }
+ if ( cp = FindAttValByName(ep, "CHAROFF") )
+ tssp->aligncharoff = atoi(cp);
+ else {
+ if ( pssp )
+ tssp->alignchar = pssp->alignchar;
+ }
+
+ if ( cp = FindAttValByName(ep, "COLSEP") )
+ tssp->colsep = !strcmp(cp, "1");
+ else {
+ if ( pssp )
+ tssp->colsep = pssp->colsep;
+ }
+ if ( cp = FindAttValByName(ep, "ROWSEP") )
+ tssp->rowsep = !strcmp(cp, "1");
+ else {
+ if ( pssp )
+ tssp->rowsep = pssp->rowsep;
+ }
+
+ return tssp;
+}
+
+/* TblFindColSpec() -- find a table colspec by name (colname)
+ *
+ */
+
+
+
+struct tblcolspec *
+TblFindColSpec(char * name, /* the name we're looking for */
+ tblsource source) /* the context in which to find it */
+{
+ register struct tblcolspec * tcsp;
+
+
+ /* first, try to find the one in the right "source" */
+
+ for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
+ if ( (tcsp->source == source) && !strcmp(tcsp->name, name) )
+ return tcsp;
+ }
+
+ /* else, try to find one from a TGroup.. */
+
+ for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
+ if ( (tcsp->source == TGroup) && !strcmp(tcsp->name, name) )
+ return tcsp;
+ }
+
+ /* else not found.. */
+
+ return 0;
+}
+
+/* TblFindColNum() -- find a table colspec by number
+ *
+ */
+
+
+
+struct tblcolspec *
+TblFindColNum(short number, /* the number we're looking for */
+ tblsource source) /* the context in which to find it */
+{
+ register struct tblcolspec * tcsp;
+
+
+
+ /* first, try to find the one in the right "source" */
+
+ for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
+ if ( (tcsp->num == number) &&
+ ((tcsp->source == source) ||
+ ((source == THead) && (tcsp->source == TGroup))) )
+ return tcsp;
+ }
+
+ /* else, try to find one from a TGroup.. */
+
+ for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
+ if ( (tcsp->source == TGroup) && (tcsp->num == number) )
+ return tcsp;
+ }
+
+ /* else not found.. */
+
+ return 0;
+}
+
+/* TblFindSpanSpec() -- find a table spanspec by name (spanname)
+ *
+ */
+
+
+
+struct tblspanspec *
+TblFindSpanSpec(char * name, /* the name we're looking for */
+ tblsource source) /* the context in which to find it */
+{
+ register struct tblspanspec * tssp;
+
+
+ /* first, try to find the one in the right "source" */
+
+ for ( tssp=tblSpanSpec; tssp; tssp=tssp->next ) {
+ if ( !strcmp(tssp->name, name) &&
+ ((tssp->source == source) ||
+ ((source == THead) && (tssp->source == TGroup))) )
+ return tssp;
+ }
+
+ /* else not found.. */
+
+ return 0;
+}
diff --git a/usr.bin/sgmls/instant/traninit.c b/usr.bin/sgmls/instant/traninit.c
new file mode 100644
index 0000000..d3df959
--- /dev/null
+++ b/usr.bin/sgmls/instant/traninit.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Program to manipulate SGML instances.
+ *
+ * This module contains the initialization routines for translation module.
+ * They mostly deal with reading data files (translation specs, SDATA
+ * mappings, character mappings).
+ *
+ * Entry points:
+ * ReadTransSpec(transfile) read/store translation spec from file
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/local/home/jfieber/src/cvsroot/nsgmlfmt/traninit.c,v 1.1.1.1 1996/01/16 05:14:10 jfieber Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <regexp.h>
+
+#include "general.h"
+#include "translate.h"
+
+#include "sgmls.h"
+#include "config.h"
+#include "std.h"
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/* forward references */
+void RememberTransSpec(Trans_t *, int);
+static void do_data(char *gi, struct sgmls_data *v, int n);
+static void build_ts(char *gi, char* cp);
+void AddCharMap(const char *from, const char* to);
+void AddSDATA(const char *from, const char *to);
+
+/* ______________________________________________________________________ */
+/* Read the translation specs from the input file, storing in memory.
+ * Arguments:
+ * Name of translation spec file.
+ */
+
+static Trans_t T;
+
+
+static
+void input_error(num, str, lineno)
+ int num;
+ char *str;
+ unsigned long lineno;
+{
+ fprintf(stderr, "Error at input line %lu: %s\n", lineno, str);
+}
+
+void
+ReadTransSpec(
+ char *transfile
+)
+{
+ FILE *fp;
+ struct sgmls *sp;
+ struct sgmls_event e;
+ char gi[LINESIZE];
+ char buf[LINESIZE];
+ char buf2[LINESIZE];
+ char *command;
+ char *sgmls = "sgmls ";
+ char maptype = '\0';
+
+ (void)sgmls_set_errhandler(input_error);
+ transfile = FilePath(transfile);
+ if (!transfile)
+ {
+ fprintf(stderr, "Error: Could not locate specified transfile\n");
+ exit(1);
+ }
+
+ /* XXX this is a quick, gross hack. Should write a parse() function. */
+ Malloc(strlen(sgmls) + strlen(transfile) + 2, command, char);
+ sprintf(command, "%s %s", sgmls, transfile);
+ fp = popen(command, "r");
+
+ sp = sgmls_create(fp);
+ while (sgmls_next(sp, &e))
+ switch (e.type) {
+ case SGMLS_EVENT_DATA:
+ do_data(gi, e.u.data.v, e.u.data.n);
+ break;
+ case SGMLS_EVENT_ENTITY:
+ fprintf(stderr, "Hm... got an entity\n");
+ break;
+ case SGMLS_EVENT_PI:
+ break;
+ case SGMLS_EVENT_START:
+ if (strncmp("RULE", e.u.start.gi, 4) == 0) {
+ /* A new transpec, so clear the data structure
+ * and look for an ID attribute.
+ */
+ struct sgmls_attribute *attr = e.u.start.attributes;
+ memset(&T, 0, sizeof T);
+ while (attr) {
+ if (attr->type == SGMLS_ATTR_CDATA
+ && strncmp("ID", attr->name, 2) == 0) {
+ strncpy(buf, attr->value.data.v->s,
+ MIN(attr->value.data.v->len, LINESIZE));
+ buf[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
+ T.my_id = atoi(buf);
+ }
+ attr = attr->next;
+ }
+ }
+ else if (strncmp("CMAP", e.u.start.gi, 4) == 0)
+ maptype = 'c';
+ else if (strncmp("SMAP", e.u.start.gi, 4) == 0)
+ maptype = 's';
+ else if (strncmp("MAP", e.u.start.gi, 3) == 0) {
+ struct sgmls_attribute *attr = e.u.start.attributes;
+ char *from = 0;
+ char *to = 0;
+
+ while (attr) {
+ if (attr->value.data.v && strncmp("FROM", attr->name, 4) == 0) {
+ strncpy(buf, attr->value.data.v->s,
+ MIN(attr->value.data.v->len, LINESIZE - 1));
+ buf[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
+ }
+ if (attr->value.data.v && strncmp("TO", attr->name, 2) == 0) {
+ strncpy(buf2, attr->value.data.v->s,
+ MIN(attr->value.data.v->len, LINESIZE - 1));
+ buf2[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
+ }
+ attr = attr->next;
+ }
+ if (maptype == 'c')
+ AddCharMap(buf, buf2);
+ else if (maptype == 's')
+ AddSDATA(buf, buf2);
+ else
+ fprintf(stderr, "Unknown map type!\n");
+ }
+ else {
+ strncpy(gi, e.u.start.gi, 512);
+ sgmls_free_attributes(e.u.start.attributes);
+ }
+ break;
+ case SGMLS_EVENT_END:
+ if (strncmp("RULE", e.u.start.gi, 4) == 0)
+ RememberTransSpec(&T, e.lineno);
+ break;
+ case SGMLS_EVENT_SUBSTART:
+ break;
+ case SGMLS_EVENT_SUBEND:
+ break;
+ case SGMLS_EVENT_APPINFO:
+ break;
+ case SGMLS_EVENT_CONFORMING:
+ break;
+ default:
+ abort();
+ }
+ sgmls_free(sp);
+ pclose(fp);
+ free(command);
+}
+
+
+static void do_data(char *gi, struct sgmls_data *v, int n)
+{
+ int i;
+ char *cp;
+ static char *buf = 0;
+ static int buf_size = 0;
+ int buf_pos = 0;
+
+
+ /* figure out how much space this element will really
+ take, inculding expanded sdata entities. */
+
+ if (!buf)
+ {
+ buf_size = 1024;
+ Malloc(buf_size, buf, char);
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ char *s;
+ int len;
+
+ /* Mark the current position. If this is SDATA
+ we will have to return here. */
+ int tmp_buf_pos = buf_pos;
+
+ /* Make sure the buffer is big enough. */
+ if (buf_size - buf_pos <= v[i].len)
+ {
+ buf_size += v[i].len * (n - i);
+ Realloc(buf_size, buf, char);
+ }
+
+ s = v[i].s;
+ len = v[i].len;
+ for (; len > 0; len--, s++)
+ {
+ if (*s != RSCHAR) {
+ if (*s == RECHAR)
+ buf[buf_pos] = '\n';
+ else
+ buf[buf_pos] = *s;
+ buf_pos++;
+ }
+ }
+ if (v[i].is_sdata)
+ {
+ char *p;
+ buf[buf_pos] = '\0';
+ p = LookupSDATA(buf + tmp_buf_pos);
+ if (p)
+ {
+ if (buf_size - tmp_buf_pos <= strlen(p))
+ {
+ buf_size += strlen(p) * (n - i);
+ Realloc(buf_size, buf, char);
+ }
+ strcpy(buf + tmp_buf_pos, p);
+ buf_pos = tmp_buf_pos + strlen(p);
+ }
+ }
+ }
+
+ /* Clean up the trailing end of the data. */
+ buf[buf_pos] = '\0';
+ buf_pos--;
+ while (buf_pos > 0 && isspace(buf[buf_pos]) && buf[buf_pos] != '\n')
+ buf_pos--;
+ if (buf[buf_pos] == '\n')
+ buf[buf_pos] = '\0';
+
+ /* Skip over whitespace at the beginning of the data. */
+ cp = buf;
+ while (*cp && isspace(*cp))
+ cp++;
+ build_ts(gi, cp);
+}
+
+/* ______________________________________________________________________ */
+/* Set a transpec parameter
+ * Arguments:
+ * gi - the parameter to set
+ * cp - the value of the parameter
+ */
+static void build_ts(char *gi, char* cp)
+{
+ if (strcmp("GI", gi) == 0)
+ {
+ char *cp2;
+ /* if we are folding the case of GIs, make all upper (unless
+ it's an internal pseudo-GI name, which starts with '_') */
+ if (fold_case && cp[0] != '_' && cp[0] != '#')
+ {
+ for (cp2=cp; *cp2; cp2++)
+ if (islower(*cp2)) *cp2 = toupper(*cp2);
+ }
+ T.gi = AddElemName(cp);
+ }
+ else if (strcmp("START", gi) == 0)
+ T.starttext = strdup(cp);
+ else if (strcmp("END", gi) == 0)
+ T.endtext = strdup(cp);
+ else if (strcmp("RELATION", gi) == 0)
+ {
+ if (!T.relations)
+ T.relations = NewMap(IMS_relations);
+ SetMapping(T.relations, cp);
+ }
+ else if (strcmp("REPLACE", gi) == 0)
+ T.replace = strdup(cp);
+ else if (strcmp("ATTVAL", gi) == 0)
+ {
+ if (!T.nattpairs)
+ {
+ Malloc(1, T.attpair, AttPair_t);
+ }
+ else
+ Realloc((T.nattpairs+1), T.attpair, AttPair_t);
+ /* we'll split name/value pairs later */
+ T.attpair[T.nattpairs].name = strdup(cp);
+ T.nattpairs++;
+ }
+ else if (strcmp("CONTEXT", gi) == 0)
+ T.context = strdup(cp);
+ else if (strcmp("MESSAGE", gi) == 0)
+ T.message = strdup(cp);
+ else if (strcmp("DO", gi) == 0)
+ T.use_id = atoi(cp);
+ else if (strcmp("CONTENT", gi) == 0)
+ T.content = strdup(cp);
+ else if (strcmp("PATTSET", gi) == 0)
+ T.pattrset = strdup(cp);
+ else if (strcmp("VERBATIM", gi) == 0)
+ T.verbatim = TRUE;
+ else if (strcmp("IGNORE", gi) == 0)
+ {
+ if (!strcmp(cp, "all"))
+ T.ignore = IGN_ALL;
+ else if (!strcmp(cp, "data"))
+ T.ignore = IGN_DATA;
+ else if (!strcmp(cp, "children"))
+ T.ignore = IGN_CHILDREN;
+ else
+ fprintf(stderr, "Bad 'Ignore:' arg in transpec %s: %s\n",
+ gi, cp);
+ }
+ else if (strcmp("VARVAL", gi) == 0)
+ {
+ char **tok;
+ int i = 2;
+ tok = Split(cp, &i, S_STRDUP);
+ T.var_name = tok[0];
+ T.var_value = tok[1];
+ }
+ else if (strcmp("VARREVAL", gi) == 0)
+ {
+ char buf[1000];
+ char **tok;
+ int i = 2;
+ tok = Split(cp, &i, S_STRDUP);
+ T.var_RE_name = tok[0];
+ ExpandVariables(tok[1], buf, 0);
+ if (!(T.var_RE_value=regcomp(buf))) {
+ fprintf(stderr, "Regex error in VarREValue Content: %s\n",
+ tok[1]);
+ }
+ }
+ else if (strcmp("SET", gi) == 0)
+ {
+ if (!T.set_var)
+ T.set_var = NewMap(IMS_setvar);
+ SetMapping(T.set_var, cp);
+ }
+ else if (strcmp("INCR", gi) == 0)
+ {
+ if (!T.incr_var)
+ T.incr_var = NewMap(IMS_incvar);
+ SetMapping(T.incr_var, cp);
+ }
+ else if (strcmp("NTHCHILD", gi) == 0)
+ T.nth_child = atoi(cp);
+ else if (strcmp("VAR", gi) == 0)
+ SetMapping(Variables, cp);
+ else if (strcmp("QUIT", gi) == 0)
+ T.quit = strdup(cp);
+ else
+ fprintf(stderr, "Unknown translation spec (skipping it): %s\n", gi);
+
+}
+
+
+/* ______________________________________________________________________ */
+/* Store translation spec 't' in memory.
+ * Arguments:
+ * Pointer to translation spec to remember.
+ * Line number where translation spec ends.
+ */
+void
+RememberTransSpec(
+ Trans_t *t,
+ int lineno
+)
+{
+ char *cp;
+ int i, do_regex;
+ static Trans_t *last_t;
+ char buf[1000];
+
+ /* If context testing, check some details and set things up for later. */
+ if (t->context) {
+ /* See if the context specified is a regular expression.
+ * If so, compile the reg expr. It is assumed to be a regex if
+ * it contains a character other than what's allowed for GIs in the
+ * OSF sgml declaration (alphas, nums, '-', and '.').
+ */
+ for (do_regex=0,cp=t->context; *cp; cp++) {
+ if (!isalnum(*cp) && *cp != '-' && *cp != '.' && *cp != ' ') {
+ do_regex = 1;
+ break;
+ }
+ }
+
+ if (do_regex) {
+ t->depth = MAX_DEPTH;
+ if (!(t->context_re=regcomp(t->context))) {
+ fprintf(stderr, "Regex error in Context: %s\n", t->context);
+ }
+ }
+ else {
+ /* If there's only one item in context, it's the parent. Treat
+ * it specially, since it's faster to just check parent gi.
+ */
+ cp = t->context;
+ if (!strchr(cp, ' ')) {
+ t->parent = t->context;
+ t->context = NULL;
+ }
+ else {
+ /* Figure out depth of context string */
+ t->depth = 0;
+ while (*cp) {
+ if (*cp) t->depth++;
+ while (*cp && !IsWhite(*cp)) cp++; /* find end of gi */
+ while (*cp && IsWhite(*cp)) cp++; /* skip space */
+ }
+ }
+ }
+ }
+
+ /* Compile regular expressions for each attribute */
+ for (i=0; i<t->nattpairs; i++) {
+ /* Initially, name points to "name value". Split them... */
+ cp = t->attpair[i].name;
+ while (*cp && !IsWhite(*cp)) cp++; /* point past end of name */
+ if (*cp) { /* value found */
+ *cp++ = EOS; /* terminate name */
+ while (*cp && IsWhite(*cp)) cp++; /* point to value */
+ ExpandVariables(cp, buf, 0); /* expand any variables */
+ t->attpair[i].val = strdup(buf);
+ }
+ else { /* value not found */
+ t->attpair[i].val = ".";
+ }
+ if (!(t->attpair[i].rex=regcomp(t->attpair[i].val))) {
+ fprintf(stderr, "Regex error in AttValue: %s %s\n",
+ t->attpair[i].name, t->attpair[i].val);
+ }
+ }
+
+ /* Compile regular expression for content */
+ t->content_re = 0;
+ if (t->content) {
+ ExpandVariables(t->content, buf, 0);
+ if (!(t->content_re=regcomp(buf)))
+ fprintf(stderr, "Regex error in Content: %s\n",
+ t->content);
+ }
+
+ /* If multiple GIs, break up into a vector, then remember it. We either
+ * sture the individual, or the list - not both. */
+ if (t->gi && strchr(t->gi, ' ')) {
+ t->gilist = Split(t->gi, 0, S_ALVEC);
+ t->gi = NULL;
+ }
+
+ /* Now, store structure in linked list. */
+ if (!TrSpecs) {
+ Malloc(1, TrSpecs, Trans_t);
+ last_t = TrSpecs;
+ }
+ else {
+ Malloc(1, last_t->next, Trans_t);
+ last_t = last_t->next;
+ }
+ *last_t = *t;
+}
+
+
+/* ______________________________________________________________________ */
+/* Add an entry to the character mapping table, allocating or
+ * expanding the table if necessary.
+ * Arguments:
+ * Character to map
+ * String to map the character to
+ * A 'c' or an 's' for character or sdata map
+ */
+
+void
+AddCharMap(
+ const char *from,
+ const char* to
+)
+{
+ static int n_alloc = 0;
+
+ if (from && to) {
+ if (nCharMap >= n_alloc) {
+ n_alloc += 32;
+ if (!CharMap) {
+ Malloc(n_alloc, CharMap, Mapping_t);
+ }
+ else {
+ Realloc(n_alloc, CharMap, Mapping_t);
+ }
+ }
+ CharMap[nCharMap].name = strdup(from);
+ CharMap[nCharMap].sval = strdup(to);
+ nCharMap++;
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Add an entry to the SDATA mapping table.
+ * Arguments:
+ * String to map
+ * String to map to
+ */
+
+void
+AddSDATA(
+ const char *from,
+ const char *to
+)
+{
+ if (from && to) {
+ if (!SDATAmap)
+ SDATAmap = NewMap(IMS_sdata);
+ SetMappingNV(SDATAmap, from, to);
+ }
+}
+
+/* ______________________________________________________________________ */
diff --git a/usr.bin/sgmls/instant/translate.c b/usr.bin/sgmls/instant/translate.c
new file mode 100644
index 0000000..cc96b25
--- /dev/null
+++ b/usr.bin/sgmls/instant/translate.c
@@ -0,0 +1,881 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Program to manipulate SGML instances.
+ *
+ * This module is for "translating" an instance to another form, usually
+ * suitable for a formatting application.
+ *
+ * Entry points for this module:
+ * DoTranslate(elem, fp)
+ * ExpandVariables(in, out, e)
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/translate.c,v 1.11 1996/06/15 22:49:00 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <regexp.h>
+
+#include "general.h"
+#define STORAGE
+#include "translate.h"
+
+static Trans_t NullTrans; /* an empty one */
+
+/* forward references */
+void ProcesOutputSpec(char *, Element_t *, FILE *, int);
+static void WasProcessed(Element_t *);
+
+/* ______________________________________________________________________ */
+/* Translate the subtree starting at 'e'. Output goes to 'fp'.
+ * This is the entry point for translating an instance.
+ * Arguments:
+ * Pointer to element under consideration.
+ * FILE pointer to where to write output.
+ */
+
+void
+DoTranslate(
+ Element_t *e,
+ FILE *fp
+)
+{
+ Trans_t *t, *tn;
+
+ /* Find transpec for each node. */
+ DescendTree(e, PrepTranspecs, 0, 0, 0);
+
+ /* Stuff to do at start of processing */
+ if ((t = FindTransByName("_Start"))) {
+ if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
+ if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
+ if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
+ if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
+ }
+
+ /* Translate topmost/first element. This is recursive. */
+ TransElement(e, fp, NULL);
+
+ /* Stuff to do at end of processing */
+ if ((t = FindTransByName("_End"))) {
+ if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
+ if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
+ if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
+ if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
+ }
+
+ /* Warn about unprocessed elements in this doc tree, if verbose mode. */
+ if (verbose)
+ DescendTree(e, WasProcessed, 0, 0, 0);
+
+ /* Clean up. This is not yet complete, which is no big deal (since the
+ * program is normally done at this point anyway. */
+ for (t=TrSpecs; t; ) {
+ tn = t->next;
+ /* free the contents of t here ... */
+ (void)free((void* )t);
+ t = tn;
+ }
+ TrSpecs = 0;
+}
+
+/* ______________________________________________________________________ */
+/* Print warning about unprocessed elements in this doc tree (if they
+ * were not explicitely ignored).
+ * Arguments:
+ * Pointer to element under consideration.
+ */
+static void
+WasProcessed(
+ Element_t *e
+)
+{
+ Trans_t *t;
+ t = e->trans;
+ if (!e->processed && (t && !t->ignore)) {
+ fprintf(stderr, "Warning: element '%s' was not processed:\n", e->gi);
+ PrintLocation(e, stderr);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* For each element find transpec.
+ * Arguments:
+ * Pointer to element under consideration.
+ */
+void
+PrepTranspecs(
+ Element_t *e
+)
+{
+ Trans_t *t;
+ t = FindTrans(e, 0);
+ e->trans = t;
+}
+
+/* ______________________________________________________________________ */
+/* Copy a buffer/string into another, expanding regular variables and immediate
+ * variables. (Special variables are done later.)
+ * Arguments:
+ * Pointer to string to expand.
+ * Pointer to expanded string. (return)
+ * Pointer to element under consideration.
+ */
+void
+ExpandVariables(
+ char *in,
+ char *out,
+ Element_t *e
+)
+{
+ register int i, j;
+ char *ip, *vp, *op;
+ char *def_val, *s, *atval, *modifier;
+ char vbuf[500];
+ int lev;
+
+ ip = in;
+ op = out;
+ while (*ip) {
+ /* start of regular variable? */
+ if (*ip == '$' && *(ip+1) == L_CURLY && *(ip+2) != '_') {
+ ip++;
+ ip++; /* point at variable name */
+ vp = vbuf;
+ /* Look for matching (closing) curly. (watch for nesting)
+ * We store the variable content in a tmp buffer, so we don't
+ * clobber the input buffer.
+ */
+ lev = 0;
+ while (*ip) {
+ if (*ip == L_CURLY) lev++;
+ if (*ip == R_CURLY) {
+ if (lev == 0) {
+ ip++;
+ break;
+ }
+ else lev--;
+ }
+ *vp++ = *ip++; /* copy to variable buffer */
+ }
+ *vp = EOS;
+ /* vbuf now contains the variable name (stuff between curlys). */
+ if (lev != 0) {
+ fprintf(stderr, "Botched variable use: %s\n", in);
+ /* copy rest of string if we can't recover ?? */
+ return;
+ }
+ /* Now, expand variable. */
+ vp = vbuf;
+
+ /* Check for immediate variables -- like _special variables but
+ * interpreted right now. These start with a "+" */
+
+ if ( *vp == '+' ) {
+
+ if ( ! strcmp(vp, "+content") ) {
+ for ( i=0; i<e->ncont; i++ ) {
+ if ( IsContData(e, i) ) {
+ j = strlen(ContData(e,i));
+ memcpy(op, ContData(e,i), j);
+ op += j;
+ } else {
+ fprintf(stderr, "warning: ${+current} skipped element content\n");
+ }
+ }
+
+ } else {
+ fprintf(stderr, "unknown immediate variable: %s\n", vp);
+ }
+
+ } else {
+
+ /* See if this variable has a default [ format: ${varname def} ] */
+
+ def_val = vp;
+ while (*def_val && *def_val != ' ') def_val++;
+ if (*def_val) *def_val++ = EOS;
+ else def_val = 0;
+ /* def_val now points to default, if it exists, null if not. */
+
+ modifier = vp;
+ while (*modifier && *modifier != ':') modifier++;
+ if (*modifier) *modifier++ = EOS;
+ else modifier = 0;
+ /* modifier now points to modifier if it exists, null if not. */
+
+ s = 0;
+ /* if attribute of current elem with this name found, use value */
+ if (e && (atval = FindAttValByName(e, vp)))
+ s = atval;
+ else /* else try for (global) variable with this name */
+ s = FindMappingVal(Variables, vp);
+
+ /* If we found a value, copy it to the output buffer. */
+
+ if (s) {
+ if ( modifier && *modifier == 'l' ) {
+ while (*s) {
+ *op = tolower(*s);
+ op++, *s++;
+ }
+ } else
+ while (*s) *op++ = *s++;
+ } else
+ if (def_val) {
+ while (*def_val) *op++ = *def_val++;
+ }
+ }
+ continue;
+ }
+ *op++ = *ip++;
+ }
+ *op = EOS; /* terminate string */
+}
+
+/* ______________________________________________________________________ */
+/* Process an "output" translation spec - one of StartText, EndText,
+ * Replace, Message. (These are the ones that produce output.)
+ * Steps done:
+ * Expand attributes and regular varaibles in input string.
+ * Pass thru string, accumulating chars to be sent to output stream.
+ * If we find the start of a special variable, output what we've
+ * accumulated, then find the special variable's "bounds" (ie, the
+ * stuff between the curly brackets), and expand that by passing to
+ * ExpandSpecialVar(). Continue until done the input string.
+ * Arguments:
+ * Input buffer (string) to be expanded and output.
+ * Pointer to element under consideration.
+ * FILE pointer to where to write output.
+ * Flag saying whether to track the character position we're on
+ * (passed to OutputString).
+ */
+void
+ProcesOutputSpec(
+ char *ib,
+ Element_t *e,
+ FILE *fp,
+ int track_pos
+)
+{
+ char obuf[LINESIZE];
+ char vbuf[LINESIZE];
+ char *dest, vname[LINESIZE], *cp;
+ int esc;
+
+ obuf[0] = EOS; /* start with empty output buffer */
+
+ ExpandVariables(ib, vbuf, e); /* expand regular variables */
+ ib = vbuf;
+ dest = obuf;
+
+ esc = 0;
+ while (*ib) {
+ /* If not a $, it's a regular char. Just copy it and go to next. */
+ if (*ib != '$') { /* look for att/variable marker */
+ *dest++ = *ib++; /* it's not. just copy character */
+ continue;
+ }
+
+ /* We have a $. What we have must be a "special variable" since
+ * regular variables have already been expanded, or just a lone $. */
+
+ if (ib[1] != L_CURLY) { /* just a stray dollar sign (no variable) */
+ *dest++ = *ib++;
+ continue;
+ }
+
+ ib++; /* point past $ */
+
+ /* Output what we have in buffer so far. */
+ *dest = EOS; /* terminate string */
+ if (obuf[0]) OutputString(obuf, fp, track_pos);
+ dest = obuf; /* ready for new stuff in buffer */
+
+ if (!strchr(ib, R_CURLY)) {
+ fprintf(stderr, "Mismatched braces in TranSpec: %s\n", ib);
+ /* how do we recover from this? */
+ }
+ ib++;
+ cp = vname;
+ while (*ib && *ib != R_CURLY) *cp++ = *ib++;
+ *cp = EOS; /* terminate att/var name */
+ ib++; /* point past closing curly */
+ /* we now have special variable name (stuff in curly {}'s) in vname */
+ ExpandSpecialVar(&vname[1], e, fp, track_pos);
+ }
+ *dest = EOS; /* terminate string in output buffer */
+
+ if (obuf[0]) OutputString(obuf, fp, track_pos);
+}
+
+/* ______________________________________________________________________ */
+/* Find the translation spec for the given tag.
+ * Returns pointer to first spec that matches (name, depth, etc., of tag).
+ * Arguments:
+ * e -- Pointer to element under consideration.
+ * specID -- name of specid that we're looking for
+ * Return:
+ * Pointer to translation spec that matches given element's context.
+ */
+
+Trans_t *
+FindTrans(
+ Element_t *e,
+ int specID
+)
+{
+ char context[LINESIZE], buf[LINESIZE], *cp, **vec, *atval;
+ int i, a, match;
+ Trans_t *t, *tt;
+
+ /* loop through all transpecs */
+ for (t=TrSpecs; t; t=t->next)
+ {
+ /* Only one of gi or gilist will be set. */
+ /* Check if elem name matches */
+ if (t->gi && !StrEq(t->gi, e->gi) && !specID) continue;
+
+ /* test if we're looking for a specific specID and then if
+ * this is it.. */
+ if (specID)
+ if (!t->my_id || (specID != t->my_id))
+ continue;
+
+ /* Match one in the list of GIs? */
+ if (t->gilist) {
+ for (match=0,vec=t->gilist; *vec; vec++) {
+ if (StrEq(*vec, e->gi)) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) continue;
+ }
+
+ /* Check context */
+
+ /* Special case of context */
+ if (t->parent)
+ if (!QRelation(e, t->parent, REL_Parent)) continue;
+
+ if (t->context) { /* no context specified -> a match */
+ FindContext(e, t->depth, context);
+
+ /* If reg expr set, do regex compare; else just string compare. */
+ if (t->context_re) {
+ if (! regexec(t->context_re, context)) continue;
+ }
+ else {
+ /* Is depth of spec deeper than element's depth? */
+ if (t->depth > e->depth) continue;
+
+ /* See if context of element matches "context" of transpec */
+ match = ( (t->context[0] == context[0]) &&
+ !strcmp(t->context, context) );
+ if (!match) continue;
+ }
+ }
+
+ /* Check attributes. Loop through list, comparing each. */
+ if (t->nattpairs) { /* no att specified -> a match */
+ for (match=1,a=0; a<t->nattpairs; a++) {
+ if (!(atval = FindAttValByName(e, t->attpair[a].name))) {
+ match = 0;
+ break;
+ }
+ if (!regexec(t->attpair[a].rex, atval)) match = 0;
+ }
+ if (!match) continue;
+ }
+
+ /* Check relationships: child, parent, ancestor, sib, ... */
+ if (t->relations) {
+ Mapping_t *r;
+ match = 1;
+ for (r=t->relations->maps,i=0; i<t->relations->n_used; i++) {
+ if (!CheckRelation(e, r[i].name, r[i].sval, 0, 0, RA_Current)) {
+ match = 0;
+ break;
+ }
+ }
+ if (!match) continue;
+ }
+
+ /* check this element's parent's attribute */
+ if (t->pattrset && e->parent) {
+ char *p, **tok;
+
+ i = 2;
+ match = 1;
+ tok = Split(t->pattrset, &i, S_STRDUP);
+ if ( i == 2 ) {
+ p = FindAttValByName(e->parent, tok[0]);
+ ExpandVariables(tok[1], buf, 0);
+ if ( !p || strcmp(p, buf) )
+ match = 0;
+ } else {
+ if (!FindAttValByName(e->parent, t->pattrset))
+ match = 0;
+ }
+ free(tok[0]);
+ if (!match) continue;
+ }
+
+ /* check this element's "birth order" */
+ if (t->nth_child) {
+ /* First one is called "1" by the user. Internally called "0". */
+ i = t->nth_child;
+ if (i > 0) { /* positive # -- count from beginning */
+ if (e->my_eorder != (i-1)) continue;
+ }
+ else { /* negative # -- count from end */
+ i = e->parent->necont - i;
+ if (e->my_eorder != i) continue;
+ }
+ }
+
+ /* check that variables match */
+ if (t->var_name) {
+ cp = FindMappingVal(Variables, t->var_name);
+ if (!cp || strcmp(cp, t->var_value)) continue;
+ }
+
+ /* check for variable regular expression match */
+ if ( t->var_RE_name ) {
+ cp = FindMappingVal(Variables, t->var_RE_name);
+ if (!cp || !regexec(t->var_RE_value, cp)) continue;
+ }
+
+ /* check content */
+ if (t->content) { /* no att specified -> a match */
+ for (match=0,i=0; i<e->ndcont; i++) {
+ if (regexec(t->content_re, e->dcont[i])) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) continue;
+ }
+
+ /* -------- at this point we've passed all criteria -------- */
+
+ /* See if we should be using another transpec's actions. */
+ if (t->use_id) {
+ if (t->use_id < 0) return &NullTrans; /* missing? */
+ /* see if we have a pointer to that transpec */
+ if (t->use_trans) return t->use_trans;
+ for (tt=TrSpecs; tt; tt=tt->next) {
+ if (t->use_id == tt->my_id) {
+ /* remember pointer for next time */
+ t->use_trans = tt;
+ return t->use_trans;
+ }
+ }
+ t->use_id = -1; /* flag it as missing */
+ fprintf(stderr, "Warning: transpec ID (%d) not found for %s.\n",
+ t->use_id, e->gi);
+ return &NullTrans;
+ }
+
+ return t;
+ }
+
+ /* At this point, we have not found a matching spec. See if there
+ * is a wildcard, and if so, use it. (Wildcard GI is named "*".) */
+ if ((t = FindTransByName("*"))) return t;
+
+ if (warnings && !specID)
+ fprintf(stderr, "Warning: transpec not found for %s\n", e->gi);
+
+ /* default spec - pass character data and descend node */
+ return &NullTrans;
+}
+
+/* ______________________________________________________________________ */
+/* Find translation spec by (GI) name. Returns the first one that matches.
+ * Arguments:
+ * Pointer to name of transpec (the "gi" field of the Trans structure).
+ * Return:
+ * Pointer to translation spec that matches name.
+ */
+
+Trans_t *
+FindTransByName(
+ char *s
+)
+{
+ Trans_t *t;
+
+ for (t=TrSpecs; t; t=t->next) {
+ /* check if tag name matches (first check 1st char, for efficiency) */
+ if (t->gi) {
+ if (*(t->gi) != *s) continue; /* check 1st character */
+ if (!strcmp(t->gi, s)) return t;
+ }
+ }
+ return NULL;
+}
+
+/* Find translation spec by its ID (SpecID).
+ * Arguments:
+ * Spec ID (an int).
+ * Return:
+ * Pointer to translation spec that matches name.
+ */
+Trans_t *
+FindTranByID(int n)
+{
+ Trans_t *t;
+
+ for (t=TrSpecs; t; t=t->next)
+ if (n == t->my_id) return t;
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Process a "chunk" of content data of an element.
+ * Arguments:
+ * Pointer to data content to process
+ * FILE pointer to where to write output.
+ */
+
+void
+DoData(
+ char *data,
+ FILE *fp,
+ int verbatim
+)
+{
+ if (!fp) return;
+ OutputString(data, fp, 1);
+}
+
+/* ______________________________________________________________________ */
+/* Handle a processing instruction. This is done similarly to elements,
+ * where we find a transpec, then do what it says. Differences: PI names
+ * start with '_' in the spec file (if a GI does not start with '_', it
+ * may be forced to upper case, sgmls keeps PIs as mixed case); the args
+ * to the PI are treated as the data of an element. Note that a PI wildcard
+ * is "_*"
+ * Arguments:
+ * Pointer to the PI.
+ * FILE pointer to where to write output.
+ */
+
+void
+DoPI(
+ char *pi,
+ FILE *fp
+)
+{
+ char buf[250], **tok;
+ int n;
+ Trans_t *t;
+
+ buf[0] = '_';
+ strcpy(&buf[1], pi);
+ n = 2;
+ tok = Split(buf, &n, 0);
+ if ((t = FindTransByName(tok[0])) ||
+ (t = FindTransByName("_*"))) {
+ if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
+ else {
+ if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
+ if (t->ignore != IGN_DATA) /* skip data nodes? */
+ if (n > 1) OutputString(tok[1], fp, 1);
+ if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
+ }
+ if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
+ }
+ else {
+ /* If not found, just print the PI in square brackets, along
+ * with a warning message. */
+ fprintf(fp, "[%s]", pi);
+ if (warnings) fprintf(stderr, "Warning: Unrecognized PI: [%s]\n", pi);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Set and increment variables, as appropriate, if the transpec says to.
+ * Arguments:
+ * Pointer to translation spec for current element.
+ */
+
+static void
+set_and_increment(
+ Trans_t *t,
+ Element_t *e
+)
+{
+ Mapping_t *m;
+ int i, inc, n;
+ char *cp, buf[50];
+ char ebuf[500];
+
+ /* set/reset variables */
+ if (t->set_var) {
+ for (m=t->set_var->maps,i=0; i<t->set_var->n_used; i++) {
+ ExpandVariables(m[i].sval, ebuf, e); /* do some expansion */
+ SetMappingNV(Variables, m[i].name, ebuf);
+ }
+ }
+
+ /* increment counters */
+ if (t->incr_var) {
+ for (m=t->incr_var->maps,i=0; i<t->incr_var->n_used; i++) {
+ cp = FindMappingVal(Variables, m[i].name);
+ /* if not set at all, set to 1 */
+ if (!cp) SetMappingNV(Variables, m[i].name, "1");
+ else {
+ if (isdigit(*cp) || (*cp == '-' && isdigit(cp[1]))) {
+ n = atoi(cp);
+ if (m[i].sval && isdigit(*m[i].sval)) inc = atoi(m[i].sval);
+ else inc = 1;
+ sprintf(buf, "%d", (n + inc));
+ SetMappingNV(Variables, m[i].name, buf);
+ } else
+ if (!*(cp+1) && isalpha(*cp)) {
+ buf[0] = *cp + 1;
+ buf[1] = 0;
+ SetMappingNV(Variables, m[i].name, buf);
+ }
+ }
+ }
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Translate one element.
+ * Arguments:
+ * Pointer to element under consideration.
+ * FILE pointer to where to write output.
+ * Pointer to translation spec for current element, or null.
+ */
+void
+TransElement(
+ Element_t *e,
+ FILE *fp,
+ Trans_t *t
+)
+{
+ int i;
+
+ if (!t) t = ((e && e->trans) ? e->trans : &NullTrans);
+
+ /* see if we should quit. */
+ if (t->quit) {
+ fprintf(stderr, "Quitting at location:\n");
+ PrintLocation(e, fp);
+ fprintf(stderr, "%s\n", t->quit);
+ exit(1);
+ }
+
+ /* See if we want to replace subtree (do text, don't descend subtree) */
+ if (t->replace) {
+ ProcesOutputSpec(t->replace, e, fp, 1);
+ if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
+ set_and_increment(t, e); /* adjust variables, if appropriate */
+ return;
+ }
+
+ if (t->starttext) ProcesOutputSpec(t->starttext, e, fp, 1);
+ if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
+
+ /* Process data for this node and descend child elements/nodes. */
+ if (t->ignore != IGN_ALL) {
+ /* Is there a "generated" node at the front of this one? */
+ if (e->gen_trans[0]) {
+ Trans_t *tp;
+ if ((tp = FindTranByID(e->gen_trans[0]))) {
+ if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
+ if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
+ if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
+ }
+ }
+ /* Loop thruthe "nodes", whether data, child element, or PI. */
+ for (i=0; i<e->ncont; i++) {
+ if (IsContElem(e,i)) {
+ if (t->ignore != IGN_CHILDREN) /* skip child nodes? */
+ TransElement(ContElem(e,i), fp, NULL);
+ }
+ else if (IsContData(e,i)) {
+ if (t->ignore != IGN_DATA) /* skip data nodes? */
+ DoData(ContData(e,i), fp, t->verbatim);
+ }
+ else if (IsContPI(e,i))
+ DoPI(e->cont[i].ch.data, fp);
+ }
+ /* Is there a "generated" node at the end of this one? */
+ if (e->gen_trans[1]) {
+ Trans_t *tp;
+ if ((tp = FindTranByID(e->gen_trans[1]))) {
+ if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
+ if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
+ if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
+ }
+ }
+ }
+
+ set_and_increment(t, e); /* adjust variables, if appropriate */
+
+ if (t->endtext) ProcesOutputSpec(t->endtext, e, fp, 1);
+
+ e->processed = 1;
+}
+
+/* ______________________________________________________________________ */
+/* Check if element matches specified relationship, and, if it does, perform
+ * action on either current element or matching element (depends on flag).
+ * Arguments:
+ * Pointer to element under consideration.
+ * Pointer to relationship name.
+ * Pointer to related element name (GI).
+ * Pointer to action to take (string - turned into an int).
+ * FILE pointer to where to write output.
+ * Flag saying whether to do action on related element (RA_Related)
+ * or on current element (RA_Current).
+ * Return:
+ * Bool, saying whether (1) or not (0) relationship matches.
+ */
+
+int
+CheckRelation(
+ Element_t *e,
+ char *relname, /* relationship name */
+ char *related, /* related element */
+ char *actname, /* action to take */
+ FILE *fp,
+ RelAction_t flag
+)
+{
+ Element_t *ep;
+ Relation_t r;
+
+ if ((r = FindRelByName(relname)) == REL_Unknown) return 0;
+ if (!(ep=QRelation(e, related, r))) return 0;
+
+ if (!actname) return 1; /* no action - return what we found */
+
+ switch (flag) {
+ case RA_Related: TranTByAction(ep, actname, fp); break;
+ case RA_Current: TranTByAction(e, actname, fp); break;
+ }
+ return 1;
+}
+
+/* ______________________________________________________________________ */
+/* Perform action given by a SpecID on the given element.
+ * Arguments:
+ * Pointer to element under consideration.
+ * SpecID of action to perform.
+ * FILE pointer to where to write output.
+ *
+ */
+void
+TranByAction(
+ Element_t *e,
+ int n,
+ FILE *fp
+)
+{
+ Trans_t *t;
+
+ t = FindTranByID(n);
+ if (!t) {
+ fprintf(stderr, "Could not find named action for %d.\n", n);
+ return;
+ }
+ TransElement(e, fp, t);
+}
+
+/* ______________________________________________________________________ */
+/* Perhaps perform action given by a SpecID on the given element.
+ * Arguments:
+ * Pointer to element under consideration.
+ * SpecID of action to perform. Unlike TranByAction, this is the argument
+ * as it occurred in the transpec (ASCII) and may end with the letter
+ * "t" which means that the transpec mustpass criteria selection.
+ * FILE pointer to where to write output.
+ */
+void
+TranTByAction(
+ Element_t *e,
+ char *strn,
+ FILE *fp
+)
+{
+ int n;
+ Trans_t *t;
+
+ n = atoi(strn);
+ if ( strn[strlen(strn)-1] != 't' ) {
+ t = FindTranByID(n);
+ if (!t) {
+ fprintf(stderr, "Could not find named action for %d.\n", n);
+ return;
+ }
+ } else {
+ t = FindTrans(e, n);
+ if ( !t || !t->my_id )
+ return;
+ }
+ TransElement(e, fp, t);
+}
+
+/* ______________________________________________________________________ */
diff --git a/usr.bin/sgmls/instant/translate.h b/usr.bin/sgmls/instant/translate.h
new file mode 100644
index 0000000..777d591
--- /dev/null
+++ b/usr.bin/sgmls/instant/translate.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * Program to manipulate SGML instances.
+ *
+ * These are data definitions for the "translating" portion of the program.
+ *
+ * ________________________________________________________________________
+ */
+
+#ifdef STORAGE
+#ifndef lint
+static char *tr_h_RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/translate.h,v 1.3 1996/06/02 21:47:32 fld Exp $";
+#endif
+#endif
+
+#define L_CURLY '{'
+#define R_CURLY '}'
+
+/* things to ignore when processing an element */
+#define IGN_NONE 0
+#define IGN_ALL 1
+#define IGN_DATA 2
+#define IGN_CHILDREN 3
+
+/* for CheckRelation() */
+typedef enum { RA_Current, RA_Related } RelAction_t;
+
+typedef struct {
+ char *name; /* attribute name string */
+ char *val; /* attribute value string */
+ regexp *rex; /* attribute value reg expr (compiled) */
+} AttPair_t;
+
+typedef struct _Trans {
+ /* criteria */
+ char *gi; /* element name of tag under consideration */
+ char **gilist; /* list of element names (multiple gi's) */
+ char *context; /* context in tree - looking depth levels up */
+ regexp *context_re; /* tree heirarchy looking depth levels up */
+ int depth; /* number of levels to look up the tree */
+ AttPair_t *attpair; /* attr name-value pairs */
+ int nattpairs; /* number of name-value pairs */
+ char *parent; /* GI has this element as parent */
+ int nth_child; /* GI is Nth child of this of parent element */
+ char *content; /* element has this string in content */
+ regexp *content_re; /* content reg expr (compiled) */
+ char *pattrset; /* is this attr set (any value) in parent? */
+ char *var_name; /* variable name */
+ char *var_value; /* variable value */
+ char *var_RE_name; /* variable name (for VarREValue) */
+ regexp *var_RE_value; /* variable value (compiled, for VarREValue) */
+ Map_t *relations; /* various relations to check */
+
+ /* actions */
+ char *starttext; /* string to output at the start tag */
+ char *endtext; /* string to output at the end tag */
+ char *replace; /* string to replace this subtree with */
+ char *message; /* message for stderr, if element encountered */
+ int ignore; /* flag - ignore content or data of element? */
+ int verbatim; /* flag - pass content verbatim or do cmap? */
+ char *var_reset;
+ char *increment; /* increment these variables */
+ Map_t *set_var; /* set these variables */
+ Map_t *incr_var; /* increment these variables */
+ char *quit; /* print message and exit */
+
+ /* pointers and bookkeeping */
+ int my_id; /* unique (hopefully) ID of this transpec */
+ int use_id; /* use transpec whose ID is this */
+ struct _Trans *use_trans; /* pointer to other transpec */
+ struct _Trans *next; /* linked list */
+ int lineno; /* line number of end of transpec */
+} Trans_t;
+
+#ifdef def
+#undef def
+#endif
+#ifdef STORAGE
+# define def
+#else
+# define def extern
+#endif
+
+def Trans_t *TrSpecs;
+def Mapping_t *CharMap;
+def int nCharMap;
+
+/* prototypes for things defined in translate.c */
+int CheckRelation(Element_t *, char *, char *, char *, FILE*, RelAction_t);
+Trans_t *FindTrans(Element_t *, int);
+Trans_t *FindTransByName(char *);
+Trans_t *FindTransByID(int);
+void PrepTranspecs(Element_t *);
+void ProcessOneSpec(char *, Element_t *, FILE *, int);
+void TransElement(Element_t *, FILE *, Trans_t *);
+void TranByAction(Element_t *, int, FILE *);
+void TranTByAction(Element_t *, char *, FILE *);
+
+/* prototypes for things defined in tranvar.c */
+void ExpandSpecialVar(char *, Element_t *, FILE *, int);
+
+/* prototypes for things defined in tables.c */
+void OSFtable(Element_t *, FILE *, char **, int);
+
+/* ______________________________________________________________________ */
+
diff --git a/usr.bin/sgmls/instant/transpec.5 b/usr.bin/sgmls/instant/transpec.5
new file mode 100644
index 0000000..297b9d0
--- /dev/null
+++ b/usr.bin/sgmls/instant/transpec.5
@@ -0,0 +1,528 @@
+...\"
+...\"
+...\" Copyright (c) 1994
+...\" Open Software Foundation, Inc.
+...\"
+...\" Permission is hereby granted to use, copy, modify and freely distribute
+...\" the software in this file and its documentation for any purpose without
+...\" fee, provided that the above copyright notice appears in all copies and
+...\" that both the copyright notice and this permission notice appear in
+...\" supporting documentation. Further, provided that the name of Open
+...\" Software Foundation, Inc. ("OSF") not be used in advertising or
+...\" publicity pertaining to distribution of the software without prior
+...\" written permission from OSF. OSF makes no representations about the
+...\" suitability of this software for any purpose. It is provided "as is"
+...\" without express or implied warranty.
+...\"
+...\" Copyright (c) 1996 X Consortium
+...\" Copyright (c) 1996 Dalrymple Consulting
+...\"
+...\" Permission is hereby granted, free of charge, to any person obtaining a copy
+...\" of this software and associated documentation files (the "Software"), to deal
+...\" in the Software without restriction, including without limitation the rights
+...\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+...\" copies of the Software, and to permit persons to whom the Software is
+...\" furnished to do so, subject to the following conditions:
+...\"
+...\" The above copyright notice and this permission notice shall be included in
+...\" all copies or substantial portions of the Software.
+...\"
+...\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+...\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+...\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+...\" X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+...\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+...\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+...\" OTHER DEALINGS IN THE SOFTWARE.
+...\"
+...\" Except as contained in this notice, the names of the X Consortium and
+...\" Dalrymple Consulting shall not be used in advertising or otherwise to
+...\" promote the sale, use or other dealings in this Software without prior
+...\" written authorization.
+...\"
+...\" Translated with /usr/local/lib/tpt/ref-man.ts by fld on cord, Wed 07 Feb 1996, 22:00
+.TH "\fBtranspec\fP" "file format"
+.SH "Name"
+\fBtranspec\fP - translation specification for \fBinstant\fP
+.SH "Synopsis"
+.na
+.PP
+\fBfile.ts\fP
+.ad
+.SH "Description"
+.PP
+The \fBtranspec\fP file is used by the \fBinstant\fP program to translate an SGML document instance to a format suitable for a formatting application.
+The convention is to name the file with the suffix \fB.ts\fP.
+.PP
+A \fBtranspec\fP file is composed of a number of individual translation specs.
+Each translation spec (transpec) is made up of a number of fields, one per line.
+Translation specs are separated by a line with a leading dash. Text after the dash is ignored.
+Fields are composed of two parts, a name and a value, separated by a colon.
+The colon must immediately follow the name, and any amount of whitespace (blanks and tabs) may be present between the colon and value.
+Values should not be quoted, and you should be careful of trailing spaces.
+(Trailing space will be considered part of the value.)
+Quotes, if they appear, will be considered part of the value of the fields.
+Lines that begin with whitespace (blanks and tabs) are a continuation of the previous line; the leading space is ignored.
+These characteristics are very similar to those of e-mail headers.
+Lines beginning with a \fB#\fP (number sign) are comments and blank lines are ignored.
+.SH "Field Descriptions"
+.PP
+Some fields are for identifying criteria that determines if a particular spec matches an element in the instance.
+Others specify what action is to take place when a match happens, such as sending text to the output stream.
+.SS "Criteria fields"
+.PP
+Criteria fields restrict the conditions under which a single translation spec will apply.
+If each field specified in a particular transpec matches an element under consideration in the document instance,
+then that translation spec is said to match. The appropriate actions, as specified in that spec, are then taken.
+The program, \fBinstant\fP, searches the list of transpecs in the order given in the file.
+Therefore, the more restrictive specs (those with more criteria) should appear before less restrictive ones.
+.PP
+For quick reference, this is a brief summary of the possible criteria fields for translation. A complete discussion of each follows.
+.P
+.TS
+tab(@);
+l l l.
+\fBField Label\fR@\fBField Value\fR@\fBDescription\fR
+GI@gi ...@name of this GI
+AttValue@attname reg-expr@current element has attribute with value
+Content@reg-expr@is reg-expr in char content>
+Context@context@element context, up the tree
+NthChild@number@current element is Nth child of its parent
+PAttSet@attname (val)@parent has this attribute set (optional to value val)
+Relation@relationship gi@gi has relationship to current element
+VarREValue@var REvalue@variable is set to regular expression value
+VarValue@var value@variable is set to value
+.TE
+'br\" labeled list
+.IP "\fBGI:\fP \fIgi\fP [...]"
+\fIgi\fP is the name of the generic identifier, or element name, to consider.
+More than one GI may appear in this field.
+.IP "\fBAttValue:\fP \fIattname\fP \fIregular-expression\fP"
+This is an attribute name-value pair, where \fIattname\fP is an attribute if the GI.
+The \fIregular-expression\fP is of the form accepted by the unix program \fBegrep\fP.
+This pair is compared to the corresponding attribute name-value pairs of the GI under consideration.
+To simply test if an attribute us set, use \fB.\fP (a dot) for \fIregular-expression\fP.
+There may be more than one of these lines for each transpec.
+.IP "\fBContent:\fP \fIregular-expression\fP"
+This specifies that the character content of GI contains a string matching the \fIregular-expression\fP.
+.IP "\fBContext:\fP \fIcontext\fP"
+This specifies the \fIcontext\fP in which to apply this translation spec.
+It is either a list of generic identifiers or a regular expression describing a list of generic identifiers, looking up the hierarchy.
+The first is the parent of the GI.
+.IP "\fBNthChild:\fP \fInumber\fP"
+This specifies that the GI is the \fInumber\fPth child element of its parent.
+Children are numbered starting with \fB1\fP.
+Negative numbers may be used to indicate order counting backwards.
+For example, -1 denotes the last child.
+.IP "\fBPAttSet:\fP \fIattname\fP"
+This specifies that the parent has this attribute, \fIattname\fP, set to any value (not IMPLIED). A value to match may optionally
+be specified after attname.
+.IP "\fBRelation:\fP \fIrelationship\fP \fIgi\fP"
+This specifies that the current element has the \fIrelationship\fP to the named \fIgi\fP.
+The acceptable relationships are: \fBancestor\fP (anywhere up the tree), \fBchild\fP (immediate child),
+\fBdescendant\fP (anywhere down the tree), \fBparent\fP (immediate ancestor), \fBsibling\fP (share same parent element),
+\fBsibling+\fP (any later sibling), \fBsibling+1\fP (the immediately following sibling), \fBsibling-\fP (any earlier sibling),
+\fBsibling-1\fP (the immediately following sibling).
+.IP "\fBVarREValue:\fP \fIvarname\fP \fIREvalue\fP"
+This specifies that the global variable \fIvarname\fP has the value \fIREvalue\fP,
+where \fIREvalue\fP is a regular expression
+(see the \fBVarValue\fP statement).
+.IP "\fBVarValue:\fP \fIvarname\fP \fIvalue\fP"
+This specifies that the global variable \fIvarname\fP has the (literal)
+value \fIvalue\fP (see the \fBVarREValue\fP statement).
+'br\" labeled list end
+.PP
+There are two special GIs.
+If specified, \fB_Start\fP and \fB_End\fP are processed as if they were GIs in the instance at the start and end of the translation, respectively.
+Their criteria are never checked. Only their actions are performed.
+.SS "Action fields"
+.PP
+For quick reference, this is a brief summary of the action fields for translation. They are only performed if all the criteria are satisfied.
+A complete discussion of each follows.
+.P
+.TS
+tab(@);
+l l l.
+\fBField Label\fR@\fBField Value\fR@\fBDescription\fR
+Action@spec-id@use transpec whose spec ID is `spec-id'
+EndText@text@text for end of element
+Increment@name@increment variable `name'
+Ignore@key@flag for ignoring element's children and/or data
+Message@text@text to send to stderr
+Quit@text@print text and quit program
+Replace@text@replace this subtree with text
+Set@name value@set variable \fIname\fP to \fIvalue\fP
+SpecID@spec-id@unique Spec ID (int) of this spec
+StartText@text@text for start of element
+.TE
+'br\" labeled list
+.IP "\fBAction:\fP \fIspec-id\fP"
+Use the actions of the spec identified by the \fBSpecID\fP with matching identifier \fIspec-id\fP.
+.IP "\fBEndText:\fP \fItext\fP"
+This specifies text to be output when the end tag is processed.
+.IP "\fBIgnore:\fP \fIkey\fP"
+This specifies that the data or children for this element are to be ignored.
+Set \fIkey\fP to \fBall\fP to ignore the element (data and child elements),
+to \fBdata\fP to ignore the immediate character data content (child elements are still descended into),
+and to \fBchildren\fP to process the immediate character data content but not descended into child elements.
+Other actions specified in this transpec are still performed, however.
+.IP "\fBIncrement:\fP \fIname\fP"
+This is used to increment a variable whose value is a number.
+If the variable is not a number, no action will be taken.
+The variable must have been previously defined. This action is done immediately before \fBEndText\fP.
+There may be more than one of these lines for each transpec.
+.IP "\fBMessage:\fP \fItext\fP"
+This specifies a string to be printed to the standard error when the matching element is processed.
+It is intended for informing the user of the progress of the translation.
+It is also used for validation of instances (see the \fB-v\fP flag of \fBinstant\fP(1));
+a spec would be written to recognize a construct that is not allowed.
+This action is done immediately after \fBStartText\fP.
+Messages are also useful for debugging spec files; one is able to easily tell when a matching spec is processed,
+without looking at the actual output of the translation.
+Note that the spec writer is responsible for putting newlines (\fB\en\fP) in the message text.
+.IP "\fBReplace:\fP \fItext\fP"
+This specifies text to replace the current subtree with.
+This is equivalent to \fBStartText\fP and \fBIgnore\fP.
+.IP "\fBQuit:\fP \fItext\fP"
+This specifies text to be printed to the standard error. The program then terminates with exit status 1.
+This is intended for bailing out when an undesirable instance is encountered
+(such as when it is known that the formatting application can never handle a class of components, like tables).
+.IP "\fBSet:\fP \fIname\fP \fIvalue\fP"
+This is used to set a variable whose name is \fIname\fP and value is \fIvalue\fP.
+Names that would be valid for GIs in the document instance are valid for variable names.
+\fIvalue\fP is the rest of the line and may be any string. This action is done immediately before \fBEndText\fP.
+There may be more than one of these lines for each transpec.
+See the discussion on variables below.
+.IP "\fBSpecID:\fP \fIspec-id\fP"
+This names the spec with the number \fIspec-id\fP. Other specs may refer to this one by this number by an \fBAction\fP field or an \fB_action\fP special variable.
+This is used for cases where several specs to perform the exact same action.
+.IP "\fBStartText:\fP \fItext\fP"
+This specifies text to be output when the start tag is processed.
+'br\" labeled list end
+.SS "Other Fields"
+.PP
+These fields may appear anywhere. The action occurs when the translation spec file is read, before any elements are translated.
+Theses are independent of any element processing.
+'br\" labeled list
+.IP "\fBVar:\fP \fIname\fP \fIvalue\fP"
+This is used to define a variable whose name is \fIname\fP and value is \fIvalue\fP.
+It is similar to \fBSet\fP, but it may occur anywhere in the file and takes effect when the spec file is read.
+'br\" labeled list end
+.SS "Text Strings"
+.PP
+The \fItext\fP referred to in the \fBStartText\fP, \fBEndText\fP, \fBReplace\fP,
+and \fBMessage\fP actions is more than simple character strings.
+Special sequences allow more complex output.
+.PP
+One type of special sequence is for C-style string processing.
+Most special characters are escaped with a \e (backslash). Like in C or shell programs, to print a \e (backslash), you must escape it with another backslash. These special character strings are:
+'br\" labeled list
+.IP "\fB\en (backslash-n)\fP"
+This specifies that a newline character is to be printed to the output stream.
+.IP "\fB\er (backslash-r)\fP"
+This specifies that a carriage return character is to be printed to the output stream.
+.IP "\fB\et (backslash-t)\fP"
+This specifies that a tab character is to be printed to the output stream.
+.IP "\fB\es (backslash-s)\fP"
+This specifies that a space is to be printed to the output stream.
+This is useful for the end of a transpec line, where it can be difficult to tell if a blank is present at the end.
+.IP "\fB\e007 (backslash-007)\fP"
+This specifies that the character whose octal value is 007 is to be printed to the output stream.
+This works for any octal character value.
+.IP "\fB^ (caret)\fP"
+This specifies the that position in the string will be at the start of a line in the output stream.
+'br\" labeled list end
+.PP
+If the first token of the text string is \fB#include\fP, then the second token is taken to be a file name and that file is included.
+If the file is not found, the library directory, as mentioned above, is searched.
+If the text string starts with a \fB!\fP (exclamation point), the rest of the line is taken to be a command and the output of that command is inserted.
+.PP
+An element's attributes may also be used in the text of output fields.
+To use an attribute value, precede its name with a \fB${\fP (dollar sign-left curly bracket) and follow it with a \fB}\fP (right curly bracket).
+(This style is followed by the Bourne shell.) For example, \fB${TYPE}\fP.
+If the attribute is not set (not IMPLIED), nothing will be printed to the output stream.
+To specify a value to use if the attribute is not set, place the value after the attribute name, separated by a space.
+To return the attribute value in lower-case, add a colon followed by
+lower-case l (\fB${TYPE:l}\fP.
+.SH "Variables"
+.PP
+Variables in \fBinstant\fP are similar to those in many other string-oriented programming languages, such as \fBsh\fP and \fBawk\fP.
+They are set by: \fBVar:\fP \fIname\fP \fIvalue\fP and \fBSet:\fP \fIname\fP \fIvalue\fP.
+Values may be set and reset to any string.
+In a \fBVar\fP line, if the value begins with a \fB!\fP,
+then the rest of the line is executed as a command, and its output is taken as the \fIvalue\fP.
+.PP
+A reference to the value of a variable follows the same syntax as
+a reference to the value of an attribute: \fB${\fIname\fB}\fR.
+If that variable has not been defined, a null value will be returned.
+A default value can be returned instead of null for an undefined variable
+by using the form: \fB${\fIname default\fB}\fR.
+.PP
+Variables may be used as attributes are, that is in any of the text strings mentioned above.
+In fact, if an attribute name is referred to and it is not set for a given element,
+\fBinstant\fP looks for a variable with the same name. This way global defaults can be set.
+If you want to be sure that you are accessing a local variable value, not an attribute value, you can use lower or mixed case names.
+Attribute names, as passed by \fBsgmls\fP, are in upper case.
+.PP
+Any number of \fBVar\fP actions may appear in the spec file. These set the values of the variables before any translation takes place.
+The \fBSet\fP actions within transpecs are performed when that spec is processed when an element matches the given criteria.
+.SS "Preset Variables"
+.PP
+Several variables are preset by \fBinstant\fP upon start of the program.
+Their values may be overridden in transpec files or on the command line.
+'br\" labeled list
+.IP "\fBdate\fP"
+This is the date and time that the program started. The format is: \f(CWTue 10 Aug 1993, 16:52\fP.
+.IP "\fBhost\fP"
+This is the name of the host where the program is run. It is what is returned by the \fBgethostname\fP library call.
+.IP "\fBtranspec\fP"
+This is the translation spec filename.
+.IP "\fBuser\fP"
+This is the login name of the user running the program.
+'br\" labeled list end
+.SS "Special Variables"
+.PP
+There is a collection of special variables called \fIspecial variables\fP.
+These are identified by starting the names with a \fB_\fP (underscore).
+This is a summary of the special variables. A complete discussion of each special variable follows.
+\fBspec-id\fP refers to a number specified in a \fBSpecID\fP field.
+When used in a special variable, it means to perform the action in that translation spec.
+.PP
+Note that when a \fIspec-id\fR is given in a special variable,
+the default is to perform the translation spec named by the \fIspec-id\fR ignoring
+of any criteria statements found there.
+For most special variables that use a \fIspec-id\fP, postpending a "\fBt\fR" to
+the \fIspec-id\fR (with no spaces between them, eg,
+"\fB${_followrel child TITLE 15t}\fR"), will cause the criteria statements
+in the named translation spec to evaluate successfully before that translation
+spec will be processed.
+.P
+.TS
+tab(@);
+l l.
+\fBVariable Usage\fR@\fBDescription\fR
+\fB_action\fP \fIspec-id\fP@do spec with id spec-id
+\fB_allatts\fP@print all attribute/value pairs
+\fB_attval\fP \fIatt\fP [\fIvalue\fP] \fIspec-id\fP@use spec-id if attribute matches
+\fB_chasetogi\fP \fIgi\fP \fIspec-id\fP@follow IDREFs until gi found
+\fB_eachatt\fP \fIatt\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id for each word of attribute value
+\fB_eachcon\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id for each word of content
+\fB_env\fP \fIenv-variable\fP@return value of env variable
+\fB_filename\fP@filename of notation
+\fB_find\fP \fIrel\fP \fIgi\fP \fIspec-id\fP@find gi based on relationship
+\fB_followlink\fP [\fIattname\fP] \fIspec-id\fP@follow IDREFs [attname] and use spec-id
+\fB_followrel\fP \fIrel\fP \fIgi\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id on rel if it matches
+\fB_gi\fP [\fBM|L|U\fP]@return GI name; M, L, U case
+\fB_id\fP \fIid [\fP\fIspec-id\fP]@find element with ID and use spec-id
+\fB_include\fP \fIfilename\fP@insert file here
+\fB_infile\fP [\fBline\fP]@instance filename [and line number]
+\fB_insertnode\fP S|E \fIspec-id\fP@do spec-id when element is traversed
+\fB_isset\fP \fIvar\fP [\fIvalue\fP] \fIspec-id\fP@do spec-id if variable matches
+\fB_location\fP@print location of current element
+\fB_namelist\fP \fIspec-id\fP [\fIspec-id\fP]@content is namelist, do spec-id for each
+\fB_nchild\fP [\fIgi\fP]@number of child elements [named \fIattname\fP]
+\fB_osftable\fP \fIformat\fP [\fIflag\fP]@print table format specification
+\fB_path\fP@print path to current element
+\fB_pattr\fP \fIattname\fP@value of parent's attribute
+\fB_pfind\fP \fIargs ...\fP@same as \fB_find\fP, but start at parent
+\fB_relation\fP \fIrel\fP \fIgi\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id if relation matches
+\fB_set\fP \fIvar\fP \fIvalue\fP@set variable to value
+\fB_!\fP\fIcommand\fP@command to run
+.TE
+'br\" labeled list
+.IP "\fB_action\fP \fIspec-id\fP"
+Use the actions of the spec identified by the \fBSpecID\fP with matching identifier \fIspec-id\fP.
+This behaves similarly to the \fBAction\fP action, but is in addition to the present translation spec.
+.IP "\fB_allatts\fP"
+Print all attribute name-value pairs of the current element to the output stream.
+The name and value are separated by a \fB=\fP (equals sign), and the value is surrounded by quotes.
+This can be useful for creating a normalized version of the instance.
+.IP "\fB_attval\fP \fIattname\fP [\fIvalue\fP] \fIspec-id\fP"
+If the current element has an attribute named \fIattname\fP, optionally whose value matches \fIvalue\fP,
+use the actions of the transpec identified by \fIspec-id\fP.
+.IP "\fB_chasetogi\fP \fIgi\fP \fIspec-id\fP"
+Follow IDREF attributes until if finds an element whose GI is \fIgi\fP or which has a child element with that GI.
+It will apply the transpec \fIspec-id\fP to that element.
+By default, \fBinstant\fP assumes the attributes named \fBLINKEND\fP, \fBLINKENDS\fP, and \fBIDREF\fP are of type IDREF or IDREFS.
+(This corresponds with the OSF DTDs.)
+You can change this by setting the variable \fBlink_atts\fP to a space-separated list of attribute names.
+.IP "\fB_eachatt\fP \fIatt\fP \fIspec-id\fP [\fIspec-id2\fP]"
+The transpec named by \fIspec-id\fR is invoked once per each word
+found in the value of the attribute \fIatt\fR.
+Inside the target transpec, the current word being processed
+is available in the variable named \fBeach_A\fR (\fB${each_A}\fR).
+If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first word
+in the attribute and \fIspec-id2\fP for the others.
+.IP "\fB_eachcon\fP \fIspec-id\fP [\fIspec-id2\fP]"
+The transpec named by \fIspec-id\fR is invoked once per each word
+found in the content of the current element.
+Inside the target transpec, the current word being processed
+is available in the variable named \fBeach_C\fR (\fB${each_C}\fR).
+If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first word
+in the content and \fIspec-id2\fP for the others.
+.IP "\fB_env\fP \fIenv-variable\fP"
+Print the value of the environment variable \fIenv-variable\fP to the output stream.
+.IP "\fB_filename\fP"
+Print the filename of the notation associated with this element, if any.
+This is used to get the filename of an external notation entity reference.
+For example, to print the filename in the latex macro from the epsf macro package, use \f(CW\e\eepsfboxi{${_filename}}\fP.
+.IP "\fB_find\fP [\fBtop\fP] \fIrelationship\fP \fIargs ...\fP \fIspec-id\fP"
+Descend the document hierarchy finding elements that match one of several criteria.
+When one is found, the action specified by \fIspec-id\fP is performed.
+If \fBtop\fP is specified, the search starts at the top of the document hierarchy, rather than at the current element.
+The possible values for \fIrelationship\fP are \fBgi\fP, \fBgi-parent\fP, \fBparent\fP, and \fBattr\fP,
+and take different arguments.
+Explanations may be best done by example:
+\fB_find gi CHAPTER 123\fP means to find elements whose GI is CHAPTER, and perform action 123;
+\fB_find gi-parent TITLE CHAPTER 124\fP means to find elements whose GI is TITLE and whose parent is CHAPTER, and perform action 124;
+\fB_find parent BODY 125\fP means to find elements whose parent's GI is BODY, and perform action 125;
+\fB_find attr TYPE UGLY 125\fP means to find elements whose attribute named TYPE is set to UGLY, and perform action 126.
+.IP "\fB_followlink\fP [\fIattname\fP] \fIspec-id\fP"
+When processing an element, \fBinstant\fP will follow the IDREF attributes until an element with no IDREF attributes is found.
+It will then apply the transpec specified by \fIspec-id\fP to that element.
+If specified, it will follow the link pointed to by \fIattname\fP.
+By default, \fBinstant\fP assumes the attributes named \fBLINKEND\fP and \fBLINKENDS\fP are if type IDREF or IDREFS.
+You can change this by setting the variable \fBlink_atts\fP to a space-separated list of attribute names.
+.IP "\fB_followrel\fP \fIrelationship\fP \fIgi\fP \fIspec-id\fP [\fIspec-id2\fP]"
+If the \fIgi\fP has the specified \fIrelationship\fP to the current element,
+perform the action specified by \fIspec-id\fP on the related element.
+If the \fIrelationship\fP to \fIgi\fP does not exist,
+and \fIspec-id2\fP is present, perform \fIspec-id2\fP on the current element.
+See the discussion of the criteria field \fBRelation\fP for acceptable relationship names.
+.IP "\fB_gi\fP [\fBM|L|U\fP]"
+Print the name of the current GI to the output stream.
+If specified, \fBM\fP, \fBL\fP, or \fBU\fP will ensure the GI name is printed in mixed, lower, or upper case, respectively.
+.IP "\fB_id\fP \fIid\fP [\fIspec-id\fP]"
+Find the element with \fIid\fP and use \fIspec-id\fP, if set. If not set, use the spec for that element's context.
+.IP "\fB_include\fP \fIfilename\fP"
+Insert the file \fIfilename\fP into the output stream.
+.IP "\fB_infile\fP [\fBline\fP]"
+Print the name of the sgml instance file to the output stream. If \fBline\fP is specified, also print the line number.
+This depends on \fBsgmls\fP being called with the \fB-l\fP option.
+.IP "\fB_insertnode\fP \fBS\fP|\fBE\fP \fIspec-id\fP"
+Do \fIspec-id\fP when the current element is traversed at a later pass.
+This can be considered inserting a node, without content, into the hierarchy.
+This is only useful if done to elements \fIbefore\fP they are processed.
+Typically \fB_chasetogi\fP or \fB_followlink\fP is specified early in an instance's processing,
+so that when the elements found by one of these actions are processed in their turn, the added actions are performed.
+\fB_insertnode\fP would be specified as the action of a \fIspec-id\fP pointed to in a \fB_chasetogi\fP or \fB_followlink\fP usage.
+.IP "\fB_location\fP"
+The location of the current element is printed to the output stream in several ways: the path to the element (see \fB_path\fP),
+a position hint, which is the nearest title, the line number, if the ESIS (output from \fBsgmls\fP) contains line numbers,
+and the ID of the element, if it has one.
+This is especially useful when using the \fBMessage\fP action to validate an instance.
+.IP "\fB_namelist\fP \fIspec-id\fP [\fIspec-id2\fP]"
+This assumes that the content of the current element is a namelist (a list of element IDs),
+and applies the action based on \fIspec-id\fP for each element pointed to.
+If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first ID in the namelist and \fIspec-id2\fP for the others.
+.IP "\fB_nchild\fP [\fIgi\fP]"
+Print the number of child elements of the element to the output stream.
+If \fIgi\fP is specified, print the number of child element with that name.
+.IP "\fB_osftable\fP \fBtex\fP|\fBtbl\fP|\fBcheck\fP [\fIflag\fP]"
+Print table markup into the output stream. The format depends on whether \fBtex\fP or \fBtbl\fP is specified.
+The \fIflag\fP may be one of \fBcellstart\fP, \fBcellend\fP, \fBrowstart\fP, \fBrowend\fP, \fBtop\fP, or \fBbottom\fP.
+The value determines what markup or text will be generated.
+If \fBcellstart\fP is specified, the correct markup for the beginning of a cell is output.
+If \fBtop\fP, \fBbottom\fP, or \fBrowend\fP are specified,
+the correct markup for the end of the appropriate position is printed to the output stream.
+If \fBcheck\fP is specified, the attributes and child elements are checked for errors and consistency.
+.IP "\fB_path\fP"
+Print the path to current GI to the output stream. A path is each element, going down the tree from the topmost element.
+A number in parentheses after each element name shows which child element the next one is in the order of children for that element.
+Ordering starts at 0.
+For example: \f(CWOSF-BOOK(3) BODY(0) CHAPTER(4) SECTION\fP.
+This says the path is \fB<OSF-BOOK>\fP's third child, \fB<BODY>\fP's zeroth,
+and \fB<CHAPTER>\fP's fourth, which is named \fB<SECTION>\fP.
+.IP "\fB_pattr\fP \fIname\fP"
+Print the value of parent's attribute whose name is \fIname\fP to the output stream.
+.IP "\fB_pfind\fP \fIrel\fP \fIgi\fP \fIspec-id\fP"
+This is exactly the same as \fB_find\fP except that the search starts at the current element's parent.
+.IP "\fB_relation\fP \fIrelationship\fP \fIgi\fP \fIspec-id\fP [\fIspec-id2\fP]"
+If the \fIgi\fP has the specified \fIrelationship\fP to the current element,
+perform the action specified by \fIspec-id\fP on the current element.
+If the relationship test fails and \fIspec-id2\fP is specified, perform that action.
+See the discussion of the criteria field \fBRelation\fP for acceptable relationship names.
+.IP "\fB_set\fP \fIvarname\fP \fIvalue\fP"
+Set the value of the variable \fIvarname\fP to \fIvalue\fP.
+.IP "\fB_isset\fP \fIvarname\fP [\fIvalue\fP] \fIspec-id\fP"
+If the value of the variable \fIvarname\fP is set to \fIvalue\fP, then perform action referred to by \fIspec-id\fP.
+If \fIvalue\fP is not specified, action will be performed if \fIvarname\fP is set to any value.
+.IP "\fB_!\fP \fIcommand\fP"
+Run the command \fIcommand\fP, directing its standard output into the output stream.
+'br\" labeled list end
+.SS "Immediate Variables"
+.PP
+\fIImmediate variables\fR are like special variables, except that they
+are expanded when the transpec is originally processed (special
+variables are processed later, near when the final output is being generated).
+The general syntax of immediate variables is \fB${+\fIimmediate_variable\ ...\fB}\fR.
+.PP
+There is currently only one immediate variable defined:
+.IP "\fB+content\fP"
+This special variable is replaced by the data content of the current element.
+.SH "Examples"
+.PP
+The following will output the given string for elements whose generic identifier is \fBP\fP (for paragraph).
+At the start of processing this element, the program ensures that the output starts on a new line,
+the \fBtroff\fP macro \fB<.P>\fP is output, then a newline.
+At the end of this element processing, the program ensures that the output starts on a new line.
+.DS
+.nf
+.ft CW
+GI: P
+StartText: ^.P^
+EndText: ^
+-
+.ft R
+.fi
+.DE
+.PP
+The following will output the given string for elements whose generic identifier is \fBCMD-ARGUMENT\fP and which have an
+attribute \fBPRESENCE\fP set to the value \fBOPTIONAL\fP.
+.DS
+.nf
+.ft CW
+GI: CMD-ARGUMENT
+AttValue: PRESENCE OPTIONAL
+StartText: $\e\e[
+EndText: $\e\e]
+-
+.ft R
+.fi
+.DE
+.PP
+The following prints the section number, title, and page number of the target of a cross reference.
+Assume the cross reference points to a section element, which contains a title element.
+The criteria for this spec to match is that the attribute \fBOSFROLE\fP is set to the value \fBgetfull\fP.
+The action is to replace the content of the \fB<XREF>\fP element with the given string.
+When processing the string, \fBinstant\fP will follow the IDREF attributes of \fB<XREF>\fP
+until an element with no IDREF attributes is found. It will then apply the transpec numbered \fB87\fP to that element,
+which will print the name of the GI in mixed case into the output stream.
+It will then print the LaTeX reference instruction with the value of the \fBLINKEND\fP attribute as an argument.
+(This will become the section number after processing by LaTeX.)
+It will then follow IDREFs until if finds an element whose GI is \fBTITLE\fP or which has a child element with that GI.
+It will apply the transpec numbered \fB1\fP to that element, which copies the title into the output stream where the cross reference occurs.
+Finally, it will print the word \fBpage\fP followed by the LaTeX instruction to obtain the page number of a reference.
+.DS
+.nf
+.ft CW
+GI: XREF
+AttValue: OSFROLE getfull
+Replace: ${_followlink 87} \e\eref{${LINKEND}},\es
+ {\e\ebf ${_chasetogi TITLE 1}}, page \e\epageref{${LINKEND}}
+-
+# Print GI name, in mixed case
+GI: _pr_gi_name
+SpecID: 87
+Ignore: 1
+EndText: ${_gi M}
+-
+GI: _pass-text
+SpecID: 1
+-
+.ft R
+.fi
+.DE
+.SH "Related Information"
+.PP
+\fBinstant\fP(1), \fBsgmls\fP(1), \fBegrep\fP(1).
diff --git a/usr.bin/sgmls/instant/tranvar.c b/usr.bin/sgmls/instant/tranvar.c
new file mode 100644
index 0000000..ab04425
--- /dev/null
+++ b/usr.bin/sgmls/instant/tranvar.c
@@ -0,0 +1,763 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * instant - a program to manipulate SGML instances.
+ *
+ * This module is for handling "special variables". These act a lot like
+ * procedure calls
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/tranvar.c,v 1.5 1996/06/11 22:43:15 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <regexp.h>
+#include "general.h"
+#include "translate.h"
+
+static char **idrefs; /* list of IDREF att names to follow */
+static char *def_idrefs[] = { "LINKEND", "LINKENDS", "IDREF", 0 };
+static char *each_A = 0; /* last seen _eachatt */
+static char *each_C = 0; /* last seen _eachcon */
+
+/* forward references */
+void ChaseIDRefs(Element_t *, char *, char *, FILE *);
+void Find(Element_t *, int, char **, FILE *);
+void GetIDREFnames();
+
+/* ______________________________________________________________________ */
+/* Handle "special" variable - read file, run command, do action, etc.
+ * Arguments:
+ * Name of special variable to expand.
+ * Pointer to element under consideration.
+ * FILE pointer to where to write output.
+ * Flag saying whether to track the character position we're on
+ * (passed to OutputString).
+ */
+
+void
+ExpandSpecialVar(
+ char *name,
+ Element_t *e,
+ FILE *fp,
+ int track_pos
+)
+{
+ FILE *infile;
+ char buf[LINESIZE], *cp, *atval;
+ char **tok;
+ int ntok, n, i, actioni;
+ char *action, *action1;
+ Element_t *ep;
+ Trans_t *t, *tt;
+
+ /* Run a command.
+ * Format: _! command args ... */
+ if (*name == '!') {
+ name++;
+ if ((infile = popen(name, "r"))) {
+ while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
+ pclose(infile);
+ fflush(fp);
+ }
+ else {
+ fprintf(stderr, "Could not start program '%s': %s",
+ name, strerror(errno));
+ }
+ return;
+ }
+
+ /* See if caller wants one of the tokens from _eachatt or _eachcon.
+ * If so, output it and return. (Yes, I admit that this is a hack.)
+ */
+ if (*name == 'A' && name[1] == EOS && each_A) {
+ OutputString(each_A, fp, track_pos);
+ return;
+ }
+ if (*name == 'C' && name[1] == EOS && each_C) {
+ OutputString(each_C, fp, track_pos);
+ return;
+ }
+
+ ntok = 0;
+ tok = Split(name, &ntok, 0);
+
+ /* Include another file.
+ * Format: _include filename */
+ if (StrEq(tok[0], "include")) {
+ name = tok[1];
+ if (ntok > 1 ) {
+ if ((infile=OpenFile(name)) == NULL) {
+ sprintf(buf, "Can not open included file '%s'", name);
+ perror(buf);
+ return;
+ }
+ while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
+ fclose(infile);
+ }
+ else fprintf(stderr, "No file name specified for include\n");
+ return;
+ }
+
+ /* Print location (nearest title, line no, path).
+ * Format: _location */
+ else if (StrEq(tok[0], "location")) {
+ PrintLocation(e, fp);
+ }
+
+ /* Print path to this element.
+ * Format: _path */
+ else if (StrEq(tok[0], "path")) {
+ (void)FindElementPath(e, buf);
+ OutputString(buf, fp, track_pos);
+ }
+
+ /* Print name of this element (gi).
+ * Format: _gi [M|L|U] */
+ else if (StrEq(tok[0], "gi")) {
+ strcpy(buf, e->gi);
+ if (ntok >= 2) {
+ if (*tok[1] == 'L' || *tok[1] == 'l' ||
+ *tok[1] == 'M' || *tok[1] == 'm') {
+ for (cp=buf; *cp; cp++)
+ if (isupper(*cp)) *cp = tolower(*cp);
+ }
+ if (*tok[1] == 'M' || *tok[1] == 'm')
+ if (islower(buf[0])) buf[0] = toupper(buf[0]);
+ }
+ OutputString(buf, fp, track_pos);
+ }
+
+ /* Print filename of this element's associated external entity.
+ * Format: _filename */
+ else if (StrEq(tok[0], "filename")) {
+ if (!e->entity) {
+ fprintf(stderr, "Expected ext entity (internal error? bug?):\n");
+ PrintLocation(e, stderr);
+ return;
+ }
+ if (!e->entity->fname) {
+ fprintf(stderr, "Expected filename (internal error? bug?):\n");
+ PrintLocation(e, stderr);
+ return;
+ }
+ OutputString(e->entity->fname, fp, track_pos);
+ }
+
+ /* Value of parent's attribute, by attr name.
+ * Format: _pattr attname */
+ else if (StrEq(tok[0], "pattr")) {
+ ep = e->parent;
+ if (!ep) {
+ fprintf(stderr, "Element does not have a parent:\n");
+ PrintLocation(ep, stderr);
+ return;
+ }
+ if ((atval = FindAttValByName(ep, tok[1]))) {
+ OutputString(atval, fp, track_pos);
+ }
+ }
+
+ /* Use an action, given transpec's SID.
+ * Format: _action action */
+ else if (StrEq(tok[0], "action")) {
+ TranTByAction(e, tok[1], fp);
+ }
+
+ /* Number of child elements of this element.
+ * Format: _nchild */
+ else if (StrEq(tok[0], "nchild")) {
+ if (ntok > 1) {
+ for (n=0,i=0; i<e->necont; i++)
+ if (StrEq(e->econt[i]->gi, tok[1])) n++;
+ }
+ else n = e->necont;
+ sprintf(buf, "%d", n);
+ OutputString(buf, fp, track_pos);
+ }
+
+ /* number of 1st child's child elements (grandchildren from first child).
+ * Format: _n1gchild */
+ else if (StrEq(tok[0], "n1gchild")) {
+ if (e->necont) {
+ sprintf(buf, "%d", e->econt[0]->necont);
+ OutputString(buf, fp, track_pos);
+ }
+ }
+
+ /* Chase this element's pointers until we hit the named GI.
+ * Do the action if it matches.
+ * Format: _chasetogi gi action */
+ else if (StrEq(tok[0], "chasetogi")) {
+ if (ntok < 3) {
+ fprintf(stderr, "Error: Not enough args for _chasetogi.\n");
+ return;
+ }
+ actioni = atoi(tok[2]);
+ if (actioni) ChaseIDRefs(e, tok[1], tok[2], fp);
+ }
+
+ /* Follow link to element pointed to, then do action.
+ * Format: _followlink [attname] action. */
+ else if (StrEq(tok[0], "followlink")) {
+ char **s;
+ if (ntok > 2) {
+ if ((atval = FindAttValByName(e, tok[1]))) {
+ if ((ep = FindElemByID(atval))) {
+ TranTByAction(ep, tok[2], fp);
+ return;
+ }
+ }
+ else fprintf(stderr, "Error: Did not find attr: %s.\n", tok[1]);
+ return;
+ }
+ GetIDREFnames();
+ for (s=idrefs; *s; s++) {
+ /* is this IDREF attr set? */
+ if ((atval = FindAttValByName(e, *s))) {
+ ntok = 0;
+ tok = Split(atval, &ntok, S_STRDUP);
+ /* we'll follow the first one... */
+ if ((ep = FindElemByID(tok[0]))) {
+ TranTByAction(ep, tok[1], fp);
+ return;
+ }
+ else fprintf(stderr, "Error: Can not find elem for ID: %s.\n",
+ tok[0]);
+ }
+ }
+ fprintf(stderr, "Error: Element does not have IDREF attribute set:\n");
+ PrintLocation(e, stderr);
+ return;
+ }
+
+ /* Starting at this element, decend tree (in-order), finding GI.
+ * Do the action if it matches.
+ * Format: _find args ... */
+ else if (StrEq(tok[0], "find")) {
+ Find(e, ntok, tok, fp);
+ }
+
+ /* Starting at this element's parent, decend tree (in-order), finding GI.
+ * Do the action if it matches.
+ * Format: _pfind args ... */
+ else if (StrEq(tok[0], "pfind")) {
+ Find(e->parent ? e->parent : e, ntok, tok, fp);
+ }
+
+ /* Content is supposed to be a list of IDREFs. Follow each, doing action.
+ * If 2 actions are specified, use 1st for the 1st ID, 2nd for the rest.
+ * Format: _namelist action [action2] */
+ else if (StrEq(tok[0], "namelist")) {
+ int id;
+ action1 = tok[1];
+ if (ntok > 2) action = tok[2];
+ else action = action1;
+ for (i=0; i<e->ndcont; i++) {
+ n = 0;
+ tok = Split(e->dcont[i], &n, S_STRDUP);
+ for (id=0; id<n; id++) {
+ if (fold_case)
+ for (cp=tok[id]; *cp; cp++)
+ if (islower(*cp)) *cp = toupper(*cp);
+ if ((e = FindElemByID(tok[id]))) {
+ if (id) TranTByAction(e, action, fp);
+ else TranTByAction(e, action1, fp); /* first one */
+ }
+ else fprintf(stderr, "Error: Can not find ID: %s.\n", tok[id]);
+ }
+ }
+ }
+
+ /* For each word in the element's content, do action.
+ * Format: _eachcon action [action] */
+ else if (StrEq(tok[0], "eachcon")) {
+ int id;
+ action1 = tok[1];
+ if (ntok > 3) action = tok[2];
+ else action = action1;
+ for (i=0; i<e->ndcont; i++) {
+ n = 0;
+ tok = Split(e->dcont[i], &n, S_STRDUP|S_ALVEC);
+ for (id=0; id<n; id++) {
+ each_C = tok[id];
+ TranTByAction(e, action, fp);
+ }
+ free(*tok);
+ }
+ }
+ /* For each word in the given attribute's value, do action.
+ * Format: _eachatt attname action [action] */
+ else if (StrEq(tok[0], "eachatt")) {
+ int id;
+ action1 = tok[2];
+ if (ntok > 3) action = tok[3];
+ else action = action1;
+ if ((atval = FindAttValByName(e, tok[1]))) {
+ n = 0;
+ tok = Split(atval, &n, S_STRDUP|S_ALVEC);
+ for (id=0; id<n; id++) {
+ each_A = tok[id];
+ if (id) TranTByAction(e, action, fp);
+ else TranTByAction(e, action1, fp); /* first one */
+ }
+ free(*tok);
+ }
+ }
+
+ /* Do action on this element if element has [relationship] with gi.
+ * Format: _relation relationship gi action [action] */
+ else if (StrEq(tok[0], "relation")) {
+ if (ntok >= 4) {
+ if (!CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Current)) {
+ /* action not done, see if alt action specified */
+ if (ntok >= 5)
+ TranTByAction(e, tok[4], fp);
+ }
+ }
+ }
+
+ /* Do action on followed element if element has [relationship] with gi.
+ * If [relationship] is not met, do alternate action on this element.
+ * Format: _followrel relationship gi action [action] */
+ else if (StrEq(tok[0], "followrel")) {
+ if (ntok >= 4) {
+ if (!CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Related)) {
+ /* action not done, see if an alt action specified */
+ if (ntok >= 5)
+ TranTByAction(e, tok[4], fp);
+ }
+ }
+ }
+
+ /* Find element with matching ID and do action. If action not specified,
+ * choose the right one appropriate for its context.
+ * Format: _id id [action] */
+ else if (StrEq(tok[0], "id")) {
+ if ((ep = FindElemByID(tok[1]))) {
+ if (ntok > 2) TranTByAction(ep, tok[2], fp);
+ else {
+ t = FindTrans(ep, 0);
+ TransElement(ep, fp, t);
+ }
+ }
+ }
+
+ /* Set variable to value.
+ * Format: _set name value */
+ else if (StrEq(tok[0], "set")) {
+ SetMappingNV(Variables, tok[1], tok[2]);
+ }
+
+ /* Do action if variable is set, optionally to value.
+ * If not set, do nothing.
+ * Format: _isset varname [value] action */
+ else if (StrEq(tok[0], "isset")) {
+ if ((cp = FindMappingVal(Variables, tok[1]))) {
+ if (ntok == 3) TranTByAction(e, tok[2], fp);
+ else if (ntok > 3 && !strcmp(cp, tok[2]))
+ TranTByAction(e, tok[3], fp);
+ }
+ }
+
+ /* Insert a node into the tree at start/end, pointing to action to perform.
+ * Format: _insertnode S|E action */
+ else if (StrEq(tok[0], "insertnode")) {
+ actioni = atoi(tok[2]);
+ if (*tok[1] == 'S') e->gen_trans[0] = actioni;
+ else if (*tok[1] == 'E') e->gen_trans[1] = actioni;
+ }
+
+ /* Do an CALS DTD table spec for TeX or troff. Looks through attributes
+ * and determines what to output. "check" means to check consistency,
+ * and print error messages.
+ * This is (hopefully) the only hard-coded part of instant.
+ *
+ * This was originally written for the OSF DTDs and recoded by FLD for
+ * CALS tables (since no one will ever use the OSF tables). Although
+ * TeX was addressed first, it seems that a fresh approach was required,
+ * and so, tbl is the first to be really *fixed*. Once tbl is stable,
+ * and there is a need for TeX again, that part will be recoded.
+ *
+ * *Obsolete* form (viz, for TeX):
+ * Format: _calstable [clear|check|tex]
+ * [cellstart|cellend|rowstart|rowend|top|bottom]
+ *
+ * New, good form:
+ *
+ * Format: _calstable [tbl]
+ * [tablestart|tableend|tablegroup|tablefoot|rowstart|
+ * rowend|entrystart|entryend]
+ */
+
+ else if (StrEq(tok[0], "calstable")) {
+ CALStable(e, fp, tok, ntok);
+ }
+
+ /* Do action if element's attr is set, optionally to value.
+ * If not set, do nothing.
+ * Format: _attval att [value] action */
+ else if (StrEq(tok[0], "attval")) {
+ if ((atval = FindAttValByName(e, tok[1]))) {
+ if (ntok == 3) TranTByAction(e, tok[2], fp);
+ else if (ntok > 3 && !strcmp(atval, tok[2]))
+ TranTByAction(e, tok[3], fp);
+ }
+ }
+ /* Same thing, but look at parent */
+ else if (StrEq(tok[0], "pattval")) {
+ if ((atval = FindAttValByName(e->parent, tok[1]))) {
+ if (ntok == 3) {
+ TranTByAction(e, tok[2], fp);
+ }
+ if (ntok > 3 && !strcmp(atval, tok[2]))
+ TranTByAction(e, tok[3], fp);
+ }
+ }
+
+ /* Print each attribute and value for the current element, hopefully
+ * in a legal sgml form: <elem-name att1="value1" att2="value2:> .
+ * Format: _allatts */
+ else if (StrEq(tok[0], "allatts")) {
+ for (i=0; i<e->natts; i++) {
+ if (i != 0) putc(' ', fp);
+ fputs(e->atts[i].name, fp);
+ fputs("=\"", fp);
+ fputs(e->atts[i].sval, fp);
+ putc('"', fp);
+ }
+ }
+
+ /* Print the element's input filename, and optionally, the line number.
+ * Format: _infile [line] */
+ else if (StrEq(tok[0], "infile")) {
+ if (e->infile) {
+ if (ntok > 1 && !strcmp(tok[1], "root")) {
+ strcpy(buf, e->infile);
+ if ((cp = strrchr(buf, '.'))) *cp = EOS;
+ fputs(buf, fp);
+ }
+ else {
+ fputs(e->infile, fp);
+ if (ntok > 1 && !strcmp(tok[1], "line"))
+ fprintf(fp, " %d", e->lineno);
+ }
+ return;
+ }
+ else fputs("input-file??", fp);
+ }
+
+ /* Get value of an environement variable */
+ else if (StrEq(tok[0], "env")) {
+ if (ntok > 1 && (cp = getenv(tok[1]))) {
+ OutputString(cp, fp, track_pos);
+ }
+ }
+
+ /* If the element is not empty do specid.
+ * Format: _notempty spec-id */
+ else if (StrEq(tok[0], "notempty")) {
+ if (ntok > 1 && e->ncont) {
+ TranTByAction(e, tok[1], fp);
+ }
+ }
+
+ /* Something unknown */
+ else {
+ fprintf(stderr, "Unknown special variable: %s\n", tok[0]);
+ tt = e->trans;
+ if (tt && tt->lineno)
+ fprintf(stderr, "Used in transpec, line %d\n", tt->lineno);
+ }
+ return;
+}
+
+/* ______________________________________________________________________ */
+/* return the value for the special variables _A (last processed _eachatt)
+ * and _C (last processed _eachcon)
+ */
+
+char *
+Get_A_C_value(const char * name)
+{
+ if ( !strcmp(name, "each_A") ) {
+ if ( each_A ) {
+ return each_A;
+ } else {
+ fprintf(stderr, "Requested value for unset _A variable\n");
+ }
+ } else
+ if ( !strcmp(name, "each_C") ) {
+ if ( each_C ) {
+ return each_C;
+ } else {
+ fprintf(stderr, "Requested value for unset _C variable\n");
+ }
+ } else {
+ fprintf(stderr, "Requested value for unknown special variable '%s'\n",
+ name);
+ }
+ return "";
+}
+
+/* ______________________________________________________________________ */
+/* Chase IDs until we find an element whose GI matches. We also check
+ * child element names, not just the names of elements directly pointed
+ * at (by IDREF attributes).
+ */
+
+void
+GetIDREFnames()
+{
+ char *cp;
+
+ if (!idrefs) {
+ /* did user or transpec set the variable */
+ if ((cp = FindMappingVal(Variables, "link_atts")))
+ idrefs = Split(cp, 0, S_STRDUP|S_ALVEC);
+ else
+ idrefs = def_idrefs;
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Chase ID references - follow IDREF(s) attributes until we find
+ * a GI named 'gi', then perform given action on that GI.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Name of GI we're looking for.
+ * Spec ID of action to take.
+ * FILE pointer to where to write output.
+ */
+void
+ChaseIDRefs(
+ Element_t *e,
+ char *gi,
+ char * action,
+ FILE *fp
+)
+{
+ int ntok, i, ei;
+ char **tok, **s, *atval;
+
+ /* First, see if we got what we came for with this element */
+ if (StrEq(e->gi, gi)) {
+ TranTByAction(e, action, fp);
+ return;
+ }
+ GetIDREFnames();
+
+ /* loop for each attribute of type IDREF(s) */
+ for (s=idrefs; *s; s++) {
+ /* is this IDREF attr set? */
+ if ((atval = FindAttValByName(e, *s))) {
+ ntok = 0;
+ tok = Split(atval, &ntok, 0);
+ for (i=0; i<ntok; i++) {
+ /* get element pointed to */
+ if ((e = FindElemByID(tok[i]))) {
+ /* OK, we found a matching GI name */
+ if (StrEq(e->gi, gi)) {
+ /* process using named action */
+ TranTByAction(e, action, fp);
+ return;
+ }
+ else {
+ /* this elem itself did not match, try its children */
+ for (ei=0; ei<e->necont; ei++) {
+ if (StrEq(e->econt[ei]->gi, gi)) {
+ TranTByAction(e->econt[ei], action, fp);
+ return;
+ }
+ }
+ /* try this elem's IDREF attributes */
+ ChaseIDRefs(e, gi, action, fp);
+ return;
+ }
+ }
+ else {
+ /* should not happen, since parser checks ID/IDREFs */
+ fprintf(stderr, "Error: Could not find ID %s\n", atval);
+ return;
+ }
+ }
+ }
+ }
+ /* if the pointers didn't lead to the GI, give error */
+ if (!s)
+ fprintf(stderr, "Error: Could not find '%s'\n", gi);
+}
+
+/* ______________________________________________________________________ */
+
+/* state to pass to recursive routines - so we don't have to use
+ * global variables. */
+typedef struct {
+ char *gi;
+ char *gi2;
+ char action[10];
+ Element_t *elem;
+ FILE *fp;
+} Descent_t;
+
+static void
+tr_find_gi(
+ Element_t *e,
+ Descent_t *ds
+)
+{
+ if (StrEq(ds->gi, e->gi))
+ if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
+}
+
+static void
+tr_find_gipar(
+ Element_t *e,
+ Descent_t *ds
+)
+{
+ if (StrEq(ds->gi, e->gi) && e->parent &&
+ StrEq(ds->gi2, e->parent->gi))
+ if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
+}
+
+static void
+tr_find_attr(
+ Element_t *e,
+ Descent_t *ds
+)
+{
+ char *atval;
+ if ((atval = FindAttValByName(e, ds->gi)) && StrEq(ds->gi2, atval))
+ TranTByAction(e, ds->action, ds->fp);
+}
+
+static void
+tr_find_parent(
+ Element_t *e,
+ Descent_t *ds
+)
+{
+ if (QRelation(e, ds->gi, REL_Parent)) {
+ if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Descend tree, finding elements that match criteria, then perform
+ * given action.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Number of tokens in special variable.
+ * Vector of tokens in special variable (eg, "find" "gi" "TITLE")
+ * FILE pointer to where to write output.
+ */
+void
+Find(
+ Element_t *e,
+ int ac,
+ char **av,
+ FILE *fp
+)
+{
+ Descent_t DS; /* state passed to recursive routine */
+
+ memset(&DS, 0, sizeof(Descent_t));
+ DS.elem = e;
+ DS.fp = fp;
+
+ /* see if we should start at the top of instance tree */
+ if (StrEq(av[1], "top")) {
+ av++;
+ ac--;
+ e = DocTree;
+ }
+ if (ac < 4) {
+ fprintf(stderr, "Bad '_find' specification - missing args.\n");
+ return;
+ }
+ /* Find elem whose GI is av[2] */
+ if (StrEq(av[1], "gi")) {
+ DS.gi = av[2];
+ strcpy(DS.action, av[3]);
+ DescendTree(e, tr_find_gi, 0, 0, &DS);
+ }
+ /* Find elem whose GI is av[2] and whose parent GI is av[3] */
+ else if (StrEq(av[1], "gi-parent")) {
+ DS.gi = av[2];
+ DS.gi2 = av[3];
+ strcpy(DS.action, av[4]);
+ DescendTree(e, tr_find_gipar, 0, 0, &DS);
+ }
+ /* Find elem whose parent GI is av[2] */
+ else if (StrEq(av[0], "parent")) {
+ DS.gi = av[2];
+ strcpy(DS.action, av[3]);
+ DescendTree(e, tr_find_parent, 0, 0, &DS);
+ }
+ /* Find elem whose attribute av[2] has value av[3] */
+ else if (StrEq(av[0], "attr")) {
+ DS.gi = av[2];
+ DS.gi2 = av[3];
+ strcpy(DS.action, av[4]);
+ DescendTree(e, tr_find_attr, 0, 0, &DS);
+ }
+}
+
+/* ______________________________________________________________________ */
+
diff --git a/usr.bin/sgmls/instant/util.c b/usr.bin/sgmls/instant/util.c
new file mode 100644
index 0000000..eb6015d
--- /dev/null
+++ b/usr.bin/sgmls/instant/util.c
@@ -0,0 +1,1109 @@
+/*
+ * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1994
+ * Open Software Foundation, Inc.
+ *
+ * Permission is hereby granted to use, copy, modify and freely distribute
+ * the software in this file and its documentation for any purpose without
+ * fee, provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation. Further, provided that the name of Open
+ * Software Foundation, Inc. ("OSF") not be used in advertising or
+ * publicity pertaining to distribution of the software without prior
+ * written permission from OSF. OSF makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Copyright (c) 1996 X Consortium
+ * Copyright (c) 1995, 1996 Dalrymple Consulting
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the X Consortium and
+ * Dalrymple Consulting shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without prior
+ * written authorization.
+ */
+/* ________________________________________________________________________
+ *
+ * General utility functions for 'instant' program. These are used
+ * throughout the rest of the program.
+ *
+ * Entry points for this module:
+ * Split(s, &n, flags) split string into n tokens
+ * NewMap(slot_incr) create a new mapping structure
+ * FindMapping(map, name) find mapping by name; return mapping
+ * FindMappingVal(map, name) find mapping by name; return value
+ * SetMapping(map, s) set mapping based on string
+ * OpenFile(filename) open file, looking in inst path
+ * FilePath(filename) find path to a file
+ * FindElementPath(elem, s) find path to element
+ * PrintLocation(ele, fp) print location of element in tree
+ * NearestOlderElem(elem, name) find prev elem up tree with name
+ * OutputString(s, fp, track_pos) output string
+ * AddElemName(name) add elem to list of known elements
+ * AddAttName(name) add att name to list of known atts
+ * FindAttByName(elem, name) find an elem's att by name
+ * FindContext(elem, lev, context) find context of elem
+ * QRelation(elem, name, rel_flag) find relation elem has to named elem
+ * DescendTree(elem, enter_f, leave_f, data_f, dp) descend doc tree,
+ * calling functions for each elem/node
+ * ________________________________________________________________________
+ */
+
+#ifndef lint
+static char *RCSid =
+ "$Header: /usr/src/docbook-to-man/Instant/RCS/util.c,v 1.4 1996/06/02 21:47:32 fld Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <regexp.h>
+/* CSS don't have it and I don't see where it's used
+#include <values.h>
+*/
+
+#include "general.h"
+#include "translate.h"
+
+/* ______________________________________________________________________ */
+/* "Split" a string into tokens. Given a string that has space-separated
+ * (space/tab) tokens, return a pointer to an array of pointers to the
+ * tokens. Like what the shell does with *argv[]. The array can be is
+ * static or allocated. Space can be allocated for string, or allocated.
+ * Arguments:
+ * Pointer to string to pick apart.
+ * Pointer to max number of tokens to find; actual number found is
+ * returned. If 0 or null pointer, use a 'sane' maximum number (hard-
+ * code). If more tokens than the number specified, make last token be
+ * a single string composed of the rest of the tokens (includes spaces).
+ * Flag. Bit 0 says whether to make a copy of input string (since we'll
+ * clobber parts of it). To free the string, use the pointer to
+ * the first token returned by the function (or *ret_value).
+ * Bit 1 says whether to allocate the vector itself. If not, use
+ * (and return) a static vector.
+ * Return:
+ * Pointer to the provided string (for convenience of caller).
+ */
+
+char **
+Split(
+ char *s, /* input string */
+ int *ntok, /* # of tokens desired (input)/found (return) */
+ int flag /* dup string? allocate a vector? */
+)
+{
+ int maxnt, i=0;
+ int n_alloc;
+ char **tokens;
+ static char *local_tokens[100];
+
+ /* Figure max number of tokens (maxnt) to find. 0 means find them all. */
+ if (ntok == NULL)
+ maxnt = 100;
+ else {
+ if (*ntok <= 0 || *ntok > 100) maxnt = 100; /* arbitrary size */
+ else maxnt = *ntok;
+ *ntok = 0;
+ }
+
+ if (!s) return 0; /* no string */
+
+ /* Point to 1st token (there may be initial space) */
+ while (*s && IsWhite(*s)) s++; /* skip initial space, if any */
+ if (*s == EOS) return 0; /* none found? */
+
+ /* See if caller wants us to copy the input string. */
+ if (flag & S_STRDUP) s = strdup(s);
+
+ /* See if caller wants us to allocate the returned vector. */
+ if (flag & S_ALVEC) {
+ n_alloc = 20;
+ Malloc(n_alloc, tokens, char *);
+ /* if caller did not specify max tokens to find, set to more than
+ * there will possibly ever be */
+ if (!ntok || !(*ntok)) maxnt = 10000;
+ }
+ else tokens = local_tokens;
+
+ i = 0; /* index into vector */
+ tokens[0] = s; /* s already points to 1st token */
+ while (i<maxnt) {
+ tokens[i] = s; /* point vector member at start of token */
+ i++;
+ /* If we allocated vector, see if we need more space. */
+ if ((flag & S_ALVEC) && i >= n_alloc) {
+ n_alloc += 20;
+ Realloc(n_alloc, tokens, char *);
+ }
+ if (i >= maxnt) break; /* is this the last one? */
+ while (*s && !IsWhite(*s)) s++; /* skip past end of token */
+ if (*s == EOS) break; /* at end of input string? */
+ if (*s) *s++ = EOS; /* terminate token string */
+ while (*s && IsWhite(*s)) s++; /* skip space - to next token */
+ }
+ if (ntok) *ntok = i; /* return number of tokens found */
+ tokens[i] = 0; /* null-terminate vector */
+ return tokens;
+}
+
+/* ______________________________________________________________________ */
+/* Mapping routines. These are used for name-value pairs, like attributes,
+ * variables, and counters. A "Map" is an opaque data structure used
+ * internally by these routines. The caller gets one when creating a new
+ * map, then hands it to other routines that need it. A "Mapping" is a
+ * name/value pair. The user has access to this.
+ * Here's some sample usage:
+ *
+ * Map *V;
+ * V = NewMap(20);
+ * SetMappingNV(V, "home", "/users/bowe");
+ * printf("Home: %s\n", FindMappingVal(V, "home");
+ */
+
+/* Allocate new map structure. Only done once for each map/variable list.
+ * Arg:
+ * Number of initial slots to allocate space for. This is also the
+ * "chunk size" - how much to allocate when we use up the given space.
+ * Return:
+ * Pointer to the (opaque) map structure. (User passes this to other
+ * mapping routines.)
+ */
+Map_t *
+NewMap(
+ int slot_increment
+)
+{
+ Map_t *M;
+ Calloc(1, M, Map_t);
+ /* should really do the memset's in Calloc/Malloc/Realloc
+ macros, but that will have to wait until time permits -CSS */
+ memset((char *)M, 0, sizeof(Map_t));
+ if (!slot_increment) slot_increment = 1;
+ M->slot_incr = slot_increment;
+ return M;
+}
+
+/* Given pointer to a Map and a name, find the mapping.
+ * Arguments:
+ * Pointer to map structure (as returned by NewMap().
+ * Variable name.
+ * Return:
+ * Pointer to the matching mapping structure, or null if not found.
+ */
+Mapping_t *
+FindMapping(
+ Map_t *M,
+ const char *name
+)
+{
+ int i;
+ Mapping_t *m;
+
+ if (!M || M->n_used == 0) return NULL;
+ for (m=M->maps,i=0; i<M->n_used; i++)
+ if (m[i].name[0] == name[0] && !strcmp(m[i].name, name)) return &m[i];
+ return NULL;
+
+}
+
+/* Given pointer to a Map and a name, return string value of the mapping.
+ * Arguments:
+ * Pointer to map structure (as returned by NewMap().
+ * Variable name.
+ * Return:
+ * Pointer to the value (string), or null if not found.
+ */
+char *
+FindMappingVal(
+ Map_t *M,
+ const char *name
+)
+{
+ Mapping_t *m;
+
+ if ( !strcmp(name, "each_A") || !strcmp(name, "each_C") ) {
+ return Get_A_C_value(name);
+ }
+
+ /*
+ if (!M || M->n_used == 0) return NULL;
+ if ((m = FindMapping(M, name))) return m->sval;
+ return NULL;
+ */
+ if (!M || M->n_used == 0) {
+ return NULL;
+ }
+ if ((m = FindMapping(M, name))) {
+ return m->sval;
+ }
+ return NULL;
+
+}
+
+/* Set a mapping/variable in Map M. Input string is a name-value pair where
+ * there is some amount of space after the name. The correct mapping is done.
+ * Arguments:
+ * Pointer to map structure (as returned by NewMap().
+ * Pointer to variable name (string).
+ * Pointer to variable value (string).
+ */
+void
+SetMappingNV(
+ Map_t *M,
+ const char *name,
+ const char *value
+)
+{
+ FILE *pp;
+ char buf[LINESIZE], *cp;
+ int i;
+ Mapping_t *m;
+
+ /* First, look to see if it's a "well-known" variable. */
+ if (!strcmp(name, "verbose")) { verbose = atoi(value); return; }
+ if (!strcmp(name, "warnings")) { warnings = atoi(value); return; }
+ if (!strcmp(name, "foldcase")) { fold_case = atoi(value); return; }
+
+ m = FindMapping(M, name); /* find existing mapping (if set) */
+
+ /* OK, we have a string mapping */
+ if (m) { /* exists - just replace value */
+ free(m->sval);
+ if (value) m->sval = strdup(value);
+ else m->sval = NULL;
+ }
+ else {
+ if (name) { /* just in case */
+ /* Need more slots for mapping structures? Allocate in clumps. */
+ if (M->n_used == 0) {
+ M->n_alloc = M->slot_incr;
+ Malloc(M->n_alloc, M->maps, Mapping_t);
+ }
+ else if (M->n_used >= M->n_alloc) {
+ M->n_alloc += M->slot_incr;
+ Realloc(M->n_alloc, M->maps, Mapping_t);
+ }
+
+ m = &M->maps[M->n_used];
+ M->n_used++;
+ m->name = strdup(name);
+ if (value) m->sval = strdup(value);
+ else m->sval = NULL;
+ }
+ }
+
+ if (value)
+ {
+ /* See if the value is a command to run. If so, run the command
+ * and replace the value with the output.
+ */
+ if (*value == '!') {
+ if ((pp = popen(value+1, "r"))) { /* run cmd, read its output */
+ i = 0;
+ cp = buf;
+ while (fgets(cp, LINESIZE-i, pp)) {
+ i += strlen(cp);
+ cp = &buf[i];
+ if (i >= LINESIZE) {
+ fprintf(stderr,
+ "Prog execution of variable '%s' too long.\n",
+ m->name);
+ break;
+ }
+ }
+ free(m->sval);
+ stripNL(buf);
+ m->sval = strdup(buf);
+ pclose(pp);
+ }
+ else {
+ sprintf(buf, "Could not start program '%s'", value+1);
+ perror(buf);
+ }
+ }
+ }
+}
+
+/* Separate name and value from input string, then pass to SetMappingNV.
+ * Arguments:
+ * Pointer to map structure (as returned by NewMap().
+ * Pointer to variable name and value (string), in form "name value".
+ */
+void
+SetMapping(
+ Map_t *M,
+ const char *s
+)
+{
+ char buf[LINESIZE];
+ char *name, *val;
+
+ if (!M) {
+ fprintf(stderr, "SetMapping: Map not initialized.\n");
+ return;
+ }
+ strcpy(buf, s);
+ name = val = buf;
+ while (*val && !IsWhite(*val)) val++; /* point past end of name */
+ if (*val) {
+ *val++ = EOS; /* terminate name */
+ while (*val && IsWhite(*val)) val++; /* point to value */
+ }
+ if (name) SetMappingNV(M, name, val);
+}
+
+/* ______________________________________________________________________ */
+/* Opens a file for reading. If not found in current directory, try
+ * lib directories (from TPT_LIB env variable, or -l option).
+ * Arguments:
+ * Filename (string).
+ * Return:
+ * FILE pointer to open file, or null if it not found or can't open.
+ */
+
+FILE *
+OpenFile(
+ char *filename
+)
+{
+ FILE *fp;
+
+ filename = FilePath(filename);
+ if ((fp=fopen(filename, "r"))) return fp;
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Opens a file for reading. If not found in current directory, try
+ * lib directories (from TPT_LIB env variable, or -l option).
+ * Arguments:
+ * Filename (string).
+ * Return:
+ * FILE pointer to open file, or null if it not found or can't open.
+ */
+
+char *
+FilePath(
+ char *filename
+)
+{
+ FILE *fp;
+ static char buf[LINESIZE];
+ int i;
+ static char **libdirs;
+ static int nlibdirs = -1;
+
+ if ((fp=fopen(filename, "r")))
+ {
+ fclose(fp);
+ strncpy(buf, filename, LINESIZE);
+ return buf;
+ }
+
+ if (*filename == '/') return NULL; /* full path specified? */
+
+ if (nlibdirs < 0) {
+ char *cp, *s;
+ if (tpt_lib) {
+ s = strdup(tpt_lib);
+ for (cp=s; *cp; cp++) if (*cp == ':') *cp = ' ';
+ nlibdirs = 0;
+ libdirs = Split(s, &nlibdirs, S_ALVEC);
+ }
+ else nlibdirs = 0;
+ }
+ for (i=0; i<nlibdirs; i++) {
+ sprintf(buf, "%s/%s", libdirs[i], filename);
+ if ((fp=fopen(buf, "r")))
+ {
+ fclose(fp);
+ return buf;
+ }
+ }
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* This will find the path to an tag. The format is the:
+ * tag1(n1):tag2(n2):tag3
+ * where the tags are going down the tree and the numbers indicate which
+ * child (the first is numbered 1) the next tag is.
+ * Returns pointer to the string just written to (so you can use this
+ * function as a printf arg).
+ * Arguments:
+ * Pointer to element under consideration.
+ * String to write path into (provided by caller).
+ * Return:
+ * Pointer to the provided string (for convenience of caller).
+ */
+char *
+FindElementPath(
+ Element_t *e,
+ char *s
+)
+{
+ Element_t *ep;
+ int i, e_path[MAX_DEPTH];
+ char *cp;
+
+ /* Move up the tree, noting "birth order" of each element encountered */
+ for (ep=e; ep; ep=ep->parent)
+ e_path[ep->depth-1] = ep->my_eorder;
+ /* Move down the tree, printing the element names to the string. */
+ for (cp=s,i=0,ep=DocTree; i<e->depth; ep=ep->econt[e_path[i]],i++) {
+ sprintf(cp, "%s(%d) ", ep->gi, e_path[i]);
+ cp += strlen(cp);
+ }
+ sprintf(cp, "%s", e->gi);
+ return s;
+}
+
+/* ______________________________________________________________________ */
+/* Print some location info about a tag. Helps user locate error.
+ * Messages are indented 2 spaces (convention for multi-line messages).
+ * Arguments:
+ * Pointer to element under consideration.
+ * FILE pointer of where to print.
+ */
+
+void
+PrintLocation(
+ Element_t *e,
+ FILE *fp
+)
+{
+ char *s, buf[LINESIZE];
+
+ if (!e || !fp) return;
+ fprintf(fp, " Path: %s\n", FindElementPath(e, buf));
+ if ((s=NearestOlderElem(e, "TITLE")))
+ fprintf(fp, " Position hint: TITLE='%s'\n", s);
+ if (e->lineno) {
+ if (e->infile)
+ fprintf(fp, " At or near instance file: %s, line: %d\n",
+ e->infile, e->lineno);
+ else
+ fprintf(fp, " At or near instance line: %d\n", e->lineno);
+ }
+ if (e->id)
+ fprintf(fp, " ID: %s\n", e->id);
+}
+
+/* ______________________________________________________________________ */
+/* Finds the data part of the nearest "older" tag (up the tree, and
+ * preceding) whose tag name matches the argument, or "TITLE", if null.
+ * Returns a pointer to the first chunk of character data.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Name (GI) of element we'll return data from.
+ * Return:
+ * Pointer to that element's data content.
+ */
+char *
+NearestOlderElem(
+ Element_t *e,
+ char *name
+)
+{
+ int i;
+ Element_t *ep;
+
+ if (!e) return 0;
+ if (!name) name = "TITLE"; /* useful default */
+
+ for (; e->parent; e=e->parent) /* move up tree */
+ for (i=0; i<=e->my_eorder; i++) { /* check preceding sibs */
+ ep = e->parent;
+ if (!strcmp(name, ep->econt[i]->gi))
+ return ep->econt[i]->ndcont ?
+ ep->econt[i]->dcont[0] : "-empty-";
+ }
+
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Expands escaped strings in the input buffer (things like tabs, newlines,
+ * octal characters - using C style escapes).
+ */
+
+char *ExpandString(
+ char *s
+)
+{
+ char c, *sdata, *cp, *ns;
+ int len, pos, addn;
+
+ if (!s) return s;
+
+ len = strlen(s);
+ pos = 0;
+ Malloc(len + 1, ns, char);
+ ns[pos] = EOS;
+
+ for ( ; *s; s++) {
+ c = *s;
+ cp = NULL;
+
+ /* Check for escaped characters from sgmls. */
+ if (*s == '\\') {
+ s++;
+ switch (*s) {
+ case 'n':
+ c = NL;
+ break;
+
+ case '\\':
+ c = '\\';
+ break;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ /* for octal numbers (C style) of the form \012 */
+ c = *s++ - '0';
+ if (*s >= '0' && *s <= '7') {
+ c = c * 8 + (*s++ - '0');
+ if (*s >= '0' && *s <= '7')
+ c = c * 8 + (*s - '0');
+ }
+ break;
+
+ case '|': /* SDATA */
+ s++; /* point past \| */
+ sdata = s;
+ /* find matching/closing \| */
+ cp = s;
+ while (*cp && *cp != '\\' && cp[1] != '|')
+ cp++;
+ if (!*cp)
+ break;
+
+ *cp = EOS; /* terminate sdata string */
+ cp++;
+ s = cp; /* s now points to | */
+
+ cp = LookupSDATA(sdata);
+ if (!cp)
+ cp = sdata;
+ c = 0;
+ break;
+
+ /* This shouldn't happen. */
+ default:
+ s--;
+ break;
+ }
+ }
+
+ /* Check for character re-mappings. */
+ if (nCharMap && c) {
+ int i;
+
+ for (i = 0; i < nCharMap; i++) {
+ if (c != CharMap[i].name[0])
+ continue;
+ cp = CharMap[i].sval;
+ c = 0;
+ break;
+ }
+ }
+
+ /* See if there is enough space for the data. */
+ /* XXX this should be MUCH smarter about predicting
+ how much extra memory it should allocate */
+ if (c)
+ addn = 1;
+ else
+ addn = strlen(cp);
+
+ /* If not, make some. */
+ if (addn > len - pos) {
+ len += addn - (len - pos);
+ Realloc(len + 1, ns, char);
+ }
+
+ /* Then copy the data. */
+ if (c)
+ ns[pos] = c;
+ else
+ strcpy(&ns[pos], cp);
+
+ pos += addn;
+ ns[pos] = EOS;
+ }
+ return(ns);
+}
+
+/* ______________________________________________________________________ */
+/* Expands escaped strings in the input buffer (things like tabs, newlines,
+ * octal characters - using C style escapes) and outputs buffer to specified
+ * fp. The hat/anchor character forces that position to appear at the
+ * beginning of a line. The cursor position is kept track of (optionally)
+ * so that this can be done.
+ * Arguments:
+ * Pointer to element under consideration.
+ * FILE pointer of where to print.
+ * Flag saying whether or not to keep track of our position in the output
+ * stream. (We want to when writing to a file, but not for stderr.)
+ */
+
+void
+OutputString(
+ char *s,
+ FILE *fp,
+ int track_pos
+)
+{
+ char c;
+ static int char_pos = 0; /* remembers our character position */
+ char *p;
+
+ if (!fp) return;
+ if (!s) s = "^"; /* no string - go to start of line */
+
+ for (p = s; *p; p++) {
+ c = *p;
+ /* If caller wants us to track position, see if it's an anchor
+ * (ie, align at a newline). */
+ if (track_pos) {
+ if (c == ANCHOR && (p == s || *(p + 1) == EOS)) {
+ /* If we're already at the start of a line, don't do
+ * another newline. */
+ if (char_pos != 0) c = NL;
+ else c = 0;
+ }
+ else char_pos++;
+ if (c == NL) char_pos = 0;
+ }
+ else if (c == ANCHOR && (p == s || *(p + 1) == EOS)) c = NL;
+ if (c) putc(c, fp);
+ }
+}
+
+/* ______________________________________________________________________ */
+/* Figure out value of SDATA entity.
+ * We rememeber lookup hits in a "cache" (a shorter list), and look in
+ * cache before general list. Typically there will be LOTS of entries
+ * in the general list and only a handful in the hit list. Often, if an
+ * entity is used once, it'll be used again.
+ * Arguments:
+ * Pointer to SDATA entity token in ESIS.
+ * Return:
+ * Mapped value of the SDATA entity.
+ */
+
+char *
+LookupSDATA(
+ char *s
+)
+{
+ char *v;
+ static Map_t *Hits; /* remember lookup hits */
+
+ /* If we have a hit list, check it. */
+ if (Hits) {
+ if ((v = FindMappingVal(Hits, s))) return v;
+ }
+
+ v = FindMappingVal(SDATAmap, s);
+
+ /* If mapping found, remember it, then return it. */
+ if ((v = FindMappingVal(SDATAmap, s))) {
+ if (!Hits) Hits = NewMap(IMS_sdatacache);
+ SetMappingNV(Hits, s, v);
+ return v;
+ }
+
+ fprintf(stderr, "Error: Could not find SDATA substitution '%s'.\n", s);
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Add tag 'name' of length 'len' to list of tag names (if not there).
+ * This is a list of null-terminated strings so that we don't have to
+ * keep using the name length.
+ * Arguments:
+ * Pointer to element name (GI) to remember.
+ * Return:
+ * Pointer to the SAVED element name (GI).
+ */
+
+char *
+AddElemName(
+ char *name
+)
+{
+ int i;
+ static int n_alloc=0; /* number of slots allocated so far */
+
+ /* See if it's already in the list. */
+ for (i=0; i<nUsedElem; i++)
+ if (UsedElem[i][0] == name[0] && !strcmp(UsedElem[i], name))
+ return UsedElem[i];
+
+ /* Allocate slots in blocks of N, so we don't have to call malloc
+ * so many times. */
+ if (n_alloc == 0) {
+ n_alloc = IMS_elemnames;
+ Calloc(n_alloc, UsedElem, char *);
+ }
+ else if (nUsedElem >= n_alloc) {
+ n_alloc += IMS_elemnames;
+ Realloc(n_alloc, UsedElem, char *);
+ }
+ UsedElem[nUsedElem] = strdup(name);
+ return UsedElem[nUsedElem++];
+}
+/* ______________________________________________________________________ */
+/* Add attrib name to list of attrib names (if not there).
+ * This is a list of null-terminated strings so that we don't have to
+ * keep using the name length.
+ * Arguments:
+ * Pointer to attr name to remember.
+ * Return:
+ * Pointer to the SAVED attr name.
+ */
+
+char *
+AddAttName(
+ char *name
+)
+{
+ int i;
+ static int n_alloc=0; /* number of slots allocated so far */
+
+ /* See if it's already in the list. */
+ for (i=0; i<nUsedAtt; i++)
+ if (UsedAtt[i][0] == name[0] && !strcmp(UsedAtt[i], name))
+ return UsedAtt[i];
+
+ /* Allocate slots in blocks of N, so we don't have to call malloc
+ * so many times. */
+ if (n_alloc == 0) {
+ n_alloc = IMS_attnames;
+ Calloc(n_alloc, UsedAtt, char *);
+ }
+ else if (nUsedAtt >= n_alloc) {
+ n_alloc += IMS_attnames;
+ Realloc(n_alloc, UsedAtt, char *);
+ }
+ UsedAtt[nUsedAtt] = strdup(name);
+ return UsedAtt[nUsedAtt++];
+}
+
+/* ______________________________________________________________________ */
+/* Find an element's attribute value given element pointer and attr name.
+ * Typical use:
+ * a=FindAttByName("TYPE", t);
+ * do something with a->val;
+ * Arguments:
+ * Pointer to element under consideration.
+ * Pointer to attribute name.
+ * Return:
+ * Pointer to the value of the attribute.
+ */
+
+/*
+Mapping_t *
+FindAttByName(
+ Element_t *e,
+ char *name
+)
+{
+ int i;
+ if (!e) return NULL;
+ for (i=0; i<e->natts; i++)
+ if (e->atts[i].name[0] == name[0] && !strcmp(e->atts[i].name, name))
+ return &(e->atts[i]);
+ return NULL;
+}
+*/
+
+char *
+FindAttValByName(
+ Element_t *e,
+ char *name
+)
+{
+ int i;
+ if (!e) return NULL;
+ for (i=0; i<e->natts; i++)
+ if (e->atts[i].name[0] == name[0] && !strcmp(e->atts[i].name, name))
+ return e->atts[i].sval;
+ return NULL;
+}
+
+/* ______________________________________________________________________ */
+/* Find context of a tag, 'levels' levels up the tree.
+ * Space for string is passed by caller.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Number of levels to look up tree.
+ * String to write path into (provided by caller).
+ * Return:
+ * Pointer to the provided string (for convenience of caller).
+ */
+
+char *
+FindContext(
+ Element_t *e,
+ int levels,
+ char *con
+)
+{
+ char *s;
+ Element_t *ep;
+ int i;
+
+ if (!e) return NULL;
+ s = con;
+ *s = EOS;
+ for (i=0,ep=e->parent; ep && levels; ep=ep->parent,i++,levels--) {
+ if (i != 0) *s++ = ' ';
+ strcpy(s, ep->gi);
+ s += strlen(s);
+ }
+ return con;
+}
+
+
+/* ______________________________________________________________________ */
+/* Tests relationship (specified by argument/flag) between given element
+ * (structure pointer) and named element.
+ * Returns pointer to matching tag if found, null otherwise.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Pointer to name of elem whose relationsip we are trying to determine.
+ * Relationship we are testing.
+ * Return:
+ * Pointer to the provided string (for convenience of caller).
+ */
+
+Element_t *
+QRelation(
+ Element_t *e,
+ char *s,
+ Relation_t rel
+)
+{
+ int i;
+ Element_t *ep;
+
+ if (!e) return 0;
+
+ /* we'll call e the "given element" */
+ switch (rel)
+ {
+ case REL_Parent:
+ if (!e->parent || !e->parent->gi) return 0;
+ if (!strcmp(e->parent->gi, s)) return e->parent;
+ break;
+ case REL_Child:
+ for (i=0; i<e->necont; i++)
+ if (!strcmp(s, e->econt[i]->gi)) return e->econt[i];
+ break;
+ case REL_Ancestor:
+ if (!e->parent || !e->parent->gi) return 0;
+ for (ep=e->parent; ep; ep=ep->parent)
+ if (!strcmp(ep->gi, s)) return ep;
+ break;
+ case REL_Descendant:
+ if (e->necont == 0) return 0;
+ /* check immediate children first */
+ for (i=0; i<e->necont; i++)
+ if (!strcmp(s, e->econt[i]->gi)) return e->econt[i];
+ /* then children's children (recursively) */
+ for (i=0; i<e->necont; i++)
+ if ((ep=QRelation(e->econt[i], s, REL_Descendant)))
+ return ep;
+ break;
+ case REL_Sibling:
+ if (!e->parent) return 0;
+ ep = e->parent;
+ for (i=0; i<ep->necont; i++)
+ if (!strcmp(s, ep->econt[i]->gi) && i != e->my_eorder)
+ return ep->econt[i];
+ break;
+ case REL_Preceding:
+ if (!e->parent || e->my_eorder == 0) return 0;
+ ep = e->parent;
+ for (i=0; i<e->my_eorder; i++)
+ if (!strcmp(s, ep->econt[i]->gi)) return ep->econt[i];
+ break;
+ case REL_ImmPreceding:
+ if (!e->parent || e->my_eorder == 0) return 0;
+ ep = e->parent->econt[e->my_eorder-1];
+ if (!strcmp(s, ep->gi)) return ep;
+ break;
+ case REL_Following:
+ if (!e->parent || e->my_eorder == (e->parent->necont-1))
+ return 0; /* last? */
+ ep = e->parent;
+ for (i=(e->my_eorder+1); i<ep->necont; i++)
+ if (!strcmp(s, ep->econt[i]->gi)) return ep->econt[i];
+ break;
+ case REL_ImmFollowing:
+ if (!e->parent || e->my_eorder == (e->parent->necont-1))
+ return 0; /* last? */
+ ep = e->parent->econt[e->my_eorder+1];
+ if (!strcmp(s, ep->gi)) return ep;
+ break;
+ case REL_Cousin:
+ if (!e->parent) return 0;
+ /* Now, see if element's parent has that thing as a child. */
+ return QRelation(e->parent, s, REL_Child);
+ break;
+ case REL_None:
+ case REL_Unknown:
+ fprintf(stderr, "You can not query 'REL_None' or 'REL_Unknown'.\n");
+ break;
+ }
+ return NULL;
+}
+
+/* Given a relationship name (string), determine enum symbol for it.
+ * Arguments:
+ * Pointer to relationship name.
+ * Return:
+ * Relation_t enum.
+ */
+Relation_t
+FindRelByName(
+ char *relname
+)
+{
+ if (!strcmp(relname, "?")) {
+ fprintf(stderr, "Supported query/relationships %s\n%s.\n",
+ "child, parent, ancestor, descendant,",
+ "sibling, sibling+, sibling+1, sibling-, sibling-1");
+ return REL_None;
+ }
+ else if (StrEq(relname, "child")) return REL_Child;
+ else if (StrEq(relname, "parent")) return REL_Parent;
+ else if (StrEq(relname, "ancestor")) return REL_Ancestor;
+ else if (StrEq(relname, "descendant")) return REL_Descendant;
+ else if (StrEq(relname, "sibling")) return REL_Sibling;
+ else if (StrEq(relname, "sibling-")) return REL_Preceding;
+ else if (StrEq(relname, "sibling-1")) return REL_ImmPreceding;
+ else if (StrEq(relname, "sibling+")) return REL_Following;
+ else if (StrEq(relname, "sibling+1")) return REL_ImmFollowing;
+ else if (StrEq(relname, "cousin")) return REL_Cousin;
+ else fprintf(stderr, "Unknown relationship: %s\n", relname);
+ return REL_Unknown;
+}
+
+/* ______________________________________________________________________ */
+/* This will descend the element tree in-order. (enter_f)() is called
+ * upon entering the node. Then all children (data and child elements)
+ * are operated on, calling either DescendTree() with a pointer to
+ * the child element or (data_f)() for each non-element child node.
+ * Before leaving the node (ascending), (leave_f)() is called. enter_f
+ * and leave_f are passed a pointer to this node and data_f is passed
+ * a pointer to the data/content (which includes the data itself and
+ * type information). dp is an opaque pointer to any data the caller
+ * wants to pass.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Pointer to procedure to call when entering element.
+ * Pointer to procedure to call when leaving element.
+ * Pointer to procedure to call for each "chunk" of content data.
+ * Void data pointer, passed to the avobe 3 procedures.
+ */
+
+void
+DescendTree(
+ Element_t *e,
+ void (*enter_f)(),
+ void (*leave_f)(),
+ void (*data_f)(),
+ void *dp
+)
+{
+ int i;
+ if (enter_f) (enter_f)(e, dp);
+ for (i=0; i<e->ncont; i++) {
+ if (e->cont[i].type == CMD_OPEN)
+ DescendTree(e->cont[i].ch.elem, enter_f, leave_f, data_f, dp);
+ else
+ if (data_f) (data_f)(&e->cont[i], dp);
+ }
+ if (leave_f) (leave_f)(e, dp);
+}
+
+/* ______________________________________________________________________ */
+/* Add element, 'e', whose ID is 'idval', to a list of IDs.
+ * This makes it easier to find an element by ID later.
+ * Arguments:
+ * Pointer to element under consideration.
+ * Element's ID attribute value (a string).
+ */
+
+void
+AddID(
+ Element_t *e,
+ char *idval
+)
+{
+ static ID_t *id_last;
+
+ if (!IDList) {
+ Malloc(1, id_last, ID_t);
+ IDList = id_last;
+ }
+ else {
+ Malloc(1, id_last->next, ID_t);
+ id_last = id_last->next;
+ }
+ id_last->elem = e;
+ id_last->id = idval;
+}
+
+/* ______________________________________________________________________ */
+/* Return pointer to element who's ID is given.
+ * Arguments:
+ * Element's ID attribute value (a string).
+ * Return:
+ * Pointer to element whose ID matches.
+ */
+
+Element_t *
+FindElemByID(
+ char *idval
+)
+{
+ ID_t *id;
+ for (id=IDList; id; id=id->next)
+ if (id->id[0] == idval[0] && !strcmp(id->id, idval)) return id->elem;
+ return 0;
+}
+
+/* ______________________________________________________________________ */
+
diff --git a/usr.bin/sgmls/libsgmls/Makefile b/usr.bin/sgmls/libsgmls/Makefile
new file mode 100644
index 0000000..0d058f3
--- /dev/null
+++ b/usr.bin/sgmls/libsgmls/Makefile
@@ -0,0 +1,17 @@
+#
+# Bmakefile for libsgmls
+#
+# $Id$
+#
+
+LIB= sgmls
+SRCS= sgmls.c
+
+CFLAGS+= -I${.CURDIR}/../sgmls
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/usr.bin/sgmls/libsgmls/sgmls.c b/usr.bin/sgmls/libsgmls/sgmls.c
new file mode 100644
index 0000000..4e25957
--- /dev/null
+++ b/usr.bin/sgmls/libsgmls/sgmls.c
@@ -0,0 +1,1032 @@
+/* sgmls.c:
+ Library for reading output of sgmls.
+
+ Written by James Clark (jjc@jclark.com). */
+
+#include "config.h"
+#include "std.h"
+#include "sgmls.h"
+#include "lineout.h"
+
+#ifdef USE_PROTOTYPES
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+typedef struct sgmls_data data_s;
+typedef struct sgmls_notation notation_s;
+typedef struct sgmls_internal_entity internal_entity_s;
+typedef struct sgmls_external_entity external_entity_s;
+typedef struct sgmls_entity entity_s;
+typedef struct sgmls_attribute attribute_s;
+typedef struct sgmls_event event_s;
+
+/* lists are sorted in reverse order of level */
+struct list {
+ int subdoc_level; /* -1 if associated with finished subdoc */
+ struct list *next;
+ char *name;
+};
+
+struct entity_list {
+ int subdoc_level;
+ struct entity_list *next;
+ entity_s entity;
+};
+
+struct notation_list {
+ int subdoc_level;
+ struct notation_list *next;
+ notation_s notation;
+};
+
+struct sgmls {
+ FILE *fp;
+ char *buf;
+ unsigned buf_size;
+ struct entity_list *entities;
+ struct notation_list *notations;
+ attribute_s *attributes;
+ unsigned long lineno;
+ char *filename;
+ unsigned filename_size;
+ unsigned long input_lineno;
+ int subdoc_level;
+ char **files; /* from `f' commands */
+ int nfiles;
+ char *sysid; /* from `s' command */
+ char *pubid; /* from `p' command */
+};
+
+enum error_code {
+ E_ZERO, /* Not an error */
+ E_NOMEM, /* Out of memory */
+ E_BADESCAPE, /* Bad escape */
+ E_NULESCAPE, /* \000 other than in data */
+ E_NUL, /* A null input character */
+ E_BADENTITY, /* Reference to undefined entity */
+ E_INTERNALENTITY, /* Internal entity when external was needed */
+ E_SYSTEM, /* System input error */
+ E_COMMAND, /* Bad command letter */
+ E_MISSING, /* Missing arguments */
+ E_NUMBER, /* Not a number */
+ E_ATTR, /* Bad attribute type */
+ E_BADNOTATION, /* Reference to undefined notation */
+ E_BADINTERNAL, /* Bad internal entity type */
+ E_BADEXTERNAL, /* Bad external entity type */
+ E_EOF, /* EOF in middle of line */
+ E_SDATA, /* \| other than in data */
+ E_LINELENGTH /* line longer than UNSIGNED_MAX */
+};
+
+static char *errlist[] = {
+ 0,
+ "Out of memory",
+ "Bad escape",
+ "\\0 escape not in data",
+ "Nul character in input",
+ "Reference to undefined entity",
+ "Internal entity when external was needed",
+ "System input error",
+ "Bad command letter",
+ "Missing arguments",
+ "Not a number",
+ "Bad attribute type",
+ "Reference to undefined notation",
+ "Bad internal entity type",
+ "Bad external entity type",
+ "EOF in middle of line",
+ "\\| other than in data",
+ "Too many V commands",
+ "Input line too long"
+};
+
+static void error P((enum error_code));
+static int parse_data P((char *, unsigned long *));
+static void parse_location P((char *, struct sgmls *));
+static void parse_notation P((char *, notation_s *));
+static void parse_internal_entity P((char *, internal_entity_s *));
+static void parse_external_entity
+ P((char *, struct sgmls *, external_entity_s *));
+static void parse_subdoc_entity P((char *, external_entity_s *));
+static attribute_s *parse_attribute P((struct sgmls *, char *));
+static void grow_datav P((void));
+static char *unescape P((char *));
+static char *unescape_file P((char *));
+static int unescape1 P((char *));
+static char *scan_token P((char **));
+static int count_args P((char *));
+static struct list *list_find P((struct list *, char *, int));
+static UNIV xmalloc P((unsigned));
+static UNIV xrealloc P((UNIV , unsigned));
+static char *strsave P((char *));
+static int read_line P((struct sgmls *));
+static notation_s *lookup_notation P((struct sgmls *, char *));
+static entity_s *lookup_entity P((struct sgmls *, char *));
+static external_entity_s *lookup_external_entity P((struct sgmls *, char *));
+static void define_external_entity P((struct sgmls *, external_entity_s *));
+static void define_internal_entity P((struct sgmls *, internal_entity_s *));
+static void define_notation P((struct sgmls *, notation_s *));
+static data_s *copy_data P((data_s *, int));
+static void list_finish_level P((struct list **, int));
+static void add_attribute P((attribute_s **, attribute_s *));
+static void default_errhandler P((int, char *, unsigned long));
+
+#define xfree(s) do { if (s) free(s); } while (0)
+
+static sgmls_errhandler *errhandler = default_errhandler;
+static unsigned long input_lineno = 0;
+
+static data_s *datav = 0;
+static int datav_size = 0;
+
+struct sgmls *sgmls_create(fp)
+ FILE *fp;
+{
+ struct sgmls *sp;
+
+ sp = (struct sgmls *)malloc(sizeof(struct sgmls));
+ if (!sp)
+ return 0;
+ sp->fp = fp;
+ sp->entities = 0;
+ sp->notations = 0;
+ sp->attributes = 0;
+ sp->lineno = 0;
+ sp->filename = 0;
+ sp->filename_size = 0;
+ sp->input_lineno = 0;
+ sp->buf_size = 0;
+ sp->buf = 0;
+ sp->subdoc_level = 0;
+ sp->files = 0;
+ sp->nfiles = 0;
+ sp->sysid = 0;
+ sp->pubid = 0;
+ return sp;
+}
+
+void sgmls_free(sp)
+ struct sgmls *sp;
+{
+ struct entity_list *ep;
+ struct notation_list *np;
+
+ if (!sp)
+ return;
+ xfree(sp->filename);
+ sgmls_free_attributes(sp->attributes);
+
+ for (ep = sp->entities; ep;) {
+ struct entity_list *tem = ep->next;
+ if (ep->entity.is_internal) {
+ xfree(ep->entity.u.internal.data.s);
+ free(ep->entity.u.internal.name);
+ }
+ else {
+ int i;
+ for (i = 0; i < ep->entity.u.external.nfilenames; i++)
+ xfree(ep->entity.u.external.filenames[i]);
+ xfree(ep->entity.u.external.filenames);
+ xfree(ep->entity.u.external.sysid);
+ xfree(ep->entity.u.external.pubid);
+ sgmls_free_attributes(ep->entity.u.external.attributes);
+ free(ep->entity.u.internal.name);
+ }
+ free(ep);
+ ep = tem;
+ }
+
+ for (np = sp->notations; np;) {
+ struct notation_list *tem = np->next;
+ xfree(np->notation.sysid);
+ xfree(np->notation.pubid);
+ free(np->notation.name);
+ free(np);
+ np = tem;
+ }
+
+ xfree(sp->buf);
+ xfree(sp->pubid);
+ xfree(sp->sysid);
+ if (sp->files) {
+ int i;
+ for (i = 0; i < sp->nfiles; i++)
+ free(sp->files[i]);
+ free(sp->files);
+ }
+ free(sp);
+
+ xfree(datav);
+ datav = 0;
+ datav_size = 0;
+}
+
+sgmls_errhandler *sgmls_set_errhandler(handler)
+ sgmls_errhandler *handler;
+{
+ sgmls_errhandler *old = errhandler;
+ if (handler)
+ errhandler = handler;
+ return old;
+}
+
+int sgmls_next(sp, e)
+ struct sgmls *sp;
+ event_s *e;
+{
+ while (read_line(sp)) {
+ char *buf = sp->buf;
+
+ e->filename = sp->filename;
+ e->lineno = sp->lineno;
+
+ switch (buf[0]) {
+ case DATA_CODE:
+ e->u.data.n = parse_data(buf + 1, &sp->lineno);
+ e->u.data.v = datav;
+ e->type = SGMLS_EVENT_DATA;
+ return 1;
+ case START_CODE:
+ {
+ char *p;
+ e->u.start.attributes = sp->attributes;
+ sp->attributes = 0;
+ e->type = SGMLS_EVENT_START;
+ p = buf + 1;
+ e->u.start.gi = scan_token(&p);
+ return 1;
+ }
+ case END_CODE:
+ {
+ char *p = buf + 1;
+ e->type = SGMLS_EVENT_END;
+ e->u.end.gi = scan_token(&p);
+ return 1;
+ }
+ case START_SUBDOC_CODE:
+ case END_SUBDOC_CODE:
+ {
+ char *p = buf + 1;
+ char *name = scan_token(&p);
+ if (buf[0] == START_SUBDOC_CODE) {
+ e->u.entity = lookup_external_entity(sp, name);
+ sp->subdoc_level++;
+ e->type = SGMLS_EVENT_SUBSTART;
+ }
+ else {
+ e->type = SGMLS_EVENT_SUBEND;
+ list_finish_level((struct list **)&sp->entities, sp->subdoc_level);
+ list_finish_level((struct list **)&sp->notations, sp->subdoc_level);
+ sp->subdoc_level--;
+ e->u.entity = lookup_external_entity(sp, name);
+ }
+ return 1;
+ }
+ case ATTRIBUTE_CODE:
+ add_attribute(&sp->attributes, parse_attribute(sp, buf + 1));
+ break;
+ case DATA_ATTRIBUTE_CODE:
+ {
+ char *p = buf + 1;
+ char *name;
+ attribute_s *a;
+ external_entity_s *ext;
+
+ name = scan_token(&p);
+ a = parse_attribute(sp, p);
+ ext = lookup_external_entity(sp, name);
+ add_attribute(&ext->attributes, a);
+ }
+ break;
+ case REFERENCE_ENTITY_CODE:
+ {
+ char *p = buf + 1;
+ char *name;
+ name = scan_token(&p);
+ e->u.entity = lookup_external_entity(sp, name);
+ e->type = SGMLS_EVENT_ENTITY;
+ return 1;
+ }
+ case DEFINE_NOTATION_CODE:
+ {
+ notation_s notation;
+
+ parse_notation(buf + 1, &notation);
+ define_notation(sp, &notation);
+ }
+ break;
+ case DEFINE_EXTERNAL_ENTITY_CODE:
+ {
+ external_entity_s external;
+
+ parse_external_entity(buf + 1, sp, &external);
+ define_external_entity(sp, &external);
+ }
+ break;
+ case DEFINE_SUBDOC_ENTITY_CODE:
+ {
+ external_entity_s external;
+
+ parse_subdoc_entity(buf + 1, &external);
+ define_external_entity(sp, &external);
+ }
+ break;
+ case DEFINE_INTERNAL_ENTITY_CODE:
+ {
+ internal_entity_s internal;
+
+ parse_internal_entity(buf + 1, &internal);
+ define_internal_entity(sp, &internal);
+ }
+ break;
+ case PI_CODE:
+ e->u.pi.len = unescape1(buf + 1);
+ e->u.pi.s = buf + 1;
+ e->type = SGMLS_EVENT_PI;
+ return 1;
+ case LOCATION_CODE:
+ parse_location(buf + 1, sp);
+ break;
+ case APPINFO_CODE:
+ e->u.appinfo = unescape(buf + 1);
+ e->type = SGMLS_EVENT_APPINFO;
+ return 1;
+ case SYSID_CODE:
+ sp->sysid = strsave(unescape(buf + 1));
+ break;
+ case PUBID_CODE:
+ sp->pubid = strsave(unescape(buf + 1));
+ break;
+ case FILE_CODE:
+ sp->files = xrealloc(sp->files, (sp->nfiles + 1)*sizeof(char *));
+ sp->files[sp->nfiles] = strsave(unescape_file(buf + 1));
+ sp->nfiles += 1;
+ break;
+ case CONFORMING_CODE:
+ e->type = SGMLS_EVENT_CONFORMING;
+ return 1;
+ default:
+ error(E_COMMAND);
+ }
+ }
+
+ return 0;
+}
+
+static
+int parse_data(p, linenop)
+ char *p;
+ unsigned long *linenop;
+{
+ int n = 0;
+ char *start = p;
+ char *q;
+ int is_sdata = 0;
+
+ /* No need to copy before first escape. */
+
+ for (; *p != '\\' && *p != '\0'; p++)
+ ;
+ q = p;
+ while (*p) {
+ if (*p == '\\') {
+ switch (*++p) {
+ case '\\':
+ *q++ = *p++;
+ break;
+ case 'n':
+ *q++ = RECHAR;
+ *linenop += 1;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val = *p++ - '0';
+ if (*p >= '0' && *p <= '7') {
+ val = val*8 + (*p++ - '0');
+ if (*p >= '0' && *p <= '7')
+ val = val*8 + (*p++ - '0');
+ }
+ *q++ = (char)val;
+ }
+ break;
+ case '|':
+ if (q > start || is_sdata) {
+ if (n >= datav_size)
+ grow_datav();
+ datav[n].s = start;
+ datav[n].len = q - start;
+ datav[n].is_sdata = is_sdata;
+ n++;
+ }
+ is_sdata = !is_sdata;
+ start = q;
+ p++;
+ break;
+ default:
+ error(E_BADESCAPE);
+ }
+ }
+ else
+ *q++ = *p++;
+ }
+
+ if (q > start || is_sdata) {
+ if (n >= datav_size)
+ grow_datav();
+ datav[n].s = start;
+ datav[n].len = q - start;
+ datav[n].is_sdata = is_sdata;
+ n++;
+ }
+ return n;
+}
+
+static
+void grow_datav()
+{
+ unsigned size = datav_size ? 2*datav_size : 2;
+ datav = (data_s *)xrealloc((UNIV)datav, size*sizeof(data_s));
+ datav_size = size;
+}
+
+static
+void parse_location(s, sp)
+ char *s;
+ struct sgmls *sp;
+{
+ unsigned size;
+
+ if (*s < '0' || *s > '9' || sscanf(s, "%lu", &sp->lineno) != 1)
+ error(E_NUMBER);
+ do {
+ ++s;
+ } while (*s >= '0' && *s <= '9');
+
+ if (*s != ' ')
+ return;
+ s++;
+ s = unescape_file(s);
+ size = strlen(s) + 1;
+ if (size <= sp->filename_size)
+ strcpy(sp->filename, s);
+ else {
+ sp->filename = xrealloc(sp->filename, size);
+ strcpy(sp->filename, s);
+ sp->filename_size = size;
+ }
+}
+
+static
+void parse_notation(s, n)
+ char *s;
+ notation_s *n;
+{
+ n->name = strsave(scan_token(&s));
+}
+
+static
+void parse_internal_entity(s, e)
+ char *s;
+ internal_entity_s *e;
+{
+ char *type;
+
+ e->name = strsave(scan_token(&s));
+ type = scan_token(&s);
+ if (strcmp(type, "CDATA") == 0)
+ e->data.is_sdata = 0;
+ else if (strcmp(type, "SDATA") == 0)
+ e->data.is_sdata = 1;
+ else
+ error(E_BADINTERNAL);
+ e->data.len = unescape1(s);
+ if (e->data.len == 0)
+ e->data.s = 0;
+ else {
+ e->data.s = xmalloc(e->data.len);
+ memcpy(e->data.s, s, e->data.len);
+ }
+}
+
+static
+void parse_external_entity(s, sp, e)
+ char *s;
+ struct sgmls *sp;
+ external_entity_s *e;
+{
+ char *type;
+ char *notation;
+
+ e->name = strsave(scan_token(&s));
+ type = scan_token(&s);
+ if (strcmp(type, "CDATA") == 0)
+ e->type = SGMLS_ENTITY_CDATA;
+ else if (strcmp(type, "SDATA") == 0)
+ e->type = SGMLS_ENTITY_SDATA;
+ else if (strcmp(type, "NDATA") == 0)
+ e->type = SGMLS_ENTITY_NDATA;
+ else
+ error(E_BADEXTERNAL);
+ notation = scan_token(&s);
+ e->notation = lookup_notation(sp, notation);
+}
+
+static
+void parse_subdoc_entity(s, e)
+ char *s;
+ external_entity_s *e;
+{
+ e->name = strsave(scan_token(&s));
+ e->type = SGMLS_ENTITY_SUBDOC;
+}
+
+static
+attribute_s *parse_attribute(sp, s)
+ struct sgmls *sp;
+ char *s;
+{
+ attribute_s *a;
+ char *type;
+
+ a = (attribute_s *)xmalloc(sizeof(*a));
+ a->name = strsave(scan_token(&s));
+ type = scan_token(&s);
+ if (strcmp(type, "CDATA") == 0) {
+ unsigned long lineno = 0;
+ a->type = SGMLS_ATTR_CDATA;
+ a->value.data.n = parse_data(s, &lineno);
+ a->value.data.v = copy_data(datav, a->value.data.n);
+ }
+ else if (strcmp(type, "IMPLIED") == 0) {
+ a->type = SGMLS_ATTR_IMPLIED;
+ }
+ else if (strcmp(type, "NOTATION") == 0) {
+ a->type = SGMLS_ATTR_NOTATION;
+ a->value.notation = lookup_notation(sp, scan_token(&s));
+ }
+ else if (strcmp(type, "ENTITY") == 0) {
+ int n, i;
+ a->type = SGMLS_ATTR_ENTITY;
+ n = count_args(s);
+ if (n == 0)
+ error(E_MISSING);
+ a->value.entity.v = (entity_s **)xmalloc(n*sizeof(entity_s *));
+ a->value.entity.n = n;
+ for (i = 0; i < n; i++)
+ a->value.entity.v[i] = lookup_entity(sp, scan_token(&s));
+ }
+ else if (strcmp(type, "TOKEN") == 0) {
+ int n, i;
+ a->type = SGMLS_ATTR_TOKEN;
+ n = count_args(s);
+ if (n == 0)
+ error(E_MISSING);
+ a->value.token.v = (char **)xmalloc(n * sizeof(char *));
+ for (i = 0; i < n; i++)
+ a->value.token.v[i] = strsave(scan_token(&s));
+ a->value.token.n = n;
+ }
+ else
+ error(E_ATTR);
+ return a;
+}
+
+void sgmls_free_attributes(p)
+ attribute_s *p;
+{
+ while (p) {
+ attribute_s *nextp = p->next;
+ switch (p->type) {
+ case SGMLS_ATTR_CDATA:
+ if (p->value.data.v) {
+ free(p->value.data.v[0].s);
+ free(p->value.data.v);
+ }
+ break;
+ case SGMLS_ATTR_TOKEN:
+ {
+ int i;
+ for (i = 0; i < p->value.token.n; i++)
+ free(p->value.token.v[i]);
+ xfree(p->value.token.v);
+ }
+ break;
+ case SGMLS_ATTR_ENTITY:
+ xfree(p->value.entity.v);
+ break;
+ case SGMLS_ATTR_IMPLIED:
+ case SGMLS_ATTR_NOTATION:
+ break;
+ }
+ free(p->name);
+ free(p);
+ p = nextp;
+ }
+}
+
+static
+data_s *copy_data(v, n)
+ data_s *v;
+ int n;
+{
+ if (n == 0)
+ return 0;
+ else {
+ int i;
+ unsigned total;
+ char *p;
+ data_s *result;
+
+ result = (data_s *)xmalloc(n*sizeof(data_s));
+ total = 0;
+ for (i = 0; i < n; i++)
+ total += v[i].len;
+ if (!total)
+ total++;
+ p = xmalloc(total);
+ for (i = 0; i < n; i++) {
+ result[i].s = p;
+ memcpy(result[i].s, v[i].s, v[i].len);
+ result[i].len = v[i].len;
+ p += v[i].len;
+ result[i].is_sdata = v[i].is_sdata;
+ }
+ return result;
+ }
+}
+
+/* Unescape s, and return nul-terminated data. Give an error
+if the data contains 0. */
+
+static
+char *unescape(s)
+ char *s;
+{
+ int len = unescape1(s);
+ if (
+#ifdef __BORLANDC__
+ len > 0 &&
+#endif
+ memchr(s, '\0', len))
+ error(E_NULESCAPE);
+ s[len] = '\0';
+ return s;
+}
+
+/* Like unescape(), but REs are represented by 012 not 015. */
+
+static
+char *unescape_file(s)
+ char *s;
+{
+ char *p;
+ p = s = unescape(s);
+ while ((p = strchr(p, RECHAR)) != 0)
+ *p++ = '\n';
+ return s;
+
+}
+
+/* Unescape s, and return length of data. The data may contain 0. */
+
+static
+int unescape1(s)
+ char *s;
+{
+ const char *p;
+ char *q;
+
+ q = strchr(s, '\\');
+ if (!q)
+ return strlen(s);
+ p = q;
+ while (*p) {
+ if (*p == '\\') {
+ switch (*++p) {
+ case '\\':
+ *q++ = *p++;
+ break;
+ case 'n':
+ *q++ = RECHAR;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val = *p++ - '0';
+ if (*p >= '0' && *p <= '7') {
+ val = val*8 + (*p++ - '0');
+ if (*p >= '0' && *p <= '7')
+ val = val*8 + (*p++ - '0');
+ }
+ *q++ = (char)val;
+ }
+ break;
+ case '|':
+ error(E_SDATA);
+ default:
+ error(E_BADESCAPE);
+ }
+ }
+ else
+ *q++ = *p++;
+ }
+ return q - s;
+}
+
+static
+char *scan_token(pp)
+ char **pp;
+{
+ char *start = *pp;
+ while (**pp != '\0') {
+ if (**pp == ' ') {
+ **pp = '\0';
+ *pp += 1;
+ break;
+ }
+ *pp += 1;
+ }
+ if (!*start)
+ error(E_MISSING);
+ return start;
+}
+
+static
+int count_args(p)
+ char *p;
+{
+ int n = 0;
+
+ while (*p != '\0') {
+ n++;
+ do {
+ ++p;
+ if (*p == ' ') {
+ p++;
+ break;
+ }
+ } while (*p != '\0');
+ }
+ return n;
+}
+
+static
+int read_line(sp)
+ struct sgmls *sp;
+{
+ unsigned i = 0;
+ FILE *fp = sp->fp;
+ int c;
+ char *buf = sp->buf;
+ unsigned buf_size = sp->buf_size;
+
+ c = getc(fp);
+ if (c == EOF) {
+ input_lineno = sp->input_lineno;
+ if (ferror(fp))
+ error(E_SYSTEM);
+ return 0;
+ }
+
+ sp->input_lineno++;
+ input_lineno = sp->input_lineno;
+ for (;;) {
+ if (i >= buf_size) {
+ if (buf_size == 0)
+ buf_size = 24;
+ else if (buf_size > (unsigned)UINT_MAX/2) {
+ if (buf_size == (unsigned)UINT_MAX)
+ error(E_LINELENGTH);
+ buf_size = (unsigned)UINT_MAX;
+ }
+ else
+ buf_size *= 2;
+ buf = xrealloc(buf, buf_size);
+ sp->buf = buf;
+ sp->buf_size = buf_size;
+ }
+ if (c == '\0')
+ error(E_NUL);
+ if (c == '\n') {
+ buf[i] = '\0';
+ break;
+ }
+ buf[i++] = c;
+ c = getc(fp);
+ if (c == EOF) {
+ if (ferror(fp))
+ error(E_SYSTEM);
+ else
+ error(E_EOF);
+ }
+ }
+ return 1;
+}
+
+static
+notation_s *lookup_notation(sp, name)
+struct sgmls *sp;
+char *name;
+{
+ struct notation_list *p
+ = (struct notation_list *)list_find((struct list *)sp->notations, name,
+ sp->subdoc_level);
+ if (!p)
+ error(E_BADNOTATION);
+ return &p->notation;
+}
+
+static
+entity_s *lookup_entity(sp, name)
+struct sgmls *sp;
+char *name;
+{
+ struct entity_list *p
+ = (struct entity_list *)list_find((struct list *)sp->entities, name,
+ sp->subdoc_level);
+ if (!p)
+ error(E_BADENTITY);
+ return &p->entity;
+}
+
+static
+external_entity_s *lookup_external_entity(sp, name)
+struct sgmls *sp;
+char *name;
+{
+ entity_s *p = lookup_entity(sp, name);
+ if (p->is_internal)
+ error(E_INTERNALENTITY);
+ return &p->u.external;
+}
+
+static
+void define_external_entity(sp, e)
+struct sgmls *sp;
+external_entity_s *e;
+{
+ struct entity_list *p;
+ e->attributes = 0;
+ e->filenames = sp->files;
+ e->nfilenames = sp->nfiles;
+ sp->files = 0;
+ sp->nfiles = 0;
+ e->pubid = sp->pubid;
+ sp->pubid = 0;
+ e->sysid = sp->sysid;
+ sp->sysid = 0;
+ p = (struct entity_list *)xmalloc(sizeof(struct entity_list));
+ memcpy((UNIV)&p->entity.u.external, (UNIV)e, sizeof(*e));
+ p->entity.is_internal = 0;
+ p->subdoc_level = sp->subdoc_level;
+ p->next = sp->entities;
+ sp->entities = p;
+}
+
+static
+void define_internal_entity(sp, e)
+struct sgmls *sp;
+internal_entity_s *e;
+{
+ struct entity_list *p;
+ p = (struct entity_list *)xmalloc(sizeof(struct entity_list));
+ memcpy((UNIV)&p->entity.u.internal, (UNIV)e, sizeof(*e));
+ p->entity.is_internal = 1;
+ p->subdoc_level = sp->subdoc_level;
+ p->next = sp->entities;
+ sp->entities = p;
+}
+
+static
+void define_notation(sp, np)
+struct sgmls *sp;
+notation_s *np;
+{
+ struct notation_list *p;
+ np->sysid = sp->sysid;
+ sp->sysid = 0;
+ np->pubid = sp->pubid;
+ sp->pubid = 0;
+ p = (struct notation_list *)xmalloc(sizeof(struct notation_list));
+ memcpy((UNIV)&p->notation, (UNIV)np, sizeof(*np));
+ p->subdoc_level = sp->subdoc_level;
+ p->next = sp->notations;
+ sp->notations = p;
+}
+
+static
+struct list *list_find(p, name, level)
+ struct list *p;
+ char *name;
+ int level;
+{
+ for (; p && p->subdoc_level == level; p = p->next)
+ if (strcmp(p->name, name) == 0)
+ return p;
+ return 0;
+}
+
+/* Move all the items in the list whose subdoc level is level to the
+end of the list and make their subdoc_level -1. */
+
+static
+void list_finish_level(listp, level)
+ struct list **listp;
+ int level;
+{
+ struct list **pp, *next_level, *old_level;
+ for (pp = listp; *pp && (*pp)->subdoc_level == level; pp = &(*pp)->next)
+ (*pp)->subdoc_level = -1;
+ next_level = *pp;
+ *pp = 0;
+ old_level = *listp;
+ *listp = next_level;
+ for (pp = listp; *pp; pp = &(*pp)->next)
+ ;
+ *pp = old_level;
+}
+
+static
+void add_attribute(pp, a)
+ attribute_s **pp, *a;
+{
+#if 0
+ for (; *pp && strcmp((*pp)->name, a->name) < 0; pp = &(*pp)->next)
+ ;
+#endif
+ a->next = *pp;
+ *pp = a;
+}
+
+
+static
+char *strsave(s)
+char *s;
+{
+ if (!s)
+ return s;
+ else {
+ char *p = xmalloc(strlen(s) + 1);
+ strcpy(p, s);
+ return p;
+ }
+}
+
+static
+UNIV xmalloc(n)
+ unsigned n;
+{
+ UNIV p = malloc(n);
+ if (!p)
+ error(E_NOMEM);
+ return p;
+}
+
+/* ANSI C says first argument to realloc can be NULL, but not everybody
+ appears to support this. */
+
+static
+UNIV xrealloc(p, n)
+ UNIV p;
+ unsigned n;
+{
+ p = p ? realloc(p, n) : malloc(n);
+ if (!p)
+ error(E_NOMEM);
+ return p;
+}
+
+static
+void error(num)
+ enum error_code num;
+{
+ (*errhandler)((int)num, errlist[num], input_lineno);
+ abort();
+}
+
+static
+void default_errhandler(num, msg, lineno)
+ int num;
+ char *msg;
+ unsigned long lineno;
+{
+ fprintf(stderr, "Line %lu: %s\n", lineno, msg);
+ exit(1);
+}
diff --git a/usr.bin/sgmls/libsgmls/sgmls.h b/usr.bin/sgmls/libsgmls/sgmls.h
new file mode 100644
index 0000000..79b2658
--- /dev/null
+++ b/usr.bin/sgmls/libsgmls/sgmls.h
@@ -0,0 +1,127 @@
+/* sgmls.h
+ Interface to a library for reading output of sgmls. */
+
+struct sgmls_data {
+ char *s;
+ unsigned len;
+ char is_sdata;
+};
+
+struct sgmls_notation {
+ char *name;
+ char *sysid;
+ char *pubid;
+};
+
+struct sgmls_internal_entity {
+ char *name;
+ struct sgmls_data data;
+};
+
+enum sgmls_external_entity_type {
+ SGMLS_ENTITY_CDATA,
+ SGMLS_ENTITY_SDATA,
+ SGMLS_ENTITY_NDATA,
+ SGMLS_ENTITY_SUBDOC
+ };
+
+struct sgmls_external_entity {
+ char *name;
+ enum sgmls_external_entity_type type;
+ char **filenames;
+ int nfilenames;
+ char *pubid;
+ char *sysid;
+ struct sgmls_attribute *attributes;
+ struct sgmls_notation *notation;
+};
+
+struct sgmls_entity {
+ union {
+ struct sgmls_internal_entity internal;
+ struct sgmls_external_entity external;
+ } u;
+ char is_internal;
+};
+
+enum sgmls_attribute_type {
+ SGMLS_ATTR_IMPLIED,
+ SGMLS_ATTR_CDATA,
+ SGMLS_ATTR_TOKEN,
+ SGMLS_ATTR_ENTITY,
+ SGMLS_ATTR_NOTATION
+};
+
+struct sgmls_attribute {
+ struct sgmls_attribute *next;
+ char *name;
+ enum sgmls_attribute_type type;
+ union {
+ struct {
+ struct sgmls_data *v;
+ int n;
+ } data;
+ struct {
+ struct sgmls_entity **v;
+ int n;
+ } entity;
+ struct {
+ char **v;
+ int n;
+ } token;
+ struct sgmls_notation *notation;
+ } value;
+};
+
+enum sgmls_event_type {
+ SGMLS_EVENT_DATA, /* data */
+ SGMLS_EVENT_ENTITY, /* external entity reference */
+ SGMLS_EVENT_PI, /* processing instruction */
+ SGMLS_EVENT_START, /* element start */
+ SGMLS_EVENT_END, /* element end */
+ SGMLS_EVENT_SUBSTART, /* subdocument start */
+ SGMLS_EVENT_SUBEND, /* subdocument end */
+ SGMLS_EVENT_APPINFO, /* appinfo */
+ SGMLS_EVENT_CONFORMING /* the document was conforming */
+ };
+
+struct sgmls_event {
+ enum sgmls_event_type type;
+ union {
+ struct {
+ struct sgmls_data *v;
+ int n;
+ } data;
+ struct sgmls_external_entity *entity;
+ struct {
+ char *s;
+ unsigned len;
+ } pi;
+ struct {
+ char *gi;
+ struct sgmls_attribute *attributes;
+ } start;
+ struct {
+ char *gi;
+ } end;
+ char *appinfo;
+ } u;
+ char *filename; /* SGML filename */
+ unsigned long lineno; /* SGML lineno */
+};
+
+#ifdef __STDC__
+void sgmls_free_attributes(struct sgmls_attribute *);
+struct sgmls *sgmls_create(FILE *);
+int sgmls_next(struct sgmls *, struct sgmls_event *);
+void sgmls_free(struct sgmls *);
+typedef void sgmls_errhandler(int, char *, unsigned long);
+sgmls_errhandler *sgmls_set_errhandler(sgmls_errhandler *);
+#else /* not __STDC__ */
+void sgmls_free_attributes();
+struct sgmls *sgmls_create();
+int sgmls_next();
+void sgmls_free();
+typedef void sgmls_errhandler();
+sgmls_errhandler *sgmls_set_errhandler();
+#endif /* not __STDC__ */
diff --git a/usr.bin/sgmls/sgmls.pl b/usr.bin/sgmls/sgmls.pl
new file mode 100755
index 0000000..edb9eb6
--- /dev/null
+++ b/usr.bin/sgmls/sgmls.pl
@@ -0,0 +1,247 @@
+#! /usr/bin/perl
+
+# This is a skeleton of a perl script for processing the output of
+# sgmls. You must change the parts marked with "XXX".
+
+# XXX This is for troff: in data, turn \ into \e (which prints as \).
+# Backslashes in SDATA entities are left as backslashes.
+
+$backslash_in_data = "\\e";
+
+$prog = $0;
+
+$prog =~ s|.*/||;
+
+$level = 0;
+
+while (<STDIN>) {
+ chop;
+ $command = substr($_, 0, 1);
+ substr($_, 0, 1) = "";
+ if ($command eq '(') {
+ &start_element($_);
+ $level++;
+ }
+ elsif ($command eq ')') {
+ $level--;
+ &end_element($_);
+ foreach $key (keys %attribute_value) {
+ @splitkey = split($;, $key);
+ if ($splitkey[0] == $level) {
+ delete $attribute_value{$key};
+ delete $attribute_type{$key};
+ }
+ }
+ }
+ elsif ($command eq '-') {
+ &unescape_data($_);
+ &data($_);
+ }
+ elsif ($command eq 'A') {
+ @field = split(/ /, $_, 3);
+ $attribute_type{$level,$field[0]} = $field[1];
+ &unescape_data($field[2]);
+ $attribute_value{$level,$field[0]} = $field[2];
+ }
+ elsif ($command eq '&') {
+ &entity($_);
+ }
+ elsif ($command eq 'D') {
+ @field = split(/ /, $_, 4);
+ $data_attribute_type{$field[0], $field[1]} = $field[2];
+ &unescape_data($field[3]);
+ $data_attribute_value{$field[0], $field[1]} = $field[3];
+ }
+ elsif ($command eq 'N') {
+ $notation{$_} = 1;
+ if (defined($sysid)) {
+ $notation_sysid{$_} = $sysid;
+ undef($sysid);
+ }
+ if (defined($pubid)) {
+ $notation_pubid{$_} = $pubid;
+ undef($pubid);
+ }
+ }
+ elsif ($command eq 'I') {
+ @field = split(/ /, $_, 3);
+ $entity_type{$field[0]} = $field[1];
+ &unescape($field[2]);
+ # You may want to substitute \e for \ if the type is CDATA.
+ $entity_text{$field[0]} = $field[2];
+ $entity_code{$field[0]} = 'I';
+ }
+ elsif ($command eq 'E') {
+ @field = split(/ /, $_);
+ $entity_code{$field[0]} = 'E';
+ $entity_type{$field[0]} = $field[1];
+ $entity_notation{$field[0]} = $field[2];
+ if (defined(@files)) {
+ foreach $i (0..$#files) {
+ $entity_filename{$field[0], $i} = $files[i];
+ }
+ undef(@files);
+ }
+ if (defined($sysid)) {
+ $entity_sysid{$field[0]} = $sysid;
+ undef($sysid);
+ }
+ if (defined($pubid)) {
+ $entity_pubid{$field[0]} = $pubid;
+ undef($pubid);
+ }
+ }
+ elsif ($command eq 'S') {
+ $entity_code{$_} = 'S';
+ if (defined(@files)) {
+ foreach $i (0..$#files) {
+ $entity_filename{$_, $i} = $files[i];
+ }
+ undef(@files);
+ }
+ if (defined($sysid)) {
+ $entity_sysid{$_} = $sysid;
+ undef($sysid);
+ }
+ if (defined($pubid)) {
+ $entity_pubid{$_} = $pubid;
+ undef($pubid);
+ }
+ }
+ elsif ($command eq '?') {
+ &unescape($_);
+ &pi($_);
+ }
+ elsif ($command eq 'L') {
+ @field = split(/ /, $_);
+ $lineno = $field[0];
+ if ($#field >= 1) {
+ &unescape($field[1]);
+ $filename = $field[1];
+ }
+ }
+ elsif ($command eq 'V') {
+ @field = split(/ /, $_, 2);
+ &unescape($field[1]);
+ $environment{$field[0]} = $field[1];
+ }
+ elsif ($command eq '{') {
+ &start_subdoc($_);
+ }
+ elsif ($command eq '}') {
+ &end_subdoc($_);
+ }
+ elsif ($command eq 'f') {
+ &unescape($_);
+ push(@files, $_);
+ }
+ elsif ($command eq 'p') {
+ &unescape($_);
+ $pubid = $_;
+ }
+ elsif ($command eq 's') {
+ &unescape($_);
+ $sysid = $_;
+ }
+ elsif ($command eq 'C') {
+ $conforming = 1;
+ }
+ else {
+ warn "$prog:$ARGV:$.: unrecognized command \`$command'\n";
+ }
+}
+
+sub unescape {
+ $_[0] =~ s/\\([0-7][0-7]?[0-7]?|.)/&esc($1)/eg;
+}
+
+sub esc {
+ local($_) = $_[0];
+ if ($_ eq '012' || $_ eq '12') {
+ ""; # ignore RS
+ }
+ elsif (/^[0-7]/) {
+ sprintf("%c", oct);
+ }
+ elsif ($_ eq 'n') {
+ "\n";
+ }
+ elsif ($_ eq '|') {
+ "";
+ }
+ elsif ($_ eq "\\") {
+ "\\";
+ }
+ else {
+ $_;
+ }
+}
+
+sub unescape_data {
+ local($sdata) = 0;
+ $_[0] =~ s/\\([0-7][0-7]?[0-7]?|.)/&esc_data($1)/eg;
+}
+
+sub esc_data {
+ local($_) = $_[0];
+ if ($_ eq '012' || $_ eq '12') {
+ ""; # ignore RS
+ }
+ elsif (/^[0-7]/) {
+ sprintf("%c", oct);
+ }
+ elsif ($_ eq 'n') {
+ "\n";
+ }
+ elsif ($_ eq '|') {
+ $sdata = !$sdata;
+ "";
+ }
+ elsif ($_ eq "\\") {
+ $sdata ? "\\" : $backslash_in_data;
+ }
+ else {
+ $_;
+ }
+}
+
+
+sub start_element {
+ local($gi) = $_[0];
+ # XXX
+}
+
+sub end_element {
+ local($gi) = $_[0];
+ # XXX
+}
+
+sub data {
+ local($data) = $_[0];
+ # XXX
+}
+
+# A processing instruction.
+
+sub pi {
+ local($data) = $_[0];
+ # XXX
+}
+
+# A reference to an external entity.
+
+sub entity {
+ local($name) = $_[0];
+ # XXX
+}
+
+sub start_subdoc {
+ local($name) = $_[0];
+ # XXX
+}
+
+sub end_subdoc {
+ local($name) = $_[0];
+ # XXX
+}
+
diff --git a/usr.bin/sgmls/sgmls/Makefile b/usr.bin/sgmls/sgmls/Makefile
new file mode 100644
index 0000000..b46e9f6
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/Makefile
@@ -0,0 +1,19 @@
+#
+# Bmakefile for sgmls
+#
+# $Id$
+#
+
+PROG= sgmls
+
+SRCS= lexrf.c pcbrf.c synrf.c context.c md1.c md2.c pars1.c pars2.c serv.c
+SRCS+= sgml1.c sgml2.c sgmlmsg.c sgmlxtrn.c traceset.c entgen.c sgmlio.c
+SRCS+= xfprintf.c main.c unixproc.c sgmldecl.c version.c strerror.c getopt.c
+SRCS+= lineout.c ambig.c lextaba.c catalog.c
+
+CFLAGS+= -I${.CURDIR}/../libsgmls
+
+.include "../Makefile.inc"
+.include <bsd.prog.mk>
+
+
diff --git a/usr.bin/sgmls/sgmls/action.h b/usr.bin/sgmls/sgmls/action.h
new file mode 100644
index 0000000..03bf478
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/action.h
@@ -0,0 +1,180 @@
+/* ACTION.H: Symbols for all PCB action codes. */
+/* CONACT.H: Symbols for content parse action names (end with '_').
+ There must be no conflict with PARSEACT.H, which
+ uses 0 through 19, or SGMLACT.H, which uses 20 through 32
+ (except that 31 - 32 can be defined here because they are
+ used only by PARSEPRO and do not conflict with SGML.C).
+*/
+#define CIR_ 31 /* Invalid character(s) ignored in MDS; restarting parse. */
+#define DTD_ 32 /* Process DOCTYPE declaration. */
+#define DTE_ 33 /* End of DOCTYPE declaration. */
+#define PEP_ 34 /* TEMP: Previous character ended prolog. */
+#define DAS_ 35 /* Current character begins data. */
+#define FCE_ 36 /* Process free character (SR12-18, 21-30). */
+#define DCE_ 37 /* Data character in element text; change PCB. */
+#define LAS_ 38 /* Start lookahead buffer with current character. */
+#define LAM_ 39 /* Move character to lookahead buffer. */
+#define LAF_ 40 /* Flush the lookahead buffer; REPEATCC. */
+#define NED_ 41 /* Process null end-tag delimiter. */
+#define NET_ 42 /* Process null end-tag. */
+#define NST_ 43 /* Process null start-tag. */
+#define NLF_ 44 /* Flush lookahead buffer except for trailing NET or SR. */
+#define ETC_ 45 /* End-tag in CDATA or RCDATA; treat as data if invalid. */
+#define SRMIN 46 /* Dummy for SHORT REFERENCES: srn = SRn - SRMIN. */
+#define SR1_ 47 /* TAB */
+#define SR2_ 48 /* RE */
+#define SR3_ 49 /* RS */
+#define SR4_ 50 /* Leading blanks */
+#define SR5_ 51 /* Null record */
+#define DAR_ 52 /* Flush data buffer after repeating current character. */
+#define SR7_ 53 /* Trailing blanks */
+#define SR8_ 54 /* Space */
+#define SR9_ 55 /* Two or more blanks */
+#define SR10 56 /* Quotation mark (first data character) */
+#define SR11 57 /* Number sign */
+#define SR12 58 /* FCE CHARACTERS start here */
+/* _ 59 */
+#define BSQ_ 60 /* Blank sequence begun; find its end. */
+/* 61 In use by PARSEACT.H */
+/* 62 In use by PARSEACT.H */
+/* 63 In use by PARSEACT.H */
+/* 64 In use by PARSEACT.H */
+#define SR19 65 /* Hyphen */
+#define SR20 66 /* Two hyphens */
+#define SR25 71 /* Left bracket */
+#define SR26 72 /* Right bracket */
+#define RBR_ 73 /* Two right brackets. */
+#define GTR_ 74 /* EOB with pending data character */
+#define MSP_ 75 /* Marked section start in prolog outside DTD */
+#define APP_ 76 /* APPINFO (other than NONE) */
+#define STE_ 77 /* Start tag ended prolog */
+#define ETE_ 78 /* End tag ended prolog */
+
+/* GRPACT.H: Symbols for group tokenization action names (all alpha).
+ There must be no conflict with PARSEACT.H, which
+ uses 0 - 19.
+*/
+#define AND 20 /* AND connector found. */
+#define DTAG 21 /* Data tag token group occurred (treat as #CHARS). */
+#define GRPE 22 /* Group ended. */
+#define GRP_ 23 /* Group started. */
+#define NAS_ 24 /* Name started in content model or name group. */
+#define NMT_ 25 /* Name or name token started in name token group. */
+#define OPT 26 /* OPT occurrence indicator for previous token. */
+#define OR 27 /* OR connector found. */
+#define OREP 28 /* OREP occurrence indicator for previous token. */
+#define REP 29 /* REP occurrence indicator for previous token. */
+#define RNS_ 30 /* Reserved name started (#PCDATA). */
+#define SEQ 31 /* SEQ connector found. */
+/* LITACT.H: Symbols for content parse action names (end with '_').
+ There must be no conflict with PARSEACT.H, which
+ uses 0 through 19.
+*/
+#define MLA_ 20 /* Move character to look-aside data buffer. */
+#define LPR_ 21 /* Move previous character to data buffer. */
+#define RSM_ 22 /* Process record start and move it to data buffer. */
+#define FUN_ 23 /* Replace function character with a space. */
+#define LP2_ 24 /* Move previous two characters to data buffer. */
+#define MLE_ 25 /* Minimum literal error: invalid character ignored. */
+#define RPR_ 26 /* Remove previous character from data buffer; terminate. */
+#define TER_ 27 /* Terminate the parse. */
+/* MDACT.H: Symbols for markup declaration parse action names (all alpha).
+ There must be no conflict with PARSEACT.H, which
+ uses 0 - 19.
+*/
+#define CDR 20 /* CD[1] (MINUS) occurred previously. */
+#define EMD 21 /* End of markup declaration. */
+#define GRPS 22 /* Group started. */
+#define LIT 23 /* Literal started: character data. */
+#define LITE 24 /* Literal started: character data; LITA is delimiter. */
+#define MGRP 25 /* Minus exception group (MINUS,GRPO). */
+#define NAS 26 /* Name started. */
+#define NMT 27 /* Name token started. */
+#define NUM 28 /* Number or number token started. */
+#define PEN 29 /* Parameter entity name being defined (PERO found). */
+#define PGRP 30 /* Plus exception group (PLUS,GRPO). */
+#define RNS 31 /* Reserved name started. */
+#define MDS 32 /* Markup declaration subset start. */
+#define PENR 33 /* REPEATCC; PERO found. */
+/* PARSEACT.H: Symbols for common parse action names (end with '_').
+ There must be no conflict with other action name
+ files, which use numbers greater than 19.
+*/
+#define CRA_ 1 /* Character reference: alphabetic. */
+#define CRN_ 2 /* Character reference: numeric; non-char refs o.k.. */
+#define NON_ 3 /* Single byte of non-character data found. */
+#define EOF_ 4 /* Error: illegal entity end; resume old input; return. */
+#define ER_ 5 /* Entity reference; start new input source; continue. */
+#define GET_ 6 /* EOB, EOS, or EE: resume old input source; continue. */
+#define INV_ 7 /* Error: invalid char terminated markup; repeat char. */
+#define LEN_ 8 /* Error: length limit exceeded; end markup; repeat char. */
+#define NOP_ 9 /* No action necessary. */
+#define PCI_ 10 /* Previous character was invalid. */
+#define PER_ 11 /* Parameter reference; start new input source; continue. */
+#define RC2_ 12 /* Back up two characters. */
+#define RCC_ 13 /* Repeat current character. */
+#define RCR_ 14 /* Repeat current character and return to caller. */
+#define EE_ 15 /* EOS or EE: resume old input source; return to caller. */
+#define RS_ 16 /* Record start: ccnt=0; ++rcnt. */
+#define ERX_ 17 /* Entity reference; start new input source; return. */
+#define SYS_ 18 /* Error allowed: SYSCHAR in input stream; replace it. */
+#define EOD_ 19 /* End of document. */
+/* Number way out of order to avoid recompilation. */
+#define NSC_ 58 /* Handle DELNONCH/DELXNONCH when NON_ is allowed */
+#define PEX_ 61 /* Parameter entity ref; start new input source; return. */
+#define DEF_ 62 /* Data entity found. */
+#define PIE_ 63 /* PI entity found (needed in markup). */
+#define LNR_ 64 /* LEN_ error with extra REPEATCC. */
+/* SGMLACT.H: Symbols for content parse action names (end with '_')
+ that are returned to SGML.C for processing.
+ There must be no conflict with PARSEACT.H, which
+ uses 0 through 19, or CONACT.H, which uses 34 and above.
+ (Note: 31 is also used in CONACT.H, but no conflict
+ is created because they are tested only in PARSEPRO.C, which
+ completes before SGML.C starts to examine those codes.
+ Also, when EOD_ is returned from PARSECON, it is changed
+ to LOP_.)
+*/
+#define CON_ 20 /* Normal content action (one of the following). */
+#define DAF_ 21 /* Data found. */
+#define ETG_ 22 /* Process end-tag. */
+#define MD_ 23 /* Process markup declaration (NAMESTRT found). */
+#define MDC_ 24 /* Process markup declaration comment (CD found). */
+#define MSS_ 25 /* Process marked section start. */
+#define MSE_ 26 /* Process marked section end. */
+#define PIS_ 27 /* Processing instruction (string). */
+#define REF_ 28 /* Record end found. */
+#define STG_ 29 /* Process start-tag. */
+#define RSR_ 30 /* Return RS to effect SGML state transition. */
+#define LOP_ 31 /* Loop for new content without returning anything. */
+/* TAGACT.H: Symbols for tag parse action names (all alpha).
+ There must be no conflict with PARSEACT.H, which
+ uses 0 - 19.
+*/
+#define AVD 20 /* Delimited attribute value started: normal delimiter. */
+#define AVU 21 /* Undelimited value started. */
+#define ETIC 22 /* Tag closed with ETI. */
+#define NVS 23 /* Name of attribute or value started. */
+#define NASV 24 /* Saved NAS was actually an NTV. */
+#define NTV 25 /* Name token value started; get name and full value. */
+#define TAGC 26 /* Tag closed normally. */
+#define TAGO 27 /* Tag closed implicitly by TAGO character. */
+#define AVDA 28 /* Delimited attribute value started: alternative delim. */
+#define DSC 29 /* Closed by DSC character. */
+/* VALACT.H: Symbols for attribute value tokenization action names (all alpha).
+*/
+#define NOPA 0 /* No action necessary. */
+#define INVA 1 /* Invalid character; terminate parse. */
+#define LENA 2 /* Length limit of token exceeded; terminate parse. */
+#define NASA 3 /* Name started. */
+#define NMTA 4 /* Name token started. */
+#define NUMA 5 /* Number or number token started. */
+
+/* SGML declaration parsing actions. */
+
+#define ESGD 20 /* End of SGML declaration. */
+#define LIT1 21 /* Literal started. */
+#define LIT2 22 /* Literal started with LITA delimiter. */
+#define NUM1 23 /* Number started. */
+#define NAS1 24 /* Name started. */
+#define ISIG 25 /* Insignificant character occurred. */
diff --git a/usr.bin/sgmls/sgmls/adl.h b/usr.bin/sgmls/sgmls/adl.h
new file mode 100644
index 0000000..930e1e8
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/adl.h
@@ -0,0 +1,118 @@
+/* ADL.H: Definitions for attribute descriptor list processing.
+*/
+/* N/C/SDATA external entity types for nxetype member of ne structure. */
+#define ESNCDATA 1 /* External character data entity. */
+#define ESNNDATA 2 /* Non-SGML data entity. */
+#define ESNSDATA 3 /* External specific character data entity. */
+#define ESNSUB 4 /* SGML subdocument entity. */
+
+/* N/C/SDATA control block for AENTITY attributes and NDATA returns.*/
+struct ne { /* N/C/SDATA entity control block. */
+ UNIV neid; /* Files for NDATA entity. */
+ UNCH *nepubid; /* Public identifier if specified. */
+ UNCH *nesysid; /* System identifier if specified. */
+ PDCB nedcn; /* Data content notation control block. */
+ struct ad *neal; /* Data attribute list (NULL if none). */
+ UNCH *neename; /* Ptr to entity name (length and EOS). */
+ UNCH nextype; /* Entity type: NDATA SDATA CDATA SUBDOC. */
+};
+#define NESZ (sizeof(struct ne))
+typedef struct ne *PNE;
+/* NDATA entity control block fields. */
+#define NEID(p) (((PNE)p)->neid) /* File ID of NDATA entity. */
+#define NESYSID(p) (((PNE)p)->nesysid) /* System ID of NDATA entity. */
+#define NEPUBID(p) (((PNE)p)->nepubid) /* Public ID of NDATA entity. */
+#define NEDCN(p) (((PNE)p)->nedcn->ename) /* Data content notation name. */
+#define NEDCNSYSID(p) (((PNE)p)->nedcn->sysid) /* Notation system ID.*/
+#define NEDCNPUBID(p) (((PNE)p)->nedcn->pubid) /* Notation public ID.*/
+#define NEDCNDEFINED(p) (((PNE)p)->nedcn->defined) /* Notation defined? */
+#define NEDCNADL(p) (((PNE)p)->nedcn->adl) /* Data content notation attlist.*/
+#define NEENAME(p) (((PNE)p)->neename) /* Entity name pointer. */
+#define NEXTYPE(p) (((PNE)p)->nextype) /* External entity type. */
+#define NEAL(p) (((PNE)p)->neal) /* Data attributes (if any). */
+#define NEDCNMARK(p) DCNMARK(((PNE)p)->nedcn)
+
+/* Attribute descriptor list entry. */
+struct ad {
+ UNCH *adname; /* Attribute name with length and EOS. */
+ UNCH adflags; /* Attribute flags. */
+ UNCH adtype; /* Value type. */
+ UNS adnum; /* Group size or member pos in grp. */
+ UNS adlen; /* Length of default or value (for capacity). */
+ UNCH *addef; /* Default value (NULL if REQUIRED or IMPLIED). */
+ union {
+ PNE n; /* AENTITY: NDATA control block. */
+ PDCB x; /* ANOTEGRP: DCN control block. */
+ } addata; /* Special data associated with some attributes.*/
+};
+#define ADSZ (sizeof(struct ad)) /* Size of an ad structure. */
+
+/* Attribute flags for entire list adflags: ADLF. */
+#define ADLREQ 0x80 /* Attribute list: 1=REQUIRED att defined. */
+#define ADLNOTE 0x40 /* Attribute list: 1=NOTATION att defined. */
+#define ADLCONR 0x20 /* Attribute list: 1=CONREF att defined. */
+
+/* Attribute flags for list member adflags: ADFLAGS(n). */
+#define AREQ 0x80 /* Attribute: 0=null; 1=required. */
+#define ACURRENT 0x40 /* Attribute: 0=normal; 1=current. */
+#define AFIXED 0x20 /* Attribute: 0=normal; 1=must equal default. */
+#define AGROUP 0x10 /* Attribute: 0=single; 1=group of ad's. */
+#define ACONREF 0x08 /* Attribute: 0=normal; 1=att is CONREF. */
+#define AINVALID 0x04 /* Attribute: 1=value is invalid; 0=o.k. */
+#define AERROR 0x02 /* Attribute: 1=error was specified; 0=o.k. */
+#define ASPEC 0x01 /* Attribute: 1=value was specified; 0=default. */
+
+/* Attribute types for adtype. */
+#define ANMTGRP 0x00 /* Attribute: Name token group or member. */
+#define ANOTEGRP 0x01 /* Attribute: Notation (name group). */
+#define ACHARS 0x02 /* Attribute: Character string. */
+#define AENTITY 0x03 /* Attribute: Data entity (name). */
+#define AID 0x04 /* Attribute: ID value (name). */
+#define AIDREF 0x05 /* Attribute: ID reference value (name). */
+#define ANAME 0x06 /* Attribute: Name. */
+#define ANMTOKE 0x07 /* Attribute: Name token. */
+#define ANUMBER 0x08 /* Attribute: Number. */
+#define ANUTOKE 0x09 /* Attribute: Number token. */
+#define ATKNLIST 0x0A /* Attribute: >= means value is a token list. */
+#define AENTITYS 0x0A /* Attribute: Data entities (name list). */
+#define AIDREFS 0x0B /* Attribute: ID reference value (name list). */
+#define ANAMES 0x0C /* Attribute: Name list. */
+#define ANMTOKES 0x0D /* Attribute: Name token list. */
+#define ANUMBERS 0x0E /* Attribute: Number list. */
+#define ANUTOKES 0x0F /* Attribute: Number token list. */
+
+/* Field definitions for entries in an attribute list.
+ The first argument to all of these is the list address.
+*/
+/* Attribute list: flags. */
+#define ADLF(a) ((a)[0].adflags)
+/* Attribute list: number of list members. */
+#define ADN(a) ((a)[0].adtype)
+/* Attribute list: number of attributes. */
+#define AN(a) ((a)[0].adnum)
+/* Nth attribute in list: name. */
+#define ADNAME(a, n) (((a)[n].adname+1))
+/* Nth att in list: number of val)ues. */
+#define ADNUM(a, n) ((a)[n].adnum)
+/* Nth attribute in list: flags. */
+#define ADFLAGS(a, n) ((a)[n].adflags)
+/* Nth attribute in list: type. */
+#define ADTYPE(a, n) ((a)[n].adtype)
+/* Nth attribute in list: len of def or val.*/
+#define ADLEN(a, n) ((a)[n].adlen)
+/* Nth attribute in list: def or value. */
+#define ADVAL(a, n) ((a)[n].addef)
+/* Nth attribute in list: special data. */
+#define ADDATA(a, n) ((a)[n].addata)
+/* Nth att: token at Pth pos in value. */
+#define ADTOKEN(a, n, p)(((a)[n].addef+(p)))
+
+#define IDHASH 101 /* Size of ID hash table. Must be prime. */
+struct id { /* ID attribute control block. */
+ struct id *idnext; /* Next ID in chain. */
+ UNCH *idname; /* ID name with length prefix and EOS. */
+ UNCH iddefed; /* Non-zero if it has been defined. */
+ struct fwdref *idrl; /* Chain of forward references to this ID. */
+};
+#define IDSZ sizeof(struct id)
+typedef struct id *PID; /* Ptr to ID attribute control block. */
diff --git a/usr.bin/sgmls/sgmls/alloc.h b/usr.bin/sgmls/sgmls/alloc.h
new file mode 100644
index 0000000..d732178
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/alloc.h
@@ -0,0 +1,8 @@
+/* alloc.h */
+
+typedef unsigned SIZE_T;
+
+/* Like malloc and realloc, but don't return if no memory is available. */
+
+extern UNIV xmalloc P((SIZE_T));
+extern UNIV xrealloc P((UNIV, SIZE_T));
diff --git a/usr.bin/sgmls/sgmls/ambig.c b/usr.bin/sgmls/sgmls/ambig.c
new file mode 100644
index 0000000..9da02eb
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/ambig.c
@@ -0,0 +1,438 @@
+/* ambig.c -
+ Content model ambiguity checking.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+/*
+This uses the construction in pp8-9 of [1], extended to deal with AND
+groups.
+
+Note that it is not correct for the purposes of ambiguity analysis to
+handle AND groups by turning them into an OR group of SEQ groups
+(consider (a&b?)).
+
+We build an automaton for the entire content model by adding the
+following case for AND:
+
+nullable(v) := nullable(left child) and nullable(right child)
+if nullable(right child) then
+ for each x in last(left child) do
+ follow(v,x) = follow(left child,x) U first(right child);
+if nullable(left child) then
+ for each x in last(right child) do
+ follow(v,x) = follow(right child,x) U first(left child);
+first(v) := first(left child) U first(right child);
+last(v) := first(left child) U first(right child);
+
+We also build an automaton for each AND group by building automata for
+each of the members of the AND group using the above procedure and
+then combine the members using:
+
+for each x in last(left child) do
+ follow(v,x) = follow(left child,x) U first(right child);
+for each x in last(right child) do
+ follow(v,x) = follow(right child,x) U first(left child);
+first(v) := first(left child) U first(right child);
+
+The content model is ambiguous just in case one of these automata is
+non-deterministic. (Note that when checking determinism we need to
+check the `first' set as well as all the `follow' sets.)
+
+Why is this correct? Consider a primitive token in a member of an AND
+group. There are two worst cases for ambiguity: firstly, when none of
+the other members of AND group have been matched; secondly, when just
+the nullable members remain to be matched. The first case is not
+affected by context of the AND group (unless the first case is
+identical to the second case.)
+
+Note that inclusions are not relevant for the purposes of determining
+the ambiguity of content models. Otherwise the case in clause
+11.2.5.1:
+
+ An element that can satisfy an element in the content model is
+ considered to do so, even if the element is also an inclusion.
+
+could never arise.
+
+[1] Anne Brueggemann-Klein, Regular Expressions into Finite Automata,
+Universitaet Freiburg, Institut fur Informatik, 33 July 1991.
+*/
+
+#include "sgmlincl.h"
+
+/* Sets of states are represented by 0-terminated, ordered lists of
+indexes in gbuf. */
+
+#define MAXSTATES (GRPGTCNT+2)
+#define listcat(x, y) strcat((char *)(x), (char *)(y))
+#define listcpy(x, y) strcpy((char *)(x), (char *)(y))
+
+/* Information about a content token. */
+
+struct contoken {
+ UNCH size;
+ UNCH nullable;
+ UNCH *first;
+ UNCH *last;
+};
+
+static VOID contoken P((int, int, struct contoken *));
+static VOID andgroup P((int, int, struct contoken *));
+static VOID orgroup P((int, int, struct contoken *));
+static VOID seqgroup P((int, int, struct contoken *));
+static VOID andambig P((int));
+static int listambig P((UNCH *));
+static VOID listmerge P((UNCH *, UNCH *));
+static struct contoken *newcontoken P((void));
+static VOID freecontoken P((struct contoken *));
+
+
+/* Dynamically allocated vector of follow sets. */
+
+static UNCH **follow;
+static UNCH *mergebuf; /* for use by listmerge */
+
+/* Set to non-zero if the content model is ambiguous. */
+
+static int ambigsw;
+
+/* Check the current content model (in gbuf) for ambiguity. */
+
+VOID ambig()
+{
+ struct contoken *s;
+ int i;
+
+ if (!follow) {
+ /* We can't allocate everything in one chunk, because that would
+ overflow a 16-bit unsigned if GRPGTCNT was 253. */
+ UNCH *ptr;
+ follow = (UNCH **)rmalloc(MAXSTATES*sizeof(UNCH *));
+ follow[0] = 0;
+ ptr = (UNCH *)rmalloc((MAXSTATES - 1)*MAXSTATES);
+ for (i = 1; i < MAXSTATES; i++) {
+ follow[i] = ptr;
+ ptr += MAXSTATES;
+ }
+ mergebuf = (UNCH *)rmalloc(MAXSTATES);
+ }
+
+ for (i = 1; i < MAXSTATES; i++)
+ follow[i][0] = 0;
+
+ ambigsw = 0;
+
+ s = newcontoken();
+ contoken(1, 1, s);
+
+ ambigsw = ambigsw || listambig(s->first);
+
+ freecontoken(s);
+
+ for (i = 1; !ambigsw && i < MAXSTATES; i++)
+ if (listambig(follow[i]))
+ ambigsw = 1;
+
+ if (ambigsw)
+ mderr(137, (UNCH *)0, (UNCH *)0);
+}
+
+/* Free memory used for ambiguity checking. */
+
+VOID ambigfree()
+{
+ if (follow) {
+ frem((UNIV)follow[1]);
+ frem((UNIV)follow);
+ frem((UNIV)mergebuf);
+ follow = 0;
+ }
+}
+
+/* Determine whether a list of primitive content tokens (each
+represented by its index in gbuf) is ambiguous. */
+
+static
+int listambig(list)
+UNCH *list;
+{
+ UNCH *p;
+ int chars = 0;
+ int rc = 0;
+
+ for (p = list; *p; p++) {
+ if ((gbuf[*p].ttype & TTMASK) == TTETD) {
+ struct etd *e = gbuf[*p].tu.thetd;
+ if (e->mark) {
+ rc = 1;
+ break;
+ }
+ e->mark = 1;
+ }
+ else {
+ assert((gbuf[*p].ttype & TTMASK) == TTCHARS);
+ if (chars) {
+ rc = 1;
+ break;
+ }
+ chars = 1;
+ }
+ }
+
+ for (p = list; *p; p++)
+ if ((gbuf[*p].ttype & TTMASK) == TTETD)
+ gbuf[*p].tu.thetd->mark = 0;
+
+ return rc;
+}
+
+
+/* Analyze a content token. The `checkand' argument is needed to ensure
+that the algorithm is not exponential in the AND-group nesting depth.
+*/
+
+static
+VOID contoken(m, checkand, res)
+int m; /* Index of content token in gbuf */
+int checkand; /* Non-zero if AND groups should be checked */
+struct contoken *res; /* Result */
+{
+ UNCH flags = gbuf[m].ttype;
+ switch (flags & TTMASK) {
+ case TTCHARS:
+ case TTETD:
+ res->first[0] = m;
+ res->first[1] = 0;
+ res->last[0] = m;
+ res->last[1] = 0;
+ res->size = 1;
+ res->nullable = 0;
+ break;
+ case TTAND:
+ if (checkand)
+ andambig(m);
+ andgroup(m, checkand, res);
+ break;
+ case TTOR:
+ orgroup(m, checkand, res);
+ break;
+ case TTSEQ:
+ seqgroup(m, checkand, res);
+ break;
+ default:
+ abort();
+ }
+ if (flags & TREP) {
+ UNCH *p;
+ for (p = res->last; *p; p++)
+ listmerge(follow[*p], res->first);
+ }
+ if (flags & TOPT)
+ res->nullable = 1;
+}
+
+/* Check an AND group for ambiguity. */
+
+static
+VOID andambig(m)
+int m;
+{
+ int i, tnum;
+ int lim;
+ struct contoken *curr;
+ struct contoken *next;
+
+ tnum = gbuf[m].tu.tnum;
+ assert(tnum > 0);
+ curr = newcontoken();
+ next = newcontoken();
+ contoken(m + 1, 0, curr);
+ i = m + 1 + curr->size;
+ curr->size += 1;
+ for (--tnum; tnum > 0; --tnum) {
+ UNCH *p;
+ contoken(i, 0, next);
+ curr->size += next->size;
+ i += next->size;
+ for (p = curr->last; *p; p++)
+ listcat(follow[*p], next->first);
+ for (p = next->last; *p; p++)
+ listmerge(follow[*p], curr->first);
+ listcat(curr->first, next->first);
+ listcat(curr->last, next->last);
+ }
+ lim = m + curr->size;
+ for (i = m + 1; i < lim; i++) {
+ if (listambig(follow[i]))
+ ambigsw = 1;
+ follow[i][0] = 0;
+ }
+ freecontoken(curr);
+ freecontoken(next);
+}
+
+/* Handle an AND group. */
+
+static
+VOID andgroup(m, checkand, res)
+int m;
+int checkand;
+struct contoken *res;
+{
+ int i, tnum;
+ /* union of the first sets of nullable members of the group */
+ UNCH *nullablefirst;
+ struct contoken *next;
+
+ tnum = gbuf[m].tu.tnum;
+ assert(tnum > 0);
+ contoken(m + 1, checkand, res);
+ nullablefirst = (UNCH *)rmalloc(MAXSTATES);
+ if (res->nullable)
+ listcpy(nullablefirst, res->first);
+ else
+ nullablefirst[0] = 0;
+ i = m + 1 + res->size;
+ res->size += 1;
+ next = newcontoken();
+ for (--tnum; tnum > 0; --tnum) {
+ UNCH *p;
+ contoken(i, checkand, next);
+ res->size += next->size;
+ i += next->size;
+ if (next->nullable)
+ for (p = res->last; *p; p++)
+ listcat(follow[*p], next->first);
+ for (p = next->last; *p; p++)
+ listmerge(follow[*p], nullablefirst);
+ listcat(res->first, next->first);
+ if (next->nullable)
+ listcat(nullablefirst, next->first);
+ listcat(res->last, next->last);
+ res->nullable &= next->nullable;
+ }
+ frem((UNIV)nullablefirst);
+ freecontoken(next);
+}
+
+/* Handle a SEQ group. */
+
+static
+VOID seqgroup(m, checkand, res)
+int m;
+int checkand;
+struct contoken *res;
+{
+ int i, tnum;
+ struct contoken *next;
+
+ tnum = gbuf[m].tu.tnum;
+ assert(tnum > 0);
+ contoken(m + 1, checkand, res);
+ i = m + 1 + res->size;
+ res->size += 1;
+ next = newcontoken();
+ for (--tnum; tnum > 0; --tnum) {
+ UNCH *p;
+ contoken(i, checkand, next);
+ res->size += next->size;
+ i += next->size;
+ for (p = res->last; *p; p++)
+ listcat(follow[*p], next->first);
+ if (res->nullable)
+ listcat(res->first, next->first);
+ if (next->nullable)
+ listcat(res->last, next->last);
+ else
+ listcpy(res->last, next->last);
+ res->nullable &= next->nullable;
+ }
+ freecontoken(next);
+}
+
+/* Handle an OR group. */
+
+static
+VOID orgroup(m, checkand, res)
+int m;
+int checkand;
+struct contoken *res;
+{
+ int i, tnum;
+ struct contoken *next;
+
+ tnum = gbuf[m].tu.tnum;
+ assert(tnum > 0);
+ contoken(m + 1, checkand, res);
+ i = m + 1 + res->size;
+ res->size += 1;
+ next = newcontoken();
+ for (--tnum; tnum > 0; --tnum) {
+ contoken(i, checkand, next);
+ res->size += next->size;
+ i += next->size;
+ listcat(res->first, next->first);
+ listcat(res->last, next->last);
+ res->nullable |= next->nullable;
+ }
+ freecontoken(next);
+}
+
+
+/* Merge the second ordered list into the first. */
+
+static
+VOID listmerge(p, b)
+UNCH *p, *b;
+{
+ UNCH *a = mergebuf;
+
+ strcpy((char *)a, (char *)p);
+
+ for (;;) {
+ if (*a) {
+ if (*b) {
+ if (*a < *b)
+ *p++ = *a++;
+ else if (*a > *b)
+ *p++ = *b++;
+ else
+ a++;
+ }
+ else
+ *p++ = *a++;
+ }
+ else if (*b)
+ *p++ = *b++;
+ else
+ break;
+ }
+ *p = '\0';
+}
+
+static
+struct contoken *newcontoken()
+{
+ struct contoken *p = (struct contoken *)rmalloc(sizeof(struct contoken)
+ + MAXSTATES*2);
+ p->first = (UNCH *)(p + 1);
+ p->last = p->first + MAXSTATES;
+ return p;
+}
+
+static
+VOID freecontoken(p)
+struct contoken *p;
+{
+ frem((UNIV)p);
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/appl.h b/usr.bin/sgmls/sgmls/appl.h
new file mode 100644
index 0000000..2513c98
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/appl.h
@@ -0,0 +1,31 @@
+/* appl.h */
+
+enum {
+ E_NOMEM = 1,
+ E_DOC,
+ E_EXEC,
+ E_FORK,
+ E_WAIT,
+ E_SIGNAL,
+ E_OPEN,
+ E_CAPBOTCH,
+ E_SUBDOC
+};
+
+VOID process_document P((int));
+VOID output_conforming P((void));
+
+VOID appl_error VP((int, ...));
+
+#ifdef SUPPORT_SUBDOC
+int run_process P((char **));
+char **make_argv P((UNIV));
+VOID get_subcaps P((void));
+#endif
+
+#ifdef SUPPORT_SUBDOC
+extern int suberr;
+#endif
+
+extern int suppsw;
+extern int locsw;
diff --git a/usr.bin/sgmls/sgmls/catalog.c b/usr.bin/sgmls/sgmls/catalog.c
new file mode 100644
index 0000000..28077a8
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/catalog.c
@@ -0,0 +1,925 @@
+/* Normalize public identifiers to handle ISO 8879[-:]1986 problem.
+What should happen if there's a duplicate in a single catalog entry file? */
+
+#include "config.h"
+#include "std.h"
+#include "catalog.h"
+
+#ifdef USE_PROTOTYPES
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+#include "alloc.h"
+
+#define MINIMUM_DATA_CHARS \
+"abcdefghijklmnopqrstuvwxyz\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+0123456789-.'()+,/:=?"
+
+#define N_DECL_TYPE 3
+#define PUBLIC_ID_MAP N_DECL_TYPE
+#define N_TABLES (N_DECL_TYPE + 1)
+
+enum literal_type {
+ NORMAL_LITERAL,
+ MINIMUM_LITERAL
+};
+
+typedef enum {
+ EOF_PARAM,
+ NAME_PARAM,
+ LITERAL_PARAM
+} PARAM_TYPE;
+
+enum catalog_error {
+ E_NAME_EXPECTED,
+ E_LITERAL_EXPECTED,
+ E_ARG_EXPECTED,
+ E_MINIMUM_DATA,
+ E_EOF_COMMENT,
+ E_EOF_LITERAL,
+ E_NUL_CHAR,
+ E_CANNOT_OPEN,
+ E_GETC,
+ E_FCLOSE
+};
+
+#define FIRST_SYSTEM_ERROR E_CANNOT_OPEN
+
+#define HASH_TABLE_INITIAL_SIZE 8
+#define HASH_TABLE_MAX_SIZE (((SIZE_T)-1)/sizeof(struct hash_table_entry *))
+
+struct hash_table_entry {
+ int file_index;
+ const char *key;
+ const char *system_id;
+};
+
+/* Number of bytes per string block. */
+#define BLOCK_SIZE 1000
+
+/* Bytes follow the struct. */
+
+struct string_block {
+ struct string_block *next;
+};
+
+struct hash_table {
+ struct hash_table_entry **v;
+ SIZE_T size; /* must be power of 2 */
+ SIZE_T used;
+ SIZE_T used_limit;
+};
+
+struct catalog {
+ struct hash_table tables[N_TABLES];
+ char **files;
+ int n_files;
+ struct string_block *blocks;
+ char *block_ptr;
+ SIZE_T block_spare;
+ CATALOG_ERROR_HANDLER error_handler;
+ int loaded;
+};
+
+struct parser {
+ FILE *fp;
+ struct catalog *cat;
+ char *param;
+ SIZE_T param_length;
+ SIZE_T param_alloc;
+ int file_index;
+ const char *filename;
+ unsigned long newline_count;
+ char minimum_data[256];
+};
+
+static
+VOID add_catalog_file P((struct catalog *cat, const char *filename,
+ SIZE_T length));
+static
+VOID load P((struct catalog *cat));
+static
+VOID parse_file P((struct parser *parser));
+static
+VOID parse_public P((struct parser *parser));
+static
+VOID parse_name_map P((struct parser *parser,
+ int decl_type));
+static
+int parse_arg P((struct parser *parser));
+static
+PARAM_TYPE parse_param P((struct parser *parser, enum literal_type));
+static
+VOID skip_comment P((struct parser *parser));
+static
+PARAM_TYPE parse_literal P((struct parser *parser, int lit,
+ enum literal_type));
+static
+PARAM_TYPE parse_name P((struct parser *parser, int first_char));
+static
+VOID param_grow P((struct parser *parser));
+static
+const char *param_save P((struct parser *parser));
+static
+char *alloc_bytes P((struct catalog *catalog, SIZE_T n));
+static
+int param_equal P((struct parser *parser, const char *key));
+static
+int hash_table_add P((struct hash_table *table, const char *s,
+ const char *system_id, int file_index));
+static
+struct hash_table_entry *hash_table_lookup P((struct hash_table *table,
+ const char *s));
+static
+struct hash_table_entry *hash_table_lookup_subst P((struct hash_table *table,
+ const char *subst_table,
+ const char *s));
+static
+VOID hash_table_init P((struct hash_table *p));
+static
+VOID hash_table_delete P((struct hash_table *p));
+static
+SIZE_T hash_table_start_index P((struct hash_table *p, const char *s));
+static
+int subst_equal P((const char *subst_table, const char *s1, const char *s2));
+static
+VOID error P((struct parser *parser, enum catalog_error err));
+
+#define param_char(parser, c) \
+ ((((parser)->param_length < (parser)->param_alloc) \
+ || (param_grow(parser), 1)), \
+ ((parser)->param[(parser)->param_length] = (c)), \
+ ((parser)->param_length += 1))
+
+#define param_init(parser) ((parser)->param_length = 0)
+#define param_chop(parser) \
+ ((parser)->param_length = (parser)->param_length - 1)
+
+const char *catalog_error_text(error_number)
+ int error_number;
+{
+ static const char *text[] = {
+ "Name expected",
+ "Literal expected",
+ "Missing argument",
+ "Only minimum data characters allowed in a public identifier",
+ "End of file in comment",
+ "End of file in literal",
+ "Nul character is not allowed",
+ "Cannot open `%s': %s",
+ "Error reading `%s': %s",
+ "Error closing `%s': %s"
+ };
+ if (error_number >= 0 && error_number < sizeof(text)/sizeof(text[0]))
+ return text[error_number];
+ else
+ return "(invalid error number)";
+}
+
+
+CATALOG catalog_create(error_handler)
+ CATALOG_ERROR_HANDLER error_handler;
+{
+ int i;
+ struct catalog *p = (struct catalog *)xmalloc(sizeof(struct catalog));
+ p->loaded = 0;
+ p->n_files = 0;
+ p->files = 0;
+ p->error_handler = error_handler;
+ p->blocks = 0;
+ p->block_spare = 0;
+ p->block_ptr = 0;
+ for (i = 0; i < N_TABLES; i++)
+ hash_table_init(p->tables + i);
+ return (CATALOG)p;
+}
+
+VOID catalog_delete(cat)
+ CATALOG cat;
+{
+ int i;
+ struct string_block *block;
+ struct catalog *catalog = (struct catalog *)cat;
+ for (i = 0; i < 4; i++)
+ hash_table_delete(catalog->tables + i);
+ if (catalog->files)
+ free(catalog->files);
+ block = catalog->blocks;
+ while (block) {
+ struct string_block *tem = block;
+ block = block->next;
+ free((UNIV)tem);
+ }
+ catalog->blocks = 0;
+ free((UNIV)catalog);
+}
+
+VOID catalog_load_file(p, filename)
+ CATALOG p;
+ const char *filename;
+{
+ add_catalog_file((struct catalog *)p, filename, strlen(filename));
+}
+
+int catalog_lookup_entity(cat, public_id, name, decl_type, subst_table,
+ system_id, catalog_file)
+ CATALOG cat;
+ const char *public_id;
+ const char *name;
+ enum catalog_decl_type decl_type;
+ const char *subst_table;
+ const char **system_id;
+ const char **catalog_file;
+{
+ struct catalog *catalog = (struct catalog *)cat;
+ const struct hash_table_entry *entry = 0;
+ if (!catalog->loaded)
+ load(catalog);
+ if (public_id)
+ entry = hash_table_lookup(catalog->tables + PUBLIC_ID_MAP, public_id);
+ if (name
+ && decl_type >= 0
+ && decl_type < N_DECL_TYPE
+ && (!entry || entry->file_index > 0)) {
+ const struct hash_table_entry *entity_entry = 0;
+ if (!subst_table)
+ entity_entry = hash_table_lookup(catalog->tables + decl_type, name);
+ else
+ entity_entry = hash_table_lookup_subst(catalog->tables + decl_type,
+ subst_table, name);
+ if (!entry
+ || (entity_entry
+ && entity_entry->file_index < entry->file_index))
+ entry = entity_entry;
+ }
+ if (!entry)
+ return 0;
+ *system_id = entry->system_id;
+ *catalog_file = catalog->files[entry->file_index];
+ return 1;
+}
+
+static
+VOID add_catalog_file(cat, filename, length)
+ struct catalog *cat;
+ const char *filename;
+ SIZE_T length;
+{
+ char *s;
+ if (!cat->files)
+ cat->files = (char **)xmalloc(sizeof(char *));
+ else
+ cat->files
+ = (char **)xrealloc(cat->files, (cat->n_files + 1)*sizeof(char *));
+ s = alloc_bytes(cat, length + 1);
+ memcpy(s, filename, length);
+ s[length] = '\0';
+ cat->files[cat->n_files] = s;
+ cat->n_files += 1;
+}
+
+static
+VOID load(cat)
+ struct catalog *cat;
+{
+ int i;
+ const char *p;
+ struct parser parser;
+ const char *env_var;
+ int optional_file_index = cat->n_files;
+
+ cat->loaded = 1;
+ parser.param = 0;
+ parser.param_alloc = 0;
+ parser.cat = cat;
+ for (i = 0; i < 256; i++)
+ parser.minimum_data[i] = 0;
+ for (p = MINIMUM_DATA_CHARS; *p; p++)
+ parser.minimum_data[(unsigned char)*p] = 1;
+ env_var = getenv(CATALOG_FILES_ENV_VAR);
+ if (!env_var || *env_var == '\0')
+ env_var = DEFAULT_CATALOG_FILES;
+ for (;;) {
+ for (p = env_var; *p && *p != PATH_FILE_SEP; p++)
+ ;
+ if (p > env_var)
+ add_catalog_file(cat, env_var, p - env_var);
+ if (!*p)
+ break;
+ env_var = p + 1;
+ }
+ for (i = 0; i < cat->n_files; i++) {
+ parser.filename = cat->files[i];
+ parser.newline_count = 0;
+ parser.fp = fopen(cat->files[i], "r");
+ if (!parser.fp) {
+ if (i < optional_file_index)
+ error(&parser, E_CANNOT_OPEN);
+ }
+ else {
+ parser.file_index = i;
+ parse_file(&parser);
+ errno = 0;
+ if (fclose(parser.fp) < 0)
+ error(&parser, E_FCLOSE);
+ }
+ }
+ if (parser.param)
+ free(parser.param);
+}
+
+static
+VOID parse_file(parser)
+ struct parser *parser;
+{
+ int skipping = 0;
+ for (;;) {
+ PARAM_TYPE type = parse_param(parser, NORMAL_LITERAL);
+ if (type == NAME_PARAM) {
+ if (param_equal(parser, "PUBLIC"))
+ parse_public(parser);
+ else if (param_equal(parser, "ENTITY"))
+ parse_name_map(parser, CATALOG_ENTITY_DECL);
+ else if (param_equal(parser, "DOCTYPE"))
+ parse_name_map(parser, CATALOG_DOCTYPE_DECL);
+ else if (param_equal(parser, "LINKTYPE"))
+ parse_name_map(parser, CATALOG_LINKTYPE_DECL);
+ else
+ skipping = 1;
+ }
+ else if (type == EOF_PARAM)
+ break;
+ else if (!skipping) {
+ skipping = 1;
+ error(parser, E_NAME_EXPECTED);
+ }
+ }
+}
+
+static
+VOID parse_public(parser)
+ struct parser *parser;
+{
+ const char *public_id;
+
+ if (parse_param(parser, MINIMUM_LITERAL) != LITERAL_PARAM)
+ error(parser, E_LITERAL_EXPECTED);
+ public_id = param_save(parser);
+ if (!parse_arg(parser))
+ return;
+ hash_table_add(parser->cat->tables + PUBLIC_ID_MAP,
+ public_id, param_save(parser), parser->file_index);
+}
+
+static
+VOID parse_name_map(parser, decl_type)
+ struct parser *parser;
+ int decl_type;
+{
+ const char *name;
+
+ if (!parse_arg(parser))
+ return;
+ name = param_save(parser);
+ if (!parse_arg(parser))
+ return;
+ hash_table_add(parser->cat->tables + decl_type,
+ name, param_save(parser), parser->file_index);
+}
+
+static
+int parse_arg(parser)
+ struct parser *parser;
+{
+ PARAM_TYPE parm = parse_param(parser, NORMAL_LITERAL);
+ if (parm != NAME_PARAM && parm != LITERAL_PARAM) {
+ error(parser, E_ARG_EXPECTED);
+ return 0;
+ }
+ return 1;
+}
+
+static
+PARAM_TYPE parse_param(parser, lit_type)
+ struct parser *parser;
+ enum literal_type lit_type;
+{
+ for (;;) {
+ int c = getc(parser->fp);
+ switch (c) {
+ case EOF:
+ if (ferror(parser->fp))
+ error(parser, E_GETC);
+ return EOF_PARAM;
+ case '"':
+ case '\'':
+ return parse_literal(parser, c, lit_type);
+ case '\n':
+ parser->newline_count += 1;
+ break;
+ case '\t':
+ case ' ':
+ break;
+ case '\0':
+ error(parser, E_NUL_CHAR);
+ break;
+ case '-':
+ c = getc(parser->fp);
+ if (c == '-') {
+ skip_comment(parser);
+ break;
+ }
+ ungetc(c, parser->fp);
+ c = '-';
+ /* fall through */
+ default:
+ return parse_name(parser, c);
+ }
+ }
+}
+
+static
+VOID skip_comment(parser)
+ struct parser *parser;
+{
+ FILE *fp = parser->fp;
+ for (;;) {
+ int c = getc(fp);
+ if (c == '-') {
+ c = getc(fp);
+ if (c == '-')
+ return;
+ }
+ if (c == EOF) {
+ if (ferror(fp))
+ error(parser, E_GETC);
+ error(parser, E_EOF_COMMENT);
+ return;
+ }
+ if (c == '\n')
+ parser->newline_count += 1;
+ }
+}
+
+static
+PARAM_TYPE parse_literal(parser, lit, lit_type)
+ struct parser *parser;
+ int lit;
+ enum literal_type lit_type;
+{
+ enum { no, yes_begin, yes_middle } skipping = yes_begin;
+ FILE *fp = parser->fp;
+ param_init(parser);
+ for (;;) {
+ int c = getc(fp);
+ if (c == lit)
+ break;
+ switch (c) {
+ case '\0':
+ error(parser, E_NUL_CHAR);
+ break;
+ case EOF:
+ if (ferror(fp))
+ error(parser, E_GETC);
+ error(parser, E_EOF_LITERAL);
+ return LITERAL_PARAM;
+ case '\n':
+ parser->newline_count += 1;
+ /* fall through */
+ case ' ':
+ if (lit_type == MINIMUM_LITERAL) {
+ if (skipping == no) {
+ param_char(parser, ' ');
+ skipping = yes_middle;
+ }
+ }
+ else
+ param_char(parser, c);
+ break;
+ default:
+ if (lit_type == MINIMUM_LITERAL) {
+ if (!parser->minimum_data[c])
+ error(parser, E_MINIMUM_DATA);
+ else {
+ skipping = no;
+ param_char(parser, c);
+ }
+ }
+ else
+ param_char(parser, c);
+ break;
+ }
+ }
+ if (skipping == yes_middle)
+ param_chop(parser);
+ return LITERAL_PARAM;
+}
+
+static
+PARAM_TYPE parse_name(parser, first_char)
+ struct parser *parser;
+ int first_char;
+{
+ FILE *fp = parser->fp;
+ param_init(parser);
+ param_char(parser, first_char);
+ for (;;) {
+ int c = getc(fp);
+ switch (c) {
+ case '\0':
+ error(parser, E_NUL_CHAR);
+ break;
+ case EOF:
+ if (ferror(fp))
+ error(parser, E_GETC);
+ goto done;
+ case '\n':
+ parser->newline_count += 1;
+ goto done;
+ case ' ':
+ case '\t':
+ goto done;
+ case '"':
+ case '\'':
+ ungetc(c, fp);
+ goto done;
+ default:
+ param_char(parser, c);
+ }
+ }
+ done:
+ return NAME_PARAM;
+}
+
+static
+VOID param_grow(parser)
+ struct parser *parser;
+{
+ if (parser->param_alloc == 0) {
+ parser->param_alloc = 256;
+ parser->param = xmalloc(parser->param_alloc);
+ }
+ else {
+ parser->param_alloc *= 2;
+ parser->param = xrealloc(parser->param, parser->param_alloc);
+ }
+}
+
+static
+const char *param_save(parser)
+ struct parser *parser;
+{
+ char *s = alloc_bytes(parser->cat, parser->param_length + 1);
+ memcpy(s, parser->param, parser->param_length);
+ s[parser->param_length] = '\0';
+ return s;
+}
+
+static
+char *alloc_bytes(catalog, n)
+ struct catalog *catalog;
+ SIZE_T n;
+{
+ char *tem;
+ if (n > catalog->block_spare) {
+ struct string_block *block;
+ SIZE_T block_size = n > BLOCK_SIZE ? n : BLOCK_SIZE;
+ block
+ = (struct string_block *)xmalloc(sizeof(struct string_block)
+ + block_size);
+ block->next = catalog->blocks;
+ catalog->blocks = block;
+ catalog->block_ptr = (char *)(block + 1);
+ catalog->block_spare = block_size;
+ }
+ tem = catalog->block_ptr;
+ catalog->block_ptr += n;
+ catalog->block_spare -= n;
+ return tem;
+}
+
+
+/* Return 1 if the current parameter is equal to key. */
+
+static
+int param_equal(parser, key)
+ struct parser *parser;
+ const char *key;
+{
+ const char *param = parser->param;
+ SIZE_T param_length = parser->param_length;
+ for (; param_length > 0; param++, param_length--, key++) {
+ unsigned char c;
+ if (*key == '\0')
+ return 0;
+ c = *param;
+ if (islower(c))
+ c = toupper(c);
+ if (c != (unsigned char)*key)
+ return 0;
+ }
+ return *key == '\0';
+}
+
+/* Return 0 if it was a duplicate. */
+
+static
+int hash_table_add(table, s, system_id, file_index)
+ struct hash_table *table;
+ const char *s;
+ const char *system_id;
+ int file_index;
+{
+ SIZE_T i;
+ struct hash_table_entry *p;
+
+ if (table->size > 0) {
+ i = hash_table_start_index(table, s);
+ while (table->v[i] != 0) {
+ if (strcmp(table->v[i]->key, s) == 0)
+ return 0;
+ if (i == 0)
+ i = table->size;
+ i--;
+ }
+ }
+ if (table->used >= table->used_limit) {
+ SIZE_T j;
+ struct hash_table_entry **old_table = table->v;
+ SIZE_T old_size = table->size;
+ if (old_size == 0) {
+ table->size = HASH_TABLE_INITIAL_SIZE;
+ table->used_limit = table->size/2;
+ }
+ else {
+ if (old_size > HASH_TABLE_MAX_SIZE/2) {
+ if (old_size == HASH_TABLE_MAX_SIZE)
+ return 0; /* FIXME: give an error? */
+ table->size = HASH_TABLE_MAX_SIZE;
+ table->used_limit = HASH_TABLE_MAX_SIZE - 1;
+ }
+ else {
+ table->size = (old_size << 1);
+ table->used_limit = table->size/2;
+ }
+ }
+ table->v
+ = (struct hash_table_entry **)xmalloc(sizeof(struct hash_table_entry *)
+ * table->size);
+ for (j = 0; j < table->size; j++)
+ table->v[j] = 0;
+ for (j = 0; j < old_size; j++)
+ if (old_table[j]) {
+ SIZE_T k = hash_table_start_index(table, old_table[j]->key);
+ while (table->v[k] != 0) {
+ if (k == 0)
+ k = table->size;
+ k--;
+ }
+ table->v[k] = old_table[j];
+ }
+ if (old_table)
+ free((UNIV)old_table);
+ i = hash_table_start_index(table, s);
+ while (table->v[i] != 0) {
+ if (i == 0)
+ i = table->size;
+ i--;
+ }
+ }
+ p = (struct hash_table_entry *)xmalloc(sizeof(struct hash_table_entry));
+ p->key = s;
+ p->system_id = system_id;
+ p->file_index = file_index;
+ table->v[i] = p;
+ table->used += 1;
+ return 1;
+}
+
+static
+struct hash_table_entry *hash_table_lookup(table, s)
+ struct hash_table *table;
+ const char *s;
+{
+ if (table->size > 0) {
+ SIZE_T i;
+ i = hash_table_start_index(table, s);
+ while (table->v[i] != 0) {
+ if (strcmp(table->v[i]->key, s) == 0)
+ return table->v[i];
+ if (i == 0)
+ i = table->size;
+ i--;
+ }
+ }
+ return 0;
+}
+
+static
+struct hash_table_entry *hash_table_lookup_subst(table, subst_table, s)
+ struct hash_table *table;
+ const char *subst_table;
+ const char *s;
+{
+ SIZE_T i;
+ for (i = 0; i < table->size; i++) {
+ struct hash_table_entry *p = table->v[i];
+ if (p && subst_equal(subst_table, s, p->key))
+ return p;
+ }
+ return 0;
+}
+
+static
+VOID hash_table_init(p)
+ struct hash_table *p;
+{
+ p->v = 0;
+ p->size = 0;
+ p->used = 0;
+ p->used_limit = 0;
+}
+
+static
+VOID hash_table_delete(p)
+ struct hash_table *p;
+{
+ if (p->v) {
+ SIZE_T i;
+ for (i = 0; i < p->size; i++)
+ if (p->v[i])
+ free(p->v[i]);
+ free(p->v);
+ }
+}
+
+static
+SIZE_T hash_table_start_index(p, s)
+ struct hash_table *p;
+ const char *s;
+{
+ unsigned long h = 0;
+ while (*s)
+ h = (h << 5) + h + (unsigned char)*s++;
+ return (h & (p->size - 1));
+}
+
+/* s1 has already been substituted; s2 has not */
+
+static
+int subst_equal(subst_table, s1, s2)
+ const char *subst_table;
+ const char *s1;
+ const char *s2;
+{
+ for (; *s1 == subst_table[(unsigned char)*s2]; s1++, s2++)
+ if (*s1 == '\0')
+ return 1;
+ return 0;
+}
+
+static
+VOID error(parser, err)
+ struct parser *parser;
+ enum catalog_error err;
+{
+ (*parser->cat->error_handler)(parser->filename,
+ parser->newline_count + 1,
+ err,
+ (err >= FIRST_SYSTEM_ERROR
+ ? CATALOG_SYSTEM_ERROR
+ : 0),
+ (err >= FIRST_SYSTEM_ERROR
+ ? errno
+ : 0));
+}
+
+#ifdef MAIN
+
+static const char *program_name;
+
+#include "getopt.h"
+
+static VOID usage P((void));
+static VOID out_of_memory P((void));
+static VOID handle_catalog_error P((const char *filename,
+ unsigned long lineno,
+ int error_number,
+ unsigned flags,
+ int sys_errno));
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int entity_flag = 0;
+ enum catalog_decl_type entity_type = CATALOG_NO_DECL;
+ char *public_id = 0;
+ char *name = 0;
+ int exit_status;
+ int opt;
+ CATALOG catalog;
+ int i;
+ const char *file;
+ const char *system_id;
+
+ program_name = argv[0];
+
+ while ((opt = getopt(argc, argv, "edl")) != -1)
+ switch (opt) {
+ case 'e':
+ entity_flag = 1;
+ entity_type = CATALOG_ENTITY_DECL;
+ break;
+ case 'd':
+ entity_flag = 1;
+ entity_type = CATALOG_DOCTYPE_DECL;
+ break;
+ case 'l':
+ entity_flag = 1;
+ entity_type = CATALOG_LINKTYPE_DECL;
+ break;
+ case '?':
+ usage();
+ }
+ if (argc - optind < 2)
+ usage();
+ if (entity_flag)
+ name = argv[optind];
+ else
+ public_id = argv[optind];
+
+ catalog = catalog_create(handle_catalog_error);
+ for (i = optind + 1; i < argc; i++)
+ catalog_load_file(catalog, argv[i]);
+ if (catalog_lookup_entity(catalog, public_id, name, entity_type, (char *)0,
+ &system_id, &file)) {
+ exit_status = 0;
+ fprintf(stderr, "%s (%s)\n", system_id, file);
+ }
+ else {
+ fprintf(stderr, "not found\n");
+ exit_status = 1;
+ }
+ catalog_delete(catalog);
+ return exit_status;
+}
+
+static
+VOID usage()
+{
+ fprintf(stderr, "usage: %s [-e] [-d] [-l] id file ...\n",
+ program_name);
+ exit(1);
+}
+
+static
+VOID handle_catalog_error(filename, lineno, error_number, flags, sys_errno)
+ const char *filename;
+ unsigned long lineno;
+ int error_number;
+ unsigned flags;
+ int sys_errno;
+{
+ fprintf(stderr, "%s:", program_name);
+ if (flags & CATALOG_SYSTEM_ERROR) {
+ putc(' ', stderr);
+ fprintf(stderr, catalog_error_text(error_number), filename);
+ putc('\n', stderr);
+ }
+ else
+ fprintf(stderr, "%s:%lu: %s\n", filename, lineno,
+ catalog_error_text(error_number));
+ fflush(stderr);
+}
+
+UNIV xmalloc(n)
+ SIZE_T n;
+{
+ UNIV p = malloc(n);
+ if (!p)
+ out_of_memory();
+ return p;
+}
+
+UNIV xrealloc(p, n)
+ UNIV p;
+ SIZE_T n;
+{
+ p = realloc(p, n);
+ if (!p)
+ out_of_memory();
+ return p;
+}
+
+static
+VOID out_of_memory()
+{
+ fprintf(stderr, "%s: out of memory\n", program_name);
+ exit(1);
+}
+
+#endif /* MAIN */
diff --git a/usr.bin/sgmls/sgmls/catalog.h b/usr.bin/sgmls/sgmls/catalog.h
new file mode 100644
index 0000000..b9509a5
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/catalog.h
@@ -0,0 +1,45 @@
+#ifndef CATALOG_H
+#define CATALOG_H 1
+
+enum catalog_decl_type {
+ CATALOG_NO_DECL = -1,
+ CATALOG_ENTITY_DECL,
+ CATALOG_DOCTYPE_DECL,
+ CATALOG_LINKTYPE_DECL
+};
+
+#define CATALOG_SYSTEM_ERROR 1
+
+#ifdef __STDC__
+
+typedef void *CATALOG;
+typedef void (*CATALOG_ERROR_HANDLER)(const char *filename,
+ unsigned long lineno,
+ int error_number,
+ unsigned flags,
+ int sys_errno);
+CATALOG catalog_create(CATALOG_ERROR_HANDLER);
+void catalog_load_file(CATALOG, const char *);
+void catalog_delete(CATALOG);
+int catalog_lookup_entity(CATALOG,
+ const char *public_id,
+ const char *name,
+ enum catalog_decl_type,
+ const char *subst_table,
+ const char **system_id,
+ const char **catalog_file);
+const char *catalog_error_text(int error_number);
+
+#else /* not __STDC__ */
+
+typedef char *CATALOG;
+typedef void (*CATALOG_ERROR_HANDLER)();
+CATALOG catalog_create();
+void catalog_load_file();
+void catalog_delete();
+int catalog_lookup_entity();
+char *catalog_error_text();
+
+#endif /* not __STDC__ */
+
+#endif /* not CATALOG_H */
diff --git a/usr.bin/sgmls/sgmls/config.h b/usr.bin/sgmls/sgmls/config.h
new file mode 100644
index 0000000..a7fa92c
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/config.h
@@ -0,0 +1,158 @@
+/* unix.cfg: Configuration file for sgmls on Unix. */
+
+/* A list of filename templates to use for searching for external entities.
+The filenames are separated by the character specified in PATH_FILE_SEP.
+See sgmls.man for details. */
+#define DEFAULT_PATH "/usr/share/sgml/%O/%C/%T:%N.%X:%N.%D"
+/* The character that separates the filenames templates. */
+#define PATH_FILE_SEP ':'
+/* The character that separates filenames in a system identifier.
+Usually the same as PATH_FILE_SEP. */
+#define SYSID_FILE_SEP ':'
+/* The environment variable that contains the list of filename templates. */
+#define PATH_ENV_VAR "SGML_PATH"
+/* A macro that returns non-zero if the filename is relative to the
+ current directory. */
+#define FILE_IS_RELATIVE(p) ((p)[0] != '/')
+/* A string containing the characters that can separate the directory
+ part of a filename from the basename. */
+#define DIR_BASE_SEP "/"
+/* The environment variable that contains the list of catalog entry files.
+ Filenames are separated by PATH_FILE_SEP. */
+#define CATALOG_FILES_ENV_VAR "SGML_CATALOG_FILES"
+/* Default list of catalog entry files. */
+#define DEFAULT_CATALOG_FILES "CATALOG:/usr/share/sgml/CATALOG"
+
+/* MIN_DAT_SUBS_FROM and MIN_DATS_SUBS_TO tell sgmls how to transform a name
+or system identifier into a legal filename. A character in
+MIN_DAT_SUBS_FROM will be transformed into the character in the
+corresponding position in MIN_DAT_SUBS_TO. If there is no such
+position, then the character is removed. */
+/* This says that spaces should be transformed to underscores, and
+slashes to percents. */
+#define MIN_DAT_SUBS_FROM " /"
+#define MIN_DAT_SUBS_TO "_%"
+
+/* Define this to allow tracing. */
+/* #define TRACE 1 */
+
+/* Define this you want support for subdocuments. This is implemented
+using features that are not part of Standard C, so you might not want
+to define it if you are porting to a new system. Otherwise I suggest
+you leave it defined. */
+#define SUPPORT_SUBDOC 1
+
+/* Define HAVE_EXTENDED_PRINTF if your *printf functions supports
+X/Open extensions; if they do, then, for example,
+
+ printf("%2$s%1$s", "bar", "foo")
+
+should print `foobar'. */
+
+/* #define HAVE_EXTENDED_PRINTF 1 */
+
+/* Define HAVE_CAT if your system provides the X/Open message
+catalogue functions catopen() and catgets(), and you want to use them.
+An implementations of these functions is included and will be used if
+you don't define this. On SunOS 4.1.1, if you do define this you
+should set CC=/usr/xpg2bin/cc in the makefile. */
+
+#define HAVE_CAT 1
+
+#ifdef __STDC__
+/* Define this if your compiler supports prototypes. */
+#define USE_PROTOTYPES 1
+#endif
+
+/* Can't use <stdarg.h> without prototypes. */
+#ifndef USE_PROTOTYPES
+#define VARARGS 1
+#endif
+
+/* If your compiler defines __STDC__ but doesn't provide <stdarg.h>,
+you must define VARARGS yourself here. */
+/* #define VARARGS 1 */
+
+/* Define this if you do not have strerror(). */
+/* #define STRERROR_MISSING 1 */
+
+/* Define this unless the character testing functions in ctype.h
+are defined for all values representable as an unsigned char. You do
+not need to define this if your system is ANSI C conformant. You
+should define for old Unix systems. */
+/* #define USE_ISASCII 1 */
+
+/* Define this if your system provides the BSD style string operations
+rather than ANSI C ones (eg bcopy() rather than memcpy(), and index()
+rather than strchr()). */
+/* #define BSD_STRINGS 1 */
+
+/* Define this if you have getopt(). */
+#define HAVE_GETOPT 1
+
+/* Define this if you have access(). */
+#define HAVE_ACCESS 1
+
+/* Define this if you have <unistd.h>. */
+#define HAVE_UNISTD_H 1
+
+/* Define this if you have <sys/stat.h>. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define this if you have waitpid(). */
+#define HAVE_WAITPID 1
+
+/* Define this if your system is POSIX.1 (ISO 9945-1:1990) compliant. */
+#define POSIX 1
+
+/* Define this if you have the vfork() system call. */
+#define HAVE_VFORK 1
+
+/* Define this if you have <vfork.h>. */
+/* #define HAVE_VFORK_H 1 */
+
+/* Define this if you don't have <stdlib.h> */
+/* #define STDLIB_H_MISSING 1 */
+
+/* Define this if you don't have <stddef.h> */
+/* #define STDDEF_H_MISSING 1 */
+
+/* Define this if you don't have <limits.h> */
+/* #define LIMITS_H_MISSING 1 */
+
+/* Define this if you don't have remove(); unlink() will be used instead. */
+/* #define REMOVE_MISSING 1 */
+
+/* Define this if you don't have raise(); kill() will be used instead. */
+/* #define RAISE_MISSING 1 */
+
+/* Define this if you don't have fsetpos() and fgetpos(). */
+/* #define FPOS_MISSING 1 */
+
+/* Universal pointer type. */
+/* If your compiler doesn't fully support void *, change `void' to `char'. */
+typedef void *UNIV;
+
+/* If your compiler doesn't support void as a function return type,
+change `void' to `int'. */
+typedef void VOID;
+
+/* If you don't have an ANSI C conformant <limits.h>, define
+CHAR_SIGNED as 1 or 0 according to whether the `char' type is signed.
+The <limits.h> on some versions of System Release V 3.2 is not ANSI C
+conformant: the value of CHAR_MIN is 0 even though the `char' type is
+signed. */
+
+/* #define CHAR_SIGNED 1 */
+/* #define CHAR_SIGNED 0 */
+#ifndef CHAR_SIGNED
+#include <limits.h>
+#if CHAR_MIN < 0
+#define CHAR_SIGNED 1
+#else
+#define CHAR_SIGNED 0
+#endif
+#endif /* not CHAR_SIGNED */
+
+/* Assume the system character set is ISO Latin-1. */
+#include "latin1.h"
diff --git a/usr.bin/sgmls/sgmls/context.c b/usr.bin/sgmls/sgmls/context.c
new file mode 100644
index 0000000..10a123a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/context.c
@@ -0,0 +1,451 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+#include "context.h"
+
+#define GI (tags[ts].tetd->etdgi+1) /* GI of current element. */
+#define NEWGI (newetd->etdgi+1) /* GI of new tag. */
+#define STATUS (*statuspt) /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
+#define PEX (-1) /* GI is a plus exception and not a minus. */
+
+#define ANYHIT(h) (grplongs == 1 ? ((h)[0] != 0) : anyhit(h))
+#define HITSET(h, n) (h[(unsigned)(n-1)>>LONGPOW] \
+ |= (1L<<((n-1)&(LONGBITS-1))))
+#define HITON(h, n) (h[(unsigned)(n-1)>>LONGPOW] & (1L<<((n-1)&(LONGBITS-1))))
+
+#define HITOFF(h, n) (!(HITON(h, n)))
+
+#define TOKENHIT HITON(H,T)
+
+static
+VOID copypos(to, from)
+struct mpos *to, *from;
+{
+ int i;
+ for (i = 0; i <= (int)from[0].t; i++) {
+ to[i].g = from[i].g;
+ to[i].t = from[i].t;
+ memcpy(to[i].h, from[i].h, grplongs*sizeof(unsigned long));
+ }
+}
+
+/* CONTEXT: Determine whether a GI is valid in the present structural context.
+ Returns RCHIT if valid, RCEND if element has ended, RCREQ if a
+ different element is required, and RCMISS if it is totally invalid.
+ On entry, pos points to the model token to be tested against the GI.
+ TO DO: Save allowed GIs for an error message on an RCMISS.
+ Support a "query" mode (what is allowed now?) by working
+ with a copy of pos.
+*/
+int context(gi, mod, pos, statuspt, mexts)
+struct etd *gi; /* ETD of new GI. */
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+UNCH *statuspt; /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
+int mexts; /* >0=stack level of minus grp; -1=plus; 0=none.*/
+{
+ UNCH toccsv, gtypesv; /* Save token's TOCC and GTYPE in case grp ends.*/
+
+ if (mexts != 0) {
+ if (mexts == -1 && STATUS == RCEND)
+ return RCPEX;
+ copypos(savedpos, pos);
+ }
+ Tstart = T; /* Save starting token for AND group testing. */
+ while (STATUS!=RCMISS && STATUS!=RCEND) {
+ TRACEGI("CONTEXT", gi, mod, pos);
+ while (TTYPE==TTOR || TTYPE==TTSEQ || TTYPE==TTAND) {
+ pos[P+1].g = M++; pos[++P].t = 1; HITCLEAR(H);
+ Tstart = T; /* Save starting token for AND group testing. */
+ TRACEGI("OPENGRP", gi, mod, pos);
+ }
+ STATUS = (UNCH)tokenreq(gi, mod, pos);
+ TRACEGI("STATUS", gi, mod, pos);
+ if (gi==TOKEN.tu.thetd) { /* Hit in model. */
+ STATUS = (UNCH)RCHIT;
+ gtypesv = GTYPE; toccsv = TOCC;
+ newtoken(mod, pos, statuspt);
+ if (mexts <= 0)
+ return RCHIT;
+ else if (gtypesv==TTOR || BITON(toccsv, TOPT)) {
+ /* restore position */
+ copypos(pos, savedpos);
+ return RCMEX;
+ }
+ else
+ return RCHITMEX;
+ }
+ if (STATUS==RCREQ) {
+ if (mexts == -1)
+ break;
+ STATUS = RCHIT;
+ nextetd = TOKEN.tu.thetd;
+ newtoken(mod, pos, statuspt);
+ return(RCREQ);
+ }
+ /* else if (STATUS==RCNREQ) */
+ if (mexts>0) return(RCMEX);
+ newtoken(mod, pos, statuspt);
+ }
+ if (mexts == -1) {
+ copypos(pos, savedpos);
+ return STATUS = RCPEX;
+ }
+ return((int)STATUS);
+}
+/* ECONTEXT: Determine whether the current element can be ended, or whether
+ non-optional tokens remain at the current level or higher.
+ Returns 1 if element can be ended, or 0 if tokens remain.
+ On entry, STATUS==RCEND if there are no tokens left; if not,
+ pos points to the next model token to be tested.
+ TO DO: Support a "query" mode (what is required now?) by working
+ with a copy of pos.
+*/
+int econtext(mod, pos, statuspt)
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+UNCH *statuspt; /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
+{
+ unsigned next; /* Position in AND group of next testable token.*/
+
+ Tstart = T;
+ TRACEEND("ECONT", mod, pos, 0, 0);
+ if (P<=1) {nextetd = 0; return(TOKENHIT || BITON(TOCC, TOPT));}
+ nextetd = TTYPE == TTETD ? TOKEN.tu.thetd : 0;
+ while (STATUS!=RCMISS && STATUS!=RCEND) {
+ STATUS = (UNCH)testend(mod, pos, 0, 0);
+ TRACEEND("ECONTEND", mod, pos, 0, 0);
+ nextetd = P<=1 || TTYPE != TTETD ? 0 : TOKEN.tu.thetd;
+ if (STATUS==RCEND) return(1);
+ if (P<=1) return(TOKENHIT || BITON(TOCC, TOPT));
+ if (STATUS==RCMISS) {
+ if (BITON(TOCC, TOPT)) nextetd = 0;
+ return(0);
+ }
+ if (!tokenopt(mod, pos)) return(0);
+
+ STATUS = RCNREQ;
+ if (GTYPE!=TTAND) ++T; /* T!=GNUM or group would have ended. */
+ else T = (UNCH)(((next = (UNS)offbit(H, (int)T, GNUM))!=0) ?
+ next : offbit(H, 0, GNUM));
+
+ M = G + grpsz(&GHDR, (int)T-1) + 1;
+ TRACEEND("ECONTNEW", mod, pos, 0, 0);
+ }
+ if (STATUS==RCMISS) {
+ if (BITON(TOCC, TOPT)) nextetd = 0;
+ return(0);
+ }
+ return(1); /* STATUS==RCEND */
+}
+/* NEWTOKEN: Find the next token to test. Set STATUS to indicate results:
+ RCEND if element has ended (no more tokens to test);
+ RCREQ if required new token was found;
+ RCNREQ if non-required new token was found;
+ RCHIT if a hit token was repeated (now non-required);
+ and RCMISS if a new token can't be found because current token
+ (which was not hit) was neither unconditionally required nor
+ optional.
+*/
+VOID newtoken(mod, pos, statuspt)
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+UNCH *statuspt; /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
+{
+ unsigned nextand = 0; /* Position in AND group of next testable token.*/
+ int currhit = (STATUS==RCHIT); /* 1=current GI hit; 0=not. */
+
+ /* If the GI was a hit, turn on the hit bit and set the status to
+ assume that the token to be tested against the next GI will
+ be non-required. If the current token is repeatable, exit so
+ it will stand as the next token to test.
+ */
+ if (STATUS==RCHIT) {
+ HITSET(H, T);
+ STATUS = RCNREQ;
+ if (BITON(TOCC, TREP)) return;
+ }
+ /* At this point, we must determine the next token to test:
+ either against the next GI, if this one was a hit, or
+ against the same GI if conditions permit a retry.
+ To find the next token, we must first end the current group,
+ if possible, and any we can that contain it.
+ If the outermost group was a hit and is repeatable, or
+ if the element has ended, we exit now.
+ If it hasn't ended, or was optional and ended with a miss,
+ we can retry the GI against the next token.
+ */
+ if ((STATUS = (UNCH)testend(mod, pos, 1, 1))!=RCNREQ) return;
+
+ /* At this point, the "current token" is either the original one,
+ or the token for the highest level unhit group that it ended.
+ We will retry a missed GI, by testing it against the next
+ token, if the current token:
+ 1. Is optional;
+ 2. Was hit (i.e., because it is repeatable and was hit by a
+ previous GI or because it is a hit group that just ended);
+ 3. Is in an AND or OR group and is not the last testable token.
+
+ It will be the next sequential one (unhit one, in an AND group);
+ if there are none left, use the first unhit token in the group.
+ In either case, set M to correspond to the new T.
+ */
+ retest:
+ TRACEEND("RETEST", mod, pos, (int)nextand, 1);
+ if (GTYPE==TTAND) {
+ nextand = offbit(H, (int)T, GNUM);
+ if (!nextand)
+ nextand = offbit(H, 0, GNUM);
+ }
+ if ( BITON(TOCC, TOPT)
+ || TOKENHIT
+ || GTYPE==TTOR /* T!=GNUM or group would have ended. */
+ || nextand ) {
+ if (GTYPE!=TTAND) ++T; /* T!=GNUM or group would have ended. */
+ else T = nextand;
+ M = G + grpsz(&GHDR, (int)T-1) + 1;
+ if (GTYPE==TTAND) {
+ /* If AND group wrapped, it can end if all non-optionals were
+ hit. */
+ if (T==Tstart && !currhit) {
+ UNCH Psave = P;
+ int rc = testend(mod, pos, 0, 1);
+ if (Psave!=P) {if ((STATUS = (UNCH)rc)==RCNREQ) goto retest;}
+ else STATUS = RCMISS;
+ }
+
+ /* We only test unhit tokens, so we must use an unhit token
+ as Tstart (which is used to detect when the AND group has
+ wrapped). */
+ else if (HITON(H,Tstart)) Tstart = T;
+ }
+ }
+ else STATUS = RCMISS;
+ TRACEEND("NEWTOKEN", mod, pos, (int)nextand, 1);
+}
+/* TESTEND: End the current group, if possible, and any that it is nested in.
+ The current token will either be a group header, or some token
+ that could not end its group. Return 1 if the (possibly new)
+ current token is repeatable; 0 if it is not.
+*/
+int testend(mod, pos, andoptsw, newtknsw)
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+int andoptsw; /* 1=test optional AND members; 0=ignore. */
+int newtknsw; /* 1=new token test; 0=end element test. */
+{
+ int rc = 0; /* Return code: RCNREQ RCHIT RCMISS RCEND */
+
+ while (!rc) {
+ TRACEEND("TRACEEND", mod, pos, rc, andoptsw);
+ /* TESTMISS:
+ If we've hit no tokens yet in the current group, and
+ the current token is the last unhit one in the group we can test,
+ we will end the group (it may never really have started!)
+ because we might be able to try the token that follows it.
+ In any group, a token is the last testable unhit token if it
+ is the last sequential one, as the GI was already tested against
+ the preceding unhit tokens. In addition,
+ in a SEQ group, it is the last testable unhit token if it isn't
+ optional, because we can't skip past it to the following ones.
+ If we end the group, before popping the level, set M to G, as this
+ level`s group header will be the next level's current token.
+ */
+ if (!ANYHIT(H) && (T==GNUM
+ || (GTYPE==TTSEQ && BITOFF(TOCC, TOPT)))) {
+ M = G; --P;
+ if (P<=1) {
+ if (BITON(TOCC, TOPT) || TOKENHIT) rc = RCEND;
+ else rc = RCMISS;
+ }
+ continue;
+ }
+ /* TESTHIT:
+ See if we've hit all the non-optional tokens in the group.
+ If so, pop to the previous level and set the group's hit bit.
+ If we were called from NEWTOKEN we are trying to find the token
+ to test against the next start-tag, so if the group is repeatable,
+ process it again. (If not, we were called from ECONTEXT and
+ are testing whether the element can be ended.)
+ Otherwise, if we are at the first level, the element is over.
+ */
+ if ((GTYPE==TTOR && TOKENHIT)
+ || (GTYPE==TTSEQ && T==(UNCH)GNUM
+ && (TOKENHIT || BITON(TOCC, TOPT)))
+ || (GTYPE==TTAND && allhit(&GHDR, H, 0, andoptsw))) {
+ M = G;
+ --P;
+ HITSET(H, T);
+ Tstart = T;
+ if (newtknsw && BITON(TOCC, TREP)) rc = RCHIT;
+ else if (P<=1) rc = RCEND;
+ /* If we are looking for a new token to test against the next
+ start-tag, then we need to consider optional and members
+ in this group, even if we didn't need to consider them
+ in the group that we just ended because that group had
+ wrapped. */
+ else if (newtknsw) andoptsw = 1;
+ /* Else loop to test new outer group. */
+ }
+ else rc = RCNREQ; /* No group ended this time, so return. */
+ }
+ TRACEEND("ENDFOUND", mod, pos, rc, andoptsw);
+ return(rc);
+}
+/* TOKENOPT: Return 1 if current token is contextually optional;
+ otherwise, return 0.
+*/
+int tokenopt(mod, pos)
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+{
+ TRACEEND("TOKENOPT", mod, pos, 0, 0);
+ return (BITON(TOCC, TOPT) /* Inherently optional. */
+ || TOKENHIT /* Was hit (handles "plus" suffix case). */
+ || (!ANYHIT(H) && groupopt(mod, pos)));
+ /* In optional group with no hits. */
+}
+/* GROUPOPT: Temporarily makes the current group be the current token so that
+ TOKENOPT() can be applied to it. Returns the value returned
+ by TOKENOPT.
+*/
+int groupopt(mod, pos)
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+{
+ UNCH saveM; /* Save M when testing if group is not required.*/
+ int rc; /* 1=contextually optional; 0=not. */
+
+ if (P==1) return(BITON(GOCC, TOPT) || TOKENHIT);
+ saveM = M; M = G; --P;
+ rc = tokenopt(mod, pos);
+ ++P; G = M; M = saveM;
+ return(rc);
+}
+/* TOKENREQ: Returns RCREQ if the current token is "contextually required".
+ That is, it is not contextually optional and
+ 1) it is a member of a "seq" group that is either required
+ or has at least 1 hit token.
+ 2) it is a member of an "and" group in which all other
+ tokens were hit.
+ Optional tokens are not counted
+ if GI is ETDCDATA, as we are looking for an
+ omitted start-tag. Otherwise, they are counted,
+ as the GI might match one of them.
+ Returns RCNREQ if the current token is "not required".
+*/
+int tokenreq(gi, mod, pos)
+struct etd *gi; /* ETD of new GI. */
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+{
+ TRACEGI("TOKENREQ", gi, mod, pos);
+ return( tokenopt(mod, pos) ? RCNREQ
+ : ( GTYPE==TTSEQ && (ANYHIT(H) || groupreq(gi, mod, pos)==RCREQ)
+#if 0
+ || (GTYPE==TTAND && allhit(&GHDR, H, T, \*gi!=ETDCDATA*\ 1))
+#endif
+ )
+ ? RCREQ : RCNREQ );
+}
+/* GROUPREQ: Temporarily makes the current group be the current token so that
+ TOKENREQ() can be applied to it. Returns the value returned
+ by TOKENREQ.
+*/
+int groupreq(gi, mod, pos)
+struct etd *gi; /* ETD of new GI. */
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+{
+ UNCH saveM; /* Save M when testing if group is not required.*/
+ int rc; /* Return code: RCREQ RCNREQ */
+
+ if (P==1) return(BITOFF(GOCC, TOPT) ? RCREQ : RCNREQ);
+ saveM = M; M = G; --P;
+ rc = tokenreq(gi, mod, pos);
+ ++P; G = M; M = saveM;
+ return(rc);
+}
+/* GRPSZ: Returns the number of tokens spanned by a group in the model (M),
+ from the group's start (G) to a specified index within the group (T).
+ M = 0, plus 1 for each token in the group, plus the size of
+ any subgroups (gotten by calling GRPSZ recursively). On entry,
+ M must be equal to G at the current level.
+*/
+int grpsz(g, t)
+struct thdr *g; /* mod[G]: Ptr to group in the model. */
+int t; /* T: Index of last token in the group. */
+{
+ struct thdr *p = g; /* Ptr to current token in the model. */
+ int m = 0; /* Size of group (including nested groups). */
+ int i = 0; /* Number of group members (loop counter). */
+ UNS type; /* Token type (without TOREP bits). */
+
+ while (++i<=t) {
+ ++p; ++m;
+ type = GET(p->ttype, TTMASK);
+ if (type==TTOR || type==TTSEQ || type==TTAND) {
+ m += grpsz(p, p->tu.tnum);
+ p = g+m;
+ }
+ }
+ return(m);
+}
+/* ALLHIT: Returns 1 if all hit bits for the specified group are turned on,
+ (other than those that correspond to optional tokens if "opt" is
+ 0) and the "but" bit (all bits if "but" bit is zero). Otherwise,
+ returns 0. GRPSZ is used to skip past subgroup tokens.
+*/
+int allhit(p, hits, but, opt)
+struct thdr *p; /* mod[G]: Ptr to group in the model. */
+unsigned long *hits; /* H: Hit bits to be tested. */
+int but; /* Index of bit to ignore; 0=test all. */
+int opt; /* 1=optional tokens must be hit; 0=ignore. */
+{
+ int b = 0; /* Index of bit being tested in hits. */
+ int e = p->tu.tnum; /* Ending index (number of bits to test). */
+ unsigned type; /* Token type (without TOREP bits). */
+
+ while (++p, ++b<=e) {
+ if (HITOFF(hits,b) && (opt || BITOFF(p->ttype,TOPT)) && b!=but)
+ return 0;
+ if ((type = GET(p->ttype,TTMASK))==TTOR || type==TTSEQ || type==TTAND)
+ p += grpsz(p, p->tu.tnum);
+ }
+ return 1;
+}
+/* OFFBIT: Returns the index of the first unset bit after (i.e., not including)
+ the caller's "first" bit. If all bits through the
+ specified last bit are on, it returns 0.
+*/
+int offbit(bits, first, last)
+unsigned long *bits; /* Bits to be tested. */
+int first; /* Index of first bit to be tested in bits. */
+int last; /* Index of last bit to be tested in bits. */
+{
+ while (++first <= last)
+ if (HITOFF(bits, first))
+ return first;
+ return 0;
+}
+
+/* ANYHIT: Return 1 if any bit is set. */
+
+int anyhit(bits)
+unsigned long *bits;
+{
+ int i;
+ for (i = 0; i < grplongs; i++)
+ if (bits[i] != 0)
+ return 1;
+ return 0;
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/context.h b/usr.bin/sgmls/sgmls/context.h
new file mode 100644
index 0000000..01f4383
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/context.h
@@ -0,0 +1,19 @@
+/* context.h */
+
+#define M pos[0].g /* Index of current token in model. */
+#ifdef P
+#undef P
+#endif
+#define P pos[0].t /* Index of current group in pos. */
+#define G pos[P].g /* Index of current group in model. */
+#define T pos[P].t /* Index of current token in its group. */
+#define Tstart pos[P].tstart /* Index of starting token in its group
+ for AND group testing. */
+#define H pos[P].h /* Pointer to hit bits for current group. */
+#define GHDR mod[G] /* Current group header. */
+#define TOKEN mod[M] /* Current token. */
+#define TTYPE (GET(TOKEN.ttype, TTMASK)) /* Token type of current token. */
+#define TOCC (GET(TOKEN.ttype, TOREP)) /* Occurrence for current token. */
+#define GTYPE (GET(GHDR.ttype, TTMASK)) /* Token type of current group. */
+#define GOCC (GET(GHDR.ttype, TOREP)) /* Occurrence for current group. */
+#define GNUM GHDR.tu.tnum /* Number of tokens in current grp. */
diff --git a/usr.bin/sgmls/sgmls/dosproc.c b/usr.bin/sgmls/sgmls/dosproc.c
new file mode 100644
index 0000000..99b526d
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/dosproc.c
@@ -0,0 +1,40 @@
+/* dosproc.c -
+
+ MS-DOS implementation of run_process().
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifdef SUPPORT_SUBDOC
+
+#include "std.h"
+#include "entity.h"
+#include "appl.h"
+
+#include <process.h>
+
+int run_process(argv)
+char **argv;
+{
+ int ret;
+ fflush(stdout);
+ fflush(stderr);
+ ret = spawnvp(P_WAIT, argv[0], argv);
+ if (ret < 0)
+ appl_error(E_EXEC, argv[0], strerror(errno));
+ return ret;
+}
+
+#endif /* SUPPORT_SUBDOC */
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/ebcdic.c b/usr.bin/sgmls/sgmls/ebcdic.c
new file mode 100644
index 0000000..b8188c7
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/ebcdic.c
@@ -0,0 +1,42 @@
+/* ASCII to EBCDIC (ISO 8859-1 to IBM CP 37v2) table. */
+/* Contributed by C. M. Sperberg-McQueen <u35395@uicvm.uic.edu>. */
+
+/* The mapping must be 1 to 1. The positions of *CHAR and *CH in the table
+must not be changed, although the values in ebcdic.h can be. */
+
+#include "ebcdic.h"
+
+unsigned char charset[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47,
+ GENRECHAR, TABCHAR, RSCHAR, 11, 12, RECHAR, 14, 15,
+ 16, 17, 18, 19, 60, 61, 50, 38,
+ 24, 25, EOFCHAR, 39, EOBCHAR, DELCDATA, DELSDATA, DELNONCH,
+ SPCCHAR, 90, 127, 123, 91, 108, 80, 125,
+ 77, 93, 92, 78, 107, 96, 75, 97,
+240, 241, 242, 243, 244, 245, 246, 247,
+248, 249, 122, 94, 76, 126, 110, 111,
+124, 193, 194, 195, 196, 197, 198, 199,
+200, 201, 209, 210, 211, 212, 213, 214,
+215, 216, 217, 226, 227, 228, 229, 230,
+231, 232, 233, 173, 224, 189, 176, 109,
+121, 129, 130, 131, 132, 133, 134, 135,
+136, 137, 145, 146, 147, 148, 149, 150,
+151, 152, 153, 162, 163, 164, 165, 166,
+167, 168, 169, 192, 79, 208, 161, 7,
+ 4, 6, 8, 9, 10, 20, 21, 23,
+ 26, 27, 32, 33, 34, 35, 36, 40,
+ 41, 42, 43, 44, 48, 49, 51, 52,
+ 53, 54, 56, 57, 58, 59, 62, 255,
+ 65, 170, 74, 177, 159, 178, 106, 181,
+187, 180, 154, 138, 95, 202, 175, 188,
+144, 143, 234, 250, 190, 160, 182, 179,
+157, 218, 155, 139, 183, 184, 185, 171,
+100, 101, 98, 102, 99, 103, 158, 104,
+116, 113, 114, 115, 120, 117, 118, 119,
+172, 105, 237, 238, 235, 239, 236, 191,
+128, 253, 254, 251, 252, 186, 174, 89,
+ 68, 69, 66, 70, 67, 71, 156, 72,
+ 84, 81, 82, 83, 88, 85, 86, 87,
+140, 73, 205, 206, 203, 207, 204, 225,
+112, 221, 222, 219, 220, 141, 142, 223,
+};
diff --git a/usr.bin/sgmls/sgmls/ebcdic.h b/usr.bin/sgmls/sgmls/ebcdic.h
new file mode 100644
index 0000000..3e0f3bd
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/ebcdic.h
@@ -0,0 +1,25 @@
+/* SGML Character Use: EBCDIC
+*/
+
+#define EOFCHAR '\077' /* FUNCTION: EE (entity end: files). */
+#define EOBCHAR '\034' /* NONCHAR: EOB (file entity: end of buffer. */
+#define RSCHAR '\045' /* FUNCTION: RS (record start). */
+#define RECHAR '\015' /* FUNCTION: RE (record end). */
+#define TABCHAR '\005' /* FUNCTION: TAB (horizontal tab). */
+#define SPCCHAR '\100' /* FUNCTION: SPACE (horizontal space). */
+#define GENRECHAR '\026' /* NONCHAR: Generated RE. */
+#define DELCDATA '\035' /* NONCHAR: Delimiter for CDATA entity in
+ attribute value. */
+#define DELSDATA '\036' /* NONCHAR: Delimiter for SDATA entity in
+ attribute value. */
+#define DELNONCH '\037' /* NONCHAR: non-SGML character prefix. */
+
+/* This should work for EBCDIC. See comment in latin1.h. */
+#define SHIFTNON(ch) ((UNCH)(ch) | 0200)
+#define UNSHIFTNON(ch) ((UNCH)(ch) & ~0200)
+
+/* See comment in latin1.h. */
+#define CANON_NONSGML 255
+
+/* See comment in latin1.h. */
+#define CANON_DATACHAR 254
diff --git a/usr.bin/sgmls/sgmls/entgen.c b/usr.bin/sgmls/sgmls/entgen.c
new file mode 100644
index 0000000..2146829
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/entgen.c
@@ -0,0 +1,517 @@
+/* entgen.c -
+
+ Implement entgen() which generates a list of filenames from a struct fpi.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifdef HAVE_ACCESS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* For R_OK. */
+#endif /* HAVE_UNISTD_H */
+
+#ifndef R_OK
+#define R_OK 4
+#endif /* not R_OK */
+
+#endif /* HAVE_ACCESS */
+
+#include "sgmlaux.h"
+
+/* Environment variable that contains path. */
+#ifndef PATH_ENV_VAR
+#define PATH_ENV_VAR "SGML_PATH"
+#endif
+/* Default search path. See field() for interpretation of %*. */
+#ifndef DEFAULT_PATH
+#define DEFAULT_PATH "/usr/local/lib/sgml/%O/%C/%T:%N.%X:%N.%D"
+#endif
+
+#ifndef PATH_FILE_SEP
+#define PATH_FILE_SEP ':'
+#endif
+
+#ifndef SYSID_FILE_SEP
+#define SYSID_FILE_SEP ':'
+#endif
+
+/* This says: change space to underscore, slash to percent. */
+
+#ifndef MIN_DAT_SUBS_FROM
+#define MIN_DAT_SUBS_FROM " /"
+#endif
+#ifndef MIN_DAT_SUBS_TO
+#define MIN_DAT_SUBS_TO "_%"
+#endif
+
+static int field P((struct fpi *, int, char *));
+static int mindatcpy P((char *, char *, int, int));
+static int testopen P((char *));
+static UNIV sysidgen P((char *));
+static UNIV catsysidgen P((const char *, const char *));
+static const char *basename P((const char *));
+
+static char *path = 0;
+
+/* Non-zero if searching should be performed when a system identifier
+is specified. */
+static int sysidsrch = 0;
+
+#define EMPTY_VERSION "default"
+
+static char *classes[] = {
+ "capacity",
+ "charset",
+ "notation",
+ "syntax",
+ "document",
+ "dtd",
+ "elements",
+ "entities",
+ "lpd",
+ "nonsgml",
+ "shortref",
+ "subdoc",
+ "text"
+ };
+
+/* This is mainly for compatibility with arcsgml. */
+
+static char *genext[] = {
+ "nsd", /* Non-SGML data entity. */
+ "gml", /* GML document or text entity. */
+ "spe", /* System parameter entity. */
+ "dtd", /* Document type definition. */
+ "lpd", /* Link process definition. */
+ "pns", /* Public non-SGML data entity. */
+ "pge", /* Public general entity. */
+ "ppe", /* Public parameter entity. */
+ "pdt", /* Public document type definition. */
+ "plp", /* Public link process definition. */
+ "vns", /* Display version non-SGML data entity. */
+ "vge", /* Display version general entity. */
+ "vpe", /* Display version parameter entity. */
+ "vdt", /* Display version document type definition.*/
+ "vlp", /* Display version link process definition.*/
+};
+
+static char *ext[] = {
+ "sgml", /* SGML subdocument */
+ "data", /* Data */
+ "text", /* General text */
+ "parm", /* Parameter entity */
+ "dtd", /* Document type definition */
+ "lpd", /* Link process definition */
+};
+
+static CATALOG catalog;
+
+VOID entginit(swp)
+struct switches *swp;
+{
+ catalog = swp->catalog;
+}
+
+/* Like memcpy, but substitute, fold to lower case (if fold is
+non-zero) and null terminate. This is used both for minimum data and
+for names. If p is NULL, do nothing. Return len. */
+
+static int mindatcpy(p, q, len, fold)
+char *p, *q;
+int len;
+int fold;
+{
+ static char subsfrom[] = MIN_DAT_SUBS_FROM;
+ static char substo[] = MIN_DAT_SUBS_TO;
+ int n;
+
+ if (!p)
+ return len;
+ for (n = len; --n >= 0; q++) {
+ char *r = strchr(subsfrom, *q);
+ if (!r) {
+ if (fold && ISASCII(*q) && isupper((UNCH)*q))
+ *p++ = tolower((UNCH)*q);
+ else
+ *p++ = *q;
+ }
+ else {
+ int i = r - subsfrom;
+ if (i < sizeof(substo) - 1)
+ *p++ = substo[i];
+ }
+ }
+ *p = '\0';
+ return len;
+}
+
+
+/* Return length of field. Copy into buf if non-NULL. */
+
+static int field(f, c, buf)
+struct fpi *f;
+int c;
+char *buf;
+{
+ int n;
+
+ switch (c) {
+ case '%':
+ if (buf) {
+ buf[0] = '%';
+ buf[1] = '\0';
+ }
+ return 1;
+ case 'N': /* the entity, document or dcn name */
+ return mindatcpy(buf, (char *)f->fpinm, ustrlen(f->fpinm),
+ (f->fpistore != 1 && f->fpistore != 2 && f->fpistore != 3
+ ? NAMECASE
+ : ENTCASE));
+ case 'D': /* dcn name */
+ if (f->fpistore != 1) /* not a external data entity */
+ return -1;
+ if (f->fpinedcn == 0) /* it's a SUBDOC */
+ return -1;
+ return mindatcpy(buf, (char *)f->fpinedcn, ustrlen(f->fpinedcn),
+ NAMECASE);
+ case 'X':
+ /* This is for compatibility with arcsgml */
+ if (f->fpistore < 1 || f->fpistore > 5)
+ return -1;
+ n = (f->fpipubis != 0)*(f->fpiversw > 0 ? 2 : 1)*5+f->fpistore - 1;
+ if (buf)
+ strcpy(buf, genext[n]);
+ return strlen(genext[n]);
+ case 'Y': /* tYpe */
+ n = f->fpistore;
+ if (n < 1 || n > 5)
+ return -1;
+ if (n == 1 && f->fpinedcn == 0) /* it's a SUBDOC */
+ n = 0;
+ if (buf)
+ strcpy(buf, ext[n]);
+ return strlen(ext[n]);
+ case 'P': /* public identifier */
+ if (!f->fpipubis)
+ return -1;
+ return mindatcpy(buf, (char *)f->fpipubis, ustrlen(f->fpipubis), 0);
+ case 'S': /* system identifier */
+ if (!f->fpisysis)
+ return -1;
+ else {
+ UNCH *p;
+ n = 0;
+ for (p = f->fpisysis; *p; p++)
+ if (*p != RSCHAR) {
+ if (buf)
+ buf[n] = *p == RECHAR ? '\n' : *p;
+ n++;
+ }
+ return n;
+ }
+ }
+ /* Other fields need a formal public identifier. */
+ /* return -1 if the formal public identifier was invalid or missing. */
+ if (f->fpiversw < 0 || !f->fpipubis)
+ return -1;
+
+ switch (c) {
+ case 'A': /* Is it available? */
+ return f->fpitt == '+' ? 0 : -1;
+ case 'I': /* Is it ISO? */
+ return f->fpiot == '!' ? 0 : -1;
+ case 'R': /* Is it registered? */
+ return f->fpiot == '+' ? 0 : -1;
+ case 'U': /* Is it unregistered? */
+ return f->fpiot == '-' ? 0 : -1;
+ case 'L': /* public text language */
+ if (f->fpic == FPICHARS)
+ return -1;
+ /* it's entered in all upper case letters */
+ return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 1);
+ case 'O': /* owner identifier */
+ return mindatcpy(buf, (char *)f->fpipubis + f->fpio, f->fpiol, 0);
+ case 'C': /* public text class */
+ n = f->fpic - 1;
+ if (n < 0 || n >= sizeof(classes)/sizeof(classes[0]))
+ return -1;
+ if (buf)
+ strcpy(buf, classes[n]);
+ return strlen(classes[n]);
+ case 'T': /* text description */
+ return mindatcpy(buf, (char *)f->fpipubis + f->fpit, f->fpitl, 0);
+ case 'V':
+ if (f->fpic < FPICMINV) /* class doesn't have version */
+ return -1;
+ if (f->fpiversw > 0) /* no version */
+ return -1;
+ if (f->fpivl == 0) { /* empty version: */
+ /* use device-independent version*/
+ if (buf)
+ strcpy(buf, EMPTY_VERSION);
+ return strlen(EMPTY_VERSION);
+ }
+ return mindatcpy(buf, (char *)f->fpipubis + f->fpiv, f->fpivl, 0);
+ case 'E': /* public text designating (escape) sequence */
+ if (f->fpic != FPICHARS)
+ return -1;
+ return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 0);
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int testopen(pathname)
+char *pathname;
+{
+#ifdef HAVE_ACCESS
+ return access(pathname, R_OK) >= 0;
+#else /* not HAVE_ACCESS */
+ FILE *fp;
+ fp = fopen(pathname, "r");
+ if (!fp)
+ return 0;
+ fclose(fp);
+ return 1;
+#endif /* not HAVE_ACCESS */
+}
+
+/* Return a pointer to an dynamically-allocated buffer that contains
+ the names of the files containing this entity, with each filename
+ terminated by a '\0', and with the list of filenames terminated by
+ another '\0'. */
+
+UNIV entgen(f)
+struct fpi *f;
+{
+ char *qname;
+ char *file;
+ enum catalog_decl_type dtype;
+ char *subst = 0;
+ const char *sysid;
+ const char *catfile;
+
+ assert(f->fpistore != 6); /* Musn't call entgen for a notation. */
+ if (!path) {
+ char *p;
+ char c;
+ path = getenv(PATH_ENV_VAR);
+ if (!path)
+ path = DEFAULT_PATH;
+ p = path;
+
+ /* Only search for system identifiers if path uses %S. */
+ while ((c = *p++) != '\0')
+ if (c == '%') {
+ if (*p == 'S') {
+ sysidsrch = 1;
+ break;
+ }
+ if (*p != '\0' && *p != PATH_FILE_SEP)
+ p++;
+ }
+ }
+
+ if (f->fpisysis && !sysidsrch)
+ return sysidgen((char *)f->fpisysis);
+
+ qname = (char *)f->fpinm;
+
+ switch (f->fpistore) {
+ case 3:
+ /* fall through */
+ qname--; /* hack */
+ case 1:
+ case 2:
+ dtype = CATALOG_ENTITY_DECL;
+ if (ENTCASE)
+ subst = getsubst();
+ break;
+ case 4:
+ dtype = CATALOG_DOCTYPE_DECL;
+ if (NAMECASE)
+ subst = getsubst();
+ break;
+ default:
+ dtype = CATALOG_NO_DECL;
+ }
+
+ if (catalog_lookup_entity(catalog,
+ (char *)f->fpipubis,
+ qname,
+ dtype,
+ (char *)subst,
+ &sysid,
+ &catfile))
+ return catsysidgen(sysid, catfile);
+ if (f->fpisysis
+ && (strchr((char *)f->fpisysis, SYSID_FILE_SEP)
+ || strcmp((char *)f->fpisysis, STDINNAME) == 0))
+ return sysidgen((char *)f->fpisysis);
+
+ file = path;
+
+ for (;;) {
+ char *p;
+ int len = 0;
+ char *fileend = strchr(file, PATH_FILE_SEP);
+ if (!fileend)
+ fileend = strchr(file, '\0');
+
+ /* Check that all substitutions are non-null, and calculate
+ the resulting total length of the filename. */
+ for (p = file; p < fileend; p++)
+ if (*p == '%') {
+ int n;
+ /* Set len to -1 if a substitution is invalid. */
+ if (++p >= fileend) {
+ len = -1;
+ break;
+ }
+ n = field(f, *p, (char *)0);
+ if (n < 0) {
+ len = -1;
+ break;
+ }
+ len += n;
+ }
+ else
+ len++;
+
+ if (len > 0) {
+ /* We've got a valid non-empty filename. */
+ char *s;
+ char *buf;
+
+ s = buf = (char *)rmalloc(len + 2);
+ for (p = file; p < fileend; p++)
+ if (*p == '%')
+ s += field(f, *++p, s);
+ else
+ *s++ = *p;
+ *s++ = '\0';
+ if (testopen(buf)) {
+ /* Terminate the array of filenames. */
+ *s++ = '\0';
+ return buf;
+ }
+ free((UNIV)buf);
+ }
+ if (*fileend == '\0')
+ break;
+ file = ++fileend;
+ }
+ return 0;
+}
+
+/* Handle a system identifier without searching. */
+
+static
+UNIV sysidgen(s)
+char *s;
+{
+ char *buf, *p;
+
+ buf = (char *)rmalloc(strlen(s) + 2);
+
+ for (p = buf; *s; s++) {
+ if (*s == SYSID_FILE_SEP) {
+ if (p > buf && p[-1] != '\0')
+ *p++ = '\0';
+ }
+ else if (*s == RECHAR)
+ *p++ = '\n';
+ else if (*s != RSCHAR)
+ *p++ = *s;
+ }
+ /* Terminate this filename. */
+ if (p > buf && p[-1] != '\0')
+ *p++ = '\0';
+ if (p == buf) {
+ /* No filenames. */
+ frem((UNIV)buf);
+ return 0;
+ }
+ /* Terminate the list. */
+ *p++ = '\0';
+ return buf;
+}
+
+/* Handle a system id in a catalog entry file. */
+static
+UNIV catsysidgen(s, catfile)
+const char *s;
+const char *catfile;
+{
+ const char *p;
+ char *bufp;
+ char *buf;
+ int nrelative = 0;
+ int catdirlen = 0;
+ if (FILE_IS_RELATIVE(s))
+ nrelative++;
+ for (p = s; *p; p++)
+ if (*p == SYSID_FILE_SEP
+ && FILE_IS_RELATIVE(p + 1))
+ nrelative++;
+ if (nrelative) {
+ const char *base = basename(catfile);
+ catdirlen = base - catfile;
+ }
+ buf = (char *)rmalloc(p - s + 2 + nrelative*catdirlen);
+ bufp = buf;
+ for (;;) {
+ if (!*s)
+ break;
+ if (*s != SYSID_FILE_SEP && FILE_IS_RELATIVE(s)) {
+ memcpy(bufp, catfile, catdirlen);
+ bufp += catdirlen;
+ }
+ for (;;) {
+ if (*s == SYSID_FILE_SEP) {
+ s++;
+ break;
+ }
+ *bufp++ = *s++;
+ if (*s == '\0')
+ break;
+ }
+ if (bufp > buf && bufp[-1] != '\0')
+ *bufp++ = '\0';
+ }
+ if (bufp == buf) {
+ frem((UNIV)buf);
+ return 0;
+ }
+ *bufp++ = '\0';
+ return buf;
+}
+
+static
+const char *basename(s)
+const char *s;
+{
+ const char *p = s;
+ while (*p)
+ p++;
+ if (p > s) {
+ while (--p > s)
+ if (strchr(DIR_BASE_SEP, *p))
+ return p + 1;
+ }
+ return s;
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/entity.h b/usr.bin/sgmls/sgmls/entity.h
new file mode 100644
index 0000000..84a3515
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/entity.h
@@ -0,0 +1,192 @@
+/* Struct dcncb: attribute list added to support data attributes. */
+#ifndef ENTITY_H /* Don't include this file more than once. */
+#define ENTITY_H
+/* ENTITY.H: Definitions and control block templates for entity management.
+*/
+#include "tools.h" /* Definitions for type declarations, etc. */
+#include "msgcat.h"
+#include "catalog.h"
+
+#define STDINNAME "-" /* File name that refers to standard input. */
+
+#define EOS '\0' /* NONCHAR: EE (entity end: strings). */
+
+#define AVALCASE 2 /* 2=untranslated string of name characters. */
+
+#define REFNAMELEN 8 /* reference quantity set NAMELEN */
+#define REFLITLEN 240 /* reference quantity set LITLEN */
+
+/* Minimization status of returned tags.
+*/
+#define MINNONE 0 /* Minimization: tag not minimized. */
+#define MINNULL 1 /* Minimization: tag was null. */
+#define MINNET 2 /* Minimization: end-tag was NET delimiter. */
+#define MINDATA 3 /* Minimization: end-tag was data tag. */
+#define MINSTAG 4 /* Minimization: tag implied by start-tag. */
+#define MINETAG 5 /* Minimization: end-tag implied by end-tag. */
+
+/* Formal public identifier public text classes.
+*/
+#define FPICAP 1
+#define FPICHARS 2
+#define FPINOT 3
+#define FPISYN 4
+#define FPICMINV 5 /* Minimum fpic value for versionable text. */
+#define FPIDOC 5
+#define FPIDTD 6
+#define FPIELEM 7
+#define FPIENT 8
+#define FPILPD 9
+#define FPINON 10
+#define FPISHORT 11
+#define FPISUB 12
+#define FPITEXT 13
+struct fpi { /* Formal public identifier. */
+ UNCH fpiot; /* Owner type: + or - or ! (for ISO). */
+ UNS fpiol; /* Length of owner identifier. */
+ UNS fpio; /* Offset in pubis of owner identifier (no EOS).*/
+ int fpic; /* Public text class. */
+ UNCH fpitt; /* Text type: - or + (for available). */
+ UNS fpitl; /* Length of text identifier. */
+ UNS fpit; /* Offset in pubis of text identifier (no EOS). */
+ UNS fpill; /* Language/designating sequence length. */
+ UNS fpil; /* Offset in pubis of language. */
+ UNS fpivl; /* Length of display version . */
+ UNS fpiv; /* Offset in pubis of display version (no EOS). */
+ int fpiversw; /* 1=use best ver; 0=use stated ver; -1=error. */
+ UNCH *fpinm; /* Entity/DCN name (EOS, no length). */
+ UNCH fpistore; /* 1=NDATA 2=general 3=parm 4=DTD 5=LPD 6=DCN. */
+ /* Name of the entity's DCN. Valid only when fpistore == 1.
+ NULL if it's a SUBDOC. */
+ UNCH *fpinedcn;
+ UNCH *fpipubis; /* Public ID string (EOS). */
+ UNCH *fpisysis; /* System ID string (EOS). */
+};
+#define FPISZ sizeof(struct fpi)
+typedef struct fpi *PFPI; /* Ptr to FPI control block. */
+
+/* General control blocks.
+*/
+#define NONONCH 1 /* Character references to non-chars invalid. */
+#define OKNONCH 0 /* Character references to non-chars allowed. */
+struct parse { /* Parse control block. */
+ char *pname; /* Parse name; content, tag, etc. */
+ UNCH *plex; /* Lexical analysis table. */
+ UNCH **ptab; /* State and action table. */
+ UNS state; /* State. */
+ UNS input; /* Input. */
+ UNS action; /* Action. */
+ UNS newstate; /* Next state. */
+};
+struct restate {
+ UNS sstate; /* State. */
+ UNS sinput; /* Input. */
+ UNS saction; /* Action. */
+ UNS snext; /* Next state. */
+};
+struct map {
+ UNCH *mapnm; /* Name followed by EOS. */
+ int mapdata; /* Data associated with that name. */
+};
+struct hash { /* Dummy structure for function arguments. */
+ struct hash *enext; /* Next entry in chain. */
+ UNCH *ename; /* Entry name with size and EOS. */
+};
+typedef struct hash *PHASH; /* Ptr to hash table entry. */
+typedef struct hash **THASH; /* Ptr to hash table. */
+
+struct fwdref { /* A forward id reference. */
+ struct fwdref *next; /* Pt to next reference in chain. */
+ UNIV msg; /* Ptr to saved error messsage. */
+};
+#define FWDREFSZ sizeof(struct fwdref)
+
+struct dcncb { /* Data content notation control block. */
+ struct dcncb *enext; /* Next DCN in chain. */
+ UNCH *ename; /* Notation name followed by EOS. */
+ UNCH mark; /* For use by application. */
+ UNCH entsw; /* Entity defined with this notation? */
+ UNCH defined; /* Has this notation been defined. */
+ UNCH *sysid; /* System identifier of notation. */
+ UNCH *pubid; /* Public identifier of notation. */
+ struct ad *adl; /* Data attribute list (NULL if none). */
+};
+#define DCBSZ sizeof(struct dcncb)
+#define DCNMARK(p) ((p)->mark ? 1 : ((p)->mark = 1, 0))
+
+typedef struct dcncb *PDCB; /* Ptr to DCN control block. */
+
+/* Number of capacities in a capacity set. */
+
+#define NCAPACITY 17
+
+struct sgmlcap {
+ char **name;
+ UNCH *points;
+ long *number;
+ long *limit;
+};
+
+struct sgmlstat { /* Document statistics. */
+ UNS dcncnt; /* Number of data content notations defined. */
+ UNS pmexgcnt; /* Number of plus or minus exception groups. */
+ UNS etdcnt; /* Number of element types declared. */
+ UNS etdercnt; /* Number of element types defined by default. */
+ UNS pmexcnt; /* Number of plus/minus exception grp members. */
+ UNS modcnt; /* Number of content model tokens defined. */
+ UNS attcnt; /* Number of attributes defined. */
+ UNS attdef; /* Characters of attribute defaults defined. */
+ UNS attgcnt; /* Number of att value grp members (incl dcn). */
+ UNS idcnt; /* Number of ID attributes specified. */
+ UNS idrcnt; /* Number of ID references specified. */
+ UNS ecbcnt; /* Number of entities declared. */
+ UNS ecbtext; /* Characters of entity text defined. */
+ UNS srcnt; /* Number of short reference tables defined. */
+ UNS dcntext; /* Characters of notation identifiers defined. */
+};
+struct switches { /* Parser control switches (1=non-standard). */
+ int swdupent; /* 1=msg if duplicate ENTITY def attempted;0=no.*/
+ int swcommnt; /* 1=return comment declarations as data; 0=no. */
+ int swrefmsg; /* 1=msg if undeclared ref is defaulted; 0=no. */
+ UNS swbufsz; /* Size of source file buffer for READ(). */
+ int swenttr; /* 1=trace entity stack in error messages; 0=no.*/
+ int sweltr; /* 1=trace element stack in error messages; 0=no. */
+ int swambig; /* 1=check content model ambiguity */
+ int swundef; /* 1=warn about undefined elements. */
+ int swcap; /* 1=report capcity errors */
+ char *prog; /* Program name for error messages. */
+#ifdef TRACE
+ char *trace; /* What to trace in the body. */
+ char *ptrace; /* What to trace in the prolog. */
+#endif /* TRACE */
+ nl_catd catd; /* Message catalog descriptor. */
+ long nopen; /* Number of open document entities */
+ int onlypro; /* Parse only the prolog. */
+ char **includes; /* List of parameter entities to be defined
+ as "INCLUDE"; NULL terminated.*/
+ VOID (*die) P((void)); /* Function to call on fatal error. */
+ CATALOG catalog; /* Catalog for generating system identifiers. */
+};
+struct markup { /* Delimiter strings for text processor. */
+ UNCH *cro; /* LEXCON markup string: CRO */
+ UNCH *dso; /* LEXCON markup string: DSO */
+ UNCH *ero; /* LEXCON markup string: ERO */
+ UNCH *etag; /* LEXMARK markup string: end-tag */
+ UNCH *lit; /* LEXMARK markup string: LIT */
+ UNCH *lita; /* LEXMARK markup string: LITA */
+ UNCH *mdc; /* LEXCON markup string: MDC */
+ UNCH *mdo; /* LEXCON markup string: MDO */
+ UNCH *mse; /* LEXCON markup string: mse */
+ UNCH *mss; /* LEXCON markup string: mss */
+ UNCH *mssc; /* LEXCON markup string: mss CDATA */
+ UNCH *mssr; /* LEXCON markup string: mss RCDATA */
+ UNCH *pic; /* LEXCON markup string: PIC */
+ UNCH *pio; /* LEXCON markup string: PIO */
+ UNCH *refc; /* LEXGRP markup string: REFC */
+ UNCH *stag; /* LEXMARK markup string: start-tag */
+ UNCH *tagc; /* LEXMARK markup string: TAGC */
+ UNCH *vi; /* LEXMARK markup string: VI */
+ int lennet; /* LEXMARK markup string length: null end-tag. */
+ int lennst; /* LEXMARK markup string length: null start-tag.*/
+};
+#endif /* ndef ENTITY_H */
diff --git a/usr.bin/sgmls/sgmls/error.h b/usr.bin/sgmls/sgmls/error.h
new file mode 100644
index 0000000..d37d493
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/error.h
@@ -0,0 +1,61 @@
+/* ERROR.H: Symbols for SGML error codes (start with 'E_').
+ Numbers 46 - 56 are generated by ERROR.C.
+ Later numbers are coded directly.
+*/
+/* SGMLERR.C: General errors and syntax errors.
+*/
+#define E_CONTEXT 1 /* W GI not allowed at this point in structure. */
+#define E_MDNAME 2 /* E Invalid markup declaration name. */
+/*efine E_LEN 3 E Syntax error: length exceeded. */
+#define E_SYS 4 /* W Illegal system character. */
+#define E_ETAG 5 /* E End-tag does not match any open start-tag. */
+#define E_STAGMAX 6 /* E Maximum number of open elements exceeded. */
+/* E_ALLNULL 7 W Start- and end-tag omitted with null content. */
+#define E_EOF 8 /* E/W Illegal entity end in markup or delimited text. */
+/* fine E_INV 9 E Markup error: invalid character. */
+#define E_CHARS 10 /* W Data found in content that doesn't allow it. */
+/* fine E_NOETDE 11 E End-tag GI not defined by element declaration. */
+#define E_BADNM 12 /* E Name is not syntactically valid. */
+#define E_BADATT 13 /* E Attribute was not defined by element declaration. */
+#define E_VALINV 14 /* W Att value/declaration conflict: invalid char. */
+#define E_VALLEN 15 /* W Att value/declaration conflict: token too long. */
+#define E_VALCNT 16 /* W Att value/declaration conflict: too many tokens. */
+#define E_VALTYPE 17 /* W Att value/declaration conflict: wrong token type.*/
+#define E_VALGRP 18 /* W Att value/declaration conflict: token not in grp.*/
+#define E_VALREQ 19 /* W Att value/declaration conflict: req unspecified. */
+/* E_EMIN 20 W End-tag implied by end-tag; not minimizable. */
+/* E_SMIN 21 W Omitted start-tag was not minimizable. */
+#define E_POSSATT 22 /* E Possible att found but not defined; used as data.*/
+/* Late additions numbered out of order to avoid recompilation. */
+/*efine E_ENTSYNC 37 E Entity and group nesting levels out of sync. */
+#define E_BADVAL 25 /* W Att value omitted (null); default used. */
+/* E_ECONTXT 30 W Element ended prematurely (some content omitted).*/
+/* E_EMINST 39 W End-tag implied by start-tag; not minimizable. */
+/* E_MEXTAG 40 W *** In Use *** */
+#define E_MEXERR 41 /* W Attempt to exclude contextually required element.*/
+#define E_DOCTYPE 42 /* W No document type defined; *DOCTYPE assumed. */
+/* E_NOETDS 43 E Start-tag GI not defined by element declaration. */
+#define E_RESTART 44 /* E Invalid chars ignored; trying to restart parse. */
+
+/* MDERROR.C: Errors in markup declarations.
+*/
+/*efine E_DUP 23 E Duplicate specification. */
+/*efine E_KEY 24 E Incorrect keyword for parameter. */
+/*efine E_MSE 26 E MSE occurred with no corresponding MS. */
+/*efine E_MSS 27 E MSS exceeded maximum nesting level. */
+/*efine E_NUM 28 E Incorrect number of parameters. */
+#define E_TYPE 29 /* E Incorrect parameter type. */
+/* Late additions numbered out of order to avoid recompilation. */
+/*efine E_VAL 38 W Incorrect parameter value. */
+
+/* RESERROR.C: Errors in resource routines.
+*/
+/* Unused I End of primary source entity. */
+/* fine E_FILBUF 31 E Could not read next buffer. */
+/* fine E_ERFILE 32 E Could not open file. */
+/* fine E_MALLOC 33 T Could not obtain required main storage. */
+/* fine E_ERMAX 34 E Maximum number of open entities exceeded. */
+/* fine E_ERNAME 35 E Referenced entity undeclared. */
+/* fine E_ERLOOP 36 E Entity referenced within itself: ref ignored. */
+/* Late additions numbered out of order to avoid recompilation. */
+/* E_ERDEF 45 E Referenced entity undeclared; SYSTEM assumed. */
diff --git a/usr.bin/sgmls/sgmls/etype.h b/usr.bin/sgmls/sgmls/etype.h
new file mode 100644
index 0000000..8ec64c1
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/etype.h
@@ -0,0 +1,93 @@
+/* ETYPE.H: Definitions for element type and group processing.
+*/
+#define MCHARS 0x80 /* Model: contains #CHARS. */
+#define MGI 0x40 /* Model: contains GI names. */
+#define MPHRASE 0x20 /* Model: first token is #CHARS. */
+#define MKEYWORD 0x1F /* Model: defined with single keyword. */
+#define MNONE 0x10 /* Model: contains no GIs or #CHARS. */
+#define MANY 0x08 /* Model: contains any GIs or #CHARS. */
+#define MRCDATA 0x04 /* Model: contains RCDATA. */
+#define MCDATA 0x02 /* Model: contains CDATA. */
+
+#define TOREP (TOPT+TREP) /* 11000000 Optional and repeatable. */
+#define TOPT 0x80 /* Token: 1=optional; 0=required. */
+#define TREP 0x40 /* Token: 1=repeatable; 0=not. */
+#define TXOREP (TXOPT+TXREP) /* * explicitly specified */
+#define TXOPT 0x20 /* ? explicitly specified */
+#define TXREP 0x10 /* + explicitly specified */
+#define TTMASK 0x0F /* 00001111 Mask for testing token type. */
+#define TTETD 4 /* 00000100 Token is an ETD. */
+#define TTAND 3 /* 00000011 Token is an AND group. */
+#define TTSEQ 2 /* 00000010 Token is a sequence group. */
+#define TTOR 1 /* 00000001 Token is an OR group. */
+#define TTCHARS 0 /* 00000000 Token is #CHARS. */
+
+struct thdr { /* Token header or model header. */
+ UNCH ttype; /* Token type attributes or model content. */
+ union {
+ int tnum; /* Group token: tokens in group.
+ Model header: content tokens at any level. */
+ struct etd *thetd; /* GI token: ptr to etd. */
+ } tu;
+};
+#define THSZ (sizeof(struct thdr))
+
+#define ETDHASH 211 /* Size of element hash table. Must be prime. */
+#define SMO 0x40 /* ETDMIN: Start-tag O minimization. */
+#define EMO 0x04 /* ETDMIN: End-tag O minimization. */
+#define EMM 0x02 /* ETDMIN: End-tag minimization explicitly
+ specified to be minus */
+#define ETDDCL 0x80 /* ETDMIN: Element was declared. */
+#define ETDUSED 0x20 /* ETDMIN: Element used in another declaration. */
+#define ETDOCC 0x10 /* ETDMIN: Element occurred in document. */
+
+struct etd { /* Element type definition. */
+ struct etd *etdnext; /* Next element type definition in hash chain. */
+ UNCH *etdgi; /* GI preceded by its length, followed by EOS. */
+ UNCH etdmin; /* Flag bits: minimization. */
+ UNCH mark; /* Mark bit: for ambiguity checking */
+ struct thdr *etdmod; /* Content model. */
+ struct etd **etdmex; /* Minus exceptions. */
+ struct etd **etdpex; /* Plus exceptions. */
+ struct ad *adl; /* Attribute descriptor list. */
+ struct entity **etdsrm; /* Short reference map. */
+};
+#define ETDSZ (sizeof(struct etd))
+typedef struct etd *PETD;
+extern struct etd dumetd[];
+
+/* Number of bits in a long must be >= 1<<LONGPOW */
+#define LONGPOW 5
+
+#define LONGBITS (1<<LONGPOW)
+
+struct mpos { /* Position of current element in model. */
+ UNCH g; /* Index of this group in the model. */
+ UNCH t; /* Index of the current token in this group. */
+ UNCH tstart; /* Index of starting token for AND group
+ testing. */
+ unsigned long *h; /* Hit bits of this group's tokens. */
+};
+
+#define HITCLEAR(h) MEMZERO((UNIV)(h), grplongs*sizeof(unsigned long))
+
+#define TAGCONER 0x01 /* 00000001 (contersw) Tag was out of context. */
+#define TAGNET 0x02 /* 00000010 (etisw) Tag has NET enabled. */
+#define TAGPEX 0x04 /* 00000100 (pexsw) Tag was plus exception. */
+#define TAGREF 0x08 /* 00001000 (conrefsw) Tag had CONREF or EMPTY.*/
+struct tag { /* Tag control block. */
+ UNCH status; /* Status of context check. */
+ UNCH tflags; /* Flags: TAGCONER TAGNET TAGPEX TAGREF */
+ struct etd *tetd; /* Element type definition for tag. */
+ struct entity **tsrm; /* Current short reference map. */
+ struct mpos *tpos; /* Position of next tag in this model. */
+};
+
+#define RCEND 1 /* No more tokens: end element and retry GI. */
+#define RCREQ 2 /* Required GI must precede proposed GI. */
+#define RCMISS 3 /* GI invalid: not element end; no required GI. */
+#define RCHIT 4 /* GI is the one expected next. */
+#define RCMEX 5 /* GI invalid: minus exception. */
+#define RCHITMEX 6 /* RCMEX with invalid attempted minus exclusion.*/
+#define RCPEX 7 /* GI is valid solely because of plus exclusion.*/
+#define RCNREQ 8 /* Token is not required; can retry invalid GI. */
diff --git a/usr.bin/sgmls/sgmls/exclude.c b/usr.bin/sgmls/sgmls/exclude.c
new file mode 100644
index 0000000..7d72cc0
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/exclude.c
@@ -0,0 +1,121 @@
+/* exclude.c -
+ Exclusion checking.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "sgmlincl.h"
+
+static int excktok P((struct thdr *, int, int *));
+static int exmark P((int));
+
+/* Check that the current exclusions are legal for the content model
+of the current element. */
+
+VOID exclude()
+{
+ struct thdr *mod = tags[ts].tetd->etdmod;
+
+ if ((mod->ttype & MKEYWORD) == 0 && exmark(1)) {
+ int excl;
+
+ excktok(mod + 1, 0, &excl);
+ exmark(0);
+ }
+}
+
+/* Set the mark field of all current exclusions to val. Return 1 if
+there are some current exclusions. */
+
+static
+int exmark(val)
+int val;
+{
+ int i;
+ int gotone = 0;
+
+ for (i = ts; i > 0; --i) {
+ struct etd **p = tags[i].tetd->etdmex;
+ if (p) {
+ for (; *p; p++)
+ (*p)->mark = val;
+ gotone = 1;
+ }
+ }
+ return gotone;
+}
+
+/* Check exclusions for this token. Return size of token. */
+
+static
+int excktok(t, orgrp, excl)
+struct thdr *t;
+int orgrp; /* 1 if token is member of or group */
+int *excl; /* Set to 1 if token is excluded. */
+{
+ int size;
+ struct thdr *tem;
+ int tnum;
+ int optional = 0;
+ int hadopt, hadreq;
+
+ *excl = 0;
+
+ switch (t->ttype & TTMASK) {
+ case TTETD:
+ if (t->tu.thetd->mark) {
+ if (orgrp || (t->ttype & TOPT))
+ *excl = 1;
+ else
+ sgmlerr(217, &pcbstag, t->tu.thetd->etdgi + 1,
+ tags[ts].tetd->etdgi + 1);
+ }
+ /* fall through */
+ case TTCHARS:
+ size = 1;
+ break;
+ case TTOR:
+ case TTAND:
+ case TTSEQ:
+ tem = t + 1;
+ hadopt = 0;
+ hadreq = 0;
+ for (tnum = t->tu.tnum; tnum > 0; --tnum) {
+ int ex;
+ int n = excktok(tem, (t->ttype & TTMASK) == TTOR, &ex);
+ if (!ex) {
+ if (tem->ttype & TOPT)
+ hadopt = 1;
+ else
+ hadreq = 1;
+ }
+ tem += n;
+ }
+ size = tem - t;
+ if ((t->ttype & TTMASK) == TTOR)
+ optional = hadreq ? hadopt : 1;
+ else
+ optional = !hadreq;
+ break;
+ default:
+ abort();
+ }
+
+ /* Was required, but exclusions have made it optional.
+ eg <!element foo - - (a | b) -(a, b)> */
+
+ if (optional && !(t->ttype & TOPT))
+ sgmlerr(216, &pcbstag, tags[ts].tetd->etdgi + 1, (UNCH *)0);
+
+ return size;
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/genlex.c b/usr.bin/sgmls/sgmls/genlex.c
new file mode 100644
index 0000000..b653d14
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/genlex.c
@@ -0,0 +1,140 @@
+/* genlex: Generate lexical tables for non-ASCII charsets. */
+
+#include "config.h"
+#include "std.h"
+#include "tools.h"
+
+#define CANON_ASCII_NONSGML 255 /* Canonical non-SGML character in ASCII. */
+#define CANON_ASCII_DATACHAR 254 /* Canonical DATACHAR in ASCII. */
+
+extern unsigned char charset[];
+extern UNCH *lextabs[];
+extern UNCH lextran[];
+
+static char *lextabnames[] = {
+ "lexcnm", "lexcon", "lexgrp", "lexlms", "lexmark", "lexsd", "lextoke",
+ "lexmin"
+};
+
+#define UNUSED -1
+
+extern int iso646charset[];
+extern int iso646G0charset[];
+extern int iso646C0charset[];
+extern int iso8859_1charset[];
+extern int iso6429C1charset[];
+
+static struct {
+ char *name;
+ int *map;
+} charsets[] = {
+ { "iso646charset", iso646charset },
+ { "iso646G0charset", iso646G0charset },
+ { "iso646G0charset", iso646G0charset },
+ { "iso8859_1charset", iso8859_1charset },
+ { "iso646C0charset", iso646C0charset },
+ { "iso6429C1charset", iso6429C1charset },
+};
+
+static VOID print_tab(s, t)
+ char *s;
+ UNCH *t;
+{
+ int i;
+ printf("UNCH %s[] = {\n", s);
+ for (i = 0; i < 256; i++)
+ printf("%2d,%c", t[i], (i + 1) % 16 == 0 ? '\n' : ' ');
+ fputs("};\n\n", stdout);
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ UNCH tab[256];
+ char special[256];
+ /* Shunned character numbers in the reference concrete syntax. */
+ static UNCH refshun[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 255
+ };
+ char shunned[256];
+ char *program_name;
+
+ program_name = strrchr(argv[0], '/');
+ if (program_name)
+ program_name++;
+ else
+ program_name = argv[0];
+
+ /* Check that the mapping is 1-1. */
+ for (i = 0; i < 256; i++)
+ tab[i] = 0;
+ for (i = 0; i < 256; i++)
+ tab[charset[i]] = 1;
+ for (i = 0; i < 256; i++)
+ if (!tab[i]) {
+ fprintf(stderr, "%s: bad mapping: no character mapped to %d\n",
+ program_name, i);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Compute special. */
+ for (i = 0; i < 256; i++)
+ special[i] = 0;
+ for (i = 0; lextabs[i]; i++) {
+ int j;
+ for (j = 0; j < 256; j++)
+ if (lextabs[i][j] != lextabs[i][CANON_ASCII_NONSGML]
+ && lextabs[i][j] != lextabs[i][CANON_ASCII_DATACHAR])
+ special[charset[j]] = 1;
+ }
+
+ /* Compute shunned. */
+ for (i = 0; i < 256; i++)
+ shunned[i] = 0;
+ for (i = 0; i < sizeof(refshun); i++)
+ shunned[refshun[i]] = 1;
+
+ printf("/* This file was automatically generated by %s. Do not edit. */\n\n",
+ program_name);
+ fputs("#include \"config.h\"\n#include \"entity.h\"\n#include \"sgmldecl.h\"\n\n",
+ stdout);
+
+ /* Generate each of the lexical tables. */
+ for (i = 0; lextabs[i]; i++) {
+ int j;
+ for (j = 0; j < 256; j++)
+ tab[charset[j]] = lextabs[i][j];
+
+ for (j = 0; j < 256; j++)
+ if (!special[j]) {
+ if (shunned[j])
+ tab[j] = lextabs[i][CANON_ASCII_NONSGML];
+ else
+ tab[j] = lextabs[i][CANON_ASCII_DATACHAR];
+ }
+ print_tab(lextabnames[i], tab);
+ }
+
+ /* Generate lextran. */
+ for (i = 0; i < 256; i++)
+ tab[charset[i]] = charset[lextran[i]];
+ print_tab("lextran", tab);
+
+ /* Generate charsets. */
+ for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
+ int j;
+ int *map = charsets[i].map;
+ printf("\nint %s[] = {\n", charsets[i].name);
+ for (j = 0; j < 256; j++)
+ if (map[j] == UNUSED)
+ printf("UNUSED,%c", (j + 1) % 8 == 0 ? '\n' : ' ');
+ else
+ printf("%3d,%c", charset[map[j]], (j + 1) % 16 == 0 ? '\n' : ' ');
+ fputs("};\n", stdout);
+ }
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/usr.bin/sgmls/sgmls/getopt.c b/usr.bin/sgmls/sgmls/getopt.c
new file mode 100644
index 0000000..9a218b3
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/getopt.c
@@ -0,0 +1,166 @@
+/* getopt.c -
+ getopt() for those systems that don't have it.
+
+ Derived from comp.sources.unix/volume3/att_getopt.
+ Modified by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifndef HAVE_GETOPT
+
+#include "std.h"
+#include "getopt.h"
+
+#ifdef SWITCHAR
+#include <dos.h>
+#endif
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+#ifndef OPTION_CHAR
+#define OPTION_CHAR '-'
+#endif
+
+int getopt(argc, argv, opts)
+int argc;
+char **argv;
+char *opts;
+{
+#ifdef SWITCHAR
+ union REGS regs;
+ static char switchar = '\0';
+#endif
+ static int sp = 1;
+ register int c;
+ register char *cp;
+ char *message;
+#ifdef SWITCHAR
+ if (switchar == '\0') {
+ regs.x.ax = 0x3700;
+ intdos(&regs, &regs);
+ if (!regs.x.cflag)
+ switchar = regs.h.dl;
+ else
+ switchar = '/';
+ }
+#endif
+ if (sp == 1) {
+ if (optind >= argc)
+ return EOF;
+ if ((
+#ifdef SWITCHAR
+ argv[optind][0] != switchar &&
+#endif
+ argv[optind][0] != OPTION_CHAR) || argv[optind][1] == '\0') {
+#ifdef REORDER_ARGS
+ int i;
+ for (i = optind; i < argc; i++)
+ if ((
+#ifdef SWITCHAR
+ argv[i][0] == switchar ||
+#endif
+ argv[i][0] == OPTION_CHAR) && argv[i][1] != '\0')
+ break;
+ if (i < argc) {
+ c = argv[i][1];
+#ifdef CASE_INSENSITIVE_OPTIONS
+ if (isupper(c))
+ c = tolower(c);
+#endif
+ if (c != ':' && c != OPTION_CHAR && (cp = strchr(opts, c)) != NULL
+ && cp[1] == ':' && argv[i][2] == 0 && i < argc - 1) {
+ int j;
+ char *temp1 = argv[i];
+ char *temp2 = argv[i+1];
+ for (j = i - 1; j >= optind; j--)
+ argv[j+2] = argv[j];
+ argv[optind] = temp1;
+ argv[optind+1] = temp2;
+ }
+ else {
+ int j;
+ char *temp = argv[i];
+ for (j = i - 1; j >= optind; j--)
+ argv[j+1] = argv[j];
+ argv[optind] = temp;
+ }
+ }
+ else
+#endif
+ return EOF;
+ }
+ if ((argv[optind][0] == OPTION_CHAR && argv[optind][1] == OPTION_CHAR
+ && argv[optind][2] == '\0')
+#ifdef SWITCHAR
+ || (argv[optind][0] == switchar && argv[optind][1] == switchar
+ && argv[optind][2] == '\0')
+#endif
+ ) {
+ optind++;
+ return(EOF);
+ }
+ }
+ optopt = c = argv[optind][sp];
+#ifdef CASE_INSENSITIVE_OPTIONS
+ if (
+#ifdef USE_ISASCII
+ isascii(c) &&
+#endif /* USE_ISASCII */
+ isupper((unsigned char)c))
+ optopt = c = tolower((unsigned char)c);
+#endif /* CASE_INSENSITIVE_OPTIONS */
+ if (c == ':' || (cp = strchr(opts, c)) == NULL) {
+ if (argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ message = ": illegal option -- ";
+ goto bad;
+ }
+ if (*++cp == ':') {
+ if (argv[optind][sp+1] != '\0')
+ optarg = &argv[optind++][sp+1];
+ else if (++optind >= argc) {
+ sp = 1;
+ message = ": option requires an argument -- ";
+ goto bad;
+ }
+ else
+ optarg = argv[optind++];
+ sp = 1;
+ }
+ else {
+ if (argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return c;
+bad:
+ if (opterr) {
+ fputs(argv[0], stderr);
+ fputs(message, stderr);
+ fputc(optopt, stderr);
+ fputc('\n', stderr);
+ }
+ return '?';
+}
+
+#endif /* not HAVE_GETOPT */
+
+/*
+Local Variables:
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: 4
+c-argdecl-indent: 4
+c-label-offset: -4
+tab-width: 4
+End:
+*/
+
diff --git a/usr.bin/sgmls/sgmls/getopt.h b/usr.bin/sgmls/sgmls/getopt.h
new file mode 100644
index 0000000..4856560
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/getopt.h
@@ -0,0 +1,11 @@
+/* Declare getopt() and associated variables. */
+
+/* Don't use prototypes in case some system header file has a
+conflicting definition. Systems differ on how they declare the second
+parameter. */
+
+extern int getopt();
+
+extern char *optarg;
+extern int optind;
+extern int opterr;
diff --git a/usr.bin/sgmls/sgmls/keyword.h b/usr.bin/sgmls/sgmls/keyword.h
new file mode 100644
index 0000000..6c092f0
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/keyword.h
@@ -0,0 +1,22 @@
+/* KEYWORD.H: Definitions for markup declaration keyword processing.
+*/
+/* Default value types for attribute definition list declaration.
+*/
+#define DNULL 1 /* Default value: implied attribute. */
+#define DREQ 2 /* Default value: required attribute. */
+#define DCURR 3 /* Default value: current attribute. */
+#define DCONR 4 /* Default value: content reference attribute. */
+#define DFIXED 5 /* Default value: fixed attribute. */
+
+/* External identifier types for entity and notation declarations.
+*/
+#define EDSYSTEM 1 /* SYSTEM (but not PUBLIC) identifier specified.*/
+#define EDPUBLIC 2 /* PUBLIC (but not SYSTEM) identifier specified.*/
+#define EDBOTH 3 /* PUBLIC and also SYSTEM identifiers specified.*/
+
+/* Marked section keywords.
+*/
+#define MSTEMP 1
+#define MSRCDATA 2
+#define MSCDATA 3
+#define MSIGNORE 4
diff --git a/usr.bin/sgmls/sgmls/latin1.h b/usr.bin/sgmls/sgmls/latin1.h
new file mode 100644
index 0000000..c6df696
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/latin1.h
@@ -0,0 +1,37 @@
+/* SGML Character Use: ISO Latin 1.
+*/
+#define EOFCHAR '\032' /* FUNCTION: EE (entity end: files). */
+#define EOBCHAR '\034' /* NONCHAR: EOB (file entity: end of buffer. */
+#define RSCHAR '\012' /* FUNCTION: RS (record start). */
+#define RECHAR '\015' /* FUNCTION: RE (record end). */
+#define TABCHAR '\011' /* FUNCTION: TAB (horizontal tab). */
+#define SPCCHAR '\040' /* FUNCTION: SPACE (horizontal space). */
+#define GENRECHAR '\010' /* NONCHAR: Generated RE. */
+#define DELCDATA '\035' /* NONCHAR: Delimiter for CDATA entity in
+ attribute value. */
+#define DELSDATA '\036' /* NONCHAR: Delimiter for SDATA entity in
+ attribute value. */
+#define DELNONCH '\037' /* NONCHAR: non-SGML character prefix. */
+
+/* These two macros are used to handle non-SGML characters. A non-SGML
+by character is represented by a DELNONCH character followed by
+SHIFTNON(original_character). SHIFTNON must transform any character
+in the set 0, EOFCHAR, EOBCHAR, GENRECHAR, DELCDATA, DELSDATA,
+DELNONCH into a character that is not one of the set 0, EOFCHAR,
+EOBCHAR. Furthermore UNSHIFTNON(SHIFTNON(c)) must be equal to c for
+every character c in the former set. */
+/* This is a simple definition that works for ASCII-like character sets. */
+#define SHIFTNON(ch) ((UNCH)(ch) | 0100)
+#define UNSHIFTNON(ch) ((UNCH)(ch) & ~0100)
+
+/* A canonical NONSGML character. The character number that is shunned
+in the reference concrete syntax and is not the number of a
+significant (in the reference concrete syntax) character nor one of
+the above characters nor 0. */
+#define CANON_NONSGML 255
+
+/* A canonical DATACHAR character. The character number that is not
+shunned in the reference concrete syntax and is not the number of a
+significant (in the reference concrete syntax) SGML character nor one
+of the above characters. */
+#define CANON_DATACHAR 254
diff --git a/usr.bin/sgmls/sgmls/lexcode.h b/usr.bin/sgmls/sgmls/lexcode.h
new file mode 100644
index 0000000..d34e3e6
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lexcode.h
@@ -0,0 +1,12 @@
+/* Definitions of lexical codes needed by both lextaba.c and lexrf.c. */
+
+#define FCE 27 /* FRE Free character in use as an entity reference */
+#define FRE 0 /* FREECHAR that is not in a CON delimiter-in-context. */
+#define LITC 21 /* LIT LITA PIC or EE in use as a literal terminator */
+#define MINLITC 13 /* LIT LITA as literal terminator in minimum data */
+#define MSC3 15 /* ] Also MSC[2]. */
+#define NET 17 /* / When enabled. */
+#define ETI 16 /* / Actually ETAGO[2] */
+#define SPCR 19 /* Space in use as SR8. */
+#define TGO2 25 /* < TAGO; also MDO[1], PIO[1] */
+#define CDE 11 /* NONSGML delcdata CDATA/SDATA delimiter */
diff --git a/usr.bin/sgmls/sgmls/lexrf.c b/usr.bin/sgmls/sgmls/lexrf.c
new file mode 100644
index 0000000..643b336
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lexrf.c
@@ -0,0 +1,125 @@
+/* LEXRF: Lexical tables for reference concrete syntax.
+*/
+
+#include "config.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "synxtrn.h" /* Declarations for concrete syntax constants. */
+#include "action.h" /* Action names for all parsing. */
+#include "lexcode.h"
+
+static UNCH SRTAB[] = { TABCHAR, '\0' };
+static UNCH SRRE[] = { RECHAR, '\0' };
+static UNCH SRRS[] = { RSCHAR, '\0' };
+static UNCH SRRSB[] = { RSCHAR, 'B', '\0' };
+static UNCH SRRSRE[] = { RSCHAR, RECHAR, '\0' };
+static UNCH SRRSBRE[] = { RSCHAR, 'B', RECHAR, '\0' };
+static UNCH SRBRE[] = { 'B', RECHAR, '\0' };
+
+struct lexical lex = { /* Delimiter set constants for parser use. */
+ { /* Markup strings for text processor use. */
+ (UNCH *)"\4&#", /* LEXCON markup string: CRO */
+ (UNCH *)"[", /* LEXCON markup string: DSO */
+ (UNCH *)"\3&", /* LEXCON markup string: ERO */
+ (UNCH *)"\4</", /* LEXMARK markup string: end-tag */
+ (UNCH *)"\3\"", /* LEXMARK markup string: LIT */
+ (UNCH *)"\3'", /* LEXMARK markup string: LITA */
+ (UNCH *)"\3>", /* LEXCON markup string: MDC */
+ (UNCH *)"\4<!", /* LEXCON markup string: MDO */
+ (UNCH *)"\5]]>", /* LEXCON markup string: mse */
+ (UNCH *)"\5<![", /* LEXCON markup string: mss */
+ (UNCH *)"\13<![CDATA[", /* LEXCON markup string: mss CDATA */
+ (UNCH *)"\14<![RCDATA[", /* LEXCON markup string: mss RCDATA */
+ (UNCH *)"\3>", /* LEXCON markup string: PIC */
+ (UNCH *)"\4<?", /* LEXCON markup string: PIO */
+ (UNCH *)"\3;", /* LEXGRP markup string: ref close. */
+ (UNCH *)"\3<", /* LEXMARK markup string: start-tag */
+ (UNCH *)"\3>", /* LEXMARK markup string: TAGC */
+ (UNCH *)"\3=", /* LEXMARK markup string: VI */
+ 3, /* LEXMARK: length of null end-tag. */
+ 2 /* LEXMARK: length of null start-tag. */
+ },
+ { /* Short reference delimiters. */
+ { /* Short reference delimiter table. */
+ {(UNCH *)"", SRCT}, /* Dummy entry to store SR count. */
+ {SRTAB, 1}, /* TAB */
+ {SRRE, 2}, /* RE */
+ {SRRS, 3}, /* RS */
+ {SRRSB, 4}, /* Leading blanks */
+ {SRRSRE, 5}, /* Null record */
+ {SRRSBRE, 6}, /* Blank record */
+ {SRBRE, 7}, /* Trailing blanks */
+ {(UNCH *)" ", 8}, /* Space */
+ {(UNCH *)"BB", 9}, /* Two or more blanks */
+ {(UNCH *)"\"", 10}, /* Quotation mark (first data character) */
+ {(UNCH *)"#", 11}, /* Number sign */
+ {(UNCH *)"%", 12}, /* FCE CHARACTERS start here */
+ {(UNCH *)"'", 13},
+ {(UNCH *)"(", 14},
+ {(UNCH *)")", 15},
+ {(UNCH *)"*", 16},
+ {(UNCH *)"+", 17},
+ {(UNCH *)",", 18},
+ {(UNCH *)"-", 19}, /* Hyphen */
+ {(UNCH *)"--", 20}, /* Two hyphens */
+ {(UNCH *)":", 21},
+ {(UNCH *)";", 22},
+ {(UNCH *)"=", 23},
+ {(UNCH *)"@", 24},
+ {(UNCH *)"[", 25},
+ {(UNCH *)"]", 26},
+ {(UNCH *)"^", 27},
+ {(UNCH *)"_", 28}, /* Low line */
+ {(UNCH *)"{", 29},
+ {(UNCH *)"|", 30},
+ {(UNCH *)"}", 31},
+ {(UNCH *)"~", 32},
+ {0, 0}
+ },
+ { /* Printable form of unprintable SR delims.*/
+ "", /* Dummy entry to balance s.dtb. */
+ "&#TAB;", /* TAB */
+ "&#RE;", /* RE */
+ "&#RS;", /* RS */
+ "&#RS;B", /* Leading blanks */
+ "&#RS;&#RE;", /* Null record */
+ "&#RS;B&#RE;", /* Blank record */
+ "B&#RE;", /* Trailing blanks */
+ "&#SPACE;" /* Space */
+ },
+ 12, /* LEXCNM: Index of first FCE in srdeltab. */
+ 20, /*LEXCNM:Index of "two hyphens" in srdeltab*/
+ 10, /* LEXCNM: Index of first SR with data char. */
+ 19, /* LEXCNM: Index of hyphen in srdeltab. */
+ SRNPRT+1, /* LEXCNM: Index of 1st printable SR. */
+ 8, /* LEXCNM: Index of space in srdeltab. */
+ 25, /* LEXCNM: Index of left bracket in srdeltab. */
+ 26, /* LEXCNM: Index of right bracket in srdeltab. */
+ }, /* End of short reference delimiters. */
+ { /* General delimiter characters. */
+ GENRECHAR, /*LEXCNM:(BS)Generated RE; can't be markup.*/
+ '"', /* LEXMARK: Char used as LIT delimiter.*/
+ '\'', /* LEXMARK: Char used as LITA delimiter.*/
+ '>', /* LEXLMS: Char used as MDC delimiter.*/
+ ']', /* LEXLMS: Char used as MSC when enabled.*/
+ '/', /* LEXCON: Char used as NET when enabled.*/
+ '%', /* LEXMARK: Char used as PERO delimiter. */
+ '>', /* LEXCON: Char used as PIC delimiter.*/
+ '<' /* LEXCON: Char used as TAGO when enabled.*/
+ },
+ { /* Lexical table code assignments. */
+ FCE, /* LEXCNM: FRE char as entity reference.*/
+ FRE, /* LEXLMS: Free character not an entity ref.*/
+ LITC, /* LEXLMS: Literal close delimiter enabled. */
+ MINLITC, /* LEXMIN: Literal close delimiter enabled. */
+ MSC3, /* LEXLMS: Marked section close delim enabled. */
+ NET, /* LEXCON: Null end-tag delimiter enabled. */
+ ETI, /* LEXCON: NET disabled; still used as ETI. */
+ SPCR, /* LEXCNM: Space in use as SHORTREF delim. */
+ TGO2, /* LEXCON: Tag open delimiter enabled. */
+ CDE /* LEXLMS: CDATA/SDATA delimiters. */
+ }
+};
+
+UNCH *lextabs[] = {
+ lexcnm, lexcon, lexgrp, lexlms, lexmark, lexsd, lextoke, lexmin, 0
+};
diff --git a/usr.bin/sgmls/sgmls/lextaba.c b/usr.bin/sgmls/sgmls/lextaba.c
new file mode 100644
index 0000000..a851d85
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lextaba.c
@@ -0,0 +1,750 @@
+/* lextaba.c: lexical tables for ASCII. */
+
+/* These tables are munged by setnonsgml(). */
+
+#include "config.h"
+#include "entity.h"
+#include "lexcode.h"
+#include "sgmldecl.h"
+
+/* LEXCNM: Lexical table for mixed content (PCBCONM) parse.
+*/
+/* Symbols for SGML character set divisions and function characters. */
+#define NU 1 /* NUMERAL Numerals */
+#define NMC 2 /* LC/UCNMCHAR . - Period and hyphen */
+#define NMS 3 /* LC/UCNMSTRT Lower and uppercase letters */
+#define SPC 4 /* SPACE 32 Space */
+#define NON 5 /* NONSGML 0-31 127 255 Unused, except for: */
+#define EE 6 /* NONSGML 00 26 Entity end (end of file) */
+#define EOB 7 /* NONSGML 28 End disk buffer */
+#define RS 8 /* Function 10 Line feed */
+#define RE 9 /* Function 13 Carrier return */
+#define SEP 10 /* SEPCHAR 09 TAB: horizontal tab */
+#define NSC 12 /* NONSGML delnonch Non-SGML character prefix */
+
+/* Symbols for SGML delimiter roles in CON and CXT.
+ ETI and NET must be the same in LEXCNM and LEXCON.
+ FRE characters are changed to FCE if an FCE entity is declared.
+ They are changed back to FRE when the entity is canceled.
+*/
+#define ERO 13 /* & Also CRO[1] */
+#define NMRE 14 /* 08 Generated non-markup RE */
+#define COM 15 /* - For MDO context; also SR19 and SR20. */
+#undef LIT1
+#define LIT1 18 /* " SR10 */
+#define MDO 20 /* ! Actually MDO[2] */
+#define MSC1 21 /* ] Both MSC[1] and MSC[2]; also SR26. */
+#define MSO 22 /* [ For MDO context; also SR25. */
+#define PIO 23 /* ? Actually PIO[2] */
+#define RNI 24 /* # For CRO[2]; also SR11. */
+#define TGC1 25 /* > For TAGO and MSC context; also MDC, PIC */
+#define TGO1 26 /* < TAGO; also MDO[1], PIO[1] */
+
+UNCH lexcnm[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE, NON, NON, NON, NON, NON, NON, NON, NMRE,SEP, RS, NON, NON, RE, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE, NON, EOB, NON, NON, NSC, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, MDO, LIT1,RNI, FRE, FRE ,ERO, FRE, FRE, FRE, FRE, FRE, FRE, COM, NMC, ETI, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU , NU , NU , NU , NU , NU , NU , NU , NU , NU , FRE, FRE, TGO1,FRE, TGC1,PIO, /*
+@ A B C D E F G H I J K L M N O */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, MSO, FRE, MSC1,FRE, FRE, /*
+` a b c d e f g h i j k l m n o */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, FRE, FRE, FRE, FRE, NON,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, NON
+};
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti lit spcr mdo msc mso net pio rni tagc tago fce */
+#undef ERO
+#undef NMRE
+#undef COM
+#undef LIT1
+/* def SPCR*/
+#undef MDO
+#undef MSC1
+#undef MSO
+#undef PIO
+#undef RNI
+#undef TGC1
+/* def TGO1*/
+/* def FCE*/
+/* LEXCON: Lexical table for RCDATA and CDATA content (PCBCON?),
+ prolog (PCBPRO), and nested declaration set (PCBMDS) parses.
+ Note: NMC is same as FRE; kept for consistency with LEXCNM and LEXLMS.
+*/
+/* Symbols for SGML character set divisions and function characters. */
+/* Same as for LEXCNM. */
+
+/* Symbols for SGML delimiter roles in CON, CXT, and DS.
+ ETI and NET must be the same in LEXCNM and LEXCON.
+ FRE characters are changed to FCE if an FCE entity is declared.
+ They are changed back to FRE when the entity is canceled.
+*/
+#define ERO 13 /* & Also CRO[1] */
+#define NMRE 14 /* 08 Generated non-markup RE */
+#define COM 15 /* - For MDO context. */
+/*#define ETI 16 / Actually ETAGO[2] */
+/*#define NET 17 / When enabled. */
+#define MDO 18 /* ! Actually MDO[2] */
+#define MSC2 19 /* ] Both MSC[1] and MSC[2]. */
+#define MSO 20 /* [ For MDO context. */
+#define PERO 21 /* % For prolog */
+#define PIO 22 /* ? Actually PIO[2] */
+#define RNI 23 /* # For CRO[2]. */
+#define TGC2 24 /* > For TAGO and MSC context; also MDC, PIC */
+
+UNCH lexcon[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE, NON, NON, NON, NON, NON, NON, NON, NMRE,SEP, RS, NON, NON, RE, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE, NON, EOB, NON, NON, NSC, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, MDO, FRE, RNI, FRE, PERO,ERO, FRE, FRE, FRE, FRE, FRE, FRE, COM, NMC, ETI, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU , NU , NU , NU , NU , NU , NU , NU , NU , NU , FRE, FRE, TGO2,FRE, TGC2,PIO, /*
+@ A B C D E F G H I J K L M N O */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, MSO, FRE, MSC2,FRE, FRE, /*
+` a b c d e f g h i j k l m n o */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, FRE, FRE, FRE, FRE, NON,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, NON
+};
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+#undef FRE
+#undef NU
+#undef NMC
+#undef NMS
+#undef SPC
+#undef NON
+#undef EE
+#undef EOB
+#undef RS
+#undef RE
+#undef SEP
+#undef NSC
+#undef ERO
+#undef NMRE
+#undef COM
+/* def ETI*/
+/* def NET*/
+#undef MDO
+#undef MSC2
+#undef MSO
+#undef PERO
+#undef PIO
+#undef RNI
+#undef TGC2
+/* LEXGRP: Lexical table for group parses, including PCBREF.
+*/
+/* Symbols for SGML character set divisions. */
+#define BIT 0 /* Bit combinations (not NONCHAR) not allowed in a group. */
+#define NMC 1 /* NAMECHAR . - Period, underscore, and numerals */
+#define NMS 2 /* NAMESTRT Lower and uppercase letters */
+#define RE 3 /* Function 13 Carrier return */
+#define SPC 4 /* SPACE 32 09 Space; includes TAB */
+#define NON 5 /* NONCHAR 0-31 127 255 Unused, except for: */
+#define EE 6 /* Function 26 00 EE: entity end (end of file) */
+#define EOB 7 /* NONCHAR 28 End disk buffer. */
+#define RS 8 /* Function 10 RS: record start (line feed) */
+
+/* Symbols for SGML delimiter roles in GRP. */
+#define AND1 9 /* & */
+#define GRPC 10 /* ) */
+#define GRPO 11 /* ( */
+#undef LIT2
+#define LIT2 12 /* " For datatags. */
+#define LITA 13 /* ' For datatags. */
+#define DTGC 14 /* ] For datatags. */
+#define DTGO 15 /* [ For datatags. */
+#define OPT1 16 /* ? */
+#define OR1 17 /* | */
+#define PERO 18 /* % */
+#define PLUS 19 /* + */
+#define REP1 20 /* * */
+#define RNI 21 /* # For #CHARS */
+#define SEQ1 22 /* , */
+#define REFC 23 /* ; For references */
+
+UNCH lexgrp[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE , NON, NON, NON, NON, NON, NON, NON, NON, SPC, RS, NON, NON, RE, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE , NON, EOB, NON, NON, NON, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, BIT, LIT2,RNI, BIT, PERO,AND1,LITA,GRPO,GRPC,REP1,PLUS,SEQ1,NMC, NMC, BIT, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NMC, NMC, NMC, NMC, NMC, NMC, NMC, NMC, NMC, NMC, BIT, REFC,BIT, BIT, BIT, OPT1,/*
+@ A B C D E F G H I J K L M N O */
+BIT, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, DTGO,BIT, DTGC,BIT, BIT, /*
+` a b c d e f g h i j k l m n o */
+BIT, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, BIT, OR1, BIT, BIT, NON,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, NON
+};
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+#undef BIT
+#undef NMC
+#undef NMS
+#undef RE
+#undef SPC
+#undef NON
+#undef EE
+#undef EOB
+#undef RS
+#undef AND1
+#undef GRPC
+#undef GRPO
+#undef LIT2
+#undef LITA
+#undef DTGC
+#undef DTGO
+#undef OPT1
+#undef OR1
+#undef PERO
+#undef PLUS
+#undef REP1
+#undef RNI
+#undef SEQ1
+#undef REFC
+/* LEXLMS: Lexical table for literal parses and marked sections.
+*/
+/* Symbols for SGML character set divisions and function characters.
+*/
+#define FRE 0 /* Free char: not in a delimiter or minimum literal. */
+#define NU 1 /* Numeral Numerals */
+#undef MIN
+#define MIN 2 /* Minimum literal '()+,-./:?= */
+#define NMS 3 /* LC/UCNMSTRT Lower and uppercase letters */
+#define SPC 4 /* SPACE 32 Space */
+#define NON 5 /* NONSGML 0-31 127 255 Unused, except for: */
+#define EE 6 /* NONSGML 00 26 Entity end (end of file) */
+#define EOB 7 /* NONSGML 28 End disk buffer */
+#define RS 8 /* Function 10 Line feed */
+#define RE 9 /* Function 13 Carrier return */
+#define SEP 10 /* SEPCHAR 09 TAB: horizontal tab */
+/*#define CDE 11 NONSGML delcdata CDATA/SDATA delimiter */
+#define NSC 12 /* NONSGML delnonch Non-SGML character prefix */
+/* Symbols for SGML delimiter roles in LIT, PI, and marked sections.
+ Either LIT, LITA, PIC, or EE, is changed to LITC when a literal is begun.
+ It is changed back when the LITC occurs (i.e., when the literal ends).
+*/
+#define ERO 13 /* & */
+#define MDO 14 /* ! Actually MDO[2] */
+#define MSO 16 /* [ For MDO context. */
+#define PERO 17 /* % For prolog. */
+#define RNI 18 /* # For CRO[2] */
+#define TGC3 19 /* > Also MDC for MSC context. */
+#define TGO3 20 /* < TAGO; also MDO[1] */
+
+/* Room has been left in the parse tables in case re-parsing of text
+ is eventually supported (i.e., saved parsed text is used by the
+ application to create a new SGML document, but CDATA and SDATA
+ entities in literals, and non-SGML characters, are left in their
+ parsed state to avoid the overhead of reconstituting the original
+ markup). In such a case, the two non-SGML characters DELCDATA and
+ DELSDATA are changed to CDE.
+ NOTE: The idea is a bad one, because the generated document would
+ be non-conforming, as it would contain non-SGML characters.
+*/
+UNCH lexlms[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE, NON, NON, NON, NON, NON, NON, NON, NON ,SEP, RS, NON, NON, RE, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE, NON, EOB, NON, NON, NSC, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, MDO, FRE, RNI, FRE, PERO,ERO, MIN, MIN, MIN, FRE, MIN, MIN, MIN, MIN, MIN, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU , NU , NU , NU , NU , NU , NU , NU , NU , NU , MIN, FRE, TGO3,MIN, TGC3,MIN, /*
+@ A B C D E F G H I J K L M N O */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, MSO, FRE, MSC3,FRE, FRE, /*
+` a b c d e f g h i j k l m n o */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, FRE, FRE, FRE, FRE, NON,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, NON
+};
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tago tagc litc */
+/* def FRE*/
+#undef NU
+#undef MIN
+#undef NMS
+#undef SPC
+#undef NON
+#undef EE
+#undef EOB
+#undef RS
+#undef RE
+#undef SEP
+/* def CDE*/
+/* def NSC*/
+#undef ERO
+#undef MDO
+/* def MSC3*/
+#undef MSO
+#undef PERO
+#undef RNI
+#undef TGC3
+#undef TGO3
+/* def LITC*/
+/* LEXMIN: Lexical table for minimum data literals.
+*/
+/* Symbols for SGML character set divisions and function characters.
+*/
+#define FRE 0 /* Free char: not in a delimiter or minimum literal. */
+#define NU 1 /* Numeral Numerals */
+#undef MIN
+#define MIN 2 /* Minimum literal '()+,-./:?= */
+#define NMS 3 /* LC/UCNMSTRT Lower and uppercase letters */
+#define SPC 4 /* SPACE 32 Space */
+#define NON 5 /* NONSGML 0-31 127 255 Unused, except for: */
+#define EE 6 /* NONSGML 00 26 Entity end (end of file) */
+#define EOB 7 /* NONSGML 28 End disk buffer */
+#define RS 8 /* Function 10 Line feed */
+#define RE 9 /* Function 13 Carrier return */
+#define SEP 10 /* SEPCHAR 09 TAB: horizontal tab */
+/*#define CDE 11 NONSGML delcdata CDATA/SDATA delimiter */
+#define NSC 12 /* NONSGML delnonch Non-SGML character prefix */
+/* Either LIT or LITA changed to LITC when a literal is begun.
+ It is changed back when the LITC occurs (i.e., when the literal ends).
+*/
+UNCH lexmin[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE, NON, NON, NON, NON, NON, NON, NON, NON ,SEP, RS, NON, NON, RE, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE, NON, EOB, NON, NON, NSC, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, FRE, FRE, FRE, FRE, FRE, FRE, MIN, MIN, MIN, FRE, MIN, MIN, MIN, MIN, MIN, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU , NU , NU , NU , NU , NU , NU , NU , NU , NU , MIN, FRE, FRE, MIN, FRE, MIN, /*
+@ A B C D E F G H I J K L M N O */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, FRE, FRE, FRE, FRE, FRE, /*
+` a b c d e f g h i j k l m n o */
+FRE, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, FRE, FRE, FRE, FRE, NON,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE,
+FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, FRE, NON
+};
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tago tagc litc */
+/* def FRE*/
+#undef NU
+#undef MIN
+#undef NMS
+#undef SPC
+#undef NON
+#undef EE
+#undef EOB
+#undef RS
+#undef RE
+#undef SEP
+/* def CDE*/
+/* def NSC*/
+/* def LITC*/
+/* LEXMARK: Lexical scan table for markup: PCBMD? and PCB?TAG.
+*/
+/* Symbols for SGML character set divisions. */
+#define BIT 0 /* Bit combinations not allowed; includes ESC SO SI */
+#define NMC 1 /* NAMECHAR . _ Period and underscore */
+#define NU 2 /* NUMERAL Numerals */
+#define NMS 3 /* NAMESTRT Lower and uppercase letters */
+#define SPC 4 /* SPACE 32 13 09 Space; includes RE TAB */
+#define NON 5 /* NONCHAR 0-31 127 255 Unused, except for: */
+#define EE 6 /* Function 26 00 EE: entity end (end of file) */
+#define EOB 7 /* NONCHAR 28 End disk buffer. */
+#define RS 8 /* Function 10 RS: record start (line feed) */
+
+/* Symbols for SGML delimiter roles in MD and TAG. */
+#define COM1 9 /* - Actually COM[1]; also COM[2], MINUS. */
+#define ETIB 10 /* / ETI; actually ETAGO[2]. */
+#define GRPO 11 /* ( */
+#define LIT3 12 /* " */
+#define LITA 13 /* ' */
+#define DSO 14 /* [ */
+#define DSC1 15 /* ] For data attribute specifications */
+#define PERO 16 /* % */
+#define PLUS 17 /* + */
+#define REFC 18 /* ; For references */
+#define RNI 19 /* # Also CRO[2] */
+#define TGC4 20 /* > Also MDC, PIC */
+#define TGO4 21 /* < TAGO; also MDO[1] */
+#define VI 22 /* = */
+
+UNCH lexmark[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE , NON, NON, NON, NON, NON, NON, NON, NON, SPC, RS, NON, NON, SPC, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE , NON, EOB, NON, NON, NON, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, BIT, LIT3,RNI, BIT, PERO,BIT, LITA,GRPO,BIT, BIT, PLUS,BIT, COM1,NMC ,ETIB,/*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU, NU, NU, NU, NU, NU, NU, NU, NU, NU, BIT, REFC,TGO4,VI, TGC4,BIT, /*
+@ A B C D E F G H I J K L M N O */
+BIT, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, DSO, BIT, DSC1, BIT, BIT, /*
+` a b c d e f g h i j k l m n o */
+BIT, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, BIT, BIT, BIT, BIT, NON,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT,
+BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, BIT, NON
+};
+/* bit nmc nu nms spc non ee eob rs com eti grpo lit lita
+ dso pero plus refc rni tagc tago vi */
+#undef BIT
+#undef NMC
+#undef NU
+#undef NMS
+#undef SPC
+#undef NON
+#undef EE
+#undef EOB
+#undef RS
+#undef COM1
+#undef ETIB
+#undef GRPO
+#undef LIT3
+#undef LITA
+#undef DSO
+#undef DSC
+#undef PERO
+#undef PLUS
+#undef REFC
+#undef RNI
+#undef TGC4
+#undef TGO4
+#undef VI
+/* LEXSD: Lexical scan table for SGML declaration.
+*/
+
+/* Symbols for SGML character set divisions. */
+#define SIG 0 /* Significant SGML characters. */
+#define DAT 1 /* DATACHAR Not significant, and not non-sgml. */
+#define NU 2 /* NUMERAL Numerals */
+#define NMS 3 /* NAMESTRT Lower and uppercase letters */
+#define SPC 4 /* SPACE 32 13 09 Space; includes RE TAB */
+#define NON 5 /* NONCHAR NONSGML */
+#define EE 6 /* Function 26 00 EE: entity end (end of file) */
+#define EOB 7 /* NONCHAR 28 End disk buffer. */
+#define RS 8 /* Function 10 RS: record start (line feed) */
+/* Symbols for SGML delimiter roles in SGML declaration. */
+#define COM1 9 /* - Actually COM[1]; also COM[2]. */
+#define LIT3 10 /* " */
+#define LITA 11 /* ' */
+#define TGC4 12 /* > Also MDC, PIC */
+
+UNCH lexsd[256] = { /*
+000 001       bs tab lf home ff cr so si */
+EE , NON, NON, NON, NON, NON, NON, NON, NON, SPC, RS, NON, NON, SPC, NON, NON, /*
+          eof esc rt left up down */
+NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, EE , NON, EOB, NON, NON, NON, /*
+032 ! " # $ % & ' ( ) * + , - . / */
+SPC, SIG, LIT3,SIG, DAT, SIG ,SIG, LITA,SIG, SIG, SIG, SIG, SIG, COM1,SIG ,SIG,/*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU, NU, NU, NU, NU, NU, NU, NU, NU, NU, SIG, SIG, SIG, SIG, TGC4,SIG, /*
+@ A B C D E F G H I J K L M N O */
+SIG, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, SIG, DAT, SIG, SIG, SIG, /*
+` a b c d e f g h i j k l m n o */
+DAT, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, SIG, SIG, SIG, SIG, NON,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT,
+DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, DAT, NON
+};
+
+#undef SIG
+#undef DAT
+#undef NON
+#undef NU
+#undef NMS
+#undef SPC
+#undef EE
+#undef EOB
+#undef RS
+#undef COM1
+#undef LIT3
+#undef LITA
+#undef TGC4
+
+/* LEXTRAN: Translation table for SGML names.
+*/
+UNCH lextran[256] = { /*
+000 001       bs tab lf home ff cr so si */
+0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , /*
+          eof esc rt left up down */
+16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , /*
+space! " # $ % & ' ( ) * + , - . / */
+32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 , /*
+@ A B C D E F G H I J K L M N O */
+64 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , 73 , 74 , 75 , 76 , 77 , 78 , 79 , /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+80 , 81 , 82 , 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 91 , 92 , 93 , 94 , 95 , /*
+` a b c d e f g h i j k l m n o */
+96 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , 73 , 74 , 75 , 76 , 77 , 78 , 79 , /*
+p q r s t u v w x y z { | } ~ 127 */
+80 , 81 , 82 , 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+/* LEXTOKE: Lexical class table for tokenization scan.
+*/
+#include "lextoke.h" /* Symbols for tokenization lexical classes. */
+UNCH lextoke[256] = { /*
+
+000 001       bs tab lf home ff cr   */
+INV, INV, INV, INV, INV, INV, INV, INV, INV, SEP, REC, INV, INV, REC, INV, INV, /*
+          eof esc rt left up down */
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, EOB, INV, INV, INV, /*
+space! " # $ % & ' ( ) * + , - . / */
+SP , INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, NMC, NMC, INV, /*
+0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+NU , NU , NU , NU , NU , NU , NU , NU , NU , NU , INV, INV, INV, INV, INV, INV, /*
+@ A B C D E F G H I J K L M N O */
+INV, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+P Q R S T U V W X Y Z [ \ ] ^ _ */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, INV, INV, INV, INV, INV, /*
+` a b c d e f g h i j k l m n o */
+INV, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, /*
+p q r s t u v w x y z { | } ~ 127 */
+NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, NMS, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV,
+INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV
+};
+
+/* This table maps ASCII to the system character set. */
+int iso646charset[] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+/* This table maps the C0 part of ISO646 to the system character set. */
+/* We through in 32 and 127 for free, since ISO 2022 maps them in
+automatically. */
+int iso646C0charset[] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+32, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, 127,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+/* This table maps the G0 part of ISO646 to the system character set. */
+int iso646G0charset[] = {
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso8859_1charset[] = {
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso6429C1charset[] = {
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
diff --git a/usr.bin/sgmls/sgmls/lextabe.c b/usr.bin/sgmls/sgmls/lextabe.c
new file mode 100644
index 0000000..5cfe0de
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lextabe.c
@@ -0,0 +1,357 @@
+/* This file was automatically generated by genlex. Do not edit. */
+
+#include "config.h"
+#include "entity.h"
+#include "sgmldecl.h"
+
+UNCH lexcnm[] = {
+ 6, 5, 5, 5, 5, 10, 5, 5, 5, 5, 5, 5, 5, 9, 5, 5,
+ 5, 5, 5, 5, 5, 5, 14, 5, 5, 5, 5, 5, 7, 5, 5, 12,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 26, 0, 0, 0,
+13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0,
+15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 23,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 18,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lexcon[] = {
+ 6, 5, 5, 5, 5, 10, 5, 5, 5, 5, 5, 5, 5, 9, 5, 5,
+ 5, 5, 5, 5, 5, 5, 14, 5, 5, 5, 5, 5, 7, 5, 5, 12,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 25, 0, 0, 0,
+13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0,
+15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 24, 22,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 20, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lexgrp[] = {
+ 6, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 5,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 11, 19, 17,
+ 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 10, 23, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 18, 0, 0, 16,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 13, 0, 12,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 15, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lexlms[] = {
+ 6, 5, 5, 5, 5, 10, 5, 5, 5, 5, 5, 5, 5, 9, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 12,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 20, 2, 2, 0,
+13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 2, 0, 0,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 17, 0, 19, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 18, 0, 2, 2, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lexmark[] = {
+ 6, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 5,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 21, 11, 17, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0,
+ 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 20, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 13, 22, 12,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 14, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lexsd[] = {
+ 6, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 5,
+ 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6,
+ 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1,
+ 9, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 12, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 11, 0, 10,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
+ 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 0, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 5,
+};
+
+UNCH lextoke[] = {
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0,
+};
+
+UNCH lexmin[] = {
+ 6, 5, 5, 5, 5, 10, 5, 5, 5, 5, 5, 5, 5, 9, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 12,
+ 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5,
+};
+
+UNCH lextran[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 193, 194, 195, 196, 197, 198, 199, 200, 201, 138, 139, 140, 141, 142, 143,
+144, 209, 210, 211, 212, 213, 214, 215, 216, 217, 154, 155, 156, 157, 158, 159,
+160, 161, 226, 227, 228, 229, 230, 231, 232, 233, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+};
+
+
+int iso646charset[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
+ 64, 90, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
+124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
+215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 173, 224, 189, 176, 109,
+121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
+151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 79, 208, 161, 7,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso646G0charset[] = {
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+ 64, 90, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
+124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
+215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 173, 224, 189, 176, 109,
+121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
+151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 79, 208, 161, 7,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso646G0charset[] = {
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+ 64, 90, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
+124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
+215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 173, 224, 189, 176, 109,
+121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
+151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 79, 208, 161, 7,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso8859_1charset[] = {
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+ 65, 170, 74, 177, 159, 178, 106, 181, 187, 180, 154, 138, 95, 202, 175, 188,
+144, 143, 234, 250, 190, 160, 182, 179, 157, 218, 155, 139, 183, 184, 185, 171,
+100, 101, 98, 102, 99, 103, 158, 104, 116, 113, 114, 115, 120, 117, 118, 119,
+172, 105, 237, 238, 235, 239, 236, 191, 128, 253, 254, 251, 252, 186, 174, 89,
+ 68, 69, 66, 70, 67, 71, 156, 72, 84, 81, 82, 83, 88, 85, 86, 87,
+140, 73, 205, 206, 203, 207, 204, 225, 112, 221, 222, 219, 220, 141, 142, 223,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso646C0charset[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
+ 64, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, 7,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
+
+int iso6429C1charset[] = {
+ 4, 6, 8, 9, 10, 20, 21, 23, 26, 27, 32, 33, 34, 35, 36, 40,
+ 41, 42, 43, 44, 48, 49, 51, 52, 53, 54, 56, 57, 58, 59, 62, 255,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
+};
diff --git a/usr.bin/sgmls/sgmls/lextoke.h b/usr.bin/sgmls/sgmls/lextoke.h
new file mode 100644
index 0000000..d2bcfa0
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lextoke.h
@@ -0,0 +1,10 @@
+/* LEXTOKE.H: Symbols for tokenization lexical classes.
+*/
+#define INV 0 /* Invalid Chars Not allowed in an SGML name. */
+#define REC 1 /* Record Boundary RS and RE. */
+#define SEP 2 /* Separator TAB. */
+#define SP 3 /* SPACE */
+#define NMC 4 /* NAMECHAR . _ Period, underscore (plus NMS, NUM). */
+#define NMS 5 /* NAMESTRT Lower and uppercase letters */
+#define NU 6 /* NUMERAL Numerals */
+#define EOB 7 /* NONCHAR 28 End disk buffer. */
diff --git a/usr.bin/sgmls/sgmls/lineout.c b/usr.bin/sgmls/sgmls/lineout.c
new file mode 100644
index 0000000..794eff8
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lineout.c
@@ -0,0 +1,656 @@
+/* lineout.c -
+ Implements line-oriented output format.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+#include "std.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "adl.h" /* Definitions for attribute list processing. */
+#include "sgmlmain.h" /* Main interface to SGML services. */
+#include "lineout.h"
+#include "appl.h"
+
+static VOID flush_data P((void));
+static VOID define_external_entity P((PNE));
+static VOID define_entity P((UNCH *));
+static VOID handle_attributes P((UNCH *, struct ad *));
+static VOID handle_token_list P((UNCH *, struct ad *, int));
+static VOID handle_single_token P((UNCH *, struct ad *, int));
+static VOID output_notation P((UNCH *, UNCH *, UNCH *));
+static VOID output_internal_entity P((UNCH *, int, UNCH *));
+static VOID output_external_entity P((UNCH *, int, UNIV, UNCH *, UNCH *,
+ UNCH *));
+static VOID output_subdoc P((UNCH *, UNIV, UNCH *, UNCH *));
+#ifdef SUPPORT_SUBDOC
+static VOID process_subdoc P((UNCH *, UNIV));
+#endif /* SUPPORT_SUBDOC */
+static VOID output_record_end P((void));
+static VOID output_pcdata P((UNS, UNCH *));
+static VOID output_cdata P((UNS, UNCH *));
+static VOID output_sdata P((UNS, UNCH *));
+static VOID output_entity_reference P((UNCH *));
+static VOID output_start_tag P((UNCH *));
+static VOID output_end_tag P((UNCH *));
+static VOID output_processing_instruction P((UNS, UNCH *));
+static VOID output_implied_attribute P((UNCH *, UNCH *));
+static char *attribute_type_string P((int));
+static VOID output_begin_attribute P((UNCH *, UNCH *, int));
+static VOID output_attribute_token P((UNS, UNCH *));
+static VOID output_end_attribute P((void));
+static VOID print_data P((UNS, UNCH *, int));
+static VOID print_string P((UNS, UNCH *, int));
+static VOID print_id P((UNIV, UNCH *, UNCH *));
+static VOID print_filename P((char *));
+static VOID output_location P((void));
+static VOID output_appinfo P((UNS, UNCH *));
+
+static int have_data = 0;
+static char *current_filename = 0;
+static unsigned long current_lineno = 0;
+
+VOID process_document(subdocsw)
+int subdocsw;
+{
+ enum sgmlevent rc;
+ struct rcbtag rcbtag;
+ struct rcbdata rcbdaf;
+
+ while ((rc = sgmlnext(&rcbdaf, &rcbtag)) != SGMLEOD) {
+#ifdef SUPPORT_SUBDOC
+ if (rc == SGMLDAF && !CONTERSW(rcbdaf) && NDESW(rcbdaf)
+ && NEXTYPE(NEPTR(rcbdaf)) == ESNSUB) {
+ if (!suppsw && !sgmlment(NEENAME(NEPTR(rcbdaf))))
+ define_external_entity(NEPTR(rcbdaf));
+ process_subdoc(NEENAME(NEPTR(rcbdaf)) + 1,
+ NEID(NEPTR(rcbdaf)));
+ continue;
+ }
+#endif /* SUPPORT_SUBDOC */
+ if (!suppsw)
+ switch (rc) {
+ case SGMLDAF:
+ if (CONTERSW(rcbdaf))
+ break;
+ if (CDESW(rcbdaf))
+ output_cdata(CDATALEN(rcbdaf), CDATA(rcbdaf));
+ else if (SDESW(rcbdaf))
+ output_sdata(CDATALEN(rcbdaf), CDATA(rcbdaf));
+ else if (NDESW(rcbdaf)) {
+ assert(NEXTYPE(NEPTR(rcbdaf)) != ESNSUB);
+ if (!sgmlment(NEENAME(NEPTR(rcbdaf))))
+ define_external_entity(NEPTR(rcbdaf));
+ output_entity_reference(NEENAME(NEPTR(rcbdaf)) + 1);
+ }
+ else
+ output_pcdata(CDATALEN(rcbdaf), CDATA(rcbdaf));
+ break;
+ case SGMLSTG:
+ if (CONTERSW(rcbtag))
+ break;
+ if (ALPTR(rcbtag))
+ handle_attributes((UNCH *)NULL, ALPTR(rcbtag));
+ output_start_tag(CURGI(rcbtag));
+ break;
+ case SGMLETG:
+ if (CONTERSW(rcbtag))
+ break;
+ output_end_tag(CURGI(rcbtag));
+ break;
+ case SGMLPIS:
+ if (CONTERSW(rcbdaf))
+ break;
+ output_processing_instruction(PDATALEN(rcbdaf),
+ PDATA(rcbdaf));
+ break;
+ case SGMLREF:
+ if (CONTERSW(rcbdaf))
+ break;
+ output_record_end();
+ break;
+ case SGMLAPP:
+ if (CONTERSW(rcbdaf))
+ break;
+ if (!subdocsw)
+ output_appinfo(ADATALEN(rcbdaf), ADATA(rcbdaf));
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+/* Output an indication that the document was conforming. */
+
+VOID output_conforming()
+{
+ if (!suppsw)
+ printf("%c\n", CONFORMING_CODE);
+}
+
+static VOID define_external_entity(p)
+PNE p;
+{
+ if (NEXTYPE(p) == ESNSUB)
+ output_subdoc(NEENAME(p) + 1, NEID(p), NEPUBID(p), NESYSID(p));
+ else {
+ if (!NEDCNMARK(p))
+ output_notation(NEDCN(p) + 1, NEDCNPUBID(p), NEDCNSYSID(p));
+ output_external_entity(NEENAME(p) + 1, NEXTYPE(p), NEID(p),
+ NEPUBID(p), NESYSID(p), NEDCN(p) + 1);
+ if (NEAL(p))
+ handle_attributes(NEENAME(p) + 1, NEAL(p));
+ }
+}
+
+static VOID define_entity(ename)
+UNCH *ename;
+{
+ int rc;
+ PNE np;
+ UNCH *tp;
+
+ if (sgmlment(ename)) /* already defined it */
+ return;
+ rc = sgmlgent(ename, &np, &tp);
+ switch (rc) {
+ case 1:
+ define_external_entity(np);
+ break;
+ case 2:
+ case 3:
+ output_internal_entity(ename + 1, rc == 3, tp);
+ break;
+ }
+}
+
+/* ENT is the name of the entity with which these attributes are associated;
+if it's NULL, they're associated with the next start tag. */
+
+static VOID handle_attributes(ent, al)
+UNCH *ent;
+struct ad *al;
+{
+ int aln;
+
+ for (aln = 1; aln <= ADN(al); aln++) {
+ if (GET(ADFLAGS(al, aln), AERROR))
+ ;
+ else if (GET(ADFLAGS(al, aln), AINVALID))
+ ;
+ else if (ADVAL(al, aln) == NULL)
+ output_implied_attribute(ent, ADNAME(al, aln));
+ else if (ADTYPE(al, aln) >= ATKNLIST)
+ handle_token_list(ent, al, aln);
+ else
+ handle_single_token(ent, al, aln);
+ if (BITON(ADFLAGS(al, aln), AGROUP))
+ aln += ADNUM(al, aln);
+ }
+}
+
+static VOID handle_token_list(ent, al, aln)
+UNCH *ent;
+struct ad *al;
+int aln;
+{
+ UNCH *ptr;
+ int i;
+ if (ADTYPE(al, aln) == AENTITYS) {
+ ptr = ADVAL(al, aln);
+ for (i = 0; i < ADNUM(al, aln); i++) {
+ /* Temporarily make token look like normal
+ name with length and EOS. */
+ UNCH c = ptr[*ptr + 1];
+ ptr[*ptr + 1] = '\0';
+ *ptr += 2;
+ define_entity(ptr);
+ *ptr -= 2;
+ ptr += *ptr + 1;
+ *ptr = c;
+ }
+ }
+ output_begin_attribute(ent, ADNAME(al, aln), ADTYPE(al, aln));
+ ptr = ADVAL(al, aln);
+ for (i = 0; i < ADNUM(al, aln); i++) {
+ /* The first byte is a length NOT including the length
+ byte; the tokens are not EOS terminated. */
+ output_attribute_token(*ptr, ptr + 1);
+ ptr += *ptr + 1;
+ }
+ output_end_attribute();
+}
+
+static VOID handle_single_token(ent, al, aln)
+UNCH *ent;
+struct ad *al;
+int aln;
+{
+ if (ADTYPE(al, aln) == ANOTEGRP && !DCNMARK(ADDATA(al, aln).x))
+ output_notation(ADVAL(al, aln) + 1,
+ ADDATA(al, aln).x->pubid,
+ ADDATA(al, aln).x->sysid);
+ else if (ADTYPE(al, aln) == AENTITY)
+ define_entity(ADVAL(al, aln));
+ output_begin_attribute(ent, ADNAME(al, aln), ADTYPE(al, aln));
+ if (ADTYPE(al, aln) == ACHARS) {
+ putchar(' ');
+ print_string(ustrlen(ADVAL(al, aln)), ADVAL(al, aln), 0);
+ }
+ else
+ output_attribute_token(*ADVAL(al, aln) - 2, ADVAL(al, aln) + 1);
+ output_end_attribute();
+}
+
+static VOID output_notation(name, pubid, sysid)
+UNCH *name;
+UNCH *pubid, *sysid;
+{
+ flush_data();
+ print_id((UNIV)0, pubid, sysid);
+ printf("%c%s\n", DEFINE_NOTATION_CODE, name);
+}
+
+static VOID output_internal_entity(ename, is_sdata, text)
+UNCH *ename;
+int is_sdata;
+UNCH *text;
+{
+ flush_data();
+ printf("%c%s %s ", DEFINE_INTERNAL_ENTITY_CODE, ename,
+ is_sdata ? "SDATA" : "CDATA");
+ print_string(text ? ustrlen(text) : 0, text, 0);
+ putchar('\n');
+}
+
+static VOID output_subdoc(nm, id, pubid, sysid)
+UNCH *nm;
+UNIV id;
+UNCH *pubid, *sysid;
+{
+ flush_data();
+ print_id(id, pubid, sysid);
+ printf("%c%s\n", DEFINE_SUBDOC_ENTITY_CODE, nm);
+}
+
+#ifdef SUPPORT_SUBDOC
+
+static VOID process_subdoc(nm, id)
+UNCH *nm;
+UNIV id;
+{
+ if (!suppsw) {
+ flush_data();
+ output_location();
+ printf("%c%s\n", START_SUBDOC_CODE, nm);
+ fflush(stdout);
+ }
+ fflush(stderr);
+
+ if (id) {
+ char **argv;
+ int ret;
+
+ argv = make_argv(id);
+ ret = run_process(argv);
+ if (ret != 0)
+ suberr++;
+
+ current_filename = 0;
+ free(argv);
+ if (ret == 0)
+ get_subcaps();
+ }
+ else {
+ suberr++;
+ appl_error(E_SUBDOC, nm);
+ }
+
+ if (!suppsw)
+ printf("%c%s\n", END_SUBDOC_CODE, nm);
+}
+
+#endif /* SUPPORT_SUBDOC */
+
+static VOID output_external_entity(nm, xtype, id, pubid, sysid, dcn)
+UNCH *nm, *dcn;
+UNIV id;
+UNCH *pubid, *sysid;
+int xtype;
+{
+ char *type;
+
+ flush_data();
+
+ print_id(id, pubid, sysid);
+
+ switch (xtype) {
+ case ESNCDATA:
+ type = "CDATA";
+ break;
+ case ESNNDATA:
+ type = "NDATA";
+ break;
+ case ESNSDATA:
+ type = "SDATA";
+ break;
+ default:
+ return;
+ }
+ printf("%c%s %s %s\n", DEFINE_EXTERNAL_ENTITY_CODE, nm, type, dcn);
+}
+
+static VOID output_record_end()
+{
+ static UNCH re = RECHAR;
+ print_data(1, &re, 0);
+}
+
+static VOID output_pcdata(n, s)
+UNS n;
+UNCH *s;
+{
+ print_data(n, s, 0);
+}
+
+static VOID output_cdata(n, s)
+UNS n;
+UNCH *s;
+{
+ print_data(n, s, 0);
+}
+
+static VOID output_sdata(n, s)
+UNS n;
+UNCH *s;
+{
+ print_data(n, s, 1);
+}
+
+static VOID output_entity_reference(s)
+UNCH *s;
+{
+ flush_data();
+ output_location();
+ printf("%c%s\n", REFERENCE_ENTITY_CODE, s);
+}
+
+static VOID output_start_tag(s)
+UNCH *s;
+{
+ flush_data();
+ output_location();
+ printf("%c%s\n", START_CODE, s);
+}
+
+static VOID output_end_tag(s)
+UNCH *s;
+{
+ flush_data();
+ printf("%c%s\n", END_CODE, s);
+}
+
+static VOID output_processing_instruction(n, s)
+UNS n;
+UNCH *s;
+{
+ flush_data();
+ output_location();
+ putchar(PI_CODE);
+ print_string(n, s, 0);
+ putchar('\n');
+}
+
+static VOID output_appinfo(n, s)
+UNS n;
+UNCH *s;
+{
+ flush_data();
+ output_location();
+ putchar(APPINFO_CODE);
+ print_string(n, s, 0);
+ putchar('\n');
+}
+
+
+static VOID output_implied_attribute(ent, aname)
+UNCH *ent, *aname;
+{
+ flush_data();
+ if (ent)
+ printf("%c%s %s IMPLIED\n", DATA_ATTRIBUTE_CODE, ent, aname);
+ else
+ printf("%c%s IMPLIED\n", ATTRIBUTE_CODE, aname);
+}
+
+static char *attribute_type_string(type)
+int type;
+{
+ switch (type) {
+ case ANMTGRP:
+ case ANAME:
+ case ANMTOKE:
+ case ANUTOKE:
+ case ANUMBER:
+ case ANAMES:
+ case ANMTOKES:
+ case ANUTOKES:
+ case ANUMBERS:
+ case AID:
+ case AIDREF:
+ case AIDREFS:
+ return "TOKEN";
+ case ANOTEGRP:
+ return "NOTATION";
+ case ACHARS:
+ return "CDATA";
+ case AENTITY:
+ case AENTITYS:
+ return "ENTITY";
+ }
+#if 0
+ fatal("invalid attribute type %d", type);
+#endif
+ return "INVALID";
+}
+
+static VOID output_begin_attribute(ent, aname, type)
+UNCH *ent, *aname;
+int type;
+{
+ flush_data();
+ if (ent)
+ printf("%c%s %s %s", DATA_ATTRIBUTE_CODE, ent, aname,
+ attribute_type_string(type));
+ else
+ printf("%c%s %s", ATTRIBUTE_CODE, aname,
+ attribute_type_string(type));
+
+}
+
+static VOID output_attribute_token(vallen, val)
+UNS vallen;
+UNCH *val;
+{
+ putchar(' ');
+ for (; vallen > 0; --vallen, ++val)
+ putchar(*val);
+}
+
+static VOID output_end_attribute()
+{
+ putchar('\n');
+}
+
+static VOID print_data(n, s, is_sdata)
+UNS n;
+UNCH *s;
+int is_sdata;
+{
+ if (n > 0 || is_sdata) {
+ if (n == 1 && *s == RECHAR)
+ current_lineno++;
+ else
+ output_location();
+ if (!have_data)
+ putchar(DATA_CODE);
+ print_string(n, s, is_sdata);
+ have_data = 1;
+ }
+}
+
+static VOID flush_data()
+{
+ if (have_data) {
+ putchar('\n');
+ have_data = 0;
+ }
+}
+
+static VOID output_location()
+{
+ char *filename;
+ unsigned long lineno;
+ int filename_changed = 0;
+
+ if (!locsw)
+ return;
+ if (!sgmlloc(&lineno, &filename))
+ return;
+ if (!current_filename || strcmp(filename, current_filename) != 0)
+ filename_changed = 1;
+ else if (lineno == current_lineno)
+ return;
+ flush_data();
+ printf("%c%lu", LOCATION_CODE, lineno);
+ current_lineno = lineno;
+ if (filename_changed) {
+ putchar(' ');
+ print_filename(filename);
+ current_filename = filename;
+ }
+ putchar('\n');
+}
+
+static VOID print_string(slen, s, is_sdata)
+UNS slen;
+UNCH *s;
+int is_sdata;
+{
+ if (is_sdata)
+ fputs("\\|", stdout);
+ while (slen > 0) {
+ UNCH ch = *s++;
+ slen--;
+ if (ch == DELSDATA) {
+ if (is_sdata)
+ ; /* I don't think this should happen */
+ else
+ fputs("\\|", stdout);
+ ;
+ }
+ else if (ch == DELCDATA)
+ ;
+ else {
+ if (ch == DELNONCH) {
+ if (!slen)
+ break;
+ ch = UNSHIFTNON(*s);
+ s++;
+ slen--;
+ }
+ switch (ch) {
+ case RECHAR:
+ fputs("\\n", stdout);
+ break;
+ case '\\':
+ fputs("\\\\", stdout);
+ break;
+ default:
+ if (ISASCII(ch) && isprint(ch))
+ putchar(ch);
+ else
+ printf("\\%03o", ch);
+ break;
+ }
+ }
+ }
+ if (is_sdata)
+ fputs("\\|", stdout);
+}
+
+
+static VOID print_id(id, pubid, sysid)
+UNIV id;
+UNCH *pubid;
+UNCH *sysid;
+{
+
+ if (pubid) {
+ putchar(PUBID_CODE);
+ print_string(ustrlen(pubid), pubid, 0);
+ putchar('\n');
+ }
+
+ if (sysid) {
+ putchar(SYSID_CODE);
+ print_string(ustrlen(sysid), sysid, 0);
+ putchar('\n');
+ }
+
+ if (id) {
+ char *p;
+
+ for (p = id; *p != '\0'; p++) {
+ putchar(FILE_CODE);
+ do {
+ switch (*p) {
+ case '\\':
+ fputs("\\\\", stdout);
+ break;
+ case '\n':
+ fputs("\\n", stdout);
+ break;
+ default:
+ if (ISASCII(*p) && isprint((UNCH)*p))
+ putchar(*p);
+ else
+ printf("\\%03o", (UNCH)*p);
+ break;
+ }
+ } while (*++p);
+ putchar('\n');
+ }
+ }
+}
+
+static VOID print_filename(s)
+char *s;
+{
+ for (; *s; s++)
+ switch (*s) {
+ case '\\':
+ fputs("\\\\", stdout);
+ break;
+ case '\n':
+ fputs("\\n", stdout);
+ break;
+ default:
+ if (ISASCII(*s) && isprint((UNCH)*s))
+ putchar(*s);
+ else
+ printf("\\%03o", (UNCH)*s);
+ break;
+ }
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/lineout.h b/usr.bin/sgmls/sgmls/lineout.h
new file mode 100644
index 0000000..f3c4231
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/lineout.h
@@ -0,0 +1,23 @@
+/* lineout.h */
+
+/* Output codes used by sgmls. */
+
+#define DATA_CODE '-'
+#define START_CODE '('
+#define END_CODE ')'
+#define ATTRIBUTE_CODE 'A'
+#define DATA_ATTRIBUTE_CODE 'D'
+#define REFERENCE_ENTITY_CODE '&'
+#define DEFINE_NOTATION_CODE 'N'
+#define DEFINE_EXTERNAL_ENTITY_CODE 'E'
+#define DEFINE_INTERNAL_ENTITY_CODE 'I'
+#define PI_CODE '?'
+#define DEFINE_SUBDOC_ENTITY_CODE 'S'
+#define START_SUBDOC_CODE '{'
+#define END_SUBDOC_CODE '}'
+#define LOCATION_CODE 'L'
+#define APPINFO_CODE '#'
+#define PUBID_CODE 'p'
+#define SYSID_CODE 's'
+#define FILE_CODE 'f'
+#define CONFORMING_CODE 'C'
diff --git a/usr.bin/sgmls/sgmls/main.c b/usr.bin/sgmls/sgmls/main.c
new file mode 100644
index 0000000..25ead40
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/main.c
@@ -0,0 +1,650 @@
+/* main.c -
+ Main program for sgmls.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+#include "std.h"
+#include "getopt.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "adl.h" /* Definitions for attribute list processing. */
+#include "sgmlmain.h" /* Main interface to SGML services. */
+#include "appl.h"
+#include "alloc.h"
+
+#define READCNT 512
+
+/* Before using argv[0] in error messages, strip off everything up to and
+including the last character in prog that occurs in PROG_PREFIX. */
+
+#ifndef PROG_PREFIX
+#define PROG_PREFIX "/"
+#endif /* not PROG_PREFIX */
+
+/* Message catalogue name. */
+#define CAT_NAME "sgmls"
+/* Message set to use for application error messages. */
+#define APP_SET 4
+/* Message set to use for error messages from catalog.c. */
+#define CAT_SET 5
+#define CATALOG_ERROR_HEADER_MSGNO 20
+#define CATALOG_ERROR_HEADER_TEXT "Catalog error at %s, line %lu"
+
+#ifdef HAVE_EXTENDED_PRINTF
+#define xvfprintf vfprintf
+#else
+extern int xvfprintf P((FILE *, char *, va_list));
+#endif
+
+static VOID usage P((void));
+static VOID fatal VP((int, ...));
+static VOID do_error P((int, va_list));
+static VOID swinit P((struct switches *));
+static VOID write_caps P((char *, struct sgmlcap *));
+static VOID do_catalog_error();
+
+static UNIV make_docent P((int, char **));
+static char *munge_program_name P((char *, char *));
+static VOID die P((void));
+#ifdef SUPPORT_SUBDOC
+static VOID build_subargv P((struct switches *));
+static VOID cleanup P((void));
+static char *create_subcap_file P((void));
+#endif /* SUPPORT_SUBDOC */
+
+static char *errlist[] = {
+ 0,
+ "Out of memory",
+ "Cannot open SGML document entity",
+ "Cannot exec `%s': %s",
+ "Cannot fork: %s",
+ "Error waiting for process: %s",
+ "Program %s got fatal signal %d",
+ "Cannot open `%s': %s",
+ "Subdocument capacity botch",
+ "Non-existent subdocument entity `%s' not processed",
+};
+
+int suppsw = 0; /* Non-zero means suppress output. */
+int locsw = 0; /* Non-zero means generate location info. */
+static char *prog; /* Program name (for error messages). */
+static nl_catd catd; /* Message catalogue descriptor. */
+static char *capfile = 0; /* File for capacity report. */
+extern char *version_string;
+static CATALOG catalog; /* Entity catalog. */
+
+char options[] = {
+ 'c', ':', 'd', 'e', 'g', 'i', ':', 'l', 'o', ':', 'p', 'r', 's', 'u', 'v',
+ 'm', ':',
+#ifdef CANT_REDIRECT_STDERR
+ 'f', ':',
+#endif /* CANT_REDIRECT_STDERR */
+#ifdef TRACE
+ 'x', ':', 'y', ':',
+#endif /* TRACE */
+ '\0'
+};
+
+#ifdef SUPPORT_SUBDOC
+int suberr = 0; /* Error in subdocument. */
+static char *subargv[sizeof(options)];
+static int subargc = 0;
+static char nopenbuf[sizeof(long)*3 + 1];
+static char sgmldecl_file[L_tmpnam];
+static char subcap_file[L_tmpnam];
+#endif
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ static char stderr_buf[BUFSIZ];
+ int opt;
+#ifdef CANT_REDIRECT_STDERR
+ char *errfile = 0;
+#endif
+ struct sgmlcap cap;
+ struct switches sw;
+ int nincludes = 0; /* number of -i options */
+ setbuf(stderr, stderr_buf);
+
+ /* Define MAIN_HOOK in config.h if some function needs to be called here. */
+#ifdef MAIN_HOOK
+ MAIN_HOOK(argc, argv);
+#endif
+#ifdef SUPPORT_SUBDOC
+ subargv[subargc++] = argv[0];
+#endif
+
+ prog = argv[0] = munge_program_name(argv[0], "sgmls");
+
+ catd = catopen(CAT_NAME, 0);
+ catalog = catalog_create(do_catalog_error);
+ swinit(&sw);
+
+ while ((opt = getopt(argc, argv, options)) != -1) {
+ switch (opt) {
+ case 'm':
+ catalog_load_file(catalog, optarg);
+ break;
+ case 'l': /* Generate location information. */
+ locsw = 1;
+ break;
+ case 'c': /* Print capacity usage. */
+ sw.swcap = 1;
+ capfile = optarg;
+ break;
+ case 's': /* Suppress output. */
+ suppsw = 1;
+ break;
+ case 'd': /* Report duplicate entity declarations. */
+ sw.swdupent = 1;
+ break;
+ case 'e': /* Provide entity stack trace in error msg. */
+ sw.swenttr = 1;
+ break;
+#ifdef CANT_REDIRECT_STDERR
+ case 'f': /* Redirect errors. */
+ errfile = optarg;
+ break;
+#endif /* CANT_REDIRECT_STDERR */
+ case 'g': /* Provide GI stack trace in error messages. */
+ sw.sweltr = 1;
+ break;
+ case 'p': /* Parse only the prolog. */
+ sw.onlypro = 1;
+ suppsw = 1;
+ break;
+ case 'r': /* Give warning for defaulted references. */
+ sw.swrefmsg = 1;
+ break;
+ case 'u':
+ sw.swundef = 1;
+ break;
+#ifdef TRACE
+ case 'x': /* Trace options for the document body. */
+ sw.trace = optarg;
+ break;
+ case 'y': /* Trace options for the prolog. */
+ sw.ptrace = optarg;
+ break;
+#endif /* TRACE */
+ case 'v': /* Print the version number. */
+ fprintf(stderr, "sgmls version %s\n", version_string);
+ fflush(stderr);
+ break;
+ case 'o':
+ sw.nopen = atol(optarg);
+ if (sw.nopen <= 0)
+ usage();
+ break;
+ case 'i': /* Define parameter entity as "INCLUDE". */
+ sw.includes = (char **)xrealloc((UNIV)sw.includes,
+ (nincludes + 2)*sizeof(char *));
+ sw.includes[nincludes++] = optarg;
+ sw.includes[nincludes] = 0;
+ break;
+ case '?':
+ usage();
+ default:
+ abort();
+ }
+ }
+
+#ifdef CANT_REDIRECT_STDERR
+ if (errfile) {
+ FILE *fp;
+ errno = 0;
+ fp = fopen(errfile, "w");
+ if (!fp)
+ fatal(E_OPEN, errfile, strerror(errno));
+ fclose(fp);
+ errno = 0;
+ if (!freopen(errfile, "w", stderr)) {
+ /* Can't use fatal() since stderr is now closed */
+ printf("%s: ", prog);
+ printf(errlist[E_OPEN], errfile, strerror(errno));
+ putchar('\n');
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif /* CANT_REDIRECT_STDERR */
+
+ (void)sgmlset(&sw);
+
+#ifdef SUPPORT_SUBDOC
+ build_subargv(&sw);
+#endif
+ if (sgmlsdoc(make_docent(argc - optind, argv + optind)))
+ fatal(E_DOC);
+
+ process_document(sw.nopen > 0);
+ sgmlend(&cap);
+ if (capfile)
+ write_caps(capfile, &cap);
+#ifdef SUPPORT_SUBDOC
+ cleanup();
+ if (suberr)
+ exit(EXIT_FAILURE);
+#endif /* SUPPORT_SUBDOC */
+ if (sgmlgcnterr() > 0)
+ exit(EXIT_FAILURE);
+ if (!sw.nopen)
+ output_conforming();
+ exit(EXIT_SUCCESS);
+}
+
+static char *munge_program_name(arg, dflt)
+char *arg, *dflt;
+{
+ char *p;
+#ifdef PROG_STRIP_EXTENSION
+ char *ext;
+#endif
+ if (!arg || !*arg)
+ return dflt;
+ p = strchr(arg, '\0');
+ for (;;) {
+ if (p == arg)
+ break;
+ --p;
+ if (strchr(PROG_PREFIX, *p)) {
+ p++;
+ break;
+ }
+ }
+ arg = p;
+#ifdef PROG_STRIP_EXTENSION
+ ext = strrchr(arg, '.');
+ if (ext) {
+ p = (char *)xmalloc(ext - arg + 1);
+ memcpy(p, arg, ext - arg);
+ p[ext - arg] = '\0';
+ arg = p;
+ }
+#endif /* PROG_STRIP_EXTENSION */
+#ifdef PROG_FOLD
+#ifdef PROG_STRIP_EXTENSION
+ if (!ext) {
+#endif
+ p = xmalloc(strlen(arg) + 1);
+ strcpy(p, arg);
+ arg = p;
+#ifdef PROG_STRIP_EXTENSION
+ }
+#endif
+ for (p = arg; *p; p++)
+ if (ISASCII((unsigned char)*p) && isupper((unsigned char)*p))
+ *p = tolower((unsigned char)*p);
+#endif /* PROG_FOLD */
+ return arg;
+}
+
+static UNIV make_docent(argc, argv)
+int argc;
+char **argv;
+{
+ UNS len = 1;
+ int i;
+ UNIV res;
+ char *ptr;
+ static char *stdinname = STDINNAME;
+
+ if (argc == 0) {
+ argv = &stdinname;
+ argc = 1;
+ }
+
+ for (i = 0; i < argc; i++)
+ len += strlen(argv[i]) + 1;
+
+ res = xmalloc(len);
+ ptr = (char *)res;
+ for (i = 0; i < argc; i++) {
+ strcpy(ptr, argv[i]);
+ ptr = strchr(ptr, '\0') + 1;
+ }
+ *ptr = '\0';
+ return res;
+}
+
+
+static VOID usage()
+{
+ /* Don't mention -o since this are for internal use only. */
+ fprintf(stderr, "Usage: %s [-deglprsuv]%s [-c file] [-i entity] [-m file]%s [filename ...]\n",
+ prog,
+#ifdef CANT_REDIRECT_STDERR
+ " [-f file]",
+#else /* not CANT_REDIRECT_STDERR */
+ "",
+#endif /* not CANT_REDIRECT_STDERR */
+#ifdef TRACE
+ " [-x flags] [-y flags]"
+#else /* not TRACE */
+ ""
+#endif /* not TRACE */
+ );
+ exit(EXIT_FAILURE);
+}
+
+static VOID die()
+{
+#ifdef SUPPORT_SUBDOC
+ cleanup();
+#endif /* SUPPORT_SUBDOC */
+ exit(EXIT_FAILURE);
+}
+
+static VOID swinit(swp)
+struct switches *swp;
+{
+ swp->swenttr = 0;
+ swp->sweltr = 0;
+ swp->swbufsz = READCNT+2;
+ swp->prog = prog;
+ swp->swdupent = 0;
+ swp->swrefmsg = 0;
+#ifdef TRACE
+ swp->trace = 0;
+ swp->ptrace = 0;
+#endif /* TRACE */
+ swp->catd = catd;
+ swp->catalog = catalog;
+ swp->swambig = 1; /* Always check for ambiguity. */
+ swp->swundef = 0;
+ swp->swcap = 0; /* Don't check capacities. */
+ swp->nopen = 0;
+ swp->onlypro = 0;
+ swp->includes = 0;
+ swp->die = die;
+}
+
+#ifdef SUPPORT_SUBDOC
+
+static VOID build_subargv(swp)
+struct switches *swp;
+{
+ if (suppsw)
+ subargv[subargc++] = "-s";
+ if (locsw)
+ subargv[subargc++] = "-l";
+ if (swp->swdupent)
+ subargv[subargc++] = "-d";
+ if (swp->swenttr)
+ subargv[subargc++] = "-e";
+ if (swp->sweltr)
+ subargv[subargc++] = "-g";
+ if (swp->swrefmsg)
+ subargv[subargc++] = "-r";
+#ifdef TRACE
+ if (swp->trace) {
+ subargv[subargc++] = "-x";
+ subargv[subargc++] = swp->trace;
+ }
+ if (swp->ptrace) {
+ subargv[subargc++] = "-y";
+ subargv[subargc++] = swp->ptrace;
+ }
+#endif /* TRACE */
+ subargv[subargc++] = "-o";
+ sprintf(nopenbuf, "%ld", swp->nopen + 1);
+ subargv[subargc++] = nopenbuf;
+}
+
+
+static
+VOID handler(sig)
+int sig;
+{
+ signal(sig, SIG_DFL);
+ cleanup();
+ raise(sig);
+}
+
+static
+VOID cleanup()
+{
+ if (sgmldecl_file[0]) {
+ (void)remove(sgmldecl_file);
+ sgmldecl_file[0] = '\0';
+ }
+ if (subcap_file[0]) {
+ (void)remove(subcap_file);
+ subcap_file[0] = '\0';
+ }
+}
+
+static
+char *store_sgmldecl()
+{
+ if (!sgmldecl_file[0]) {
+ FILE *fp;
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, handler);
+#ifdef SIGTERM
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, handler);
+#endif /* SIGTERM */
+#ifdef SIGPIPE
+ if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal(SIGPIPE, handler);
+#endif
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, handler);
+#endif
+ tmpnam(sgmldecl_file);
+ errno = 0;
+ fp = fopen(sgmldecl_file, "w");
+ if (!fp)
+ fatal(E_OPEN, sgmldecl_file, strerror(errno));
+ sgmlwrsd(fp);
+ fclose(fp);
+ }
+ return sgmldecl_file;
+}
+
+static
+char *create_subcap_file()
+{
+ if (subcap_file[0] == '\0') {
+ FILE *fp;
+ tmpnam(subcap_file);
+ fp = fopen(subcap_file, "w");
+ if (!fp)
+ fatal(E_OPEN, subcap_file, strerror(errno));
+ fclose(fp);
+ }
+ return subcap_file;
+}
+
+char **make_argv(id)
+UNIV id;
+{
+ int nfiles;
+ char *p;
+ char **argv;
+ int i;
+
+ for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1)
+ nfiles++;
+
+ argv = (char **)xmalloc((subargc + 2 + 1 + nfiles + 1)*sizeof(char *));
+ memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *));
+
+ i = subargc;
+
+ argv[i++] = "-c";
+ argv[i++] = create_subcap_file();
+
+ argv[i++] = store_sgmldecl();
+
+ for (p = (char *)id; *p; p = strchr(p, '\0') + 1)
+ argv[i++] = p;
+ argv[i] = 0;
+ return argv;
+}
+
+VOID get_subcaps()
+{
+ long cap[NCAPACITY];
+ FILE *fp;
+ int i;
+
+ if (!subcap_file[0])
+ return;
+ errno = 0;
+ fp = fopen(subcap_file, "r");
+ if (!fp)
+ fatal(E_OPEN, subcap_file, strerror(errno));
+ for (i = 0; i < NCAPACITY; i++)
+ if (fscanf(fp, "%*s %ld", cap + i) != 1)
+ fatal(E_CAPBOTCH);
+ fclose(fp);
+ sgmlsubcap(cap);
+}
+
+
+#endif /* SUPPORT_SUBDOC */
+
+/* Print capacity statistics.*/
+
+static VOID write_caps(name, p)
+char *name;
+struct sgmlcap *p;
+{
+ FILE *fp;
+ int i;
+ fp = fopen(name, "w");
+ if (!fp)
+ fatal(E_OPEN, name, strerror(errno));
+ /* This is in RACT format. */
+ for (i = 0; i < NCAPACITY; i++)
+ fprintf(fp, "%s %ld\n", p->name[i], p->number[i]*p->points[i]);
+ fclose(fp);
+}
+
+UNIV xmalloc(n)
+UNS n;
+{
+ UNIV p = malloc(n);
+ if (!p)
+ fatal(E_NOMEM);
+ return p;
+}
+
+UNIV xrealloc(s, n)
+UNIV s;
+UNS n;
+{
+ s = s ? realloc(s, n) : malloc(n);
+ if (!s)
+ fatal(E_NOMEM);
+ return s;
+}
+
+static
+#ifdef VARARGS
+VOID fatal(va_alist) va_dcl
+#else
+VOID fatal(int errnum,...)
+#endif
+{
+#ifdef VARARGS
+ int errnum;
+#endif
+ va_list ap;
+
+#ifdef VARARGS
+ va_start(ap);
+ errnum = va_arg(ap, int);
+#else
+ va_start(ap, errnum);
+#endif
+ do_error(errnum, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+#ifdef VARARGS
+VOID appl_error(va_alist) va_dcl
+#else
+VOID appl_error(int errnum,...)
+#endif
+{
+#ifdef VARARGS
+ int errnum;
+#endif
+ va_list ap;
+
+#ifdef VARARGS
+ va_start(ap);
+ errnum = va_arg(ap, int);
+#else
+ va_start(ap, errnum);
+#endif
+ do_error(errnum, ap);
+ va_end(ap);
+}
+
+static
+VOID do_error(errnum, ap)
+int errnum;
+va_list ap;
+{
+ char *text;
+ fprintf(stderr, "%s: ", prog);
+ assert(errnum > 0);
+ assert(errnum < sizeof(errlist)/sizeof(errlist[0]));
+ text = catgets(catd, APP_SET, errnum, errlist[errnum]);
+ assert(text != 0);
+ xvfprintf(stderr, text, ap);
+ fputc('\n', stderr);
+ fflush(stderr);
+}
+
+static
+VOID do_catalog_error(filename, lineno, error_number, flags, sys_errno)
+char *filename;
+unsigned long lineno;
+int error_number;
+unsigned flags;
+int sys_errno;
+{
+ char *text;
+ unsigned indent;
+ text = catgets(catd, CAT_SET, error_number,
+ (char *)catalog_error_text(error_number)); /* XXX */
+ assert(text != 0);
+ fprintf(stderr, "%s: ", prog);
+ indent = strlen(prog) + 2;
+ if (flags & CATALOG_SYSTEM_ERROR)
+ fprintf(stderr, text, filename, strerror(sys_errno));
+ else {
+ unsigned i;
+ fprintf(stderr,
+ catgets(catd, APP_SET,
+ CATALOG_ERROR_HEADER_MSGNO,
+ CATALOG_ERROR_HEADER_TEXT),
+ filename, lineno);
+ fputs(":\n", stderr);
+ for (i = 0; i < indent; i++)
+ putc(' ', stderr);
+ fputs(text, stderr);
+ }
+ putc('\n', stderr);
+ fflush(stderr);
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/md1.c b/usr.bin/sgmls/sgmls/md1.c
new file mode 100644
index 0000000..66c476d
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/md1.c
@@ -0,0 +1,866 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+/* MDADL: Process ATTLIST declaration.
+*/
+VOID mdadl(tbuf)
+UNCH *tbuf; /* Work area for tokenization (tbuf). */
+{
+ int i; /* Loop counter; temporary variable. */
+ int adlim; /* Number of unused ad slots in al. */
+ struct ad *alperm = 0; /* Attribute definition list. */
+ int stored = 0;
+
+ mdname = key[KATTLIST]; /* Identify declaration for messages. */
+ subdcl = 0; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es level for entity nesting check. */
+ reqadn = noteadn = 0; /* No required attributes yet. */
+ idadn = conradn = 0; /* No special atts yet.*/
+ AN(al) = 0; /* Number of attributes defined. */
+ ADN(al) = 0; /* Number of ad's in al (atts + name vals).*/
+ /* PARAMETER 1: Element name or a group of them.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: element name or group");
+ switch (pcbmd.action) {
+ case NAS:
+ nmgrp[0] = etddef(tbuf);
+ nmgrp[1] = 0;
+ break;
+ case GRPS:
+ parsegrp(nmgrp, &pcbgrnm, tbuf);
+ break;
+ case RNS: /* Reserved name started. */
+ if (ustrcmp(tbuf+1, key[KNOTATION])) {
+ mderr(118, tbuf+1, key[KNOTATION]);
+ return;
+ }
+ mdnadl(tbuf);
+ return;
+ default:
+ mderr(121, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* Save first GI for error msgs. */
+ if (nmgrp[0])
+ subdcl = nmgrp[0]->etdgi+1;
+ /* PARAMETER 2: Attribute definition list.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: attribute list");
+ if (pcbmd.action!=NAS) {
+ mderr(120, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ while (pcbmd.action==NAS) {
+ al[ADN(al)+1].adname = savenm(tbuf);
+ if ((adlim = ATTCNT-((int)++ADN(al)))<0) {
+ mderr(111, (UNCH *)0, (UNCH *)0);
+ adlfree(al, 1);
+ return;
+ }
+ ++AN(al);
+ if (mdattdef(adlim, 0)) {
+ adlfree(al, 1);
+ return;
+ }
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ }
+ if (AN(al)>0) { /* Save list only if 1 or more good atts. */
+ if (reqadn) SET(ADLF(al), ADLREQ); /* Element must have start-tag. */
+ if (noteadn) SET(ADLF(al), ADLNOTE); /* Element cannot be EMPTY. */
+ if (conradn) SET(ADLF(al), ADLCONR); /* Element cannot be EMPTY. */
+ alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
+ memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
+ ds.attcnt += AN(al); /* Number of attributes defined. */
+ ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
+ TRACEADL(alperm);
+ }
+ /* Clear attribute list for next declaration. */
+ MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
+
+ /* PARAMETER 3: End of declaration.
+ */
+ /* Next pcb.action was set during attribute definition loop. */
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
+ if (es!=mdessv) synerr(37, &pcbmd);
+
+ /* EXECUTE: Store the definition for each element name specified.
+ */
+ TRACEGRP(nmgrp);
+ for (i = 0; nmgrp[i]; i++) {
+ if (nmgrp[i]->adl) { /* Error if an ADL exists. */
+ mderr(112, (UNCH *)0, (UNCH *)0);
+ continue;
+ }
+ nmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
+ stored = 1;
+ if (alperm && nmgrp[i]->etdmod)
+ etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
+ }
+ if (!stored && alperm) {
+ adlfree(alperm, 1);
+ frem((UNIV)alperm);
+ }
+}
+/* ETDADL: Check compatibility between ETD and ADL.
+*/
+VOID etdadl(p)
+struct etd *p; /* Pointer to element type definition. */
+{
+ parmno = 0;
+ /* Minimizable element cannot have required attribute. */
+ if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
+ mderr(40, (UNCH *)0, (UNCH *)0);
+ RESET(p->etdmin, SMO);
+ }
+ /* Empty element cannot have NOTATION attribute.
+ Attribute is not removed (too much trouble), but we trap
+ attempts to specify it on the start-tag in adlval().
+ */
+ if (GET(p->etdmod->ttype, MNONE)) {
+ if (GET(p->adl[0].adflags, ADLNOTE))
+ mderr(83, (UNCH *)0, (UNCH *)0);
+
+ /* Empty element cannot have CONREF attribute.
+ Attribute is not removed because it just acts
+ like IMPLIED anyway.
+ */
+ if (GET(p->adl[0].adflags, ADLCONR))
+ mderr(85, (UNCH *)0, (UNCH *)0);
+ }
+#if 0
+ /* "-" should not be specified for the end-tag minimization if
+ the element has a content reference attribute. */
+ if (GET(p->adl[0].adflags, ADLCONR) && BITON(p->etdmin, EMM))
+ mderr(153, (UNCH *)0, (UNCH *)0);
+#endif
+}
+/* MDNADL: Process ATTLIST declaration for notation.
+ TO DO: Pass deftab and dvtab as parameters so
+ that prohibited types can be handled by leaving
+ them out of the tables.
+*/
+VOID mdnadl(tbuf)
+UNCH *tbuf; /* Work area for tokenization (tbuf). */
+{
+ int i; /* Loop counter; temporary variable. */
+ int adlim; /* Number of unused ad slots in al. */
+ struct ad *alperm = 0; /* Attribute definition list. */
+ int stored = 0;
+
+ /* PARAMETER 1: Notation name or a group of them.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: notation name or group");
+ switch (pcbmd.action) {
+ case NAS:
+ nnmgrp[0] = dcndef(tbuf);
+ nnmgrp[1] = 0;
+ break;
+ case GRPS:
+ parsngrp(nnmgrp, &pcbgrnm, tbuf);
+ break;
+ default:
+ mderr(121, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ subdcl = nnmgrp[0]->ename+1; /* Save first name for error msgs. */
+ /* PARAMETER 2: Attribute definition list.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: attribute list");
+ if (pcbmd.action!=NAS) {
+ mderr(120, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ while (pcbmd.action==NAS) {
+ al[ADN(al)+1].adname = savenm(tbuf);
+ if ((adlim = ATTCNT-((int)ADN(al)++))<0) {
+ mderr(111, (UNCH *)0, (UNCH *)0);
+ adlfree(al, 1);
+ return;
+ }
+ ++AN(al);
+ if (mdattdef(adlim, 1)) {
+ adlfree(al, 1);
+ return;
+ }
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ }
+ if (AN(al)>0) { /* Save list only if 1 or more good atts. */
+ alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
+ memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
+ ds.attcnt += AN(al); /* Number of attributes defined. */
+ ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
+ TRACEADL(alperm);
+ }
+ /* Clear attribute list for next declaration. */
+ MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
+
+ /* PARAMETER 3: End of declaration.
+ */
+ /* Next pcb.action was set during attribute definition loop. */
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
+ if (es!=mdessv) synerr(37, &pcbmd);
+
+ /* EXECUTE: Store the definition for each notation name specified.
+ */
+ TRACENGR(nnmgrp);
+ for (i = 0; nnmgrp[i]; i++) {
+ if (nnmgrp[i]->adl) { /* Error if an ADL exists. */
+ mderr(112, (UNCH *)0, (UNCH *)0);
+ continue;
+ }
+ nnmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
+ if (nnmgrp[i]->entsw)
+ fixdatt(nnmgrp[i]);
+ stored = 1;
+ TRACEDCN(nnmgrp[i]);
+ }
+ if (!stored && alperm) {
+ adlfree(alperm, 1);
+ frem((UNIV)alperm);
+ }
+}
+
+/* Data attributes have been specified for notation p, but entities
+have already been declared with notation p. Fix up the definitions of
+all entities with notation p. Generate an error for any data
+attribute that was required. */
+
+VOID fixdatt(p)
+struct dcncb *p;
+{
+ int i;
+ for (i = 0; i < ENTHASH; i++) {
+ struct entity *ep;
+ for (ep = etab[i]; ep; ep = ep->enext)
+ if (ep->estore == ESN && ep->etx.n && ep->etx.n->nedcn == p) {
+ int adn;
+ initatt(p->adl);
+ /* Don't use adlval because if there were required
+ attributes the error message wouldn't say what
+ entity was involved. */
+ for (adn = 1; adn <= ADN(al); adn++) {
+ if (GET(ADFLAGS(al,adn), AREQ)) {
+ sgmlerr(218, &pcbstag, ADNAME(al,adn),
+ ep->ename + 1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ }
+ if (BITON(ADFLAGS(al, adn), AGROUP))
+ adn += ADNUM(al, adn);
+ }
+ storedatt(ep->etx.n);
+ }
+ }
+}
+
+/* MDATTDEF: Process an individual attribute definition.
+ The attribute name is parsed by the caller.
+ Duplicate attributes are parsed, but removed from list.
+ Returns 0 if successful, otherwise returns 1.
+*/
+int mdattdef(adlim, datt)
+int adlim; /* Remaining capacity of al (in tokens).*/
+int datt; /* Non-zero if a data attribute. */
+{
+ int deftype; /* Default value type: 0=not keyword. */
+ int errsw = 0; /* 1=semantic error; ignore att. */
+ int novalsw = 0; /* 1=semantic error; treat as IMPLIED. */
+ int attadn = (int)ADN(al); /* Save ad number of this attribute. */
+ struct parse *grppcb = NULL; /* PCB for name/token grp parse. */
+ int errcode; /* Error type returned by PARSEVAL, ANMTGRP. */
+ UNCH *advalsv; /* Save area for permanent value ptr. */
+
+ /* PARAMETER 1: Attribute name (parsed by caller).
+ */
+ TRACEMD("1: attribute name");
+ if (anmget((int)ADN(al)-1, al[attadn].adname)) {
+ errsw = 1;
+ mderr(99, ADNAME(al,attadn), (UNCH *)0);
+ }
+ ADNUM(al,attadn) = ADFLAGS(al,attadn) = ADLEN(al,attadn) = 0;
+ ADVAL(al,attadn) = 0; ADDATA(al,attadn).x = 0; ADTYPE(al,attadn) = ANMTGRP;
+ /* PARAMETER 2: Declared value.
+ */
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: declared value");
+ switch (pcbmd.action) {
+ case NAS: /* Keyword for value type. */
+ switch (ADTYPE(al,attadn) = (UNCH)mapsrch(dvtab, lbuf+1)) {
+ case 0:
+ mderr(100, ADNAME(al,attadn), lbuf+1);
+ return 1;
+ case ANOTEGRP:
+ if (datt) {
+ errsw = 1;
+ mderr(156, (UNCH *)0, (UNCH *)0);
+ }
+ else if (!noteadn) noteadn = ADN(al);
+ else {
+ errsw = 1;
+ mderr(101, ADNAME(al,attadn), (UNCH *)0);
+ }
+ grppcb = &pcbgrnm; /* NOTATION requires name grp. */
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
+ break;
+ case AID:
+ if (datt) {
+ errsw = 1;
+ mderr(144, (UNCH *)0, (UNCH *)0);
+ }
+ else if (!idadn)
+ idadn = attadn;
+ else {
+ errsw = 1;
+ mderr(102, ADNAME(al,attadn), (UNCH *)0);
+ }
+ break;
+ case AIDREF:
+ case AIDREFS:
+ if (datt) {
+ errsw = 1;
+ mderr(155, (UNCH *)0, (UNCH *)0);
+ }
+ break;
+ case AENTITY:
+ case AENTITYS:
+ if (datt) {
+ errsw = 1;
+ mderr(154, (UNCH *)0, (UNCH *)0);
+ }
+ break;
+ }
+ break;
+ case GRPS:
+ grppcb = &pcbgrnt; /* Normal grp is name token grp. */
+ break;
+ case EMD:
+ mderr(103, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ default:
+ mderr(104, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ }
+ /* PARAMETER 2A: Name token group.
+ */
+ if (grppcb != NULL) {
+ TRACEMD("2A: name group");
+ switch (pcbmd.action) {
+ case GRPS: /* Name token list. */
+ SET(ADFLAGS(al,attadn), AGROUP);
+ /* Call routine to parse group, create ad entries in adl. */
+ errcode = anmtgrp(grppcb, al+attadn,
+ (GRPCNT<adlim ? GRPCNT+1 : adlim+1),
+ &al[attadn].adnum, ADN(al));
+ if (errcode<=0) {
+ if (adlim < GRPCNT)
+ mderr(111, (UNCH *)0, (UNCH *)0);
+ else
+ mderr(105, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ }
+ ADN(al) += ADNUM(al,attadn); /* Add grp size to total ad cnt.*/
+ break;
+ default:
+ mderr(106, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ }
+ }
+ /* PARAMETER 3: Default value keyword.
+ */
+ parsemd(lbuf, AVALCASE,
+ (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt, LITLEN);
+ TRACEMD("3: default keyword");
+ switch (pcbmd.action) {
+ case RNS: /* Keyword. */
+ deftype = mapsrch(deftab, lbuf+1);
+ switch (deftype) {
+ case DFIXED: /* FIXED */
+ SET(ADFLAGS(al,attadn), AFIXED);
+ parsemd(lbuf, AVALCASE,
+ (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt,
+ LITLEN); /* Real default. */
+ goto parm3x; /* Go process specified value. */
+ case DCURR: /* CURRENT: If ID, treat as IMPLIED. */
+ if (ADTYPE(al,attadn)==AID) {
+ mderr(80, ADNAME(al,attadn), (UNCH *)0);
+ break;
+ }
+ if (datt) {
+ mderr(157, (UNCH *)0, (UNCH *)0);
+ break;
+ }
+ SET(ADFLAGS(al,attadn), ACURRENT);
+ break;
+ case DREQ: /* REQUIRED */
+ SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
+ break;
+ case DCONR: /* CONREF */
+ if (ADTYPE(al,attadn)==AID) {
+ mderr(107, ADNAME(al,attadn), (UNCH *)0);
+ break;
+ }
+ if (datt) {
+ mderr(158, (UNCH *)0, (UNCH *)0);
+ break;
+ }
+ SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
+ case DNULL: /* IMPLIED */
+ break;
+ default: /* Unknown keyword is an error. */
+ mderr(108, ADNAME(al,attadn), lbuf+1);
+ errsw = 1;
+ }
+ if (errsw) {
+ /* Ignore erroneous att. */
+ adlfree(al, attadn);
+ --AN(al);
+ ADN(al) = (UNCH)attadn-1;
+ }
+ return(0);
+ default:
+ break;
+ }
+ /* PARAMETER 3x: Default value (non-keyword).
+ */
+ parm3x:
+ TRACEMD("3x: default (non-keyword)");
+ if (ADTYPE(al,attadn)==AID) { /* If ID, treat as IMPLIED. */
+ mderr(81, ADNAME(al,attadn), (UNCH *)0);
+ novalsw = 1; /* Keep parsing to keep things straight. */
+ }
+ switch (pcbmd.action) {
+ case LIT: /* Literal. */
+ case LITE: /* Literal. */
+ /* Null string (except CDATA) is error: msg and treat as IMPLIED. */
+ if (*lbuf == '\0' && ADTYPE(al,attadn)!=ACHARS) {
+ mderr(82, ADNAME(al,attadn), (UNCH *)0);
+ novalsw = 1;
+ }
+ break;
+ case NAS: /* Name character string. */
+ case NMT: /* Name character string. */
+ case NUM: /* Number or number token string. */
+ /* The name won't have a length byte because AVALCASE was specified. */
+ break;
+ case CDR:
+ parsetkn(lbuf, NMC, LITLEN);
+ break;
+ case EMD:
+ mderr(109, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ default:
+ mderr(110, ADNAME(al,attadn), (UNCH *)0);
+ return 1;
+ }
+ if (errsw) {
+ /* Ignore erroneous att. */
+ adlfree(al, attadn);
+ --AN(al);
+ ADN(al) = (UNCH)attadn-1;
+ return(0);
+ }
+ if (novalsw) return(0);
+
+ /* PARAMETER 3y: Validate and store default value.
+ */
+ if (ADTYPE(al,attadn)==ACHARS) {
+ UNS len = vallen(ACHARS, 0, lbuf);
+ if (len > LITLEN) {
+ /* Treat as implied. */
+ sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
+ return 0;
+ }
+ /* No more checking for CDATA value. */
+ ADNUM(al,attadn) = 0; /* CDATA is 0 tokens. */
+ ADVAL(al,attadn) = savestr(lbuf);/* Store default; save ptr. */
+ ADLEN(al,attadn) = len;
+ ds.attdef += len;
+ return 0;
+ }
+ /* Parse value and save token count (GROUP implies 1 token). */
+ advalsv = (UNCH *)rmalloc(ustrlen(lbuf)+2); /* Storage for tokenized value. */
+ errcode = parseval(lbuf, (UNS)ADTYPE(al,attadn), advalsv);
+ if (BITOFF(ADFLAGS(al,attadn), AGROUP)) ADNUM(al,attadn) = (UNCH)tokencnt;
+
+ /* If value was invalid, or was a group member that was not in the group,
+ issue an appropriate message and set the error switch. */
+ if (errcode)
+ {sgmlerr((UNS)errcode, &pcbmd, ADNAME(al,attadn), lbuf); errsw = 1;}
+ else if ( BITON(ADFLAGS(al,attadn), AGROUP)
+ && !amemget(&al[attadn], (int)ADNUM(al,attadn), advalsv) ) {
+ sgmlerr(79, &pcbmd, ADNAME(al,attadn), advalsv+1);
+ errsw = 1;
+ }
+ ADLEN(al,attadn) = vallen(ADTYPE(al,attadn), ADNUM(al,attadn), advalsv);
+ if (ADLEN(al,attadn) > LITLEN) {
+ sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
+ ADLEN(al,attadn) = 0;
+ errsw = 1;
+ }
+ /* For valid tokenized value, save it and update statistics. */
+ if (!errsw) {
+ ADVAL(al,attadn) = advalsv;
+ ds.attdef += ADLEN(al,attadn);
+ return 0;
+ }
+ /* If value was bad, free the value's storage and treat as
+ IMPLIED or REQUIRED. */
+ frem((UNIV)advalsv); /* Release storage for value. */
+ ADVAL(al,attadn) = NULL; /* And make value NULL. */
+ return 0;
+}
+/* ANMTGRP: Parse a name or name token group, create attribute descriptors
+ for its members, and add them to the attribute descriptor list.
+ The parse either terminates or returns a good token, so no
+ switch is needed.
+*/
+int anmtgrp(pcb, nt, grplim, adn, adsz)
+struct parse *pcb; /* PCB for name or name token grp. */
+struct ad nt[]; /* Buffer for creating name token list. */
+int grplim; /* Maximum size of list (plus 1). */
+UNS *adn; /* Ptr to number of names or tokens in grp. */
+int adsz; /* Size of att def list. */
+{
+ UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
+ int essv = es; /* Entity stack level when grp started. */
+
+ *adn = 0; /* Group is empty to start. */
+ while (parse(pcb)!=GRPE && *adn<grplim) {
+ switch (pcb->action) {
+ case NAS_: /* Name or name token (depending on pcb). */
+ case NMT_:
+ parsenm(lbuf, NAMECASE);
+ nt[*adn+1].adname = savenm(lbuf);
+ if (antvget((int)(adsz+*adn), nt[*adn+1].adname, (UNCH **)0))
+ mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
+ nt[++*adn].adtype = adtype;
+ nt[*adn].addef = NULL;
+ continue;
+
+ case EE_: /* Entity ended (correctly or incorrectly). */
+ if (es<essv) {synerr(37, pcb); essv = es;}
+ continue;
+
+ case PIE_: /* PI entity reference (invalid). */
+ entpisw = 0; /* Reset PI entity indicator. */
+ synerr(59, pcb);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if (es!=essv) synerr(37, pcb);
+ if (*adn==grplim) return -1;
+ else return *adn; /* Return number of tokens. */
+}
+/* MDDTDS: Process start of DOCTYPE declaration (through MSO).
+*/
+VOID mddtds(tbuf)
+UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
+{
+ struct fpi fpicb; /* Formal public identifier structure. */
+ union etext etx; /* Ptr to entity text. */
+ UNCH estore = ESD; /* Entity storage class. */
+ int emdsw = 0; /* 1=end of declaration found; 0=not yet. */
+
+ mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es for checking entity nesting. */
+ dtdrefsw = 0; /* No external DTD entity as yet. */
+ /* PARAMETER 1: Document type name.
+ */
+ pcbmd.newstate = 0;
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: doc type name");
+ if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
+ dtype = savenm(tbuf);
+ subdcl = dtype+1; /* Subject of declaration for error msgs. */
+
+ /* PARAMETER 2: External identifier keyword or MDS.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: extid or MDS");
+ switch (pcbmd.action) {
+ case NAS:
+ if (mdextid(tbuf, &fpicb, dtype+1, &estore, (PNE)0)==0) return;
+ if ((etx.x = entgen(&fpicb))==0)
+ mderr(146, dtype+1, (UNCH *)0);
+ else
+ dtdrefsw = 1; /* Signal external DTD entity. */
+ break;
+ case MDS:
+ goto execute;
+ default:
+ mderr(128, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* PARAMETER 3: MDS or end of declaration.
+ */
+ TRACEMD("3: MDS or EMD");
+ switch (pcbmd.action) {
+ default: /* Treat as end of declaration. */
+ mderr(126, (UNCH *)0, (UNCH *)0);
+ case EMD:
+ emdsw = 1;
+ case MDS:
+ break;
+ }
+ /* EXECUTE: Store entity definition if an external ID was specified.
+ */
+ execute:
+ if (es!=mdessv) synerr(37, &pcbmd);
+ propcb = &pcbmds; /* Prepare to parse doc type definition (MDS). */
+ if (dtdrefsw) {
+ /* TO DO: If concurrent DTD's supported, free existing
+ etext for all but first DTD (or reuse it). */
+ entdef(indtdent, estore, &etx);
+ ++ds.ecbcnt; ds.ecbtext += entlen;
+ if (emdsw) {
+ REPEATCC; /* Push back the MDC. */
+ *FPOS = lex.d.msc; /* Simulate end of DTD subset. */
+ REPEATCC; /* Back up to read MSC next. */
+ delmscsw = 1; /* Insert MSC after referenced DTD. */
+ }
+ }
+ indtdsw = 1; /* Allow "DTD only" parameters. */
+ return;
+}
+/* MDDTDE: Process DOCTYPE declaration end.
+*/
+VOID mddtde(tbuf)
+UNCH *tbuf; /* Work area for tokenization. */
+{
+ mdessv = es; /* Save es for checking entity nesting. */
+ propcb = &pcbpro; /* Restore normal prolog parse. */
+ indtdsw = 0; /* Prohibit "DTD only" parameters. */
+
+ mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
+ subdcl = dtype+1; /* Subject of declaration for error msgs. */
+ parmno = 0; /* No parameters as yet. */
+ /* PARAMETER 4: End of declaration.
+ */
+ pcbmd.newstate = pcbmdtk;
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ if (es!=mdessv) synerr(37, &pcbmd);
+}
+/* MDELEM: Process ELEMENT declaration.
+*/
+VOID mdelem(tbuf)
+UNCH *tbuf; /* Work area for tokenization (tbuf). */
+{
+ UNCH *ranksuff = lbuf; /* Rank suffix. */
+ UNS dctype = 0; /* Declared content type (from dctab). */
+ UNCH fmin = 0; /* Minimization bit flags. */
+ int i; /* Loop counter. */
+ UNS u; /* Temporary variable. */
+ struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
+ struct thdr *cmod, *cmodsv; /* Ptr to content model. */
+ UNCH *etdgi; /* GI of current etd (when going through group).*/
+ int minomitted = 0; /* Tag minimization parameters omitted. */
+
+ mdname = key[KELEMENT]; /* Identify declaration for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es level for entity nesting check. */
+ ranksuff[0] = 0;
+ mexgrp = pexgrp = 0;
+
+ /* PARAMETER 1: Element name or a group of them.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: element name or grp");
+ switch (pcbmd.action) {
+ case NAS:
+ nmgrp[0] = etddef(tbuf);
+ nmgrp[1] = 0;
+ break;
+ case GRPS:
+ parsegrp(nmgrp, &pcbgrnm, tbuf);
+ break;
+ default:
+ mderr(121, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* Save first GI for trace and error messages. */
+ if (nmgrp[0])
+ subdcl = nmgrp[0]->etdgi+1;
+
+ /* PARAMETER 1A: Rank suffix (optional).
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1A: rank suffix");
+ switch (pcbmd.action) {
+ case NUM:
+ ustrcpy(ranksuff, tbuf);
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ default:
+ break;
+ }
+ /* PARAMETER 2A: Start-tag minimization.
+ */
+ TRACEMD("2A: start min");
+ switch (pcbmd.action) {
+ case CDR:
+ break;
+ case NAS:
+ if (!ustrcmp(tbuf+1, key[KO])) {
+ if (OMITTAG==YES) SET(fmin, SMO);
+ break;
+ }
+ /* fall through */
+ default:
+ if (OMITTAG==NO) {minomitted=1; break;}
+ mderr(129, tbuf+1, (UNCH *)0);
+ return;
+ }
+ /* Must omit omitted end-tag minimization, if omitted
+ start-tag minimization was omitted (because OMITTAG == NO). */
+ if (!minomitted) {
+ /* PARAMETER 2B: End-tag minimization.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2B: end min");
+ switch (pcbmd.action) {
+ case NAS:
+ if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
+ if (OMITTAG==YES) SET(fmin, EMO);
+ break;
+ case MGRP:
+ REPEATCC;
+ /* fall through */
+ case CDR:
+ SET(fmin, EMM);
+ break;
+ default:
+ mderr(129, tbuf+1, (UNCH *)0);
+ return;
+ }
+ /* PARAMETER 3: Declared content.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ }
+ TRACEMD("3: declared content");
+ switch (pcbmd.action) {
+ case NAS:
+ dctype = mapsrch(dctab, tbuf+1);
+ if (!dctype) {mderr(24, tbuf+1, (UNCH *)0); return;}
+ /* Eliminate incompatibilities among parameters. */
+ if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
+ mderr(58, (UNCH *)0, (UNCH *)0);
+ RESET(fmin, SMO);
+ }
+ if (GET(dctype, MNONE) && BITON(fmin, EMM)) {
+ mderr(87, (UNCH *)0, (UNCH *)0);
+ SET(fmin, EMO);
+ }
+ /* If valid, process like a content model. */
+ case GRPS:
+ cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
+ if (cmodsv==0) return;
+ u = (dctype ? 1 : cmodsv->tu.tnum+2) * THSZ;
+ cmod = (struct thdr *)rmalloc(u);
+ memcpy((UNIV)cmod , (UNIV)cmodsv, u );
+ ds.modcnt += cmod->tu.tnum;
+ TRACEMOD(cmod);
+ break;
+ default:
+ mderr(130, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* PARAMETERS 3A, 3B: Exceptions or end.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
+ /* PARAMETER 3A: Minus exceptions.
+ */
+ TRACEMD("3A: -grp");
+ switch (pcbmd.action) {
+ case MGRP:
+ /* We cheat and use nnmgrp for this. */
+ mexgrp = copygrp((PETD *)nnmgrp,
+ u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
+ ++ds.pmexgcnt; ds.pmexcnt += u-1;
+ TRACEGRP(mexgrp);
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ default:
+ break;
+ }
+ /* PARAMETER 3B: Plus exceptions.
+ */
+ TRACEMD("3B: +grp");
+ switch (pcbmd.action) {
+ case PGRP:
+ pexgrp = copygrp((PETD *)nnmgrp,
+ u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
+ ++ds.pmexgcnt; ds.pmexcnt += u-1;
+ TRACEGRP(pexgrp);
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ default:
+ break;
+ }
+ }
+ /* PARAMETER 4: End of declaration.
+ */
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ if (es!=mdessv) synerr(37, &pcbmd);
+
+ /* EXECUTE: Store the definition for each element name specified.
+ */
+ TRACEGRP(nmgrp);
+ for (i = -1; nmgrp[++i];) {
+ etdgi = nmgrp[i]->etdgi;
+ if (*ranksuff) {
+ if ((tbuf[0] = *etdgi + ustrlen(ranksuff)) - 2 > NAMELEN) {
+ mderr(131, etdgi+1, ranksuff);
+ continue;
+ }
+ memcpy(tbuf+1, etdgi+1, *etdgi-1);
+ ustrcpy(tbuf+*etdgi-1, ranksuff);
+ etdcan(etdgi);
+ nmgrp[i] = etddef(tbuf);
+ }
+ if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
+ etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
+ ++ds.etdcnt;
+ if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
+ TRACEETD(nmgrp[i]);
+ }
+}
+
+VOID adlfree(al, aln)
+struct ad *al;
+int aln;
+{
+ for (; aln <= ADN(al); aln++) {
+ frem((UNIV)al[aln].adname);
+ if (ADVAL(al, aln))
+ frem((UNIV)ADVAL(al, aln));
+ if (BITON(ADFLAGS(al, aln), AGROUP)) {
+ int i;
+ for (i = 0; i < ADNUM(al, aln); i++)
+ frem((UNIV)al[aln + i + 1].adname);
+ aln += ADNUM(al, aln);
+ }
+ }
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/md2.c b/usr.bin/sgmls/sgmls/md2.c
new file mode 100644
index 0000000..df7e57e
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/md2.c
@@ -0,0 +1,792 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+/* MDENTITY: Process ENTITY declaration.
+*/
+VOID mdentity(tbuf)
+UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
+{
+ struct fpi fpicb; /* Formal public identifier structure. */
+ struct fpi *fpis = &fpicb; /* Ptr to current or #DEFAULT fpi. */
+ union etext etx; /* Ptr to entity text. */
+ UNCH estore = ESM; /* Entity storage class. */
+ struct entity *ecb; /* Ptr to entity control block. */
+ int parmsw = 0; /* 1=parameter entity declaration; 0 = not. */
+ int defltsw = 0; /* 1=#DEFAULT declaration; 0=not. */
+ PNE pne = 0; /* Ptr to N/C/SDATA entity control block. */
+
+ mdname = key[KENTITY]; /* Declaration name for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es for checking entity nesting. */
+ /* PARAMETER 1: Entity name.
+ */
+ pcbmd.newstate = 0;
+ parsemd(nmbuf, ENTCASE, &pcblitp, NAMELEN);
+ TRACEMD("1: entity nm");
+ switch (pcbmd.action) {
+ case PEN:
+ parsemd(nmbuf + 1, ENTCASE, &pcblitp, NAMELEN);
+ if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
+ if (nmbuf[1] == NAMELEN + 2) {
+ /* It was too long. */
+ nmbuf[0] = NAMELEN + 2;
+ nmbuf[NAMELEN + 1] = '\0';
+ mderr(65, (UNCH *)0, (UNCH *)0);
+ }
+ else
+ nmbuf[0] = nmbuf[1] + 1; /* Increment length for PERO. */
+ nmbuf[1] = lex.d.pero; /* Prefix PERO to name. */
+ parmsw = 1; /* Indicate parameter entity. */
+ case NAS:
+ break;
+ case RNS: /* Reserved name started. */
+ if (ustrcmp(nmbuf+1, key[KDEFAULT])) {
+ mderr(118, nmbuf+1, key[KDEFAULT]);
+ return;
+ }
+ memcpy(nmbuf, indefent, *indefent);/* Copy #DEFAULT to name buffer. */
+ fpis = &fpidf; /* Use #DEFAULT fpi if external. */
+ defltsw = 1; /* Indicate #DEFAULT is being defined.*/
+ break;
+ default:
+ mderr(122, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ subdcl = nmbuf+1; /* Subject name for error messages. */
+ /* PARAMETER 2: Entity text keyword (optional).
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ TRACEMD("2: keyword");
+ switch (pcbmd.action) {
+ case NAS:
+ if ((estore = (UNCH)mapsrch(enttab, tbuf+1))==0) {
+ estore = parmsw ? ESP : ESF;
+ pne = (PNE)rmalloc(NESZ);
+ if (mdextid(tbuf, fpis, nmbuf+1+parmsw, &estore, pne)==0)
+ return;
+ if (defltsw) etx.x = NULL;
+ else if ((etx.x = entgen(&fpicb))==0) {
+ if (parmsw)
+ mderr(148, nmbuf+2, (UNCH *)0);
+ else
+ mderr(147, nmbuf+1, (UNCH *)0);
+ }
+ goto parm4;
+ }
+ if (parmsw && (estore==ESX || estore==ESC)) {
+ mderr(38, tbuf+1, (UNCH *)0);
+ estore = ESM;
+ }
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ break;
+ default:
+ estore = ESM;
+ break;
+ }
+ /* PARAMETER 3: Parameter literal.
+ */
+ TRACEMD("3: literal");
+ switch (pcbmd.action) {
+ case LITE:
+ case LIT:
+ switch (estore) {
+ case ESM: /* LITERAL: parameter literal required. */
+ case ESC: /* CDATA: parameter literal required. */
+ case ESX: /* SDATA: parameter literal required. */
+ case ESI: /* PI: parameter literal required. */
+ etx.c = savestr(tbuf);
+ break;
+ case ESMD: /* MD: parameter literal required. */
+ etx.c = sandwich(tbuf, lex.m.mdo, lex.m.mdc);
+ goto bcheck;
+ case ESMS: /* MS: parameter literal required. */
+ etx.c = sandwich(tbuf, lex.m.mss, lex.m.mse);
+ goto bcheck;
+ case ESS: /* STARTTAG: parameter literal required. */
+ etx.c = sandwich(tbuf, lex.m.stag, lex.m.tagc);
+ goto bcheck;
+ case ESE: /* ENDTAG: parameter literal required. */
+ etx.c = sandwich(tbuf, lex.m.etag, lex.m.tagc);
+ bcheck:
+ if (etx.c == 0) {
+ mderr(225, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ break;
+ }
+ break;
+ default:
+ mderr(123, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* PARAMETER 4: End of declaration.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ parm4:
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ if (es!=mdessv) synerr(37, &pcbmd);
+
+ /* EXECUTE: If the entity already exists, ignore the new definition.
+ If it is a new entity, store the definition.
+ */
+ if ((ecb = entfind(nmbuf))!=0 && ecb->estore) {
+ if (ecb->dflt) {
+ mderr(228, nmbuf + 1, (UNCH *)0);
+ hout((THASH)etab, nmbuf, hash(nmbuf, ENTHASH));
+ if (ecb->estore == ESN) {
+ frem((UNIV)NEID(ecb->etx.n));
+ frem((UNIV)ecb->etx.n);
+ }
+ else if (ecb->estore >= ESFM)
+ frem((UNIV)ecb->etx.x);
+ frem((UNIV)ecb);
+ }
+ else {
+ /* Duplicate definition: not an error. */
+ if (sw.swdupent) mderr(68, nmbuf+1, (UNCH *)0);
+ if (estore<ESFM) frem((UNIV)etx.c);
+ return;
+ }
+ }
+ ++ds.ecbcnt; /* Do capacity before NOTATION. */
+ ds.ecbtext += estore<ESFM ? ustrlen(etx.c) : entlen;
+ ecb = entdef(nmbuf, estore, &etx); /* Define the entity. */
+ if (estore==ESN) { /* If entity is external: */
+ NEENAME(pne) = ecb->ename; /* Store entity name in ne. */
+ NEID(pne) = etx.x; /* Store system fileid in ne. */
+ NESYSID(pne) = fpis->fpisysis ? savestr(fpis->fpisysis) : 0;
+ NEPUBID(pne) = fpis->fpipubis ? savestr(fpis->fpipubis) : 0;
+ ecb->etx.n = pne; /* Store ne control block in etx. */
+ TRACEESN(pne);
+ }
+ else if (pne)
+ frem((UNIV)pne);
+ if (defltsw) {
+ ecbdeflt = ecb; /* If #DEFAULT save ecb. */
+ if (fpidf.fpipubis)
+ fpidf.fpipubis = savestr(fpidf.fpipubis);
+ if (fpidf.fpisysis)
+ fpidf.fpisysis = savestr(fpidf.fpisysis);
+ }
+}
+/* SANDWICH: Catenate a prefix and suffix to a string.
+ The result has an EOS but no length.
+ Return 0 if the result if longer than LITLEN.
+*/
+UNCH *sandwich(s, pref, suff)
+UNCH *s; /* String, with EOS. */
+UNCH *pref; /* Prefix, with length and EOS. */
+UNCH *suff; /* Suffix, with length and EOS. */
+{
+ UNCH *pt;
+ UNS slen, tlen;
+
+ slen = ustrlen(s);
+ tlen = slen + (*pref - 2) + (*suff - 2);
+ if (tlen > LITLEN)
+ return 0;
+ pt = (UNCH *)rmalloc(tlen + 1);
+ memcpy(pt, pref + 1, *pref - 2);
+ memcpy(pt + (*pref - 2), s, slen);
+ memcpy(pt + (*pref - 2) + slen, suff + 1, *suff - 1);
+ return pt;
+}
+/* MDEXTID: Process external identifier parameter of a markup declaration.
+ On entry, tbuf contains SYSTEM or PUBLIC if all is well.
+ NULL is returned if an error, otherwise fpis. If it is a
+ valid external data entity, the caller's estore is set to ESN
+ and its nxetype is set to the code for the external entity type.
+ The event that terminated the parse is preserved in pcb.action,
+ so the caller should process it before further parsing.
+*/
+struct fpi *mdextid(tbuf, fpis, ename, estore, pne)
+UNCH *tbuf; /* Work area for tokenization[2*(LITLEN+2)]. */
+struct fpi *fpis; /* FPI structure. */
+UNCH *ename; /* Entity or notation name, with EOS, no length.*/
+ /* NOTE: No PERO on parameter entity name. */
+UNCH *estore; /* DTD, general or parameter entity, DCN. */
+PNE pne; /* Caller's external entity ptr. */
+{
+ PDCB dcb; /* Ptr to DCN control block. */
+ int exidtype; /* External ID type: 0=none 1=system 2=public. */
+ int exetype; /* External entity type. */
+
+ MEMZERO((UNIV)fpis, (UNS)FPISZ); /* Initialize fpi structure. */
+ /* Move entity name into fpi (any PERO was stripped by caller). */
+ fpis->fpinm = ename;
+ entlen = 0; /* Initialize external ID length. */
+
+ /* PARAMETER 1: External identifier keyword or error.
+ */
+ TRACEMD("1: extid keyword");
+ if ((exidtype = mapsrch(exttab, tbuf+1))==0) {
+ mderr(29, (UNCH *)0, (UNCH *)0);
+ return (struct fpi *)0;
+ }
+ if (exidtype==EDSYSTEM) goto parm3;
+
+ /* PARAMETER 2: Public ID literal.
+ */
+ /* The length of a minimum literal cannot exceed the value of LITLEN
+ in the reference quantity set. */
+ parsemd(pubibuf, NAMECASE, &pcblitv, REFLITLEN);
+ TRACEMD("2: pub ID literal");
+ switch (pcbmd.action) {
+ case LITE: /* Use alternative literal delimiter. */
+ case LIT: /* Save literal as public ID string. */
+ entlen = ustrlen(pubibuf);
+ fpis->fpipubis = pubibuf;
+ break;
+ default:
+ mderr(117, (UNCH *)0, (UNCH *)0);
+ return (struct fpi *)0; /* Signal error to caller. */
+ }
+ /* PARAMETER 3: System ID literal.
+ */
+ parm3:
+ parsemd(sysibuf, NAMECASE, &pcblitc, LITLEN);
+ TRACEMD("3: sys ID literal");
+ if (pcbmd.action==LIT || pcbmd.action==LITE) {
+ entlen += ustrlen(sysibuf);
+ fpis->fpisysis = sysibuf;
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ }
+ else memcpy(tbuf, sysibuf, *sysibuf);
+ if (*estore!=ESF || pcbmd.action!=NAS) goto genfpi;
+
+ /* PARAMETER 4: Entity type keyword.
+ */
+ TRACEMD("4: Entity type");
+ if ((exetype = mapsrch(extettab, tbuf+1))==0) {
+ mderr(24, tbuf+1, (UNCH *)0);
+ return (struct fpi *)0;
+ }
+ if (exetype==ESNSUB && SUBDOC == NO) {
+ mderr(90, tbuf+1, (UNCH *)0);
+ return (struct fpi *)0;
+ }
+
+ NEXTYPE(pne) = (UNCH)exetype; /* Save entity type in caller's ne. */
+ *estore = ESN; /* Signal that entity is a data entity. */
+
+ if (exetype==ESNSUB) {
+ pne->nedcn = 0;
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+ goto genfpi;
+ }
+ /* PARAMETER 5: Notation name.
+ */
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("5: notation");
+ if (pcbmd.action!=NAS) {mderr(119, tbuf+1, (UNCH *)0); return (struct fpi *)0;}
+ /* Locate the data content notation. */
+ pne->nedcn = dcb = dcndef(lbuf);
+ /* Note that we have defined an entity with this notation.
+ If attributes are later defined for this notation, we'll
+ have to fix up this entity. */
+ dcb->entsw = 1;
+
+ /* PARAMETER 6: Data attribute specification.
+ */
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("6: [att list]");
+ if (pcbmd.action!=MDS) { /* No attributes specified. */
+ if (dcb->adl == 0)
+ NEAL(pne) = 0;
+ else {
+ initatt(dcb->adl);
+ adlval((int)ADN(al), (struct etd *)0);
+ storedatt(pne);
+ }
+ goto genfpi;
+ }
+ if (dcb->adl==0) { /* Atts specified, but none defined. */
+ mderr(22, (UNCH *)0, (UNCH *)0);
+ return (struct fpi *)0;
+ }
+ pcbstag.newstate = pcbstan; /* First separator is optional. */
+ if ((parseatt(dcb->adl, tbuf))==0)/* Empty list. */
+ mderr(91, (UNCH *)0, (UNCH *)0);
+ else {
+ adlval((int)ADN(al), (struct etd *)0);
+ storedatt(pne);
+ }
+ parse(&pcbeal); /* Parse the list ending. */
+ parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
+
+ /* GENFPI: Builds a formal public identifier structure, including the
+ entity name, offsets of the components of the public ID, and
+ other data a system might use to identify the actual file.
+ */
+ genfpi:
+ TRACEMD("7: generate fpi");
+ fpis->fpistore = *estore - ESFM + 1; /* External entity type: 1-6. */
+ if (*estore == ESN) {
+ if (NEXTYPE(pne) == ESNSUB)
+ fpis->fpinedcn = 0;
+ else
+ fpis->fpinedcn = NEDCN(pne) + 1;
+ }
+ /* Analyze public ID and make structure entries. */
+ if (exidtype==EDPUBLIC) {
+ if (parsefpi(fpis)>0) {
+ if (FORMAL==YES)
+ mderr(88, fpis->fpipubis, (UNCH *)0);
+ fpis->fpiversw = -1; /* Signal bad formal public ID. */
+ }
+ }
+ return fpis;
+}
+
+/* Store a data attribute. */
+
+VOID storedatt(pne)
+PNE pne;
+{
+ int i;
+
+ NEAL(pne) = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
+ memcpy((UNIV)NEAL(pne), (UNIV)al, (1+ADN(al))*ADSZ);
+ for (i = 1; i <= (int)ADN(al); i++) {
+ if (GET(ADFLAGS(al, i), ASPEC))
+ ds.attdef += ADLEN(al, i);
+ if (NEAL(pne)[i].addef != 0)
+ NEAL(pne)[i].addef = savestr(NEAL(pne)[i].addef);
+ }
+ ds.attcnt += AN(al); /* Number of attributes defined. */
+#if 0
+ /* I can't see any reason to increase AVGRPCNT here. */
+ ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
+#endif
+}
+
+/* PARSEFPI: Parses a formal public identifier and builds a control block.
+ PARSEFPI returns a positive error code (1-10), or 0 if no errors.
+ It set fpiversw if no version was specified in the ID and the
+ public text is in a class that permits display versions.
+ Note: An empty version ("//") can be specified (usually it is
+ the non-device-specific form, such as a definitional entity set).
+*/
+int parsefpi(f)
+PFPI f; /* Ptr to formal public identifier structure. */
+{
+ UNCH *l; /* Pointer to EOS of public identifier. */
+ UNCH *p, *q; /* Ptrs to current field in public identifier. */
+ UNS len; /* Field length */
+
+ p = f->fpipubis; /* Point to start of identifier. */
+ l = p + ustrlen(p); /* Point to EOS of identifier. */
+ if ((*p=='+' || *p=='-')
+ && p[1] == '/' && p[2] == '/') { /* If owner registered,
+ unregistered. */
+ f->fpiot = *p; /* Save owner type. */
+ p += 3;
+ }
+ else f->fpiot = '!'; /* Indicate ISO owner identifier. */
+ if ((q = pubfield(p, l, '/', &len))==0) /* Find end of owner ID field. */
+ return 2;
+ f->fpiol = len; /* Save owner ID length. */
+ f->fpio = p - f->fpipubis; /* Save offset in pubis to owner ID. */
+
+ if ((p = pubfield(q, l, ' ', &len))==0) /* Find end of text class field. */
+ return 3;
+ *(--p) = EOS; /* Temporarily make class a string. */
+ f->fpic = mapsrch(pubcltab, q); /* Check for valid uc class name.*/
+ *p++ = ' '; /* Restore the SPACE delimiter. */
+ if (f->fpic==0) return 4; /* Error if not valid uc class name.*/
+
+ /* The public text class in a notation identifier must be NOTATION. */
+ if (f->fpistore == ESK - ESFM + 1 && f->fpic != FPINOT) return 10;
+
+ if (*p=='-' && p[1] == '/' && p[2] == '/') { /* If text is unavailable
+ public text.*/
+ f->fpitt = *p; /* Save text type. */
+ p += 3;
+ }
+ else f->fpitt = '+'; /* Indicate available public text. */
+ if ((q = pubfield(p, l, '/', &len))==0) /* Find end of text description. */
+ return 6;
+ f->fpitl = len; /* Save text description length. */
+ f->fpit = p - f->fpipubis; /* Save ptr to description.*/
+
+ p = pubfield(q, l, '/', &len); /* Bound language field. */
+ if (f->fpic != FPICHARS) {
+ int i;
+ /* Language must be all upper-case letters. */
+ /* The standard only says that it *should* be two letters, so
+ don't enforce that. */
+ /* Language must be a name, which means it can't be empty. */
+ if (len == 0)
+ return 7;
+ for (i = 0; i < len; i++) {
+ /* Don't assume ASCII. */
+ if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", q[i]))
+ return 7;
+ }
+ }
+ f->fpill = len;
+ f->fpil = q - f->fpipubis;
+ if (p!=0) { /* If there is a version field: */
+ if (f->fpic<FPICMINV) /* Error if class prohibits versions. */
+ return 8;
+ if ((pubfield(p, l, '/', &len))!=0) /* Bound version field. */
+ return 9; /* Error if yet another field. */
+ f->fpivl = len; /* Save version length. */
+ f->fpiv = p - f->fpipubis; /* Save ptr (in pubis) to version. */
+ }
+ else if (f->fpic>=FPICMINV) f->fpiversw = 1;/* No version: get the best. */
+ return(0);
+}
+/* PUBFIELD: Returns ptr to next field, or NULL if ID has ended.
+*/
+#ifdef USE_PROTOTYPES
+UNCH *pubfield(UNCH *p, UNCH *l, UNCH d, UNS *lenp)
+#else
+UNCH *pubfield(p, l, d, lenp)
+UNCH *p; /* Public identifier field (no length or EOS). */
+UNCH *l; /* Pointer to EOS of public identifier. */
+UNCH d; /* Field delimiter: ' ' or '/'. */
+UNS *lenp; /* Gets field length */
+#endif
+{
+ UNCH *psv = p+1; /* Save starting value of p. */
+
+ while (p<l) {
+ if (*p++==d) { /* Test for delimiter character. */
+ *lenp = p - psv; /* Save field length (no len or EOS). */
+ if (d=='/' && *p++!=d) /* Solidus requires a second one. */
+ continue;
+ return(p); /* Return ptr to next field. */
+ }
+ }
+ *lenp = p - --psv; /* Save field length (no len or EOS). */
+ return NULL;
+}
+/* MDMS: Process marked section start.
+ If already in special parse, bump the level counters and return
+ without parsing the declaration.
+*/
+struct parse *mdms(tbuf, pcb)
+UNCH *tbuf; /* Work area for tokenization [NAMELEN+2]. */
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ int key; /* Index of keyword in mslist. */
+ int ptype; /* Parameter token type. */
+ int pcbcode = 0; /* Parse code: 0=same; 2-4 per defines. */
+
+ if (++mslevel>TAGLVL) {
+ --mslevel;
+ sgmlerr(27, (struct parse *)0, ntoa(TAGLVL), (UNCH *)0);
+ }
+
+ /* If already in IGNORE mode, return without parsing parameters. */
+ if (msplevel) {++msplevel; return(pcb);}
+
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es for checking entity nesting. */
+ pcbmd.newstate = pcbmdtk; /* First separator is optional. */
+
+ /* PARAMETERS: TEMP, RCDATA, CDATA, IGNORE, INCLUDE, or MDS. */
+ while ((ptype = parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN))==NAS){
+ if ((key = mapsrch(mstab, tbuf+1))==0) {
+ sgmlerr(64, (struct parse *)0, ntoa(parmno), tbuf+1);
+ continue;
+ }
+ if (key==MSTEMP) continue; /* TEMP: for documentation. */
+ msplevel = 1; /* Special parse required. */
+ if (key>pcbcode) pcbcode = key; /* Update if higher priority. */
+ }
+ if (ptype!=MDS) {
+ NEWCC; /* Syntax error did REPEATCC. */
+ sgmlerr(97, (struct parse *)0, lex.m.dso, (UNCH *)0);
+ REPEATCC; /* 1st char of marked section. */
+ }
+ if (es!=mdessv) synerr(37, pcb);
+ TRACEMS(1, pcbcode, mslevel, msplevel);
+ if (pcbcode==MSIGNORE) pcb = &pcbmsi;
+ else if (pcbcode) {
+ pcb = pcbcode==MSCDATA ? &pcbmsc : (rcessv = es, &pcbmsrc);
+ }
+ return(pcb); /* Tell caller whether to change the parse. */
+}
+/* MDMSE: Process marked section end.
+ Issue an error if no marked section had started.
+*/
+int mdmse()
+{
+ int retcode = 0; /* Return code: 0=same parse; 1=cancel special. */
+
+ if (mslevel) --mslevel;
+ else sgmlerr(26, (struct parse *)0, (UNCH *)0, (UNCH *)0);
+
+ if (msplevel) if (--msplevel==0) retcode = 1;
+ TRACEMS(0, retcode, mslevel, msplevel);
+ return retcode;
+}
+/* MDNOT: Process NOTATION declaration.
+*/
+VOID mdnot(tbuf)
+UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
+{
+ struct fpi fpicb; /* Formal public identifier structure. */
+ PDCB dcb; /* Ptr to notation entity in dcntab. */
+ UNCH estore = ESK; /* Entity storage class. */
+
+ mdname = key[KNOTATION]; /* Identify declaration for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es for checking entity nesting. */
+
+ /* PARAMETER 1: Notation name.
+ */
+ pcbmd.newstate = 0;
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: name");
+ if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
+ subdcl = lbuf+1; /* Save notation name for error msgs. */
+
+ /* PARAMETER 2: External identifier keyword.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: extid");
+ if (pcbmd.action!=NAS) {mderr(29, (UNCH *)0, (UNCH *)0); return;}
+ if (mdextid(tbuf, &fpicb, lbuf+1, &estore, (PNE)0)==0) return;
+
+ /* PARAMETER 3: End of declaration.
+ Token was parsed by MDEXTID.
+ */
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ if (es!=mdessv) synerr(37, &pcbmd);
+
+ /* EXECUTE: Store notation name.
+ */
+ if ((dcb = dcnfind(lbuf)) != 0 && dcb->defined) {
+ mderr(56, lbuf+1, (UNCH *)0);
+ return;
+ }
+ /* else */
+ dcb = dcndef(lbuf);
+ dcb->defined = 1;
+ dcb->sysid = fpicb.fpisysis ? savestr(fpicb.fpisysis) : 0;
+ dcb->pubid = fpicb.fpipubis ? savestr(fpicb.fpipubis) : 0;
+ ++ds.dcncnt;
+ ds.dcntext += entlen;
+ TRACEDCN(dcb);
+ return;
+}
+/* DCNDEF: Define a notation and return its DCNCB.
+ If caller does not care if it already exists,
+ he should specify NULL for the notation text
+ so we don't clobber the existing text (if any).
+*/
+struct dcncb *dcndef(nname)
+UNCH *nname; /* Notation name (with length and EOS). */
+{
+ return((PDCB)hin((THASH)dcntab, nname, 0, DCBSZ));
+}
+/* DCNFIND: If a notation was declared, return its DCNCB.
+ Return NULL if it is not defined.
+*/
+struct dcncb *dcnfind(nname)
+UNCH *nname; /* Notation name (with length and EOS). */
+{
+ return((PDCB)hfind((THASH)dcntab, nname, 0));
+}
+#define SRM(i) (srhptr->srhsrm[i]) /* Current entry in SHORTREF map. */
+/* MDSRMDEF: Process short reference mapping declaration.
+*/
+VOID mdsrmdef(tbuf)
+UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
+{
+ struct entity *entcb; /* Ptr to defined entity. */
+ PSRH srhptr; /* Ptr to short reference map hdr (in srhtab).*/
+ int srn; /* Short reference delimiter number in srdeltab.*/
+ int mapused = 0; /* Has map already been used? */
+
+ mdname = key[KSHORTREF]; /* Identify declaration for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ if (!sd.shortref) {mderr(198, (UNCH *)0, (UNCH *)0); return;}
+ mdessv = es; /* Save es for checking entity nesting. */
+ /* PARAMETER 1: SHORTREF map name.
+ */
+ pcbmd.newstate = 0;
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: map nm");
+ if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
+ if ((srhptr = srhfind(tbuf))!=0) {
+ mapused = 1;
+ /* Error if map was declared (not just used). */
+ if (SRM(0)) {mderr(56, tbuf+1, (UNCH *)0); return;}
+ }
+ else srhptr = srhdef(tbuf); /* Create map with SRs mapped to NULL.*/
+ SRM(0) = (PECB)srhptr; /* Indicate map was actually declared.*/
+ subdcl = srhptr->ename+1; /* Save map name for error msgs. */
+
+ while (parsemd(tbuf, NAMECASE, &pcblitp, SRMAXLEN) == LIT
+ || pcbmd.action==LITE ) {
+ /* PARAMETER 2: Delimiter string.
+ */
+ TRACEMD("2: SR string");
+ if ((srn = mapsrch(lex.s.dtb, tbuf))==0) {
+ mderr(124, tbuf, (UNCH *)0);
+ goto cleanup;
+ }
+ /* PARAMETER 3: Entity name.
+ */
+ parsemd(tbuf, ENTCASE, &pcblitp, NAMELEN);
+ TRACEMD("3: entity");
+ if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); goto cleanup;}
+ if ((entcb = entfind(tbuf))==0) {
+ union etext etx;
+ etx.x = 0;
+ entcb = entdef(tbuf, '\0', &etx);
+ }
+ if (SRM(srn)) {
+ mderr(56, (srn<lex.s.prtmin ? (UNCH *)lex.s.pdtb[srn]
+ : lex.s.dtb[srn].mapnm), (UNCH *)0);
+ continue;
+ }
+ SRM(srn) = entcb;
+ if (srn>=lex.s.fce && srn!=lex.s.hyp && srn!=lex.s.hyp2
+ && srn!=lex.s.lbr && srn!=lex.s.rbr)
+ lexcnm[*lex.s.dtb[srn].mapnm] = lex.l.fce;
+ else if (srn==lex.s.spc) lexcnm[' '] = lex.l.spcr;
+ }
+ /* PARAMETER 4: End of declaration.
+ */
+ TRACEMD(emd);
+ if (parmno==2)
+ {mderr((UNS)(pcbmd.action==EMD ? 28:123), (UNCH *)0, (UNCH *)0); goto cleanup;}
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ if (es!=mdessv) synerr(37, &pcbmd);
+ ++ds.srcnt;
+ TRACESRM("SHORTREF", srhptr->srhsrm, (UNCH *)0);
+ return;
+
+ cleanup:
+ /* Don't free the map if the map was in use (because of a USEMAP
+ declaration) before this declaration. */
+ if (mapused)
+ MEMZERO((UNIV)srhptr->srhsrm, sizeof(PECB)*(lex.s.dtb[0].mapdata+1));
+ else {
+ frem((UNIV)srhptr->srhsrm);
+ hout((THASH)srhtab, srhptr->ename, 0);
+ frem((UNIV)srhptr);
+ }
+}
+/* MDSRMUSE: Activate a short reference map.
+*/
+VOID mdsrmuse(tbuf)
+UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
+{
+ PSRH srhptr; /* Ptr to short reference map hdr (in srhtab).*/
+ TECB srmptr; /* Ptr to short reference map (in header). */
+ int i; /* Loop counter; temporary variable. */
+
+ mdname = key[KUSEMAP]; /* Identify declaration for messages. */
+ subdcl = NULL; /* No subject as yet. */
+ parmno = 0; /* No parameters as yet. */
+ mdessv = es; /* Save es for checking entity nesting. */
+ /* PARAMETER 1: SHORTREF map name or "#EMPTY".
+ */
+ pcbmd.newstate = 0;
+ parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("1: map nm");
+ subdcl = lbuf+1; /* Subject name for error messages. */
+ switch (pcbmd.action) {
+ case RNS: /* Empty SHORTREF map requested. */
+ if (ustrcmp(lbuf+1, key[KEMPTY])) {
+ mderr(118, lbuf+1, key[KEMPTY]);
+ return;
+ }
+ srmptr = SRMNULL;
+ break;
+ case NAS: /* Map name specified; save if undefined. */
+ if ((srhptr = srhfind(lbuf))==0) {
+ if (!indtdsw) {mderr(125, (UNCH *)0, (UNCH *)0); return;}
+ srmptr = NULL;
+ }
+ else
+ srmptr = srhptr->srhsrm;
+ break;
+ default:
+ mderr(120, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* PARAMETER 2: Element name or a group of them. (In DTD only.)
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD("2: GI or grp");
+ switch (pcbmd.action) {
+ case NAS:
+ if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
+ nmgrp[0] = etddef(tbuf);
+ nmgrp[1] = (PETD)NULL;
+ break;
+ case GRPS:
+ if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
+ parsegrp(nmgrp, &pcbgrnm, tbuf);
+ break;
+ case EMD:
+ if (indtdsw) {mderr(28, (UNCH *)0, (UNCH *)0); return;}
+ if (docelsw) {mderr(233, (UNCH *)0, (UNCH *)0); return;}
+ tags[ts].tsrm = srmptr;
+ TRACESRM("USEMAP", tags[ts].tsrm, tags[ts].tetd->etdgi+1);
+ goto realemd;
+ default:
+ mderr(indtdsw ? 121 : 126, (UNCH *)0, (UNCH *)0);
+ return;
+ }
+ /* PARAMETER 3: End of declaration.
+ */
+ parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
+ TRACEMD(emd);
+ if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
+ /* If map has not yet been defined, do it and get map pointer. */
+ if (!srmptr) srmptr = (srhdef(lbuf))->srhsrm;
+
+ /* Store the map pointer for each element name specified.
+ */
+ TRACEGRP(nmgrp);
+ for (i = -1; nmgrp[++i];) {
+ if (!nmgrp[i]->etdsrm) nmgrp[i]->etdsrm = srmptr;
+ else if (sw.swdupent) mderr(68, nmgrp[i]->etdgi+1, (UNCH *)0);
+ }
+ realemd:
+ if (es!=mdessv) synerr(37, &pcbmd);
+}
+/* SRHDEF: Define a SHORTREF map and return ptr to its header.
+ All entries in map are mapped to NULL.
+ Caller must determine whether it already exists.
+*/
+PSRH srhdef(sname)
+UNCH *sname; /* SHORTREF map name (with length and EOS). */
+{
+ PSRH srh; /* Ptr to SHORTREF map hdr in srhtab. */
+
+ (srh = (PSRH)hin((THASH)srhtab, sname, 0, SRHSZ))->srhsrm =
+ (TECB)rmalloc((UNS)(lex.s.dtb[0].mapdata+1)*sizeof(PECB));
+ return(srh);
+}
+/* SRHFIND: If a SHORTREF map was declared, return the ptr to its header.
+ Return NULL if it is not defined.
+*/
+PSRH srhfind(sname)
+UNCH *sname; /* SHORTREF map name (with length and EOS). */
+{
+ return((PSRH)hfind((THASH)srhtab, sname, 0));
+}
+#undef SRM
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/msg.h b/usr.bin/sgmls/sgmls/msg.h
new file mode 100644
index 0000000..5526337
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/msg.h
@@ -0,0 +1,258 @@
+/*
+Severity codes:
+I information (not an SGML error at all)
+W warning (an SGML markup error but it knows what you mean)
+E error
+C critical (fatal)
+
+Type codes:
+R resource
+C ?context/content
+M minimization
+Q quantity
+S syntax
+D declaration
+U unsupported feature
+*/
+struct {
+ char *text;
+ char severity;
+ char type;
+} messages[] = {
+/* 0 */ {0},
+/* 1 */ {"%s element not allowed at this point in %s element", 'E', 'C'},
+/* 2 */ {"%s markup declaration not permitted here; declaration ended", 'E', 'D'},
+/* 3 */ {"Length of name, number, or token exceeded NAMELEN or LITLEN limit", 'E', 'Q'},
+/* 4 */ {"Non-SGML character ignored", 'E', 'S'},
+/* 5 */ {"%s end-tag ignored: doesn't end any open element (current is %s)", 'E', 'C'},
+/* 6 */ {"%s start-tag exceeds open element limit; possible lies from %s on", 'E', 'Q'},
+/* 7 */ {"Start-tag omitted from %s with empty content", 'E', 'M'},
+/* 8 */ {"Illegal entity end in markup or delimited text", 'E', 'S'},
+/* 9 */ {"Incorrect character in markup; markup terminated", 'E', 'S'},
+/* 10 */ {"Data not allowed at this point in %s element", 'E', 'C'},
+/* 11 */ {"No element declaration for %s end-tag GI; end-tag ignored", 'E', 'C'},
+/* 12 */ {"%s name ignored: not a syntactically valid SGML name", 'E', 'S'},
+/* 13 */ {"%s = \"%s\" attribute ignored: not defined for this element", 'E', 'C'},
+/* 14 */ {"%s = \"%s\" attribute value defaulted: invalid character", 'E', 'S'},
+/* 15 */ {"%s = \"%s\" attribute value defaulted: token too long", 'E', 'Q'},
+/* 16 */ {"%s = \"%s\" attribute value defaulted: too many tokens", 'E', 'C'},
+/* 17 */ {"%s = \"%s\" attribute value defaulted: wrong token type", 'E', 'C'},
+/* 18 */ {"%s = \"%s\" attribute value defaulted: token not in group", 'E', 'C'},
+/* 19 */ {"Required %s attribute was not specified; may affect processing", 'E', 'C'},
+/* 20 */ {"%s end-tag implied by %s end-tag; not minimizable", 'E', 'M'},
+/* 21 */ {"%s start-tag implied by %s start-tag; not minimizable", 'W', 'M'},
+/* 22 */ {"Possible attributes treated as data because none were defined", 'E', 'C'},
+/* 23 */ {"Duplicate specification occurred for \"%s\"; may affect processing", 'E', 'D'},
+/* 24 */ {"\"%s\" keyword invalid; declaration terminated", 'E', 'D'},
+/* 25 */ {"%s = \"%s\" attribute defaulted: empty string not allowed for token", 'E', 'C'},
+/* 26 */ {"Marked section end ignored; not in a marked section", 'E', 'S'},
+/* 27 */ {"Marked section start ignored; %s marked sections open already", 'E', 'Q'},
+/* 28 */ {"One or more parameters missing; declaration ignored", 'E', 'D'},
+/* 29 */ {"\"PUBLIC\" or \"SYSTEM\" required; declaration terminated", 'E', 'D'},
+/* 30 */ {"%s element ended prematurely; required %s omitted", 'E', 'C'},
+/* 31 */ {"Entity \"%s\" terminated: could not read file", 'E', 'R'},
+/* 32 */ {"Could not open file for entity \"%s\"; entity reference ignored", 'E', 'R'},
+/* 33 */ {"Insufficient main memory; unable to continue parsing", 'C', 'R'},
+/* 34 */ {"%s entity reference ignored; exceeded open entity limit (%s)", 'E', 'Q'},
+/* 35 */ {"No declaration for entity \"%s\"; reference ignored", 'E', 'C'},
+/* 36 */ {"%s entity reference occurred within own text; reference ignored", 'E', 'C'},
+/* 37 */ {"Entity nesting level out of sync", 'E', 'S'},
+/* 38 */ {"Parameter entity text cannot have %s keyword; keyword ignored", 'E', 'D'},
+/* 39 */ {"%s end-tag implied by %s start-tag; not minimizable", 'W', 'M'},
+/* 40 */ {"Start-tag minimization ignored; element has required attribute", 'E', 'D'},
+/* 41 */ {"Required %s element cannot be excluded from %s element", 'E', 'C'},
+/* 42 */ {"No DOCTYPE declaration; document type is unknown", 'E', 'C'},
+/* 43 */ {"Undefined %1$s start-tag GI was used in DTD; \"%1$s O O ANY\" assumed", 'E', 'C'},
+/* 44 */ {"Invalid character(s) ignored; attempting to resume DOCTYPE subset", 'E', 'S'},
+/* 45 */ {"No declaration for entity \"%s\"; default definition used", 'I', 'C'},
+/* 46 */ {"%s end-tag implied by NET delimiter; not minimizable", 'W', 'M'},
+/* 47 */ {"%s end-tag implied by data; not minimizable", 'W', 'M'},
+/* 48 */ {"%s end-tag implied by short start-tag (no GI); not minimizable", 'W', 'M'},
+/* 49 */ {"%s start-tag implied by data; not minimizable", 'W', 'M'},
+/* 50 */ {"%s start-tag implied by short start-tag (no GI); not minimizable", 'W', 'M'},
+/* 51 */ {"Short end-tag (no GI) ignored: no open elements", 'E', 'C'},
+/* 52 */ {"No definition for %1$s document type; \"%1$s O O ANY\" assumed", 'E', 'C'},
+/* 53 */ {"No definition for %1$s implied start-tag; \"%1$s O O ANY\" assumed", 'E', 'C'},
+/* 54 */ {"%s element ended prematurely; required subelement omitted", 'E', 'C'},
+/* 55 */ {"Content model token %s: connectors conflict; first was used", 'E', 'D'},
+/* 56 */ {"Duplicate specification occurred for \"%s\"; duplicate ignored", 'E', 'D'},
+/* 57 */ {"Bad end-tag in R/CDATA element; treated as short (no GI) end-tag", 'E', 'S'},
+/* 58 */ {"Start-tag minimization should be \"-\" for element with declared content", 'I', 'D'},
+/* 59 */ {"Reference to PI entity not permitted here; reference ignored", 'E', 'S'},
+/* 60 */ {"Non-SGML character found; should have been character reference", 'W', 'S'},
+/* 61 */ {"Numeric character reference exceeds 255; reference ignored", 'E', 'S'},
+/* 62 */ {"Invalid alphabetic character reference ignored", 'E', 'S'},
+/* 63 */ {"Invalid character in minimum literal; character ignored", 'E', 'S'},
+/* 64 */ {"Keyword %s ignored; \"%s\" is not a valid marked section keyword", 'E', 'D'},
+/* 65 */ {"Parameter entity name longer than (NAMELEN-1); truncated", 'E', 'Q'},
+/* 66 */ {"Start-tag length exceeds TAGLEN limit; parsed correctly", 'W', 'Q'},
+/* 67 */ {"%s attribute defaulted: FIXED attribute must equal default", 'W', 'C'},
+/* 68 */ {"Duplicate specification occurred for \"%s\"; duplicate ignored", 'I', 'D'},
+/* 69 */ {"%s = \"%s\" IDREF attribute ignored: referenced ID does not exist", 'E', 'C'},
+/* 70 */ {"%s = \"%s\" IDREF attribute ignored: number of IDs in list exceeds GRPCNT limit", 'E', 'Q'},
+/* 71 */ {"%s = \"%s\" ID attribute ignored: ID in use for another element", 'E', 'C'},
+/* 72 */ {"%s = \"%s\" ENTITY attribute not general entity; may affect processing", 'E', 'C'},
+/* 73 */ {"%s = \"%s\" attribute ignored: previously specified in same list", 'W', 'C'},
+/* 74 */ {"\"?\" = \"%s\" name token ignored: not in any group in this list", 'E', 'C'},
+/* 75 */ {"Normalized attribute specification length over ATTSPLEN limit", 'E', 'Q'},
+/* 76 */ {"%s = \"%s\" NOTATION ignored: element content is empty", 'E', 'C'},
+/* 77 */ {"%s = \"%s\" NOTATION undefined: may affect processing", 'E', 'C'},
+/* 78 */ {"Entity \"%2$s\" has undefined notation \"%1$s\"", 'E', 'C'},
+/* 79 */ {"%s = \"%s\" default attribute value not in group; #IMPLIED used", 'E', 'C'},
+/* 80 */ {"#CURRENT default value treated as #IMPLIED for %s ID attribute", 'E', 'D'},
+/* 81 */ {"ID attribute %s cannot have a default value; treated as #IMPLIED", 'E', 'D'},
+/* 82 */ {"%s attribute must be token, not empty string; treated as #IMPLIED", 'E', 'D'},
+/* 83 */ {"NOTATION attribute ignored for EMPTY element", 'E', 'D'},
+/* 84 */ {"%s = \"%s\" NOTATION ignored: content reference specified", 'E', 'C'},
+/* 85 */ {"#CONREF default value treated as #IMPLIED for EMPTY element", 'W', 'D'},
+/* 86 */ {"%s = \"%s\" entity not data entity; may affect processing", 'E', 'C'},
+/* 87 */ {"End-tag minimization should be \"O\" for EMPTY element", 'I', 'D'},
+/* 88 */ {"Formal public identifier \"%s\" invalid; treated as informal", 'E', 'S'},
+/* 89 */ {"Out-of-context %2$s start-tag ended %1$s document element (and parse)", 'E', 'C'},
+/* 90 */ {"\"%s\" keyword is for unsupported feature; declaration terminated", 'E', 'D'},
+/* 91 */ {"Attribute specification list in prolog cannot be empty", 'E', 'D'},
+/* 92 */ {"Document ended invalidly within a literal; parsing ended", 'C', 'S'},
+/* 93 */ {"General entity \"%s\" in short reference map \"%s\" undeclared", 'E', 'D'},
+/* 94 */ {"Could not reopen file to continue entity \"%s\"; entity terminated", 'E', 'R'},
+/* 95 */ {"Out-of-context data ended %s document element (and parse)", 'E', 'C'},
+/* 96 */ {"Short start-tag (no GI) ended %s document element (and parse)", 'E', 'C'},
+/* 97 */ {"DSO delimiter (%s) omitted from marked section declaration", 'E', 'D'},
+/* 98 */ {"Group token %s: duplicate name or name token \"%s\" ignored", 'E', 'D'},
+/* 99 */ {"Attempt to redefine %s attribute ignored", 'E', 'D'},
+/* 100 */ {"%s definition ignored: %s is not a valid declared value keyword", 'E', 'D'},
+/* 101 */ {"%s definition ignored: NOTATION attribute already defined", 'E', 'D'},
+/* 102 */ {"%s definition ignored: ID attribute already defined", 'E', 'D'},
+/* 103 */ {"%s definition ignored: no declared value specified", 'E', 'D'},
+/* 104 */ {"%s definition ignored: invalid declared value specified", 'E', 'D'},
+/* 105 */ {"%s definition ignored: number of names or name tokens in group exceeded GRPCNT limit", 'E', 'D'},
+/* 106 */ {"%s definition ignored: name group omitted for NOTATION attribute", 'E', 'D'},
+/* 107 */ {"#CONREF default value treated as #IMPLIED for %s ID attribute", 'E', 'D'},
+/* 108 */ {"%s definition ignored: %s is not a valid default value keyword", 'E', 'D'},
+/* 109 */ {"%s definition ignored: no default value specified", 'E', 'D'},
+/* 110 */ {"%s definition ignored: invalid default value specified", 'E', 'D'},
+/* 111 */ {"More than ATTCNT attribute names and/or name (token) values; terminated", 'E', 'D'},
+/* 112 */ {"Attempted redefinition of attribute definition list ignored", 'E', 'D'},
+/* 113 */ {"Content model token %s: more than GRPCNT model group tokens; terminated", 'E', 'Q'},
+/* 114 */ {"Content model token %s: more than GRPGTCNT content model tokens; terminated", 'E', 'Q'},
+/* 115 */ {"Content model token %s: more than GRPLVL nested model groups; terminated", 'E', 'Q'},
+/* 116 */ {"Content model token %s: %s invalid; declaration terminated", 'E', 'D'},
+/* 117 */ {"\"PUBLIC\" specified without public ID; declaration terminated", 'E', 'D'},
+/* 118 */ {"\"%s\" keyword invalid (only %s permitted); declaration terminated", 'E', 'D'},
+/* 119 */ {"\"%s\" specified without notation name; declaration terminated", 'E', 'D'},
+/* 120 */ {"Parameter must be a name; declaration terminated", 'E', 'D'},
+/* 121 */ {"Parameter must be a GI or a group of them; declaration terminated", 'E', 'D'},
+/* 122 */ {"Parameter must be a name or PERO (%%); declaration terminated", 'E', 'D'},
+/* 123 */ {"Parameter must be a literal; declaration terminated", 'E', 'D'},
+/* 124 */ {"\"%s\" not valid short reference delimiter; declaration terminated", 'E', 'D'},
+/* 125 */ {"Map does not exist; declaration ignored", 'E', 'C'},
+/* 126 */ {"MDC delimiter (>) expected; following text may be misinterpreted", 'E', 'D'},
+/* 127 */ {"Document ended invalidly within prolog; parsing ended", 'C', 'S'},
+/* 128 */ {"\"PUBLIC\" or \"SYSTEM\" or DSO ([) required; declaration terminated", 'E', 'D'},
+/* 129 */ {"Minimization must be \"-\" or \"O\" (not \"%s\"); declaration terminated", 'E', 'D'},
+/* 130 */ {"Content model or keyword expected; declaration terminated", 'E', 'D'},
+/* 131 */ {"Rank stem \"%s\" + suffix \"%s\" more than NAMELEN characters; not defined", 'E', 'D'},
+/* 132 */ {"Undefined %s start-tag GI ignored; not used in DTD", 'E', 'C'},
+/* 133 */ {"Document ended invalidly within a markup declaration; parsing ended", 'C', 'S'},
+/* 134 */ {"Normalized length of literal exceeded %s; markup terminated", 'E', 'Q'},
+/* 135 */ {"R/CDATA marked section in declaration subset; prolog terminated", 'E', 'D'},
+/* 136 */ {"%s = \"%s\" ENTITIES attribute ignored: more than GRPCNT in list", 'E', 'Q'},
+/* 137 */ {"Content model is ambiguous", 'W', 'D'},
+/* 138 */ {"Invalid parameter entity name \"%s\"", 'E', 'S'},
+/* 139 */ {"Document ended invalidly within a marked section; parsing ended", 'C', 'S'},
+/* 140 */ {"Element \"%s\" used in DTD but not defined", 'I', 'D'},
+/* 141 */ {"Invalid NDATA or SUBDOC entity reference occurred; ignored", 'E', 'S'},
+/* 142 */ {"Associated element type not allowed in document instance", 'E', 'C'},
+/* 143 */ {"Illegal DSC character; in different entity from DSO", 'E', 'C'},
+/* 144 */ {"Declared value of data attribute cannot be ID", 'E', 'D' },
+/* 145 */ {"Invalid reference to external CDATA or SDATA entity; ignored", 'E', 'S'},
+/* 146 */ {"Could not find external document type \"%s\"", 'E', 'R'},
+/* 147 */ {"Could not find external general entity \"%s\"", 'I', 'R'},
+/* 148 */ {"Could not find external parameter entity \"%s\"", 'I', 'R'},
+/* 149 */ {"Reference to non-existent general entity \"%s\" ignored", 'E', 'R'},
+/* 150 */ {"Could not find entity \"%s\" using default declaration", 'I', 'R'},
+/* 151 */ {"Could not find entity \"%2$s\" in attribute %1$s using default declaration", 'E', 'R'},
+/* 152 */ {"Short reference map \"%s\" used in USEMAP declaration but not defined; declaration will be ignored", 'E', 'D'},
+/* 153 */ {"End-tag minimization should be \"O\" for element with CONREF attribute", 'I', 'D'},
+/* 154 */ {"Declared value of data attribute cannot be ENTITY or ENTITIES", 'E', 'D' },
+/* 155 */ {"Declared value of data attribute cannot be IDREF or IDREFS", 'E', 'D' },
+/* 156 */ {"Declared value of data attribute cannot be NOTATION", 'E', 'D' },
+/* 157 */ {"CURRENT cannot be specified for a data attribute", 'E', 'D' },
+/* 158 */ {"CONREF cannot be specified for a data attribute", 'E', 'D' },
+/* 159 */ {"Parameter must be a number or CONTROLS or NONE", 'E', 'D'},
+/* 160 */ {"Cannot create temporary file", 'C', 'R'},
+/* 161 */ {"Document ended invalidly within SGML declaration", 'C', 'D'},
+/* 162 */ {"Capacity limit %s exceeded by %s points", 'W', 'Q'},
+/* 163 */ {"Amendment 1 requires \"ISO 8879:1986\" instead of \"ISO 8879-1986\"", 'W', 'D'},
+/* 164 */ {"Non-markup, non-minimum data character in SGML declaration", 'E', 'D'},
+/* 165 */ {"Parameter cannot be a literal", 'E', 'D'},
+/* 166 */ {"Invalid concrete syntax scope \"%s\"", 'E', 'D'},
+/* 167 */ {"Parameter must be a number", 'E', 'D'},
+/* 168 */ {"\"%s\" should have been \"%s\"", 'E', 'D'},
+/* 169 */ {"Character number %s is not supported as an additional name character", 'E', 'U'},
+/* 170 */ {"Parameter must be a literal or \"%s\"", 'E', 'D'},
+/* 171 */ {"Bad character description for character %s", 'E', 'D'},
+/* 172 */ {"Character number %s is described more than once", 'W', 'D'},
+/* 173 */ {"Character number plus number of characters exceeds 256", 'E', 'D'},
+/* 174 */ {"No description for upper half of character set: assuming \"128 128 UNUSED\"", 'W', 'D'},
+/* 175 */ {"Character number %s was not described; assuming UNUSED", 'E', 'D'},
+/* 176 */ {"Non-significant shunned character number %s not declared UNUSED", 'E', 'D'},
+/* 177 */ {"Significant character \"%s\" cannot be non-SGML", 'E', 'D'},
+/* 178 */ {"Unknown capacity set \"%s\"", 'E', 'U'},
+/* 179 */ {"No capacities specified." , 'E', 'D'},
+/* 180 */ {"Unknown concrete syntax \"%s\"", 'E', 'U'},
+/* 181 */ {"Character number exceeds 255", 'E', 'D'},
+/* 182 */ {"Concrete syntax SWITCHES not supported", 'E', 'U'},
+/* 183 */ {"\"INSTANCE\" scope not supported", 'E', 'U'},
+/* 184 */ {"Value of \"%s\" feature must be one or more", 'E', 'D'},
+/* 185 */ {"\"%s\" invalid; must be \"YES\" or \"NO\"", 'E', 'D'},
+/* 186 */ {"\"%s\" invalid; must be \"PUBLIC\" or \"SGMLREF\"", 'E', 'D'},
+/* 187 */ {"Feature \"%s\" is not supported", 'E', 'U'},
+/* 188 */ {"Too many open subdocument entities", 'E', 'Q'},
+/* 189 */ {"Invalid formal public identifier", 'W', 'D'},
+/* 190 */ {"Public text class must be \"%s\"", 'W', 'D'},
+/* 191 */ {"Use of character number %s as an SGML character is not supported", 'W', 'U'},
+/* 192 */ {"Notation \"%s\" not defined in DTD", 'W', 'D'},
+/* 193 */ {"Unclosed start or end tag requires \"SHORTTAG YES\"", 'W', 'M'},
+/* 194 */ {"Net-enabling start tag requires \"SHORTTAG YES\"", 'W', 'M'},
+/* 195 */ {"Attribute name omission requires \"SHORTTAG YES\"", 'W', 'M'},
+/* 196 */ {"Undelimited attribute value requires \"SHORTTAG YES\"", 'W', 'M'},
+/* 197 */ {"Attribute specification omitted for \"%s\": requires markup minimization", 'W', 'M'},
+/* 198 */ {"Concrete syntax does not have any short reference delimiters", 'E', 'D'},
+/* 199 */ {"Character number %s not in the base character set; assuming UNUSED", 'E', 'D'},
+/* 200 */ {"Character number %s is UNUSED in the syntax reference character set", 'E', 'D'},
+/* 201 */ {"Character number %s was not described in the syntax reference character set", 'E', 'D'},
+/* 202 */ {"Character number %s in the syntax reference character set has no corresponding character in the system character set", 'E', 'D'},
+/* 203 */ {"Character number %s was described using an unknown base set", 'E', 'D'},
+/* 204 */ {"Duplication specification for added function \"%s\"", 'E', 'D'},
+/* 205 */ {"Added function character cannot be \"%s\"", 'E', 'D'},
+/* 206 */ {"Only reference concrete syntax function characters supported", 'E', 'U'},
+/* 207 */ {"Only reference concrete syntax general delimiters supported", 'E', 'U'},
+/* 208 */ {"Only reference concrete syntax short reference delimiters supported", 'E', 'U'},
+/* 209 */ {"Unrecognized keyword \"%s\"", 'E', 'D'},
+/* 210 */ {"Unrecognized quantity name \"%s\"", 'E', 'D'},
+/* 211 */ {"Interpretation of \"%s\" is not a valid name in the declared concrete syntax", 'E', 'D'},
+/* 212 */ {"Replacement reserved name \"%s\" cannot be reference reserved name", 'E', 'D'},
+/* 213 */ {"Duplicate replacement reserved name \"%s\"", 'E', 'D'},
+/* 214 */ {"Quantity \"%s\" must not be less than %s", 'E', 'D'},
+/* 215 */ {"Only values up to %2$s are supported for quantity \"%1$s\"", 'E', 'U'},
+/* 216 */ {"%s element cannot be excluded from %s element because it is neither inherently optional nor a member of an or group", 'E', 'C'},
+/* 217 */ {"Marked section not allowed in other prolog", 'E', 'C'},
+/* 218 */ {"Required %s attribute was not specified for entity %s", 'E', 'C'},
+/* 219 */ {"UCNMSTRT must have the same number of characters as LCNMSTRT", 'E', 'D'},
+/* 220 */ {"UCNMCHAR must have the same number of characters as LCNMCHAR", 'E', 'D'},
+/* 221 */ {"Character number %s assigned to both LCNMSTRT or UCNMSTRT and LCNMCHAR or UCNMCHAR", 'E', 'D'},
+/* 222 */ {"Character number %s cannot be an additional name character", 'E', 'D'},
+/* 223 */ {"It is unsupported for \"-\" not to be assigned to UCNMCHAR or LCNMCHAR", 'E', 'U'},
+/* 224 */ {"Normalized length of value of attribute \"%s\" exceeded LITLEN", 'E', 'Q'},
+/* 225 */ {"Length of interpreted parameter literal exceeds LITLEN less the length of the bracketing delimiters", 'E', 'Q'},
+/* 226 */ {"Start tag of document element omitted; not minimizable", 'W', 'M'},
+/* 227 */ {"Unrecognized designating escape sequence \"%s\"", 'I', 'U'},
+/* 228 */ {"Earlier reference to entity \"%s\" used default entity", 'I', 'D'},
+/* 229 */ {"Reference to non-existent parameter entity \"%s\" ignored", 'E', 'R'},
+/* 230 */ {"DSC within marked section; marked section terminated", 'E', 'C'},
+/* 231 */ {"Document element end tag can only occur in document element because entity end not allowed in other prolog", 'E', 'C'},
+/* 232 */ {"Character reference not allowed in other prolog", 'E', 'C'},
+/* 233 */ {"USEMAP declaration not allowed in other prolog", 'E', 'D'},
+/* 234 */ {"Entity reference not allowed in other prolog", 'E', 'C'},
+/* 235 */ {"Value assigned to capacity %s exceeds value assigned to TOTALCAP", 'W', 'D'},
+};
diff --git a/usr.bin/sgmls/sgmls/msgcat.c b/usr.bin/sgmls/sgmls/msgcat.c
new file mode 100644
index 0000000..5c7ee9f
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/msgcat.c
@@ -0,0 +1,840 @@
+/* msgcat.c -
+ X/Open message catalogue functions and gencat utility.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifndef HAVE_CAT
+
+/* In this implementation the message catalogue format is the same as the
+message text source file format (see pp 42-43 of the X/Open
+Portability Guide, Issue 3, Volume 3.) This means that you don't have
+to use the gencat utility, but it is still useful for checking and
+merging catalogues. */
+
+/* Compile this with -DGENCAT to get the gencat utility. */
+
+#include "std.h"
+#include "msgcat.h"
+
+#ifdef USE_PROTOTYPES
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+#ifdef USE_ISASCII
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#endif
+
+/* Default message set. */
+#define NL_SETD 1
+
+#ifndef PATH_FILE_SEP
+#define PATH_FILE_SEP ':'
+#endif
+
+#ifndef DEFAULT_NLSPATH
+#define DEFAULT_NLSPATH ""
+#endif
+
+#ifndef DEFAULT_LANG
+#define DEFAULT_LANG "default"
+#endif
+
+#define HASH_TAB_SIZE 251
+
+struct message {
+ struct message *next;
+ unsigned msgnum;
+ unsigned setnum;
+ char *text;
+};
+
+struct cat {
+ char *name;
+ int loaded;
+ int bad;
+ struct message *table[HASH_TAB_SIZE];
+};
+
+static char *read_buf = 0;
+static unsigned read_buf_len = 0;
+
+/* Errors that can be generated by read_catalog. */
+
+enum cat_err {
+ E_ZERO, /* not an error */
+ E_BADARG,
+ E_NOMEM,
+ E_NOSUCHCOMMAND,
+ E_INPUT,
+ E_EOF,
+ E_BADSEP,
+ E_BADLINE
+};
+
+#ifdef GENCAT
+/* These must match enum cat_err. */
+static char *cat_errlist[] = {
+ "Error 0",
+ "Invalid argument to command",
+ "Out of memory",
+ "Unrecognized command",
+ "Input error",
+ "Unexpected end of file",
+ "Space or tab expected after message number",
+ "Invalid line",
+};
+#endif /* GENCAT */
+
+#ifndef GENCAT
+/* The value of NLSPATH. */
+static char *nlspath = 0;
+/* The value of LANG. */
+static char *lang = 0;
+#endif /* not GENCAT */
+
+static int current_lineno = -1;
+static enum cat_err cat_errno = E_ZERO;
+
+#ifndef GENCAT
+static void load_catalog P((struct cat *));
+static FILE *find_catalog P((char *, char **));
+#endif
+static int read_catalog P((FILE *, struct message **));
+static void delete_set P((struct message **, unsigned));
+static void delete_message P((struct message **, unsigned, unsigned));
+static int hash P((unsigned setnum, unsigned msgnum));
+static char *parse_text P((FILE *, int));
+
+#ifndef GENCAT
+
+nl_catd catopen(name, oflag)
+char *name;
+int oflag;
+{
+ struct cat *catp;
+ int i;
+
+ if (!name)
+ return 0;
+
+ catp = (struct cat *)malloc(sizeof *catp);
+ if (!catp)
+ return 0;
+ for (i = 0; i < HASH_TAB_SIZE; i++)
+ catp->table[i] = 0;
+ catp->name = malloc(strlen(name) + 1);
+ catp->loaded = 0;
+ catp->bad = 0;
+ strcpy(catp->name, name);
+ return (nl_catd)catp;
+}
+
+int catclose(catd)
+nl_catd catd;
+{
+ int i;
+ struct cat *catp = (struct cat *)catd;
+
+ if (!catp)
+ return 0;
+
+ for (i = 0; i < HASH_TAB_SIZE; i++) {
+ struct message *p, *nextp;
+ for (p = catp->table[i]; p; p = nextp) {
+ nextp = p->next;
+ free(p->text);
+ free((char *)p);
+ }
+ }
+ if (catp->name)
+ free(catp->name);
+ free((char *)catp);
+ return 0;
+}
+
+char *catgets(catd, setnum, msgnum, dflt)
+nl_catd catd;
+int setnum, msgnum;
+char *dflt;
+{
+ struct message *p;
+ struct cat *catp;
+
+ /* setnum and msgnum are required to be >= 1. */
+ if (!catd || setnum <= 0 || msgnum <= 0)
+ return dflt;
+ catp = (struct cat *)catd;
+ if (!catp->loaded)
+ load_catalog(catp);
+ if (catp->bad)
+ return dflt;
+ for (p = catp->table[hash(setnum, msgnum)]; p; p = p->next)
+ if (p->msgnum == msgnum && p->setnum == setnum)
+ break;
+ if (!p)
+ return dflt;
+ return p->text;
+}
+
+static
+VOID load_catalog(catp)
+struct cat *catp;
+{
+ FILE *fp;
+ char *path;
+
+ catp->loaded = 1;
+ fp = find_catalog(catp->name, &path);
+ if (!fp) {
+ catp->bad = 1;
+ return;
+ }
+ current_lineno = 0;
+ if (read_catalog(fp, catp->table) < 0)
+ catp->bad = 1;
+ fclose(fp);
+ if (read_buf) {
+ free(read_buf);
+ read_buf = 0;
+ }
+ read_buf_len = 0;
+ free(path);
+}
+
+static
+FILE *find_catalog(name, pathp)
+char *name;
+char **pathp;
+{
+ char *path;
+
+ if (!name)
+ return 0;
+ if (!nlspath) {
+ nlspath = getenv("NLSPATH");
+ if (!nlspath)
+ nlspath = DEFAULT_NLSPATH;
+ }
+ if (!lang) {
+ lang = getenv("LANG");
+ if (!lang)
+ lang = DEFAULT_LANG;
+ }
+ path = nlspath;
+ for (;;) {
+ char *p;
+ unsigned len = 0;
+
+ for (p = path; *p != '\0' && *p != PATH_FILE_SEP; p++) {
+ if (*p == '%') {
+ if (p[1] == 'N') {
+ p++;
+ len += strlen(name);
+ }
+ else if (p[1] == 'L') {
+ p++;
+ len += strlen(lang);
+ }
+ else if (p[1] == '%') {
+ p++;
+ len++;
+ }
+ else
+ len++;
+
+ }
+ else
+ len++;
+ }
+ if (len > 0) {
+ char *s, *try;
+ FILE *fp;
+ s = try = malloc(len + 1);
+ if (!s)
+ return 0;
+ for (p = path; *p != '\0' && *p != PATH_FILE_SEP; p++) {
+ if (*p == '%') {
+ if (p[1] == 'N') {
+ p++;
+ strcpy(s, name);
+ s += strlen(name);
+ }
+ else if (p[1] == 'L') {
+ p++;
+ strcpy(s, lang);
+ s += strlen(lang);
+ }
+ else if (p[1] == '%') {
+ p++;
+ *s++ = '%';
+ }
+ else
+ *s++ = *p;
+ }
+ else
+ *s++ = *p;
+ }
+ *s++ = '\0';
+ fp = fopen(try, "r");
+ if (fp) {
+ *pathp = try;
+ return fp;
+ }
+ free(try);
+ }
+ if (*p == '\0')
+ break;
+ path = ++p;
+ }
+ return 0;
+}
+
+#endif /* not GENCAT */
+
+/* 0 success, -1 error */
+
+static
+int parse_message(c, fp, table, setnum, quote)
+int c;
+FILE *fp;
+struct message **table;
+unsigned setnum;
+int quote;
+{
+ unsigned msgnum;
+ struct message *msgp;
+ char *text;
+ int hc;
+
+ msgnum = c - '0';
+ for (;;) {
+ c = getc(fp);
+ if (!isdigit(c))
+ break;
+ msgnum = msgnum*10 + (c - '0');
+ }
+ if (c == '\n') {
+ delete_message(table, setnum, msgnum);
+ return 0;
+ }
+ if (c != ' ' && c != '\t') {
+ cat_errno = E_BADSEP;
+ return -1;
+ }
+ text = parse_text(fp, quote);
+ if (!text)
+ return -1;
+ hc = hash(setnum, msgnum);
+ for (msgp = table[hc]; msgp; msgp = msgp->next)
+ if (msgp->setnum == setnum && msgp->msgnum == msgnum)
+ break;
+ if (msgp)
+ free(msgp->text);
+ else {
+ msgp = (struct message *)malloc(sizeof *msgp);
+ if (!msgp) {
+ cat_errno = E_NOMEM;
+ return -1;
+ }
+ msgp->next = table[hc];
+ table[hc] = msgp;
+ msgp->msgnum = msgnum;
+ msgp->setnum = setnum;
+ }
+ msgp->text = text;
+ return 0;
+}
+
+static
+char *parse_text(fp, quote)
+FILE *fp;
+int quote;
+{
+ unsigned i = 0;
+ char *p;
+ int c;
+ int quoted;
+
+ c = getc(fp);
+ if (c == quote) {
+ quoted = 1;
+ c = getc(fp);
+ }
+ else
+ quoted = 0;
+ for (;; c = getc(fp)) {
+ if (c == EOF) {
+ if (ferror(fp)) {
+ cat_errno = E_INPUT;
+ return 0;
+ }
+ break;
+ }
+ if (c == '\n')
+ break;
+ /* XXX
+
+ Can quotes be used in quoted message text if protected by \ ?
+
+ Is it illegal to omit the closing quote if there's an opening
+ quote?
+
+ Is it illegal to have anything after a closing quote?
+
+ */
+
+ if (quoted && c == quote) {
+ /* Skip the rest of the line. */
+ while ((c = getc(fp)) != '\n')
+ if (c == EOF) {
+ if (ferror(fp)) {
+ cat_errno = E_INPUT;
+ return 0;
+ }
+ break;
+ }
+ break;
+ }
+ if (c == '\\') {
+ int d;
+
+ c = getc(fp);
+ if (c == EOF)
+ break;
+ switch (c) {
+ case '\n':
+ current_lineno++;
+ continue;
+ case 'n':
+ c = '\n';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c -= '0';
+ d = getc(fp);
+ if (d >= '0' && d <= '7') {
+ c = c*8 + d - '0';
+ d = getc(fp);
+ if (d >= '0' && d <= '7')
+ c = c*8 + d - '0';
+ else if (d != EOF)
+ ungetc(d,fp);
+ }
+ else if (d != EOF)
+ ungetc(d, fp);
+ if (c == '\0')
+ continue; /* XXX */
+ break;
+ default:
+ /* Ignore the quote. */
+ break;
+ }
+ }
+ if (i >= read_buf_len) {
+ if (!read_buf)
+ read_buf = malloc(read_buf_len = 40);
+ else
+ read_buf = realloc(read_buf, read_buf_len *= 2);
+ if (!read_buf) {
+ cat_errno = E_NOMEM;
+ return 0;
+ }
+ }
+ read_buf[i++] = c;
+ }
+ p = malloc(i + 1);
+ if (!p) {
+ cat_errno = E_NOMEM;
+ return 0;
+ }
+ memcpy(p, read_buf, i);
+ p[i] = '\0';
+ return p;
+}
+
+/* 0 success, -1 error */
+
+static
+int parse_command(fp, table, setnump, quotep)
+FILE *fp;
+struct message **table;
+unsigned *setnump;
+int *quotep;
+{
+ char buf[128];
+ if (fgets(buf, 128, fp) == NULL) {
+ cat_errno = ferror(fp) ? E_INPUT : E_EOF;
+ return -1;
+ }
+ if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n')
+ /* a comment */;
+ else if (strncmp(buf, "set", 3) == 0) {
+ if (sscanf(buf + 3, "%u", setnump) != 1) {
+ cat_errno = E_BADARG;
+ return -1;
+ }
+
+ }
+ else if (strncmp(buf, "delset", 6) == 0) {
+ unsigned num;
+ if (sscanf(buf + 6, "%u", &num) != 1) {
+ cat_errno = E_BADARG;
+ return -1;
+ }
+ delete_set(table, num);
+ *setnump = NL_SETD;
+ }
+ else if (strncmp(buf, "quote", 5) == 0) {
+ char *p = buf + 5;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ /* XXX should \ be allowed as the quote character? */
+ if (*p == '\0' || *p == '\n')
+ *quotep = -1;
+ else
+ *quotep = *p;
+ }
+ else {
+ cat_errno = E_NOSUCHCOMMAND;
+ return -1;
+ }
+ if (strchr(buf, '\n') == 0) {
+ int c;
+ while ((c = getc(fp)) != '\n' && c != EOF)
+ ;
+ }
+ return 0;
+}
+
+
+static
+VOID delete_set(table, setnum)
+struct message **table;
+unsigned setnum;
+{
+ int i;
+
+ for (i = 0; i < HASH_TAB_SIZE; i++) {
+ struct message *p, *nextp;
+ for (p = table[i], table[i] = 0; p; p = nextp) {
+ nextp = p->next;
+ if (p->setnum == setnum)
+ free((char *)p);
+ else {
+ p->next = table[i];
+ table[i] = p;
+ }
+ }
+ }
+}
+
+static
+VOID delete_message(table, setnum, msgnum)
+struct message **table;
+unsigned setnum, msgnum;
+{
+ struct message **pp;
+
+ for (pp = &table[hash(setnum, msgnum)]; *pp; pp = &(*pp)->next)
+ if ((*pp)->setnum == setnum && (*pp)->msgnum == msgnum) {
+ struct message *p = *pp;
+ *pp = p->next;
+ free(p->text);
+ free((char *)p);
+ break;
+ }
+}
+
+/* 0 success, -1 error. On error cat_errno is set to the error number. */
+
+static
+int read_catalog(fp, table)
+FILE *fp;
+struct message **table;
+{
+ int c;
+ unsigned setnum = NL_SETD;
+ int quote_char = -1;
+
+ for (;;) {
+ /* start of line */
+ c = getc(fp);
+ if (c == EOF)
+ break;
+ ++current_lineno;
+ if (isdigit(c)) {
+ if (parse_message(c, fp, table, setnum, quote_char) < 0)
+ return -1;
+ }
+ else if (c == '$') {
+ if (parse_command(fp, table, &setnum, &quote_char) < 0)
+ return -1;
+ }
+ else if (c != '\n') {
+ while ((c = getc(fp)) != '\n' && c != EOF)
+ if (c != ' ' && c != '\t') {
+ cat_errno = E_BADLINE;
+ return -1;
+ }
+ if (c == EOF)
+ break;
+ }
+ }
+ return 0;
+}
+
+static
+int hash(setnum, msgnum)
+unsigned setnum, msgnum;
+{
+ return ((setnum << 8) + msgnum) % HASH_TAB_SIZE;
+}
+
+#ifdef GENCAT
+
+static char *program_name;
+
+static int message_compare P((UNIV, UNIV));
+static void print_text P((char *, FILE *));
+static void usage P((void));
+
+#ifdef VARARGS
+static void fatal();
+#else
+static void fatal P((char *,...));
+#endif
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ FILE *fp;
+ int i, j, nmessages;
+ struct message **list;
+ unsigned setnum;
+ struct message *table[HASH_TAB_SIZE];
+
+ program_name = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ for (i = 0; i < HASH_TAB_SIZE; i++)
+ table[i] = 0;
+ for (i = 1; i < argc; i++) {
+ errno = 0;
+ fp = fopen(argv[i], "r");
+ if (!fp) {
+ if (i > 1)
+ fatal("can't open `%s': %s", argv[i], strerror(errno));
+ }
+ else {
+ current_lineno = 0;
+ cat_errno = E_ZERO;
+ if (read_catalog(fp, table) < 0) {
+ assert(cat_errno != E_ZERO);
+ assert(cat_errno
+ < sizeof(cat_errlist)/sizeof(cat_errlist[0]));
+ fatal("%s:%d: %s", argv[i], current_lineno,
+ cat_errlist[cat_errno]);
+ }
+ fclose(fp);
+ }
+ }
+
+ errno = 0;
+ fp = fopen(argv[1], "w");
+ if (!fp)
+ fatal("can't open `%s' for output: %s", argv[1], strerror(errno));
+ nmessages = 0;
+ for (i = 0; i < HASH_TAB_SIZE; i++) {
+ struct message *p;
+ for (p = table[i]; p; p = p->next)
+ nmessages++;
+ }
+ list = (struct message **)malloc(nmessages*sizeof(struct message *));
+ if (!list)
+ fatal("out of memory");
+ j = 0;
+ for (i = 0; i < HASH_TAB_SIZE; i++) {
+ struct message *p;
+ for (p = table[i]; p; p = p->next)
+ list[j++] = p;
+ }
+ assert(j == nmessages);
+
+ qsort((UNIV)list, nmessages, sizeof(struct message *), message_compare);
+
+ setnum = NL_SETD;
+ for (i = 0; i < nmessages; i++) {
+ struct message *p = list[i];
+ if (p->setnum != setnum) {
+ setnum = p->setnum;
+ fprintf(fp, "$set %u\n", setnum);
+ }
+ fprintf(fp, "%u ", p->msgnum);
+ print_text(p->text, fp);
+ putc('\n', fp);
+ }
+ if (fclose(fp) == EOF)
+ fatal("error closing `%s'", argv[1]);
+ return 0;
+}
+
+static
+VOID usage()
+{
+ fprintf(stderr, "usage: %s catfile msgfile...\n", program_name);
+ exit(1);
+}
+
+static
+#ifdef VARARGS
+VOID fatal(va_alist) va_dcl
+#else /* not VARARGS */
+VOID fatal(char *message,...)
+#endif /* not VARARGS */
+{
+ va_list ap;
+
+#ifdef VARARGS
+ char *message;
+ va_start(ap);
+ message = va_arg(ap, char *);
+#else /* not VARARGS */
+ va_start(ap, message);
+#endif /* not VARARGS */
+
+ fprintf(stderr, "%s: ", program_name);
+ vfprintf(stderr, message, ap);
+ putc('\n', stderr);
+ va_end(ap);
+ exit(1);
+}
+
+static
+int message_compare(p1, p2)
+UNIV p1;
+UNIV p2;
+{
+ struct message *m1 = *(struct message **)p1;
+ struct message *m2 = *(struct message **)p2;
+
+ if (m1->setnum < m2->setnum)
+ return -1;
+ if (m1->setnum > m2->setnum)
+ return 1;
+ if (m1->msgnum < m2->msgnum)
+ return -1;
+ if (m1->msgnum > m2->msgnum)
+ return 1;
+ return 0;
+}
+
+static
+VOID print_text(s, fp)
+char *s;
+FILE *fp;
+{
+ for (; *s; s++) {
+ if (*s == '\\')
+ fputs("\\\\", fp);
+ else if (ISASCII(*s) && isprint((unsigned char)*s))
+ putc(*s, fp);
+ else {
+ switch (*s) {
+ case '\n':
+ fputs("\\n", fp);
+ break;
+ case '\b':
+ fputs("\\b", fp);
+ break;
+ case '\f':
+ fputs("\\f", fp);
+ break;
+ case '\t':
+ fputs("\\t", fp);
+ break;
+ case '\v':
+ fputs("\\v", fp);
+ break;
+ case '\r':
+ fputs("\\r", fp);
+ break;
+ default:
+ fprintf(fp, "\\%03o", (unsigned char)*s);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* GENCAT */
+
+#ifdef TEST
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ nl_catd catd;
+ int msgnum, setnum;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s catalogue\n", argv[0]);
+ exit(1);
+ }
+ catd = catopen(argv[1], 0);
+ fprintf(stderr, "Enter set number, message number pairs:\n");
+ fflush(stderr);
+ while (scanf("%d %d", &setnum, &msgnum) == 2) {
+ char *msg = catgets(catd, setnum, msgnum, "<default>");
+ fprintf(stderr, "Returned \"%s\"\n", msg);
+ fflush(stderr);
+ }
+ return 0;
+}
+
+#endif /* TEST */
+
+#endif /* not HAVE_CAT */
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/msgcat.h b/usr.bin/sgmls/sgmls/msgcat.h
new file mode 100644
index 0000000..83e998a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/msgcat.h
@@ -0,0 +1,13 @@
+
+#ifdef HAVE_CAT
+#include <nl_types.h>
+#else
+typedef UNIV nl_catd;
+#endif
+
+/* Don't use prototypes here in case nl_types.h declares a conflicting
+prototype. */
+
+nl_catd catopen();
+int catclose();
+char *catgets();
diff --git a/usr.bin/sgmls/sgmls/pars1.c b/usr.bin/sgmls/sgmls/pars1.c
new file mode 100644
index 0000000..0a67cbc
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/pars1.c
@@ -0,0 +1,984 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+#define GI (tags[ts].tetd->etdgi+1) /* GI of current element. */
+#define NEWGI (newetd->etdgi+1) /* GI of new tag. */
+
+static VOID doincludes P((void));
+static int pentname P((char *));
+static struct mpos *newmpos P((void));
+static VOID commbufs P((void));
+static VOID checkdtd P((void));
+
+/* PARSECON: Parse content of an element.
+*/
+int parsecon(tbuf, pcb)
+UNCH *tbuf; /* Work area for tokenization. */
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ int srn; /* SHORTREF delimiter number (1-32). */
+ int refrc; /* Return code from sentref, stagetd, etc. */
+
+ TRACECON(etagimct, dostag, datarc, pcb, conrefsw, didreq);
+ if (eodsw) return(EOD_);
+ if (didreq && (conrefsw & TAGREF)) {didreq = 0; goto conr;}
+ if (etagimct>0) {etagimsw = --etagimct ? 1 : 0; destack(); return(ETG_);}
+ if (dostag) {
+ conrefsw = conrefsv;
+ etisw = etiswsv;
+ if (charmode) {dostag = 0; return datarc;}
+ return stag(datarc);
+ }
+ if (conrefsw) {
+ conr:
+ destack();
+ conrefsw = 0;
+ return ETG_;
+ }
+ else if (eofsw) return(EOD_);
+
+ datarc = 0;
+ while (1) {
+ parse(pcb);
+ srn = (int)pcb->action - SRMIN; /* Just in case it's a SHORTREF. */
+ switch (pcb->action) {
+ case DCE_: /* Data character in element content. */
+ /* The data character might be a non-SGML character so
+ reprocess it using pcbconm. */
+ REPEATCC;
+ pcb = conpcb = &pcbconm;
+ pcb->newstate = pcbcnet;
+ continue;
+ case DAS_: /* Current character begins data. */
+ data = FPOS;
+ continue;
+
+ case NLF_: /* NET or SR returns data in lookahead buffer. */
+ datalen = (UNS)(ptcon - data); REPEATCC;
+ goto rcc;
+
+ case LAF_: /* Return data in lookahead buffer: mixed. */
+ datalen = (UNS)(ptcon+1 - data);
+ goto rcc;
+
+ case NON_: /* Single nonchar in nonchbuf. */
+ datalen = 2; data = nonchbuf;
+ goto nrcc;
+
+ case DAR_: /* Return data except for last char. */
+ REPEATCC;
+ case DAF_: /* Return data in source entity buffer. */
+ datalen = (UNS)(FPOS - data);
+ rcc:
+ REPEATCC;
+ case DEF_: /* Return data in data entity. */
+ nrcc:
+ datarc = DAF_;
+ if (pcb==&pcbcone) {
+ pcbconm.newstate = pcbcnet;
+ conpcb = &pcbconm;
+ }
+ if (charmode) return(datarc);
+ stagmin = MINNONE; stagreal = newetd = ETDCDATA;
+ return(stag(datarc));
+
+ case LAS_: /* Start lookahead buffer with current char. */
+ *(ptcon = data = tbuf+1) = *FPOS;
+ continue;
+
+ case LAM_: /* Move character to lookahead buffer. */
+ *++ptcon = *FPOS;
+ continue;
+
+ case STG_: /* Process non-null start-tag. */
+ CTRSET(tagctr); /* Start counting tag length. */
+ tages = es;
+ parsenm(tbuf, NAMECASE); /* Get the GI. */
+ newetd = etdref(tbuf);
+ if (newetd && newetd->adl) {
+ parseatt(newetd->adl, tbuf);
+ adlval((int)ADN(al), newetd);
+ }
+ parsetag(&pcbstag); /* Parse the tag ending. */
+ if ((CTRGET(tagctr)-tagdelsw)>=TAGLEN)
+ sgmlerr(66, &pcbstag, (UNCH *)0, (UNCH *)0);
+ if (!newetd) {
+ sgmlerr(132, pcb, tbuf+1, (UNCH *)0);
+ continue;
+ }
+ return(stagetd(&pcbstag));
+
+ case NST_: /* Process null start-tag. */
+ return nstetd();
+
+ case ETC_: /* End-tag in CDATA or RCDATA. */
+ case ETG_: /* Process non-null end-tag. */
+ newetd = etdref(parsenm(tbuf, NAMECASE)); /* Get the GI. */
+ parsetag(&pcbetag); /* Parse tag end. */
+ if (!newetd) /* Error: undefined.*/
+ sgmlerr(11, &pcbetag, tbuf+1, (UNCH *)0);
+ else if (etagetd(&pcbetag)>=0) return ETG_;/* Open element. */
+ if (pcb->action!=ETC_) continue;
+ /* Tag is undefined or not for an open element and we are in
+ a CDATA or RCDATA element; issue message and treat as
+ null end-tag (</>).
+ */
+ sgmlerr(57, &pcbetag, (UNCH *)0, (UNCH *)0);
+ case NET_: /* Process null end-tag. */
+ if ((refrc = netetd(conpcb))!=0) return ETG_;
+ continue;
+
+ case NED_: /* Process null end-tag delimiter. */
+ etagmin = MINNET;
+ newetd = etagreal = ETDNET;
+ etagimct = etag();
+ etagimsw = etagimct ? 1 : 0; destack();
+ return ETG_;
+ case GTR_:
+ if (entget()!=-1) {
+ data = FPOS;
+ continue;
+ }
+ /* fall through */
+ case EOD_: /* End of primary file. */
+ if (ts<1) return(EOD_); /* Normal end: stack is empty. */
+ etagimct = ts-1; /* Treat as end-tag for top tag on stack. */
+ etagmin = MINETAG; etagreal = tags[0].tetd;
+ destack();
+ eofsw = 1; /* Return EOD_ after destacking all. */
+ return ETG_;
+
+ /* Short references ending with blanks:
+ If the blank sequence is followed by RE, go do SR7 or SR6.
+ If the entity is undefined and we are in mixed content,
+ the blanks must be returned as data. If not, they
+ can be ignored.
+ */
+ case SR9_: /* Process SR9 (two or more blanks). */
+ REPEATCC; /* Make first blank the CC. */
+ case SR4_: /* Process SR4 (RS, blanks). */
+ parseseq(tbuf, BSEQLEN); /* Squeeze out all blanks. */
+ if (*FPOS=='\r') {srn = (srn==9) ? 7 : 6; data = tbuf; goto sr6;}
+ else REPEATCC;
+ if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
+ if (refrc>0) return refrc;
+ if (refrc==ENTUNDEF && pcb==&pcbconm)
+ {data = tbuf; goto nrcc;}
+ continue;
+
+ /* Short references ending with RE:
+ If the reference is defined, the RE is ignored.
+ For RE and RS RE,
+ no special action is needed if the reference is undefined,
+ as the RE will be processed immediately as the current character.
+ For B RE and RS B RE,
+ the input is primed with a special character that will
+ be treated as an RE that cannot be a short reference.
+ */
+ case SR7_: /* Process SR7 (blanks, RE). */
+ datalen = (UNS)(FPOS - data);
+ case SR2_: /* Process SR2 (RE). */
+ case SR5_: /* Process SR5 (RS, RE). */
+ sr6: /* Process SR6 (RS, blanks, RE). */
+ if ((refrc = shortref(srn, pcb))!=ENTUNDEF) {
+ if (refrc==DEF_) goto nrcc; /* Defined: data entity. */
+ if (refrc>0) return refrc; /* Defined: tag entity. */
+ continue; /* Defined: not tag. */
+ }
+ if (pcb!=&pcbconm) continue; /* Not mixed; ignore chars. */
+ if (srn>=6) /* Return blanks as data. */
+ {*FPOS = lex.d.genre; REPEATCC; goto nrcc;}
+ case REF_: /* Undefined SR with RE; return record end. */
+ datarc = REF_;
+ if (charmode) return(datarc);
+#if 0
+ /* The standard says this situation can force a tag.
+ See 323:3-6, 412:1-7. */
+ /* If RE would be ignored, don't treat it as start-tag
+ because it could force a required tag; but do change
+ state to show that an RE was ignored.
+ */
+ if (scbsgml[pss].snext==scbsgmst) {
+ scbsgml[pss].snext = scbsgmnr;
+ TRACEGML(scbsgml, pss, conactsw, conact);
+ continue;
+ }
+#endif
+ stagmin = MINNONE; stagreal = newetd = ETDCDATA;
+ return(stag(datarc));
+
+ case SR3_: /* Process SR3 (RS). */
+ REPEATCC;
+ if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
+ if (refrc>0) return refrc;
+ continue;
+
+ case RBR_: /* Two right brackets */
+ srn = 26;
+ REPEATCC;
+ /* fall through */
+ case SR1_: /* Process SR1 (TAB). */
+ case SR8_: /* Process SR8 (space). */
+ case SR19: /* Process SR19 (-). */
+ case SR26: /* Process SR26 (]). */
+ REPEATCC;
+ goto srproc;
+
+ case FCE_: /* Process free character (SR11-18, SR21-32). */
+ fce[0] = *FPOS;
+ srn = mapsrch(&lex.s.dtb[lex.s.fce], fce);
+ case SR10: /* Process SR10 ("). */
+ case SR11: /* Process SR11 (#). */
+ case SR20: /* Process SR20 (-). */
+ case SR25: /* Process SR25 ([). */
+ srproc:
+ if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
+ if (refrc>0) return refrc;
+ if (refrc==ENTUNDEF) { /* Treat the SR as data. */
+ data = FPOS - (srn==lex.s.hyp2);/* Two data chars if SR20.*/
+ if (pcb!=&pcbconm) { /* If not in mixed content: */
+ if (srn>=lex.s.data) { /* Change PCB. */
+ pcb = conpcb = &pcbconm;
+ pcb->newstate = pcbcnda;
+ }
+ }
+ else pcb->newstate = pcbcnda;/* Now in data found state. */
+ }
+ continue;
+
+ case ERX_: /* Entity ref in RCDATA: cancel ending delims.*/
+ lexcon[lex.d.tago] = lex.l.fre;
+ lexcon[lex.d.net] = lex.l.nonet;
+ lexlms[lex.d.msc] = lex.l.fre;
+ continue;
+
+ case EE_: /* Entity end in RCDATA: check nesting. */
+ if (es<rcessv) {synerr(37, pcb); rcessv = es;}
+ /* If back at top level, re-enable the ending delimiters. */
+ if (es==rcessv) {
+ lexcon[lex.d.tago] = lex.l.tago;
+ lexcon[lex.d.net] = etictr ? lex.l.net : lex.l.nonet;
+ lexlms[lex.d.msc] = lex.l.msc;
+ }
+ continue;
+
+ case PIE_: /* PI entity: same as PIS_. */
+ return PIS_;
+
+ case RSR_: /* Record start: ccnt=0; ++rcnt.*/
+ ++RCNT; CTRSET(RSCC);
+ return RSR_;
+ case MSS_:
+ if (ts == 0) synerr(217, pcb);
+ return MSS_;
+ default:
+ return (int)pcb->action; /* Default (MD_ MDC_ MSS_ MSE_ PIS_). */
+ }
+ }
+}
+/* STAGETD: Process start-tag etd.
+*/
+int stagetd(pcb)
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ if (!newetd->etdmod) {
+ sgmlerr(43, pcb, newetd->etdgi+1, (UNCH *)0);
+ ++ds.etdercnt;
+ etdset(newetd, (UNCH)SMO+EMO+ETDOCC, &undechdr,
+ (PETD *)0, (PETD *)0, (PECB *)0);
+ TRACEETD(newetd);
+ }
+ stagmin = MINNONE; stagreal = newetd;
+ return stag(0);
+}
+/* NSTETD: Process null start-tag etd.
+*/
+int nstetd()
+{
+ if (sd.omittag && ts > 0)
+ newetd = tags[ts].tetd;
+ else if (!sd.omittag && lastetd != 0)
+ newetd = lastetd;
+ else
+ newetd = tags[0].tetd->etdmod[2].tu.thetd;
+ stagmin = MINNULL; stagreal = ETDNULL;
+ etisw = 0;
+ return stag(0);
+}
+/* ETAGETD: Process end-tag etd.
+*/
+int etagetd(pcb)
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ etagmin = MINNONE; etagreal = newetd;
+ if ((etagimct = etag())<0) {
+ sgmlerr(E_ETAG, pcb, NEWGI, tags[ts].tetd->etdgi+1);
+ return etagimct;
+ }
+ etagimsw = etagimct ? 1 : 0; destack();
+ return ETG_;
+}
+/* NETETD: Process null end-tag etd.
+*/
+int netetd(pcb)
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ if (ts<1) {
+ sgmlerr(51, pcb, (UNCH *)0, (UNCH *)0);
+ return 0;
+ }
+ etagmin = MINNULL; etagreal = ETDNULL;
+ etagimsw = 0; destack();
+ return ETG_;
+}
+/* SHORTREF: Process a short (alternative) reference to an entity.
+ Returns ENTUNDEF if entity is not defined, otherwise returns
+ the return code from stagetd or etagetd if the entity was
+ a tag, or zero if an error occurred somewhere.
+*/
+int shortref(srn, pcb)
+int srn; /* Short reference number. */
+struct parse *pcb; /* Parse control block for this parse. */
+{
+ int rc; /* Return code from entopen. */
+
+ if (tags[ts].tsrm==SRMNULL || !tags[ts].tsrm[srn]) return ENTUNDEF;
+ rc = entopen(tags[ts].tsrm[srn]);
+ if (rc==ENTDATA) return DEF_;
+ if (rc==ENTPI) return PIS_;
+ return(0);
+}
+/* PARSEPRO: Parse prolog.
+ Note: ptpro cannot overrun tbuf (and therefore needn't be
+ tested), as long as the buffer exceeds the longest
+ lookahead sequence in the content parse tables.
+*/
+int parsepro()
+{
+ struct parse *oldpcb;
+
+ while (1) {
+ int rc; /* Return code: DAF MSS DCE */
+ switch (parse(propcb)) {
+
+ case LAS_: /* Start lookahead buffer with current char. */
+ *(ptpro = data = tbuf+1) = *FPOS;
+ continue;
+ case LAM_: /* Move character to lookahead buffer. */
+ *++ptpro = *FPOS;
+ continue;
+ case LAF_: /* Return data in lookahead buffer. */
+ datalen = (UNS)(ptpro+1 - data);
+ REPEATCC;
+ rc = DAF_;
+ break; /* Prolog ended; data pending. */
+
+ case DTD_: /* Process document type declaration. */
+ parsenm(tbuf, NAMECASE); /* Get declaration name. */
+ if (!ustrcmp(tbuf+1, sgmlkey)
+ && !dtdsw && !sgmlsw++) {
+#if 0
+ parse(&pcbmdi);
+#endif
+ /* If we got some appinfo, return. */
+ if (sgmldecl())
+ return APP_;
+ continue;
+ }
+ if (!ustrcmp(tbuf+1, key[KDOCTYPE]) && !dtdsw++) {
+ startdtd();
+ mddtds(tbuf);
+ continue;
+ }
+ sgmlerr(E_MDNAME, propcb, tbuf+1, (UNCH *)0);
+ continue;
+ case DTE_: /* DOCTYPE declaration (and prolog) ended. */
+ REPEATCC; /* Put back char that followed MSC. */
+ if (es != 0)
+ sgmlerr(143, propcb, (UNCH *)0, (UNCH *)0);
+ else if (dtdrefsw) {/* Process referenced DTD before real DTE. */
+ dtdrefsw = 0; /* Keep us from coming through here again. */
+ REPEATCC; /* Put back MSC so it follows referenced DTD. */
+ entref(indtdent);
+ }
+ else {
+ if (mslevel > 0) {
+ sgmlerr(230, propcb, (UNCH *)0, (UNCH *)0);
+ mslevel = 0;
+ msplevel = 0;
+ }
+ mddtde(tbuf);
+ }
+ continue;
+
+ case MD_:
+ /* Process markup declaration within DTD or LPD. */
+ parsenm(tbuf, NAMECASE); /* Get declaration name. */
+ if (!ustrcmp(tbuf+1, key[KENTITY]))
+ mdentity(tbuf);
+ else if (!ustrcmp(tbuf+1, key[KUSEMAP]))
+ mdsrmuse(tbuf);
+ else if (!ustrcmp(tbuf+1, key[KATTLIST]))
+ mdadl(tbuf);
+ else if (!ustrcmp(tbuf+1, key[KSHORTREF]))
+ mdsrmdef(tbuf);
+ else if (!ustrcmp(tbuf+1, key[KELEMENT]))
+ mdelem(tbuf);
+ else if (!ustrcmp(tbuf+1, key[KNOTATION]))
+ mdnot(tbuf);
+ else
+ sgmlerr(E_MDNAME, propcb, tbuf+1, (UNCH *)0);
+ continue;
+ case MDC_: /* Process markup declaration comment. */
+ sgmlsw++; /* SGML declaration not allowed after comment */
+ parsemd(tbuf, NAMECASE, (struct parse *)0, NAMELEN);
+ continue;
+
+ case MSS_: /* Process marked section start. */
+ oldpcb = propcb;
+ propcb = mdms(tbuf, propcb);
+ if (propcb==&pcbmsc || propcb==&pcbmsrc) {
+ if (oldpcb == &pcbmds)
+ sgmlerr(135, oldpcb, (UNCH *)0, (UNCH *)0);
+ conpcb = propcb;
+ rc = DCE_;
+ break;
+ }
+ continue;
+ case MSE_: /* Process marked section end. */
+ if (mdmse()) propcb = &pcbmds;
+ continue;
+ case MSP_: /* Marked section start in prolog outside DTD */
+ rc = MSS_;
+ break;
+ case PIE_: /* PI entity: same as PIS_. */
+ return(PIS_);
+
+ case EOD_: /* Return end of primary entity. */
+ if (dtdsw && propcb == &pcbpro) {
+ /* We've had a DTD, so check it. */
+ setdtype();
+ checkdtd();
+ }
+ if (!sw.onlypro || propcb != &pcbpro || !dtdsw)
+ sgmlerr(127, propcb, (UNCH *)0, (UNCH *)0);
+ return propcb->action;
+ case PIS_: /* Return processing instruction (string). */
+ sgmlsw++; /* SGML declaration not allowed after PI */
+ return((int)propcb->action); /* Prolog will continue later. */
+
+ case CIR_: /* Chars ignored; trying to resume parse. */
+ synerr(E_RESTART, propcb);
+ REPEATCC;
+ continue;
+ case ETE_: /* End tag ended prolog */
+ REPEATCC;
+ /* fall through */
+ case STE_: /* Start tag ended prolog */
+ REPEATCC;
+ REPEATCC;
+ rc = STE_;
+ break;
+ case PEP_: /* Previous character ended prolog. */
+ REPEATCC;
+ case DCE_: /* Data character ended prolog. */
+ REPEATCC;
+ rc = DCE_;
+ break;
+ case EE_: /* Illegal entity end in ignored marked section. */
+ /* An error message has already been given. */
+ continue;
+ default:
+ abort();
+ } /* switch */
+ setdtype(); /* First pass only: set document type. */
+ checkdtd();
+ if (sw.onlypro)
+ return EOD_;
+ TRACESET(); /* Set trace switches. */
+ endprolog();
+ /* *DOC is first element; stack it at level 0. */
+ stack(newetd = nextetd = stagreal = etagreal = docetd);
+ return(rc);
+ } /* while */
+}
+
+/* Allocate buffers that are used in the DTD. */
+
+VOID startdtd()
+{
+ nmgrp = (struct etd **)rmalloc((GRPCNT+1)*sizeof(struct etd *));
+ nnmgrp = (PDCB *)rmalloc((GRPCNT+1)*sizeof(PDCB));
+ gbuf = (struct thdr *)rmalloc((GRPGTCNT+3)*sizeof(struct thdr));
+ /* The extra 1 is for parsing the name of a parameter entity in
+ mdentity(). */
+ nmbuf = (UNCH *)rmalloc(NAMELEN+3);
+ pubibuf = (UNCH *)rmalloc(LITLEN+1);
+ sysibuf = (UNCH *)rmalloc(LITLEN+1);
+ commbufs();
+ doincludes();
+}
+
+static
+VOID checkdtd()
+{
+ struct dcncb *np;
+ struct srh *sp;
+
+ if (sw.swundef) {
+ int i;
+ struct etd *ep;
+
+ for (i = 0; i < ETDHASH; i++)
+ for (ep = etdtab[i]; ep; ep = ep->etdnext)
+ if (!ep->etdmod)
+ sgmlerr(140, (struct parse *)0, ep->etdgi + 1,
+ (UNCH *)0);
+ }
+ for (sp = srhtab[0]; sp; sp = sp->enext)
+ if (sp->srhsrm[0] == 0)
+ sgmlerr(152, (struct parse *)0, sp->ename + 1, (UNCH *)0);
+ else {
+ int i;
+ for (i = 1; i < lex.s.dtb[0].mapdata + 1; i++) {
+ struct entity *ecb = sp->srhsrm[i];
+ if (ecb && !ecb->estore) {
+ sgmlerr(93, (struct parse *)0,
+ ecb->ename + 1,
+ sp->srhsrm[0]->ename + 1);
+ sp->srhsrm[i] = 0;
+ }
+ }
+ }
+ for (np = dcntab[0]; np; np = np->enext)
+ if (!np->defined)
+ sgmlerr(192, (struct parse *)0, np->ename + 1, (UNCH *)0);
+}
+
+/* Return non-zero if s is a valid parameter entity name.
+If so put a transformed name in entbuf. */
+
+static
+int pentname(s)
+char *s;
+{
+ int i;
+ if (lextoke[(UNCH)*s] != NMS)
+ return 0;
+ entbuf[2] = ENTCASE ? lextran[(UNCH)*s] : (UNCH)*s;
+ for (i = 1; s[i]; i++) {
+ if (i > NAMELEN - 1)
+ return 0;
+ if (lextoke[(UNCH)s[i]] < NMC || s[i] == EOBCHAR)
+ return 0;
+ entbuf[i + 2] = ENTCASE ? lextran[(UNCH)s[i]] : (UNCH)s[i];
+ }
+ entbuf[1] = lex.d.pero;
+ entbuf[i + 2] = '\0';
+ entbuf[0] = (UNCH)(i + 3); /* length byte, PERO and '\0' */
+ return 1;
+}
+
+/* Handle sw.includes. */
+
+static
+VOID doincludes()
+{
+ char **p;
+ if (!sw.includes)
+ return;
+ for (p = sw.includes; *p; p++) {
+ if (pentname(*p)) {
+ if (!entfind(entbuf)) {
+ union etext etx;
+ etx.c = savestr(key[KINCLUDE]);
+ entdef(entbuf, ESM, &etx);
+ ++ds.ecbcnt;
+ ds.ecbtext += ustrlen(key[KINCLUDE]);
+ }
+ }
+ else
+ sgmlerr(138, (struct parse *)0, (UNCH *)*p, (UNCH *)0);
+ }
+}
+
+/* Allocate buffers that are use both in the DTD and the instance. */
+
+static
+VOID commbufs()
+{
+ al = (struct ad *)rmalloc((ATTCNT+2)*sizeof(struct ad));
+ lbuf = (UNCH *)rmalloc(LITLEN + 1);
+}
+
+static
+struct mpos *newmpos()
+{
+ int j;
+ unsigned long *h;
+ struct mpos *p = (struct mpos *)rmalloc((GRPLVL+2)*sizeof(struct mpos));
+
+ assert(grplongs > 0);
+ h = (unsigned long *)rmalloc((GRPLVL+2)*grplongs*sizeof(unsigned long));
+ for (j = 0; j < GRPLVL+2; j++) {
+ p[j].h = h;
+ h += grplongs;
+ }
+ return p;
+}
+
+/* Perform end of prolog buffer allocation. */
+
+VOID endprolog()
+{
+ int i;
+
+ ambigfree();
+ if (dtdsw) {
+ frem((UNIV)nmgrp);
+ frem((UNIV)nnmgrp);
+ frem((UNIV)gbuf);
+ frem((UNIV)nmbuf);
+ frem((UNIV)sysibuf);
+ frem((UNIV)pubibuf);
+ }
+ else {
+ commbufs();
+ doincludes();
+ }
+ scbsgml = (struct restate *)rmalloc((TAGLVL+1)*sizeof(struct restate));
+ tags = (struct tag *)rmalloc((TAGLVL+1)*sizeof(struct tag));
+ grplongs = (GRPCNT + LONGBITS - 1)/LONGBITS;
+ for (i = 0; i < TAGLVL+1; i++)
+ tags[i].tpos = newmpos();
+ savedpos = newmpos();
+}
+
+/* SETDTYPE: Establish specified or default document type.
+*/
+VOID setdtype()
+{
+ /* Initialize default model hdr for declared content. */
+ undechdr.ttype = MANY+MCHARS+MGI; /* Declared content is ANY. */
+ undechdr.tu.tnum = 0; /* No content model. */
+
+ /* Initialize content model and etd for *DOC. */
+ prcon[0].ttype = MGI; /* Model is an element model. */
+ prcon[0].tu.tnum = 2; /* A single group with a single GI in it. */
+ prcon[1].ttype = TTSEQ; /* Non-repeatable SEQ group. */
+ prcon[1].tu.tnum = 1; /* Only one token in group. */
+ prcon[2].ttype = TTETD; /* Token is an etd. */
+ docetd = etddef(indocetd); /* etd for document as a whole. */
+ etdset(docetd, ETDOCC, prcon, (PETD *)0, (PETD *)0, SRMNULL);
+
+ /* Put specified or default document type etd in *DOC model. */
+ if (!dtype) {
+ sgmlerr(E_DOCTYPE, propcb, (UNCH *)0, (UNCH *)0);
+ dtype = indefetd;
+ }
+ prcon[2].tu.thetd = etddef(dtype);
+ if (!prcon[2].tu.thetd->etdmod) {
+ if (dtype != indefetd)
+ sgmlerr(52, propcb, dtype+1, (UNCH *)0);
+ ++ds.etdercnt;
+ etdset(prcon[2].tu.thetd, (UNCH)SMO+EMO+ETDUSED+ETDOCC, &undechdr,
+ (PETD *)0, (PETD *)0, (PECB *)0);
+ }
+ TRACEETD(docetd);
+ TRACEMOD(prcon);
+ TRACEETD(prcon[2].tu.thetd);
+ return;
+}
+/* PARSETAG: Tag end parser for SGML documents.
+ For start-tags, it
+ sets etisw to TAGNET if tag ended with ETI; otherwise to 0.
+*/
+VOID parsetag(pcb)
+struct parse *pcb; /* Parse control block: pcbstag or pcbetag. */
+{
+ tagdelsw = 1; /* Assume tag had an ETI or TAGC. */
+ switch (parse(pcb)) {
+ case ETIC: /* Tag closed with ETI. */
+ if (!sd.shorttag) synerr(194, pcb);
+ etisw = TAGNET; /* Set switch for stack entry flag. */
+ return;
+ case DSC:
+ synerr(9, pcb);
+ REPEATCC;
+ etisw = 0;
+ return;
+ case NVS: /* Att name or value token found. */
+ case NTV: /* Name token value found. */
+ synerr(E_POSSATT, pcb);
+ pcb->newstate = 0; /* Reset parse state. */
+ REPEATCC; /* Put it back for next read. */
+ tagdelsw = 0; /* Tag had no closing delimiter. */
+ etisw = 0; /* Don't flag stack entry. */
+ return;
+ case TAGO: /* Tag closing implied by TAGO. */
+ if (!sd.shorttag) synerr(193, pcb);
+ REPEATCC; /* Put it back for next read. */
+ tagdelsw = 0; /* Tag had no closing delimiter. */
+ case TAGC: /* Normal close. */
+ default: /* Invalid character (msg was sent). */
+ etisw = 0; /* Don't flag stack entry. */
+ return;
+ }
+}
+/* STAG: Check whether a start-tag is valid at this point in the document
+ structure, or whether other tags must precede it.
+ Special case processing is done for the fake tag, #CDATA, as
+ it is never stacked.
+*/
+int stag(dataret)
+int dataret; /* Data pending: DAF_ REF_ 0=not #PCDATA. */
+{
+ int rc, realrc; /* Return code from context or other test. */
+ int mexts = 0; /* >0=stack level of minus grp; -1=plus; 0=none.*/
+
+ badresw = pexsw = 0;
+ /* If real element (i.e., not #PCDATA) set mexts and test if empty. */
+ if (dataret==0) {
+ mexts = pexmex(newetd);
+ /* If element is declared empty, it is same as a conref. */
+ if (GET(newetd->etdmod->ttype, MNONE)) conrefsw = TAGREF;
+ }
+ if (GET(tags[ts].tetd->etdmod->ttype, MANY))
+ rc = mexts>0 ? RCMEX : RCHIT;
+ else rc = context(newetd, tags[ts].tetd->etdmod, tags[ts].tpos,
+ &tags[ts].status, mexts);
+ TRACESTG(newetd, dataret, rc, nextetd, mexts);
+
+ switch (rc) {
+ case RCEND: /* End current element, then retry start-tag. */
+ if (ts<1) realrc = RCMISS;
+ else realrc = RCEND;
+ break;
+ case RCREQ: /* Stack compulsory GI, then retry start-tag. */
+ realrc = RCREQ;
+ break;
+ case RCMISS: /* Start-tag invalid (#PCDATA or real). */
+ if (ts>0 && GET(tags[ts].tetd->etdmod->ttype, MANY))
+ realrc = RCEND;
+ else realrc = RCMISS;
+ break;
+ case RCMEX: /* Start-tag invalid (minus exception). */
+ etagimct = ts - mexts;
+ realrc = RCEND;
+ break;
+ case RCHITMEX: /* Invalid minus exclusion for required element. */
+ sgmlerr(216, &pcbstag, NEWGI, tags[mexts].tetd->etdgi+1);
+ /* fall through */
+ case RCHIT: /* Start-tag was valid. */
+ realrc = RCHIT;
+ break;
+ case RCPEX: /* Start-tag valid only because of plus exception. */
+ pexsw = TAGPEX;
+ realrc = RCHIT;
+ break;
+ default:
+ abort();
+ }
+
+ switch (realrc) {
+ case RCEND: /* End current element, then retry start-tag. */
+ if (didreq) sgmlerr(07, &pcbstag, nextetd->etdgi+1, (UNCH *)0);
+ didreq = 0; /* No required start-tag done. */
+ dostag = 1; etiswsv = etisw; /* Save real start-tag status. */
+ conrefsv = conrefsw; /* Save real start-tag conref. */
+ conrefsw = 0; /* Current element is not empty. */
+ etagmin = MINSTAG; destack(); /* Process omitted end-tag. */
+ return ETG_;
+ case RCREQ: /* Stack compulsory GI, then retry start-tag. */
+ if (!BADPTR(nextetd)) {
+ if ((mexts = pexmex(nextetd))>0)
+ sgmlerr(E_MEXERR, &pcbstag, nextetd->etdgi+1,
+ tags[mexts].tetd->etdgi+1);
+ if (!nextetd->etdmod) {
+ sgmlerr(53, &pcbstag, nextetd->etdgi+1, (UNCH *)0);
+ etdset(nextetd, (UNCH)SMO+EMO+ETDOCC, &undechdr,
+ (PETD *)0, (PETD *)0, (PECB *)0);
+ ++ds.etdercnt;
+ TRACEETD(nextetd);
+ }
+ }
+ if (BITOFF(nextetd->etdmin, SMO)) {
+ if (!BADPTR(stagreal))
+ sgmlerr(21, &pcbstag, nextetd->etdgi+1, stagreal->etdgi+1);
+ else if (stagreal==ETDCDATA)
+ sgmlerr(49, &pcbstag, nextetd->etdgi+1, (UNCH *)0);
+ else sgmlerr(50, &pcbstag, nextetd->etdgi+1, (UNCH *)0);
+ }
+ didreq = 1; /* Required start-tag done. */
+ dostag = 1; etiswsv = etisw; /* Save real start-tag status. */
+ etisw = 0; conrefsv = conrefsw; /* Save real start-tag conref. */
+ /* If element is declared empty, it is same as a conref. */
+ conrefsw = (GET(nextetd->etdmod->ttype, MNONE)) ? TAGREF : 0;
+ stack(nextetd); /* Process omitted start-tag. */
+ return STG_;
+ case RCMISS: /* Start-tag invalid (#PCDATA or actual). */
+ dostag = 0; contersw |= 1; didreq = 0;
+ if (dataret) {
+ if (dataret==REF_) badresw = 1;
+ else sgmlerr(E_CHARS, conpcb, tags[ts].tetd->etdgi+1, (UNCH *)0);
+ return dataret;
+ }
+ sgmlerr(E_CONTEXT, &pcbstag, NEWGI, tags[ts].tetd->etdgi+1);
+ if (stagmin!=MINNULL) stagmin = MINNONE; stack(newetd);
+ return STG_;
+ case RCHIT: /* Start-tag was valid. */
+ dostag = 0; didreq = 0;
+ if (dataret) return dataret;
+ stack(newetd);
+ return STG_;
+ }
+ return NOP_; /* To avoid Borland C++ warning */
+}
+/* PEXMEX: See if a GI is in a plus or minus exception group on the stack.
+ If in a minus, returns stack level of minus group; otherwise,
+ returns -1 if in a plus and not a minus, and zero if in neither.
+*/
+int pexmex(curetd)
+struct etd *curetd; /* The etd for this GI. */
+{
+ int tsl; /* Temporary stack level for looping. */
+ int pex = 0; /* 1=found in plus grp; 0=not. */
+
+ for (tsl = ts; tsl>0; --tsl) {
+ if (tags[tsl].tetd->etdmex && ingrp(tags[tsl].tetd->etdmex, curetd))
+ return(tsl);
+ if (tags[tsl].tetd->etdpex && ingrp(tags[tsl].tetd->etdpex, curetd))
+ pex = -1;
+ }
+ return(pex);
+}
+/* STACK: Add a new entry to the tag stack.
+ If there is no room, issue a message and reuse last position.
+*/
+VOID stack(curetd)
+struct etd *curetd; /* The etd for this entry. */
+{
+ /* Stack the new element type definition (error if no room). */
+ if (++ts>TAGLVL)
+ sgmlerr(E_STAGMAX, conpcb, curetd->etdgi+1, tags[--ts].tetd->etdgi+1);
+ tags[ts].tetd = curetd;
+
+ /* Set flags: plus exception + tag had ETI + context error + empty. */
+ tags[ts].tflags = (UNCH)pexsw + etisw + contersw + conrefsw; contersw = 0;
+
+ /* If tag had ETI, update ETI counter and enable NET if first ETI. */
+ if (etisw && ++etictr==1) lexcon[lex.d.net] = lexcnm[lex.d.net] = lex.l.net;
+
+ /* If etd has ALT table, use it; otherwise, use last element's ALT. */
+ if (curetd->etdsrm) {
+ if (curetd->etdsrm != SRMNULL && curetd->etdsrm[0] == NULL) {
+ /* Map hasn't been defined. Ignore it.
+ We already gave an error. */
+ curetd->etdsrm = 0;
+ tags[ts].tsrm = tags[ts-1].tsrm;
+ }
+ else
+ tags[ts].tsrm = curetd->etdsrm;
+ }
+ else
+ tags[ts].tsrm = tags[ts-1].tsrm;
+
+ /* Initialize rest of stack entry. */
+ tags[ts].status = 0;
+ tags[ts].tpos[0].g = 1; /* M: Index in model of next token to test.*/
+ tags[ts].tpos[0].t = 1; /* P: Index in tpos of current group. */
+ HITCLEAR(tags[ts].tpos[0].h);
+ tags[ts].tpos[1].g = 1; /* Index of group in model (dummy grp). */
+ tags[ts].tpos[1].t = 1; /* 1st token is next in grp to be tested. */
+ HITCLEAR(tags[ts].tpos[1].h); /* No hits yet as yet. */
+ TRACESTK(&tags[ts], ts, etictr);
+ return;
+}
+/* ETAG: Check validity of an end-tag by seeing if it matches any tag
+ on the stack. If so, return the offset of the match from the
+ current entry (0=current). If there is no match, issue a message
+ and return an error code (-1).
+ If the newetd is ETDNET, a NET delimiter was found, so check for
+ a tag that ended with ETI instead of a matching GI.
+*/
+int etag()
+{
+ int tsl = ts+1; /* Temporary stack level for looping. */
+
+ /* See if end-tag is anywhere on stack, starting at current entry. */
+ while (--tsl) {
+ if (newetd!=ETDNET ? newetd==tags[tsl].tetd : tags[tsl].tflags) {
+ TRACEETG(&tags[ts], newetd, tsl, ts-tsl);
+ return(ts-tsl);
+ }
+ }
+ return (-1); /* End-tag didn't match any start-tag. */
+}
+/* DESTACK:
+ Call ECONTEXT to see if element can be ended at this point.
+ and issue message if there are required tags left.
+ Remove the current entry from the tag stack.
+ Issue an error if the destacked element was not minimizable
+ and its end-tag was omitted.
+*/
+VOID destack()
+{
+ register int ecode = 0; /* Error code (0=o.k.). */
+ UNCH *eparm2 = NULL; /* Second parameter of error message. */
+ register int minmsgsw; /* 1=message if tag omitted; 0=no message. */
+
+ /* If element has a content model (i.e., not a keyword) and there
+ are required tags left, and no CONREF attribute was specified,
+ issue an error message.
+ */
+ lastetd = tags[ts].tetd;
+ if (!GET(tags[ts].tetd->etdmod->ttype, MKEYWORD)
+ && !conrefsw
+ && !econtext(tags[ts].tetd->etdmod, tags[ts].tpos, &tags[ts].status)) {
+ if (BADPTR(nextetd))
+ sgmlerr(54, conpcb, tags[ts].tetd->etdgi+1, (UNCH *)0);
+ else
+ sgmlerr(30, conpcb, tags[ts].tetd->etdgi+1, nextetd->etdgi+1);
+ }
+ /* If the current tag ended with ETI, decrement the etictr.
+ If etictr is now zero, disable the NET delimiter.
+ */
+ if (GET(tags[ts--].tflags, TAGNET) && --etictr==0)
+ lexcon[lex.d.net] = lexcnm[lex.d.net] = lex.l.nonet;
+
+ minmsgsw = BITOFF(tags[ts+1].tetd->etdmin, EMO);
+ if (!conrefsw && minmsgsw && (etagimsw || etagmin==MINETAG)) {
+ /* Minimization caused by NET delimiter. */
+ if (BADPTR(etagreal)) ecode = 46;
+ /* Minimization caused by a containing end-tag. */
+ else {ecode = 20; eparm2 = etagreal->etdgi+1;}
+ }
+ else if (!conrefsw && etagmin==MINSTAG && (minmsgsw || ts<=0)) {
+ /* Minimization caused by out-of-context start-tag. */
+ if (!BADPTR(stagreal)) {
+ ecode = ts>0 ? 39 : 89;
+ eparm2 = stagreal->etdgi+1;
+ }
+ /* Minimization caused by out-of-context data. */
+ else if (stagreal==ETDCDATA) ecode = ts>0 ? 47 : 95;
+ /* Minimization caused by out-of-context short start-tag. */
+ else ecode = ts>0 ? 48 : 96;
+ if (ts<=0 && ecode) eodsw = 1;
+ }
+ if (ecode) sgmlerr((UNS)ecode, conpcb, tags[ts+1].tetd->etdgi+1, eparm2);
+ /* TEMP: See if parser bug caused stack to go below zero. */
+ else if (ts<0) {sgmlerr(64, conpcb, (UNCH *)0, (UNCH *)0); ts = 0;}
+ TRACEDSK(&tags[ts], &tags[ts+1], ts, etictr);
+ if (ts == 0) {
+ docelsw = 1; /* Finished document element. */
+ if (es > 0) sgmlerr(231, conpcb, (UNCH *)0, (UNCH *)0);
+ }
+}
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/pars2.c b/usr.bin/sgmls/sgmls/pars2.c
new file mode 100644
index 0000000..4249797
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/pars2.c
@@ -0,0 +1,1333 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+/* PARSE: Parse a source input stream with specified lexical and state tables.
+ Return to caller with action code.
+*/
+int parse(pcb)
+struct parse *pcb; /* Current parse control block. */
+{
+ int rc; /* Return code from ENTREF. */
+
+ while (1) {
+ NEWCC;
+ pcb->input = pcb->plex[*FPOS];
+ pcb->state = pcb->newstate;
+ pcb->newstate = (*(pcb->ptab + pcb->state)) [pcb->input];
+ pcb->action = (*(pcb->ptab + pcb->state + 1)) [pcb->input];
+ TRACEPCB(pcb);
+ switch (pcb->action) {
+ case RC2_: /* Back up two characters. */
+ REPEATCC;
+ case RCC_: /* Repeat current character. */
+ REPEATCC;
+ case NOP_: /* No action necessary.*/
+ continue;
+
+ case RS_: /* Record start: ccnt=0; ++rcnt.*/
+ ++RCNT; CTRSET(RSCC);
+ continue;
+
+ case GET_: /* EOB or dull EOS or EE found: keep going.*/
+ if (entget()==-1) {pcb->action = EOD_; break;}/* Signal if EOD.*/
+ continue;
+
+ case EOF_: /* Illegal entity end; return EE_. */
+ synerr(E_EOF, pcb);
+ pcb->action = EE_;
+ case EE_: /* Important EOS or EE found: return to caller.*/
+ if (entget()==-1) pcb->action = EOD_; /* Signal if EOD. */
+ break;
+
+ case PER_: /* Parameter entity reference. */
+ REPEATCC; /* Use PERO as 1st char of entity name. */
+ parsenm(entbuf, ENTCASE);
+ parse(&pcbref); /* Handle REFC or other terminator. */
+ rc = entref(entbuf);
+ if (rc==ENTPI) {pcb->action = PIE_; break;}
+ continue;
+
+ case ER_: /* General entity reference; continue. */
+ parsenm(entbuf, ENTCASE);
+ parse(&pcbref); /* Handle REFC or other terminator. */
+ rc = entref(entbuf);
+ if (rc==ENTDATA) {pcb->action = DEF_; break;}
+ if (rc==ENTPI) {pcb->action = PIE_; break;}
+ continue;
+
+
+ case PEX_: /* Parameter entity reference; return. */
+ REPEATCC; /* Use PERO as 1st char of entity name. */
+ case ERX_: /* General entity reference; return. */
+ parsenm(entbuf, ENTCASE);
+ parse(&pcbref); /* Handle REFC or other terminator. */
+ rc = entref(entbuf);
+ if (rc == ENTDATA){
+ /* Reference to external data/subdoc entity in replaceable
+ character data. */
+ if (BITON(entdatsw, NDECONT)) {
+ switch (((PNE)data)->nextype) {
+ case ESNCDATA:
+ case ESNSDATA:
+ /* The standard says `non-SGML data entity'
+ but the amendment should have changed it
+ to `external data entity'. */
+ synerr(145, pcb);
+ break;
+ case ESNNDATA:
+ case ESNSUB:
+ /* This is definitely illegal. */
+ synerr(141, pcb);
+ break;
+ }
+ entdatsw = 0;
+ continue;
+ }
+ pcb->action = DEF_;
+ }
+ else if (rc == ENTPI) {
+ /* Reference to PI entity not allowed in replaceable
+ character data. */
+ synerr(59, pcb);
+ entpisw = 0;
+ continue;
+ }
+ else if (rc) pcb->action = EE_;
+ break;
+
+ case CRN_: /* Character reference: numeric. */
+ parsetkn(entbuf, NU, NAMELEN);
+ parse(&pcbref); /* Handle reference terminator. */
+ pcb->action = charrefn(entbuf, pcb);
+ if (pcb->action==CRN_) continue; /* Invalid reference */
+ break;
+
+ case CRA_: /* Character reference: alphabetic. */
+ parsenm(entbuf, NAMECASE);
+ parse(&pcbref); /* Handle reference terminator. */
+ charrefa(entbuf);
+ if (docelsw) synerr(232, pcb);
+ continue;
+
+ case SYS_: /* Invalid NONCHAR: send msg and ignore. */
+ synerr(E_SYS, pcb);
+ if (*FPOS == DELNONCH) NEWCC;
+ continue;
+
+ case NON_: /* Valid NONCHAR: prefix and shift encoding. */
+ synerr(60, pcb);
+ pcb->action = datachar(*FPOS, pcb);
+ break;
+ case NSC_:
+ synerr(60, pcb);
+ NEWCC;
+ nonchbuf[1] = *FPOS;
+ pcb->action = NON_;
+ break;
+ case PCI_: /* Previous character was invalid (INV_). */
+ REPEATCC;
+ case INV_: /* Markup ended by invalid char; repeat char. */
+ synerr(9, pcb);
+ REPEATCC;
+ break;
+
+ case LNR_: /* Previous char exceeded len; back up to it. */
+ REPEATCC;
+ case LEN_: /* Token too long; ignore excess character. */
+ synerr(3, pcb);
+ continue;
+
+ case RCR_: /* Repeat current char and return to caller. */
+ REPEATCC;
+ default: /* Actions for specific parse. */
+ break;
+ }
+ return (int)pcb->action;
+ }
+}
+/* CHARREFA: Resolve an alphabetical reference to a function character
+ and put the character in the read buffer.
+ If reference is bad, issue an error message.
+*/
+VOID charrefa(r)
+UNCH *r; /* Undelimited char ref (with length and EOS). */
+{
+ UNCH thechar;
+
+ thechar = mapsrch(funtab, r+1);
+ if (thechar == 0)
+ synerr(62, &pcbref);
+ else {
+ /* This isn't ideal, because the character position will still
+ be wrong for one line. */
+ if (thechar == RSCHAR) RCNT--;
+ setcurchar(thechar);
+ REPEATCC;
+ }
+}
+
+/* Make the current character ch. */
+
+VOID setcurchar(ch)
+int ch;
+{
+ /* If we're reading directly from an internal entity, we can't
+ change the entity, since the entity might be referenced again.
+ So in this case we copy the entity. This is inefficient, but
+ it will only happen in a case like this:
+
+ <!entity % amp "&">
+ <!entity e "x%amp;#SPACE;">
+
+ Usually character references will have been processed while the
+ entity was being defined. */
+ if (*FPOS != ch) {
+ if (!FILESW && !COPIEDSW) {
+ UNCH *s = savestr(FBUF + 1);
+ FPOS = s + (FPOS - FBUF - 1);
+ FBUF = s - 1;
+ COPIEDSW = 1;
+ }
+ *FPOS = ch;
+ }
+}
+
+/* CHARREFN: Resolve a numeric character reference.
+ If reference is bad, issue an error message.
+*/
+
+int charrefn(r, pcb)
+UNCH *r; /* Undelimited character reference. */
+struct parse *pcb; /* Current parse control block. */
+{
+ int thechar;
+
+ thechar = atoi((char *)r);
+ if (thechar<0 || thechar>255) {
+ synerr(61, &pcbref);
+ return((int)pcb->action);
+ }
+ return datachar(thechar, pcb);
+}
+
+/* Return ch as a datachar. If this a non-SGML character which might
+confuse the parser, shift it to a code that won't and place it in a
+special buffer which has DELNONCH in the preceding byte. Otherwise
+put it the read buffer. */
+
+int datachar(ch, pcb)
+int ch;
+struct parse *pcb;
+{
+ switch (ch) {
+ case EOS:
+ case EOFCHAR:
+ case EOBCHAR:
+ case GENRECHAR:
+ case DELCDATA:
+ case DELSDATA:
+ case DELNONCH:
+ /* A potentially confusing character which must be prefixed
+ with DELNONCH. */
+ nonchbuf[1] = SHIFTNON((UNCH)ch);
+ return NON_;
+ }
+ setcurchar(ch);
+ /* If in content, return DCE_ for element content, DAF_ for mixed. */
+ /* If not content, it must be a literal parse, so return MLA_. */
+ if (pcb == conpcb) {
+ if (pcb == &pcbcone)
+ return DCE_;
+ else {
+ data = FPOS;
+ /* Action for DAF_ will do REPEATCC. */
+ NEWCC;
+ return DAF_;
+ }
+ }
+ else
+ return MLA_;
+}
+/* INITATT: Initialize al with adl. */
+
+VOID initatt(adl)
+struct ad *adl;
+{
+ notadn = 0; /* No NOTATION attribute yet. */
+ conrefsw = 0; /* Assume no content reference att. */
+ /* Copy attribute definition list as a template. */
+ memcpy((UNIV)al, (UNIV)adl, (1+ADN(adl))*ADSZ);
+}
+
+/* PARSEATT: Parse attribute specification list.
+ Make a current copy of the attribute definition list
+ and update it with the user's specifications.
+ Indicate each attribute that was specified in the
+ list (as opposed to defaulted) by setting the ASPEC flag.
+ If no attributes were specified, return NULL. Otherwise,
+ if in the prolog, make a permanent copy of the list and
+ return its pointer. If not in the prolog, return al.
+*/
+struct ad *parseatt(adl, pt)
+struct ad *adl; /* Attribute definition list. */
+UNCH *pt; /* Tokenization area: tbuf[TAGLEN+ATTSPLEN]. */
+{
+ UNCH *antvptr;
+ UNCH *nm = 0; /* Pointer to saved name in tbuf (with length). */
+ int adn = -1; /* Position of attribute in list (-1=empty). */
+ UNCH *tbuflim = pt + ATTSPLEN;
+ mdessv = es; /* Save es for checking entity nesting. */
+ initatt(adl);
+ while (pt<=tbuflim) {
+ parse(&pcbstag);
+ switch (pcbstag.action) {
+ case NVS: /* Att name or value token found. */
+ parsenm(pt, NAMECASE); /* Case translation wanted on name. */
+ pt += *(nm = pt); /* Save name while pointing past it. */
+ continue;
+
+ case AVD: /* Delimited value found. */
+ case AVDA: /* Delimited value found (alternate delimiter). */
+ /* Find position (adn) of saved attribute name in list. */
+ adn = anmget((int)ADN(al), nm);
+ parselit(pt,
+ (adn == 0 || ADTYPE(al, adn) == ACHARS)
+ ? &pcblitr
+ : &pcblitt,
+ LITLEN,
+ (pcbstag.action==AVD) ? lex.d.lit : lex.d.lita);
+ if (adn == 0) {
+ /* Error: unrecognized attribute name. */
+ sgmlerr(13, &pcbstag, nm+1, pt);
+ continue;
+ }
+ /* Tokenize and validate value; let it default if an error. */
+ /* Put value in list and bump ptr by the normalized length
+ (which is always >= the actual length). */
+ if (!attval(1, pt, adn, adl)) pt += ADLEN(al,adn);
+ continue;
+ case AVU: /* Attribute value found: undelimited. */
+ if (!sd.shorttag) sgmlerr(196, &pcbstag, (UNCH *)0, (UNCH *)0);
+ parsetkn(pt, NMC, LITLEN);
+ /* Find position (adn) of saved attribute name in list. */
+ if ((adn = anmget((int)ADN(al), nm))==0) {
+ /* Error: unrecognized attribute name. */
+ sgmlerr(13, &pcbstag, nm+1, pt);
+ continue;
+ }
+ /* Tokenize and validate value; let it default if an error. */
+ /* Put value in list and bump ptr by the normalized length
+ (which is always >= the actual length). */
+ if (!attval(1, pt, adn, adl)) pt += ADLEN(al,adn);
+ continue;
+
+ case NASV: /* Saved NVS was really an NTV. */
+ REPEATCC; /* Put back next token starter. */
+ pt = nm; /* Back up to NVS. */
+ case NTV: /* Name token value found. */
+ if (!sd.shorttag) sgmlerr(195, &pcbstag, (UNCH *)0, (UNCH *)0);
+ if (pcbstag.action==NTV) parsenm(pt, NAMECASE);
+ if ((adn = antvget((int)ADN(al), pt, &antvptr))==0) {
+ /* Error: unrecognized name token value. */
+ sgmlerr(74, &pcbstag, pt+1, (UNCH *)0);
+ continue;
+ }
+ /* Validate value; let it default if an error. */
+ /* Put value in list and bump ptr by the normalized length
+ (which is always >= the actual length). */
+ if (!attval(0, antvptr+1, adn, adl)) pt += ADLEN(al,adn);
+ continue;
+
+ default: /* All attributes have been parsed. */
+ REPEATCC; /* Put next char back for tag close parse. */
+ break;
+ }
+ break;
+ }
+ if (pt>tbuflim) synerr(75, &pcbstag);
+ if (es!=mdessv) synerr(37, &pcbstag);
+ if (adn<0) return((struct ad *)0); /* List was empty. */
+ TRACEADL(al);
+ return al;
+}
+/* ATTVAL: Validate a specified attribute value. Issue a message if it is
+ the wrong type (or otherwise is not up to spec), and use the default.
+ Call PARSEVAL to tokenize the value, unless it is a CDATA string.
+ If the attribute is a group, the value is a string.
+ For other types, the token count is set by PARSEVAL if the value
+ is syntactically correct. If incorrect (or if CDATA) the token
+ count is zero (i.e., the value is a string).
+ The length of a token does not include the length byte, and
+ there is no EOS. A string length (as always) includes both
+ the length byte and the EOS.
+ If it is a CONREF attribute, set a switch for STAG().
+ If it is a CURRENT attribute, store the value as the new default.
+*/
+#define DEFVAL adl[adn].addef /* Default value of current attribute. */
+#define DEFNUM adl[adn].adnum /* Default group size of current attribute. */
+#define DEFLEN adl[adn].adlen /* Length of default value of current attribute.*/
+int attval(mtvsw, adval, adn, adl)
+int mtvsw; /* Must tokenize value: 1=yes; 0=no. */
+UNCH *adval; /* Untokenized attribute value. */
+int adn; /* Attribute's position in list. */
+struct ad *adl; /* Element's master att def list. */
+{
+ int errcode; /* Value/declaration conflict error code. */
+
+ if (GET(ADFLAGS(al,adn), ASPEC)) /* Can't respecify same attribute. */
+ {sgmlerr(73, &pcbstag, ADNAME(al,adn), adval); return(1);}
+ SET(ADFLAGS(al,adn), ASPEC); /* Indicate att was specified. */
+ if (GET(ADFLAGS(al,adn), ACONREF)) /* If attribute is content reference: */
+ conrefsw = TAGREF; /* Set switch for STAG(). */
+ if (mtvsw && ADTYPE(al,adn)!=ACHARS) {
+ /* If no syntax errors, check for proper group membership. */
+ if ( ((errcode = parseval(adval, ADTYPE(al,adn), lbuf))==0)
+ && GET(ADFLAGS(al,adn), AGROUP)
+ && !amemget(&al[adn], ADNUM(al,adn), lbuf) ) errcode = 18;
+ /* If syntax or group membership error, send message and exit. */
+ if (errcode) {
+ sgmlerr(errcode, &pcbstag, ADNAME(al,adn), adval);
+ SET(ADFLAGS(al,adn), AERROR);
+ return(1);
+ }
+ /* Replace specified value in adval with tokenized in lbuf. */
+ ustrcpy(adval, lbuf);
+ if (BITOFF(ADFLAGS(al,adn), AGROUP)) ADNUM(al,adn) = (UNCH)tokencnt;
+ }
+ if (!mtvsw)
+ adval--;
+ /* If attribute is FIXED, specified value must equal default. */
+ if (BITON(ADFLAGS(al,adn), AFIXED) && ustrcmp(adval, DEFVAL)) {
+ /* Since the value has been tokenized, don't use it in the
+ error message. */
+ sgmlerr(67, &pcbstag, ADNAME(al,adn), (UNCH *)0);
+ SET(ADFLAGS(al,adn), AERROR);
+ return(1);
+ }
+ ADLEN(al,adn) = vallen(ADTYPE(al,adn), ADNUM(al,adn), adval);
+ if (ADLEN(al,adn) > LITLEN) {
+ sgmlerr(224, &pcbstag, ADNAME(al,adn), (UNCH *)0);
+ SET(ADFLAGS(al,adn), AERROR);
+ return 1;
+ }
+ ADVAL(al,adn) = adval;
+ /* If attribute is CURRENT, value is new default.*/
+ if (GET(ADFLAGS(al,adn), ACURRENT)) {
+ if (ADLEN(al,adn)>DEFLEN) {
+ ds.attdef += (ADLEN(al,adn) - DEFLEN);
+ DEFLEN = ADLEN(al,adn);
+ }
+ DEFVAL = replace(DEFVAL, ADVAL(al,adn));
+ DEFNUM = ADNUM(al,adn);
+ }
+ return(0); /* Indicate value was valid. */
+}
+/* ADLVAL: Validate the completed attribute definition list (defaults plus
+ specified values). Issue a message if an
+ attribute is required or current and its value is NULL.
+*/
+VOID adlval(adsz, newetd)
+int adsz; /* Size of list. */
+struct etd *newetd; /* Element type definition for this element. */
+{
+ int adn = 1; /* Position in list. */
+ UNCH *npt, *pt; /* Ptr save areas. */
+ UNCH nptsv; /* Save area for ptr value (length?). */
+ struct dcncb *dpt; /* Save area for dcncb ptr. */
+
+ aentctr = 0; /* Number of AENTITY tokens in this att list. */
+ idrctr = 0; /* Number of IDREF tokens in this att list. */
+ do {
+ if (ADVAL(al,adn)==NULL) { /* NULL value */
+ if (GET(ADFLAGS(al,adn), AREQ+ACURRENT)) { /*Error if REQ, CURRENT*/
+ sgmlerr(19, &pcbstag, ADNAME(al,adn), (UNCH *)0);
+ SET(ADFLAGS(al,adn), AINVALID);
+ }
+ }
+ else switch (ADTYPE(al,adn)) {
+ case AENTITY: /* Return data ecb pointer if valid entity. */
+ aenttst(adn, ADVAL(al,adn));
+ break;
+ case AENTITYS: /* Return data ecb pointers if valid entities. */
+ pt = ADVAL(al,adn);
+ tokencnt = (int)ADNUM(al,adn);
+ while (tokencnt--) {
+ nptsv = *(npt = pt + *pt+1);
+ *pt += 2; *npt = EOS;
+ aenttst(adn, pt);
+ *pt -= 2; *(pt = npt) = nptsv;
+ }
+ break;
+ case AID:
+ /* Define ID; msg if it already exists. */
+ if (iddef(ADVAL(al,adn))) {
+ sgmlerr(71, &pcbstag, ADNAME(al,adn), ADVAL(al,adn)+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ continue;
+ }
+ ++ds.idcnt;
+ break;
+ case AIDREF:
+ idreftst(adn, ADVAL(al,adn));
+ break;
+ case AIDREFS:
+ pt = ADVAL(al,adn);
+ tokencnt = (int)ADNUM(al,adn);
+ while (tokencnt--) {
+ nptsv = *(npt = pt + *pt+1);
+ *pt += 2; *npt = EOS;
+ idreftst(adn, pt);
+ *pt -= 2; *(pt = npt) = nptsv;
+ }
+ break;
+ case ANOTEGRP: /* Return notation identifier. */
+ if (GET(ADFLAGS(al,adn), ASPEC)) notadn = adn;/*NOTATION specified*/
+ if ((dpt = dcnfind(ADVAL(al,adn)))==0) {
+ sgmlerr(77, &pcbstag, ADNAME(al,adn), ADVAL(al,adn)+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ }
+ else ADDATA(al,adn).x = dpt;
+ break;
+ }
+ if (!sd.shorttag && !sd.omittag && ADVAL(al,adn)!=NULL
+ && !GET(ADFLAGS(al,adn), ASPEC+AINVALID))
+ sgmlerr(197, &pcbstag, ADNAME(al,adn), (UNCH *)0);
+ } while ((adn+=BITON(ADFLAGS(al,adn),AGROUP) ? (int)ADNUM(al,adn)+1 : 1)<=adsz);
+
+ /* Error if NOTATION specified with CONREF attribute or EMPTY element. */
+ if (notadn && (conrefsw
+ || (newetd && GET(newetd->etdmod->ttype, MNONE)))) {
+ sgmlerr((UNS)(conrefsw ? 84 : 76), &pcbstag,
+ ADNAME(al,notadn), ADVAL(al,notadn)+1);
+ SET(ADFLAGS(al,notadn), AINVALID);
+ }
+}
+/* AENTTST: Validate an individual ENTITY token in AENTITY or AENTITYS value.
+*/
+VOID aenttst(adn, pt)
+int adn; /* Position in list. */
+UNCH *pt; /* Ptr to current ENTITY token in value. */
+{
+ struct entity *ept; /* Save area for ecb ptr. */
+
+ if (++aentctr>GRPCNT) {
+ sgmlerr(136, &pcbstag, ADNAME(al,adn), pt+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ return;
+ }
+ if ( (ept = entfind(pt))==0
+ && (ecbdeflt==0 || (ept = usedef(pt))==0) ) {
+ sgmlerr(ecbdeflt ? 151 : 72, &pcbstag, ADNAME(al,adn), pt+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ return;
+ }
+ if (ept->estore==ESX || ept->estore==ESC || ept->estore==ESN) {
+ /* Error if DCN has no notation identifier. */
+ if (ept->estore==ESN && NEXTYPE(ept->etx.n)!=ESNSUB
+ && !NEDCNDEFINED(ept->etx.n)) {
+ sgmlerr(78, &pcbstag, NEDCN(ept->etx.n)+1,
+ pt+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ }
+ }
+ else {
+ sgmlerr(86, &pcbstag, ADNAME(al,adn), pt+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ }
+}
+/* IDREFTST: Validate an individual IDREF token in an IDREF or IDREFS value.
+*/
+VOID idreftst(adn, pt)
+int adn; /* Position in list. */
+UNCH *pt; /* Ptr to current IDREF token in value. */
+{
+ struct fwdref *rp;
+ if (++idrctr>GRPCNT) {
+ sgmlerr(70, &pcbstag, ADNAME(al,adn), pt+1);
+ SET(ADFLAGS(al,adn), AINVALID);
+ return;
+ }
+ /* Note IDREF; indicate if ID exists. */
+ if ((rp = idref(pt)) != 0)
+ rp->msg = saverr(69, &pcbstag, ADNAME(al,adn), pt+1);
+ ++ds.idrcnt;
+}
+/* ANMGET: Locate an attribute name in an attribute definition list.
+*/
+int anmget(adsz, nm)
+int adsz; /* Size of list. */
+UNCH *nm; /* Value to be found (with length byte). */
+{
+ int adn = 0; /* Position in list. */
+
+ while (++adn <= adsz && ustrcmp(nm+1, ADNAME(al,adn))) {
+ if (BITON(ADFLAGS(al,adn), AGROUP)) adn += (int)ADNUM(al,adn);
+ }
+ return (adn > adsz) ? 0 : adn;
+}
+/* ANTVGET: Find the position of a name token value in an attribute list.
+ Return the position of the attribute definition, or zero
+ if none was found. Set pp to the value, if non-NULL.
+*/
+int antvget(adsz, nm, pp)
+int adsz; /* Size of list. */
+UNCH *nm; /* Value to be found (with length byte). */
+UNCH **pp; /* Store value here */
+{
+ int adn = 0; /* Position in list. */
+
+ while (++adn<=adsz) {
+ /* Test only name group members. */
+ if (BITON(ADFLAGS(al,adn), AGROUP)) {
+ int advn; /* Position of value in sub-list. */
+ if ((advn = amemget(&al[adn], (int)ADNUM(al,adn), nm))!=0) {
+ if (pp)
+ *pp = al[adn+advn].adname;
+ return adn;
+ }
+ adn += (int)ADNUM(al,adn);
+ }
+ }
+ return 0;
+}
+/* AMEMGET: Get the position of a member in an attribute name token group.
+ Returns the position, or zero if not found.
+ The length byte is ignored in the comparison so that final
+ form tokens from ATTVAL can be compared to group members.
+*/
+int amemget(anmtgrp, adsz, nm)
+struct ad anmtgrp[]; /* Name token group. */
+int adsz; /* Size of group. */
+UNCH *nm; /* Name to be found (with length byte). */
+{
+ int adn = 0; /* Position in group. */
+
+ while ( ++adn<=adsz && ustrncmp(nm+1, anmtgrp[adn].adname+1, (UNS)*nm-1)) ;
+ return (adn>adsz) ? 0 : adn;
+}
+/* VALLEN: Returns the length of an attribute value for capacity
+ calculations. Normally, the length is NORMSEP plus the number
+ of characters. For tokenized lists, it is NORMSEP,
+ plus the number of characters in the tokens, plus
+ NORMSEP for each token.
+ ACHARS and tokenized lists don't have a length byte.
+
+*/
+UNS vallen(type, num, def)
+int type; /* ADTYPE(al,adn) */
+int num; /* ADNUM(al,adn) */
+UNCH *def; /* ADVAL(al,adn) */
+{
+ if (type == ACHARS)
+ return ustrlen(def) + NORMSEP;
+ if (type < ATKNLIST)
+ return *def - 2 + NORMSEP;
+ return ustrlen(def) + num * (NORMSEP - 1) + NORMSEP;
+}
+/* PARSEGRP: Parse GI names, get their etds, and form an array of pointers
+ to them. The array is terminated by a NULL pointer.
+ The number of pointers (including the NULL) is returned.
+ The grp buffer must have room for GRPCNT+1 etds.
+*/
+UNS parsegrp(grp, pcb, tbuf)
+struct etd *grp[]; /* Buffer for building the group. */
+struct parse *pcb; /* Current parse control block. */
+UNCH *tbuf;
+{
+ int grpcnt = 0; /* Number of etds in the group. */
+ int i;
+ int essv = es; /* Entity stack level when grp started. */
+
+ while (parse(pcb)!=GRPE && grpcnt<GRPCNT) {
+ switch (pcb->action) {
+ case NAS_: /* GI name: get its etd for the group. */
+ grp[grpcnt] = etddef(parsenm(tbuf, NAMECASE));
+ for (i = 0; i < grpcnt; i++)
+ if (grp[i] == grp[grpcnt]) {
+ mderr(98, ntoa(grpcnt + 1), grp[grpcnt]->etdgi + 1);
+ break;
+ }
+ if (i == grpcnt)
+ grpcnt++;
+ continue;
+
+ case EE_: /* Entity ended (correctly or incorrectly). */
+ if (es<essv) {synerr(37, pcb); essv = es;}
+ continue;
+
+ case PIE_: /* PI entity reference (invalid). */
+ entpisw = 0; /* Reset PI entity indicator. */
+ synerr(59, pcb);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ grp[grpcnt++] = 0; /* NULL pointer indicates end of group. */
+ if (es!=essv) synerr(37, pcb);
+ return grpcnt; /* Return number of ptrs in group. */
+}
+/* PARSNGRP: Parse notation names, get their dcncbs, and form an array of
+ pointers to them. The array is terminated by a NULL pointer.
+ The number of pointers (including the NULL) is returned.
+ The grp buffer must have room for GRPCNT+1 members.
+*/
+UNS parsngrp(grp, pcb, tbuf)
+struct dcncb *grp[]; /* Buffer for building the group. */
+struct parse *pcb; /* Current parse control block. */
+UNCH *tbuf;
+{
+ int grpcnt = 0; /* Number of members in the group. */
+ int i;
+ int essv = es; /* Entity stack level when grp started. */
+
+ while (parse(pcb)!=GRPE && grpcnt<GRPCNT) {
+ switch (pcb->action) {
+ case NAS_: /* Member name: get its control block. */
+ grp[grpcnt] = dcndef(parsenm(tbuf, NAMECASE));
+ for (i = 0; i < grpcnt; i++)
+ if (grp[i] == grp[grpcnt]) {
+ mderr(98, ntoa(grpcnt + 1), grp[grpcnt]->ename + 1);
+ break;
+ }
+ if (i == grpcnt)
+ grpcnt++;
+ continue;
+
+ case EE_: /* Entity ended (correctly or incorrectly). */
+ if (es<essv) {synerr(37, pcb); essv = es;}
+ continue;
+
+ case PIE_: /* PI entity reference (invalid). */
+ entpisw = 0; /* Reset PI entity indicator. */
+ synerr(59, pcb);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ grp[grpcnt++] = 0; /* NULL pointer indicates end of group. */
+ if (es!=essv) synerr(37, pcb);
+ return grpcnt; /* Return number of ptrs in group. */
+}
+/* COPYGRP: Allocate storage for a group and copy the group into it.
+*/
+PETD *copygrp(pg, grpsz)
+PETD pg[]; /* Pointer to a group (array of etd ptrs). */
+UNS grpsz; /* Number of ptrs in grp, including final NULL. */
+{
+ UNS glen; /* Group length in characters. */
+ PETD *gnm; /* Ptr to permanent name group. */
+
+ if (pg==0) return (PETD *)0;
+ glen = grpsz * sizeof(struct etd *);
+ memcpy( (UNIV)(gnm = (struct etd **)rmalloc(glen)) , (UNIV)pg, glen );
+ return gnm;
+}
+/* INGRP: Locate an etd in a name group and return its index+1 (or zero
+ if not found).
+*/
+int ingrp(pg, ketd)
+PETD pg[]; /* Array of pointers to etds. */
+PETD ketd; /* Pointer to etd to be found in group. */
+{
+ int i = 0; /* Array index. */
+
+ while (pg[i]) if (pg[i++]==ketd) return i;
+ return 0;
+}
+/* PARSELIT: Parse a delimited string and collect it into a token.
+ Caller supplies buffer, which must be 1 longer than
+ maximum string allowed.
+ Caller also supplies character that delimits the string.
+ TODO: Return 1 if CDATA, SDATA or NONSGML occurred.
+*/
+#ifdef USE_PROTOTYPES
+VOID parselit(UNCH *tbuf, struct parse *pcb, UNS maxlen, UNCH del)
+#else
+VOID parselit(tbuf, pcb, maxlen, del)
+UNCH *tbuf; /* Work area for tokenization (parmlen+1). */
+struct parse *pcb; /* Current parse control block. */
+UNS maxlen; /* Maximum length of token. */
+UNCH del; /* Literal delimiter: LIT LITA PIC EOS */
+#endif
+{
+ UNCH *pt = tbuf; /* Current pointer into tbuf. */
+ UNCH lexsv = pcb->plex[del];/* Saved value of delimiter in lexical table. */
+ int essv = es; /* Entity stack level when literal started. */
+ UNCH datadel; /* Delimiter for CDATA/SDATA entity. */
+ int parmlen = (int)maxlen + 1; /* Working limit (to be decremented). */
+ int overflow = 0; /* Did the buffer overflow? */
+
+ pcb->plex[del] = pcb->plex == lexlms ? lex.l.litc : lex.l.minlitc;
+
+ /* The RPR_ action may cause the length of the literal to decrease by
+ 1 (this discards a final space in a minimum literal); so while
+ building the literal, the length must be allowed to grow to
+ maxlen + 1. */
+
+ do {
+ switch (parse(pcb)) {
+ case LP2_: /* Move 2nd char back to buffer; redo prev.*/
+ REPEATCC;
+ case LPR_: /* Move previous char to buffer; REPEATCC; */
+ REPEATCC;
+ case MLA_: /* Move character to buffer. */
+ if (parmlen <= 0) { overflow = 1; break; }
+ *pt++ = *FPOS; --parmlen;
+ continue;
+
+ case FUN_: /* Function char found; replace with space.*/
+ if (parmlen <= 0) { overflow = 1; break; }
+ *pt++ = ' '; --parmlen;
+ continue;
+
+ case RSM_: /* Record start: ccnt=0; ++rcnt.*/
+ ++RCNT; CTRSET(RSCC);
+ if (parmlen <= 0) { overflow = 1; break; }
+ *pt++ = *FPOS; --parmlen;
+ continue;
+
+ case ERX_: /* Entity reference: cancel LITC delim. */
+ case PEX_: /* Parameter entity ref: cancel LITC delim.*/
+ lexlms[del] = lexsv;
+ continue;
+
+ case EE_:
+ if (es<essv) {
+ synerr(37, pcb);
+ essv = es;
+ }
+ /* If back at top level, re-enable the LITC delimiter. */
+ if (es==essv) lexlms[del] = lex.l.litc;
+ continue;
+
+ case MLE_: /* Char not allowed in minimum literal. */
+ synerr(63, pcb);
+ continue;
+
+ case DEF_: /* Data entity: add it to buffer. */
+ if (pcb == &pcblitt) {
+ int parmlensv = parmlen;
+ entdatsw = 0;
+ parmlen = tokdata(pt, parmlen);
+ if (parmlen < 0)
+ break;
+ pt += parmlensv - parmlen;
+ continue;
+ }
+ if (parmlen < datalen + 2) {
+ entdatsw = 0;
+ overflow = 1;
+ break;
+ }
+ parmlen -= datalen + 2;
+ *pt++ = datadel =
+ BITON(entdatsw, CDECONT) ? DELCDATA : DELSDATA;
+ entdatsw = 0;
+ memcpy( pt , data, datalen );
+ pt += datalen;
+ *pt++ = datadel;
+ continue;
+
+ case NON_: /* Non-SGML char (delimited and shifted). */
+ if (parmlen < 2) { overflow = 1; break; }
+ parmlen -= 2;
+ memcpy( pt , nonchbuf, 2 );
+ pt += 2;
+ continue;
+
+ case RPR_: /* Remove character from buffer. */
+ --pt; ++parmlen;
+ break;
+
+ case EOD_:
+ exiterr(92, pcb);
+
+ default:
+ break;
+ }
+ break;
+ } while (!overflow && pcb->action!=TER_);
+
+ if (parmlen <= 0) {
+ --pt;
+ overflow = 1;
+ }
+ if (overflow)
+ sgmlerr(134, pcb, ntoa((int)maxlen),(UNCH *)0);
+
+ datalen = (UNS)(pt-tbuf);/* To return PI string to text processor. */
+ *pt++ = EOS;
+ pcb->plex[del] = lexsv; /* Restore normal delimiter handling. */
+ if (es!=essv) synerr(37, pcb);
+}
+
+/* Handle a data entity in a tokenized attribute value literal.
+Parmlen is amount of space left. Return new parmlen. If there's not
+enough space return -1, and copy up to parmlen + 1 characters. Only
+tokenization should be done, not attribute value interpretation. */
+
+int tokdata(pt, parmlen)
+UNCH *pt;
+int parmlen;
+{
+ int skip = (pcblitt.newstate == 0);
+ int i;
+
+ for (i = 0; parmlen >= 0 && i < datalen; i++) {
+ switch (data[i]) {
+ case SPCCHAR:
+ if (!skip) {
+ *pt++ = data[i];
+ parmlen--;
+ skip = 1;
+ }
+ break;
+ default:
+ if (data[i] == DELNONCH) {
+ assert(i + 1 < datalen);
+ if ((parmlen -= 2) < 0)
+ break;
+ *pt++ = DELNONCH;
+ *pt++ = data[++i];
+ skip = 0;
+ }
+ else {
+ *pt++ = data[i];
+ parmlen--;
+ skip = 0;
+ }
+ break;
+ }
+ }
+ pcblitt.newstate = skip ? 0 : pcblittda;
+ return parmlen;
+}
+
+
+/* PARSEMD: Parser for markup declarations.
+ It returns a token each time it is called.
+
+*/
+int parsemd(pt, namecase, lpcb, tokenlen)
+UNCH *pt; /* Token buffer: >=tokenlen+2. */
+int namecase; /* Case translation: ENTCASE NAMECASE AVALCASE. */
+struct parse *lpcb; /* Parse control block for literal parse. */
+UNS tokenlen; /* Max length of expected token: NAMELEN LITLEN */
+{
+ struct parse *pcb; /* Current parse control block. */
+
+ pcb = (lpcb) ? &pcbmd : &pcbmdc; /* If no literal pcb, dcl is comment. */
+
+ doparse: while (parse(pcb)==EE_)
+ if (es<mdessv) {synerr(37, pcb); mdessv = es;}
+ if (pcb->action==PIE_) { /* PI entity reference not allowed. */
+ entpisw = 0; /* Reset PI entity indicator. */
+ synerr(59, pcb);
+ goto doparse;
+ }
+ ++parmno; /* Increment parameter counter. */
+ switch (pcb->action) {
+ case CDR: /* COM[1] (MINUS) occurred previously. */
+ REPEATCC;
+ return (int)pcb->action;
+ case LIT: /* Literal: CDATA with LIT delimiter. */
+ parselit(pt, lpcb, tokenlen, lex.d.lit);
+ return (int)pcb->action;
+ case LITE: /* Literal: CDATA with LITA delimiter. */
+ parselit(pt, lpcb, tokenlen, lex.d.lita);
+ return((int)(pcb->action = LIT));
+ case RNS: /* Reserved name started (after RNI). */
+ parsenm(pt, NAMECASE);
+ return (int)pcb->action;
+ case NAS: /* Name started. */
+ if (namecase!=AVALCASE) {
+ parsenm(pt, namecase);
+ return (int)pcb->action;
+ }
+ /* Treat attribute value as name character string. */
+ case NMT: /* Name token string. */
+ parsetkn(pt, NMC, (int)tokenlen); /* Get undelimited value. */
+ return (int)pcb->action;
+ case NUM: /* Number or number token string. */
+ parsetkn(pt, (UNCH)((int)tokenlen<=NAMELEN ? NU:NMC), (int)tokenlen);
+ if (tokenlen > NAMELEN) pcb->newstate = 0;
+ return (int)pcb->action;
+ case PENR:
+ REPEATCC;
+ return (pcb->action = PEN);
+ case EOD_:
+ exiterr(133, pcb);
+ /* EXIT */
+ default: /* End of declaration. */
+ return (int)pcb->action; /* EMD GRPS MGRP PEN PGRP */
+ }
+}
+/* PARSEMOD: If the declared content was a keyword, the token count is zero
+ and it is only necessary to save the type. Otherwise,
+ collect the outermost token count and model type bytes for a model.
+ The count includes tokens found in nested groups also.
+ After building the model, parse for its occurrence indicator.
+*/
+struct thdr *parsemod(dctype)
+int dctype; /* Content type (0=model). */
+{
+ gbuf[0].ttype = (UNCH)dctype; /* Initialize content flags byte. */
+ if (dctype) {gbuf[0].tu.tnum = 0; return gbuf;} /* Return if not model. */
+
+ gbuf[0].tu.tnum = 0; /* Don't count 1st group or model header. */
+ gbuf[1].ttype = 0; /* Initialize 1st group type ... */
+ gbuf[1].tu.tnum = 0; /* and count. */
+ grplvl = 1; /* Content model is 1st level group. */
+ pcbgrcm.newstate = 0; /* Go parse the model group. */
+ /* Empty group is trapped during syntax parse; other errors return NULL. */
+ if (!parsegcm(&pcbgrcm, &gbuf[1], &gbuf[0])) return (struct thdr *)0;
+ parse(&pcbgrcs); /* Get the model suffix, if there is one. */
+ switch(pcbgrcs.action) {
+ case OPT: /* OPT occurrence indicator for model. */
+ SET(gbuf[1].ttype, TOPT|TXOPT);
+ break;
+ case REP: /* REP occurrence indicator for model. */
+ SET(gbuf[1].ttype, TREP|TXREP);
+ break;
+ case OREP: /* OREP occurrence indicator for model. */
+ SET(gbuf[1].ttype, TOREP|TXOREP);
+ break;
+ case EE_:
+ if (es < mdessv) {
+ synerr(37, &pcbmd);
+ mdessv = es;
+ }
+ default: /* RCR_: Repeat char and return. */
+ break;
+ }
+ if (sw.swambig) ambig(); /* Check content model for ambiguity. */
+ return gbuf;
+}
+/* PARSEGCM: Collect token headers (struct thdr) into a group (array).
+ An etd is defined for each GI (if none exists) and its pointer is
+ stored in the header. The function is called recursively.
+*/
+struct thdr *parsegcm(pcb, pgh, gbuf)
+struct parse *pcb; /* Current parse control block. */
+struct thdr *pgh; /* Current group header in group buffer. */
+struct thdr *gbuf; /* Header for outermost group (model). */
+{
+#define MCON gbuf->ttype /* Model type (content attributes). */
+ struct thdr *pg=pgh; /* Current group token. */
+ struct thdr *pgsv=pgh; /* Saved current token for occ indicator. */
+ int optcnt = 0; /* Count of optional tokens in group. */
+ int essv = es; /* Entity stack level when grp started. */
+
+ while (gbuf->tu.tnum<=GRPGTCNT && pgh->tu.tnum<=GRPCNT && parse(pcb)!=GRPE)
+ switch (pcb->action) {
+
+ case NAS_: /* GI name: get its etd and store it. */
+ ++gbuf->tu.tnum; ++pgh->tu.tnum;
+ (pgsv = ++pg)->ttype = TTETD;
+ pg->tu.thetd = etddef(parsenm(tbuf, NAMECASE));
+ SET(MCON, MGI);
+ continue;
+
+ case RNS_: /* Reserved name started (#PCDATA). */
+ parsenm(tbuf, NAMECASE);
+ if (ustrcmp(tbuf+1, key[KPCDATA])) {
+ mderr(116, ntoa(gbuf->tu.tnum), tbuf+1);
+ return (struct thdr *)0;
+ }
+ /* If #PCDATA is the first non-group token, model is a phrase. */
+ if (!MCON) SET(MCON, MPHRASE);
+ case DTAG: /* Data tag template ignored; treat as #PCDATA. */
+ if (pcb->action==DTAG) SET(pgh->ttype, TTSEQ); /* DTAG is SEQ grp. */
+ ++gbuf->tu.tnum; ++pgh->tu.tnum;
+ (++pg)->ttype = TTCHARS+TOREP;/* #PCDATA is OPT and REP. */
+ pg->tu.thetd = ETDCDATA;
+ ++optcnt; /* Ct opt tokens to see if grp is opt.*/
+ SET(MCON, MCHARS);
+ continue;
+
+ case GRP_: /* Group started. */
+ ++gbuf->tu.tnum; ++pgh->tu.tnum;
+ (pgsv = ++pg)->ttype = 0; /* Type will be set by connector. */
+ pg->tu.tnum = 0; /* Group has number instead of etd. */
+ if (++grplvl>GRPLVL) {
+ mderr(115, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ return (struct thdr *)0;
+ }
+ pg = parsegcm(pcb, pg, gbuf);
+ if (!pg) return (struct thdr *)0;
+ if (GET(pgsv->ttype, TOPT)) ++optcnt; /* Indicate nested opt grp. */
+ --grplvl;
+ continue;
+
+ case OREP: /* OREP occurrence indicator for current token.*/
+ SET(pgsv->ttype, TREP|TXREP);
+ /* Now treat like OPT. */
+ case OPT: /* OPT occurrence indicator for current token. */
+ SET(pgsv->ttype, TXOPT);
+ if (GET(pgsv->ttype, TOPT)) continue; /* Exit if nested opt grp. */
+ SET(pgsv->ttype, TOPT);
+ ++optcnt; /* Count opt tokens to see if grp is optional. */
+ continue;
+ case REP: /* REP occurrence indicator for current token. */
+ SET(pgsv->ttype, TREP|TXREP);
+ continue;
+
+ case OR: /* OR connector found. */
+ if BITOFF(pgh->ttype, TTAND) SET(pgh->ttype, TTOR);
+ else if (GET(pgh->ttype, TTAND)!=TTOR)
+ mderr(55, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ continue;
+ case AND: /* AND connector found. */
+ if BITOFF(pgh->ttype, TTAND) SET(pgh->ttype, TTAND);
+ else if (GET(pgh->ttype, TTAND)!=TTAND)
+ mderr(55, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ continue;
+ case SEQ: /* SEQ connector found. */
+ if BITOFF(pgh->ttype, TTAND) SET(pgh->ttype, TTSEQ);
+ else if (GET(pgh->ttype, TTAND)!=TTSEQ)
+ mderr(55, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ continue;
+
+ case EE_: /* Entity ended (correctly or incorrectly). */
+ if (es<essv) {synerr(37, pcb); essv = es;}
+ continue;
+
+ case PIE_: /* PI entity reference (not permitted). */
+ entpisw = 0; /* Reset PI entity indicator. */
+ synerr(59, pcb);
+ continue;
+
+ default: /* Syntax errors return in disgrace. */
+ synerr(37, pcb);
+ return (struct thdr *)0;
+ }
+ if (pgh->tu.tnum>GRPCNT) {
+ mderr(113, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ return (struct thdr *)0;
+ }
+ if (gbuf->tu.tnum>GRPGTCNT) {
+ mderr(114, ntoa(gbuf->tu.tnum), (UNCH *)0);
+ return (struct thdr *)0;
+ }
+ if (pgh->tu.tnum==1) SET(pgh->ttype, TTSEQ); /* Unit grp is SEQ. */
+ /* An optional token in an OR group makes the group optional. */
+ if (GET(pgh->ttype, TTMASK)==TTOR && optcnt) SET(pgh->ttype, TOPT);
+ /* If all tokens in any group are optional, so is the group. */
+ if (pgh->tu.tnum<=optcnt) SET(pgh->ttype, TOPT);
+
+ if (es!=essv) synerr(37, pcb);
+ return pg; /* Return pointer to GRPS token. */
+}
+/* PARSENM: Parser for SGML names, which can be translated with LEXTRAN.
+ The input is read from the entity stack. CC is 1st char of name.
+ Returns a pointer to the parsed name.
+*/
+UNCH *parsenm(tbuf, nc)
+UNCH *tbuf; /* Buffer for name: >=NAMELEN+2. */
+int nc; /* Namecase translation: 1=yes; 0=no. */
+{
+ UNCH len; /* Length of name (incl EOS & length byte). */
+
+ *(tbuf + (len = 1) ) = nc ? lextran[*FPOS] : *FPOS;
+ while ((NEWCC, (int)lextoke[*FPOS]>=NMC) && (len<NAMELEN)) {
+ TRACETKN(NMC, lextoke);
+ if (lextoke[*(tbuf + ++len) = (nc ? lextran[*FPOS] : *FPOS)]==EOB) {
+ --len;
+ entget();
+ }
+ }
+ REPEATCC; /* Put back the non-token character. */
+ *(tbuf + ++len) = EOS; /* Terminate name with standard EOS. */
+ *tbuf = ++len; /* Store length ahead of name. */
+ return tbuf;
+}
+/* PARSETKN: Parser for start-tag attribute value tokens.
+ First character of token is already in *FPOS.
+ Returns a pointer to the parsed token.
+ Parsed token has EOS but no length byte.
+*/
+#ifdef USE_PROTOTYPES
+UNCH *parsetkn(UNCH *tbuf, UNCH scope, int maxlen)
+#else
+UNCH *parsetkn(tbuf, scope, maxlen)
+UNCH *tbuf; /* Buffer for token: >=maxlen+1. */
+UNCH scope; /* Minimum lexical class allowed. */
+int maxlen; /* Maximum length of a token. */
+#endif
+{
+ int i = 1;
+ tbuf[0] = *FPOS;
+ while (i < maxlen) {
+ NEWCC;
+ if (lextoke[*FPOS] < scope) {
+ REPEATCC;
+ break;
+ }
+ TRACETKN(scope, lextoke);
+ if (*FPOS == EOBCHAR)
+ entget();
+ else
+ tbuf[i++] = *FPOS;
+ }
+ tbuf[i] = EOS;
+ return tbuf;
+}
+/* PARSESEQ: Parser for blank sequences (i.e., space and TAB characters ).
+ First character of sequence is already in *FPOS.
+*/
+VOID parseseq(tbuf, maxlen)
+UNCH *tbuf; /* Buffer for storing found sequence. */
+int maxlen; /* Maximum length of a blank sequence. */
+{
+ tbuf[0] = *FPOS;
+ datalen = 1;
+ for (;;) {
+ NEWCC;
+ if (*FPOS == EOBCHAR) {
+ entget();
+ continue;
+ }
+ if ((lextoke[*FPOS] != SEP && *FPOS != SPCCHAR)
+ || datalen >= maxlen)
+ break;
+ tbuf[datalen++] = *FPOS;
+ TRACETKN(SEP, lextoke);
+ }
+}
+/* S2VALNM: Parser for attribute values that are tokenized like names.
+ The input is read from a string (hence S ("string") 2 ("to") VALNM).
+ It stops at the first bad character.
+ Returns a pointer to the created name.
+*/
+#ifdef USE_PROTOTYPES
+UNCH *s2valnm(UNCH *nm, UNCH *s, UNCH scope, int translate)
+#else
+UNCH *s2valnm(nm, s, scope, translate)
+UNCH *nm; /* Name to be created. */
+UNCH *s; /* Source string to be parsed as name. */
+UNCH scope; /* Minimum lexical class allowed. */
+int translate; /* Namecase translation: 1=yes; 0=no. */
+#endif
+{
+ UNCH len = 0; /* Length of name (incl EOS and length). */
+
+ for (; (int)lextoke[*s] >= scope && len < NAMELEN; s++)
+ nm[++len] = translate ? lextran[*s] : *s;
+ nm[++len] = EOS; /* Terminate name with standard EOS. */
+ *nm = ++len; /* Store length ahead of name. */
+ return nm;
+}
+/* PARSEVAL: Parser for attribute values.
+ The input is read from a string and tokenized in a buffer.
+ The input is terminated by EOS.
+ Each token is preceded by its actual length; there is no EOS.
+ If an error occurs while parsing, or
+ if a token doesn't conform, set the token count to 0 to show that
+ value was not tokenized and return the error code.
+ After successful parse, return buffer length and 0 error code.
+ The number of tokens found is set in external variable tokencnt.
+*/
+int parseval(s, atype, tbuf)
+UNCH *s; /* Source string to be parsed as token list. */
+UNS atype; /* Type of token list expected. */
+UNCH *tbuf; /* Work area for tokenization. */
+{
+ int t;
+ UNCH *pt = tbuf;
+
+ pcbval.newstate = 0; tokencnt = 0;
+ while (1) {
+ for (;;) {
+ pcbval.input = lextoke[*s];
+ pcbval.state = pcbval.newstate;
+ pcbval.newstate = (*(pcbval.ptab + pcbval.state)) [pcbval.input];
+ pcbval.action = (*(pcbval.ptab + pcbval.state+1)) [pcbval.input];
+ TRACEVAL(&pcbval, atype, s, tokencnt);
+ if (pcbval.action != NOPA)
+ break;
+ s++;
+ }
+
+
+ switch (pcbval.action) {
+ case INVA: /* Invalid character; terminate parse. */
+ if (*s == '\0') goto alldone; /* Normal termination. */
+ tokencnt = 0; /* Value was not tokenized. */
+ return(14);
+ case LENA: /* Length limit of token exceeded; end parse. */
+ tokencnt = 0; /* Value was not tokenized. */
+ return(15);
+ default: /* Token begun: NUMA, NASA, or NMTA. */
+ break;
+ }
+
+ ++tokencnt; /* One token per iteration. */
+ switch (atype) {
+ case AENTITY:
+ if (tokencnt>1) {tokencnt = 0; return(16);}
+ case AENTITYS:
+ if (pcbval.action!=NASA) {tokencnt = 0; return(17);}
+ s2valnm(pt, s, NMC, ENTCASE);
+ break;
+
+ case AID:
+ case AIDREF:
+ case ANAME:
+ case ANOTEGRP:
+ if (tokencnt>1) {tokencnt = 0; return(16);}
+ case AIDREFS:
+ case ANAMES:
+ if (pcbval.action!=NASA) {tokencnt = 0; return(17);}
+ s2valnm(pt, s, NMC, NAMECASE);
+ break;
+
+ case ANMTGRP:
+ case ANMTOKE:
+ if (tokencnt>1) {tokencnt = 0; return(16);}
+ case ANMTOKES:
+ /* No test needed because NMTA, NUMA and NASA are all valid. */
+ s2valnm(pt, s, NMC, NAMECASE);
+ break;
+
+ case ANUMBER:
+ if (tokencnt>1) {tokencnt = 0; return(16);}
+ case ANUMBERS:
+ if (pcbval.action!=NUMA) {tokencnt = 0; return(17);}
+ s2valnm(pt, s, NU, NAMECASE);
+ t = lextoke[s[*pt - 2]];
+ if (t == NMS || t == NMC) {tokencnt = 0; return(17);}
+ break;
+
+ case ANUTOKE:
+ if (tokencnt>1) {tokencnt = 0; return(16);}
+ case ANUTOKES:
+ if (pcbval.action!=NUMA) {tokencnt = 0; return(17);}
+ s2valnm(pt, s, NMC, NAMECASE);
+ break;
+ }
+ *pt -= 2;
+ s += *pt;
+ pt += *pt + 1;
+ }
+ alldone:
+ *pt++ = EOS;
+ if (*tbuf == '\0')
+ return 25;
+ if (atype < ATKNLIST)
+ *tbuf += 2; /* include length and EOS */
+ return 0;
+}
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/pcbrf.c b/usr.bin/sgmls/sgmls/pcbrf.c
new file mode 100644
index 0000000..554fdfb
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/pcbrf.c
@@ -0,0 +1,1351 @@
+/* PCBRF: Parse tables for reference concrete syntax.
+*/
+#include "config.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "action.h" /* Action names for all parsing. */
+#include "synxtrn.h" /* Declarations for concrete syntax constants. */
+#include "adl.h" /* Definitions for attribute list processing. */
+/* PCBCONM: State and action table for content parse of mixed content.
+ Initial state assumes a start-tag was just processed.
+*/
+/* Symbols for state names (end with a number). */
+#define ET0 0 /* Markup found or buffer flushed; no data. */
+#define DA0 2 /* Data in buffer. */
+#define DA1 4 /* Data and space in buffer. */
+#define ER0 6 /* ERO found; start lookahead buffer. */
+#define CR0 8 /* CRO found (ERO, RNI). */
+#define RS0 10 /* RS found; possible SR 3-6. */
+#define ME0 12 /* MSC found; possible SR26. */
+#define ME1 14 /* MSC, MSC found. */
+#define ES0 16 /* TAGO found; start lookahead buffer. */
+#define EE0 18 /* End-tag start (TAGO,ETI); move to lookahead buffer. */
+#define NE0 20 /* End-tag start (TAGO,NET); process NET if not end-tag. */
+#define MD0 22 /* MDO found (TAGO, MDO[2]). */
+#define MC0 24 /* MDO, COM found. */
+#define SC0 26 /* COM found; possible SR19-20. */
+#define SP0 28 /* Space found; data pending; possible SR7 or SR9. */
+#define SR0 30 /* SPCR found; possible SR7 or SR9. */
+#define TB0 32 /* TAB found; possible SR7 or SR9. */
+
+int pcbcnet = ET0; /* PCBCONM: markup found or data buffer flushed.*/
+int pcbcnda = DA0; /* PCBCONM: data in buffer. */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+et0 []={DA0 ,DA0 ,DA0 ,DA0 ,SP0 ,ET0 ,ET0 ,ET0 ,RS0 ,ET0 ,TB0 ,DA0 ,ET0 ,ER0 ,
+ ET0 ,SC0 ,DA0 ,ET0 ,ET0 ,SR0 ,DA0 ,ME0 ,ET0 ,DA0 ,ET0 ,DA0 ,ES0 ,ET0 },/*et0*/
+et0a[]={DAS_,DAS_,DAS_,DAS_,DAS_,NON_,GET_,GET_,RSR_,SR2_,DAS_,DAS_,NSC_,LAS_,
+ REF_,NOP_,DAS_,NED_,SR10,DAS_,DAS_,NOP_,SR25,DAS_,SR11,DAS_,LAS_,FCE_},
+
+da0 []={DA0 ,DA0 ,DA0 ,DA0 ,DA1 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,DA0 ,ET0 ,DA0 ,ET0 ,ET0 },/*da0*/
+da0a[]={NOP_,NOP_,NOP_,NOP_,NOP_,DAF_,DAF_,DAF_,DAF_,DAF_,DAF_,NOP_,DAF_,DAF_,
+ DAF_,DAF_,NOP_,DAF_,DAF_,DAF_,NOP_,DAF_,DAF_,NOP_,DAF_,NOP_,DAF_,DAF_},
+
+da1 []={DA0 ,DA0 ,DA0 ,DA0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,DA0 ,ET0 ,DA0 ,ET0 ,ET0 },/*da1*/
+da1a[]={NOP_,NOP_,NOP_,NOP_,DAR_,DAF_,DAF_,DAR_,DAF_,DAR_,DAR_,NOP_,DAF_,DAF_,
+ DAF_,DAF_,NOP_,DAF_,DAF_,DAR_,NOP_,DAF_,DAF_,NOP_,DAF_,NOP_,DAF_,DAF_},
+
+er0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ER0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,CR0 ,ET0 ,ET0 ,ET0 },/*er0*/
+er0a[]={LAF_,LAF_,LAF_,ER_ ,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAM_,LAF_,LAF_,LAF_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+cr0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,CR0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*cr0*/
+cr0a[]={NLF_,CRN_,NLF_,CRA_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_},
+
+rs0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,RS0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*rs0*/
+rs0a[]={SR3_,SR3_,SR3_,SR3_,SR4_,SR3_,SR3_,GET_,SR3_,SR5_,SR4_,SR3_,SR3_,SR3_,
+ SR3_,SR3_,SR3_,NED_,SR3_,SR4_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_},
+
+me0 []={ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ME0, ET0 ,ET0 ,ET0 ,ET0, ET0, ET0,
+ ET0 ,ET0 ,ET0 ,ET0, ET0, ET0, ET0, ME1 ,ET0, ET0, ET0 ,ET0, ET0, ET0 },/*me0*/
+me0a[]={SR26,SR26,SR26,SR26,SR26,SR26,SR26,GET_,SR26,SR26,SR26,SR26,SR26,SR26,
+ SR26,SR26,SR26,SR26,SR26,SR26,SR26,NOP_,SR26,SR26,SR26,SR26,SR26,SR26},
+
+me1 []={ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ME1, ET0 ,ET0 ,ET0 ,ET0, ET0, ET0,
+ ET0 ,ET0 ,ET0 ,ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ET0 ,ET0, ET0, ET0 },/*me1*/
+me1a[]={RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,GET_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,
+ RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,MSE_,RBR_,RBR_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+es0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ES0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,EE0 ,NE0 ,ET0 ,ET0 ,MD0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*es0*/
+es0a[]={LAF_,LAF_,LAF_,STG_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAM_,LAM_,LAF_,LAF_,LAM_,LAF_,LAF_,PIS_,LAF_,NST_,LAF_,LAF_},
+
+ee0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,EE0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*ee0*/
+ee0a[]={LAF_,LAF_,LAF_,ETG_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,NET_,LAF_,LAF_},
+
+ne0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,NE0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*ne0*/
+ne0a[]={NLF_,NLF_,NLF_,ETG_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NET_,NLF_,NLF_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+md0 []={ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, MD0, ET0 ,ET0 ,ET0 ,ET0, ET0, ET0,
+ ET0 ,MC0 ,ET0 ,ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ET0 ,ET0, ET0, ET0 },/*md0*/
+md0a[]={LAF_,LAF_,LAF_,MD_ ,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,MSS_,LAF_,LAF_,MDC_,LAF_,LAF_},
+
+mc0 []={ET0, ET0, ET0, ET0, ET0, ET0 ,ET0, MC0, ET0 ,ET0, ET0 ,ET0, ET0, ET0,
+ ET0 ,ET0 ,ET0 ,ET0, ET0, ET0, ET0, ET0 ,ET0 ,ET0 ,ET0 ,ET0, ET0, ET0 },/*mc0*/
+mc0a[]={NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,MDC_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_},
+
+sc0 []={ET0, ET0, ET0, ET0, ET0, ET0 ,ET0, SC0, ET0 ,ET0, ET0 ,ET0, ET0, ET0,
+ ET0 ,ET0 ,ET0 ,ET0, ET0, ET0, ET0, ET0 ,ET0 ,ET0 ,ET0 ,ET0, ET0, ET0 },/*sc0*/
+sc0a[]={SR19,SR19,SR19,SR19,SR19,SR19,SR19,GET_,SR19,SR19,SR19,SR19,SR19,SR19,
+ SR19,SR20,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+sp0 []={DA0 ,DA0 ,DA0 ,DA0 ,ET0 ,ET0 ,ET0 ,SP0 ,ET0 ,ET0 ,ET0 ,DA0 ,DA0 ,ET0 ,
+ ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,ET0 ,DA0 ,ET0 ,ET0 ,DA0 ,DA0 ,DA0 ,ET0 ,ET0 },/*sp0*/
+sp0a[]={NOP_,NOP_,NOP_,NOP_,SR9_,DAF_,DAF_,GTR_,DAF_,SR7_,SR9_,NOP_,NOP_,DAF_,
+ DAF_,DAF_,NOP_,DAF_,DAF_,SR9_,NOP_,DAF_,DAF_,NOP_,NOP_,NOP_,DAF_,DAF_},
+
+sr0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,SR0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*sr0*/
+sr0a[]={SR8_,SR8_,SR8_,SR8_,SR9_,SR8_,SR8_,GET_,SR8_,SR7_,SR9_,SR8_,SR8_,SR8_,
+ SR8_,SR8_,SR8_,SR8_,SR8_,SR9_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_},
+
+tb0 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,TB0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*tb0*/
+tb0a[]={SR1_,SR1_,SR1_,SR1_,SR9_,SR1_,SR1_,GET_,SR1_,SR7_,SR9_,SR1_,SR1_,SR1_,
+ SR1_,SR1_,SR1_,SR1_,SR1_,SR9_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+
+*conmtab[] = {et0, et0a, da0, da0a, da1, da1a, er0, er0a, cr0, cr0a, rs0, rs0a,
+ me0, me0a, me1, me1a, es0, es0a, ee0, ee0a, ne0, ne0a, md0, md0a,
+ mc0, mc0a, sc0, sc0a, sp0, sp0a, sr0, sr0a, tb0, tb0a };
+struct parse pcbconm = {"CONM", lexcnm, conmtab, 0, 0, 0, 0};
+#undef ET0
+#undef DA0
+#undef DA1
+#undef ER0
+#undef CR0
+#undef RS0
+#undef ME0
+#undef ME1
+#undef ES0
+#undef EE0
+#undef NE0
+#undef MD0
+#undef MC0
+#undef SC0
+#undef SP0
+#undef SR0
+#undef TB0
+/* PCBCONE: State and action table for content parse of element content.
+ Initial state assumes a start-tag was just processed.
+*/
+/* Symbols for state names (end with a number). */
+#define ET2 0 /* Markup found. */
+#define ER2 2 /* ERO found; start lookahead buffer. */
+#define CR2 4 /* CRO found (ERO, RNI). */
+#define RS2 6 /* RS found; possible SR 3-6 if they were declared. */
+#define ME2 8 /* MSC found. */
+#define ME3 10 /* MSC, MSC found. */
+#define ES2 12 /* TAGO found; start lookahead buffer. */
+#define EE2 14 /* End-tag start (TAGO,ETI); move to lookahead buffer. */
+#define NE2 16 /* End-tag start (TAGO,NET); process NET if not end-tag. */
+#define MD2 18 /* MDO found (TAGO, MDO[2]). */
+#define MC2 20 /* MDO, COM found. */
+#define SC2 22 /* COM found; possible SR19-20 if they were mapped. */
+#define SP2 24 /* Space found; possible SR7 or SR9. */
+#define SR2 26 /* SPCR found; possible SR7 or SR9. */
+#define TB2 28 /* TAB found; possible SR7 or SR9. */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+et2 []={ET2 ,ET2 ,ET2 ,ET2 ,SP2 ,ET2 ,ET2 ,ET2 ,RS2 ,ET2 ,TB2 ,ET2 ,ET2 ,ER2 ,
+ ET2 ,SC2 ,ET2 ,ET2 ,ET2 ,SR2 ,ET2 ,ME2 ,ET2 ,ET2 ,ET2 ,ET2 ,ES2 ,ET2 },/*et2*/
+et2a[]={DCE_,DCE_,DCE_,DCE_,NOP_,DCE_,GET_,GET_,RS_ ,SR2_,NOP_,DCE_,DCE_,LAS_,
+ NOP_,NOP_,DCE_,NED_,SR10,NOP_,DCE_,NOP_,SR25,DCE_,SR11,DCE_,LAS_,FCE_},
+
+er2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ER2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,CR2 ,ET2 ,ET2 ,ET2 },/*er2*/
+er2a[]={LAF_,LAF_,LAF_,ER_ ,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAM_,LAF_,LAF_,LAF_},
+
+cr2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,CR2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*cr2*/
+cr2a[]={NLF_,CRN_,NLF_,CRA_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_},
+
+rs2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,RS2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*rs2*/
+rs2a[]={SR3_,SR3_,SR3_,SR3_,SR4_,SR3_,SR3_,GET_,SR3_,SR5_,SR4_,SR3_,SR3_,SR3_,
+ SR3_,SR3_,SR3_,NED_,SR3_,SR4_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_,SR3_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spcr mdo msc mso pio rni tagc tago fce */
+me2 []={ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ME2, ET2 ,ET2 ,ET2 ,ET2, ET2, ET2,
+ ET2 ,ET2, ET2 ,ET2, ET2, ET2, ET2, ME3 ,ET2, ET2, ET2 ,ET2, ET2, ET2 },/*me2*/
+me2a[]={SR26,SR26,SR26,SR26,SR26,SR26,SR26,GET_,SR26,SR26,SR26,SR26,SR26,SR26,
+ SR26,SR26,SR26,SR26,SR26,SR26,SR26,NOP_,SR26,SR26,SR26,SR26,SR26,SR26},
+
+me3 []={ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ME3, ET2 ,ET2 ,ET2 ,ET2, ET2, ET2,
+ ET2 ,ET2, ET2 ,ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ET2 ,ET2, ET2, ET2 },/*me3*/
+me3a[]={RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,GET_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,
+ RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,RBR_,MSE_,RBR_,RBR_},
+
+es2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ES2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,EE2 ,NE2 ,ET2 ,ET2 ,MD2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*es2*/
+es2a[]={LAF_,LAF_,LAF_,STG_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAM_,LAM_,LAF_,LAF_,LAM_,LAF_,LAF_,PIS_,LAF_,NST_,LAF_,LAF_},
+
+ee2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,EE2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*ee2*/
+ee2a[]={LAF_,LAF_,LAF_,ETG_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,NET_,LAF_,LAF_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spc mdo msc mso pio rni tagc tago fce */
+ne2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,NE2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*ne2*/
+ne2a[]={NLF_,NLF_,NLF_,ETG_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NET_,NLF_,NLF_},
+
+md2 []={ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, MD2, ET2 ,ET2 ,ET2 ,ET2, ET2, ET2,
+ ET2 ,MC2, ET2 ,ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ET2 ,ET2, ET2, ET2 },/*md2*/
+md2a[]={LAF_,LAF_,LAF_,MD_ ,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,MSS_,LAF_,LAF_,MDC_,LAF_,LAF_},
+
+mc2 []={ET2, ET2, ET2, ET2, ET2, ET2 ,ET2, MC2, ET2 ,ET2, ET2 ,ET2, ET2, ET2,
+ ET2 ,ET2, ET2 ,ET2, ET2, ET2, ET2, ET2 ,ET2 ,ET2 ,ET2 ,ET2, ET2, ET2 },/*mc2*/
+mc2a[]={NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,GET_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,
+ NLF_,MDC_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_,NLF_},
+
+sc2 []={ET2, ET2, ET2, ET2, ET2, ET2 ,ET2, SC2, ET2 ,ET2, ET2 ,ET2, ET2, ET2,
+ ET2 ,ET2 ,ET2 ,ET2, ET2, ET2, ET2, ET2 ,ET2 ,ET2 ,ET2 ,ET2, ET2, ET2 },/*sc2*/
+sc2a[]={SR19,SR19,SR19,SR19,SR19,SR19,SR19,GET_,SR19,SR19,SR19,SR19,SR19,SR19,
+ SR19,SR20,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19,SR19},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net lit spc mdo msc mso pio rni tagc tago fce */
+sp2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,SP2 ,RS2 ,ET2 ,ET2 ,ET2 ,ET2 ,ER2 ,
+ ET2 ,SC2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ME2 ,ET2 ,ET2 ,ET2 ,ET2 ,ES2 ,ET2 },/*sp2*/
+sp2a[]={DCE_,DCE_,DCE_,DCE_,SR9_,DCE_,GET_,GET_,RS_ ,SR7_,SR9_,DCE_,DCE_,LAS_,
+ NOP_,NOP_,DCE_,NED_,SR10,SR9_,DCE_,LAS_,DCE_,DCE_,SR11,DCE_,LAS_,DCE_},
+
+sr2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,SR2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*sr2*/
+sr2a[]={SR8_,SR8_,SR8_,SR8_,SR9_,SR8_,SR8_,GET_,SR8_,SR7_,SR9_,SR8_,SR8_,SR8_,
+ SR8_,SR8_,SR8_,SR8_,SR8_,SR9_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_,SR8_},
+
+tb2 []={ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,TB2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,
+ ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 },/*tb2*/
+tb2a[]={SR1_,SR1_,SR1_,SR1_,SR9_,SR1_,SR1_,GET_,SR1_,SR7_,SR9_,SR1_,SR1_,SR1_,
+ SR1_,SR1_,SR1_,SR1_,SR1_,SR9_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_,SR1_},
+
+*conetab[] = {et2, et2a, er2, er2a, cr2, cr2a, rs2, rs2a, me2, me2a, me3, me3a,
+ es2, es2a, ee2, ee2a, ne2, ne2a, md2, md2a, mc2, mc2a, sc2, sc2a,
+ sp2, sp2a, sr2, sr2a, tb2, tb2a };
+struct parse pcbcone = {"CONE", lexcnm, conetab, 0, 0, 0, 0};
+#undef ET2
+#undef ER2
+#undef CR2
+#undef RS2
+#undef ME2
+#undef ME3
+#undef ES2
+#undef EE2
+#undef NE2
+#undef MD2
+#undef MC2
+#undef SC2
+#undef SP2
+#undef SR2
+#undef TB2
+/* PCBCONR: State and action table for content parse of replaceable character
+ data. Initial state assumes a start-tag was just processed.
+ Only entity references and character references are recognized.
+*/
+/* Symbols for state names (end with a number). */
+#define ET4 0 /* Markup found or buffer flushed; no data. */
+#define DA4 2 /* Data in buffer. */
+#define ER4 4 /* ERO found; start lookahead buffer. */
+#define CR4 6 /* CRO found (ER2, RNI). */
+#define ES4 8 /* TAGO found; start lookahead buffer. */
+#define EE4 10 /* End-tag start (TAGO,ETI); move to lookahead buffer. */
+#define NE4 12 /* End-tag start (TAGO,NET); process NET if not end-tag. */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+et4 []={DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,DA4 ,DA4 ,ET4 ,ER4 ,
+ ET4 ,DA4 ,DA4 ,ET4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,ES4 },/*et4*/
+et4a[]={DAS_,DAS_,DAS_,DAS_,DAS_,NON_,EE_ ,GET_,RS_ ,REF_,DAS_,DAS_,NSC_,LAS_,
+ REF_,DAS_,DAS_,NED_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_,LAS_},
+
+da4 []={DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,DA4 ,DA4 ,ET4 ,ET4 ,
+ ET4 ,DA4 ,DA4 ,ET4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,DA4 ,ET4 },/*da4*/
+da4a[]={NOP_,NOP_,NOP_,NOP_,NOP_,DAF_,DAF_,DAF_,DAF_,DAF_,NOP_,NOP_,DAF_,DAF_,
+ DAF_,NOP_,NOP_,DAF_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,DAF_},
+
+er4 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ER4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,
+ ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,CR4 ,ET4 ,ET4 },/*er4*/
+er4a[]={LAF_,LAF_,LAF_,ERX_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAM_,LAF_,LAF_},
+
+cr4 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,CR4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,
+ ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 },/*cr4*/
+cr4a[]={LAF_,CRN_,LAF_,CRA_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+es4 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ES4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,
+ ET4 ,ET4 ,EE4 ,NE4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 },/*es4*/
+es4a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAM_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+ee4 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,EE4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,
+ ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 },/*ee4*/
+ee4a[]={LAF_,LAF_,LAF_,ETC_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,NET_,LAF_},
+
+ne4 []={EE4 ,EE4 ,EE4 ,ET4 ,EE4 ,EE4 ,EE4 ,NE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,
+ EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,EE4 ,ET4 ,EE4 },/*ne4*/
+ne4a[]={RC2_,RC2_,RC2_,ETC_,RC2_,RC2_,RC2_,GET_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,
+ RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,NET_,RC2_},
+
+*conrtab[] = {et4, et4a, da4, da4a, er4, er4a, cr4, cr4a,
+ es4, es4a, ee4, ee4a, ne4, ne4a};
+struct parse pcbconr = {"CONR", lexcon, conrtab, 0, 0, 0, 0};
+#undef ET4
+#undef DA4
+#undef ER4
+#undef CR4
+#undef ES4
+#undef EE4
+#undef NE4
+/* PCBCONC: State and action table for content parse of character data.
+ Initial state assumes a start-tag was just processed.
+*/
+/* Symbols for state names (end with a number). */
+#define ET6 0 /* Markup found or buffer flushed; no data. */
+#define DA6 2 /* Data in buffer. */
+#define ES6 4 /* TAGO found; start lookahead buffer. */
+#define EE6 6 /* End-tag start (TAGO,ETI); move to lookahead buffer. */
+#define NE6 8 /* End-tag start (TAGO,NET); process NET if not end-tag. */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+et6 []={DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,DA6 ,DA6 ,ET6 ,DA6 ,
+ ET6 ,DA6 ,DA6 ,ET6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,ES6 },/*et6*/
+et6a[]={DAS_,DAS_,DAS_,DAS_,DAS_,NON_,EOF_,GET_,RS_ ,REF_,DAS_,DAS_,NSC_,DAS_,
+ REF_,DAS_,DAS_,NED_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_,LAS_},
+
+da6 []={DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,DA6 ,DA6 ,ET6 ,ET6 ,
+ ET6 ,DA6 ,DA6 ,ET6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,DA6 ,ET6 },/*da6*/
+da6a[]={NOP_,NOP_,NOP_,NOP_,NOP_,DAF_,DAF_,DAF_,DAF_,DAF_,NOP_,NOP_,DAF_,DAF_,
+ DAF_,NOP_,NOP_,DAF_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,DAF_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+es6 []={ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ES6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,
+ ET6 ,ET6 ,EE6 ,NE6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 },/*es6*/
+es6a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAM_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+ee6 []={ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,EE6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,
+ ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 ,ET6 },/*ee6*/
+ee6a[]={LAF_,LAF_,LAF_,ETC_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,NET_,LAF_},
+
+ne6 []={EE6 ,EE6 ,EE6 ,ET6 ,EE6 ,EE6 ,EE6 ,NE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,
+ EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,EE6 ,ET6 ,EE6 },/*ne6*/
+ne6a[]={RC2_,RC2_,RC2_,ETC_,RC2_,RC2_,RC2_,GET_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,
+ RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,RC2_,NET_,RC2_},
+
+*conctab[] = {et6, et6a, da6, da6a, es6, es6a, ee6, ee6a, ne6, ne6a};
+struct parse pcbconc = {"CONC", lexcon, conctab, 0, 0, 0, 0};
+#undef ET6
+#undef DA6
+#undef ES6
+#undef EE6
+#undef NE6
+/* PCBPRO: State and action table for prolog parse.
+ Initial state assumes document just began.
+*/
+/* Symbols for state names (end with a number). */
+#define ET7 0 /* Markup found. */
+#define ES7 2 /* TAGO found; start lookahead buffer. */
+#define MD7 4 /* MDO found (TAGO, MDO[2]). */
+#define MC7 6 /* MDO, COM found. */
+#define EE7 8 /* TAGO, ETI found */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+et7 []={ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,
+ ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ES7 },/*et7*/
+et7a[]={DCE_,DCE_,DCE_,DCE_,NOP_,DCE_,EE_ ,GET_,RS_ ,NOP_,NOP_,DCE_,DCE_,DCE_,
+ DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,DCE_,LAS_},
+
+es7 []={ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ES7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,
+ ET7 ,ET7 ,EE7 ,ET7 ,MD7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 },/*es7*/
+es7a[]={PEP_,PEP_,PEP_,STE_,PEP_,PEP_,PEP_,GET_,PEP_,PEP_,PEP_,PEP_,PEP_,PEP_,
+ PEP_,PEP_,LAM_,PEP_,LAM_,PEP_,PEP_,PEP_,PIS_,PEP_,STE_,PEP_},
+
+md7 []={ET7, ET7, ET7, ET7, ET7 ,ET7, ET7, MD7, ET7 ,ET7 ,ET7 ,ET7, ET7, ET7,
+ ET7, MC7, ET7, ET7, ET7, ET7 ,ET7, ET7, ET7, ET7 ,ET7, ET7 },/*md7*/
+md7a[]={LAF_,LAF_,LAF_,DTD_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAM_,LAF_,LAF_,LAF_,LAF_,MSP_,LAF_,LAF_,LAF_,NOP_,LAF_},
+
+mc7 []={ET7, ET7, ET7, ET7, ET7, ET7 ,ET7, MC7, ET7 ,ET7, ET7 ,ET7, ET7, ET7,
+ ET7, ET7, ET7, ET7, ET7, ET7 ,ET7 ,ET7, ET7 ,ET7 ,ET7, ET7 },/*mc7*/
+mc7a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,MDC_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+ee7 []={ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,EE7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,
+ ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 ,ET7 },/*ee7*/
+ee7a[]={LAF_,LAF_,LAF_,ETE_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,ETE_,LAF_},
+
+*protab[] = {et7, et7a, es7, es7a, md7, md7a, mc7, mc7a, ee7, ee7a};
+struct parse pcbpro = {"PRO", lexcon, protab, 0, 0, 0, 0};
+#undef ET7
+#undef ES7
+#undef MD7
+#undef MC7
+#undef EE7
+/* PCBMDS: State and action table for parse of markup declaration subset.
+ Initial state assumes subset just began (MSO found).
+*/
+/* Symbols for state names (end with a number). */
+#define ET8 0 /* Markup found. */
+#define ER8 2 /* PERO found; start lookahead buffer. */
+#define ME8 4 /* MSC found. */
+#define ME9 6 /* MSC, MSC found. */
+#define ES8 8 /* TAGO found; start lookahead buffer. */
+#define MD8 10 /* MDO found (TAGO, MDO[2]). */
+#define MC8 12 /* MDO, CD found. */
+#define DC8 14 /* Data characters found (erroneously). */
+
+static UNCH
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+et8 []={DC8 ,DC8 ,DC8 ,DC8 ,ET8 ,DC8 ,ET8 ,ET8 ,ET8 ,ET8 ,ET8 ,DC8 ,DC8 ,DC8 ,
+ DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,ME8 ,DC8 ,ER8 ,DC8 ,DC8 ,DC8 ,ES8 },/*et8*/
+et8a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,GET_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+er8 []={DC8 ,DC8 ,DC8 ,ET8 ,DC8 ,DC8 ,DC8 ,ER8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,
+ DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 },/*er8*/
+er8a[]={NOP_,NOP_,NOP_,PER_,NOP_,SYS_,NOP_,GET_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+me8 []={ET8, ET8, ET8, ET8, ET8 ,ET8, ET8, ME8, ET8 ,ET8 ,ET8 ,ET8, ET8, ET8,
+ ET8 ,ET8, ET8 ,ET8, ET8, ME9 ,ET8, ET8, ET8, ET8 ,ET8, ET8 },/*me8*/
+me8a[]={DTE_,DTE_,DTE_,DTE_,DTE_,DTE_,DTE_,GET_,DTE_,DTE_,DTE_,DTE_,DTE_,DTE_,
+ DTE_,DTE_,DTE_,DTE_,DTE_,NOP_,DTE_,DTE_,DTE_,DTE_,DTE_,DTE_},
+
+me9 []={DC8, DC8, DC8, DC8, DC8 ,DC8, DC8, ME9, DC8 ,DC8 ,DC8 ,DC8, DC8, DC8,
+ DC8 ,DC8, DC8 ,DC8, DC8, DC8 ,DC8, DC8, DC8, DC8 ,ET8, DC8 },/*me9*/
+me9a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,GET_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,MSE_,NOP_},
+
+/* free nu nmc nms spc non ee eob rs re sep cde nsc ero
+ nmre com eti net mdo msc mso pero pio rni tagc tago */
+es8 []={DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,ES8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,
+ DC8 ,DC8 ,DC8 ,DC8 ,MD8 ,DC8 ,DC8 ,DC8 ,ET8 ,DC8 ,DC8 ,DC8 },/*es8*/
+es8a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,GET_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,PIS_,NOP_,NOP_,NOP_},
+
+md8 []={DC8, DC8, DC8, ET8, DC8 ,DC8, DC8, MD8, DC8 ,DC8 ,DC8 ,DC8, DC8, DC8,
+ DC8 ,MC8, DC8 ,DC8, DC8, DC8 ,ET8, DC8, DC8, DC8 ,ET8, DC8 },/*md8*/
+md8a[]={NOP_,NOP_,NOP_,MD_ ,NOP_,SYS_,NOP_,GET_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,MSS_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+mc8 []={DC8, DC8, DC8, DC8, DC8, DC8 ,DC8, MC8, DC8 ,DC8, DC8 ,DC8, DC8, DC8,
+ DC8 ,ET8, DC8 ,DC8, DC8, DC8 ,DC8 ,DC8, DC8 ,DC8 ,DC8, DC8 },/*mc8*/
+mc8a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,GET_,NOP_,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,MDC_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+dc8 []={DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,
+ DC8 ,DC8 ,DC8 ,DC8 ,DC8 ,ET8 ,DC8 ,ET8 ,DC8 ,DC8 ,DC8 ,ET8 },/*dc8*/
+dc8a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,GET_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,CIR_,NOP_,CIR_,NOP_,NOP_,NOP_,CIR_},
+
+*mdstab[] = {et8, et8a, er8, er8a, me8, me8a, me9, me9a,
+ es8, es8a, md8, md8a, mc8, mc8a, dc8, dc8a};
+struct parse pcbmds = {"MDS", lexcon, mdstab, 0, 0, 0, 0};
+#undef ET8
+#undef ER8
+#undef ME8
+#undef ME9
+#undef ES8
+#undef MD8
+#undef MC8
+#undef DC8
+/* PCBGRCM: State and action table for content model group.
+ Groups can nest. Reserved names are allowed.
+ Data tag token groups are allowed.
+ A non-reserved name or model group can have a suffix.
+ Columns are based on LEXGRP.C.
+*/
+/* Symbols for state names (end with a number). */
+#define TK1 0 /* Token expected: name, #CHARS, data tag grp, model. */
+#define CO1 2 /* Connector between tokens expected. */
+#define ER1 4 /* PERO found when token was expected. */
+#define SP1 6 /* Name or model: suffix or connector expected. */
+#define RN1 8 /* RNI found; possible #PCDATA. */
+#define DG1 10 /* Data tag: group begun; name expected. */
+#define DN1 12 /* Data tag: name found; SEQ connector expected. */
+#define DT1 14 /* Data tag: ignore template and pattern; MSC expected. */
+#define DR1 16 /* PERO found when data tag name was expected. */
+#define LI1 18 /* Literal in data tag group; search for LIT. */
+#define LA1 20 /* Literal in data tag group; search for LITA. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+tk01 []={TK1 ,TK1 ,SP1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,DG1 ,TK1 ,TK1 ,ER1 ,TK1 ,TK1 ,RN1 ,TK1 ,TK1 },/*tk1*/
+tk01a[]={INV_,INV_,NAS_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,INV_,INV_,GRP_,INV_,INV_,
+ INV_,GRP_,INV_,INV_,NOP_,INV_,INV_,NOP_,INV_,INV_},
+
+co01 []={TK1 ,TK1 ,TK1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,TK1 ,SP1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*co1*/
+co01a[]={INV_,INV_,INV_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,AND ,GRPE,INV_,INV_,INV_,
+ INV_,INV_,INV_,OR ,INV_,INV_,INV_,INV_,SEQ ,INV_},
+
+er01 []={TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,ER1 ,TK1 ,ER1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*er1*/
+er01a[]={PCI_,PCI_,PER_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+sp01 []={TK1 ,TK1 ,TK1 ,CO1 ,CO1 ,SP1 ,CO1 ,SP1 ,CO1 ,TK1 ,SP1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,CO1 ,TK1 ,TK1 ,CO1 ,CO1 ,TK1 ,TK1 ,TK1 },/*sp1*/
+sp01a[]={INV_,LEN_,LEN_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,AND ,GRPE,INV_,INV_,INV_,
+ INV_,INV_,OPT ,OR ,INV_,REP ,OREP,INV_,SEQ ,LEN_},
+
+/* bit nmc nms spc spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+rn01 []={TK1 ,TK1 ,CO1 ,TK1 ,TK1 ,RN1 ,TK1 ,RN1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*rn1*/
+rn01a[]={PCI_,PCI_,RNS_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+dg01 []={TK1 ,TK1 ,DN1 ,DG1 ,DG1 ,DG1 ,DG1 ,DG1 ,DG1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,DR1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*dg1*/
+dg01a[]={INV_,INV_,NAS_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,INV_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,NOP_,INV_,INV_,INV_,INV_,INV_},
+
+dn01 []={TK1 ,TK1 ,TK1 ,DN1 ,DN1 ,DN1 ,DN1 ,DN1 ,DN1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,DT1 ,TK1 },/*dn1*/
+dn01a[]={INV_,INV_,INV_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,INV_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,INV_,INV_,INV_,INV_,DTAG,INV_},
+
+dt01 []={TK1 ,TK1 ,TK1 ,DT1 ,DT1 ,DT1 ,DT1 ,DT1 ,DT1 ,TK1 ,DT1 ,DT1 ,LI1 ,LA1 ,
+ SP1 ,TK1 ,TK1 ,DT1 ,DT1 ,TK1 ,TK1 ,TK1 ,DT1 ,TK1 },/*dt1*/
+dt01a[]={INV_,INV_,INV_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,INV_,NOP_,NOP_,NOP_,NOP_,
+ GRPE,INV_,INV_,NOP_,NOP_,INV_,INV_,INV_,NOP_,INV_},
+
+/* bit nmc nms spc spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+dr01 []={TK1 ,TK1 ,DG1 ,TK1 ,TK1 ,DR1 ,TK1 ,DR1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*dr1*/
+dr01a[]={PCI_,PCI_,PER_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+li01 []={LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,DT1 ,LI1 ,
+ LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 },/*li1*/
+li01a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+la01 []={LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,DT1 ,
+ LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 },/*la1*/
+la01a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+*grcmtab[] = {tk01, tk01a, co01, co01a, er01, er01a, sp01, sp01a,
+ rn01, rn01a, dg01, dg01a, dn01, dn01a, dt01, dt01a,
+ dr01, dr01a, li01, li01a, la01, la01a};
+struct parse pcbgrcm = {"GRCM", lexgrp, grcmtab, 0, 0, 0, 0};
+#undef TK1
+#undef CO1
+#undef ER1
+#undef SP1
+#undef RN1
+#undef DG1
+#undef DN1
+#undef DT1
+#undef DR1
+#undef LI1
+#undef LA1
+/* PCBGRCS: State and action table for content model suffix.
+ If suffix occurs, process it. Otherwise, put character
+ back for the next parse.
+*/
+/* Symbols for state names (end with a number). */
+#define SP4 0 /* Suffix expected. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+sp04 []={SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,
+ SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 ,SP4 },/*sp4*/
+sp04a[]={RCR_,RCR_,RCR_,RCR_,RCR_,SYS_,EE_ ,GET_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,
+ RCR_,RCR_,OPT ,RCR_,RCR_,REP ,OREP,RCR_,RCR_,RCR_},
+
+*grcstab[] = {sp04, sp04a};
+struct parse pcbgrcs = {"GRCS", lexgrp, grcstab, 0, 0, 0, 0};
+#undef SP4
+/* PCBGRNT: State and action table for name token group parse.
+ Groups cannot nest. Reserved names are not allowed.
+ No suffixes or data tag pattern groups.
+*/
+/* Symbols for state names (end with a number). */
+#define TK1 0 /* Token expected: name, #CHARS, data tag grp, model. */
+#define CO1 2 /* Connector between tokens expected. */
+#define ER1 4 /* PERO found when token was expected. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+tk02 []={TK1 ,CO1 ,CO1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,ER1 ,TK1 ,TK1 ,TK1 ,TK1 ,CO1 },/*tk1*/
+tk02a[]={INV_,NMT_,NMT_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,INV_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,NOP_,INV_,INV_,INV_,INV_,NMT_},
+
+co02 []={TK1 ,TK1 ,TK1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*co1*/
+co02a[]={INV_,INV_,INV_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,NOP_,GRPE,INV_,INV_,INV_,
+ INV_,INV_,INV_,NOP_,INV_,INV_,INV_,INV_,NOP_,INV_},
+
+er02 []={TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,ER1 ,TK1 ,ER1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*er1*/
+er02a[]={PCI_,PCI_,PER_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+*grnttab[] = {tk02, tk02a, co02, co02a, er02, er02a};
+struct parse pcbgrnt = {"GRNT", lexgrp, grnttab, 0, 0, 0, 0};
+#undef TK1
+#undef CO1
+#undef ER1
+/* PCBGRNM: State and action table for name group parse.
+ Groups cannot nest. Reserved names are not allowed.
+ No suffixes or data tag pattern groups.
+*/
+/* Symbols for state names (end with a number). */
+#define TK1 0 /* Token expected: name, #CHARS, data tag grp, model. */
+#define CO1 2 /* Connector between tokens expected. */
+#define ER1 4 /* PERO found when token was expected. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+tk03 []={TK1 ,TK1 ,CO1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,ER1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*tk1*/
+tk03a[]={INV_,INV_,NAS_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,INV_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,NOP_,INV_,INV_,INV_,INV_,INV_},
+
+co03 []={TK1 ,TK1 ,TK1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,CO1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*co1*/
+co03a[]={INV_,INV_,INV_,NOP_,NOP_,SYS_,EE_ ,GET_,RS_ ,NOP_,GRPE,INV_,INV_,INV_,
+ INV_,INV_,INV_,NOP_,INV_,INV_,INV_,INV_,NOP_,INV_},
+
+er03 []={TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,ER1 ,TK1 ,ER1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*er1*/
+er03a[]={PCI_,PCI_,PER_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+*grnmtab[] = {tk03, tk03a, co03, co03a, er03, er03a};
+struct parse pcbgrnm = {"GRNM", lexgrp, grnmtab, 0, 0, 0, 0};
+#undef TK1
+#undef CO1
+#undef ER1
+/* PCBREF: State and action table to find the end of entity, parameter entity,
+ and character references. The opening delimiter and name
+ have already been found; the parse determines whether the
+ tokenization of the name ended normally and processes the REFC.
+*/
+/* Symbols for state names (end with a number). */
+#define ER5 0 /* Handle REFC or other entity reference termination. */
+#define ER6 2 /* Return to caller and reset state for next call. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+er05 []={ER5 ,ER6 ,ER6 ,ER6 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,
+ ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER6 },/*er5*/
+er05a[]={RCR_,LEN_,LEN_,NOP_,RCR_,SYS_,RCR_,GET_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,
+ RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,NOP_},
+
+er06 []={ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,
+ ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 ,ER5 },/*er6*/
+er06a[]={RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,
+ RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_,RCR_},
+
+*reftab[]={er05, er05a, er06, er06a};
+struct parse pcbref = {"ENTREF", lexgrp, reftab, 0, 0, 0, 0};
+#undef ER5
+#undef ER6
+/*
+Use (typical) Name Ending Chsw References RS RE SEP
+Parameter literal LITPC LIT/A OK Parm,Char RSM_ LAM_ LAM_
+ Data tag template NO
+System ID LITC LIT/A n/a none RSM_ LAM_ LAM_
+ Processing instruction PIC
+Attribute value LITRV LIT/A NO Gen,Char RS_ FUN_ FUN_
+Minimum literal LITV LIT/A n/a none RS_ FUN_ MLE_
+*/
+/* PCBLITP: Literal parse with parameter and character references;
+ no function character translation.
+*/
+/* Symbols for state names (end with a number). */
+#define DA0 0 /* Data in buffer. */
+#define ER0 2 /* ERO found. */
+#define CR0 4 /* CRO found (ER0, RNI). */
+#define PR0 6 /* PRO found (for PCBLITP). */
+
+static UNCH
+/* free num min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+da13 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ER0 ,
+ DA0 ,DA0 ,DA0 ,PR0 ,DA0 ,DA0 ,DA0 ,DA0 },/*da3*/
+da13a[]={MLA_,MLA_,MLA_,MLA_,MLA_,NON_,EE_ ,GET_,RSM_,MLA_,MLA_,MLA_,NSC_,NOP_,
+ MLA_,MLA_,MLA_,NOP_,MLA_,MLA_,MLA_,TER_},
+
+er13 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ER0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 },/*er3*/
+er13a[]={LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,GET_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,
+ LPR_,LPR_,LPR_,LPR_,NOP_,LPR_,LPR_,LPR_},
+
+cr13 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*cr3*/
+cr13a[]={LP2_,CRN_,LP2_,CRA_,LP2_,LP2_,LP2_,GET_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,
+ LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_},
+
+pr13 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,PR0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*pr3*/
+pr13a[]={LPR_,LPR_,LPR_,PEX_,LPR_,LPR_,LPR_,GET_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,
+ LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_},
+
+*litptab[] = {da13, da13a, er13, er13a, cr13, cr13a, pr13, pr13a};
+struct parse pcblitp = {"LITP", lexlms, litptab, 0, 0, 0, 0};
+#undef DA0
+#undef ER0
+#undef CR0
+#undef PR0
+/* PCBLITC: Literal parse; no references; no function char translation.
+ Used for character data (system data).
+*/
+/* Symbols for state names (end with a number). */
+#define DA0 0 /* Data in buffer. */
+
+static UNCH
+/* free num min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+da2 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*da2*/
+da2a[]={MLA_,MLA_,MLA_,MLA_,MLA_,SYS_,EOF_,GET_,RSM_,MLA_,MLA_,MLA_,SYS_,MLA_,
+ MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,TER_},
+
+*litctab[] = {da2, da2a};
+struct parse pcblitc = {"LITC", lexlms, litctab, 0, 0, 0, 0};
+#undef DA0
+/* PCBLITR: Attribute value parse; general and character references;
+ function chars are translated.
+*/
+/* Symbols for state names (end with a number). */
+#define DA0 0 /* Data in buffer. */
+#define ER0 2 /* ERO found. */
+#define CR0 4 /* CRO found (ER0, RNI). */
+
+static UNCH
+/* free num min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+da11 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ER0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*da1*/
+da11a[]={MLA_,MLA_,MLA_,MLA_,MLA_,NON_,EE_ ,GET_,RS_ ,FUN_,FUN_,MLA_,NSC_,NOP_,
+ MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,TER_},
+
+er11 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ER0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 },/*er1*/
+er11a[]={LPR_,LPR_,LPR_,ERX_,LPR_,LPR_,LPR_,GET_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,
+ LPR_,LPR_,LPR_,LPR_,NOP_,LPR_,LPR_,LPR_},
+
+cr11 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*cr1*/
+cr11a[]={LP2_,CRN_,LP2_,CRA_,LP2_,LP2_,LP2_,GET_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,
+ LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_},
+
+*litrtab[] = {da11, da11a, er11, er11a, cr11, cr11a};
+struct parse pcblitr = {"LITR", lexlms, litrtab, 0, 0, 0, 0};
+#undef DA0
+#undef ER0
+#undef CR0
+/* PCBLITV: Literal parse; no references; RS ignored; RE/SPACE sequences
+ become single SPACE. Only minimum data characters allowed.
+*/
+/* Symbols for state names (end with a number). */
+#define LS0 0 /* Leading SPACE or RE found. */
+#define VA0 2 /* Valid character found. */
+#define SP0 4 /* SPACE/RE sequence begun. */
+
+static UNCH
+/* free num min nms spc non ee eob rs re sep cde nsc
+ litc */
+ls10 []={VA0 ,VA0 ,VA0 ,VA0 ,LS0 ,VA0 ,LS0 ,LS0 ,LS0 ,LS0 ,LS0 ,VA0 ,VA0 ,
+ LS0 },/*ls0*/
+ls10a[]={MLE_,MLA_,MLA_,MLA_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,MLE_,SYS_,SYS_,
+ TER_},
+va10 []={VA0 ,VA0 ,VA0 ,VA0 ,SP0 ,VA0 ,VA0 ,VA0 ,VA0 ,SP0 ,SP0 ,VA0 ,VA0 ,
+ LS0 },/*va0*/
+da10a[]={MLE_,MLA_,MLA_,MLA_,MLA_,SYS_,EOF_,GET_,RS_ ,FUN_,MLE_,SYS_,SYS_,
+ TER_},
+sp10 []={VA0 ,VA0 ,VA0 ,VA0 ,SP0 ,VA0 ,VA0 ,SP0 ,SP0 ,SP0 ,SP0 ,VA0 ,VA0 ,
+ LS0 },/*sp0*/
+sp10a[]={MLE_,MLA_,MLA_,MLA_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,MLE_,SYS_,SYS_,
+ RPR_},
+
+*litvtab[] = {ls10, ls10a, va10, da10a, sp10, sp10a};
+struct parse pcblitv = {"LITV", lexmin, litvtab, 0, 0, 0, 0};
+#undef LS0
+#undef VA0
+#undef SP0
+/* PCBLITT: Tokenized attribute value parse.
+*/
+
+/* PCBLITT: Attribute value parse; general and character references;
+ function chars are translated.
+*/
+/* Symbols for state names (end with a number). */
+#define SP0 0 /* Ignore spaces */
+#define DA0 2 /* Data character */
+#define ER0 4 /* ERO found; ignore space */
+#define ER1 6 /* ERO found; don't ignore space */
+#define CR0 8 /* CRO found (ER0, RNI); ignore space */
+#define CR1 10 /* CR0 found; don't ignore space */
+
+int pcblittda = DA0;
+
+static UNCH
+/* free num min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+
+sp14 []={DA0 ,DA0 ,DA0 ,DA0 ,SP0 ,DA0 ,DA0 ,SP0 ,SP0 ,SP0 ,SP0 ,DA0 ,DA0 ,ER0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*sp0*/
+sp14a[]={MLA_,MLA_,MLA_,MLA_,NOP_,NON_,EE_ ,GET_,RS_ ,NOP_,NOP_,MLA_,NSC_,NOP_,
+ MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,TER_},
+
+da14 []={DA0 ,DA0 ,DA0 ,DA0 ,SP0 ,DA0 ,DA0 ,DA0 ,DA0 ,SP0 ,SP0 ,DA0 ,DA0 ,ER1 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,SP0 },/*da0*/
+da14a[]={MLA_,MLA_,MLA_,MLA_,MLA_,NON_,EE_ ,GET_,RS_ ,FUN_,FUN_,MLA_,NSC_,NOP_,
+ MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,MLA_,TER_},
+
+er14 []={DA0 ,DA0 ,DA0 ,SP0 ,DA0 ,DA0 ,DA0 ,ER0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 },/*er0*/
+er14a[]={LPR_,LPR_,LPR_,ERX_,LPR_,LPR_,LPR_,GET_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,
+ LPR_,LPR_,LPR_,LPR_,NOP_,LPR_,LPR_,LPR_},
+
+er15 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ER1 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,CR1 ,DA0 ,DA0 ,DA0 },/*er1*/
+er15a[]={LPR_,LPR_,LPR_,ERX_,LPR_,LPR_,LPR_,GET_,LPR_,LPR_,LPR_,LPR_,LPR_,LPR_,
+ LPR_,LPR_,LPR_,LPR_,NOP_,LPR_,LPR_,LPR_},
+
+cr14 []={DA0 ,DA0 ,DA0 ,SP0 ,DA0 ,DA0 ,DA0 ,CR0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*cr0*/
+cr14a[]={LP2_,CRN_,LP2_,CRA_,LP2_,LP2_,LP2_,GET_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,
+ LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_},
+
+cr15 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,CR1 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,
+ DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*cr1*/
+cr15a[]={LP2_,CRN_,LP2_,CRA_,LP2_,LP2_,LP2_,GET_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,
+ LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_,LP2_},
+
+*litttab[] = {sp14, sp14a, da14, da14a, er14, er14a, er15, er15a, cr14, cr14a,
+ cr15, cr15a};
+struct parse pcblitt = {"LITT", lexlms, litttab, 0, 0, 0, 0};
+#undef SP0
+#undef DA0
+#undef ER0
+#undef ER1
+#undef CR0
+#undef CR1
+/* PCBMD: State and action table for markup declaration tokenization.
+ Columns are based on LEXMARK.C.
+*/
+/* Symbols for state names (end with a number). */
+#define SP1 0 /* Separator before token expected (but not -). */
+#define SP2 2 /* Separator before token expected. */
+#define TK1 4 /* Token expected. */
+#define CM1 6 /* COM[1] found: possible comment, MGRP, or minus.*/
+#define CM2 8 /* COM[2] found; in comment. */
+#define CM3 10 /* Ending COM[1] found; end comment or continue it. */
+#define PR1 12 /* PERO found when token was expected. */
+#define PX1 14 /* PLUS found: PGRP or error. */
+#define RN1 16 /* RNI found; possible reserved name start. */
+
+int pcbmdtk = TK1; /* PCBMD: token expected. */
+
+static UNCH
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+sp21 []={SP1 ,SP1 ,SP1 ,SP1 ,TK1 ,SP1 ,TK1 ,SP1 ,TK1 ,SP1 ,SP1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,SP1 ,PR1 ,PX1 ,SP1 ,RN1 ,SP1 ,SP1 ,SP1 },
+sp21a[]={INV_,LEN_,LEN_,LEN_,NOP_,SYS_,EE_ ,GET_,RS_ ,LEN_,INV_,GRPS,LIT ,LITE,
+ MDS ,INV_,NOP_,NOP_,INV_,NOP_,EMD ,INV_,INV_},
+
+sp22 []={SP2 ,SP2 ,SP2 ,SP2 ,TK1 ,SP2 ,TK1 ,SP2 ,TK1 ,CM1 ,SP2 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,SP2 ,PR1 ,PX1 ,SP2 ,RN1 ,SP2 ,SP2 ,SP2 },
+sp22a[]={INV_,LEN_,LEN_,LEN_,NOP_,SYS_,EE_ ,GET_,RS_ ,NOP_,INV_,GRPS,LIT ,LITE,
+ MDS ,INV_,NOP_,NOP_,INV_,NOP_,EMD ,INV_,INV_},
+
+tk21 []={SP1 ,SP1 ,SP2 ,SP1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,CM1 ,SP1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,SP1 ,PR1 ,PX1 ,SP1 ,RN1 ,SP1 ,SP1 ,SP1 },
+tk21a[]={INV_,NMT ,NUM ,NAS ,NOP_,SYS_,EE_ ,GET_,RS_ ,NOP_,INV_,GRPS,LIT ,LITE,
+ MDS ,INV_,NOP_,NOP_,INV_,NOP_,EMD ,INV_,INV_},
+
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+
+cm21 []={TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,CM1 ,TK1 ,CM1 ,TK1 ,CM2 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },
+cm21a[]={CDR ,CDR ,CDR ,CDR ,CDR ,SYS_,CDR ,GET_,CDR ,NOP_,CDR ,MGRP,CDR ,CDR ,
+ CDR ,CDR ,CDR ,CDR ,CDR ,CDR ,CDR ,CDR ,CDR },
+
+cm22 []={CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,TK1 ,CM2 ,CM2 ,CM3 ,CM2 ,CM2 ,CM2 ,CM2 ,
+ CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 },
+cm22a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+cm23 []={CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM3 ,TK1 ,CM3 ,CM2 ,TK1 ,CM2 ,CM2 ,CM2 ,CM2 ,
+ CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 },
+cm23a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+pr21 []={SP1 ,SP1 ,SP1 ,TK1 ,TK1 ,PR1 ,SP2 ,PR1 ,TK1 ,SP2 ,SP1 ,SP1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP2 ,SP1 ,SP1 ,TK1 ,SP1 ,SP1 ,SP1 },
+pr21a[]={PCI_,PCI_,PCI_,PER_,PEN ,SYS_,PENR,GET_,PEN ,PENR,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PENR,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+px21 []={SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,PX1 ,SP1 ,PX1 ,SP1 ,SP1 ,SP1 ,TK1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 },
+px21a[]={PCI_,PCI_,PCI_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PGRP,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+rn21 []={TK1 ,TK1 ,TK1 ,SP1 ,TK1 ,RN1 ,TK1 ,RN1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,
+ TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },
+rn21a[]={PCI_,PCI_,PCI_,RNS ,PCI_,SYS_,PCI_,GET_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+*mdtab[] = {sp21, sp21a, sp22, sp22a, tk21, tk21a, cm21, cm21a, cm22, cm22a,
+ cm23, cm23a, pr21, pr21a, px21, px21a, rn21, rn21a};
+struct parse pcbmd = {"MD", lexmark, mdtab, 0, 0, 0, 0};
+#undef SP1
+#undef SP2
+#undef TK1
+#undef CM1
+#undef CM2
+#undef CM3
+#undef PR1
+#undef PX1
+#undef RN1
+/* PCBMDC: State and action table for comment declaration.
+*/
+/* Symbols for state names (end with a number). */
+#define CD2 0 /* COM[2] found; in comment. */
+#define CD3 2 /* Ending COM[1] found; end comment or continue it. */
+#define EM1 4 /* Ending COM[2] found; start new comment or end. */
+#define CD1 6 /* COM[1] found; new comment or error. */
+
+static UNCH
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+cd22 []={CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD3 ,CD2 ,CD2 ,CD2 ,CD2 ,
+ CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 },
+cd22a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+cd23 []={CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD3 ,CD2 ,CD3 ,CD2 ,EM1 ,CD2 ,CD2 ,CD2 ,CD2 ,
+ CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 },
+cd23a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+em21 []={CD2 ,CD2 ,CD2 ,CD2 ,EM1 ,EM1 ,CD2 ,EM1 ,EM1 ,CD1 ,CD2 ,CD2 ,CD2 ,CD2 ,
+ CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 },
+em21a[]={INV_,INV_,INV_,INV_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,INV_,INV_,EMD ,INV_,INV_},
+
+cd21 []={CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD1 ,CD2 ,CD1 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,
+ CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 ,CD2 },
+cd21a[]={PCI_,PCI_,PCI_,PCI_,PCI_,SYS_,EOF_,GET_,PCI_,NOP_,PCI_,PCI_,PCI_,PCI_,
+ PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_,PCI_},
+
+*mdctab[] = {cd22, cd22a, cd23, cd23a, em21, em21a, cd21, cd21a};
+struct parse pcbmdc = {"MDC", lexmark, mdctab, 0, 0, 0, 0};
+#undef CD2
+#undef CD3
+#undef EM1
+#undef CD1
+/* PCBMDI: State and action table for ignoring markup declarations.
+ Literals are handled properly so a TAGC won't end the declaration.
+ An error is noted if the entity ends within a declaration that
+ is being ignored.
+ TO DO: Handle nested declaration sets.
+*/
+/* Symbols for state names (end with a number). */
+#define NC1 0 /* Not in a comment; TAGC ends declaration. */
+#define IC1 2 /* COM[1] found; possible comment. */
+#define IC2 4 /* COM[2] found; in comment. */
+#define IC3 6 /* Ending COM[1] found; end comment or continue it. */
+#define LI1 8 /* Literal parameter; search for LIT. */
+#define LA1 10 /* Literal parameter; search for LITA. */
+
+static UNCH
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+nc21 []={NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,IC1 ,NC1 ,NC1 ,LI1 ,LA1 ,
+ NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 },
+nc21a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,EMD ,NOP_,NOP_},
+
+ic21 []={NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,IC1 ,NC1 ,IC1 ,NC1 ,IC2 ,NC1 ,NC1 ,LI1 ,LA1 ,
+ NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 ,NC1 },
+ic21a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,EMD ,NOP_,NOP_},
+
+ic22 []={IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,NC1 ,IC2 ,IC2 ,IC3 ,IC2 ,IC2 ,IC2 ,IC2 ,
+ IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 },
+ic22a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+ic23 []={IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC3 ,NC1 ,IC3 ,IC2 ,NC1 ,IC2 ,IC2 ,IC2 ,IC2 ,
+ IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 ,IC2 },/*ic3*/
+ic23a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+li21 []={LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,NC1 ,LI1 ,
+ LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 ,LI1 },/*li1*/
+li21a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+la21 []={LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,NC1 ,
+ LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 ,LA1 },/*la1*/
+la21a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+*mditab[] = {nc21, nc21a, ic21, ic21a, ic22, ic22a,
+ ic23, ic23a, li21, li21a, la21, la21a};
+struct parse pcbmdi = {"MDI", lexmark, mditab, 0, 0, 0, 0};
+#undef NC1
+#undef IC1
+#undef IC2
+#undef IC3
+#undef LI1
+#undef LA1
+/* PCBMSRC: State and action table for marked section in RCDATA mode.
+ Nested marked sections are not recognized; the first MSE ends it.
+ Initial state assumes an MS declaration was processed.
+ Columns are based on LEXLMS.C but LITC column needn't exist.
+*/
+/* Symbols for state names (end with a number). */
+#define ET0 0 /* MSS processed or buffer flushed; no data. */
+#define DA0 2 /* Data in buffer. */
+#define ER0 4 /* ERO found; start lookahead buffer. */
+#define CR0 6 /* CRO found (ER0, RNI). */
+#define ME0 8 /* MSC found. */
+#define ME1 10 /* MSC, MSC found. */
+
+static UNCH
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+et30 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,DA0 ,DA0 ,ET0 ,ER0 ,
+ DA0 ,ME0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*et0*/
+et30a[]={DAS_,DAS_,DAS_,DAS_,DAS_,NON_,EE_ ,GET_,RS_ ,REF_,DAS_,DAS_,NSC_,LAS_,
+ DAS_,LAS_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_},
+
+da30 []={DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,DA0 ,DA0 ,ET0 ,ET0 ,
+ DA0 ,ET0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 ,DA0 },/*da0*/
+da30a[]={NOP_,NOP_,NOP_,NOP_,NOP_,DAF_,DAF_,DAF_,DAF_,DAF_,NOP_,NOP_,DAF_,DAF_,
+ NOP_,DAF_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+er30 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ER0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,CR0 ,ET0 ,ET0 ,ET0 },/*er0*/
+er30a[]={LAF_,LAF_,LAF_,ERX_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAM_,LAF_,LAF_,LAF_},
+
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+cr30 []={ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,CR0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,
+ ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 ,ET0 },/*cr0*/
+cr30a[]={LAF_,CRN_,LAF_,CRA_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+me30 []={ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ME0, ET0 ,ET0 ,ET0 ,ET0, ET0 ,ET0 ,
+ ET0, ME1, ET0 ,ET0, ET0 ,ET0, ET0 ,ET0 },/*me0*/
+me30a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+me31 []={ET0, ET0, ET0, ET0, ET0 ,ET0, ET0, ME1, ET0 ,ET0 ,ET0 ,ET0, ET0 ,ET0 ,
+ ET0, ET0, ET0 ,ET0, ET0 ,ET0, ET0 ,ET0,},/*me1*/
+me31a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,MSE_,LAF_,LAF_},
+
+*msrctab[]={et30, et30a, da30, da30a, er30, er30a, cr30, cr30a,
+ me30, me30a, me31, me31a};
+struct parse pcbmsrc = {"MSRCDATA", lexlms, msrctab, 0, 0, 0, 0};
+#undef ET0
+#undef DA0
+#undef ER0
+#undef CR0
+#undef ME0
+#undef ME1
+/* PCBMSC: State and action table for marked section in CDATA mode.
+ Nested marked sections are not recognized; the first MSE ends it.
+ Initial state assumes an MS declaration was processed.
+*/
+/* Symbols for state names (end with a number). */
+#define ET2 0 /* MSS processed or buffer flushed; no data. */
+#define DA2 2 /* Data in buffer. */
+#define ME2 4 /* MSC found. */
+#define ME3 6 /* MSC, MSC found. */
+
+static UNCH
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+et32 []={DA2 ,DA2 ,DA2 ,DA2 ,DA2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,DA2 ,DA2 ,ET2 ,DA2 ,
+ DA2 ,ME2 ,DA2 ,DA2 ,DA2 ,DA2 ,DA2 ,DA2 },/*et2*/
+et32a[]={DAS_,DAS_,DAS_,DAS_,DAS_,NON_,EOF_,GET_,RS_ ,REF_,DAS_,DAS_,NSC_,DAS_,
+ DAS_,LAS_,DAS_,DAS_,DAS_,DAS_,DAS_,DAS_},
+
+da32 []={DA2 ,DA2 ,DA2 ,DA2 ,DA2 ,ET2 ,ET2 ,ET2 ,ET2 ,ET2 ,DA2 ,DA2 ,ET2 ,DA2 ,
+ DA2 ,ET2 ,DA2 ,DA2 ,DA2 ,DA2 ,DA2 ,DA2 },/*da2*/
+da32a[]={NOP_,NOP_,NOP_,NOP_,NOP_,DAF_,DAF_,DAF_,DAF_,DAF_,NOP_,NOP_,DAF_,NOP_,
+ NOP_,DAF_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+me32 []={ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ME2, ET2 ,ET2 ,ET2 ,ET2, ET2 ,ET2 ,
+ ET2, ME3, ET2 ,ET2, ET2 ,ET2, ET2, ET2,},/*me2*/
+me32a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAM_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_},
+
+me33 []={ET2, ET2, ET2, ET2, ET2 ,ET2, ET2, ME3, ET2 ,ET2 ,ET2 ,ET2, ET2 ,ET2 ,
+ ET2, ET2, ET2 ,ET2, ET2 ,ET2, ET2, ET2,},/*me3*/
+me33a[]={LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,GET_,LAF_,LAF_,LAF_,LAF_,LAF_,LAF_,
+ LAF_,LAF_,LAF_,LAF_,LAF_,MSE_,LAF_,LAF_},
+
+*msctab[]={et32, et32a, da32, da32a, me32, me32a, me33, me33a};
+struct parse pcbmsc = {"MSCDATA", lexlms, msctab, 0, 0, 0, 0};
+#undef ET2
+#undef DA2
+#undef ME2
+#undef ME3
+/* PCBMSI: State and action table for marked section in IGNORE mode.
+ Nested marked sections are recognized; the matching MSE ends it.
+ Initial state assumes an MS declaration, MSS, or MSE was processed.
+*/
+/* Symbols for state names (end with a number). */
+#define ET4 0 /* Markup found or buffer flushed; no data. */
+#define ME4 2 /* MSC found. */
+#define ME5 4 /* MSC, MSC found. */
+#define ES4 6 /* TAGO found. */
+#define MD4 8 /* MDO found (TAGO, MDO[2]). */
+
+static UNCH
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc refc */
+et34 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,
+ ET4 ,ME4 ,ET4 ,ET4 ,ET4 ,ET4 ,ES4 ,ET4 ,ET4 },/*et4*/
+et34a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+me34 []={ET4, ET4, ET4, ET4, ET4 ,ET4, ET4, ME4, ET4 ,ET4 ,ET4 ,ET4, ET4, ET4 ,
+ ET4, ME5 ,ET4, ET4, ET4 ,ET4, ET4, ET4, ET4,},/*me4*/
+me34a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+me35 []={ET4, ET4, ET4, ET4, ET4 ,ET4, ET4, ME5, ET4 ,ET4 ,ET4 ,ET4, ET4, ET4 ,
+ ET4, ET4 ,ET4, ET4, ET4 ,ET4, ET4, ET4, ET4,},/*me5*/
+me35a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,MSE_,NOP_,NOP_,NOP_},
+
+/* free nu min nms spc non ee eob rs re sep cde nsc ero
+ mdo msc mso pero rni tagc tago litc */
+es34 []={ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ES4 ,ET4 ,ES4 ,ET4 ,ET4 ,ET4 ,ET4 ,ES4 ,ET4 ,
+ MD4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 ,ET4 },/*es4*/
+es34a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+md34 []={ET4, ET4, ET4, ET4, ET4 ,MD4, ET4, MD4, ET4 ,ET4 ,ET4 ,ET4, ET4, ET4 ,
+ ET4, ET4 ,ET4, ET4, ET4 ,ET4, ET4, ET4,},/*md4*/
+md34a[]={NOP_,NOP_,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,SYS_,NOP_,
+ NOP_,NOP_,MSS_,NOP_,NOP_,NOP_,NOP_,NOP_},
+
+*msitab[]={et34, et34a, me34, me34a, me35, me35a, es34, es34a, md34, md34a};
+struct parse pcbmsi = {"MSIGNORE", lexlms, msitab, 0, 0, 0, 0};
+#undef ET4
+#undef ME4
+#undef ME5
+#undef ES4
+#undef MD4
+#undef NS4
+/* PCBSTAG: State and action table for start-tag parse.
+ Columns are based on LEXMARK.C.
+*/
+/* Symbols for state names (end with a number). */
+#define SP1 0 /* Separator before name expected. */
+#define AN1 2 /* Attribute name expected. */
+#define SP2 4 /* Separator or value indicator expected. */
+#define VI1 6 /* Value indicator expected. */
+#define AV1 8 /* Attribute value expected. */
+
+int pcbstan = AN1; /* PCBSTAG: attribute name expected. */
+
+static UNCH
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+sp41 []={SP1 ,SP1 ,SP1 ,SP1 ,AN1 ,SP1 ,SP1 ,SP1 ,AN1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 },
+sp41a[]={INV_,LEN_,LEN_,LEN_,NOP_,SYS_,EOF_,GET_,RS_ ,LEN_,ETIC,INV_,INV_,INV_,
+ INV_,DSC ,INV_,INV_,INV_,INV_,TAGC,TAGO,INV_},
+
+an41 []={SP1 ,SP1 ,SP1 ,SP2 ,AN1 ,AN1 ,AN1 ,AN1 ,AN1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 },
+an41a[]={INV_,NTV ,NTV ,NVS ,NOP_,SYS_,EOF_,GET_,RS_ ,NTV ,ETIC,INV_,INV_,INV_,
+ INV_,DSC ,INV_,INV_,INV_,INV_,TAGC,TAGO,INV_},
+
+sp42 []={SP1 ,SP1 ,SP1 ,SP1 ,VI1 ,SP2 ,SP2 ,SP2 ,VI1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,AV1 },
+sp42a[]={INV_,LEN_,LEN_,LEN_,NOP_,SYS_,EOF_,GET_,RS_ ,LEN_,NASV,INV_,INV_,INV_,
+ INV_,NASV,INV_,INV_,INV_,INV_,NASV,NASV,NOP_},
+
+/* bit nmc num nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+vi41 []={SP1 ,AN1 ,AN1 ,AN1 ,VI1 ,VI1 ,VI1 ,VI1 ,VI1 ,AN1 ,SP1 ,SP1 ,SP1 ,SP1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,AV1 },
+vi41a[]={INV_,NASV,NASV,NASV,NOP_,SYS_,EOF_,GET_,RS_ ,NASV,NASV,INV_,INV_,INV_,
+ INV_,NASV,INV_,INV_,INV_,INV_,NASV,NASV,NOP_},
+
+av41 []={SP1 ,SP1 ,SP1 ,SP1 ,AV1 ,AV1 ,AV1 ,AV1 ,AV1 ,SP1 ,SP1 ,SP1 ,AN1 ,AN1 ,
+ SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 ,SP1 },
+av41a[]={INV_,AVU ,AVU ,AVU ,NOP_,SYS_,EOF_,GET_,RS_ ,AVU ,INV_,INV_,AVD ,AVDA,
+ INV_,INV_,INV_,INV_,INV_,INV_,INV_,INV_,INV_},
+
+*stagtab[] = {sp41, sp41a, an41, an41a, sp42, sp42a, vi41, vi41a, av41, av41a};
+struct parse pcbstag = {"STAG", lexmark, stagtab, 0, 0, 0, 0};
+#undef SP1
+#undef AN1
+#undef SP2
+#undef VI1
+#undef AV1
+/* PCBETAG: State and action table for end-tag parse.
+*/
+#define TC1 0 /* Tag close expected (no attributes allowed). */
+
+static UNCH
+/* bit nmc nu nms spc non ee eob rs com eti grpo lit lita
+ dso dsc pero plus refc rni tagc tago vi */
+tc41 []={TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,
+ TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 ,TC1 },/*tc1*/
+tc41a[]={INV_,INV_,INV_,INV_,NOP_,SYS_,EOF_,GET_,RS_ ,INV_,INV_,INV_,INV_,INV_,
+ INV_,INV_,INV_,INV_,INV_,INV_,TAGC,TAGO,INV_},
+
+*etagtab[] = {tc41, tc41a};
+struct parse pcbetag = {"ETAG", lexmark, etagtab, 0, 0, 0, 0};
+#undef TC1
+/* PCBVAL: State and action table for tokenizing attribute values.
+ Columns are based on lextoke (but EOB cannot occur).
+*/
+/* Symbols for state names (end with a number). */
+#define TK1 0 /* Token expected. */
+#define SP1 2 /* Separator before token expected. */
+
+static UNCH
+/* inv rec sep sp nmc nms nu eob */
+tk51 []={TK1 ,TK1 ,TK1 ,TK1 ,SP1 ,SP1 ,SP1 },/*tk1*/
+tk51a[]={INVA,INVA,INVA,NOPA,NMTA,NASA,NUMA},
+
+sp51 []={TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 },/*sp1*/
+sp51a[]={INVA,INVA,INVA,NOPA,LENA,LENA,LENA},
+
+*valtab[] = {tk51, tk51a, sp51, sp51a};
+struct parse pcbval = {"VAL", lextoke, valtab, 0, 0, 0, 0};
+#undef TK1
+#undef SP1
+/* PCBEAL: State and action table for end of attribute specification list.
+ If delimiter occurs, process it. Otherwise, put invalid character
+ back for the next parse.
+*/
+/* Symbols for state names (end with a number). */
+#define AL0 0 /* Delimiter expected. */
+
+static UNCH
+/* bit nmc nms re spc non ee eob rs and grpc grpo lit lita
+ dtgc dtgo opt or pero plus rep rni seq refc */
+al00 []={AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,
+ AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 ,AL0 },/*al0*/
+al00a[]={INV_,INV_,INV_,INV_,INV_,SYS_,EE_ ,GET_,INV_,INV_,INV_,INV_,INV_,INV_,
+ GRPE,INV_,INV_,INV_,INV_,INV_,INV_,INV_,INV_,INV_},
+
+*ealtab[] = {al00, al00a};
+struct parse pcbeal = {"EAL", lexgrp, ealtab, 0, 0, 0, 0};
+#undef AL0
+
+/* PCBSD: State and action tables for SGML declaration parsing. */
+
+/* Symbols for state names. */
+
+#define SP1 0 /* Separator before token expected (but not -) */
+#define SP2 2 /* Separator before token expected. */
+#define TK1 4 /* Token expected. */
+#define CM1 6 /* COM[1] found: possible comment.*/
+#define CM2 8 /* COM[2] found; in comment. */
+#define CM3 10 /* Ending COM[1] found; end comment or continue it. */
+static UNCH
+/* sig dat num nms spc non ee eob rs com lit lita tagc */
+
+sp31 []={SP1 ,SP1 ,SP1 ,SP1 ,TK1 ,SP1 ,SP1 ,SP1 ,TK1 ,SP1 ,TK1 ,TK1 ,SP1 },
+sp31a[]={INV_,ISIG,LEN_,LEN_,NOP_,SYS_,EOF_,GET_,RS_ ,LEN_,LIT1,LIT2,ESGD},
+
+sp32 []={SP2 ,SP2 ,SP2 ,SP2 ,TK1 ,SP2 ,SP2 ,SP2 ,TK1 ,CM1 ,TK1 ,TK1 ,SP2 },
+sp32a[]={INV_,ISIG,LEN_,LEN_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,LIT1,LIT2,ESGD},
+
+tk31 []={TK1 ,TK1 ,SP2 ,SP1 ,TK1 ,TK1 ,TK1 ,TK1 ,TK1 ,CM1 ,TK1 ,TK1 ,SP1 },
+tk31a[]={INV_,ISIG,NUM1,NAS1,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,LIT1,LIT2,ESGD},
+
+cm31 []={TK1 ,CM1 ,TK1 ,TK1 ,TK1 ,CM1 ,TK1 ,CM1 ,TK1 ,CM2 ,TK1 ,TK1 ,TK1 },
+cm31a[]={PCI_,ISIG,PCI_,PCI_,PCI_,SYS_,PCI_,GET_,PCI_,NOP_,PCI_,PCI_,PCI_},
+
+cm32 []={CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,CM2 ,TK1 ,CM2 ,CM2 ,CM3 ,CM2 ,CM2 ,CM2 },
+cm32a[]={NOP_,ISIG,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_},
+
+cm33 []={CM2 ,CM3 ,CM2 ,CM2 ,CM2 ,CM3 ,TK1 ,CM3 ,CM2 ,TK1 ,CM2 ,CM2 ,CM2 },
+cm33a[]={NOP_,ISIG,NOP_,NOP_,NOP_,SYS_,EOF_,GET_,RS_ ,NOP_,NOP_,NOP_,NOP_},
+
+*sdtab[]={sp31, sp31a, sp32, sp32a, tk31, tk31a, cm31, cm31a, cm32, cm32a,
+ cm33, cm33a};
+
+struct parse pcbsd = {"SD", lexsd, sdtab, 0, 0, 0, 0};
+
+#undef SP1
+#undef SP2
+#undef TK1
+#undef CM1
+#undef CM2
+#undef CM3
diff --git a/usr.bin/sgmls/sgmls/portproc.c b/usr.bin/sgmls/sgmls/portproc.c
new file mode 100644
index 0000000..a057d24
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/portproc.c
@@ -0,0 +1,105 @@
+/* portproc.c -
+
+ Semi-portable implementation of run_process().
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifdef SUPPORT_SUBDOC
+
+#include "std.h"
+#include "entity.h"
+#include "appl.h"
+#include "alloc.h"
+
+/* This code shows how you might use system() to implement run_process().
+ANSI C says very little about the behaviour of system(), and so this
+is necessarily system dependent. */
+
+/* Characters that are significant to the shell and so need quoting. */
+#define SHELL_MAGIC "$\\\"';&()|<>^ \t\n"
+/* Character with which to quote shell arguments. */
+#define SHELL_QUOTE_CHAR '\''
+/* String that can be used to get SHELL_QUOTE_CHAR into a quoted argument. */
+#define SHELL_ESCAPE_QUOTE "'\\''"
+/* Character that can be used to separate arguments to the shell. */
+#define SHELL_ARG_SEP ' '
+
+static UNS shell_quote P((char *, char *));
+
+int run_process(argv)
+char **argv;
+{
+ char **p;
+ char *s, *command;
+ int ret;
+ UNS len = 0;
+
+ for (p = argv; *p; p++)
+ len += shell_quote(*p, (char *)0);
+ len += p - argv;
+ s = command = xmalloc(len);
+ for (p = argv; *p; ++p) {
+ if (s > command)
+ *s++ = SHELL_ARG_SEP;
+ s += shell_quote(*p, s);
+ }
+ *s++ = '\0';
+ errno = 0;
+ ret = system(command);
+ if (ret < 0)
+ appl_error(E_EXEC, argv[0], strerror(errno));
+ free(command);
+ return ret;
+}
+
+/* Quote a string so that it appears as a single argument to the
+shell (as used for system()). Store the quoted argument in result, if
+result is not NULL. Return the length. */
+
+static
+UNS shell_quote(s, result)
+char *s, *result;
+{
+ UNS len = 0;
+ int quoted = 0;
+
+ if (strpbrk(s, SHELL_MAGIC)) {
+ quoted = 1;
+ len++;
+ if (result)
+ result[0] = SHELL_QUOTE_CHAR;
+ }
+ for (; *s; s++) {
+ if (*s == SHELL_QUOTE_CHAR) {
+ if (result)
+ strcpy(result + len, SHELL_ESCAPE_QUOTE);
+ len += strlen(SHELL_ESCAPE_QUOTE);
+ }
+ else {
+ if (result)
+ result[len] = *s;
+ len++;
+ }
+ }
+ if (quoted) {
+ if (result)
+ result[len] = SHELL_QUOTE_CHAR;
+ len++;
+ }
+ return len;
+}
+
+#endif /* SUPPORT_SUBDOC */
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/serv.c b/usr.bin/sgmls/sgmls/serv.c
new file mode 100644
index 0000000..b9699d2
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/serv.c
@@ -0,0 +1,299 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+/* ETDDEF: Define an element type definition.
+ Use an existing one if there is one; otherwise create one, which
+ rmalloc initializes to zero which shows it is a virgin etd.
+*/
+PETD etddef(ename)
+UNCH *ename; /* Element name (GI) with length byte. */
+{
+ PETD p; /* Pointer to an etd. */
+ int hnum; /* Hash number for ename. */
+
+ if ((p = (PETD)hfind((THASH)etdtab,ename,hnum = hash(ename, ETDHASH)))==0){
+ p = (PETD)hin((THASH)etdtab, ename, hnum, ETDSZ);
+ }
+ return p;
+}
+/* ETDSET: Store data in an element type definition.
+ The etd must be valid and virgin (except for adl and etdmin).
+ As an etd cannot be modified, there is no checking for existing
+ pointers and no freeing of their storage.
+*/
+#ifdef USE_PROTOTYPES
+PETD etdset(PETD p, UNCH fmin, struct thdr *cmod, PETD *mexgrp, PETD *pexgrp,
+ struct entity **srm)
+#else
+PETD etdset(p, fmin, cmod, mexgrp, pexgrp, srm)
+PETD p; /* Pointer to an etd. */
+UNCH fmin; /* Minimization bit flags. */
+struct thdr *cmod; /* Pointer to content model. */
+PETD *mexgrp; /* Pointers to minus and plus exception lists. */
+PETD *pexgrp; /* Pointers to minus and plus exception lists. */
+struct entity **srm; /* Short reference map. */
+#endif
+{
+ p->etdmin |= fmin;
+ p->etdmod = cmod;
+ p->etdmex = mexgrp;
+ p->etdpex = pexgrp;
+ p->etdsrm = srm;
+ return p;
+}
+/* ETDREF: Retrieve the pointer to an element type definition.
+*/
+PETD etdref(ename)
+UNCH *ename; /* Element name (GI) with length byte.. */
+{
+
+ return (PETD)hfind((THASH)etdtab, ename, hash(ename, ETDHASH));
+}
+/* ETDCAN: Cancel an element definition. The etd is freed and is removed
+ from the hash table, but its model and other pointers are not freed.
+*/
+VOID etdcan(ename)
+UNCH *ename; /* GI name (with length and EOS). */
+{
+ PETD p;
+
+ if ((p = (PETD)hout((THASH)etdtab, ename, hash(ename, ETDHASH)))!=0)
+ frem((UNIV)p);
+}
+/* SYMBOL TABLE FUNCTIONS: These functions manage hash tables that are used
+ for entities, element type definitions, IDs, and other purposes. The
+ interface will be expanded in the future to include multiple environments,
+ probably by creating arrays of the present hash tables with each table
+ in the array corresponding to an environment level.
+*/
+/* HASH: Form hash value for a string.
+ From the Dragon Book, p436.
+*/
+int hash(s, hashsize)
+UNCH *s; /* String to be hashed. */
+int hashsize; /* Size of hash table array. */
+{
+ unsigned long h = 0, g;
+
+ while (*s != 0) {
+ h <<= 4;
+ h += *s++;
+ if ((g = h & 0xf0000000) != 0) {
+ h ^= g >> 24;
+ h ^= g;
+ }
+ }
+ return (int)(h % hashsize);
+}
+/* HFIND: Look for a name in a hash table.
+*/
+struct hash *hfind(htab, s, h)
+struct hash *htab[]; /* Hash table. */
+UNCH *s; /* Entity name. */
+int h; /* Hash value for entity name. */
+{
+ struct hash *np;
+
+ for (np = htab[h]; np != 0; np = np->enext)
+ if (ustrcmp(s, np->ename) == 0) return np; /* Found it. */
+ return (struct hash *)0; /* Not found. */
+}
+/* HIN: Locates an entry in a hash table, or allocates a new one.
+ Returns a pointer to a structure containing a name
+ and a pointer to the next entry. Other data in the
+ structure must be maintained by the caller.
+*/
+struct hash *hin(htab, name, h, size)
+struct hash *htab[]; /* Hash table. */
+UNCH *name; /* Entity name. */
+int h; /* Hash value for entity name. */
+UNS size; /* Size of structures pointed to by table. */
+{
+ struct hash *np;
+
+ if ((np = hfind(htab, name, h))!=0) return np; /* Return if name found. */
+ /* Allocate space for structure and name. */
+ np = (struct hash *)rmalloc(size + name[0]);
+ np->ename = (UNCH *)np + size;
+ memcpy(np->ename, name, name[0]); /* Store name in it. */
+ np->enext = htab[h]; /* 1st entry is now 2nd.*/
+ htab[h] = np; /* New entry is now 1st.*/
+ return np; /* Return new entry ptr. */
+}
+/* HOUT: Remove an entry from a hash table and return its pointer.
+ The caller must free any pointers in the entry and then
+ free the entry itself if that is what is desired; this
+ routine does not free any storage.
+*/
+struct hash *hout(htab, s, h)
+struct hash *htab[]; /* Hash table. */
+UNCH *s; /* Search argument entry name. */
+int h; /* Hash value for search entry name. */
+{
+ struct hash **pp;
+
+ for (pp = &htab[h]; *pp != 0; pp = &(*pp)->enext)
+ if (ustrcmp(s, (*pp)->ename) == 0) { /* Found it. */
+ struct hash *tem = *pp;
+ *pp = (*pp)->enext;
+ return tem;
+ }
+ return 0; /* NULL if not found; else ptr. */
+}
+/* SAVESTR: Save a null-terminated string
+*/
+UNCH *savestr(s)
+UNCH *s;
+{
+ UNCH *rp;
+
+ rp = (UNCH *)rmalloc(ustrlen(s) + 1);
+ ustrcpy(rp, s);
+ return rp;
+}
+/* SAVENM: Save a name (with length and EOS)
+*/
+UNCH *savenm(s)
+UNCH *s;
+{
+ UNCH *p;
+ p = (UNCH *)rmalloc(*s);
+ memcpy(p, s, *s);
+ return p;
+}
+/* REPLACE: Free the storage for the old string (p) and store the new (s).
+ If the specified ptr is NULL, don't free it.
+*/
+UNCH *replace(p, s)
+UNCH *p;
+UNCH *s;
+{
+ if (p) frem((UNIV)p); /* Free old storage (if any). */
+ if (!s) return(s); /* Return NULL if new string is NULL. */
+ return savestr(s);
+}
+/* RMALLOC: Interface to memory allocation with error handling.
+ If storage is not available, fatal error message is issued.
+ Storage is initialized to zeros.
+*/
+UNIV rmalloc(size)
+unsigned size; /* Number of bytes of initialized storage. */
+{
+ UNIV p = (UNIV)calloc(size, 1);
+ if (!p) exiterr(33, (struct parse *)0);
+ return p;
+}
+UNIV rrealloc(p, n)
+UNIV p;
+UNS n;
+{
+ UNIV r = realloc(p, n);
+ if (!r)
+ exiterr(33, (struct parse *)0);
+ return r;
+}
+
+UNCH *pt;
+/* FREM: Free specified memory area gotten with rmalloc().
+*/
+VOID frem(ptr)
+UNIV ptr; /* Memory area to be freed. */
+{
+ free(ptr);
+}
+/* MAPSRCH: Find a string in a table and return its associated value.
+ The last entry must be a dummy consisting of a NULL pointer for
+ the string and whatever return code is desired if the
+ string is not found in the table.
+*/
+int mapsrch(maptab, name)
+struct map maptab[];
+UNCH *name;
+{
+ int i = 0;
+
+ do {
+ UNCH *mapnm, *nm;
+ for (mapnm = maptab[i].mapnm, nm=name; *nm==*mapnm; mapnm++) {
+ if (!*nm++) return maptab[i].mapdata;
+ }
+ } while (maptab[++i].mapnm);
+ return maptab[i].mapdata;
+}
+/* IDDEF: Define an ID control block; return -1 if it already exists.
+*/
+int iddef(iname)
+UNCH *iname; /* ID name (with length and EOS). */
+{
+ PID p;
+ struct fwdref *r;
+
+ p = (PID)hin((THASH)itab, iname, hash(iname, IDHASH), IDSZ);
+ if (p->iddefed) return(-1);
+ p->iddefed = 1;
+ TRACEID("IDDEF", p);
+ /* Delete any forward references. */
+ r = p->idrl;
+ p->idrl = 0;
+ while (r) {
+ struct fwdref *tem = r->next;
+ if (r->msg)
+ msgsfree(r->msg);
+ frem((UNIV)r);
+ r = tem;
+ }
+ return(0);
+}
+/* IDREF: Store a reference to an ID and define the ID if it doesn't yet exist.
+ Return 0 if already defined, otherwise pointer to a fwdref.
+*/
+struct fwdref *idref(iname)
+UNCH *iname; /* ID name (with length and EOS). */
+{
+ PID p;
+ int hnum;
+ struct fwdref *rp;
+
+ if ((p = (PID)hfind((THASH)itab, iname, (hnum = hash(iname, IDHASH))))==0)
+ p = (PID)hin((THASH)itab, iname, hnum, IDSZ);
+ if (p->iddefed)
+ return 0;
+ rp = (struct fwdref *)rmalloc(FWDREFSZ);
+ rp->next = p->idrl;
+ p->idrl = rp;
+ rp->msg = 0;
+ TRACEID("IDREF", p);
+ return rp;
+}
+/* IDRCK: Check idrefs.
+*/
+VOID idrck()
+{
+ int i;
+ PID p;
+ struct fwdref *r;
+
+ for (i = 0; i < IDHASH; i++)
+ for (p = itab[i]; p; p = p->idnext)
+ if (!p->iddefed)
+ for (r = p->idrl; r; r = r->next)
+ svderr(r->msg);
+}
+/* NTOA: Converts a positive integer to an ASCII string (abuf)
+ No leading zeros are generated.
+*/
+UNCH *ntoa(i)
+int i;
+{
+ static UNCH buf[1 + 3*sizeof(int) + 1];
+ sprintf((char *)buf, "%d", i);
+ return buf;
+}
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgml1.c b/usr.bin/sgmls/sgmls/sgml1.c
new file mode 100644
index 0000000..c138c9f
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgml1.c
@@ -0,0 +1,485 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+
+#define ETDCON (tags[ts].tetd->etdmod->ttype) /* ETD content flags. */
+
+/* SGML: Main SGML driver routine.
+*/
+enum sgmlevent sgmlnext(rcbdafp, rcbtagp)
+struct rcbdata *rcbdafp;
+struct rcbtag *rcbtagp;
+{
+ while (prologsw && !conactsw) {
+ int oconact;
+ conact = parsepro();
+ conactsw = 0; /* Assume sgmlact() will not be skipped. */
+ switch(conact) {
+
+ case PIS_:
+ case EOD_:
+ case APP_: /* APPINFO */
+ conactsw = 1; /* We can skip sgmlact() in opening state. */
+ break;
+
+ case DAF_:
+ newetd = stagreal = ETDCDATA;
+ conact = stag(datarc = DAF_);
+ conactsw = 1; /* We can skip sgmlact() in opening state. */
+ prologsw = 0; /* End the prolog. */
+ break;
+ case DCE_:
+ case MSS_:
+ /* prcon[2].tu.thetd holds the etd for the document element. */
+ newetd = stagreal = prcon[2].tu.thetd;
+ stagmin = MINSTAG; /* This tag was minimized. */
+ /* It's an error if the start tag of the document element
+ is not minimizable. */
+ if (BITOFF(newetd->etdmin, SMO))
+ sgmlerr(226, conpcb, (UNCH *)0, (UNCH *)0);
+ oconact = conact; /* Save conact. */
+ conact = stag(0); /* Start the document element. */
+ conactsw = 1; /* conact needs processing. */
+ prologsw = 0; /* The prolog is finished. */
+ if (oconact == MSS_) {
+ if (msplevel==0) conpcb = getpcb((int)ETDCON);
+ conpcb = mdms(tbuf, conpcb); /* Parse the marked section
+ start. */
+ }
+ break;
+ default: /* STE_: not defined in SGMLACT.H. */
+ if (msplevel==0) conpcb = getpcb((int)ETDCON);
+ prologsw = 0; /* End the prolog. */
+ break;
+ }
+ }
+ for (;;) {
+ unsigned swact; /* Switch action: saved conact, new, or sgmlact.*/
+
+ if (conactsw) {
+ conactsw = 0;
+ swact = conact;
+ contersw = contersv;
+ }
+ else {
+ conact = parsecon(tbuf, conpcb);
+ swact = sgmlact((UNCH)(conact != EOD_ ? conact : LOP_));
+ }
+
+ switch (swact) {
+
+ case MD_: /* Process markup declaration. */
+ parsenm(tbuf, NAMECASE); /* Get declaration name. */
+ if (!ustrcmp(tbuf+1, key[KUSEMAP])) mdsrmuse(tbuf);
+ else sgmlerr(E_MDNAME, conpcb, tbuf+1, (UNCH *)0);
+ continue;
+ case MDC_: /* Process markup declaration comment. */
+ if (*FPOS!=lex.d.mdc)
+ parsemd(tbuf, NAMECASE, (struct parse *)0, NAMELEN);
+ continue;
+
+ case MSS_: /* Process marked section start. */
+ conpcb = mdms(tbuf, conpcb);
+ continue;
+ case MSE_: /* Process marked section end (drop to LOP_). */
+ if (mdmse()) conpcb = getpcb((int)ETDCON);
+ continue;
+
+ case PIS_: /* Return processing instruction (string). */
+ if (entpisw) rcbdafp->data = data;
+ else {
+ parselit(tbuf, &pcblitc, PILEN, lex.d.pic);
+ rcbdafp->data = tbuf;
+ }
+ rcbdafp->datalen = datalen;
+ rcbdafp->contersw = entpisw;
+ entpisw = 0; /* Reset for next time.*/
+ scbset(); /* Update location in current scb. */
+ return SGMLPIS;
+
+ case APP_:
+ rcbdafp->data = tbuf;
+ rcbdafp->datalen = ustrlen(tbuf);
+ rcbdafp->contersw = 0;
+ scbset();
+ return SGMLAPP;
+ case ETG_: /* Return end-tag. */
+ charmode = 0; /* Not in char mode unless CDATA or RCDATA.*/
+ if (msplevel==0) conpcb = getpcb((int)ETDCON);
+ rcbtagp->contersw = tags[ts+1].tflags;
+ rcbtagp->tagmin = etagimsw ? MINETAG : etagmin;
+ rcbtagp->curgi = tags[ts+1].tetd->etdgi;
+ rcbtagp->ru.oldgi = tags[ts].tetd->etdgi;
+ if (etagmin==MINSTAG) rcbtagp->tagreal =
+ BADPTR(stagreal) ? stagreal : (PETD)stagreal->etdgi;
+ else rcbtagp->tagreal =
+ BADPTR(etagreal) ? etagreal : (PETD)etagreal->etdgi;
+ rcbtagp->etictr = etictr;
+ rcbtagp->srmnm = tags[ts].tsrm!=SRMNULL ? tags[ts].tsrm[0]->ename
+ : 0;
+ scbset(); /* Update location in current scb. */
+ return SGMLETG;
+
+ case STG_: /* Return start-tag. */
+ charmode = 0; /* Not in char mode unless CDATA or RCDATA.*/
+ if (!conrefsw && msplevel==0) conpcb = getpcb((int)ETDCON);
+ rcbtagp->contersw = tags[ts].tflags;
+ rcbtagp->tagmin = dostag ? MINSTAG : stagmin;
+ rcbtagp->curgi = tags[ts].tetd->etdgi;
+ /* Get attribute list if one was defined for this element. */
+ rcbtagp->ru.al = !tags[ts].tetd->adl ? 0 :
+ rcbtagp->tagmin==MINNONE ? al : tags[ts].tetd->adl;
+ rcbtagp->tagreal = BADPTR(stagreal)?stagreal:(PETD)stagreal->etdgi;
+ rcbtagp->etictr = etictr;
+ rcbtagp->srmnm = tags[ts].tsrm!=SRMNULL ? tags[ts].tsrm[0]->ename
+ : 0;
+ scbset(); /* Update location in current scb. */
+ return SGMLSTG;
+
+ case DAF_: /* Return data in source entity buffer. */
+ charmode = 1;
+ rcbdafp->datalen = datalen;
+ rcbdafp->data = data;
+ rcbdafp->contersw = contersw | entdatsw;
+ contersw = entdatsw = 0;/* Reset for next time.*/
+ scbset(); /* Update location in current scb. */
+ return SGMLDAF;
+
+ case CON_: /* Process conact after returning REF_. */
+ conactsw = 1;
+ contersv = contersw;
+ case REF_: /* Return RE found. */
+ if (badresw) {
+ badresw = 0;
+ sgmlerr(E_CHARS, &pcbconm, tags[ts].tetd->etdgi+1, (UNCH *)0);
+ continue;
+ }
+ charmode = 1;
+ rcbdafp->contersw = contersw;
+ contersw = 0; /* Reset for next time.*/
+ scbset(); /* Update location in current scb. */
+ return SGMLREF;
+
+ case EOD_: /* End of source document entity. */
+ if (mslevel != 0) sgmlerr(139, conpcb, (UNCH *)0, (UNCH *)0);
+ idrck(); /* Check idrefs. */
+ scbset(); /* Update location in current scb. */
+ return SGMLEOD;
+
+ default: /* LOP_: Loop again with no action. */
+ continue;
+ }
+ }
+}
+/* PCBSGML: State and action table for action codes returned to text processor
+ by SGML.C.
+ Columns are based on SGMLACT.H values minus DAF_, except that end
+ of document has input code LOP_, regardless of its action code.
+*/
+/* Symbols for state names (end with a number). */
+#define ST1 0 /* Just had a start tag. */
+#define NR1 2 /* Just had an RS or RE. */
+#define DA1 4 /* Just had some data. */
+#define NR2 6 /* Just had an RE; RE pending. */
+#define ST2 8 /* Had only markup since last RE/RS; RE pending. */
+
+static UNCH sgmltab[][11] = {
+/*daf_ etg_ md_ mdc_ mss_ mse_ pis_ ref_ stg_ rsr_ eod */
+ {DA1 ,DA1 ,ST1 ,ST1 ,ST1 ,ST1 ,ST1 ,NR1 ,ST1 ,NR1 ,ST1 },/*st1*/
+ {DAF_,ETG_,MD_ ,MDC_,MSS_,MSE_,PIS_,LOP_,STG_,LOP_,EOD_},
+
+ {DA1 ,DA1 ,ST1 ,ST1 ,ST1 ,ST1 ,ST1 ,NR2 ,ST1 ,NR1 ,ST1 },/*nr1*/
+ {DAF_,ETG_,MD_ ,MDC_,MSS_,MSE_,PIS_,LOP_,STG_,LOP_,EOD_},
+
+ {DA1 ,DA1 ,DA1 ,DA1 ,DA1 ,DA1 ,DA1 ,NR2 ,ST1 ,NR1 ,ST1 },/*da1*/
+ {DAF_,ETG_,MD_ ,MDC_,MSS_,MSE_,PIS_,LOP_,STG_,LOP_,EOD_},
+
+ {DA1 ,DA1 ,ST2 ,ST2 ,ST2 ,ST2 ,ST2 ,NR2 ,ST1 ,NR2 ,ST1 },/*nr2*/
+ {CON_,ETG_,MD_ ,MDC_,MSS_,MSE_,PIS_,REF_,CON_,LOP_,EOD_},
+
+ {DA1 ,DA1 ,ST2 ,ST2 ,ST2 ,ST2 ,ST2 ,NR2 ,ST1 ,NR2 ,ST1 },/*st2*/
+ {CON_,ETG_,MD_ ,MDC_,MSS_,MSE_,PIS_,LOP_,CON_,LOP_,EOD_},
+};
+int scbsgmst = ST1; /* SCBSGML: trailing stag or markup; ignore RE. */
+int scbsgmnr = NR1; /* SCBSGML: new record; do not ignore RE. */
+/* SGMLACT: Determine action to be taken by SGML.C based on current state and
+ specified input.
+ For start or end of a plus exception element, push or pop the
+ pcbsgml stack.
+ Return to caller with action code.
+*/
+#ifdef USE_PROTOTYPES
+int sgmlact(UNCH conret)
+#else
+int sgmlact(conret)
+UNCH conret; /* Action returned to SGML.C by content parse. */
+#endif
+{
+ int action;
+
+ if (conret==STG_ && GET(tags[ts].tflags, TAGPEX))
+ {++pss; scbsgml[pss].snext = ST1;}
+ scbsgml[pss].sstate = scbsgml[pss].snext;
+ scbsgml[pss].snext = sgmltab[scbsgml[pss].sstate]
+ [scbsgml[pss].sinput = conret-DAF_];
+ scbsgml[pss].saction = sgmltab[scbsgml[pss].sstate+1][scbsgml[pss].sinput];
+ TRACEGML(scbsgml, pss, conactsw, conact);
+ action = scbsgml[pss].saction;
+ if (conret==ETG_ && GET(tags[ts+1].tflags, TAGPEX)) {
+ pss--;
+ /* An included subelement affects the enclosing state like a
+ processing instruction (or MDC_ or MD_),
+ that is to say NR1 is changed to ST1 and NR2 to ST2. */
+ scbsgml[pss].sstate = scbsgml[pss].snext;
+ scbsgml[pss].snext = sgmltab[scbsgml[pss].sstate][PIS_ - DAF_];
+ }
+ return action;
+}
+/* GETPCB: Choose pcb for new or resumed element.
+*/
+struct parse *getpcb(etdcon)
+int etdcon; /* Content type of new or resumed element. */
+{
+ if (BITON(etdcon, MGI)) {
+ return(BITON(etdcon, MCHARS) ? &pcbconm : &pcbcone);
+ }
+ if (BITON(etdcon, MCDATA) || BITON(etdcon, MRCDATA)) {
+ charmode = 1;
+ return(BITON(etdcon, MCDATA) ? &pcbconc : (rcessv = es, &pcbconr));
+ }
+ return(&pcbconm);
+}
+
+struct markup *sgmlset(swp)
+struct switches *swp;
+{
+ /* Initialize variables based on switches structure members. */
+ sw = *swp;
+ rbufs = (UNCH *)rmalloc((UNS)3+sw.swbufsz) + 3; /* DOS file read area. */
+ TRACEPRO(); /* Set trace switches for prolog. */
+ msginit(swp);
+ ioinit(swp);
+ entginit(swp);
+ sdinit();
+ return &lex.m;
+}
+
+/* Points for each capacity, indexed by *CAP in sgmldecl.h. We'll replace
+2 with the real NAMELEN at run time. */
+
+static UNCH cappoints[] = {
+ 1,
+ 2,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 2,
+ 2,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2
+};
+
+static long capnumber[NCAPACITY];
+static long maxsubcap[NCAPACITY];
+
+VOID sgmlend(p)
+struct sgmlcap *p;
+{
+ int i;
+ for (; es >= 0; --es)
+ if (FILESW)
+ fileclos();
+
+ capnumber[NOTCAP] = ds.dcncnt;
+ capnumber[EXGRPCAP] = ds.pmexgcnt;
+ capnumber[ELEMCAP] = ds.etdcnt+ds.etdercnt;
+ capnumber[EXNMCAP] = ds.pmexcnt;
+ capnumber[GRPCAP] = ds.modcnt;
+ capnumber[ATTCAP] = ds.attcnt;
+ capnumber[ATTCHCAP] = ds.attdef;
+ capnumber[AVGRPCAP] = ds.attgcnt;
+ capnumber[IDCAP] = ds.idcnt;
+ capnumber[IDREFCAP] = ds.idrcnt;
+ capnumber[ENTCAP] = ds.ecbcnt;
+ capnumber[ENTCHCAP] = ds.ecbtext;
+ capnumber[MAPCAP] = ds.srcnt + ds.srcnt*lex.s.dtb[0].mapdata;
+ capnumber[NOTCHCAP] = ds.dcntext;
+
+ capnumber[TOTALCAP] = 0;
+
+ for (i = 1; i < NCAPACITY; i++) {
+ if (cappoints[i] > 1)
+ cappoints[i] = NAMELEN;
+ capnumber[i] += maxsubcap[i]/cappoints[i];
+ capnumber[TOTALCAP] += (long)capnumber[i] * cappoints[i];
+ }
+ p->number = capnumber;
+ p->points = cappoints;
+ p->limit = sd.capacity;
+ p->name = captab;
+
+ if (sw.swcap) {
+ for (i = 0; i < NCAPACITY; i++) {
+ long excess = capnumber[i]*cappoints[i] - sd.capacity[i];
+ if (excess > 0) {
+ char buf[sizeof(long)*3 + 1];
+ sprintf(buf, "%ld", excess);
+ sgmlerr(162, (struct parse *)0,
+ (UNCH *)captab[i], (UNCH *)buf);
+ }
+ }
+ }
+}
+
+VOID sgmlsubcap(v)
+long *v;
+{
+ int i;
+ for (i = 0; i < NCAPACITY; i++)
+ if (v[i] > maxsubcap[i])
+ maxsubcap[i] = v[i];
+}
+
+int sgmlsdoc(ptr)
+UNIV ptr;
+{
+ struct entity *e;
+ union etext etx;
+ etx.x = ptr;
+
+ e = entdef(indocent, ESF, &etx);
+ if (!e)
+ return -1;
+ return entopen(e);
+}
+
+/* SGMLGENT: Get a data entity.
+ Returns:
+ -1 if the entity does not exist
+ -2 if it is not a data entity
+ 1 if it is an external entity
+ 2 if it is an internal cdata entity
+ 3 if it is an internal sdata entity
+*/
+int sgmlgent(iname, np, tp)
+UNCH *iname;
+PNE *np;
+UNCH **tp;
+{
+ PECB ep; /* Pointer to an entity control block. */
+
+ ep = entfind(iname);
+ if (!ep)
+ return -1;
+ switch (ep->estore) {
+ case ESN:
+ if (np)
+ *np = ep->etx.n;
+ return 1;
+ case ESC:
+ if (tp)
+ *tp = ep->etx.c;
+ return 2;
+ case ESX:
+ if (tp)
+ *tp = ep->etx.c;
+ return 3;
+ }
+ return -2;
+}
+
+/* Mark an entity. */
+
+int sgmlment(iname)
+UNCH *iname;
+{
+ PECB ep;
+ int rc;
+
+ ep = entfind(iname);
+ if (!ep)
+ return -1;
+ rc = ep->mark;
+ ep->mark = 1;
+ return rc;
+}
+
+int sgmlgcnterr()
+{
+ return msgcnterr();
+}
+
+char *getsubst()
+{
+ return (char *)lextran;
+}
+
+/* This is for error handling functions that want to print a gi backtrace. */
+
+UNCH *getgi(i)
+int i;
+{
+ return i >= 0 && i <= ts ? tags[i].tetd->etdgi + 1 : NULL;
+}
+
+/* Returns the value of prologsw for the use by error handling functions. */
+
+int inprolog()
+{
+ return prologsw;
+}
+
+/* Used by the error handling functions to access scbs. */
+
+int getlocation(level, locp)
+int level;
+struct location *locp;
+{
+ if (level < 0 || level > es)
+ return 0;
+ if (locp) {
+ int es = level;
+ /* source macros access a variable called `es' */
+
+ locp->filesw = FILESW;
+ locp->rcnt = RCNT;
+ locp->ccnt = CCNT;
+ locp->ename = ENTITY + 1;
+ locp->fcb = SCBFCB;
+ locp->curchar = CC;
+ locp->nextchar = NEXTC;
+ }
+ return 1;
+}
+
+int sgmlloc(linenop, filenamep)
+unsigned long *linenop;
+char **filenamep;
+{
+ int level = es;
+ int es;
+
+ for (es = level; es >= 0 && !FILESW; es--)
+ ;
+ if (es < 0)
+ return 0;
+ *linenop = RCNT;
+ *filenamep = ioflid(SCBFCB);
+ return 1;
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgml2.c b/usr.bin/sgmls/sgmls/sgml2.c
new file mode 100644
index 0000000..df75b6a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgml2.c
@@ -0,0 +1,522 @@
+/* Added exiterr() for terminal errors to prevent SGML.MSG errors. */
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+static int iorc; /* Return code from io* functions */
+/* ENTDEF: Process an entity definition and return the pointer to it.
+ The entity text must be in permanent storage.
+ There is no checking to see if the entity already exists;
+ the caller must have done that.
+*/
+#ifdef USE_PROTOTYPES
+PECB entdef(UNCH *ename, UNCH estore, union etext *petx)
+#else
+PECB entdef(ename, estore, petx)
+UNCH *ename; /* Entity name (with length and EOS). */
+UNCH estore; /* Entity storage class. */
+union etext *petx; /* Ptr to entity text union. */
+#endif
+{
+ PECB p;
+
+ p = (PECB)hin((THASH)etab, ename, hash(ename, ENTHASH), ENTSZ);
+ memcpy((UNIV)&p->etx, (UNIV)petx, ETEXTSZ);
+ p->estore = estore;
+ TRACEECB("ENTDEF", p);
+ return(p);
+}
+/* ENTFIND: If an entity exists, return ptr to its ecb.
+ Return NULL if it is not defined.
+*/
+PECB entfind(ename)
+UNCH *ename; /* Entity name (with length and EOS). */
+{
+ PECB p;
+
+ p = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH));
+ TRACEECB("ENTFIND", p);
+ return p;
+}
+/* ENTREF: Process a general or parameter entity reference.
+ If the entity is defined it returns the return code from ENTOPEN.
+ It returns ENTUNDEF for undefined parameter entity references
+ and for general entity references when defaulting is not allowed.
+ Otherwise, it uses the default entity text.
+*/
+int entref(ename)
+UNCH *ename; /* Entity name (with length and EOS). */
+{
+ PECB ecb; /* Entity control block. */
+
+ /* Get the entity control block, if the entity has been defined. */
+ if ((ecb = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH)))==0
+ || ecb->estore == 0) {
+ if (ename[1] == lex.d.pero || ecbdeflt == 0) {
+ sgmlerr(35, (struct parse *)0, ename+1, (UNCH *)0);
+ return(ENTUNDEF);
+ }
+ else
+ ecb = usedef(ename);
+ }
+ return(entopen(ecb));
+}
+/* ENTOPEN: Open a newly referenced entity.
+ Increment the stack pointer (es) and initialize the new entry.
+ ENTDATA if entity is CDATA or SDATA, ENTPI if it is PI,
+ 0 if normal and all o.k.; <0 if not.
+*/
+int entopen(ecb)
+struct entity *ecb; /* Entity control block. */
+{
+ int i; /* Loop counter. */
+
+ /* See if we have exceeded the entity nesting level. */
+ if (es>=ENTLVL) {
+ sgmlerr(34, (struct parse *)0, ecb->ename+1, ntoa(ENTLVL));
+ return(ENTMAX);
+ }
+ if (docelsw) sgmlerr(234, (struct parse *)0, (UNCH *)0, (UNCH *)0);
+ /* If entity is an etd, pi, or data, return it without creating an scb. */
+ switch (ecb->estore) {
+ case ESN:
+ if (NEXTYPE(ecb->etx.n)!=ESNSUB) {
+ if (!NEDCNDEFINED(ecb->etx.n))
+ sgmlerr(78, (struct parse *)0, NEDCN(ecb->etx.n)+1,
+ ecb->ename+1);
+ }
+ else {
+#if 0
+ if (!NEID(ecb->etx.n)) {
+ sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
+ return ENTFILE;
+ }
+#endif
+ if (sw.nopen >= sd.subdoc)
+ sgmlerr(188, (struct parse *)0,
+ (UNCH *)NULL, (UNCH *)NULL);
+ }
+ data = (UNCH *)ecb->etx.n;
+ entdatsw = NDECONT;
+ return(ENTDATA);
+ case ESC:
+ case ESX:
+ datalen = ustrlen(ecb->etx.c);
+ /* Ignore reference to empty CDATA entity. */
+ if (datalen == 0 && ecb->estore == ESC) return(0);
+ data = ecb->etx.c;
+ entdatsw = (ecb->estore==ESC) ? CDECONT : SDECONT;
+ return(ENTDATA);
+ case ESI:
+ datalen = ustrlen(ecb->etx.c);
+ data = ecb->etx.c;
+ entpisw = 4;
+ return(ENTPI);
+ }
+ /* If the same entity is already open, send msg and ignore it.
+ Level 0 needn't be tested, as its entity name is always *DOC.
+ */
+ for (i = 0; ++i<=es;) if (scbs[i].ecb.enext==ecb) {
+ sgmlerr(36, (struct parse *)0, ecb->ename+1, (UNCH *)0);
+ return(ENTLOOP);
+ }
+ /* Update SCB if entity trace is wanted in messages or entity is a file.
+ (Avoid this at start when es==-1 or memory will be corrupted.)
+ */
+ if (es >= 0 && (sw.swenttr || FILESW)) scbset();
+
+ /* Stack the new source control block (we know there is room). */
+ ++es; /* Increment scbs index. */
+ RCNT = CCO = RSCC = 0; /* No records or chars yet. */
+ COPIEDSW = 0;
+ memcpy((UNIV)&ECB, (UNIV)ecb, (UNS)ENTSZ); /* Copy the ecb into the scb. */
+ ECBPTR = ecb; /* Save the ecb pointer in scb.ecb.enext. */
+ TRACEECB("ENTOPEN", ECBPTR);
+
+ /* For memory entities, the read buffer is the entity text.
+ The text starts at FBUF, so FPOS should be FBUF-1
+ because it is bumped before each character is read.
+ */
+ if (ECB.estore<ESFM) {FPOS = (FBUF = ECB.etx.c)-1; return 0;}
+
+ /* For file entities, suspend any open file and do first read. */
+ if (ECB.etx.x == 0) {
+ --es;
+ switch (ecb->estore) {
+ case ESF:
+ sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
+ break;
+ case ESP:
+ sgmlerr(229, (struct parse *)0, ecb->ename + 2, (UNCH *)0);
+ break;
+ default:
+ abort();
+ }
+ return ENTFILE;
+ }
+ fileopen(); /* Open new external file. */
+ if (iorc<0) { /* If open not successful: */
+ FPOS = FBUF-1; /* Clean CCNT for OPEN error msg.*/
+ filerr(32, ecb->ename+1);
+ --es; /* Pop the stack. */
+ return(ENTFILE);
+ }
+ filepend(es); /* Suspend any open file. */
+ fileread(); /* First read of file must be ok.*/
+ return 0;
+}
+/* ENTGET: Get next record of entity (if there is one).
+ Otherwise, close the file (if entity is a file) and
+ pop the entity stack. If nothing else is on the stack,
+ return -1 to advise the caller.
+*/
+int entget()
+{
+ RSCC += (CCO = FPOS-FBUF);
+ /* Characters-in-record (ignore EOB/EOF). */
+ if (es == tages)
+ tagctr += CCO; /* Update tag length counter. */
+ switch (*FPOS) {
+ case EOBCHAR: /* End of file buffer: refill it. */
+ rbufs[-2] = FPOS[-2];
+ rbufs[-1] = FPOS[-1];
+ fileread(); /* Read the file. */
+ if (iorc > 0) break;
+ readerr:
+ filerr(31, ENTITY+1); /* Treat error as EOF. */
+ case EOFCHAR: /* End of file: close it. */
+ fileclos(); /* Call SGMLIO to close file. */
+ conterr:
+ if (es==0) { /* Report if it is primary file. */
+ FPOS = FBUF-1; /* Preserve CCNT for omitted end-tags. */
+ return -1;
+ }
+ case EOS: /* End of memory entity: pop the stack. */
+ TRACEECB("ENTPOP", ECBPTR);
+ if (COPIEDSW) {
+ frem((UNIV)(FBUF + 1));
+ COPIEDSW = 0;
+ }
+ --es; /* Pop the SCB stack. */
+ if (FBUF) break; /* Not a PEND file. */
+ filecont(); /* Resume previous file. */
+ if (iorc<0) { /* If CONT not successful: */
+ filerr(94, ENTITY+1);
+ goto conterr;
+ }
+ fileread(); /* Read the file. */
+ if (iorc<=0) goto readerr; /* If READ not successful: */
+ rbufs[-1] = SCB.pushback;
+ FPOS += CCO;
+ CCO = 0;
+ if (delmscsw && es==0) { /* End of DTD. */
+ delmscsw = 0;
+ *rbufs = lex.d.msc;
+ }
+ break;
+ }
+ return 0;
+}
+/* USEDEF: Use the default value for an entity reference.
+ Returns the ECB for the defaulted entity.
+*/
+PECB usedef(ename)
+UNCH *ename; /* Entity name (with length and EOS). */
+{
+ union etext etx; /* Save return from entgen. */
+ PECB ecb; /* Entity control block. */
+ PNE pne = 0; /* Ptr to NDATA entity control block. */
+ UNCH estore; /* Default entity storage type. */
+
+ if ((estore = ecbdeflt->estore)<ESFM) /* Default is an internal string. */
+ etx.c = ecbdeflt->etx.c;
+ else {
+ /* Move entity name into fpi. */
+ fpidf.fpinm = ename + 1;
+ if ((etx.x = entgen(&fpidf))==0)
+ sgmlerr(150, (struct parse *)0, ename + 1, (UNCH *)0);
+ if (estore==ESN) {
+ memcpy((UNIV)(pne=(PNE)rmalloc((UNS)NESZ)),(UNIV)ecbdeflt->etx.n,(UNS)NESZ);
+ NEID(pne) = etx.x;
+ etx.n = pne;
+ }
+ }
+ if (sw.swrefmsg) sgmlerr(45, (struct parse *)0, ename+1, (UNCH *)0);
+ ++ds.ecbcnt;
+ ecb = entdef(ename, estore, &etx);
+ ecb->dflt = 1;
+ if (pne) NEENAME(pne) = ecb->ename;
+ return(ecb);
+}
+/* SCBSET: Set source control block to current location in the current entity.
+ This routine is called by SGML when it returns to the text
+ processor and by ERROR when it reports an error.
+*/
+VOID scbset()
+{
+ if (es >= 0 && FBUF) {
+ CC = *FPOS;
+ if (*FPOS == DELNONCH)
+ NEXTC = FPOS[1];
+ else
+ NEXTC = 0;
+ CCO = FPOS + 1 - FBUF;
+ }
+}
+/* FILEOPEN: Call IOOPEN to open an external entity (file).
+*/
+VOID fileopen() /* Open an external entity's file. */
+{
+ iorc = ioopen(ECB.etx.x, &SCBFCB);
+}
+/* FILEREAD: Call IOREAD to read an open external entity (file).
+*/
+VOID fileread() /* Read the current external entity's file. */
+{
+ int newfile;
+ iorc = ioread(SCBFCB, rbufs, &newfile);
+ FPOS = (FBUF = rbufs) - 1; /* Actual read buffer. */
+ if (newfile) RCNT = 0;
+}
+/* FILEPEND: Call IOPEND to close an open external entity (file) temporarily.
+*/
+VOID filepend(es) /* Close the current external entity's file. */
+int es; /* Local index to scbs. */
+{
+ while (--es>=0) { /* Find last external file on stack. */
+ int off;
+ if (!FILESW) continue; /* Not an external file. */
+ if (!FBUF) continue; /* Already suspended. */
+ off = CCO;
+ assert(off >= -1);
+ if (off < 0) off = 0;
+ else CCO = 0;
+ FPOS -= CCO;
+ SCB.pushback = FPOS[-1];
+ FBUF = 0; /* Indicate pending file. */
+ RSCC += off; /* Update characters-in-record counter. */
+ if (es == tages)
+ tagctr += off; /* Update tag length counter. */
+ iopend(SCBFCB, off, rbufs);
+ return;
+ }
+}
+/* FILECONT: Call IOCONT to reopen an external entity (file).
+*/
+VOID filecont() /* Open an external entity's file. */
+{
+ iorc = iocont(SCBFCB);
+}
+/* FILECLOS: Call IOCLOSE to close an open external entity (file).
+*/
+VOID fileclos() /* Close the current external entity's file. */
+{
+ if (!SCBFCB)
+ return;
+ ioclose(SCBFCB);
+ /* The fcb will have been freed by sgmlio.
+ Make sure we don't access it again. */
+ SCBFCB = NULL;
+}
+/* ERROR: Interface to text processor SGML I/O services for error handling.
+*/
+VOID error(e)
+struct error *e;
+{
+ scbset(); /* Update location in source control block. */
+ msgprint(e);
+}
+/* PTRSRCH: Find a pointer in a list and return its index.
+ Search key must be on list as there is no limit test.
+ This routine is internal only -- not for user data.
+*/
+UNIV mdnmtab[] = {
+ (UNIV)key[KATTLIST],
+ (UNIV)key[KDOCTYPE],
+ (UNIV)key[KELEMENT],
+ (UNIV)key[KENTITY],
+ (UNIV)key[KLINKTYPE],
+ (UNIV)key[KLINK],
+ (UNIV)key[KNOTATION],
+ (UNIV)sgmlkey,
+ (UNIV)key[KSHORTREF],
+ (UNIV)key[KUSELINK],
+ (UNIV)key[KUSEMAP]
+};
+UNIV pcbtab[] = {
+ (UNIV)&pcbconc,
+ (UNIV)&pcbcone,
+ (UNIV)&pcbconm,
+ (UNIV)&pcbconr,
+ (UNIV)&pcbetag,
+ (UNIV)&pcbgrcm,
+ (UNIV)&pcbgrcs,
+ (UNIV)&pcbgrnm,
+ (UNIV)&pcbgrnt,
+ (UNIV)&pcblitc,
+ (UNIV)&pcblitp,
+ (UNIV)&pcblitr,
+ (UNIV)&pcblitt,
+ (UNIV)&pcblitv,
+ (UNIV)&pcbmd,
+ (UNIV)&pcbmdc,
+ (UNIV)&pcbmdi,
+ (UNIV)&pcbmds,
+ (UNIV)&pcbmsc,
+ (UNIV)&pcbmsi,
+ (UNIV)&pcbmsrc,
+ (UNIV)&pcbpro,
+ (UNIV)&pcbref,
+ (UNIV)&pcbstag,
+ (UNIV)&pcbval,
+ (UNIV)&pcbeal,
+ (UNIV)&pcbsd,
+};
+UNS ptrsrch(ptrtab, ptr)
+UNIV ptrtab[];
+UNIV ptr;
+{
+ UNS i;
+
+ for (i = 0; ; ++i)
+ if (ptrtab[i] == ptr)
+ break;
+ return i;
+}
+/* MDERR: Process errors for markup declarations.
+ Prepare the special parameters that only exist for
+ markup declaration errors.
+*/
+VOID mderr(number, parm1, parm2)
+UNS number; /* Error number. */
+UNCH *parm1; /* Additional parameters (or NULL). */
+UNCH *parm2; /* Additional parameters (or NULL). */
+{
+ struct error err;
+ errorinit(&err, subdcl ? MDERR : MDERR2, number);
+ err.parmno = parmno;
+ err.subdcl = subdcl;
+ err.eparm[0] = (UNIV)parm1;
+ err.eparm[1] = (UNIV)parm2;
+ err.errsp = (sizeof(pcbtab)/sizeof(pcbtab[0])) + ptrsrch(mdnmtab,
+ (UNIV)mdname);
+ error(&err);
+}
+/* SGMLERR: Process errors for SGML parser.
+*/
+VOID sgmlerr(number, pcb, parm1, parm2)
+UNS number; /* Error number. */
+struct parse *pcb; /* Current parse control block. */
+UNCH *parm1; /* Error message parameters. */
+UNCH *parm2; /* Error message parameters. */
+{
+ struct error err;
+ errorinit(&err, DOCERR, number);
+ if (!pcb) pcb = prologsw ? propcb : conpcb;
+ err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
+ err.eparm[0] = (UNIV)parm1;
+ err.eparm[1] = (UNIV)parm2;
+ error(&err);
+}
+/* SAVERR: Save an error for possible later use.
+*/
+UNIV saverr(number, pcb, parm1, parm2)
+UNS number; /* Error number. */
+struct parse *pcb; /* Current parse control block. */
+UNCH *parm1; /* Error message parameters. */
+UNCH *parm2; /* Error message parameters. */
+{
+ struct error err;
+ errorinit(&err, DOCERR, number);
+ if (!pcb) pcb = prologsw ? propcb : conpcb;
+ err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
+ err.eparm[0] = (UNIV)parm1;
+ err.eparm[1] = (UNIV)parm2;
+ scbset();
+ return msgsave(&err);
+}
+/* SAVMDERR: Save an md error for possible later use.
+*/
+UNIV savmderr(number, parm1, parm2)
+UNS number; /* Error number. */
+UNCH *parm1; /* Additional parameters (or NULL). */
+UNCH *parm2; /* Additional parameters (or NULL). */
+{
+ struct error err;
+ errorinit(&err, subdcl ? MDERR : MDERR2, number);
+ err.parmno = parmno;
+ err.subdcl = subdcl;
+ err.eparm[0] = (UNIV)parm1;
+ err.eparm[1] = (UNIV)parm2;
+ err.errsp = (sizeof(pcbtab)/sizeof(pcbtab[0])) + ptrsrch(mdnmtab,
+ (UNIV)mdname);
+ scbset();
+ return msgsave(&err);
+}
+/* SVDERR: Print a saved error.
+*/
+VOID svderr(p)
+UNIV p;
+{
+ msgsprint(p);
+}
+/* EXITERR: Process terminal errors for SGML parser.
+*/
+VOID exiterr(number, pcb)
+UNS number; /* Error number. */
+struct parse *pcb; /* Current parse control block. */
+{
+ struct error err;
+ errorinit(&err, EXITERR, number);
+ if (!pcb) pcb = prologsw ? propcb : conpcb;
+ err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
+ error(&err);
+ /* The error handler should have exited. */
+ abort();
+}
+/* SYNERR: Process syntax errors for SGML parser.
+*/
+VOID synerr(number, pcb)
+UNS number; /* Error number. */
+struct parse *pcb; /* Current parse control block. */
+{
+ struct error err;
+ errorinit(&err, DOCERR, number);
+ err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
+ error(&err);
+}
+/* FILERR: Process a file access error.
+*/
+VOID filerr(number, parm)
+UNS number;
+UNCH *parm;
+{
+ struct error err;
+ errorinit(&err, FILERR, number);
+ err.eparm[0] = (UNIV)parm;
+ err.sverrno = errno;
+ error(&err);
+}
+/* ERRORINIT: Constructor for struct error.
+*/
+VOID errorinit(e, type, number)
+struct error *e;
+UNS type;
+UNS number;
+{
+ int i;
+ e->errtype = type;
+ e->errnum = number;
+ e->errsp = 0;
+ for (i = 0; i < MAXARGS; i++)
+ e->eparm[i] = 0;
+ e->parmno = 0;
+ e->subdcl = 0;
+}
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgmlaux.h b/usr.bin/sgmls/sgmls/sgmlaux.h
new file mode 100644
index 0000000..6073e66
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlaux.h
@@ -0,0 +1,72 @@
+/* This file controls the interface between the parser core and the auxiliary
+functions in entgen.c, sgmlio.c, and sgmlmsg.c */
+
+#include "std.h"
+#include "entity.h"
+#include "sgmldecl.h"
+
+/* Error types (ERRTYPE) for calls to error-handling services
+ performed for SGML by the text processor (SGMLIO).
+ NOTE: Strings in these blocks have no lengths, but cannot exceed
+ NAMELEN (plus 1 more byte for the zero terminator).
+*/
+#define FILERR 0 /* Error: file access. */
+#define DOCERR 1 /* Error: in document markup. */
+#define MDERR 2 /* Error: in markup declaration with subdcl. */
+#define MDERR2 3 /* Error: in markup declaration with no subdcl. */
+#define EXITERR 4 /* Error: terminal error in document markup. */
+/* Quantities affecting error messages and their arguments.
+*/
+#define MAXARGS 2 /* Maximum number of arguments in a msg. */
+
+/* NOTE: Error handler must return, or next call to SGML must be RSET or END,
+ except for EXITERR errors which must not return.
+*/
+struct error { /* IPB for error messages. */
+ UNS errtype; /* Type of error: DOC, MD, MD2, FIL. */
+ UNS errnum; /* Error number. */
+ UNS errsp; /* Special parameter index in message file. */
+ int sverrno; /* Saved value of errno. */
+ int parmno; /* MDERROR: declaration parameter number. */
+ UNCH *subdcl; /* MDERROR: subject of declaration. */
+ UNIV eparm[MAXARGS]; /* Ptrs to arguments (no length, but EOS). */
+};
+
+struct location {
+ int filesw;
+ unsigned long rcnt;
+ int ccnt;
+ UNCH curchar;
+ UNCH nextchar;
+ UNCH *ename;
+ UNIV fcb;
+};
+
+int ioopen P((UNIV, UNIV*));
+VOID ioclose P((UNIV));
+int ioread P((UNIV, UNCH *, int *));
+VOID iopend P((UNIV, int, UNCH *));
+int iocont P((UNIV));
+VOID ioinit P((struct switches *));
+char *ioflid P((UNIV));
+
+UNIV entgen P((struct fpi *));
+VOID entginit P((struct switches *));
+
+VOID msgprint P((struct error *));
+VOID msginit P((struct switches *));
+UNIV msgsave P((struct error *));
+VOID msgsprint P((UNIV));
+VOID msgsfree P((UNIV));
+int msgcnterr P((void));
+
+
+int inprolog P((void));
+UNCH *getgi P((int));
+
+int getlocation P((int, struct location *));
+UNIV rmalloc P((unsigned int));
+UNIV rrealloc P((UNIV, UNS));
+VOID frem P((UNIV));
+VOID exiterr P((unsigned int,struct parse *));
+char *getsubst P((void));
diff --git a/usr.bin/sgmls/sgmls/sgmldecl.c b/usr.bin/sgmls/sgmls/sgmldecl.c
new file mode 100644
index 0000000..6ef6b68
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmldecl.c
@@ -0,0 +1,1804 @@
+/* sgmldecl.c -
+ SGML declaration parsing.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "sgmlincl.h"
+
+/* Symbolic names for the error numbers that are be generated only by
+this module. */
+
+#define E_SHUNCHAR 159
+#define E_STANDARD 163
+#define E_SIGNIFICANT 164
+#define E_BADLIT 165
+#define E_SCOPE 166
+#define E_XNUM 167
+#define E_BADVERSION 168
+#define E_NMUNSUP 169
+#define E_XNMLIT 170
+#define E_CHARDESC 171
+#define E_CHARDUP 172
+#define E_CHARRANGE 173
+#define E_7BIT 174
+#define E_CHARMISSING 175
+#define E_SHUNNED 176
+#define E_NONSGML 177
+#define E_CAPSET 178
+#define E_CAPMISSING 179
+#define E_SYNTAX 180
+#define E_CHARNUM 181
+#define E_SWITCHES 182
+#define E_INSTANCE 183
+#define E_ZEROFEATURE 184
+#define E_YESNO 185
+#define E_CAPACITY 186
+#define E_NOTSUPPORTED 187
+#define E_FORMAL 189
+#define E_BADCLASS 190
+#define E_MUSTBENON 191
+#define E_BADBASECHAR 199
+#define E_SYNREFUNUSED 200
+#define E_SYNREFUNDESC 201
+#define E_SYNREFUNKNOWN 202
+#define E_SYNREFUNKNOWNSET 203
+#define E_FUNDUP 204
+#define E_BADFUN 205
+#define E_FUNCHAR 206
+#define E_GENDELIM 207
+#define E_SRDELIM 208
+#define E_BADKEY 209
+#define E_BADQUANTITY 210
+#define E_BADNAME 211
+#define E_REFNAME 212
+#define E_DUPNAME 213
+#define E_QUANTITY 214
+#define E_QTOOBIG 215
+#define E_NMSTRTCNT 219
+#define E_NMCHARCNT 220
+#define E_NMDUP 221
+#define E_NMBAD 222
+#define E_NMMINUS 223
+#define E_UNKNOWNSET 227
+#define E_TOTALCAP 235
+
+#define CANON_NMC '.' /* Canonical name character. */
+#define CANON_NMS 'A' /* Canonical name start character. */
+#define CANON_MIN ':' /* Canonical minimum data character. */
+
+#define SUCCESS 1
+#define FAIL 0
+#define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
+#define matches(tok, str) (ustrcmp((tok)+1, (str)) == 0)
+
+static UNCH standard[] = "ISO 8879:1986";
+
+#define REFERENCE_SYNTAX "ISO 8879:1986//SYNTAX Reference//EN"
+#define CORE_SYNTAX "ISO 8879:1986//SYNTAX Core//EN"
+
+static UNCH (*newkey)[REFNAMELEN+1] = 0;
+
+struct pmap {
+ char *name;
+ UNIV value;
+};
+
+/* The reference capacity set. */
+#define REFCAPSET \
+{ 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, \
+35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L }
+
+long refcapset[NCAPACITY] = REFCAPSET;
+
+/* A pmap of known capacity sets. */
+
+static struct pmap capset_map[] = {
+ { "ISO 8879:1986//CAPACITY Reference//EN", (UNIV)refcapset },
+ { 0 },
+};
+
+/* Table of capacity names. Must match *CAP in sgmldecl.h. */
+
+char *captab[] = {
+ "TOTALCAP",
+ "ENTCAP",
+ "ENTCHCAP",
+ "ELEMCAP",
+ "GRPCAP",
+ "EXGRPCAP",
+ "EXNMCAP",
+ "ATTCAP",
+ "ATTCHCAP",
+ "AVGRPCAP",
+ "NOTCAP",
+ "NOTCHCAP",
+ "IDCAP",
+ "IDREFCAP",
+ "MAPCAP",
+ "LKSETCAP",
+ "LKNMCAP",
+};
+
+/* The default SGML declaration. */
+#define MAXNUMBER 99999999L
+
+/* Reference quantity set */
+
+#define REFATTCNT 40
+#define REFATTSPLEN 960
+#define REFBSEQLEN 960
+#define REFDTAGLEN 16
+#define REFDTEMPLEN 16
+#define REFENTLVL 16
+#define REFGRPCNT 32
+#define REFGRPGTCNT 96
+#define REFGRPLVL 16
+#define REFNORMSEP 2
+#define REFPILEN 240
+#define REFTAGLEN 960
+#define REFTAGLVL 24
+
+#define ALLOC_MAX 65534
+
+#define BIGINT 30000
+
+#define MAXATTCNT ((ALLOC_MAX/sizeof(struct ad)) - 2)
+#define MAXATTSPLEN BIGINT
+#define MAXBSEQLEN BIGINT
+#define MAXDTAGLEN 16
+#define MAXDTEMPLEN 16
+#define MAXENTLVL ((ALLOC_MAX/sizeof(struct source)) - 1)
+#define MAXGRPCNT MAXGRPGTCNT
+/* Must be between 96 and 253 */
+#define MAXGRPGTCNT 253
+#define MAXGRPLVL MAXGRPGTCNT
+#define MAXLITLEN BIGINT
+/* This guarantees that NAMELEN < LITLEN (ie there's always space for a name
+in a buffer intended for a literal.) */
+#define MAXNAMELEN (REFLITLEN - 1)
+#define MAXNORMSEP 2
+#define MAXPILEN BIGINT
+#define MAXTAGLEN BIGINT
+#define MAXTAGLVL ((ALLOC_MAX/sizeof(struct tag)) - 1)
+
+/* Table of quantity names. Must match Q* in sgmldecl.h. */
+
+static char *quantity_names[] = {
+ "ATTCNT",
+ "ATTSPLEN",
+ "BSEQLEN",
+ "DTAGLEN",
+ "DTEMPLEN",
+ "ENTLVL",
+ "GRPCNT",
+ "GRPGTCNT",
+ "GRPLVL",
+ "LITLEN",
+ "NAMELEN",
+ "NORMSEP",
+ "PILEN",
+ "TAGLEN",
+ "TAGLVL",
+};
+
+static int max_quantity[] = {
+ MAXATTCNT,
+ MAXATTSPLEN,
+ MAXBSEQLEN,
+ MAXDTAGLEN,
+ MAXDTEMPLEN,
+ MAXENTLVL,
+ MAXGRPCNT,
+ MAXGRPGTCNT,
+ MAXGRPLVL,
+ MAXLITLEN,
+ MAXNAMELEN,
+ MAXNORMSEP,
+ MAXPILEN,
+ MAXTAGLEN,
+ MAXTAGLVL,
+};
+
+static char *quantity_changed;
+
+/* Non-zero means the APPINFO parameter was not NONE. */
+static int appinfosw = 0;
+
+struct sgmldecl sd = {
+ REFCAPSET, /* capacity */
+#ifdef SUPPORT_SUBDOC
+ MAXNUMBER, /* subdoc */
+#else /* not SUPPORT_SUBDOC */
+ 0, /* subdoc */
+#endif /* not SUPPORT_SUBDOC */
+ 1, /* formal */
+ 1, /* omittag */
+ 1, /* shorttag */
+ 1, /* shortref */
+ { 1, 0 }, /* general/entity name case translation */
+ { /* reference quantity set */
+ REFATTCNT,
+ REFATTSPLEN,
+ REFBSEQLEN,
+ REFDTAGLEN,
+ REFDTEMPLEN,
+ REFENTLVL,
+ REFGRPCNT,
+ REFGRPGTCNT,
+ REFGRPLVL,
+ REFLITLEN,
+ REFNAMELEN,
+ REFNORMSEP,
+ REFPILEN,
+ REFTAGLEN,
+ REFTAGLVL,
+ },
+};
+
+static int systemcharset[] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+};
+
+/* This is a private use designating sequence that by convention
+refers to the whole system character set whatever it is. */
+
+#define SYSTEM_CHARSET_DESIGNATING_SEQUENCE "ESC 2/5 2/15 3/0"
+
+static struct pmap charset_map[] = {
+ { "ESC 2/5 4/0", (UNIV)iso646charset }, /* ISO 646 IRV */
+ { "ESC 2/8 4/2", (UNIV)iso646G0charset }, /* ISO Registration Number 6, ASCII */
+ { "ESC 2/8 4/0", (UNIV)iso646G0charset }, /* ISO Registration Number 6, ASCII */
+ { "ESC 2/13 4/1", (UNIV)iso8859_1charset }, /* Latin 1 */
+ { "ESC 2/1 4/0", (UNIV)iso646C0charset }, /* ISO 646, C0 */
+ { "ESC 2/2 4/3", (UNIV)iso6429C1charset }, /* ISO 6429, C1 */
+ { SYSTEM_CHARSET_DESIGNATING_SEQUENCE, (UNIV)systemcharset },
+ /* system character set */
+ { 0 }
+};
+
+static int synrefcharset[256]; /* the syntax reference character set */
+
+#define CHAR_NONSGML 01
+#define CHAR_SIGNIFICANT 02
+#define CHAR_MAGIC 04
+#define CHAR_SHUNNED 010
+
+static UNCH char_flags[256];
+static int done_nonsgml = 0;
+static UNCH *nlextoke = 0; /* new lextoke */
+static UNCH *nlextran = 0; /* new lextran */
+#define MAX_SAVED_ERRS 4
+static UNIV saved_errs[MAX_SAVED_ERRS];
+static int nsaved_errs = 0;
+
+static UNCH kcharset[] = "CHARSET";
+static UNCH kbaseset[] = "BASESET";
+static UNCH kdescset[] = "DESCSET";
+static UNCH kunused[] = "UNUSED";
+static UNCH kcapacity[] = "CAPACITY";
+static UNCH kpublic[] = "PUBLIC";
+static UNCH ksgmlref[] = "SGMLREF";
+static UNCH kscope[] = "SCOPE";
+static UNCH kdocument[] = "DOCUMENT";
+static UNCH kinstance[] = "INSTANCE";
+static UNCH ksyntax[] = "SYNTAX";
+static UNCH kswitches[] = "SWITCHES";
+static UNCH kfeatures[] = "FEATURES";
+static UNCH kminimize[] = "MINIMIZE";
+static UNCH kdatatag[] = "DATATAG";
+static UNCH komittag[] = "OMITTAG";
+static UNCH krank[] = "RANK";
+static UNCH kshorttag[] = "SHORTTAG";
+static UNCH klink[] = "LINK";
+static UNCH ksimple[] = "SIMPLE";
+static UNCH kimplicit[] = "IMPLICIT";
+static UNCH kexplicit[] = "EXPLICIT";
+static UNCH kother[] = "OTHER";
+static UNCH kconcur[] = "CONCUR";
+static UNCH ksubdoc[] = "SUBDOC";
+static UNCH kformal[] = "FORMAL";
+static UNCH kyes[] = "YES";
+static UNCH kno[] = "NO";
+static UNCH kappinfo[] = "APPINFO";
+static UNCH knone[] = "NONE";
+static UNCH kshunchar[] = "SHUNCHAR";
+static UNCH kcontrols[] = "CONTROLS";
+static UNCH kfunction[] = "FUNCTION";
+static UNCH krs[] = "RS";
+static UNCH kre[] = "RE";
+static UNCH kspace[] = "SPACE";
+static UNCH knaming[] = "NAMING";
+static UNCH klcnmstrt[] = "LCNMSTRT";
+static UNCH kucnmstrt[] = "UCNMSTRT";
+static UNCH klcnmchar[] = "LCNMCHAR";
+static UNCH kucnmchar[] = "UCNMCHAR";
+static UNCH knamecase[] = "NAMECASE";
+static UNCH kdelim[] = "DELIM";
+static UNCH kgeneral[] = "GENERAL";
+static UNCH kentity[] = "ENTITY";
+static UNCH kshortref[] = "SHORTREF";
+static UNCH knames[] = "NAMES";
+static UNCH kquantity[] = "QUANTITY";
+
+#define sderr mderr
+
+static UNIV pmaplookup P((struct pmap *, char *));
+static UNCH *ltous P((long));
+static VOID sdfixstandard P((UNCH *, int));
+static int sdparm P((UNCH *, struct parse *));
+static int sdname P((UNCH *, UNCH *));
+static int sdckname P((UNCH *, UNCH *));
+static int sdversion P((UNCH *));
+static int sdcharset P((UNCH *));
+static int sdcsdesc P((UNCH *, int *));
+static int sdpubcapacity P((UNCH *));
+static int sdcapacity P((UNCH *));
+static int sdscope P((UNCH *));
+static VOID setlexical P((void));
+static VOID noemptytag P((void));
+static int sdpubsyntax P((UNCH *));
+static int sdsyntax P((UNCH *));
+static int sdxsyntax P((UNCH *));
+static int sdtranscharnum P((UNCH *));
+static int sdtranschar P((int));
+static int sdshunchar P((UNCH *));
+static int sdsynref P((UNCH *));
+static int sdfunction P((UNCH *));
+static int sdnaming P((UNCH *));
+static int sddelim P((UNCH *));
+static int sdnames P((UNCH *));
+static int sdquantity P((UNCH *));
+static int sdfeatures P((UNCH *));
+static int sdappinfo P((UNCH *));
+static VOID sdsaverr P((UNS, UNCH *, UNCH *));
+
+static VOID bufsalloc P((void));
+static VOID bufsrealloc P((void));
+
+/* Parse the SGML declaration. Return non-zero if there was some appinfo. */
+
+int sgmldecl()
+{
+ int i;
+ int errsw = 0;
+ UNCH endbuf[REFNAMELEN+2]; /* buffer for parsing terminating > */
+ static int (*section[]) P((UNCH *)) = {
+ sdversion,
+ sdcharset,
+ sdcapacity,
+ sdscope,
+ sdsyntax,
+ sdfeatures,
+ sdappinfo,
+ };
+ /* These are needed if we use mderr. */
+ parmno = 0;
+ mdname = sgmlkey;
+ subdcl = NULL;
+ nsaved_errs = 0;
+ for (i = 0; i < SIZEOF(section); i++)
+ if ((*section[i])(tbuf) == FAIL) {
+ errsw = 1;
+ break;
+ }
+ if (sd.formal) {
+ /* print saved errors */
+ int i;
+ for (i = 0; i < nsaved_errs; i++)
+ svderr(saved_errs[i]);
+ }
+ else {
+ /* free saved errors */
+ int i;
+ for (i = 0; i < nsaved_errs; i++)
+ msgsfree(saved_errs[i]);
+ }
+
+ if (!errsw)
+ setlexical();
+ bufsrealloc();
+ /* Parse the >. Don't overwrite the appinfo. */
+ if (!errsw)
+ sdparm(endbuf, 0);
+ /* We must exit if we hit end of document. */
+ if (pcbsd.action == EOD_)
+ exiterr(161, &pcbsd);
+ if (!errsw && pcbsd.action != ESGD)
+ sderr(126, (UNCH *)0, (UNCH *)0);
+ return appinfosw;
+}
+
+/* Parse the literal (which should contain the version of the
+standard) at the beginning of a SGML declaration. */
+
+static int sdversion(tbuf)
+UNCH *tbuf;
+{
+ if (sdparm(tbuf, &pcblitv) != LIT1) {
+ sderr(123, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ sdfixstandard(tbuf, 0);
+ if (ustrcmp(tbuf, standard) != 0)
+ sderr(E_BADVERSION, tbuf, standard);
+ return SUCCESS;
+}
+
+/* Parse the CHARSET section. Use one token lookahead. */
+
+static int sdcharset(tbuf)
+UNCH *tbuf;
+{
+ int i;
+ int status[256];
+
+ if (sdname(tbuf, kcharset) == FAIL) return FAIL;
+ (void)sdparm(tbuf, 0);
+
+ if (sdcsdesc(tbuf, status) == FAIL)
+ return FAIL;
+
+#if 0
+ for (i = 128; i < 256; i++)
+ if (status[i] != UNDESC)
+ break;
+ if (i >= 256) {
+ /* Only a 7-bit character set was described. Fill it out to 8-bits. */
+ for (i = 128; i < 256; i++)
+ status[i] = UNUSED;
+#if 0
+ sderr(E_7BIT, (UNCH *)0, (UNCH *)0);
+#endif
+ }
+#endif
+ /* Characters that are declared UNUSED in the document character set
+ are assigned to non-SGML. */
+ for (i = 0; i < 256; i++) {
+ if (status[i] == UNDESC) {
+#if 0
+ sderr(E_CHARMISSING, ltous((long)i), (UNCH *)0);
+#endif
+ char_flags[i] |= CHAR_NONSGML;
+ }
+ else if (status[i] == UNUSED)
+ char_flags[i] |= CHAR_NONSGML;
+ }
+ done_nonsgml = 1;
+ return SUCCESS;
+}
+
+/* Parse a character set description. Uses one character lookahead. */
+
+static int sdcsdesc(tbuf, status)
+UNCH *tbuf;
+int *status;
+{
+ int i;
+ int nsets = 0;
+ struct fpi fpi;
+
+ for (i = 0; i < 256; i++)
+ status[i] = UNDESC;
+
+ for (;;) {
+ int nchars;
+ int *baseset = 0;
+
+ if (pcbsd.action != NAS1) {
+ if (nsets == 0) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ break;
+ }
+ if (!matches(tbuf, kbaseset)) {
+ if (nsets == 0) {
+ sderr(118, tbuf+1, kbaseset);
+ return FAIL;
+ }
+ break;
+ }
+ nsets++;
+ MEMZERO((UNIV)&fpi, FPISZ);
+ if (sdparm(tbuf, &pcblitv) != LIT1) {
+ sderr(123, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ fpi.fpipubis = tbuf;
+ /* Give a warning if it is not a CHARSET fpi. */
+ if (parsefpi(&fpi))
+ sdsaverr(E_FORMAL, (UNCH *)0, (UNCH *)0);
+ else if (fpi.fpic != FPICHARS)
+ sdsaverr(E_BADCLASS, kcharset, (UNCH *)0);
+ else {
+ fpi.fpipubis[fpi.fpil + fpi.fpill] = '\0';
+ baseset = (int *)pmaplookup(charset_map,
+ (char *)fpi.fpipubis + fpi.fpil);
+ if (!baseset)
+ sderr(E_UNKNOWNSET, fpi.fpipubis + fpi.fpil, (UNCH *)0);
+ }
+ if (sdname(tbuf, kdescset) == FAIL) return FAIL;
+ nchars = 0;
+ for (;;) {
+ long start, count;
+ long basenum;
+ if (sdparm(tbuf, 0) != NUM1)
+ break;
+ start = atol((char *)tbuf);
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ count = atol((char *)tbuf);
+ switch (sdparm(tbuf, &pcblitv)) {
+ case NUM1:
+ basenum = atol((char *)tbuf);
+ break;
+ case LIT1:
+ basenum = UNKNOWN;
+ break;
+ case NAS1:
+ if (matches(tbuf, kunused)) {
+ basenum = UNUSED;
+ break;
+ }
+ /* fall through */
+ default:
+ sderr(E_CHARDESC, ltous(start), (UNCH *)0);
+ return FAIL;
+ }
+ if (start + count > 256)
+ sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
+ else {
+ int i;
+ int lim = (int)start + count;
+ for (i = (int)start; i < lim; i++) {
+ if (status[i] != UNDESC)
+ sderr(E_CHARDUP, ltous((long)i), (UNCH *)0);
+ else if (basenum == UNUSED || basenum == UNKNOWN)
+ status[i] = (int)basenum;
+ else if (baseset == 0)
+ status[i] = UNKNOWN_SET;
+ else {
+ int n = basenum + (i - start);
+ if (n < 0 || n > 255)
+ sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
+ else {
+ if (baseset[n] == UNUSED)
+ sderr(E_BADBASECHAR, ltous((long)n),
+ (UNCH *)0);
+ status[i] = baseset[n];
+ }
+ }
+ }
+ }
+ nchars++;
+ }
+ if (nchars == 0) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ }
+ return SUCCESS;
+}
+
+/* Parse the CAPACITY section. Uses one token lookahead. */
+
+static int sdcapacity(tbuf)
+UNCH *tbuf;
+{
+ int ncap;
+ int i;
+
+ if (sdckname(tbuf, kcapacity) == FAIL)
+ return FAIL;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kpublic))
+ return sdpubcapacity(tbuf);
+ if (!matches(tbuf, ksgmlref)) {
+ sderr(E_CAPACITY, tbuf+1, (UNCH *)0);
+ return FAIL;
+ }
+ memcpy((UNIV)sd.capacity, (UNIV)refcapset, sizeof(sd.capacity));
+ ncap = 0;
+ for (;;) {
+ int capno = -1;
+ int i;
+
+ if (sdparm(tbuf, 0) != NAS1)
+ break;
+ for (i = 0; i < SIZEOF(captab); i++)
+ if (matches(tbuf, captab[i])) {
+ capno = i;
+ break;
+ }
+ if (capno < 0)
+ break;
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ sd.capacity[capno] = atol((char *)tbuf);
+ ncap++;
+ }
+ if (ncap == 0) {
+ sderr(E_CAPMISSING, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ for (i = 1; i < NCAPACITY; i++)
+ if (sd.capacity[i] > sd.capacity[0])
+ sderr(E_TOTALCAP, (UNCH *)captab[i], (UNCH *)0);
+ return SUCCESS;
+}
+
+/* Parse a CAPACITY section that started with PUBLIC. Must do one
+token lookahead, since sdcapacity() also does. */
+
+static int sdpubcapacity(tbuf)
+UNCH *tbuf;
+{
+ UNIV ptr;
+ if (sdparm(tbuf, &pcblitv) != LIT1) {
+ sderr(123, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ sdfixstandard(tbuf, 1);
+ ptr = pmaplookup(capset_map, (char *)tbuf);
+ if (!ptr)
+ sderr(E_CAPSET, tbuf, (UNCH *)0);
+ else
+ memcpy((UNIV)sd.capacity, (UNIV)ptr, sizeof(sd.capacity));
+ (void)sdparm(tbuf, 0);
+ return SUCCESS;
+}
+
+/* Parse the SCOPE section. Uses no lookahead. */
+
+static int sdscope(tbuf)
+UNCH *tbuf;
+{
+ if (sdckname(tbuf, kscope) == FAIL)
+ return FAIL;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kdocument))
+ ;
+ else if (matches(tbuf, kinstance))
+ sderr(E_INSTANCE, (UNCH *)0, (UNCH *)0);
+ else {
+ sderr(E_SCOPE, tbuf+1, (UNCH *)0);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* Parse the SYNTAX section. Uses one token lookahead. */
+
+static int sdsyntax(tbuf)
+UNCH *tbuf;
+{
+ if (sdname(tbuf, ksyntax) == FAIL) return FAIL;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kpublic))
+ return sdpubsyntax(tbuf);
+ return sdxsyntax(tbuf);
+}
+
+/* Parse the SYNTAX section which starts with PUBLIC. Uses one token
+lookahead. */
+
+static int sdpubsyntax(tbuf)
+UNCH *tbuf;
+{
+ int nswitches;
+ if (sdparm(tbuf, &pcblitv) != LIT1)
+ return FAIL;
+ sdfixstandard(tbuf, 1);
+ if (ustrcmp(tbuf, CORE_SYNTAX) == 0)
+ sd.shortref = 0;
+ else if (ustrcmp(tbuf, REFERENCE_SYNTAX) == 0)
+ sd.shortref = 1;
+ else
+ sderr(E_SYNTAX, tbuf, (UNCH *)0);
+ if (sdparm(tbuf, 0) != NAS1)
+ return SUCCESS;
+ if (!matches(tbuf, kswitches))
+ return SUCCESS;
+ nswitches = 0;
+ for (;;) {
+ int errsw = 0;
+
+ if (sdparm(tbuf, 0) != NUM1)
+ break;
+ if (atol((char *)tbuf) > 255) {
+ sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
+ errsw = 1;
+ }
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (!errsw) {
+ if (atol((char *)tbuf) > 255)
+ sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
+ }
+ nswitches++;
+ }
+ if (nswitches == 0) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ sderr(E_SWITCHES, (UNCH *)0, (UNCH *)0);
+ return SUCCESS;
+}
+
+/* Parse an explicit concrete syntax. Uses one token lookahead. */
+
+static
+int sdxsyntax(tbuf)
+UNCH *tbuf;
+{
+ static int (*section[]) P((UNCH *)) = {
+ sdshunchar,
+ sdsynref,
+ sdfunction,
+ sdnaming,
+ sddelim,
+ sdnames,
+ sdquantity,
+ };
+ int i;
+
+ for (i = 0; i < SIZEOF(section); i++)
+ if ((*section[i])(tbuf) == FAIL)
+ return FAIL;
+ return SUCCESS;
+}
+
+/* Parse the SHUNCHAR section. Uses one token lookahead. */
+
+static
+int sdshunchar(tbuf)
+UNCH *tbuf;
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ char_flags[i] &= ~CHAR_SHUNNED;
+
+ if (sdckname(tbuf, kshunchar) == FAIL)
+ return FAIL;
+
+ if (sdparm(tbuf, 0) == NAS1) {
+ if (matches(tbuf, knone)) {
+ (void)sdparm(tbuf, 0);
+ return SUCCESS;
+ }
+ if (matches(tbuf, kcontrols)) {
+ for (i = 0; i < 256; i++)
+ if (ISASCII(i) && iscntrl(i))
+ char_flags[i] |= CHAR_SHUNNED;
+ if (sdparm(tbuf, 0) != NUM1)
+ return SUCCESS;
+ }
+ }
+ if (pcbsd.action != NUM1) {
+ sderr(E_SHUNCHAR, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ do {
+ long n = atol((char *)tbuf);
+ if (n > 255)
+ sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
+ else
+ char_flags[(int)n] |= CHAR_SHUNNED;
+ } while (sdparm(tbuf, 0) == NUM1);
+ return SUCCESS;
+}
+
+/* Parse the syntax reference character set. Uses one token lookahead. */
+
+static
+int sdsynref(tbuf)
+UNCH *tbuf;
+{
+ return sdcsdesc(tbuf, synrefcharset);
+}
+
+/* Translate a character number from the syntax reference character set
+to the system character set. If it can't be done, give an error message
+and return -1. */
+
+static
+int sdtranscharnum(tbuf)
+UNCH *tbuf;
+{
+ long n = atol((char *)tbuf);
+ if (n > 255) {
+ sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
+ return -1;
+ }
+ return sdtranschar((int)n);
+}
+
+
+static
+int sdtranschar(n)
+int n;
+{
+ int ch = synrefcharset[n];
+ if (ch >= 0)
+ return ch;
+ switch (ch) {
+ case UNUSED:
+ sderr(E_SYNREFUNUSED, ltous((long)n), (UNCH *)0);
+ break;
+ case UNDESC:
+ sderr(E_SYNREFUNDESC, ltous((long)n), (UNCH *)0);
+ break;
+ case UNKNOWN:
+ sderr(E_SYNREFUNKNOWN, ltous((long)n), (UNCH *)0);
+ break;
+ case UNKNOWN_SET:
+ sderr(E_SYNREFUNKNOWNSET, ltous((long)n), (UNCH *)0);
+ break;
+ default:
+ abort();
+ }
+ return -1;
+}
+
+
+/* Parse the function section. Uses two tokens lookahead. "NAMING"
+could be a function name. */
+
+static
+int sdfunction(tbuf)
+UNCH *tbuf;
+{
+ static UNCH *fun[] = { kre, krs, kspace };
+ static int funval[] = { RECHAR, RSCHAR, ' ' };
+ int i;
+ int had_tab = 0;
+ int changed = 0; /* attempted to change reference syntax */
+
+ if (sdckname(tbuf, kfunction) == FAIL)
+ return FAIL;
+ for (i = 0; i < SIZEOF(fun); i++) {
+ int ch;
+ if (sdname(tbuf, fun[i]) == FAIL)
+ return FAIL;
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ ch = sdtranscharnum(tbuf);
+ if (ch >= 0 && ch != funval[i])
+ changed = 1;
+ }
+ for (;;) {
+ int tabsw = 0;
+ int namingsw = 0;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, (UNCH *)"TAB")) {
+ tabsw = 1;
+ if (had_tab)
+ sderr(E_FUNDUP, (UNCH *)0, (UNCH *)0);
+ }
+ else {
+ for (i = 0; i < SIZEOF(fun); i++)
+ if (matches(tbuf, fun[i]))
+ sderr(E_BADFUN, fun[i], (UNCH *)0);
+ if (matches(tbuf, knaming))
+ namingsw = 1;
+ else
+ changed = 1;
+ }
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (namingsw) {
+ if (matches(tbuf, klcnmstrt))
+ break;
+ changed = 1;
+ }
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (tabsw && !had_tab) {
+ int ch = sdtranscharnum(tbuf);
+ if (ch >= 0 && ch != TABCHAR)
+ changed = 1;
+ had_tab = 1;
+ }
+
+ }
+ if (!had_tab)
+ changed = 1;
+ if (changed)
+ sderr(E_FUNCHAR, (UNCH *)0, (UNCH *)0);
+ return SUCCESS;
+}
+
+/* Parse the NAMING section. Uses no lookahead. */
+
+static
+int sdnaming(tbuf)
+UNCH *tbuf;
+{
+ int i;
+ int bad = 0;
+ static UNCH *classes[] = { klcnmstrt, kucnmstrt, klcnmchar, kucnmchar };
+ static UNCH *types[] = { kgeneral, kentity };
+
+#define NCLASSES SIZEOF(classes)
+
+ int bufsize = 4; /* allocated size of buf */
+ UNCH *buf = (UNCH *)rmalloc(bufsize); /* holds characters
+ in naming classes */
+ int bufi = 0; /* next index into buf */
+ int start[NCLASSES]; /* index of first character for each class */
+ int count[NCLASSES]; /* number of characters for each class */
+
+ for (i = 0; i < NCLASSES; i++) {
+ UNCH *s;
+
+ if (sdckname(tbuf, classes[i]) == FAIL) {
+ frem((UNIV)buf);
+ return FAIL;
+ }
+ if (sdparm(tbuf, &pcblitp) != LIT1) {
+ sderr(123, (UNCH *)0, (UNCH *)0);
+ frem((UNIV)buf);
+ return FAIL;
+ }
+ start[i] = bufi;
+
+ for (s = tbuf; *s; s++) {
+ int c = *s;
+ if (c == DELNONCH) {
+ c = UNSHIFTNON(*s);
+ s++;
+ }
+ c = sdtranschar(c);
+ if (c < 0)
+ bad = 1;
+ else if ((char_flags[c] & (CHAR_SIGNIFICANT | CHAR_MAGIC))
+ && c != '.' && c != '-') {
+ int class = lextoke[c];
+ if (class == SEP || class == SP || class == NMC
+ || class == NMS || class == NU)
+ sderr(E_NMBAD, ltous((long)c), (UNCH *)0);
+ else
+ sderr(E_NMUNSUP, ltous((long)c), (UNCH *)0);
+ bad = 1;
+ }
+ if (bufi >= bufsize)
+ buf = (UNCH *)rrealloc((UNIV)buf, bufsize *= 2);
+ buf[bufi++] = c;
+ }
+
+ count[i] = bufi - start[i];
+ (void)sdparm(tbuf, 0);
+ }
+ if (!bad && count[0] != count[1]) {
+ sderr(E_NMSTRTCNT, (UNCH *)0, (UNCH *)0);
+ bad = 1;
+ }
+ if (!bad && count[2] != count[3]) {
+ sderr(E_NMCHARCNT, (UNCH *)0, (UNCH *)0);
+ bad = 1;
+ }
+ if (!bad) {
+ nlextoke = (UNCH *)rmalloc(256);
+ memcpy((UNIV)nlextoke, lextoke, 256);
+ nlextoke['.'] = nlextoke['-'] = INV;
+
+ nlextran = (UNCH *)rmalloc(256);
+ memcpy((UNIV)nlextran, lextran, 256);
+
+ for (i = 0; i < count[0]; i++) {
+ UNCH lc = buf[start[0] + i];
+ UNCH uc = buf[start[1] + i];
+ nlextoke[lc] = NMS;
+ nlextoke[uc] = NMS;
+ nlextran[lc] = uc;
+ }
+
+ for (i = 0; i < count[2]; i++) {
+ UNCH lc = buf[start[2] + i];
+ UNCH uc = buf[start[3] + i];
+ if (nlextoke[lc] == NMS) {
+ sderr(E_NMDUP, ltous((long)lc), (UNCH *)0);
+ bad = 1;
+ }
+ else if (nlextoke[uc] == NMS) {
+ sderr(E_NMDUP, ltous((long)uc), (UNCH *)0);
+ bad = 1;
+ }
+ else {
+ nlextoke[lc] = NMC;
+ nlextoke[uc] = NMC;
+ nlextran[lc] = uc;
+ }
+ }
+ if (nlextoke['-'] != NMC) {
+ sderr(E_NMMINUS, (UNCH *)0, (UNCH *)0);
+ bad = 1;
+ }
+ if (bad) {
+ if (nlextoke) {
+ frem((UNIV)nlextoke);
+ nlextoke = 0;
+ }
+ if (nlextran) {
+ frem((UNIV)nlextran);
+ nlextran = 0;
+ }
+ }
+ }
+
+ frem((UNIV)buf);
+
+ if (sdckname(tbuf, knamecase) == FAIL)
+ return FAIL;
+ for (i = 0; i < SIZEOF(types); ++i) {
+ if (sdname(tbuf, types[i]) == FAIL)
+ return FAIL;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kyes))
+ sd.namecase[i] = 1;
+ else if (matches(tbuf, kno))
+ sd.namecase[i] = 0;
+ else {
+ sderr(E_YESNO, tbuf+1, (UNCH *)0);
+ return FAIL;
+ }
+ }
+ return SUCCESS;
+}
+
+/* Parse the DELIM section. Uses one token lookahead. */
+
+static
+int sddelim(tbuf)
+UNCH *tbuf;
+{
+ int changed = 0;
+ if (sdname(tbuf, kdelim) == FAIL
+ || sdname(tbuf, kgeneral) == FAIL
+ || sdname(tbuf, ksgmlref) == FAIL)
+ return FAIL;
+ for (;;) {
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kshortref))
+ break;
+ if (sdparm(tbuf, &pcblitp) != LIT1) {
+ sderr(123, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ changed = 1;
+ }
+ if (changed) {
+ sderr(E_GENDELIM, (UNCH *)0,(UNCH *)0);
+ changed = 0;
+ }
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, ksgmlref))
+ sd.shortref = 1;
+ else if (matches(tbuf, knone))
+ sd.shortref = 0;
+ else {
+ sderr(118, tbuf+1, ksgmlref); /* probably they forgot SGMLREF */
+ return FAIL;
+ }
+ while (sdparm(tbuf, &pcblitp) == LIT1)
+ changed = 1;
+ if (changed)
+ sderr(E_SRDELIM, (UNCH *)0, (UNCH *)0);
+ return SUCCESS;
+}
+
+/* Parse the NAMES section. Uses one token lookahead. */
+
+static
+int sdnames(tbuf)
+UNCH *tbuf;
+{
+ int i;
+ if (sdckname(tbuf, knames) == FAIL)
+ return FAIL;
+ if (sdname(tbuf, ksgmlref) == FAIL)
+ return FAIL;
+
+ while (sdparm(tbuf, 0) == NAS1) {
+ int j;
+ if (matches(tbuf, kquantity))
+ break;
+ for (i = 0; i < NKEYS; i++)
+ if (matches(tbuf, key[i]))
+ break;
+ if (i >= NKEYS) {
+ sderr(E_BADKEY, tbuf+1, (UNCH *)0);
+ return FAIL;
+ }
+ if (sdparm(tbuf, &pcblitp) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (!newkey) {
+ newkey = (UNCH (*)[REFNAMELEN+1])rmalloc((REFNAMELEN+1)*NKEYS);
+ MEMZERO((UNIV)newkey, (REFNAMELEN+1)*NKEYS);
+ }
+ for (j = 0; j < NKEYS; j++) {
+ if (matches(tbuf, key[j])) {
+ sderr(E_REFNAME, tbuf + 1, (UNCH *)0);
+ break;
+ }
+ if (matches(tbuf, newkey[j])) {
+ sderr(E_DUPNAME, tbuf + 1, (UNCH *)0);
+ break;
+ }
+ }
+ if (j >= NKEYS)
+ ustrcpy(newkey[i], tbuf + 1);
+ }
+ /* Now install the new keys. */
+ if (newkey) {
+ for (i = 0; i < NKEYS; i++)
+ if (newkey[i][0] != '\0') {
+ UNCH temp[REFNAMELEN + 1];
+
+ ustrcpy(temp, key[i]);
+ ustrcpy(key[i], newkey[i]);
+ ustrcpy(newkey[i], temp);
+ }
+ }
+ return SUCCESS;
+}
+
+/* Parse the QUANTITY section. Uses one token lookahead. */
+
+static int sdquantity(tbuf)
+UNCH *tbuf;
+{
+ int quantity[NQUANTITY];
+ int i;
+
+ for (i = 0; i < NQUANTITY; i++)
+ quantity[i] = -1;
+ if (sdckname(tbuf, kquantity) == FAIL)
+ return FAIL;
+ if (sdname(tbuf, ksgmlref) == FAIL)
+ return FAIL;
+ while (sdparm(tbuf, 0) == NAS1 && !matches(tbuf, kfeatures)) {
+ long n;
+ for (i = 0; i < SIZEOF(quantity_names); i++)
+ if (matches(tbuf, quantity_names[i]))
+ break;
+ if (i >= SIZEOF(quantity_names)) {
+ sderr(E_BADQUANTITY, tbuf + 1, (UNCH *)0);
+ return FAIL;
+ }
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ n = atol((char *)tbuf);
+ if (n < sd.quantity[i])
+ sderr(E_QUANTITY, (UNCH *)quantity_names[i],
+ ltous((long)sd.quantity[i]));
+ else if (n > max_quantity[i]) {
+ sderr(E_QTOOBIG, (UNCH *)quantity_names[i],
+ ltous((long)max_quantity[i]));
+ quantity[i] = max_quantity[i];
+ }
+ else
+ quantity[i] = (int)n;
+ }
+ for (i = 0; i < NQUANTITY; i++)
+ if (quantity[i] > 0) {
+ sd.quantity[i] = quantity[i];
+ if (!quantity_changed)
+ quantity_changed = (char *)rmalloc(NQUANTITY);
+ quantity_changed[i] = 1;
+ }
+ return SUCCESS;
+}
+
+/* Parse the FEATURES section. Uses no lookahead. */
+
+static int sdfeatures(tbuf)
+UNCH *tbuf;
+{
+ static struct {
+ UNCH *name;
+ UNCH argtype; /* 0 = no argument, 1 = boolean, 2 = numeric */
+ UNIV valp; /* UNCH * if boolean, long * if numeric. */
+ } features[] = {
+ { kminimize, 0, 0 },
+ { kdatatag, 1, 0 },
+ { komittag, 1, (UNIV)&sd.omittag },
+ { krank, 1, 0 },
+ { kshorttag, 1, (UNIV)&sd.shorttag },
+ { klink, 0, 0 },
+ { ksimple, 2, 0 },
+ { kimplicit, 1, 0 },
+ { kexplicit, 2, 0 },
+ { kother, 0, 0 },
+ { kconcur, 2, 0 },
+ { ksubdoc, 2, (UNIV)&sd.subdoc },
+ { kformal, 1, (UNIV)&sd.formal },
+ };
+
+ int i;
+
+ if (sdckname(tbuf, kfeatures) == FAIL)
+ return FAIL;
+ for (i = 0; i < SIZEOF(features); i++) {
+ if (sdname(tbuf, features[i].name) == FAIL) return FAIL;
+ if (features[i].argtype > 0) {
+ long n;
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (matches(tbuf, kyes)) {
+ if (features[i].argtype > 1) {
+ if (sdparm(tbuf, 0) != NUM1) {
+ sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ n = atol((char *)tbuf);
+ if (n == 0)
+ sderr(E_ZEROFEATURE, features[i].name, (UNCH *)0);
+ }
+ else
+ n = 1;
+ }
+ else if (matches(tbuf, kno))
+ n = 0;
+ else {
+ sderr(E_YESNO, tbuf+1, (UNCH *)0);
+ return FAIL;
+ }
+ if (features[i].valp == 0) {
+ if (n > 0)
+ sderr(E_NOTSUPPORTED, features[i].name,
+ (UNCH *)0);
+ }
+ else if (features[i].argtype > 1)
+ *(long *)features[i].valp = n;
+ else
+ *(UNCH *)features[i].valp = (UNCH)n;
+ }
+ }
+ if (!sd.shorttag)
+ noemptytag();
+ return SUCCESS;
+}
+
+/* Parse the APPINFO section. Uses no lookahead. */
+
+static int sdappinfo(tbuf)
+UNCH *tbuf;
+{
+ if (sdname(tbuf, kappinfo) == FAIL) return FAIL;
+ switch (sdparm(tbuf, &pcblitv)) {
+ case LIT1:
+ appinfosw = 1;
+ break;
+ case NAS1:
+ if (matches(tbuf, knone))
+ break;
+ sderr(118, tbuf+1, knone);
+ return FAIL;
+ default:
+ sderr(E_XNMLIT, knone, (UNCH *)0);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* Change a prefix of ISO 8879-1986 to ISO 8879:1986. Amendment 1 to
+the standard requires the latter. */
+
+static VOID sdfixstandard(tbuf, silently)
+UNCH *tbuf;
+int silently;
+{
+ if (strncmp((char *)tbuf, "ISO 8879-1986", 13) == 0) {
+ if (!silently)
+ sderr(E_STANDARD, (UNCH *)0, (UNCH *)0);
+ tbuf[8] = ':';
+ }
+}
+
+static int sdname(tbuf, key)
+UNCH *tbuf;
+UNCH *key;
+{
+ if (sdparm(tbuf, 0) != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (!matches(tbuf, key)) {
+ sderr(118, tbuf+1, key);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+static int sdckname(tbuf, key)
+UNCH *tbuf;
+UNCH *key;
+{
+ if (pcbsd.action != NAS1) {
+ sderr(120, (UNCH *)0, (UNCH *)0);
+ return FAIL;
+ }
+ if (!matches(tbuf, key)) {
+ sderr(118, tbuf+1, key);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* Parse a SGML declaration parameter. If lpcb is NULL, pt must be
+REFNAMELEN+2 characters long, otherwise at least LITLEN+2 characters
+long. LPCB should be NULL if a literal is not allowed. */
+
+static int sdparm(pt, lpcb)
+UNCH *pt; /* Token buffer. */
+struct parse *lpcb; /* PCB for literal parse. */
+{
+ for (;;) {
+ parse(&pcbsd);
+ if (pcbsd.action != ISIG)
+ break;
+ sderr(E_SIGNIFICANT, (UNCH *)0, (UNCH *)0);
+ }
+ ++parmno;
+ switch (pcbsd.action) {
+ case LIT1:
+ if (!lpcb) {
+ sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
+ REPEATCC;
+ return pcbsd.action = INV_;
+ }
+ parselit(pt, lpcb, REFLITLEN, lex.d.lit);
+ return pcbsd.action;
+ case LIT2:
+ if (!lpcb) {
+ sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
+ REPEATCC;
+ return pcbsd.action = INV_;
+ }
+ parselit(pt, lpcb, REFLITLEN, lex.d.lita);
+ return pcbsd.action = LIT1;
+ case NAS1:
+ parsenm(pt, 1);
+ return pcbsd.action;
+ case NUM1:
+ parsetkn(pt, NU, REFNAMELEN);
+ return pcbsd.action;
+ }
+ return pcbsd.action;
+}
+
+VOID sdinit()
+{
+ int i;
+ /* Shunned character numbers in the reference concrete syntax. */
+ static UNCH refshun[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 255
+ };
+ UNCH **p;
+ /* A character is magic if it is a non-SGML character used for
+ some internal purpose in the parser. */
+ char_flags[EOS] |= CHAR_MAGIC;
+ char_flags[EOBCHAR] |= CHAR_MAGIC;
+ char_flags[EOFCHAR] |= CHAR_MAGIC;
+ char_flags[GENRECHAR] |= CHAR_MAGIC;
+ char_flags[DELNONCH] |= CHAR_MAGIC;
+ char_flags[DELCDATA] |= CHAR_MAGIC;
+ char_flags[DELSDATA] |= CHAR_MAGIC;
+
+ /* Figure out the significant SGML characters. */
+ for (p = lextabs; *p; p++) {
+ UNCH datclass = (*p)[CANON_DATACHAR];
+ UNCH nonclass = (*p)[CANON_NONSGML];
+ for (i = 0; i < 256; i++)
+ if (!(char_flags[i] & CHAR_MAGIC)
+ && (*p)[i] != datclass && (*p)[i] != nonclass)
+ char_flags[i] |= CHAR_SIGNIFICANT;
+ }
+ for (i = 0; i < SIZEOF(refshun); i++)
+ char_flags[refshun[i]] |= CHAR_SHUNNED;
+ for (i = 0; i < 256; i++)
+ if (ISASCII(i) && iscntrl(i))
+ char_flags[i] |= CHAR_SHUNNED;
+ bufsalloc();
+}
+
+
+static
+VOID bufsalloc()
+{
+ scbs = (struct source *)rmalloc((REFENTLVL+1)*sizeof(struct source));
+ tbuf = (UNCH *)rmalloc(REFATTSPLEN+REFLITLEN+1);
+ /* entbuf is used for parsing numeric character references */
+ entbuf = (UNCH *)rmalloc(REFNAMELEN + 2);
+}
+
+static
+VOID bufsrealloc()
+{
+ UNS size;
+
+ if (ENTLVL != REFENTLVL)
+ scbs = (struct source *)rrealloc((UNIV)scbs,
+ (ENTLVL+1)*sizeof(struct source));
+ /* Calculate the size for tbuf. */
+ size = LITLEN + ATTSPLEN;
+ if (PILEN > size)
+ size = PILEN;
+ if (BSEQLEN > size)
+ size = BSEQLEN;
+ if (size != REFATTSPLEN + REFLITLEN)
+ tbuf = (UNCH *)rrealloc((UNIV)tbuf, size + 1);
+ if (NAMELEN != REFNAMELEN)
+ entbuf = (UNCH *)rrealloc((UNIV)entbuf, NAMELEN + 2);
+}
+
+
+/* Check that the non-SGML characters are compatible with the concrete
+syntax and munge the lexical tables accordingly. If IMPLIED is
+non-zero, then the SGML declaration was implied; in this case, don't
+give error messages about shunned characters not being declared
+non-SGML. Also make any changes that are required by the NAMING section.
+*/
+
+static VOID setlexical()
+{
+ int i;
+ UNCH **p;
+
+ if (nlextoke) {
+ /* Handle characters that were made significant by the
+ NAMING section. */
+ for (i = 0; i < 256; i++)
+ if (nlextoke[i] == NMC || nlextoke[i] == NMS)
+ char_flags[i] |= CHAR_SIGNIFICANT;
+ }
+
+ for (i = 0; i < 256; i++)
+ if (char_flags[i] & CHAR_SIGNIFICANT) {
+ /* Significant SGML characters musn't be non-SGML. */
+ if (char_flags[i] & CHAR_NONSGML) {
+ UNCH buf[2];
+ buf[0] = i;
+ buf[1] = '\0';
+ sderr(E_NONSGML, buf, (UNCH *)0);
+ char_flags[i] &= ~CHAR_NONSGML;
+ }
+ }
+ else {
+ /* Shunned characters that are not significant SGML characters
+ must be non-SGML. */
+ if ((char_flags[i] & (CHAR_SHUNNED | CHAR_NONSGML))
+ == CHAR_SHUNNED) {
+ sderr(E_SHUNNED, ltous((long)i), (UNCH *)0);
+ char_flags[i] |= CHAR_NONSGML;
+ }
+ }
+
+
+ /* Now munge the lexical tables. */
+ for (p = lextabs; *p; p++) {
+ UNCH nonclass = (*p)[CANON_NONSGML];
+ UNCH datclass = (*p)[CANON_DATACHAR];
+ UNCH nmcclass = (*p)[CANON_NMC];
+ UNCH nmsclass = (*p)[CANON_NMS];
+ UNCH minclass = (*p)[CANON_MIN];
+ for (i = 0; i < 256; i++) {
+ if (char_flags[i] & CHAR_NONSGML) {
+ /* We already know that it's not significant. */
+ if (!(char_flags[i] & CHAR_MAGIC))
+ (*p)[i] = nonclass;
+ }
+ else {
+ if (char_flags[i] & CHAR_MAGIC) {
+ sderr(E_MUSTBENON, ltous((long)i), (UNCH *)0);
+ }
+ else if (!(char_flags[i] & CHAR_SIGNIFICANT))
+ (*p)[i] = datclass;
+ else if (*p == lexmin) {
+ /* If it used to be NONSGML, but its now significant,
+ treat it like a datachar. */
+ if ((*p)[i] == nonclass)
+ (*p)[i] = datclass;
+ }
+ else if (nlextoke
+ /* This relies on the fact that lextoke
+ occurs last in lextabs. */
+ && lextoke[i] != nlextoke[i]) {
+ switch (nlextoke[i]) {
+ case NMC:
+ (*p)[i] = nmcclass;
+ break;
+ case NMS:
+ (*p)[i] = nmsclass;
+ break;
+ case INV:
+ /* This will happen if period is not a
+ name character. */
+ (*p)[i] = minclass;
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+ }
+ }
+ if (nlextran) {
+ memcpy((UNIV)lextran, (UNIV)nlextran, 256);
+ frem((UNIV)nlextran);
+ }
+ if (nlextoke) {
+ frem((UNIV)nlextoke);
+ nlextoke = 0;
+ }
+
+}
+
+/* Munge parse tables so that empty start and end tags are not recognized. */
+
+static VOID noemptytag()
+{
+ static struct parse *pcbs[] = { &pcbconm, &pcbcone, &pcbconr, &pcbconc };
+ int i;
+
+ for (i = 0; i < SIZEOF(pcbs); i++) {
+ int maxclass, maxstate;
+ int j, k, act;
+ UNCH *plex = pcbs[i]->plex;
+ UNCH **ptab = pcbs[i]->ptab;
+
+ /* Figure out the maximum lexical class. */
+ maxclass = 0;
+ for (j = 0; j < 256; j++)
+ if (plex[j] > maxclass)
+ maxclass = plex[j];
+
+ /* Now figure out the maximum state number and at the same time
+ change actions. */
+
+ maxstate = 0;
+
+ for (j = 0; j <= maxstate; j += 2) {
+ for (k = 0; k <= maxclass; k++)
+ if (ptab[j][k] > maxstate)
+ maxstate = ptab[j][k];
+ /* If the '>' class has an empty start or end tag action,
+ change it to the action that the NMC class has. */
+ act = ptab[j + 1][plex['>']];
+ if (act == NET_ || act == NST_)
+ ptab[j + 1][plex['>']] = ptab[j + 1][plex['_']];
+ }
+ }
+}
+
+/* Lookup the value of the entry in pmap PTR whose key is KEY. */
+
+static UNIV pmaplookup(ptr, key)
+struct pmap *ptr;
+char *key;
+{
+ for (; ptr->name; ptr++)
+ if (strcmp(key, ptr->name) == 0)
+ return ptr->value;
+ return 0;
+}
+
+/* Return an ASCII representation of N. */
+
+static UNCH *ltous(n)
+long n;
+{
+ static char buf[sizeof(long)*3 + 2];
+ sprintf(buf, "%ld", n);
+ return (UNCH *)buf;
+}
+
+VOID sgmlwrsd(fp)
+FILE *fp;
+{
+ int i;
+ int changed;
+ char *p;
+ char uc[256]; /* upper case characters (with different lower
+ case characters) */
+ char lcletter[256]; /* LC letters: a-z */
+
+ fprintf(fp, "<!SGML \"%s\"\n", standard);
+ fprintf(fp,
+ "CHARSET\nBASESET \"-//Dummy//CHARSET Dummy//%s\"\nDESCSET\n",
+ SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
+
+ if (!done_nonsgml) {
+ done_nonsgml = 1;
+ for (i = 0; i < 256; i++)
+ if ((char_flags[i] & (CHAR_SIGNIFICANT | CHAR_SHUNNED))
+ == CHAR_SHUNNED)
+ char_flags[i] |= CHAR_NONSGML;
+ }
+ i = 0;
+ while (i < 256) {
+ int j;
+ for (j = i + 1; j < 256; j++)
+ if ((char_flags[j] & CHAR_NONSGML)
+ != (char_flags[i] & CHAR_NONSGML))
+ break;
+ if (char_flags[i] & CHAR_NONSGML)
+ fprintf(fp, "%d %d UNUSED\n", i, j - i);
+ else
+ fprintf(fp, "%d %d %d\n", i, j - i, i);
+ i = j;
+ }
+ fprintf(fp, "CAPACITY\n");
+ changed = 0;
+ for (i = 0; i < NCAPACITY; i++)
+ if (refcapset[i] != sd.capacity[i]) {
+ if (!changed) {
+ fprintf(fp, "SGMLREF\n");
+ changed = 1;
+ }
+ fprintf(fp, "%s %ld\n", captab[i], sd.capacity[i]);
+ }
+ if (!changed)
+ fprintf(fp, "PUBLIC \"%s\"\n", capset_map[0].name);
+ fprintf(fp, "SCOPE DOCUMENT\n");
+
+ fprintf(fp, "SYNTAX\nSHUNCHAR");
+ for (i = 0; i < 256; i++)
+ if (char_flags[i] & CHAR_SHUNNED)
+ break;
+ if (i == 256)
+ fprintf(fp, " NONE\n");
+ else {
+ for (; i < 256; i++)
+ if (char_flags[i] & CHAR_SHUNNED)
+ fprintf(fp, " %d", i);
+ fprintf(fp, "\n");
+ }
+
+ fprintf(fp,
+ "BASESET \"-//Dummy//CHARSET Dummy//%s\"\nDESCSET 0 256 0\n",
+ SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
+
+ fprintf(fp, "FUNCTION\nRE %d\nRS %d\nSPACE %d\nTAB SEPCHAR %d\n",
+ RECHAR, RSCHAR, ' ', TABCHAR);
+
+ MEMZERO((UNIV)uc, 256);
+ for (i = 0; i < 256; i++)
+ if (lextran[i] != i)
+ uc[lextran[i]] = 1;
+
+ MEMZERO((UNIV)lcletter, 256);
+ for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++)
+ lcletter[(unsigned char)*p]= 1;
+
+ fprintf(fp, "NAMING\n");
+ fputs("LCNMSTRT \"", fp);
+ for (i = 0; i < 256; i++)
+ if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
+ fprintf(fp, "&#%d;", i);
+ fputs("\"\n", fp);
+ fputs("UCNMSTRT \"", fp);
+ for (i = 0; i < 256; i++)
+ if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
+ fprintf(fp, "&#%d;", lextran[i]);
+ fputs("\"\n", fp);
+ fputs("LCNMCHAR \"", fp);
+ for (i = 0; i < 256; i++)
+ if (lextoke[i] == NMC && !uc[i])
+ fprintf(fp, "&#%d;", i);
+ fputs("\"\n", fp);
+ fputs("UCNMCHAR \"", fp);
+ for (i = 0; i < 256; i++)
+ if (lextoke[i] == NMC && !uc[i])
+ fprintf(fp, "&#%d;", lextran[i]);
+ fputs("\"\n", fp);
+
+ fprintf(fp, "NAMECASE\nGENERAL %s\nENTITY %s\n",
+ sd.namecase[0] ? "YES" : "NO",
+ sd.namecase[1] ? "YES" : "NO");
+ fprintf(fp, "DELIM\nGENERAL SGMLREF\nSHORTREF %s\n",
+ sd.shortref ? "SGMLREF" : "NONE");
+ fprintf(fp, "NAMES SGMLREF\n");
+ if (newkey) {
+ /* The reference key was saved in newkey. */
+ for (i = 0; i < NKEYS; i++)
+ if (newkey[i][0])
+ fprintf(fp, "%s %s\n", newkey[i], key[i]);
+ }
+ fprintf(fp, "QUANTITY SGMLREF\n");
+ if (quantity_changed)
+ for (i = 0; i < NQUANTITY; i++)
+ if (quantity_changed[i])
+ fprintf(fp, "%s %d\n", quantity_names[i], sd.quantity[i]);
+ fprintf(fp,
+ "FEATURES\nMINIMIZE\nDATATAG NO OMITTAG %s RANK NO SHORTTAG %s\n",
+ sd.omittag ? "YES" : "NO",
+ sd.shorttag ? "YES" : "NO");
+ fprintf(fp, "LINK SIMPLE NO IMPLICIT NO EXPLICIT NO\n");
+ fprintf(fp, "OTHER CONCUR NO ");
+ if (sd.subdoc > 0)
+ fprintf(fp, "SUBDOC YES %ld ", sd.subdoc);
+ else
+ fprintf(fp, "SUBDOC NO ");
+ fprintf(fp, "FORMAL %s\n", sd.formal ? "YES" : "NO");
+ fprintf(fp, "APPINFO NONE");
+ fprintf(fp, ">\n");
+}
+
+/* Save an error to be printed only if FORMAL is declared as YES. */
+
+static
+VOID sdsaverr(number, parm1, parm2)
+UNS number;
+UNCH *parm1;
+UNCH *parm2;
+{
+ saved_errs[nsaved_errs++] = savmderr(number, parm1, parm2);
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgmldecl.h b/usr.bin/sgmls/sgmls/sgmldecl.h
new file mode 100644
index 0000000..1111f72
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmldecl.h
@@ -0,0 +1,90 @@
+/* sgmldecl.h: SGML declaration parsing. */
+
+#define QATTCNT 0
+#define QATTSPLEN 1
+#define QBSEQLEN 2
+#define QDTAGLEN 3
+#define QDTEMPLEN 4
+#define QENTLVL 5
+#define QGRPCNT 6
+#define QGRPGTCNT 7
+#define QGRPLVL 8
+#define QLITLEN 9
+#define QNAMELEN 10
+#define QNORMSEP 11
+#define QPILEN 12
+#define QTAGLEN 13
+#define QTAGLVL 14
+
+#define NQUANTITY (QTAGLVL+1)
+
+#define TOTALCAP 0
+#define ENTCAP 1
+#define ENTCHCAP 2
+#define ELEMCAP 3
+#define GRPCAP 4
+#define EXGRPCAP 5
+#define EXNMCAP 6
+#define ATTCAP 7
+#define ATTCHCAP 8
+#define AVGRPCAP 9
+#define NOTCAP 10
+#define NOTCHCAP 11
+#define IDCAP 12
+#define IDREFCAP 13
+#define MAPCAP 14
+#define LKSETCAP 15
+#define LKNMCAP 16
+
+extern char *captab[];
+
+struct sgmldecl {
+ long capacity[NCAPACITY];
+ long subdoc;
+ UNCH formal;
+ UNCH omittag;
+ UNCH shorttag;
+ UNCH shortref;
+ UNCH namecase[2]; /* case translation of general/entity names */
+ int quantity[NQUANTITY];
+};
+
+extern struct sgmldecl sd;
+
+#define OMITTAG (sd.omittag)
+#define SUBDOC (sd.subdoc)
+#define SHORTTAG (sd.shorttag)
+#define FORMAL (sd.formal)
+
+#define ATTCNT (sd.quantity[QATTCNT])
+#define ATTSPLEN (sd.quantity[QATTSPLEN])
+#define BSEQLEN (sd.quantity[QBSEQLEN])
+#define ENTLVL (sd.quantity[QENTLVL])
+#define GRPGTCNT (sd.quantity[QGRPGTCNT])
+#define GRPCNT (sd.quantity[QGRPCNT])
+#define GRPLVL (sd.quantity[QGRPLVL])
+#define LITLEN (sd.quantity[QLITLEN])
+#define NAMELEN (sd.quantity[QNAMELEN])
+#define NORMSEP (sd.quantity[QNORMSEP])
+#define PILEN (sd.quantity[QPILEN])
+#define TAGLEN (sd.quantity[QTAGLEN])
+#define TAGLVL (sd.quantity[QTAGLVL])
+
+#define NAMECASE (sd.namecase[0])
+#define ENTCASE (sd.namecase[1])
+
+#define YES 1
+#define NO 0
+
+#define UNUSED -1
+#define UNKNOWN -2
+#define UNDESC -3
+#define UNKNOWN_SET -4
+
+extern int iso646charset[];
+extern int iso646G0charset[];
+extern int iso646C0charset[];
+extern int iso8859_1charset[];
+extern int iso6429C1charset[];
+
+
diff --git a/usr.bin/sgmls/sgmls/sgmlfnsm.h b/usr.bin/sgmls/sgmls/sgmlfnsm.h
new file mode 100644
index 0000000..3003d67
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlfnsm.h
@@ -0,0 +1,130 @@
+/* SGMLFNSM.H: SGML function declarations (ANSI prototypes). */
+VOID adlfree P((struct ad *, int));
+VOID adlval P((int,struct etd *));
+VOID aenttst P((int, UNCH *));
+int allhit P((struct thdr *,unsigned long *,int,int));
+VOID ambig P((void));
+VOID ambigfree P((void));
+int amemget P((struct ad *,int,UNCH *));
+int anmget P((int,UNCH *));
+int anmtgrp P((struct parse *,struct ad *,int,UNS *,int));
+int antvget P((int,UNCH *,UNCH **));
+int anyhit P((unsigned long *));
+int attval P((int,UNCH *,int,struct ad *));
+VOID charrefa P((UNCH *));
+int charrefn P((UNCH *, struct parse *));
+int context P((struct etd *,struct thdr *,struct mpos *,UNCH *,int));
+struct etd **copygrp P((struct etd **,unsigned int));
+int datachar P((int, struct parse *));
+struct dcncb *dcnfind P((UNCH *));
+VOID destack P((void));
+int econtext P((struct thdr *,struct mpos *,UNCH *));
+VOID endprolog P((void));
+struct entity *entfind P((UNCH *));
+int entopen P((struct entity *));
+/* VOID eposset P((void)); NOT YET IN USE. */
+VOID error P((struct error *));
+VOID errorinit P((struct error *, unsigned, unsigned));
+int etag P((void));
+int etagetd P((struct parse *));
+VOID etdadl P((struct etd *));
+VOID etdcan P((UNCH *));
+struct etd *etddef P((UNCH *));
+struct etd *etdref P((UNCH *));
+VOID exclude P((void));
+VOID fileclos P((void));
+VOID filecont P((void));
+VOID fileopen P((void));
+VOID filepend P((int));
+VOID fileread P((void));
+VOID filerr P((unsigned, UNCH *));
+VOID fixdatt P((struct dcncb *));
+struct parse *getpcb P((int));
+int groupopt P((struct thdr *,struct mpos *));
+int groupreq P((struct etd *,struct thdr *,struct mpos *));
+int grpsz P((struct thdr *,int));
+int hash P((UNCH *,int));
+struct hash *hfind P((struct hash **,UNCH *,int));
+struct hash *hin P((struct hash **,UNCH *,int,unsigned int));
+int iddef P((UNCH *));
+VOID idrck P((void));
+struct fwdref *idref P((UNCH *));
+VOID idreftst P((int,UNCH *));
+int ingrp P((struct etd **,struct etd *));
+VOID initatt P((struct ad *));
+int mapsrch P((struct map *,UNCH *));
+VOID mdadl P((UNCH *));
+int mdattdef P((int, int));
+VOID mddtde P((UNCH *));
+VOID mddtds P((UNCH *));
+VOID mdelem P((UNCH *));
+VOID mdentity P((UNCH *));
+VOID mderr P((unsigned int,UNCH *,UNCH *));
+struct parse *mdms P((UNCH *,struct parse *));
+int mdmse P((void));
+VOID mdnadl P((UNCH *));
+VOID mdnot P((UNCH *));
+VOID mdsrmdef P((UNCH *));
+VOID mdsrmuse P((UNCH *));
+int netetd P((struct parse *));
+VOID newtoken P((struct thdr *,struct mpos *,UNCH *));
+int nstetd P((void));
+UNCH *ntoa P((int));
+int offbit P((unsigned long *,int,int));
+int parsecon P((UNCH *,struct parse *));
+int parsefpi P((struct fpi *));
+struct thdr *parsegcm P((struct parse *,struct thdr *,struct thdr *));
+VOID parselit P((UNCH *,struct parse *,unsigned int,UNCH));
+struct thdr *parsemod P((int));
+int parsepro P((void));
+VOID parseseq P((UNCH *,int));
+VOID parsetag P((struct parse *));
+int parseval P((UNCH *,unsigned int,UNCH *));
+int pexmex P((struct etd *));
+unsigned int ptrsrch P((UNIV *,UNIV));
+UNCH *pubfield P((UNCH *,UNCH *,UNCH,UNS *));
+UNCH *replace P((UNCH *,UNCH *));
+UNCH *sandwich P((UNCH *,UNCH *,UNCH *));
+UNIV saverr P((unsigned int,struct parse *,UNCH *,UNCH *));
+UNIV savmderr P((unsigned int,UNCH *,UNCH *));
+VOID scbset P((void));
+VOID sdinit P((void));
+VOID setcurchar P((int));
+VOID setdtype P((void));
+int sgmlact P((UNCH));
+int sgmldecl P((void));
+VOID sgmlerr P((unsigned int,struct parse *,UNCH *,UNCH *));
+int shortref P((int,struct parse *));
+struct srh *srhfind P((UNCH *));
+VOID stack P((struct etd *));
+int stag P((int));
+int stagetd P((struct parse *));
+VOID startdtd P((void));
+UNCH *savenm P((UNCH *));
+UNCH *savestr P((UNCH *));
+VOID storedatt P((PNE));
+VOID svderr P((UNIV));
+VOID synerr P((unsigned int,struct parse *));
+int testend P((struct thdr *,struct mpos *,int,int));
+int tokenopt P((struct thdr *,struct mpos *));
+int tokenreq P((struct etd *,struct thdr *,struct mpos *));
+UNS vallen P((int,int,UNCH *));
+struct dcncb *dcndef P((UNCH *));
+struct entity *entdef P((UNCH *,UNCH,union etext *));
+int entget P((void));
+int entref P((UNCH *));
+struct etd *etdset P((struct etd *,UNCH,struct thdr *,struct etd **,
+ struct etd **, struct entity **));
+struct hash *hout P((struct hash **,UNCH *,int));
+struct fpi *mdextid P((UNCH *,struct fpi *,UNCH *,UNCH *,struct ne *));
+int parse P((struct parse *));
+struct ad *parseatt P((struct ad *,UNCH *));
+unsigned int parsegrp P((struct etd **,struct parse *, UNCH *));
+unsigned int parsngrp P((struct dcncb **,struct parse *, UNCH *));
+int parsemd P((UNCH *,int,struct parse *,unsigned int));
+UNCH *parsenm P((UNCH *,int));
+UNCH *parsetkn P((UNCH *,UNCH,int));
+UNCH *s2valnm P((UNCH *,UNCH *,UNCH,int));
+struct srh *srhdef P((UNCH *));
+int tokdata P((UNCH *, int));
+struct entity *usedef P((UNCH *));
diff --git a/usr.bin/sgmls/sgmls/sgmlincl.h b/usr.bin/sgmls/sgmls/sgmlincl.h
new file mode 100644
index 0000000..c4eb5cc
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlincl.h
@@ -0,0 +1,20 @@
+/* SGMLINCL.H: Include file for parser core. */
+#ifndef SGMLINCL /* Don't include this file more than once. */
+#define SGMLINCL 1
+#include "config.h"
+#include "std.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "action.h" /* Action names for all parsing. */
+#include "adl.h" /* Definitions for attribute list processing. */
+#include "error.h" /* Symbols for error codes. */
+#include "etype.h" /* Definitions for element type processing. */
+#include "keyword.h" /* Definitions for keyword processing. */
+#include "lextoke.h" /* Symbols for tokenization lexical classes. */
+#include "source.h" /* Templates for source entity control blocks. */
+#include "synxtrn.h" /* Declarations for concrete syntax constants. */
+#include "sgmlxtrn.h" /* External variable declarations. */
+#include "trace.h" /* Declarations for internal trace functions. */
+#include "sgmlmain.h"
+#include "sgmlaux.h"
+#include "sgmlfnsm.h" /* ANSI C: Declarations for SGML functions. */
+#endif /* ndef SGMLINCL */
diff --git a/usr.bin/sgmls/sgmls/sgmlio.c b/usr.bin/sgmls/sgmls/sgmlio.c
new file mode 100644
index 0000000..c78bb7a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlio.c
@@ -0,0 +1,384 @@
+/* sgmlio.c -
+ IO functions for core parser.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+/* SGML must see a file in which records start with RS and end with
+ RE, and EOFCHAR (Ctl-Z) is present at the end. This module must
+ supply these characters if they are not naturally present in the
+ file. SGML will open two files at a time: when an entity is
+ nested, the new file is opened before closing the old in order to
+ make sure the open is successful. If it is, the original open file
+ is closed temporarily (IOPEND); when the stack is popped, the new
+ file is closed and the original file is re-opened (IOCONT). SGML
+ will check error returns for the initial open of a file and all
+ reads, and for re-openings when the stack is popped, but not for
+ closes. Returning <0 indicates an error; 0 or more is a successful
+ operation, except for IOREAD where the return value is the number
+ of characters read, and must exceed 0 to be successful. The first
+ READ must always be successful, and normally consists of just
+ priming the buffer with EOBCHAR (or RS EOBCHAR). SGMLIO must
+ assure that there is an EOBCHAR at the end of each block read,
+ except for the last block of the entity, which must have an
+ EOFCHAR.
+
+ SGML views an entity as a contiguous whole, without regard to its
+ actual form of storage. SGMLIO supports entities that are
+ equivalent to a single file of one or more records, or to a
+ concatenation of files.
+*/
+
+/* Uses only stream I/O. This module should be portable to most ANSI
+ systems. */
+/* We try to ensure that if an IO operation fails, then errno will contain
+ a meaningful value (although it may be zero.) */
+
+#include "config.h"
+#ifdef HAVE_O_NOINHERIT
+#include <fcntl.h>
+#include <io.h>
+#endif /* HAVE_O_NOINHERIT */
+
+#include "sgmlaux.h" /* Include files for auxiliary functions.. */
+
+#ifdef HAVE_O_NOINHERIT
+#define FOPENR(file) nifopen(file)
+FILE *nifopen P((char *));
+#else /* not HAVE_O_NOINHERIT */
+#define FOPENR(file) fopen((file), "r")
+#endif /* not HAVE_O_NOINHERIT */
+
+struct iofcb { /* I/O file control block. */
+ FILE *fp; /* File handle. */
+ fpos_t off; /* Offset in file of current read block. */
+ char *next; /* Next file (NULL if no more). */
+ char *file; /* Current file (no length byte). */
+ int pendoff; /* Offset into line when file suspended. */
+ char bol; /* Non-zero if currently at beginning of line. */
+ char first; /* Non-zero if the first read. */
+ char wasbol; /* Non-zero if current block was at beginning of line. */
+ char canseek;
+ UNCH *pendbuf; /* Saved partial buffer for suspended file
+ that can't be closed and reopened. */
+};
+
+static char *lastfile; /* The name of the last file closed. */
+static int bufsize; /* Size of buffer passed to ioread(). */
+static char ismagic[256]; /* Table of magic chars that need to be prefixed
+ by DELNONCH. */
+static int stdinused = 0;
+
+static char *nextstr P((char *)); /* Iterate over list of strings. */
+static FILE *openfile P((char *, char *));
+static int closefile P((FILE *));
+static int isreg P((FILE *));
+
+VOID ioinit(swp)
+struct switches *swp;
+{
+ ismagic[EOBCHAR] = 1;
+ ismagic[EOFCHAR] = 1;
+ ismagic[EOS] = 1;
+ ismagic[(UNCH)DELNONCH] = 1;
+ ismagic[(UNCH)GENRECHAR] = 1;
+ bufsize = swp->swbufsz;
+}
+
+int ioopen(id, pp)
+UNIV id;
+UNIV *pp;
+{
+ struct iofcb *f;
+ char *s;
+ errno = 0;
+ if (!id)
+ return -1;
+ s = id;
+ if (!*s)
+ return -1;
+ f = (struct iofcb *)rmalloc((UNS)sizeof(struct iofcb));
+ f->file = s;
+ f->next = nextstr(s);
+ errno = 0;
+ f->fp = openfile(f->file, &f->canseek);
+ f->bol = 1;
+ f->first = 1;
+ f->pendbuf = 0;
+ *pp = (UNIV)f;
+ return f->fp ? 1 : -1;
+}
+
+VOID ioclose(p)
+UNIV p;
+{
+ struct iofcb *f = (struct iofcb *)p;
+ if (f->fp)
+ closefile(f->fp);
+ lastfile = f->file;
+ frem((UNIV)f);
+}
+
+VOID iopend(p, off, buf)
+UNIV p;
+int off;
+UNCH *buf;
+{
+ struct iofcb *f = (struct iofcb *)p;
+ if (!f->canseek) {
+ UNCH *s;
+ for (s = buf + off; *s != EOFCHAR && *s != EOBCHAR; s++)
+ ;
+ s++;
+ f->pendbuf = (UNCH *)rmalloc((UNS)(s - buf - off));
+ memcpy((UNIV)f->pendbuf, (UNIV)(buf + off), (UNS)(s - buf - off));
+ return;
+ }
+ f->bol = 0;
+ if (f->wasbol) {
+ if (off == 0)
+ f->bol = 1;
+ else
+ off--;
+ }
+ f->pendoff = off;
+ if (f->fp) {
+ fclose(f->fp);
+ f->fp = 0;
+ }
+}
+
+int iocont(p)
+UNIV p;
+{
+ struct iofcb *f = (struct iofcb *)p;
+ int c = EOF;
+ int off = f->pendoff;
+
+ if (!f->canseek)
+ return 0;
+
+ errno = 0;
+ f->fp = FOPENR(f->file);
+ if (!f->fp)
+ return -1;
+ if (fsetpos(f->fp, &f->off))
+ return -1;
+ while (--off >= 0) {
+ c = getc(f->fp);
+ if (c != EOF && ismagic[c])
+ off--;
+ }
+ if (c == '\n')
+ f->bol = 1;
+ if (ferror(f->fp))
+ return -1;
+ return 0;
+}
+
+/* Return -1 on error, otherwise the number of bytes read. The
+strategy is to concatenate the files, insert a RS at the beginning of
+each line, and change each '\n' into a RE. The returned data
+shouldn't cross a file boundary, otherwise error messages might be
+inaccurate. The first read must always succeed. */
+
+int ioread(p, buf, newfilep)
+UNIV p;
+UNCH *buf;
+int *newfilep;
+{
+ int i = 0;
+ struct iofcb *f = (struct iofcb *)p;
+ FILE *fp;
+ int c;
+
+ *newfilep = 0;
+ if (f->first) {
+ buf[i] = EOBCHAR;
+ f->first = 0;
+ return 1;
+ }
+ if (f->pendbuf) {
+ for (i = 0;
+ (buf[i] = f->pendbuf[i]) != EOBCHAR && buf[i] != EOFCHAR;
+ i++)
+ ;
+ frem((UNIV)f->pendbuf);
+ f->pendbuf = 0;
+ return i + 1;
+ }
+ fp = f->fp;
+ for (;;) {
+ errno = 0;
+ if (f->canseek && fgetpos(fp, &f->off))
+ f->canseek = 0;
+ errno = 0;
+ c = getc(fp);
+ if (c != EOF)
+ break;
+ if (ferror(fp))
+ return -1;
+ if (closefile(fp) == EOF)
+ return -1;
+ if (!f->next){
+ f->fp = 0;
+ buf[0] = EOFCHAR;
+ return 1;
+ }
+ f->file = f->next;
+ f->next = nextstr(f->next);
+ *newfilep = 1;
+ errno = 0;
+ fp = f->fp = openfile(f->file, &f->canseek);
+ if (!fp)
+ return -1;
+ f->bol = 1;
+ }
+ if (f->bol) {
+ f->bol = 0;
+ buf[i++] = RSCHAR;
+ f->wasbol = 1;
+ }
+ else
+ f->wasbol = 0;
+ errno = 0;
+ for (;;) {
+ if (c == '\n') {
+ f->bol = 1;
+ buf[i++] = RECHAR;
+ break;
+ }
+ if (ismagic[c]) {
+ buf[i++] = DELNONCH;
+ buf[i++] = SHIFTNON(c);
+ }
+ else
+ buf[i++] = c;
+ if (i >= bufsize - 2)
+ break;
+ c = getc(fp);
+ if (c == EOF) {
+ if (ferror(fp))
+ return -1;
+ /* This is in the middle of a line. */
+ break;
+ }
+ }
+ buf[i++] = EOBCHAR;
+ return i;
+}
+
+static char *nextstr(p)
+char *p;
+{
+ p = strchr(p, '\0');
+ return *++p ? p : 0;
+}
+
+/* Return the filename associated with p. If p is NULL, return the filename
+of the last file closed. */
+
+char *ioflid(p)
+UNIV p;
+{
+ if (!p)
+ return lastfile;
+ return ((struct iofcb *)p)->file;
+}
+
+static
+FILE *openfile(name, seekp)
+char *name;
+char *seekp;
+{
+ FILE *fp;
+ if (strcmp(name, STDINNAME) == 0) {
+ if (stdinused)
+ return 0;
+ stdinused = 1;
+ *seekp = 0;
+ return stdin;
+ }
+ fp = FOPENR(name);
+ if (fp)
+ *seekp = isreg(fp);
+ return fp;
+}
+
+/* Return -1 on error, 0 otherwise. */
+
+static
+int closefile(fp)
+FILE *fp;
+{
+ if (fp == stdin) {
+ stdinused = 0;
+ clearerr(fp);
+ return 0;
+ }
+ else
+ return fclose(fp);
+}
+
+#ifdef HAVE_O_NOINHERIT
+
+/* This is the same as fopen(name, "r") except that it tells DOS that
+the file descriptor should not be inherited by child processes. */
+
+FILE *nifopen(name)
+char *name;
+{
+ int fd = open(name, O_RDONLY|O_NOINHERIT|O_TEXT);
+ if (fd < 0)
+ return 0;
+ return fdopen(fd, "r");
+}
+
+#endif /* HAVE_O_NOINHERIT */
+
+#ifdef HAVE_SYS_STAT_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_ISREG
+#ifdef S_IFMT
+#ifdef S_IFREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif /* S_IFREG */
+#endif /* S_IFMT */
+#endif /* not S_ISREG */
+
+#endif /* HAVE_SYS_STAT_H */
+
+/* Return 1 if fp might be associated with a regular file. 0
+otherwise. We check this because on many Unix systems lseek() will
+succeed on a (pseudo-)terminal although terminals aren't seekable in
+the way we need. */
+
+static
+int isreg(fp)
+FILE *fp;
+{
+#ifdef S_ISREG
+ struct stat sb;
+
+ /* This assumes that a system that has S_ISREG will also have
+ fstat() and fileno(). */
+ if (fstat(fileno(fp), &sb) == 0)
+ return S_ISREG(sb.st_mode);
+#endif /* S_ISREG */
+ return 1;
+}
+
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+comment-column: 30
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgmlmain.h b/usr.bin/sgmls/sgmls/sgmlmain.h
new file mode 100644
index 0000000..3911f76
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlmain.h
@@ -0,0 +1,101 @@
+/* SGMLMAIN: Main interface to SGML services.
+
+Preprocessor variable names are the only supported interface
+to data maintained by SGML. They are defined in this file or in adl.h.
+*/
+/* Return control block types (RCBTYPE) from calls to parser (SGML):
+ Names and strings follow the convention for the IPBs.
+*/
+enum sgmlevent {
+ SGMLEOD, /* End of document. */
+ SGMLDAF, /* Data found. */
+ SGMLSTG, /* Start-tag found. */
+ SGMLETG, /* End-tag found. */
+ SGMLREF, /* Record end found. */
+ SGMLPIS, /* Processing instruction (string). */
+ SGMLAPP /* APPINFO (string) */
+};
+
+struct rcbdata { /* Return control block: DAF EOD REF PIS APP. */
+ UNS contersw; /* 1=context error; 2,4,8=data type; 0=not. */
+ UNS datalen; /* Length of data or PI (0=single nonchar). */
+ UNCH *data; /* Data, PI, single nonSGML, or NDATA ecb ptr. */
+};
+
+struct rcbtag { /* Return control block for STG and ETG. */
+ UNS contersw; /* 1=context error; 2=NET enabled; 0/0=not. */
+ UNS tagmin; /* Minim: NONE NULL NET DATA; implied by S/ETAG */
+ UNCH *curgi; /* Start-tag (or end-tag) GI. */
+ union {
+ struct ad *al; /* Start-tag: attribute list. */
+ UNCH *oldgi; /* End-tag: resumed GI. */
+ } ru;
+ struct ad *lal; /* Start-tag: link attribute list (UNUSED). */
+ UNS format; /* Format class for default processing. */
+ struct etd *tagreal; /* Dummy etd or ptr to GI that implied this tag.*/
+ int etictr; /* Number of elements on stack with NET enabled.*/
+ UNCH *srmnm; /* Current SHORTREF map name (NULL=#EMPTY). */
+};
+
+/* Accessors for rcbdata and rcbtag. */
+/* Datatype abbreviations: C=unsigned char S=string U=unsigned int L=4 bytes
+ A=array P=ptr to structure N=name (see sgmlcb.h)
+*/
+/* Data control block fields: processing instructions (SGMLPIS).
+*/
+#define PDATA(d) ((d).data) /*S PI string. */
+#define PDATALEN(d) ((d).datalen) /*U Length of PI string. */
+#define PIESW(d) (((d).contersw & 4)) /*U 1=PIDATA entity returned. */
+/* Data control block fields: other data types.
+*/
+#define CDATA(d) ((d).data) /*S CDATA content string. */
+#define CDATALEN(d) ((d).datalen) /*U Length of CDATA content string. */
+#define CONTERSW(d) (((d).contersw &1))/*U 1=CDATA or TAG out of context. */
+#define CDESW(d) (((d).contersw & 2)) /*U 1=CDATA entity returned. */
+#define SDESW(d) (((d).contersw & 4)) /*U 1=SDATA entity returned. */
+#define NDESW(d) (((d).contersw & 8)) /*U 1=NDATA entity returned. */
+#define NEPTR(d) ((PNE)(d).data) /*P Ptr to NDATA control block. */
+#define MARKUP(d) ((d).data) /*A Markup delimiter strings. */
+#define DTYPELEN(d) ((d).datalen) /*U Length of doc type name +len+EOS. */
+#define DOCTYPE(d) ((d).data) /*S Document type name (with len+EOS). */
+#define ADATA(d) ((d).data) /*S APPINFO */
+#define ADATALEN(d) ((d).datalen) /*U Length of APPINFO string. */
+/* Tag control block fields.
+*/
+#define ALPTR(t) ((t).ru.al) /*P Ptr to SGML attribute list. */
+#define CURGI(t) ((t).curgi+1) /*N GI of started or ended element. */
+#define OLDGI(t) ((t).ru.oldgi) /*S GI of resumed element. */
+#define TAGMIN(t) (t).tagmin /*U Minimization for current tag. */
+#define TAGREAL(t) ((t).tagreal) /*P Dummy etd that implied this tag. */
+#define TAGRLNM(t) ((UNCH *)(t).tagreal) /*P GI of tag that implied this tag.*/
+#define ETISW(t) (((t).contersw & 2)) /*U 1=NET delimiter enabled by ETI. */
+#define PEXSW(t) (((t).contersw & 4)) /*U 1=Element was plus exception. */
+#define MTYSW(t) (((t).contersw & 8)) /*U 1=Element is empty. */
+#define ETICTR(t) ((t).etictr) /*U Number of active NET delimiters. */
+#define SRMNM(t) ((t).srmnm) /*S Name of current SHORTREF map. */
+#define SRMCNT(t) ((t).contersw) /*U Number of SHORTREF maps defined. */
+#define FORMAT(t) ((t).format) /*U Format class.*/
+
+/* These function names are chosen so as to be distinct in the first 6
+letters. */
+
+/* Initialize. */
+struct markup *sgmlset P((struct switches *));
+/* Cleanup and return capacity usage statistics. */
+VOID sgmlend P((struct sgmlcap *));
+/* Set document entity. */
+int sgmlsdoc P((UNIV));
+/* Get entity. */
+int sgmlgent P((UNCH *, PNE *, UNCH **));
+/* Mark an entity. Return is non-zero if already marked.*/
+int sgmlment P((UNCH *));
+/* Get the next sgml event. */
+enum sgmlevent sgmlnext P((struct rcbdata *, struct rcbtag *));
+/* Get the error count. */
+int sgmlgcnterr P((void));
+/* Get the current location. */
+int sgmlloc P((unsigned long *, char **));
+/* Write out the SGML declaration. */
+VOID sgmlwrsd P((FILE *));
+/* Note subdocument capacity usage. */
+VOID sgmlsubcap P((long *));
diff --git a/usr.bin/sgmls/sgmls/sgmlmsg.c b/usr.bin/sgmls/sgmls/sgmlmsg.c
new file mode 100644
index 0000000..4d98c55
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlmsg.c
@@ -0,0 +1,514 @@
+/* sgmlmsg.c -
+ message handling for core parser
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+#include "sgmlaux.h"
+#include "msg.h"
+
+static nl_catd catd;
+
+#define TEXT_SET 1 /* message set number for text of messages */
+#define HEADER_SET 2 /* message set number for header strings */
+#define PARM_SET 3 /* message set number for special parameters */
+
+#ifdef HAVE_EXTENDED_PRINTF
+#define xfprintf fprintf
+#else
+extern int xfprintf VP((FILE *, char *,...));
+#endif
+
+#define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
+
+static char *gettext P((int));
+static char *getheader P((int));
+static char *getparm P((int));
+static VOID elttrace P((FILE *, int));
+static int printit P((FILE *, struct error *));
+static char *transparm P((UNCH *, char *));
+static VOID spaces P((FILE *, int));
+
+#define PARMBUFSIZ 50
+static char parmbuf[PARMBUFSIZ*2];
+static char *parmbuf1 = parmbuf;
+static char *parmbuf2 = parmbuf + PARMBUFSIZ;
+
+static char *prog; /* program name */
+static int sweltr; /* non-zero means print an element trace */
+static int swenttr; /* non-zero means print an entity trace */
+static int cnterr = 0;
+static VOID (*die) P((void));
+
+static char *headers[] = {
+"In file included",
+"SGML error", /* parameters: type, severity, number */
+"Unsupported feature", /* type U errors */
+"Error", /* for type R errors */
+"Warning", /* severity type I */
+" at %s, %.0sline %lu", /* ignore entity name and ccnt */
+" at entity %s, line %lu",
+"%.0s%.0s in declaration parameter %d", /* ignore first two parameters */
+"%.0s in declaration parameter %d", /* ignore first parameter */
+"%.0s", /* parse mode */
+" at end of file",
+" at end of entity",
+" at record start",
+" at record end",
+" at \"%c\"",
+" at \"\\%03o\"",
+" accessing \"%s\"",
+"Element structure:"
+};
+
+/* Indexes into headers[] */
+
+#define HDRPFX 0
+#define HDRALL 1
+#define HDRUNSUP 2
+#define HDRSYS 3
+#define HDRWARN 4
+#define HDRLOC 5
+#define HDRELOC 6
+#define HDRMD 7
+#define HDRMD2 8
+#define HDRMODE 9
+#define HDREOF 10
+#define HDREE 11
+#define HDRRS 12
+#define HDRRE 13
+#define HDRPRT 14
+#define HDRCTL 15
+#define HDRFIL 16
+#define HDRELT 17
+
+/* Special parameters (error::errsp) */
+static char *parms[] = {
+"character data",
+"element content",
+"mixed content",
+"replaceable character data",
+"tag close",
+"content model group",
+"content model occurrence indicator",
+"name group",
+"name token group",
+"system data",
+"parameter literal",
+"attribute value literal",
+"tokenized attribute value literal",
+"minimum literal",
+"markup declaration",
+"markup declaration comment",
+"ignored markup declaration",
+"declaration subset",
+"CDATA marked section",
+"IGNORE marked section",
+"RCDATA marked section",
+"prolog",
+"reference",
+"attribute specification list",
+"tokenized attribute value",
+"attribute specification list close",
+"SGML declaration",
+"attribute definition list",
+"document type",
+"element",
+"entity",
+"link type",
+"link set",
+"notation",
+"SGML",
+"short reference mapping",
+"link set use",
+"short reference use",
+};
+
+static FILE *tfp; /* temporary file for saved messages */
+
+struct saved {
+ long start;
+ long end;
+ char exiterr;
+ char countit;
+};
+
+VOID msgprint(e)
+struct error *e;
+{
+ if (printit(stderr, e))
+ ++cnterr;
+ fflush(stderr);
+ if (e->errtype == EXITERR) {
+ if (die) {
+ (*die)();
+ abort();
+ }
+ else
+ exit(EXIT_FAILURE);
+ }
+}
+
+/* Save an error message. */
+
+UNIV msgsave(e)
+struct error *e;
+{
+ struct saved *sv;
+
+ sv = (struct saved *)rmalloc(sizeof(struct saved));
+ if (!tfp) {
+ tfp = tmpfile();
+ if (!tfp)
+ exiterr(160, (struct parse *)0);
+ }
+ sv->start = ftell(tfp);
+ sv->countit = (char)printit(tfp, e);
+ sv->end = ftell(tfp);
+ sv->exiterr = (char)(e->errtype == EXITERR);
+ return (UNIV)sv;
+}
+
+/* Print a saved error message. */
+
+VOID msgsprint(p)
+UNIV p;
+{
+ struct saved *sv = (struct saved *)p;
+ long cnt;
+
+ assert(p != 0);
+ assert(tfp != 0);
+ if (fseek(tfp, sv->start, SEEK_SET) < 0)
+ return;
+ /* Temporary files are opened in binary mode, so this is portable. */
+ cnt = sv->end - sv->start;
+ while (--cnt >= 0) {
+ int c = getc(tfp);
+ if (c == EOF)
+ break;
+ putc(c, stderr);
+ }
+ fflush(stderr);
+ if (sv->countit)
+ ++cnterr;
+ if (sv->exiterr)
+ exit(EXIT_FAILURE);
+}
+
+/* Free a sved error message. */
+
+VOID msgsfree(p)
+UNIV p;
+{
+ frem(p);
+}
+
+/* Return 1 if it should be counted as an error. */
+
+static int printit(efp, e)
+FILE *efp;
+struct error *e;
+{
+ int indent;
+ int countit;
+ int hdrcode;
+ int filelevel = -1, prevfilelevel = -1, toplevel;
+ struct location loc;
+ char type[2], severity[2];
+
+ assert(e->errnum < SIZEOF(messages));
+ assert(messages[e->errnum].text != NULL);
+ if (prog) {
+ fprintf(efp, "%s: ", prog);
+ indent = strlen(prog) + 2; /* don't rely on return value of fprintf */
+ /* Don't want to waste too much space on indenting. */
+ if (indent > 10)
+ indent = 4;
+ }
+ else
+ indent = 4;
+
+ for (toplevel = 0; getlocation(toplevel, &loc); toplevel++)
+ if (loc.filesw) {
+ prevfilelevel = filelevel;
+ filelevel = toplevel;
+ }
+ toplevel--;
+
+ if (e->errtype == FILERR) {
+ toplevel--;
+ filelevel = prevfilelevel;
+ }
+ if (swenttr && filelevel > 0) {
+ int level = 0;
+ int middle = 0; /* in the middle of a line */
+ do {
+ (void)getlocation(level, &loc);
+ if (loc.filesw) {
+ if (middle) {
+ fputs(":\n", efp);
+ spaces(efp, indent);
+ }
+ else
+ middle = 1;
+ xfprintf(efp, getheader(HDRPFX));
+ xfprintf(efp, getheader(HDRLOC), ioflid(loc.fcb),
+ loc.ename, loc.rcnt, loc.ccnt);
+ }
+ else if (middle)
+ xfprintf(efp, getheader(HDRELOC),
+ loc.ename, loc.rcnt + 1, loc.ccnt);
+ }
+ while (++level != filelevel);
+ if (middle) {
+ fputs(":\n", efp);
+ spaces(efp, indent);
+ }
+ }
+
+ /* We use strings for the type and severity,
+ so that the format can use %.0s to ignore them. */
+
+ type[0] = messages[e->errnum].type;
+ type[1] = '\0';
+ severity[0] = messages[e->errnum].severity;
+ severity[1] = '\0';
+
+ countit = (severity[0] != 'I');
+ if (!countit)
+ hdrcode = HDRWARN;
+ else if (type[0] == 'R')
+ hdrcode = HDRSYS;
+ else if (type[0] == 'U')
+ hdrcode = HDRUNSUP;
+ else
+ hdrcode = HDRALL;
+
+ xfprintf(efp, getheader(hdrcode), type, severity, e->errnum);
+
+ if (filelevel >= 0) {
+ (void)getlocation(filelevel, &loc);
+ xfprintf(efp, getheader(HDRLOC),
+ ioflid(loc.fcb), loc.ename, loc.rcnt, loc.ccnt);
+ while (filelevel < toplevel) {
+ ++filelevel;
+ if (swenttr) {
+ (void)getlocation(filelevel, &loc);
+ xfprintf(efp, getheader(HDRELOC),
+ loc.ename, loc.rcnt + 1, loc.ccnt);
+ }
+ }
+ }
+
+ /* It is necessary to copy the result of getparm() because
+ the specification of catgets() says in can return a
+ pointer to a static buffer which may get overwritten
+ by the next call to catgets(). */
+
+ switch (e->errtype) {
+ case MDERR:
+ strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
+ xfprintf(efp, getheader(HDRMD), parmbuf,
+ (e->subdcl ? e->subdcl : (UNCH *)""), e->parmno);
+ break;
+ case MDERR2:
+ /* no subdcl parameter */
+ strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
+ xfprintf(efp, getheader(HDRMD2), parmbuf, e->parmno);
+ break;
+ case DOCERR:
+ case EXITERR:
+ if (toplevel < 0)
+ break;
+ strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
+ xfprintf(efp, getheader(HDRMODE), parmbuf);
+ switch (loc.curchar) {
+ case EOFCHAR:
+ xfprintf(efp, getheader(HDREOF));
+ break;
+ case RSCHAR:
+ xfprintf(efp, getheader(HDRRS));
+ break;
+ case RECHAR:
+ xfprintf(efp, getheader(HDRRE));
+ break;
+ case DELNONCH:
+ xfprintf(efp, getheader(HDRCTL), UNSHIFTNON(loc.nextchar));
+ break;
+ case EOS:
+ xfprintf(efp, getheader(HDREE));
+ break;
+ case EOBCHAR:
+ break;
+ default:
+ if (ISASCII(loc.curchar) && isprint(loc.curchar))
+ xfprintf(efp, getheader(HDRPRT), loc.curchar);
+ else
+ xfprintf(efp, getheader(HDRCTL), loc.curchar);
+ break;
+ }
+ break;
+ case FILERR:
+ if (getlocation(toplevel + 1, &loc))
+ xfprintf(efp, getheader(HDRFIL), ioflid(loc.fcb));
+ break;
+ }
+ fputs(":\n", efp);
+
+ if (e->errtype == FILERR && e->sverrno != 0) {
+ char *errstr = strerror(e->sverrno);
+ UNS len = strlen(errstr);
+ /* Strip a trailing newline if there is one. */
+ if (len > 0 && errstr[len - 1] == '\n')
+ len--;
+ spaces(efp, indent);
+ for (; len > 0; len--, errstr++)
+ putc(*errstr, efp);
+ fputs(":\n", efp);
+ }
+
+ spaces(efp, indent);
+
+ xfprintf(efp, gettext(e->errnum),
+ transparm((UNCH *)e->eparm[0], parmbuf1),
+ transparm((UNCH *)e->eparm[1], parmbuf2));
+ putc('\n', efp);
+
+ if (sweltr)
+ elttrace(efp, indent);
+ return countit;
+}
+
+/* Print an element trace. */
+static VOID elttrace(efp, indent)
+FILE *efp;
+int indent;
+{
+ int i = 1;
+ UNCH *gi;
+
+ gi = getgi(i);
+ if (!gi)
+ return;
+ spaces(efp, indent);
+ xfprintf(efp, getheader(HDRELT));
+ do {
+ fprintf(efp, " %s", (char *)gi);
+ gi = getgi(++i);
+ } while (gi);
+ putc('\n', efp);
+}
+
+static VOID spaces(efp, indent)
+FILE *efp;
+int indent;
+{
+ while (--indent >= 0)
+ putc(' ', efp);
+}
+
+VOID msginit(swp)
+struct switches *swp;
+{
+ catd = swp->catd;
+ prog = swp->prog;
+ sweltr = swp->sweltr;
+ swenttr = swp->swenttr;
+ die = swp->die;
+}
+
+/* Return the error count. */
+
+int msgcnterr()
+{
+ return cnterr;
+}
+
+/* Transform a parameter into a form suitable for printing. */
+
+static char *transparm(s, buf)
+UNCH *s;
+char *buf;
+{
+ char *ptr;
+ int cnt;
+
+ if (!s)
+ return 0;
+
+ ptr = buf;
+ cnt = PARMBUFSIZ - 4; /* space for `...\0' */
+
+ while (*s) {
+ UNCH ch = *s++;
+ if (ch == DELNONCH) {
+ if (*s == '\0')
+ break;
+ ch = UNSHIFTNON(*s);
+ s++;
+ }
+ if (ch == DELCDATA || ch == DELSDATA)
+ ;
+ else if (ch == '\\') {
+ if (cnt < 2)
+ break;
+ *ptr++ = '\\';
+ *ptr++ = '\\';
+ cnt -= 2;
+ }
+ else if (ISASCII(ch) && isprint(ch)) {
+ if (cnt < 1)
+ break;
+ *ptr++ = ch;
+ cnt--;
+ }
+ else {
+ if (cnt < 4)
+ break;
+ sprintf(ptr, "\\%03o", ch);
+ ptr += 4;
+ cnt -= 4;
+ }
+ }
+ if (!*s)
+ *ptr = '\0';
+ else
+ strcpy(ptr, "...");
+ return buf;
+}
+
+/* The message and set numbers in the catgets function must be > 0. */
+
+static char *gettext(n)
+int n;
+{
+ assert(n > 0 && n < SIZEOF(messages));
+ assert(messages[n].text != 0);
+ return catgets(catd, TEXT_SET, n, messages[n].text);
+}
+
+static char *getheader(n)
+int n;
+{
+ assert(n >= 0 && n < SIZEOF(headers));
+ return catgets(catd, HEADER_SET, n + 1, headers[n]);
+}
+
+static char *getparm(n)
+int n;
+{
+ assert(n >= 0 && n < SIZEOF(parms));
+ return catgets(catd, PARM_SET, n + 1, parms[n]);
+}
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/sgmls.1 b/usr.bin/sgmls/sgmls/sgmls.1
new file mode 100644
index 0000000..bd92c92
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmls.1
@@ -0,0 +1,970 @@
+'\" $Id$
+'\" t
+.\" Uncomment the next line to get a man page accurate for MS-DOS
+.\"nr Os 1
+.\" Uncomment the next line if tracing is enabled.
+.\"nr Tr 1
+.if \n(.g .if !r Os .nr Os 0
+.tr \(ts"
+.ds S \s-1SGML\s0
+.de TS
+.br
+.sp .5
+..
+.de TE
+.br
+.sp .5
+..
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH SGMLS 1
+.SH NAME
+sgmls \- a validating SGML parser
+.sp
+An \*S System Conforming to
+.if n .br
+International Standard ISO 8879 \(em
+.br
+Standard Generalized Markup Language
+.SH SYNOPSIS
+.B sgmls
+[
+.B \-deglprsuv
+]
+[
+.BI \-c file
+]
+.if \n(Os=1 \{\
+[
+.BI \-f file
+]
+.\}
+[
+.BI \-i name
+]
+[
+.BI \-m file
+]
+.if \n(Tr \{\
+[
+.BI \-x flags
+]
+[
+.BI \-y flags
+]
+.\}
+[
+.I filename\|.\|.\|.
+]
+.SH DESCRIPTION
+.I Sgmls
+parses and validates
+the \*S document entity in
+.I filename\|.\|.\|.
+and prints on the standard output a simple \s-1ASCII\s0 representation of its
+Element Structure Information Set.
+(This is the information set which a structure-controlled
+conforming \*S application should act upon.)
+Note that the document entity may be spread amongst several files;
+for example, the SGML declaration, document type declaration and document
+instance set could each be in a separate file.
+If no filenames are specified, then
+.I sgmls
+will read the document entity from the standard input.
+A filename of
+.B \-
+can also be used to refer to the standard input.
+.LP
+The following options are available:
+.TP
+.BI \-c file
+Report any capacity limits that are exceeded
+and write a report of capacity usage to
+.IR file .
+The report is in the format of a RACT result.
+RACT is the Reference Application for Capacity Testing defined in the
+Proposed American National Standard
+.I
+Conformance Testing for Standard Generalized Markup Language (SGL) Systems
+(X3.190-199X),
+Draft July 1991.
+.TP
+.B \-d
+Warn about duplicate entity declarations.
+.TP
+.B \-e
+Describe open entities in error messages.
+Error messages always include the position of the most recently
+opened external entity.
+.if \n(Os=1 \{\
+.TP
+.BI \-f file
+Redirect errors to
+.IR file .
+.\}
+.TP
+.B \-g
+Show the \s-1GI\s0s of open elements in error messages.
+.TP
+.BI \-i name
+Pretend that
+.RS
+.IP
+.BI <!ENTITY\ %\ name\ \(tsINCLUDE\(ts>
+.LP
+occurs at the start of the document type declaration subset
+in the \*S document entity.
+Since repeated definitions of an entity are ignored,
+this definition will take precedence over any other definitions
+of this entity in the document type declaration.
+Multiple
+.B \-i
+options are allowed.
+If the \*S declaration replaces the reserved name
+.B INCLUDE
+then the new reserved name will be the replacement text of the entity.
+Typically the document type declaration will contain
+.IP
+.BI <!ENTITY\ %\ name\ \(tsIGNORE\(ts>
+.LP
+and will use
+.BI % name ;
+in the status keyword specification of a marked section declaration.
+In this case the effect of the option will be to cause the marked
+section not to be ignored.
+.RE
+.TP
+.B \-l
+Output
+.B L
+commands giving the current line number and filename.
+.TP
+.BI \-m file
+Map public identifiers and entity names to system identifiers
+using the catalog entry file
+.IR file .
+Multiple
+.B \-m
+options are allowed.
+Catalog entry files specified with the
+.B -m
+option will be searched before the defaults.
+.TP
+.B \-p
+Parse only the prolog.
+.I Sgmls
+will exit after parsing the document type declaration.
+Implies
+.BR \-s .
+.TP
+.B \-r
+Warn about defaulted references.
+.TP
+.B \-s
+Suppress output.
+Error messages will still be printed.
+.TP
+.B \-u
+Warn about undefined elements: elements used in the DTD but not defined.
+.TP
+.B \-v
+Print the version number.
+.if \n(Tr \{\
+.TP
+.BI \-x flags
+.br
+.ns
+.TP
+.BI \-y flags
+Enable debugging output;
+.B \-x
+applies to the document body,
+.B \-y
+to the prolog.
+Each character in the
+.I flags
+argument enables tracing of a particular activity.
+.RS
+.TP
+.B t
+Trace state transitions.
+.TP
+.B a
+Trace attribute activity.
+.TP
+.B c
+Trace context checking.
+.TP
+.B d
+Trace declaration parsing.
+.TP
+.B e
+Trace entities.
+.TP
+.B g
+Trace groups.
+.TP
+.B i
+Trace \s-1ID\s0s.
+.TP
+.B m
+Trace marked sections.
+.TP
+.B n
+Trace notations.
+.RE
+.\}
+.SS "Entity Manager"
+An external entity resides in one or more files.
+The entity manager component of
+.I sgmls
+maps a sequence of files into an entity in three sequential stages:
+.IP 1.
+each carriage return character is turned into a non-SGML character;
+.IP 2.
+each newline character is turned into a record end character,
+and at the same time
+a record start character is inserted at the beginning of each line;
+.IP 3.
+the files are concatenated.
+.LP
+A system identifier is
+interpreted as a list of filenames separated by
+.if \n(Os=0 colons.
+.if \n(Os=1 semi-colons.
+A filename of
+.B \-
+can be used to refer to the standard input.
+.LP
+If a system identifier is not specified,
+then the entity manager can generate one using catalog
+entry files in the format defined in the SGML Open Draft Technical
+Resolution on Entity Management. A catalog entry file contains a
+sequence of entries in one of the following four forms:
+.TP
+.BI PUBLIC\ pubid\ sysid
+This specifies that
+.I sysid
+should be used as the system identifier if the public
+identifier is
+.IR pubid .
+.I Sysid
+is a system identifier as defined in ISO 8879 and
+.I pubid
+is a public identifier as defined in ISO 8879.
+.TP
+.BI ENTITY\ name\ sysid
+This specifies that
+.I sysid
+should be used as the system identifier if the entity is a general
+entity whose name is
+.IR name .
+.TP
+.BI ENTITY\ % name\ sysid
+This specifies that
+.I sysid
+should be used as the system identifier if the entity is a parameter
+entity whose name is
+.IR name .
+Note that there is no space between the
+.B %
+and the
+.IR name .
+.TP
+.BI DOCTYPE\ name\ sysid
+This specifies that
+.I sysid
+should be used as the system identifier if the entity is an
+entity declared in a document type declaration whose document type name is
+.IR name .
+.LP
+The last two forms are extensions to the SGML Open format.
+The delimiters can be omitted from the
+.I sysid
+provided it does not contain any white space.
+Comments are allowed between parameters delimited by
+.B --
+as in SGML.
+The environment variable
+.B \s-1SGML_CATALOG_FILES\s0
+contains a
+.if \n(Os=0 colon-separated
+.if \n(Os=1 semicolon-separated
+list of catalog entry files.
+These will be searched after any catalog entry files specified
+using the
+.B \-m
+option.
+If this environment variable is not set,
+then a system dependent list of catalog entry files will be used.
+A match in a catalog entry file for a PUBLIC entry will take
+precedence over a match in the same file for an ENTITY
+or DOCTYPE entry.
+A filename in a system identifier in a catalog entry file
+is interpreted relative to the directory containing the catalog
+entry file.
+.LP
+If no match can be found in a catalog entry file, then the entity
+manager will attempt to generate a filename using the public
+identifier (if there is one) and other information available to it.
+Notation identifiers are not subject to this treatment. This process
+is controlled by the environment variable
+.BR \s-1SGML_PATH\s0 ;
+this contains a
+.if \n(Os=0 colon-separated
+.if \n(Os=1 semicolon-separated
+list of filename templates.
+A filename template is a filename that may contain
+substitution fields; a substitution field is a
+.B %
+character followed by a single letter that indicates the value
+of the substitution.
+The value of a substitution can either be a string
+or it can be
+.IR null .
+The entity manager transforms the list of
+filename templates into a list of filenames by substituting for each
+substitution field and discarding any template
+that contained a substitution field whose value was null.
+It then uses the first resulting filename that exists and is readable.
+Substitution values are transformed before being used for substitution:
+firstly, any names that were subject to upper case substitution
+are folded to lower case;
+secondly,
+.if \n(Os=0 \{\
+.\" Unix
+space characters are mapped to underscores
+and slashes are mapped to percents.
+.\}
+.if \n(Os=1 \{\
+.\" MS-DOS
+the characters
+.B +,./:=?
+and space characters are deleted.
+.\}
+The value of the
+.B %S
+field is not transformed.
+The values of substitution fields are as follows:
+.TP
+.B %%
+A single
+.BR % .
+.TP
+.B %D
+The entity's data content notation.
+This substitution will succeed only for external data entities.
+.TP
+.B %N
+The entity, notation or document type name.
+.TP
+.B %P
+The public identifier if there was a public identifier,
+otherwise null.
+.TP
+.B %S
+The system identifier if there was a system identifier
+otherwise null.
+.TP
+.B %X
+(This is provided mainly for compatibility with \s-1ARCSGML\s0.)
+A three-letter string chosen as follows:
+.LP
+.RS
+.ne 11
+.TS
+tab(&);
+c|c|c s
+c|c|c s
+c|c|c|c
+c|c|c|c
+l|lB|lB|lB.
+&&With public identifier
+&&_
+&No public&Device&Device
+&identifier&independent&dependent
+_
+Data or subdocument entity&nsd&pns&vns
+General SGML text entity&gml&pge&vge
+Parameter entity&spe&ppe&vpe
+Document type definition&dtd&pdt&vdt
+Link process definition&lpd&plp&vlp
+.TE
+.LP
+The device dependent version is selected if the public text class
+allows a public text display version but no public text display
+version was specified.
+.RE
+.TP
+.B %Y
+The type of thing for which the filename is being generated:
+.TS
+tab(&);
+l lB.
+SGML subdocument entity&sgml
+Data entity&data
+General text entity&text
+Parameter entity&parm
+Document type definition&dtd
+Link process definition&lpd
+.TE
+.LP
+The value of the following substitution fields will be null
+unless a valid formal public identifier was supplied.
+.TP
+.B %A
+Null if the text identifier in the
+formal public identifier contains an unavailable text indicator,
+otherwise the empty string.
+.TP
+.B %C
+The public text class, mapped to lower case.
+.TP
+.B %E
+The public text designating sequence (escape sequence)
+if the public text class is
+.BR \s-1CHARSET\s0 ,
+otherwise null.
+.TP
+.B %I
+The empty string if the owner identifier in the formal public identifier
+is an \s-1ISO\s0 owner identifier,
+otherwise null.
+.TP
+.B %L
+The public text language, mapped to lower case,
+unless the public text class is
+.BR \s-1CHARSET\s0 ,
+in which case null.
+.TP
+.B %O
+The owner identifier (with the
+.B +//
+or
+.B \-//
+prefix stripped.)
+.TP
+.B %R
+The empty string if the owner identifier in the formal public identifier
+is a registered owner identifier,
+otherwise null.
+.TP
+.B %T
+The public text description.
+.TP
+.B %U
+The empty string if the owner identifier in the formal public identifier
+is an unregistered owner identifier,
+otherwise null.
+.TP
+.B %V
+The public text display version.
+This substitution will be null if the public text class
+does not allow a display version or if no version was specified.
+If an empty version was specified, a value of
+.B default
+will be used.
+.LP
+Normally if the external identifier for an entity includes a system
+identifier, the entity manager will use the specified system
+identifier and not attempt to generate one.
+If, however,
+.B \s-1SGML_PATH\s0
+uses the
+.B %S
+field,
+then the entity manager will first search for a matching
+entry in the catalog entry files.
+If a match is found, then this will be used instead of the
+specified system identifier.
+Otherwise,
+if the specified system identifier does not contain any
+.if \n(Os=0 colons,
+.if \n(Os=1 semi-colons,
+the entity manager will use
+.B \s-1SGML_PATH\s0
+to generate a filename.
+Otherwise the entity manager will use the specified system identifier.
+.br
+.ne 18
+.SS "System declaration"
+The system declaration for
+.I sgmls
+is as follows:
+.LP
+.TS
+tab(&);
+c1 s1 s1 s1 s1 s1 s1 s1 s
+c s s s s s s s s
+l l s s s s s s s
+l l s s s s s s s
+l l s s s s s s s
+l l l s s s s s s
+c s s s s s s s s
+l l l l l l l l l
+l l l l l l l l l
+l l l l l l l l l
+l l s s s s s s s
+l l l s s s s s s
+l l l s s s s s s
+c s s s s s s s s
+l l l l l l l l l.
+SYSTEM "ISO 8879:1986"
+CHARSET
+BASESET&"ISO 646-1983//CHARSET
+&\h'\w'"'u'International Reference Version (IRV)//ESC 2/5 4/0"
+DESCSET&0\0128\00
+CAPACITY&PUBLIC&"ISO 8879:1986//CAPACITY Reference//EN"
+FEATURES
+MINIMIZE&DATATAG&NO&OMITTAG&YES&RANK&NO&SHORTTAG&YES
+LINK&SIMPLE&NO&IMPLICIT&NO&EXPLICIT&NO
+OTHER&CONCUR&NO&SUBDOC&YES 1&FORMAL&YES
+SCOPE&DOCUMENT
+SYNTAX&PUBLIC&"ISO 8879:1986//SYNTAX Reference//EN"
+SYNTAX&PUBLIC&"ISO 8879:1986//SYNTAX Core//EN"
+VALIDATE
+&GENERAL&YES&MODEL&YES&EXCLUDE&YES&CAPACITY&YES
+&NONSGML&YES&SGML&YES&FORMAL&YES
+.T&
+c s s s s s s s s
+l l l l l l l l l.
+SDIF
+&PACK&NO&UNPACK&NO
+.TE
+.LP
+Exceeding a capacity limit will be ignored unless the
+.B \-c
+option is given.
+.LP
+The memory usage of
+.I sgmls
+is not a function of the capacity points used by a document;
+however,
+.I sgmls
+can handle capacities significantly greater than the reference capacity set.
+.LP
+In some environments,
+higher values may be supported for the \s-1SUBDOC\s0 parameter.
+.LP
+Documents that do not use optional features are also supported.
+For example, if
+.B FORMAL\ NO
+is specified in the \*S declaration,
+public identifiers will not be required to be valid formal public identifiers.
+.LP
+Certain parts of the concrete syntax may be changed:
+.RS
+.LP
+The shunned character numbers can be changed.
+.LP
+Eight bit characters can be assigned to
+\s-1LCNMSTRT\s0, \s-1UCNMSTRT\s0, \s-1LCNMCHAR\s0 and \s-1UCNMCHAR\s0.
+.LP
+Uppercase substitution can be performed or not performed
+both for entity names and for other names.
+.LP
+Either short reference delimiters assigned by the reference delimiter set
+or no short reference delimiters are supported.
+.LP
+The reserved names can be changed.
+.LP
+The quantity set can be increased within certain limits
+subject to there being sufficient memory available.
+The upper limit on \s-1\%NAMELEN\s0 is 239.
+The upper limits on
+\s-1\%ATTCNT\s0, \s-1\%ATTSPLEN\s0, \s-1\%BSEQLEN\s0, \s-1\%ENTLVL\s0,
+\s-1\%LITLEN\s0, \s-1\%PILEN\s0, \s-1\%TAGLEN\s0, and \s-1\%TAGLVL\s0
+are more than thirty times greater than the reference limits.
+The upper limit on
+\s-1\%GRPCNT\s0, \s-1\%GRPGTCNT\s0, and \s-1\%GRPLVL\s0 is 253.
+\s-1\%NORMSEP\s0
+cannot be changed.
+\s-1\%DTAGLEN\s0
+are
+\s-1\%DTEMPLEN\s0
+irrelevant since
+.I sgmls
+does not support the
+\s-1\%DATATAG\s0
+feature.
+.RE
+.SS "\*S declaration"
+The \*S declaration may be omitted,
+the following declaration will be implied:
+.TS
+tab(&);
+c1 s1 s1 s1 s1 s1 s1 s1 s
+c s s s s s s s s
+l l s s s s s s s.
+<!SGML "ISO 8879:1986"
+CHARSET
+BASESET&"ISO 646-1983//CHARSET
+&\h'\w'"'u'International Reference Version (IRV)//ESC 2/5 4/0"
+DESCSET&\0\00\0\09\0UNUSED
+&\0\09\0\02\0\09
+&\011\0\02\0UNUSED
+&\013\0\01\013
+&\014\018\0UNUSED
+&\032\095\032
+&127\0\01\0UNUSED
+.T&
+l l l s s s s s s
+l l s s s s s s s
+l l l s s s s s s
+c s s s s s s s s
+l l l l l l l l l.
+CAPACITY&PUBLIC&"ISO 8879:1986//CAPACITY Reference//EN"
+SCOPE&DOCUMENT
+SYNTAX&PUBLIC&"ISO 8879:1986//SYNTAX Reference//EN"
+FEATURES
+MINIMIZE&DATATAG&NO&OMITTAG&YES&RANK&NO&SHORTTAG&YES
+LINK&SIMPLE&NO&IMPLICIT&NO&EXPLICIT&NO
+OTHER&CONCUR&NO&SUBDOC&YES 99999999&FORMAL&YES
+.T&
+c s s s s s s s s.
+APPINFO NONE>
+.TE
+with the exception that characters 128 through 254 will be assigned to
+\s-1DATACHAR\s0.
+.LP
+.I Sgmls
+identifies base character sets using the designating sequence in the
+public identifier. The following designating sequences are
+recognized:
+.TS
+tab(&);
+c c c c c
+c c c c ^
+c c c c ^
+l n n n l.
+Designating&ISO&Minimum&Number&Description
+Escape&Registration&Character&of&
+Sequence&Number&Number&Characters&
+_
+ESC 2/5 4/0&-&0&128&full set of ISO 646 IRV
+ESC 2/8 4/0&2&33&94&G0 set of ISO 646 IRV
+ESC 2/8 4/2&6&33&94&G0 set of ASCII
+ESC 2/13 4/1&100&32&96&G1 set of ISO 8859-1
+ESC 2/1 4/0&1&0&32&C0 set of ISO 646
+ESC 2/2 4/3&77&0&32&C1 set of ISO 6429
+ESC 2/5 2/15 3/0&-&0&256&the system character set
+.TE
+.LP
+When one of the G0 sets is used as a base set, the characters SPACE
+and DELETE are treated as occurring at positions 32 and 127
+respectively; although these characters are not part of the character
+sets designated by the escape sequences, this mimics the behaviour of
+ISO 2022 with respect to these code positions.
+.SS "Output format"
+The output is a series of lines.
+Lines can be arbitrarily long.
+Each line consists of an initial command character
+and one or more arguments.
+Arguments are separated by a single space,
+but when a command takes a fixed number of arguments
+the last argument can contain spaces.
+There is no space between the command character and the first argument.
+Arguments can contain the following escape sequences.
+.TP
+.B \e\e
+A
+.BR \e.
+.TP
+.B \en
+A record end character.
+.TP
+.B \e|
+Internal \s-1SDATA\s0 entities are bracketed by these.
+.TP
+.BI \e nnn
+The character whose code is
+.I nnn
+octal.
+.LP
+A record start character will be represented by
+.BR \e012 .
+Most applications will need to ignore
+.B \e012
+and translate
+.B \en
+into newline.
+.LP
+The possible command characters and arguments are as follows:
+.TP
+.BI ( gi
+The start of an element whose generic identifier is
+.IR gi .
+Any attributes for this element
+will have been specified with
+.B A
+commands.
+.TP
+.BI ) gi
+The end an element whose generic identifier is
+.IR gi .
+.TP
+.BI \- data
+Data.
+.TP
+.BI & name
+A reference to an external data entity
+.IR name ;
+.I name
+will have been defined using an
+.B E
+command.
+.TP
+.BI ? pi
+A processing instruction with data
+.IR pi .
+.TP
+.BI A name\ val
+The next element to start has an attribute
+.I name
+with value
+.I val
+which takes one of the following forms:
+.RS
+.TP
+.B IMPLIED
+The value of the attribute is implied.
+.TP
+.BI CDATA\ data
+The attribute is character data.
+This is used for attributes whose declared value is
+.BR \s-1CDATA\s0 .
+.TP
+.BI NOTATION\ nname
+The attribute is a notation name;
+.I nname
+will have been defined using a
+.B N
+command.
+This is used for attributes whose declared value is
+.BR \s-1NOTATION\s0 .
+.TP
+.BI ENTITY\ name\|.\|.\|.
+The attribute is a list of general entity names.
+Each entity name will have been defined using an
+.BR I ,
+.B E
+or
+.B S
+command.
+This is used for attributes whose declared value is
+.B \s-1ENTITY\s0
+or
+.BR \s-1ENTITIES\s0 .
+.TP
+.BI TOKEN\ token\|.\|.\|.
+The attribute is a list of tokens.
+This is used for attributes whose declared value is anything else.
+.RE
+.TP
+.BI D ename\ name\ val
+This is the same as the
+.B A
+command, except that it specifies a data attribute for an
+external entity named
+.IR ename .
+Any
+.B D
+commands will come after the
+.B E
+command that defines the entity to which they apply, but
+before any
+.B &
+or
+.B A
+commands that reference the entity.
+.TP
+.BI N nname
+.IR nname.
+Define a notation
+This command will be preceded by a
+.B p
+command if the notation was declared with a public identifier,
+and by a
+.B s
+command if the notation was declared with a system identifier.
+A notation will only be defined if it is to be referenced
+in an
+.B E
+command or in an
+.B A
+command for an attribute with a declared value of
+.BR \s-1NOTATION\s0 .
+.TP
+.BI E ename\ typ\ nname
+Define an external data entity named
+.I ename
+with type
+.I typ
+.RB ( \s-1CDATA\s0 ,
+.B \s-1NDATA\s0
+or
+.BR \s-1SDATA\s0 )
+and notation
+.IR not.
+This command will be preceded by one or more
+.B f
+commands giving the filenames generated by the entity manager from the system
+and public identifiers,
+by a
+.B p
+command if a public identifier was declared for the entity,
+and by a
+.B s
+command if a system identifier was declared for the entity.
+.I not
+will have been defined using a
+.B N
+command.
+Data attributes may be specified for the entity using
+.B D
+commands.
+An external data entity will only be defined if it is to be referenced in a
+.B &
+command or in an
+.B A
+command for an attribute whose declared value is
+.B \s-1ENTITY\s0
+or
+.BR \s-1ENTITIES\s0 .
+.TP
+.BI I ename\ typ\ text
+Define an internal data entity named
+.I ename
+with type
+.I typ
+.RB ( \s-1CDATA\s0
+or
+.BR \s-1SDATA\s0 )
+and entity text
+.IR text .
+An internal data entity will only be defined if it is referenced in an
+.B A
+command for an attribute whose declared value is
+.B \s-1ENTITY\s0
+or
+.BR \s-1ENTITIES\s0 .
+.TP
+.BI S ename
+Define a subdocument entity named
+.IR ename .
+This command will be preceded by one or more
+.B f
+commands giving the filenames generated by the entity manager from the system
+and public identifiers,
+by a
+.B p
+command if a public identifier was declared for the entity,
+and by a
+.B s
+command if a system identifier was declared for the entity.
+A subdocument entity will only be defined if it is referenced
+in a
+.B {
+command
+or in an
+.B A
+command for an attribute whose declared value is
+.B \s-1ENTITY\s0
+or
+.BR \s-1ENTITIES\s0 .
+.TP
+.BI s sysid
+This command applies to the next
+.BR E ,
+.B S
+or
+.B N
+command and specifies the associated system identifier.
+.TP
+.BI p pubid
+This command applies to the next
+.BR E ,
+.B S
+or
+.B N
+command and specifies the associated public identifier.
+.TP
+.BI f filename
+This command applies to the next
+.B E
+or
+.B S
+command and specifies an associated filename.
+There will be more than one
+.B f
+command for a single
+.B E
+or
+.B S
+command if the system identifier used a
+.if \n(Os=0 colon.
+.if \n(Os=1 semi-colon.
+.TP
+.BI { ename
+The start of the \*S subdocument entity
+.IR ename ;
+.I ename
+will have been defined using a
+.B S
+command.
+.TP
+.BI } ename
+The end of the \*S subdocument entity
+.IR ename .
+.TP
+.BI L lineno\ file
+.TQ
+.BI L lineno
+Set the current line number and filename.
+The
+.I filename
+argument will be omitted if only the line number has changed.
+This will be output only if the
+.B \-l
+option has been given.
+.TP
+.BI # text
+An \s-1APPINFO\s0 parameter of
+.I text
+was specified in the \*S declaration.
+This is not strictly part of the ESIS, but a structure-controlled
+application is permitted to act on it.
+No
+.B #
+command will be output if
+.B \s-1APPINFO\s0\ \s-1NONE\s0
+was specified.
+A
+.B #
+command will occur at most once,
+and may be preceded only by a single
+.B L
+command.
+.TP
+.B C
+This command indicates that the document was a conforming \*S document.
+If this command is output, it will be the last command.
+An \*S document is not conforming if it references a subdocument entity
+that is not conforming.
+.SH BUGS
+Some non-SGML characters in literals are counted as two characters for the
+purposes of quantity and capacity calculations.
+.SH "SEE ALSO"
+The \*S Handbook, Charles F. Goldfarb
+.br
+\s-1ISO\s0 8879 (Standard Generalized Markup Language),
+International Organization for Standardization
+.SH ORIGIN
+\s-1ARCSGML\s0 was written by Charles F. Goldfarb.
+.LP
+.I Sgmls
+was derived from \s-1ARCSGML\s0 by James Clark (jjc@jclark.com),
+to whom bugs should be reported.
diff --git a/usr.bin/sgmls/sgmls/sgmlxtrn.c b/usr.bin/sgmls/sgmls/sgmlxtrn.c
new file mode 100644
index 0000000..74d7894
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlxtrn.c
@@ -0,0 +1,225 @@
+/* Standard Generalized Markup Language Users' Group (SGMLUG)
+ SGML Parser Materials (ARCSGML 1.0)
+
+(C) 1983-1988 Charles F. Goldfarb (assigned to IBM Corporation)
+(C) 1988-1991 IBM Corporation
+
+Licensed to the SGML Users' Group for distribution under the terms of
+the following license: */
+
+char license[] =
+"SGMLUG hereby grants to any user: (1) an irrevocable royalty-free,\n\
+worldwide, non-exclusive license to use, execute, reproduce, display,\n\
+perform and distribute copies of, and to prepare derivative works\n\
+based upon these materials; and (2) the right to authorize others to\n\
+do any of the foregoing.\n";
+
+#include "sgmlincl.h"
+
+/* SGMLXTRN: Storage allocation and initialization for all public variables.
+ Exceptions: Constants lex????? and del????? are defined in
+ LEX?????.C modules; constants pcb????? are defined in PCB?????.c.
+*/
+int badresw = 0; /* 1=REF_ out of context; 0=valid. */
+int charmode = 0; /* >0=in #CHARS; 0=not. */
+int conactsw = 0; /* 1=return saved content action 0=get new one.*/
+int conrefsw = 0; /* 1=content reference att specified; 0=no. */
+int contersv = 0; /* Save contersw while processing pending REF. */
+int contersw = 0; /* 1=element or #CHARS out of context; 0=valid. */
+int datarc = 0; /* Return code for data: DAF_ or REF_. */
+int delmscsw = 0; /* 1=DELMSC must be read on return to es==0. */
+int didreq = 0; /* 1=required implied tag processed; 0=no. */
+int docelsw = 0; /* 1=had document element; 0=no */
+int dostag = 0; /* 1=retry newetd instead of parsing; 0=parse. */
+int dtdsw = 0; /* DOCTYPE declaration found: 1=yes; 0=no. */
+int entdatsw = 0; /* 2=CDATA entity; 4=SDATA; 8=NDATA; 0=none. */
+int entpisw = 0; /* 4=PI entity occurred; 0=not. */
+int eodsw = 0; /* 1=eod found in error; 0=not yet. */
+int eofsw = 0; /* 1=eof found in body of document; 0=not yet. */
+int es = -1; /* Index of current source in stack. */
+int etagimct = 0; /* Implicitly ended elements left on stack. */
+int etagimsw = 0; /* 1=end-tag implied by other end-tag; 0=not. */
+int etagmin = MINNONE; /* Minim: NONE NULL NET DATA; implied by S/ETAG*/
+int etictr = 0; /* Number of "NET enabled" tags on stack. */
+int etisw = 0; /* 1=tag ended with eti; 0=did not. */
+int indtdsw = 0; /* Are we in the DTD? 1=yes; 0=no. */
+int mslevel = 0; /* Nesting level of marked sections. */
+int msplevel = 0; /* Nested MS levels subject to special parse. */
+int prologsw = 1; /* 1=in prolog; 0=not. */
+int pss = 0; /* SGMLACT: scbsgml stack level. */
+int sgmlsw = 0; /* SGML declaration found: 1=yes; 0=no. */
+int stagmin = MINNONE; /* Minimization: NONE, NULL tag, implied by STAG*/
+int tagctr = 0; /* Tag source chars read. */
+int tages = -1; /* ES level at start of tag. */
+int ts = -1; /* Index of current tag in stack. */
+struct parse *propcb = &pcbpro; /* Current PCB for prolog parse. */
+int aentctr = 0; /* Number of ENTITY tokens in this att list. */
+int conact = 0; /* Return code from content parse. */
+int conrefsv = 0; /* Save conrefsw when doing implied start-tag.*/
+int dtdrefsw = 0; /* External DTD? 1=yes; 0=no. */
+int etiswsv = 0; /* Save etisw when processing implied start-tag.*/
+int grplvl = 0; /* Current level of nested grps in model. */
+int idrctr = 0; /* Number of IDREF tokens in this att list. */
+int mdessv = 0; /* ES level at start of markup declaration. */
+int notadn = 0; /* Position of NOTATION attribute in list. */
+int parmno = 0; /* Current markup declaration parameter number. */
+int pexsw = 0; /* 1=tag valid solely because of plus exception.*/
+int rcessv = 0; /* ES level at start of RCDATA content. */
+int tagdelsw = 0; /* 1=tag ended with delimiter; 0=no delimiter. */
+int tokencnt = 0; /* Number of tokens found in attribute value. */
+struct entity *ecbdeflt = 0; /* #DEFAULT ecb (NULL if no default entity). */
+struct etd *docetd = 0; /* The etd for the document as a whole. */
+struct etd *etagreal = 0; /* Actual or dummy etd that implied this tag. */
+struct etd *newetd = 0; /* The etd for a start- or end-tag recognized. */
+struct etd *nextetd = 0; /* ETD that must come next (only one choice). */
+struct etd *lastetd = 0; /* most recently ended ETD. */
+struct etd *stagreal = 0; /* Actual or dummy etd that implied this tag. */
+struct parse *conpcb = 0; /* Current PCB for content parse. */
+UNCH *data = 0; /* Pointer to returned data in buffer. */
+UNCH *mdname = 0; /* Name of current markup declaration. */
+UNCH *ptcon = 0; /* Current pointer into tbuf. */
+UNCH *ptpro = 0; /* Current pointer into tbuf. */
+UNCH *rbufs = 0; /* DOS file read area: start position for read. */
+UNCH *subdcl = 0; /* Subject of markup declaration (e.g., GI). */
+UNS conradn = 0; /* 1=CONREF attribute in list (0=no). */
+UNS datalen = 0; /* Length of returned data in buffer. */
+UNS entlen = 0; /* Length of TAG or EXTERNAL entity text. */
+UNS idadn = 0; /* Number of ID attribute (0 if none). */
+UNS noteadn = 0; /* Number of NOTATION attribute (0 if none). */
+UNS reqadn = 0; /* Num of atts with REQUIRED default (0=none). */
+int grplongs; /* Number of longs for GRPCNT bitvector. */
+
+/* Variable arrays and structures.
+*/
+struct ad *al = 0; /* Current attribute list work area. */
+struct dcncb *dcntab[1]; /* List of data content notation names. */
+struct entity *etab[ENTHASH]; /* Entity hash table. */
+struct etd *etdtab[ETDHASH]; /* Element type definition hash table. */
+struct fpi fpidf; /* Fpi for #DEFAULT entity. */
+struct id *itab[IDHASH]; /* Unique identifier hash table. */
+struct etd **nmgrp = 0; /* Element name group */
+PDCB *nnmgrp = 0; /* Notation name group */
+struct restate *scbsgml = 0; /* SGMLACT: return action state stack. */
+struct source *scbs = 0; /* Stack of open sources ("SCB stack"). */
+struct srh *srhtab[1]; /* List of SHORTREF table headers. */
+struct sgmlstat ds; /* Document statistics. */
+struct switches sw; /* Parser control switches set by text proc. */
+struct tag *tags = 0; /* Stack of open elements ("tag stack"). */
+struct thdr *gbuf = 0; /* Buffer for creating group. */
+struct thdr prcon[3]; /* 0-2: Model for *DOC content. */
+struct thdr undechdr; /* 0:Default model hdr for undeclared content.*/
+UNCH *dtype = 0; /* Document type name. */
+UNCH *entbuf = 0; /* Buffer for entity reference name. */
+UNCH fce[2]; /* String form of FCE char.
+ (fce[1] must be EOS).*/
+/* Buffer for non-SGML character reference.*/
+UNCH nonchbuf[2] = { DELNONCH };
+UNCH *tbuf; /* Work area for tokenization. */
+UNCH *lbuf = 0; /* In tbuf: Literal parse area.*/
+UNCH *sysibuf = 0; /* Buffer for system identifiers. */
+UNCH *pubibuf = 0; /* Buffer for public identifiers. */
+UNCH *nmbuf = 0; /* Name buffer used by mdentity. */
+struct mpos *savedpos;
+
+/* Constants.
+*/
+struct map dctab[] = { /* Keywords for declared content parameter.*/
+ { key[KRCDATA], MRCDATA+MPHRASE },
+ { key[KCDATA], MCDATA+MPHRASE },
+ { key[KANY], MANY+MCHARS+MGI },
+ { key[KEMPTY], MNONE+MPHRASE },
+ { NULL, 0 }
+};
+struct map deftab[] = { /* Default value keywords. */
+ { key[KIMPLIED], DNULL },
+ { key[KREQUIRED], DREQ },
+ { key[KCURRENT], DCURR },
+ { key[KCONREF], DCONR },
+ { key[KFIXED], DFIXED},
+ { NULL, 0}
+};
+struct map dvtab[] = { /* Declared value: keywords and type codes.*/
+/* TYPE NUMBER */
+/* grp ANMTGRP Case 1 0 Grp size */
+/* grp member ANMTGRP Case 0 Position */
+/* grp ANOTEGRP Case 1 1 Grp size */
+ { key[KNOTATION], ANOTEGRP}, /* Case 1 Position */
+ { key[KCDATA], ACHARS }, /* Case 2 Always 0 */
+ { key[KENTITY], AENTITY }, /* Case 3 Normal 1 */
+ { key[KID], AID }, /* Case 4 Normal 1 */
+ { key[KIDREF], AIDREF }, /* Case 5 Normal 1 */
+ { key[KNAME], ANAME }, /* Case 6 Normal 1 */
+ { key[KNMTOKEN], ANMTOKE }, /* Case 7 Normal 1 */
+ { key[KNUMBER], ANUMBER }, /* Case 8 Normal 1 */
+ { key[KNUTOKEN], ANUTOKE }, /* Case 9 Normal 1 */
+ { key[KENTITIES], AENTITYS}, /* Case A Normal 1 */
+ { key[KIDREFS], AIDREFS }, /* Case B # tokens */
+ { key[KNAMES], ANAMES }, /* Case C # tokens */
+ { key[KNMTOKENS], ANMTOKES}, /* Case D # tokens */
+ { key[KNUMBERS], ANUMBERS}, /* Case E # tokens */
+ { key[KNUTOKENS], ANUTOKES}, /* Case F # tokens */
+ { NULL, 0 } /* Case 0 ERROR */
+};
+struct map enttab[] = { /* Entity declaration second parameter. */
+ { key[KCDATA], ESC },
+ { key[KSDATA], ESX },
+ { key[KMS], ESMS},
+ { key[KPI], ESI },
+ { key[KSTARTTAG], ESS },
+ { key[KENDTAG], ESE },
+ { key[KMD], ESMD},
+ { NULL, 0 }
+};
+struct map exttab[] = { /* Keywords for external identifier. */
+ { key[KSYSTEM], EDSYSTEM },
+ { key[KPUBLIC], EDPUBLIC },
+ { NULL, 0 }
+};
+struct map extettab[] = { /* Keywords for external entity type. */
+ { key[KCDATA], ESNCDATA },
+ { key[KNDATA], ESNNDATA },
+ { key[KSDATA], ESNSDATA },
+ { key[KSUBDOC], ESNSUB },
+ { NULL, 0 }
+};
+struct map funtab[] = { /* Function character reference names. */
+ { key[KRE], RECHAR },
+ { key[KRS], RSCHAR },
+ { key[KSPACE], SPCCHAR },
+ /* We should use an extra table for added functions. */
+ { (UNCH *)"TAB", TABCHAR },
+ { NULL, 0 }
+};
+struct map mstab[] = { /* Marked section keywords. */
+ { key[KTEMP], MSTEMP },
+ { key[KINCLUDE], MSTEMP }, /* Treat INCLUDE like TEMP; both are NOPs.*/
+ { key[KRCDATA], MSRCDATA},
+ { key[KCDATA], MSCDATA },
+ { key[KIGNORE], MSIGNORE},
+ { NULL, 0 }
+};
+struct map pubcltab[] = { /* Names for public text class. */
+ { (UNCH *)"CAPACITY", FPICAP },
+ { (UNCH *)"CHARSET", FPICHARS},
+ { (UNCH *)"DOCUMENT", FPIDOC },
+ { (UNCH *)"DTD", FPIDTD },
+ { (UNCH *)"ELEMENTS", FPIELEM },
+ { (UNCH *)"ENTITIES", FPIENT },
+ { (UNCH *)"LPD", FPILPD },
+ { (UNCH *)"NONSGML", FPINON },
+ { (UNCH *)"NOTATION", FPINOT },
+ { (UNCH *)"SHORTREF", FPISHORT},
+ { (UNCH *)"SUBDOC", FPISUB },
+ { (UNCH *)"SYNTAX", FPISYN },
+ { (UNCH *)"TEXT", FPITEXT },
+ { NULL, 0 }
+};
+UNCH indefent[] = "\12#DEFAULT"; /* Internal name: default entity name. */
+UNCH indefetd[] = "\12*DOCTYPE"; /* Internal name: default document type. */
+UNCH indocent[] = "\12*SGMLDOC"; /* Internal name: SGML document entity. */
+UNCH indocetd[] = "\6*DOC"; /* Internal name: document level etd. */
+UNCH indtdent[] = "\11*DTDENT"; /* Internal name: external DTD entity. */
+
+struct etd dumetd[3];
+struct entity *dumpecb;
+UNCH sgmlkey[] = "SGML";
diff --git a/usr.bin/sgmls/sgmls/sgmlxtrn.h b/usr.bin/sgmls/sgmls/sgmlxtrn.h
new file mode 100644
index 0000000..e551200
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/sgmlxtrn.h
@@ -0,0 +1,123 @@
+/* SGMLXTRN.H: External declarations for SGML public variables.
+ Exceptions: Constants lex????? and del????? are defined in
+ LEX?????.C modules; constants pcb????? are defined in PCB?????.c.
+*/
+#ifndef SGMLXTRN /* Don't include this file more than once. */
+#define SGMLXTRN
+extern int badresw; /* 1=REF_ out of context; 0=valid. */
+extern int charmode; /* >0=in #CHARS; 0=not. */
+extern int conactsw; /* 1=return saved content action 0=get new one.*/
+extern int conrefsw; /* 1=content reference att specified; 0=no. */
+extern int contersv; /* Save contersw while processing pending REF. */
+extern int contersw; /* 1=element or #CHARS out of context; 0=valid. */
+extern int datarc; /* Return code for data: DAF_ or REF_. */
+extern int delmscsw; /* 1=DELMSC must be read on return to es==0. */
+extern int didreq; /* 1=required implied tag processed; 0=no. */
+extern int docelsw; /* 1=had document element; 0=no */
+extern int dostag; /* 1=retry newetd instead of parsing; 0=parse. */
+extern int dtdsw; /* DOCTYPE declaration found: 1=yes; 0=no. */
+extern int entdatsw; /* 2=CDATA entity; 4=SDATA; 8=NDATA; 0=none. */
+extern int entpisw; /* 4=PI entity occurred; 0=not. */
+extern int eodsw; /* 1=eod found in error; 0=not yet. */
+extern int eofsw; /* 1=eof found in body of document; 0=not yet. */
+extern int etagimct; /* Implicitly ended elements left on stack. */
+extern int etagimsw; /* 1=end-tag implied by other end-tag; 0=not. */
+extern int etagmin; /* Minim: NONE NULL NET DATA; implied by S/ETAG*/
+extern int etictr; /* Number of "NET enabled" tags on stack. */
+extern int etisw; /* 1=tag ended with eti; 0=did not. */
+extern int indtdsw; /* Are we in the DTD? 1=yes; 0=no. */
+extern int mslevel; /* Nesting level of marked sections. */
+extern int msplevel; /* Nested MS levels subject to special parse. */
+extern int prologsw; /* 1=in prolog; 0=not. */
+extern int pss; /* SGMLACT: scbsgml stack level. */
+extern int sgmlsw; /* SGML declaration found: 1=yes; 0=no. */
+extern int stagmin; /* Minimization: NONE, NULL tag, implied by STAG*/
+extern int tagctr; /* Tag source chars read. */
+extern int tages; /* ES level at start of tag. */
+extern int ts; /* Index of current tag in stack. */
+extern struct parse *propcb; /* Current PCB for prolog parse. */
+extern int aentctr; /* Number of ENTITY tokens in this att list. */
+extern int conact; /* Return code from content parse. */
+extern int conrefsv; /* Save conrefsw when doing implied start-tag.*/
+extern int dtdrefsw; /* External DTD? 1=yes; 0=no. */
+extern int etiswsv; /* Save etisw when processing implied start-tag.*/
+extern int grplvl; /* Current level of nested grps in model. */
+extern int idrctr; /* Number of IDREF tokens in this att list. */
+extern int mdessv; /* ES level at start of markup declaration. */
+extern int notadn; /* Position of NOTATION attribute in list. */
+extern int parmno; /* Current markup declaration parameter number. */
+extern int pexsw; /* 1=tag valid solely because of plus exception.*/
+extern int rcessv; /* ES level at start of RCDATA content. */
+extern int tagdelsw; /* 1=tag ended with delimiter; 0=no delimiter. */
+extern int tokencnt; /* Number of tokens found in attribute value. */
+extern struct entity *ecbdeflt; /* #DEFAULT ecb (NULL if no default entity). */
+extern struct etd *docetd; /* The etd for the document as a whole. */
+extern struct etd *etagreal; /* Actual or dummy etd that implied this tag. */
+extern struct etd *newetd; /* The etd for a start- or end-tag recognized. */
+extern struct etd *nextetd; /* ETD that must come next (only one choice). */
+extern struct etd *lastetd; /* Most recently ended ETD. */
+extern struct etd *stagreal; /* Actual or dummy etd that implied this tag. */
+extern struct parse *conpcb; /* Current PCB for content parse. */
+extern UNCH *data; /* Pointer to returned data in buffer. */
+extern UNCH *mdname; /* Name of current markup declaration. */
+extern UNCH *ptcon; /* Current pointer into tbuf. */
+extern UNCH *ptpro; /* Current pointer into tbuf. */
+extern UNCH *rbufs; /* DOS file read area: start position for read. */
+extern UNCH *subdcl; /* Subject of markup declaration (e.g., GI). */
+extern UNS conradn; /* 1=CONREF attribute in list (0=no). */
+extern UNS datalen; /* Length of returned data in buffer. */
+extern UNS entlen; /* Length of TAG or EXTERNAL entity text. */
+extern UNS idadn; /* Number of ID attribute (0 if none). */
+extern UNS noteadn; /* Number of NOTATION attribute (0 if none). */
+extern UNS reqadn; /* Num of atts with REQUIRED default (0=none). */
+extern int grplongs; /* Number of longs for GRPCNT bitvector. */
+/* Variable arrays and structures.
+*/
+extern struct ad *al; /* Current attribute list work area. */
+extern struct dcncb *dcntab[];/* List of data content notation names. */
+extern struct entity *etab[]; /* Entity hash table. */
+extern struct etd *etdtab[]; /* Element type definition hash table. */
+extern struct fpi fpidf; /* Fpi for #DEFAULT entity. */
+extern struct id *itab[]; /* Unique identifier hash table. */
+extern struct etd **nmgrp; /* Element name group */
+extern PDCB *nnmgrp; /* Notation name group */
+extern struct restate *scbsgml; /* SGMLACT: return action state stack. */
+extern struct srh *srhtab[]; /* List of SHORTREF table headers. */
+extern struct sgmlstat ds; /* Document statistics. */
+extern struct switches sw; /* Parser control switches set by text proc. */
+extern struct tag *tags; /* Stack of open elements ("tag stack"). */
+extern struct thdr *gbuf; /* Buffer for creating group. */
+extern struct thdr prcon[]; /* 0-2: Model for *DOC content. */
+extern struct thdr undechdr; /* 0: Default model hdr for undeclared content. */
+extern UNCH *dtype; /* Document type name. */
+extern UNCH *entbuf; /* Buffer for entity reference name. */
+extern UNCH fce[]; /* String form of FCE char (fce[1] must be EOS).*/
+extern UNCH nonchbuf[]; /* Buffer for valid nonchar character reference.*/
+extern UNCH *tbuf; /* Work area for tokenization. */
+extern UNCH *lbuf; /* In tbuf: Literal parse area; TAGLEN limit.*/
+extern struct entity *dumpecb; /* SRMNULL points to this. */
+extern UNCH *sysibuf;
+extern UNCH *pubibuf;
+extern UNCH *nmbuf; /* Name buffer used by mdentity. */
+extern struct mpos *savedpos;
+
+/* Constants.
+*/
+extern int scbsgmnr; /* SCBSGML: new record; do not ignore RE. */
+extern int scbsgmst; /* SCBSGML: trailing stag or markup; ignore RE. */
+extern struct map dctab[]; /* Keywords for declared content parameter. */
+extern struct map deftab[]; /* Default value keywords. */
+extern struct map dvtab[]; /* Declared value: keywords and type codes.*/
+extern struct map enttab[]; /* Entity declaration second parameter. */
+extern struct map exttab[]; /* Keywords for external identifier. */
+extern struct map extettab[]; /* Keywords for external entity type. */
+extern struct map funtab[]; /* Function character reference names. */
+extern struct map mstab[]; /* Marked section keywords. */
+extern struct map pubcltab[]; /* Keywords for public text class. */
+extern UNCH indefent[]; /* Internal name: default entity name. */
+extern UNCH indefetd[]; /* Internal name: default document type. */
+extern UNCH indocent[]; /* Internal name: SGML document entity. */
+extern UNCH indocetd[]; /* Internal name: etd for document as a whole. */
+extern UNCH indtdent[]; /* Internal name: external DTD entity. */
+extern char license[]; /* SGML Users' Group free license. */
+#endif /* ndef SGMLXTRN */
diff --git a/usr.bin/sgmls/sgmls/source.h b/usr.bin/sgmls/sgmls/source.h
new file mode 100644
index 0000000..32cc85a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/source.h
@@ -0,0 +1,114 @@
+/* SOURCE.H: Entity and source control block structures and definitions.
+*/
+#define ENTHASH 503 /* Size of entity hash table. Must be prime. */
+/* Entity storage class values for estore member of entity structure. */
+#define EST 1 /* String: Tag (usually a fixed STARTGI). */
+ /* <MDENTITY sets these:> */
+#define ESMD 2 /* String: Markup declaration. */
+#define ESMS 3 /* String: Marked section. */
+#define ESM 4 /* String: ordinary text. */
+ /* <ENTOPEN treats these specially:> */
+#define ESS 5 /* ETD: Start-tag. */
+#define ESE 6 /* ETD: End-tag. */
+#define ESI 7 /* String: PI. */
+#define ESX 8 /* String: SDATA general entity. */
+#define ESC 9 /* String: CDATA general entity. */
+ /* </MDENTITY> <MDEXTID sets these:> */
+#define ESFM 10 /* LPU: minimum external (file) storage class. */
+#define ESN 10 /* XCB: N/C/SDATA or SUBDOC control block. */
+ /* </ENTOPEN> */
+#define ESF 11 /* LPU: General entity. */
+#define ESP 12 /* LPU: Parameter entity. */
+#define ESD 13 /* LPU: Document type definition. */
+#define ESL 14 /* LPU: Link process definition. */
+#define ESK 15 /* LPU: Data content notation. */
+ /* </MDEXTID> */
+
+union etext { /* Entity text. */
+ UNIV x; /* External ID generated by system. */
+ UNCH *c; /* Character string. */
+ struct ne *n; /* N/C/SDATA or SUBDOC entity control block. */
+};
+#define ETEXTSZ sizeof(union etext)
+struct entity { /* Entity control block. */
+ struct entity *enext; /* Next entity in chain. */
+ UNCH *ename; /* Entity name with length and EOS. */
+ UNCH estore; /* Storage class (see values above). */
+ UNCH dflt; /* Declared as default entity. */
+ UNCH mark; /* For use by for sgmlment. */
+ union etext etx; /* Entity text. */
+};
+#define ENTSZ sizeof(struct entity)
+typedef struct entity *PECB; /* Ptr to entity control block. */
+typedef struct entity **TECB; /* Table of entity control blocks. */
+
+struct source { /* Source control block. */
+ struct entity ecb; /* Entity control block. */
+ unsigned long rcnt; /* Source record number. */
+ int ccnt; /* Source record chars since last RS. */
+ int curoff; /* Offset of curchar (chars read in this block).*/
+ UNCH curchar; /* Current character. */
+ UNCH nextchar; /* If curchar was DELNONCH, next character. */
+ UNIV fcb; /* SGMLIO fcb ptr returned by OPEN. */
+ UNCH *fbuf; /* 1st char in buffer (0=PEND) or entity text. */
+ UNCH *fpos; /* Current char in buffer or entity text. */
+ UNCH pushback; /* Character before pend position */
+ char copied; /* Is this a copy of the internal entity? */
+};
+#define SCBSZ sizeof(struct source)
+typedef struct source *PSCB; /* Ptr to source control block. */
+
+extern int es; /* Index of current source in stack. */
+extern struct source *scbs; /* Stack of open sources ("SCB stack"). */
+
+/* Member definitions for source and entity control blocks.
+*/
+#define SCB (scbs[es]) /* Ptr to current source control block. */
+
+#define ECB SCB.ecb /* Pointer to current entity control block. */
+#define FBUF SCB.fbuf /* Pointer to start of entity buffer. */
+#define FPOS SCB.fpos /* Pointer to current char of current source. */
+#define RSCC SCB.ccnt /* CCNT at start of block (across EOB/EOS/EOF). */
+#define CCO SCB.curoff /* Offset in read buffer of current char. */
+#define CC SCB.curchar /* Current character of current source entity. */
+#define NEXTC SCB.nextchar /* Next character in current source entity. */
+#define CCNT (SCB.ccnt+CCO) /* Position of CC in current record (RS=0). */
+#define RCNT SCB.rcnt /* Position of record in entity (origin=1). */
+#define SCBFCB SCB.fcb /* Current file control block (if FILESW). */
+#define ECBPTR ((ECB.enext)) /* Pointer to this entity's ECB. */
+#define ENTITY ((ECB.ename)) /* Current entity name. */
+#define FILESW (ECB.estore>=ESFM) /* 1=Entity is external file; 0=internal. */
+#define NEWCC (++FPOS) /* Get next current character. */
+#define REPEATCC (--FPOS) /* Repeat previous current character. */
+#define COPIEDSW SCB.copied /* Non-zero means entity was copied. */
+
+struct srh { /* Short reference map header. */
+ struct srh *enext; /* Next short reference map in chain. */
+ UNCH *ename; /* Short reference map name. */
+ TECB srhsrm; /* Ptr to short reference map. */
+};
+#define SRHSZ (sizeof(struct srh))
+typedef struct srh *PSRH; /* Ptr to short reference map header. */
+#define SRMNULL (&dumpecb) /* Dummy ptr to empty short reference map. */
+
+/* Definitions for ENTOPEN/ENTREF return codes.
+*/
+#define ENTUNDEF -1 /* Callers of ENTOPEN: entity undefined. */
+#define ENTLOOP -2 /* ENTOPEN: endless loop entity. */
+#define ENTMAX -3 /* ENTOPEN: too many open entities. */
+#define ENTFILE -4 /* ENTOPEN: file I/O error. */
+#define ENTDATA -5 /* ENTOPEN: CDATA or SDATA entity. */
+#define ENTPI -6 /* ENTOPEN: PI entity. */
+
+/* Definitions for ENTDATA switches set in contersw.
+*/
+#define CDECONT 2 /* 0010 CDATA entity referenced. */
+#define SDECONT 4 /* 0100 SDATA entity referenced. */
+#define NDECONT 8 /* 1000 NDATA entity referenced. */
+
+/* Definitions for manipulating signed source character counters.
+*/
+#define CTRSET(CTR) (CTR = (int) -(FPOS+1-FBUF)) /* Init source char ctr. */
+#define CTRGET(CTR) (CTR + (int) (FPOS+1-FBUF)) /* Read source char ctr. */
+
+
diff --git a/usr.bin/sgmls/sgmls/std.h b/usr.bin/sgmls/sgmls/std.h
new file mode 100644
index 0000000..4e6e856
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/std.h
@@ -0,0 +1,110 @@
+/* std.h -
+ Include standard header files.
+*/
+
+#ifndef STD_H
+#define STD_H 1
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef SUPPORT_SUBDOC
+#include <signal.h>
+#endif /* SUPPORT_SUBDOC */
+
+#ifndef STDDEF_H_MISSING
+#include <stddef.h>
+#endif /* not STDDEF_H_MISSING */
+
+#ifndef LIMITS_H_MISSING
+#include <limits.h>
+#endif /* not LIMITS_H_MISSING */
+
+#ifndef UINT_MAX
+#define UINT_MAX (sizeof(unsigned int) == 2 ? 0x7fff : \
+ (sizeof(unsigned int) == 4 ? 0x7fffffff : cant_guess_UINT_MAX))
+#endif
+
+#ifdef VARARGS
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+
+#ifdef BSD_STRINGS
+#include <strings.h>
+#define memcpy(to, from, n) bcopy(from, to, n)
+#define memcmp(p, q, n) bcmp(p, q, n)
+#define strchr(s, c) index(s, c)
+#define strrchr(s, c) rindex(s, c)
+#else /* not BSD_STRINGS */
+#include <string.h>
+#endif /* not BSD_STRINGS */
+
+extern char *strerror();
+
+#ifdef STDLIB_H_MISSING
+UNIV malloc();
+UNIV calloc();
+UNIV realloc();
+char *getenv();
+long atol();
+#else /* not STDLIB_H_MISSING */
+#include <stdlib.h>
+#endif /* not STDLIB_H_MISSING */
+
+#ifdef REMOVE_MISSING
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#define remove unlink
+#endif /* REMOVE_MISSING */
+
+#ifdef RAISE_MISSING
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#define raise(sig) kill(getpid(), sig)
+#endif /* RAISE_MISSING */
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifdef FPOS_MISSING
+typedef long fpos_t;
+#define fsetpos(stream, pos) fseek(stream, *(pos), SEEK_SET)
+#define fgetpos(stream, pos) ((*(pos) = ftell(stream)) == -1L)
+#endif /* FPOS_MISSING */
+
+/* Old BSD systems lack L_tmpnam and tmpnam(). This is a partial
+emulation using mktemp(). It requires that the argument to tmpnam()
+be non-NULL. */
+
+#ifndef L_tmpnam
+#define tmpnam_template "/tmp/sgmlsXXXXXX"
+#define L_tmpnam (sizeof(tmpnam_template))
+#undef tmpnam
+#define tmpnam(buf) \
+ (mktemp(strcpy(buf, tmpnam_template)) == 0 || (buf)[0] == '\0' ? 0 : (buf))
+#endif /* not L_tmpnam */
+
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* not STD_H */
diff --git a/usr.bin/sgmls/sgmls/stklen.c b/usr.bin/sgmls/sgmls/stklen.c
new file mode 100644
index 0000000..43af5dd
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/stklen.c
@@ -0,0 +1,2 @@
+/* This tells Borland C++ to allocate a 14k stack. */
+unsigned _stklen = 14*1024;
diff --git a/usr.bin/sgmls/sgmls/strerror.c b/usr.bin/sgmls/sgmls/strerror.c
new file mode 100644
index 0000000..f5679c0
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/strerror.c
@@ -0,0 +1,36 @@
+/* strerror.c -
+ ANSI C strerror() function.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifdef STRERROR_MISSING
+#include <stdio.h>
+
+char *strerror(n)
+int n;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ static char buf[sizeof("Error ") + 1 + 3*sizeof(int)];
+
+ if (n >= 0 && n < sys_nerr && sys_errlist[n] != 0)
+ return sys_errlist[n];
+ else {
+ sprintf(buf, "Error %d", n);
+ return buf;
+ }
+}
+
+#endif /* STRERROR_MISSING */
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/synrf.c b/usr.bin/sgmls/sgmls/synrf.c
new file mode 100644
index 0000000..2076107
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/synrf.c
@@ -0,0 +1,72 @@
+/* SYNRF: Reserved names and other constants for reference concrete syntax.
+*/
+#include "config.h"
+#include "entity.h" /* Templates for entity control blocks. */
+#include "synxtrn.h" /* Declarations for concrete syntax constants. */
+#include "adl.h" /* Definitions for attribute list processing. */
+UNCH key[NKEYS][REFNAMELEN+1] = {
+ "ANY",
+ "ATTLIST",
+ "CDATA",
+ "CONREF",
+ "CURRENT",
+ "DEFAULT",
+ "DOCTYPE",
+ "ELEMENT",
+ "EMPTY",
+ "ENDTAG",
+ "ENTITIES",
+ "ENTITY",
+ "FIXED",
+ "ID",
+ "IDLINK",
+ "IDREF",
+ "IDREFS",
+ "IGNORE",
+ "IMPLIED",
+ "INCLUDE",
+ "INITIAL",
+ "LINK",
+ "LINKTYPE",
+ "MD",
+ "MS",
+ "NAME",
+ "NAMES",
+ "NDATA",
+ "NMTOKEN",
+ "NMTOKENS",
+ "NOTATION",
+ "NUMBER",
+ "NUMBERS",
+ "NUTOKEN",
+ "NUTOKENS",
+ "O",
+ "PCDATA",
+ "PI",
+ "POSTLINK",
+ "PUBLIC",
+ "RCDATA",
+ "RE",
+ "REQUIRED",
+ "RESTORE",
+ "RS",
+ "SDATA",
+ "SHORTREF",
+ "SIMPLE",
+ "SPACE",
+ "STARTTAG",
+ "SUBDOC",
+ "SYSTEM",
+ "TEMP",
+ "USELINK",
+ "USEMAP"
+};
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/synxtrn.h b/usr.bin/sgmls/sgmls/synxtrn.h
new file mode 100644
index 0000000..1cdf9a0
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/synxtrn.h
@@ -0,0 +1,154 @@
+/* SYNXTRN.H: External declarations for concrete syntax constants.
+*/
+/* Short References
+*/
+#define SRCT 32 /* Number of short reference delimiters. */
+#define SRMAXLEN 3 /* Maximum length of a SHORTREF delimiter. */
+#define SRNPRT 8 /* Number of non-printable SHORTREF delimiters. */
+struct srdel {
+ struct map dtb[SRCT+2]; /* LEXCNM: Short reference delimiters. */
+ char *pdtb[SRNPRT+1]; /* LEXCNM: Printable form of unprintable SRs. */
+ int fce; /* LEXCNM: Index of first FCE in srdeltab. */
+ int hyp2; /* LEXCNM: Index of "two hyphens" in srdeltab. */
+ int data; /* LEXCNM: Index of first SR with data char. */
+ int hyp; /* LEXCNM: Index of hyphen in srdeltab. */
+ int prtmin; /* LEXCNM: Index of 1st printable SR. */
+ int spc; /* LEXCNM: Index of space in srdeltab. */
+ int lbr; /* LEXCNM: Index of left bracket in srdeltab. */
+ int rbr; /* LEXCNM: Index of right bracket in srdeltab. */
+};
+struct delim {
+ UNCH genre; /* LEXCON: Generated RE; cannot be markup. */
+ UNCH lit; /* LEXMARK: Char used as LIT delimiter.*/
+ UNCH lita; /* LEXMARK: Char used as LITA delimiter.*/
+ UNCH mdc; /* LEXLMS: Char used as MDC delimiter.*/
+ UNCH msc; /* LEXCON: Char used as MSC delimiter. */
+ UNCH net; /* LEXCON: Char used as NET when enabled.*/
+ UNCH pero; /* LEXMARK: Char used as PERO delimiter. */
+ UNCH pic; /* LEXCON: Char used as PIC delimiter.*/
+ UNCH tago; /* LEXCON: Char used as TAGO when enabled.*/
+};
+struct lexcode {
+ UNCH fce; /* LEXCNM: FRE character as entity reference. */
+ UNCH fre; /* LEXCON: Free character not an entity ref. */
+ UNCH litc; /* LEXLMS: Literal close delimiter enabled. */
+ UNCH minlitc; /* LEXMIN: Literal close delimiter enabled. */
+ UNCH msc; /* LEXLMS: Marked section close delim enabled. */
+ UNCH net; /* LEXCON: Null end-tag delimiter enabled. */
+ UNCH nonet; /* LEXCON: NET disabled; still used as ETI. */
+ UNCH spcr; /* LEXCNM: Space in use as SHORTREF delimiter. */
+ UNCH tago; /* LEXCON: Tag open delimiter enabled. */
+ UNCH cde; /* LEXLMS: CDATA/SDATA delimiters. */
+};
+struct lexical {
+ struct markup m; /* Markup strings for text processor. */
+ struct srdel s; /* Short reference delimiters. */
+ struct delim d; /* General delimiter characters. */
+ struct lexcode l; /* Lexical table code assignments. */
+};
+extern struct lexical lex; /* Delimiter set constants. */
+extern UNCH lexcnm[]; /* Lexical table: mixed content. */
+extern UNCH lexcon[]; /* Lexical table for content (except mixed). */
+extern UNCH lexgrp[]; /* Lexical table for groups. */
+extern UNCH lexlms[]; /* Lexical table: literals and marked sections. */
+extern UNCH lexmin[]; /* Lexical table: minimum data literal. */
+extern UNCH lexmark[]; /* Lexical table for markup. */
+extern UNCH lexsd[]; /* Lexical table for SGML declaration. */
+extern UNCH lextran[]; /* Case translation table for SGML names. */
+extern UNCH lextoke[]; /* Lexical table for tokenization. */
+extern UNCH *lextabs[]; /* List of all lexical tables. */
+extern struct parse pcbconc; /* PCB: character data. */
+extern struct parse pcbcone; /* PCB: element content (no data allowed). */
+extern struct parse pcbconm; /* PCB: mixed content (data allowed). */
+extern struct parse pcbconr; /* PCB: replaceable character data. */
+extern struct parse pcbetag; /* PCB: end-tags. */
+extern struct parse pcbgrcm; /* PCB: content model group. */
+extern struct parse pcbgrcs; /* PCB: content model suffix. */
+extern struct parse pcbgrnm; /* PCB: name group. */
+extern struct parse pcbgrnt; /* PCB: name token group. */
+extern struct parse pcblitc; /* PCB: literal with CDATA. */
+extern struct parse pcblitp; /* PCB: literal with CDATA, parm & char refs. */
+extern struct parse pcblitr; /* PCB: attribute value with general refs. */
+extern struct parse pcblitt; /* PCB: tokenized attribute value. */
+extern struct parse pcblitv; /* PCB: literal with CDATA, function char trans.*/
+extern struct parse pcbmd; /* PCB: markup declaration. */
+extern struct parse pcbmdc; /* PCB: comment declaration. */
+extern struct parse pcbmdi; /* PCB: markup declaration (ignored). */
+extern struct parse pcbmds; /* PCB: markup declaration subset. */
+extern struct parse pcbmsc; /* PCB: marked section in CDATA mode. */
+extern struct parse pcbmsi; /* PCB: marked section in IGNORE mode. */
+extern struct parse pcbmsrc; /* PCB: marked section in RCDATA mode. */
+extern struct parse pcbpro; /* PCB: prolog. */
+extern struct parse pcbref; /* PCB: reference. */
+extern struct parse pcbstag; /* PCB: start-tag. */
+extern struct parse pcbval; /* PCB: attribute value. */
+extern struct parse pcbeal; /* PCB: end of attribute list. */
+extern struct parse pcbsd; /* PCB: SGML declaration. */
+extern int pcbcnda; /* PCBCONM: data in buffer. */
+extern int pcbcnet; /* PCBCONM: markup found or data buffer flushed.*/
+extern int pcbmdtk; /* PCBMD: token expected. */
+extern int pcbstan; /* PCBSTAG: attribute name expected. */
+extern int pcblittda; /* PCBLITT: data character found */
+
+#define KANY 0
+#define KATTLIST 1
+#define KCDATA 2
+#define KCONREF 3
+#define KCURRENT 4
+#define KDEFAULT 5
+#define KDOCTYPE 6
+#define KELEMENT 7
+#define KEMPTY 8
+#define KENDTAG 9
+#define KENTITIES 10
+#define KENTITY 11
+#define KFIXED 12
+#define KID 13
+#define KIDLINK 14
+#define KIDREF 15
+#define KIDREFS 16
+#define KIGNORE 17
+#define KIMPLIED 18
+#define KINCLUDE 19
+#define KINITIAL 20
+#define KLINK 21
+#define KLINKTYPE 22
+#define KMD 23
+#define KMS 24
+#define KNAME 25
+#define KNAMES 26
+#define KNDATA 27
+#define KNMTOKEN 28
+#define KNMTOKENS 29
+#define KNOTATION 30
+#define KNUMBER 31
+#define KNUMBERS 32
+#define KNUTOKEN 33
+#define KNUTOKENS 34
+#define KO 35
+#define KPCDATA 36
+#define KPI 37
+#define KPOSTLINK 38
+#define KPUBLIC 39
+#define KRCDATA 40
+#define KRE 41
+#define KREQUIRED 42
+#define KRESTORE 43
+#define KRS 44
+#define KSDATA 45
+#define KSHORTREF 46
+#define KSIMPLE 47
+#define KSPACE 48
+#define KSTARTTAG 49
+#define KSUBDOC 50
+#define KSYSTEM 51
+#define KTEMP 52
+#define KUSELINK 53
+#define KUSEMAP 54
+
+#define NKEYS (KUSEMAP+1)
+
+extern UNCH key[NKEYS][REFNAMELEN+1];
+
+/* Holds the SGML keyword (not alterable by concrete syntax). */
+extern UNCH sgmlkey[];
diff --git a/usr.bin/sgmls/sgmls/tools.h b/usr.bin/sgmls/sgmls/tools.h
new file mode 100644
index 0000000..57ce45a
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/tools.h
@@ -0,0 +1,76 @@
+/* TOOLS.H: Definitions for type declarations, printing, bit handling, etc.
+*/
+
+#if CHAR_SIGNED
+typedef unsigned char UNCH;
+#else
+typedef char UNCH;
+#endif
+
+#if CHAR_SIGNED
+#define ustrcmp(s1, s2) strcmp((char *)(s1), (char *)(s2))
+#define ustrcpy(s1, s2) strcpy((char *)(s1), (char *)(s2))
+#define ustrchr(s, c) (UNCH *)strchr((char *)(s), c)
+#define ustrncmp(s1, s2, n) strncmp((char *)(s1), (char *)(s2), n)
+#define ustrncpy(s1, s2, n) strncpy((char *)(s1), (char *)(s2), n)
+#define ustrlen(s1) strlen((char *)(s1))
+#else
+#define ustrcmp strcmp
+#define ustrcpy strcpy
+#define ustrchr strchr
+#define ustrncmp strncmp
+#define ustrncpy strncpy
+#define ustrlen strlen
+#endif
+
+#if 0
+int ustrcmp(UNCH *, UNCH *);
+UNCH *ustrchr(UNCH *, int);
+int ustrncmp(UNCH *, UNCH *, UNS);
+int ustrncpy(UNCH *, UNCH *, UNS);
+int ustrlen(UNCH *);
+#endif
+
+typedef unsigned UNS;
+
+#ifdef USE_ISASCII
+#define ISASCII(c) isascii(c)
+#else
+#define ISASCII(c) (1)
+#endif
+
+#ifdef BSD_STRINGS
+#define MEMZERO(s, n) bzero(s, n)
+#else /* not BSD_STRINGS */
+#define MEMZERO(s, n) memset(s, '\0', n)
+#endif /* not BSD_STRINGS */
+
+/* Macros for bit manipulation.
+*/
+#define SET(word, bits) ((word) |= (bits)) /* Turn bits on */
+#define RESET(word, bits) ((word) &= ~(bits)) /* Turn bits off */
+#define GET(word, bits) ((word) & (bits)) /* 1=any bit on */
+#define BITOFF(word, bits) (GET(word, bits)==0) /* 1=no bits on */
+#define BITON(word, bits) ((word) & (bits)) /* 1=any bit on */
+
+#define ETDCDATA (dumetd) /* Dummy etd pointer for #PCDATA. */
+#define ETDNULL (dumetd + 1) /* Dummy etd pointer for null tag. */
+#define ETDNET (dumetd + 2) /* Dummy etd pointer for NET delimiter. */
+#define BADPTR(p) \
+ ((p) == NULL || (p) == ETDCDATA || (p) == ETDNULL || (p) == ETDNET)
+#define PTRNUM(p) ((p) == NULL ? 0 : ((p) - dumetd) + 1)
+
+#ifdef USE_PROTOTYPES
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+/* VP is used for prototypes of varargs functions. You can't have a
+prototype if the function is defined using varargs.h rather than
+stdarg.h. */
+#ifdef VARARGS
+#define VP(parms) ()
+#else
+#define VP(parms) P(parms)
+#endif
diff --git a/usr.bin/sgmls/sgmls/trace.h b/usr.bin/sgmls/sgmls/trace.h
new file mode 100644
index 0000000..f917a26
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/trace.h
@@ -0,0 +1,113 @@
+/* TRACE.H: Declarations for internal trace functions. */
+
+#ifdef TRACE
+
+/* Trace variables.
+*/
+extern int trace; /* Switch: 1=trace state transitions; 0=don't. */
+extern int atrace; /* Switch: 1=trace attribute activity; 0=don't. */
+extern int ctrace; /* Switch: 1=trace context checking; 0=don't. */
+extern int dtrace; /* Switch: 1=trace declaration parsing; 0=don't.*/
+extern int etrace; /* Switch: 1=trace entity activity; 0=don't.*/
+extern int gtrace; /* Switch: 1=trace group creations; 0=don't. */
+extern int itrace; /* Switch: 1=trace ID activity; 0=don't. */
+extern int mtrace; /* Switch: 1=trace MS activity; 0=don't. */
+extern int ntrace; /* Switch: 1=trace data notation activity. */
+extern char emd[]; /* For "EMD" parameter type in dtrace calls. */
+
+VOID traceadl P((struct ad *));
+VOID tracecon P((int,int,int,struct parse *,int,int));
+VOID tracedcn P((struct dcncb *));
+VOID tracedsk P((struct tag *,struct tag *,int,int));
+VOID traceecb P((char *,struct entity *));
+VOID traceend P((char *,struct thdr *,struct mpos *,int,int));
+VOID traceesn P((struct ne *));
+VOID traceetd P((struct etd *));
+VOID traceetg P((struct tag *,struct etd *,int,int));
+VOID tracegi P((char *,struct etd *,struct thdr *,struct mpos *));
+VOID tracegml P((struct restate *,int,int,int));
+VOID tracegrp P((struct etd **));
+VOID traceid P((char *,struct id *));
+VOID tracemd P((char *));
+VOID tracemod P((struct thdr *));
+VOID tracems P((int,int,int,int));
+VOID tracengr P((struct dcncb **));
+VOID tracepcb P((struct parse *));
+VOID tracepro P((void));
+VOID traceset P((void));
+VOID tracesrm P((char *,struct entity **,UNCH *));
+VOID tracestg P((struct etd *,int,int,struct etd *,int));
+VOID tracestk P((struct tag *,int,int));
+VOID tracetkn P((int,UNCH *));
+VOID traceval P((struct parse *,unsigned int,UNCH *,int));
+
+#define TRACEADL(al) ((void)(atrace && (traceadl(al), 1)))
+#define TRACECON(etagimct, dostag, datarc, pcb, conrefsw, didreq) \
+ ((void)(gtrace \
+ && (tracecon(etagimct, dostag, datarc, pcb, conrefsw, didreq), 1)))
+#define TRACEDCN(dcn) ((void)(ntrace && (tracedcn(dcn), 1)))
+#define TRACEDSK(pts, ptso, ts3, etictr) \
+ ((void)(gtrace && (tracedsk(pts, ptso, ts3, etictr), 1)))
+#define TRACEECB(action, p) \
+ ((void)(etrace && (traceecb(action, p), 1)))
+#define TRACEEND(stagenm, mod, pos, rc, opt) \
+ ((void)(ctrace && (traceend(stagenm, mod, pos, rc, opt), 1)))
+#define TRACEESN(p) \
+ ((void)((etrace || atrace || ntrace) && (traceesn(p), 1)))
+#define TRACEETD(p) ((void)(gtrace && (traceetd(p), 1)))
+#define TRACEETG(pts, curetd, tsl, etagimct) \
+ ((void)(gtrace && (traceetg(pts, curetd, tsl, etagimct), 1)))
+#define TRACEGI(stagenm, gi, mod, pos) \
+ ((void)(ctrace && (tracegi(stagenm, gi, mod, pos), 1)))
+#define TRACEGML(scb, pss, conactsw, conact) \
+ ((void)(trace && (tracegml(scb, pss, conactsw, conact), 1)))
+#define TRACEGRP(p) ((void)(gtrace && (tracegrp(p), 1)))
+#define TRACEID(action, p) ((void)(itrace && (traceid(action, p), 1)))
+#define TRACEMD(p) ((void)(dtrace && (tracemd(p), 1)))
+#define TRACEMOD(p) ((void)(gtrace && (tracemod(p), 1)))
+#define TRACEMS(action, code, mslevel, msplevel) \
+ ((void)(mtrace && (tracems(action, code, mslevel, msplevel), 1)))
+#define TRACENGR(p) ((void)(gtrace && (tracengr(p), 1)))
+#define TRACEPCB(p) ((void)(trace && (tracepcb(p), 1)))
+#define TRACEPRO() (tracepro())
+#define TRACESET() (traceset())
+#define TRACESRM(action, pg, gi) \
+ ((void)(etrace && (tracesrm(action, pg, gi), 1)))
+#define TRACESTG(curetd, dataret, rc, nextetd, mexts) \
+ ((void)(gtrace && (tracestg(curetd, dataret, rc, nextetd, mexts), 1)))
+#define TRACESTK(pts, ts2, etictr) \
+ ((void)(gtrace && (tracestk(pts, ts2, etictr), 1)))
+#define TRACETKN(scope, lextoke) \
+ ((void)(trace && (tracetkn(scope, lextoke), 1)))
+#define TRACEVAL(pcb, atype, aval, tokencnt) \
+ ((void)(atrace && (traceval(pcb, atype, aval, tokencnt), 1)))
+
+#else /* not TRACE */
+
+#define TRACEADL(al) /* empty */
+#define TRACECON(etagimct, dostag, datarc, pcb, conrefsw, didreq) /* empty */
+#define TRACEDCN(dcn) /* empty */
+#define TRACEDSK(pts, ptso, ts3, etictr) /* empty */
+#define TRACEECB(action, p) /* empty */
+#define TRACEEND(stagenm, mod, pos, rc, opt) /* empty */
+#define TRACEESN(p) /* empty */
+#define TRACEETG(pts, curetd, tsl, etagimct) /* empty */
+#define TRACEETD(p) /* empty */
+#define TRACEGI(stagenm, gi, mod, pos) /* empty */
+#define TRACEGML(scb, pss, conactsw, conact) /* empty */
+#define TRACEGRP(p) /* empty */
+#define TRACEID(action, p) /* empty */
+#define TRACEMD(p) /* empty */
+#define TRACEMOD(p) /* empty */
+#define TRACEMS(action, code, mslevel, msplevel) /* empty */
+#define TRACENGR(p) /* empty */
+#define TRACEPCB(p) /* empty */
+#define TRACEPRO() /* empty */
+#define TRACESET() /* empty */
+#define TRACESRM(action, pg, gi) /* empty */
+#define TRACESTG(curetd, dataret, rc, nextetd, mexts) /* empty */
+#define TRACESTK(pts, ts2, etictr) /* empty */
+#define TRACETKN(scope, lextoke) /* empty */
+#define TRACEVAL(pcb, atype, aval, tokencnt) /* empty */
+
+#endif /* not TRACE */
diff --git a/usr.bin/sgmls/sgmls/traceset.c b/usr.bin/sgmls/sgmls/traceset.c
new file mode 100644
index 0000000..e57003f
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/traceset.c
@@ -0,0 +1,462 @@
+#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
+
+#ifdef TRACE
+
+#include "context.h"
+
+/* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ */
+#define STATUX tags[ts].status
+
+/* Trace variables.
+*/
+int trace = 0; /* Switch: 1=trace state transitions; 0=don't. */
+int atrace = 0; /* Switch: 1=trace attribute activity; 0=don't. */
+int ctrace = 0; /* Switch: 1=trace context checking; 0=don't. */
+int dtrace = 0; /* Switch: 1=trace declaration parsing; 0=don't.*/
+int etrace = 0; /* Switch: 1=trace entity activity; 0=don't.*/
+int gtrace = 0; /* Switch: 1=trace group creations; 0=don't. */
+int itrace = 0; /* Switch: 1=trace ID activity; 0=don't. */
+int mtrace = 0; /* Switch: 1=trace MS activity; 0=don't. */
+int ntrace = 0; /* Switch: 1=trace notation activity; 0=don't. */
+char emd[] = "EMD"; /* For "EMD" parameter type in dtrace calls. */
+
+/* Return a printable representation of c.
+*/
+static
+char *printable(c)
+int c;
+{
+ static char buf[5];
+ if (c >= 040 && c < 0177) {
+ buf[0] = c;
+ buf[1] = '\0';
+ }
+ else
+ sprintf(buf, "\\%03o", (UNCH)c);
+ return buf;
+}
+
+static
+VOID dotrace(s)
+char *s;
+{
+ trace = (s && strchr(s, 't') != 0);
+ atrace = (s && strchr(s, 'a') != 0);
+ ctrace = (s && strchr(s, 'c') != 0);
+ dtrace = (s && strchr(s, 'd') != 0);
+ etrace = (s && strchr(s, 'e') != 0);
+ gtrace = (s && strchr(s, 'g') != 0);
+ itrace = (s && strchr(s, 'i') != 0);
+ mtrace = (s && strchr(s, 'm') != 0);
+ ntrace = (s && strchr(s, 'n') != 0);
+}
+/* TRACESET: Set switches for tracing body of document.
+*/
+VOID traceset()
+{
+ dotrace(sw.trace);
+
+ if (trace||atrace||ctrace||dtrace||etrace||gtrace||itrace||mtrace||ntrace)
+ fprintf(stderr,
+"TRACESET: state=%d;att=%d;con=%d;dcl=%d;ent=%d;grp=%d;id=%d;ms=%d;dcn=%d.\n",
+ trace, atrace, ctrace, dtrace, etrace, gtrace, itrace,
+ mtrace, ntrace);
+}
+/* TRACEPRO: Set switches for tracing prolog.
+ */
+VOID tracepro()
+{
+ dotrace(sw.ptrace);
+
+ if (trace||atrace||dtrace||etrace||gtrace||mtrace||ntrace)
+ fprintf(stderr,
+ "TRACEPRO: state=%d; att=%d; dcl=%d; ent=%d; grp=%d; ms=%d; dcn=%d.\n",
+ trace, atrace, dtrace, etrace, gtrace, mtrace, ntrace);
+}
+/* TRACEPCB: Trace character just parsed and other pcb data.
+ */
+VOID tracepcb(pcb)
+struct parse *pcb;
+{
+ fprintf(stderr, "%-8s %2u-%2u-%2u-%2u from %s [%3d] in %s, %lu:%d.\n",
+ pcb->pname, pcb->state, pcb->input, pcb->action,
+ pcb->newstate, printable(*FPOS), *FPOS, ENTITY+1, RCNT,
+ RSCC+FPOS+1-FBUF);
+}
+/* TRACETKN: Trace character just read during token parse.
+ */
+VOID tracetkn(scope, lextoke)
+int scope;
+UNCH lextoke[]; /* Lexical table for token and name parses. */
+{
+ fprintf(stderr, "TOKEN %2d-%2d from %s [%3d] in %s, %lu:%d.\n",
+ scope, lextoke[*FPOS],
+ printable(*FPOS), *FPOS, ENTITY+1, RCNT,
+ RSCC+FPOS+1-FBUF);
+}
+/* TRACEGML: Trace state of main SGML driver routine.
+ */
+VOID tracegml(scb, pss, conactsw, conact)
+struct restate *scb;
+int pss, conactsw, conact;
+{
+ fprintf(stderr,
+ "SGML%02d %2d-%2d-%2d-%2d in main driver; conactsw=%d; conact=%d.\n",
+ pss, scb[pss].sstate, scb[pss].sinput, scb[pss].saction,
+ scb[pss].snext, conactsw, conact);
+}
+/* TRACEVAL: Trace parse of an attribute value that is a token list.
+ */
+VOID traceval(pcb, atype, aval, tokencnt)
+struct parse *pcb;
+UNS atype; /* Type of token list expected. */
+UNCH *aval; /* Value string to be parsed as token list. */
+int tokencnt; /* Number of tokens found in attribute value. */
+{
+ fprintf(stderr,
+ "%-8s %2d-%2d-%2d-%2d at %p, atype=%02x, tokencnt=%d: ",
+ pcb->pname, pcb->state, pcb->input, pcb->action,
+ pcb->newstate, (UNIV)aval, atype, tokencnt);
+ fprintf(stderr, "%s\n", aval);
+}
+/* TRACESTK: Trace entry just placed on tag stack.
+ */
+VOID tracestk(pts, ts2, etictr)
+struct tag *pts; /* Stack entry for this tag. */
+int ts2; /* Stack depth. */
+int etictr; /* Number of "netok" tags on stack. */
+{
+ fprintf(stderr,
+ "STACK %s begun; stack depth %d; tflag=%02x; etictr=%d",
+ pts->tetd->etdgi+1, ts2, pts->tflags, etictr);
+ fprintf(stderr, " srm=%s.\n",
+ pts->tsrm!=SRMNULL ? (char *)(pts->tsrm[0]->ename+1) : "#EMPTY");
+}
+/* TRACEDSK: Trace entry just removed from tag stack.
+ */
+VOID tracedsk(pts, ptso, ts3, etictr)
+struct tag *pts; /* Stack entry for new open tag. */
+struct tag *ptso; /* Stack entry for tag just ended. */
+int ts3; /* Stack depth. */
+int etictr; /* Number of "netok" tags on stack. */
+{
+ fprintf(stderr,
+ "DESTACK %s ended; otflag=%02x; %s resumed; depth=%d; tflag=%02x; etictr=%d",
+ ptso->tetd->etdgi+1, ptso->tflags,
+ pts->tetd->etdgi+1, ts3, pts->tflags, etictr);
+ fprintf(stderr, " srm=%s.\n",
+ pts->tsrm!=SRMNULL ? (char *)(pts->tsrm[0]->ename+1) : "#EMPTY");
+}
+/* TRACECON: Trace interactions between content parse and stag/context
+ processing.
+ */
+VOID tracecon(etagimct, dostag, datarc, pcb, conrefsw, didreq)
+int etagimct; /* Implicitly ended elements left on stack. */
+int dostag; /* 1=retry newetd instead of parsing; 0=parse. */
+int datarc; /* Return code for data: DAF_ or REF_ or zero. */
+struct parse *pcb; /* Parse control block for this parse. */
+int conrefsw; /* 1=content reference att specified; 0=no. */
+int didreq; /* 1=required implied empty tag processed; 0=no.*/
+{
+ fprintf(stderr,
+ "CONTENT etagimct=%d dostag=%d datarc=%d pname=%s action=%d \
+conrefsw=%d didreq=%d\n",
+ etagimct, dostag, datarc, pcb->pname, pcb->action,
+ conrefsw, didreq);
+}
+/* TRACESTG: Trace start-tag context validation input and results.
+ */
+VOID tracestg(curetd, dataret, rc, nextetd, mexts)
+struct etd *curetd; /* The etd for this tag. */
+int dataret; /* Data pending: DAF_ REF_ 0=not #PCDATA. */
+int rc; /* Return code from context or other test. */
+struct etd *nextetd; /* The etd for a forced start-tag (if rc==2). */
+int mexts; /* >0=stack level of minus grp; -1=plus; 0=none.*/
+{
+ fprintf(stderr,
+ "STARTTAG newetd=%p; dataret=%d; rc=%d; nextetd=%p; mexts=%d.\n",
+ (UNIV)curetd, dataret, rc, (UNIV)nextetd, mexts);
+}
+/* TRACEETG: Trace end-tag matching test on stack.
+ */
+VOID traceetg(pts, curetd, tsl, etagimct)
+struct tag *pts; /* Stack entry for this tag. */
+struct etd *curetd; /* The etd for this tag. */
+int tsl; /* Temporary stack level for looping. */
+int etagimct; /* Num of implicitly ended tags left on stack. */
+{
+ fprintf(stderr,
+ "ENDTAG tsl=%d; newetd=%p; stacketd=%p; tflags=%02x; etagimct=%d.\n",
+ tsl, (UNIV)curetd, (UNIV)pts->tetd, pts->tflags, etagimct);
+}
+/* TRACEECB: Trace entity control block activity.
+ */
+VOID traceecb(action, p)
+char *action;
+struct entity *p;
+{
+ static char estype1[] = " TMMMSEIXCNFPDLK";
+ static char estype2[] = " DS ";
+ if (!p)
+ return;
+ fprintf(stderr,
+ "%-8s (es=%d) type %c%c entity %s at %p containing ",
+ action, es, estype1[p->estore], estype2[p->estore], p->ename+1,
+ (UNIV)p);
+ if (p->estore==ESN && strcmp(action, "ENTDEF"))
+ traceesn(p->etx.n);
+ else if (p->etx.x==0)
+ fprintf(stderr, "[NOTHING]");
+ else
+ fprintf(stderr, "%s",
+ p->etx.c[0] ? (char *)p->etx.c : "[EMPTY]");
+ putc('\n', stderr);
+}
+/* TRACEDCN: Trace data content notation activity.
+ */
+VOID tracedcn(p)
+struct dcncb *p;
+{
+ fprintf(stderr,
+ "DCN dcn=%p; adl=%p; notation is %s\n",
+ (UNIV)p, (UNIV)p->adl, p->ename+1);
+ if (p->adl)
+ traceadl(p->adl);
+}
+/* TRACEESN: Print a data entity control block.
+ */
+VOID traceesn(p)
+PNE p;
+{
+ fprintf(stderr, "ESN Entity name is %s; entity type is %s.\n",
+ (NEENAME(p)!=0) ? ((char *)NEENAME(p))+1 : "[UNDEFINED]",
+ /* NEXTYPE(p)); */
+ (NEXTYPE(p)==1 ? "CDATA" : (NEXTYPE(p)==2 ? "NDATA" : "SDATA")));
+ fprintf(stderr, " System ID is %s\n",
+ (NEID(p)!=0) ? (char *)NEID(p) : "[UNDEFINED]");
+ if (p->nedcn!=0)
+ tracedcn(p->nedcn);
+}
+/* TRACESRM: Print the members of a short reference map.
+ */
+VOID tracesrm(action, pg, gi)
+char *action;
+TECB pg;
+UNCH *gi;
+{
+ int i = 0; /* Loop counter. */
+
+ if (pg==SRMNULL)
+ fprintf(stderr, "%-8s SHORTREF table empty for %s.\n", action, gi);
+ else {
+ fprintf(stderr, "%-8s %s at %p mapped for %s.\n",
+ action, pg[0]->ename+1, (UNIV)pg,
+ gi ? (char *)gi : "definition");
+ while (++i<=lex.s.dtb[0].mapdata)
+ if (pg[i])
+ fprintf(stderr, "%14s%02u %p %s\n",
+ "SR", i, (UNIV)pg[i], pg[i]->ename+1);
+ }
+}
+/* TRACEADL: Print an attribute definition list.
+ */
+VOID traceadl(al)
+struct ad al[];
+{
+ int i=0;
+
+ fprintf(stderr, "ADLIST %p %d membe%s; %d attribut%s\n",
+ (UNIV)al, ADN(al), ADN(al)==1 ? "r" : "rs", AN(al),
+ AN(al)==1 ? "e" : "es");
+ while (++i<=ADN(al)) {
+ fprintf(stderr,
+ (BITOFF(ADFLAGS(al,i), AGROUP) && ADTYPE(al,i)<=ANOTEGRP)
+ ? " %p %-8s %02x %02x %2d %2d %p %p\n"
+ : " %p %-8s %02x %02x %2d %2d %p %p\n",
+ &al[i], ADNAME(al,i), ADFLAGS(al,i), ADTYPE(al,i), ADNUM(al,i),
+ ADLEN(al,i), ADVAL(al,i), ADDATA(al,i).x);
+ if (ADVAL(al,i)) {
+ fprintf(stderr, "%s", ADVAL(al,i));
+ if (ADTYPE(al,i)==AENTITY && ADDATA(al,i).n!=0) {
+ fprintf(stderr, "=>");
+ traceesn(ADDATA(al,i).n);
+ }
+ else if (ADTYPE(al,i)==ANOTEGRP) {
+ fprintf(stderr, "=>");
+ tracedcn(ADDATA(al,i).x);
+ }
+ }
+ else
+ fprintf(stderr, "[%s]",
+ GET(ADFLAGS(al,i), AREQ)
+ ? "REQUIRED"
+ : (GET(ADFLAGS(al,i), ACURRENT) ? "CURRENT" : "NULL"));
+ }
+ fprintf(stderr, "\n");
+}
+/* TRACEMOD: Print the members of a model.
+ */
+VOID tracemod(pg)
+struct thdr pg[];
+{
+ fprintf(stderr, "MODEL %p %02x %d\n",
+ (UNIV)&pg[0], pg[0].ttype, pg[0].tu.tnum);
+ if ((pg[0].ttype & MKEYWORD) == 0) {
+ int i;
+
+ for (i = 1; i < pg[0].tu.tnum + 2; i++) {
+ if (GET(pg[i].ttype, TTMASK) == TTETD)
+ fprintf(stderr, " %p %02x %s\n",
+ (UNIV)&pg[i], pg[i].ttype, pg[i].tu.thetd->etdgi+1);
+ else if (GET(pg[i].ttype, TTMASK) == TTCHARS)
+ fprintf(stderr, " %p %02x %s\n",
+ (UNIV)&pg[i], pg[i].ttype, "#PCDATA");
+ else
+ fprintf(stderr, " %p %02x %d\n",
+ (UNIV)&pg[i], pg[i].ttype, pg[i].tu.tnum);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+/* TRACEGRP: Print the members of a name (i.e., etd) group.
+ */
+VOID tracegrp(pg)
+struct etd *pg[];
+{
+ int i = -1; /* Loop counter. */
+
+ fprintf(stderr, "ETDGRP %p\n", (UNIV)pg);
+ while (pg[++i]!=0)
+ fprintf(stderr, " %p %s\n", (UNIV)pg[i], pg[i]->etdgi+1);
+}
+/* TRACENGR: Print the members of a notation (i.e., dcncb) group.
+ */
+VOID tracengr(pg)
+struct dcncb *pg[];
+{
+ int i = -1; /* Loop counter. */
+
+ fprintf(stderr, "DCNGRP %p\n", (UNIV)pg);
+ while (pg[++i]!=0)
+ fprintf(stderr, " %p %s\n", (UNIV)pg[i], pg[i]->ename+1);
+}
+/* TRACEETD: Print an element type definition.
+ */
+VOID traceetd(p)
+struct etd *p; /* Pointer to an etd. */
+{
+ fprintf(stderr,
+"ETD etd=%p %s min=%02x cmod=%p ttype=%02x mex=%p, pex=%p, ",
+ (UNIV)p, p->etdgi+1, p->etdmin, (UNIV)p->etdmod,
+ p->etdmod->ttype, (UNIV)p->etdmex, (UNIV)p->etdpex);
+ fprintf(stderr, "adl=%p, srm=%s.\n",
+ (UNIV)p->adl,
+ (p->etdsrm==SRMNULL)
+ ? "#EMPTY"
+ : (p->etdsrm) ? (char *)(p->etdsrm[0]->ename+1) : "#CURRENT");
+}
+/* TRACEID: Print an ID control block.
+ */
+VOID traceid(action, p)
+char *action;
+struct id *p; /* Pointer to an ID. */
+{
+ fprintf(stderr, "%-8s %s at %p is %s; ", action, p->idname+1, (UNIV)p,
+ p->iddefed ? "defined" : "undefined");
+ fprintf(stderr, "last ref=%p\n", (UNIV)p->idrl);
+}
+/* TRACEMD: Trace a markup declaration parameter.
+ */
+VOID tracemd(parmid)
+char *parmid; /* Parameter identifier. */
+{
+ fprintf(stderr, "MDPARM %-8s for %-8s, token %02d, type %02u, %s.\n",
+ mdname, subdcl ? (char *)subdcl : "[NONE]", parmno, pcbmd.action, parmid);
+}
+/* TRACEMS: Trace marked section activity.
+ */
+VOID tracems(action, code, mslevel, msplevel)
+int action; /* 1=began new level; 0=resumed previous. */
+int code;
+int mslevel; /* Nesting level of marked sections. */
+int msplevel; /* Nested MS levels subject to special parse. */
+{
+ fprintf(stderr,
+ "MS%c %2d %s nesting level %d (msp %d).\n",
+ (action ? ' ' : 'E'), code, (action ? "began" : "resumed"),
+ mslevel, msplevel);
+}
+
+static
+VOID tracehits(h)
+unsigned long *h;
+{
+ int i;
+ fprintf(stderr, " H=");
+ for (i = grplongs - 1; i >= 0; --i)
+ fprintf(stderr, "%0*lx", LONGBITS/4, h[i]);
+}
+
+/* TRACEGI: Trace GI testing stages in CONTEXT.C processing.
+ */
+VOID tracegi(stagenm, gi, mod, pos)
+char *stagenm;
+struct etd *gi; /* ETD of new GI. */
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+{
+ int i = 0; /* Loop counter. */
+
+ fprintf(stderr, "%-10s %d:", stagenm, P);
+ while (++i<=P)
+ fprintf(stderr, " %d-%d", pos[i].g, pos[i].t);
+ fprintf(stderr, " (%u) gocc=%02x gtype=%02x gnum=%d",
+ M, GOCC, GTYPE, GNUM);
+ tracehits(H);
+ fprintf(stderr, " status=%d Tstart=%d\n", STATUX, Tstart);
+ fprintf(stderr,
+ "=>%-8s tocc=%02x ttype=%02x thetd=%p (%s) gietd=%p (%s)\n",
+ tags[ts].tetd->etdgi+1, TOCC, TTYPE, (UNIV)TOKEN.tu.thetd,
+ (TTYPE
+ ? (TTYPE==TTETD ? (char *)(TOKEN.tu.thetd->etdgi+1) : "#GROUP")
+ : "#PCDATA"),
+ (UNIV)gi,
+ (gi==ETDCDATA ? "#PCDATA" : (char *)(gi->etdgi+1)));
+}
+/* TRACEEND: Trace testing for end of group in CONTEXT.C processing.
+ */
+VOID traceend(stagenm, mod, pos, rc, opt)
+char *stagenm;
+struct thdr mod[]; /* Model of current open element. */
+struct mpos pos[]; /* Position in open element's model. */
+int rc; /* Return code: RCNREQ RCHIT RCMISS RCEND */
+int opt; /* ALLHIT parm: 1=test optionals; 0=ignore. */
+{
+ int i = 0; /* Loop counter. */
+
+ fprintf(stderr, "%-10s %d:", stagenm, P);
+ while (++i<=P)
+ fprintf(stderr, " %d-%d", pos[i].g, pos[i].t);
+ fprintf(stderr, " (%u) gocc=%02x gtype=%02x gnum=%d",
+ M, GOCC, GTYPE, GNUM);
+ tracehits(H);
+ fprintf(stderr, " status=%d Tstart=%d\n", STATUX, Tstart);
+ fprintf(stderr, "=>%-8s tocc=%02x ttype=%02x thetd=%p (%s)",
+ tags[ts].tetd->etdgi+1, TOCC, TTYPE, (UNIV)TOKEN.tu.thetd,
+ (TTYPE
+ ? (TTYPE==TTETD ? (char *)(TOKEN.tu.thetd->etdgi+1) : "#GROUP")
+ : "#PCDATA"));
+ fprintf(stderr, " rc=%d offbitT=%d allhit=%d\n",
+ rc, offbit(H, (int)T, GNUM), allhit(&GHDR, H, 0, opt));
+}
+
+#endif /* TRACE */
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/unix.cfg b/usr.bin/sgmls/sgmls/unix.cfg
new file mode 100644
index 0000000..0bc8410
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/unix.cfg
@@ -0,0 +1,147 @@
+/* unix.cfg: Configuration file for sgmls on Unix. */
+
+/* A list of filename templates to use for searching for external entities.
+The filenames are separated by the character specified in PATH_FILE_SEP.
+See sgmls.man for details. */
+#define DEFAULT_PATH "/usr/local/lib/sgml/%O/%C/%T:%N.%X:%N.%D"
+/* The character that separates the filenames templates. */
+#define PATH_FILE_SEP ':'
+/* The character that separates filenames in a system identifier.
+Usually the same as PATH_FILE_SEP. */
+#define SYSID_FILE_SEP ':'
+/* The environment variable that contains the list of filename templates. */
+#define PATH_ENV_VAR "SGML_PATH"
+
+/* MIN_DAT_SUBS_FROM and MIN_DATS_SUBS_TO tell sgmls how to transform a name
+or system identifier into a legal filename. A character in
+MIN_DAT_SUBS_FROM will be transformed into the character in the
+corresponding position in MIN_DAT_SUBS_TO. If there is no such
+position, then the character is removed. */
+/* This says that spaces should be transformed to underscores, and
+slashes to percents. */
+#define MIN_DAT_SUBS_FROM " /"
+#define MIN_DAT_SUBS_TO "_%"
+
+/* Define this to allow tracing. */
+/* #define TRACE 1 */
+
+/* Define this you want support for subdocuments. This is implemented
+using features that are not part of Standard C, so you might not want
+to define it if you are porting to a new system. Otherwise I suggest
+you leave it defined. */
+#define SUPPORT_SUBDOC 1
+
+/* Define HAVE_EXTENDED_PRINTF if your *printf functions supports
+X/Open extensions; if they do, then, for example,
+
+ printf("%2$s%1$s", "bar", "foo")
+
+should print `foobar'. */
+
+/* #define HAVE_EXTENDED_PRINTF 1 */
+
+/* Define HAVE_CAT if your system provides the X/Open message
+catalogue functions catopen() and catgets(), and you want to use them.
+An implementations of these functions is included and will be used if
+you don't define this. On SunOS 4.1.1, if you do define this you
+should set CC=/usr/xpg2bin/cc in the makefile. */
+
+/* #define HAVE_CAT 1 */
+
+#ifdef __STDC__
+/* Define this if your compiler supports prototypes. */
+#define USE_PROTOTYPES 1
+#endif
+
+/* Can't use <stdarg.h> without prototypes. */
+#ifndef USE_PROTOTYPES
+#define VARARGS 1
+#endif
+
+/* If your compiler defines __STDC__ but doesn't provide <stdarg.h>,
+you must define VARARGS yourself here. */
+/* #define VARARGS 1 */
+
+/* Define this if you do not have strerror(). */
+#define STRERROR_MISSING 1
+
+/* Define this unless the character testing functions in ctype.h
+are defined for all values representable as an unsigned char. You do
+not need to define this if your system is ANSI C conformant. You
+should define for old Unix systems. */
+/* #define USE_ISASCII 1 */
+
+/* Define this if your system provides the BSD style string operations
+rather than ANSI C ones (eg bcopy() rather than memcpy(), and index()
+rather than strchr()). */
+/* #define BSD_STRINGS 1 */
+
+/* Define this if you have getopt(). */
+#define HAVE_GETOPT 1
+
+/* Define this if you have access(). */
+#define HAVE_ACCESS 1
+
+/* Define this if you have <unistd.h>. */
+#define HAVE_UNISTD_H 1
+
+/* Define this if you have <sys/stat.h>. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define this if you have waitpid(). */
+#define HAVE_WAITPID 1
+
+/* Define this if your system is POSIX.1 (ISO 9945-1:1990) compliant. */
+#define POSIX 1
+
+/* Define this if you have the vfork() system call. */
+#define HAVE_VFORK 1
+
+/* Define this if you have <vfork.h>. */
+#define HAVE_VFORK_H 1
+
+/* Define this if you don't have <stdlib.h> */
+/* #define STDLIB_H_MISSING 1 */
+
+/* Define this if you don't have <stddef.h> */
+/* #define STDDEF_H_MISSING 1 */
+
+/* Define this if you don't have <limits.h> */
+/* #define LIMITS_H_MISSING 1 */
+
+/* Define this if you don't have remove(); unlink() will be used instead. */
+#define REMOVE_MISSING 1
+
+/* Define this if you don't have raise(); kill() will be used instead. */
+#define RAISE_MISSING 1
+
+/* Define this if you don't have fsetpos() and fgetpos(). */
+#define FPOS_MISSING 1
+
+/* Universal pointer type. */
+/* If your compiler doesn't fully support void *, change `void' to `char'. */
+typedef void *UNIV;
+
+/* If your compiler doesn't support void as a function return type,
+change `void' to `int'. */
+typedef void VOID;
+
+/* If you don't have an ANSI C conformant <limits.h>, define
+CHAR_SIGNED as 1 or 0 according to whether the `char' type is signed.
+The <limits.h> on some versions of System Release V 3.2 is not ANSI C
+conformant: the value of CHAR_MIN is 0 even though the `char' type is
+signed. */
+
+/* #define CHAR_SIGNED 1 */
+/* #define CHAR_SIGNED 0 */
+#ifndef CHAR_SIGNED
+#include <limits.h>
+#if CHAR_MIN < 0
+#define CHAR_SIGNED 1
+#else
+#define CHAR_SIGNED 0
+#endif
+#endif /* not CHAR_SIGNED */
+
+/* Assume the system character set is ISO Latin-1. */
+#include "latin1.h"
diff --git a/usr.bin/sgmls/sgmls/unixproc.c b/usr.bin/sgmls/sgmls/unixproc.c
new file mode 100644
index 0000000..9e79d62
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/unixproc.c
@@ -0,0 +1,98 @@
+/* unixproc.c -
+
+ Unix implementation of run_process().
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+#include "config.h"
+
+#ifdef SUPPORT_SUBDOC
+
+#ifdef POSIX
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#endif /* POSIX */
+
+#include "std.h"
+#include "entity.h"
+#include "appl.h"
+
+#ifndef POSIX
+
+#define WIFSTOPPED(s) (((s) & 0377) == 0177)
+#define WIFSIGNALED(s) (((s) & 0377) != 0 && ((s) & 0377 != 0177))
+#define WIFEXITED(s) (((s) & 0377) == 0)
+#define WEXITSTATUS(s) (((s) >> 8) & 0377)
+#define WTERMSIG(s) ((s) & 0177)
+#define WSTOPSIG(s) (((s) >> 8) & 0377)
+#define _SC_OPEN_MAX 0
+#define sysconf(name) (20)
+typedef int pid_t;
+
+#endif /* not POSIX */
+
+#ifndef HAVE_VFORK
+#define vfork() fork()
+#endif /* not HAVE_VFORK */
+
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif /* HAVE_VFORK_H */
+
+int run_process(argv)
+char **argv;
+{
+ pid_t pid;
+ int status;
+ int ret;
+
+ /* Can't trust Unix implementations to support fflush(NULL). */
+ fflush(stderr);
+ fflush(stdout);
+
+ pid = vfork();
+ if (pid == 0) {
+ /* child */
+ int i;
+ int open_max = (int)sysconf(_SC_OPEN_MAX);
+
+ for (i = 3; i < open_max; i++)
+ (void)close(i);
+ execvp(argv[0], argv);
+ appl_error(E_EXEC, argv[0], strerror(errno));
+ fflush(stderr);
+ _exit(127);
+ }
+ if (pid < 0) {
+ appl_error(E_FORK, strerror(errno));
+ return -1;
+ }
+ /* parent */
+ while ((ret = wait(&status)) != pid)
+ if (ret < 0) {
+ appl_error(E_WAIT, strerror(errno));
+ return -1;
+ }
+ if (WIFSIGNALED(status)) {
+ appl_error(E_SIGNAL, argv[0], WTERMSIG(status));
+ return -1;
+ }
+ /* Must have exited normally. */
+ return WEXITSTATUS(status);
+}
+
+#endif /* SUPPORT_SUBDOC */
+
+/*
+Local Variables:
+c-indent-level: 5
+c-continued-statement-offset: 5
+c-brace-offset: -5
+c-argdecl-indent: 0
+c-label-offset: -5
+End:
+*/
diff --git a/usr.bin/sgmls/sgmls/version.c b/usr.bin/sgmls/sgmls/version.c
new file mode 100644
index 0000000..f3b2d7c
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/version.c
@@ -0,0 +1 @@
+char *version_string = "1.1.91";
diff --git a/usr.bin/sgmls/sgmls/xfprintf.c b/usr.bin/sgmls/sgmls/xfprintf.c
new file mode 100644
index 0000000..1c50469
--- /dev/null
+++ b/usr.bin/sgmls/sgmls/xfprintf.c
@@ -0,0 +1,564 @@
+/* xfprintf.c -
+ X/Open extended v?fprintf implemented in terms of v?fprintf.
+
+ Written by James Clark (jjc@jclark.com).
+*/
+
+/* Compile with:
+
+ -DVARARGS to use varargs.h instead of stdarg.h
+ -DLONG_DOUBLE_MISSING if your compiler doesn't like `long double'
+ -DFP_SUPPORT to include floating point stuff
+*/
+
+#include "config.h"
+
+#ifndef HAVE_EXTENDED_PRINTF
+
+#include "std.h"
+
+#ifdef lint
+/* avoid stupid lint warnings */
+#undef va_arg
+#define va_arg(ap, type) (ap, (type)0)
+#endif
+
+#ifdef FP_SUPPORT
+#ifdef LONG_DOUBLE_MISSING
+typedef double long_double;
+#else
+typedef long double long_double;
+#endif
+#endif /* FP_SUPPORT */
+
+#ifdef USE_PROTOTYPES
+#define P(parms) parms
+#else
+#define P(parms) ()
+#endif
+
+#ifdef VARARGS
+typedef int (*printer)();
+#else
+typedef int (*printer)(UNIV, const char *, ...);
+#endif
+
+enum arg_type {
+ NONE,
+ INT,
+ UNSIGNED,
+ LONG,
+ UNSIGNED_LONG,
+#ifdef FP_SUPPORT
+ DOUBLE,
+ LONG_DOUBLE,
+#endif /* FP_SUPPORT */
+ PCHAR,
+ PINT,
+ PLONG,
+ PSHORT
+};
+
+union arg {
+ int i;
+ unsigned u;
+ long l;
+ unsigned long ul;
+#ifdef FP_SUPPORT
+ double d;
+ long_double ld;
+#endif /* FP_SUPPORT */
+ char *pc;
+ UNIV pv;
+ int *pi;
+ short *ps;
+ long *pl;
+};
+
+#define NEXT 0
+#define MISSING 10
+
+struct spec {
+ enum arg_type type;
+ char pos;
+ char field_width;
+ char precision;
+};
+
+#define FLAG_CHARS "-+ #0"
+
+static int parse_spec P((const char **, struct spec *));
+static int find_arg_types P((const char *, enum arg_type *));
+static void get_arg P((enum arg_type, va_list *, union arg *));
+static int do_arg P((UNIV, printer, const char *, enum arg_type, union arg *));
+static int xdoprt P((UNIV, printer, const char *, va_list));
+static int printit P((UNIV, printer, const char *, va_list, int, union arg *));
+static int maybe_positional P((const char *));
+
+/* Return 1 if sucessful, 0 otherwise. **pp points to character after % */
+
+static int parse_spec(pp, sp)
+const char **pp;
+struct spec *sp;
+{
+ char modifier = 0;
+ sp->pos = NEXT;
+ if (isdigit((unsigned char)(**pp)) && (*pp)[1] == '$') {
+ if (**pp == '0')
+ return 0;
+ sp->pos = **pp - '0';
+ *pp += 2;
+ }
+
+ while (**pp != '\0' && strchr(FLAG_CHARS, **pp))
+ *pp += 1;
+
+ /* handle the field width */
+
+ sp->field_width = MISSING;
+ if (**pp == '*') {
+ *pp += 1;
+ if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
+ if (**pp == '0')
+ return 0;
+ sp->field_width = **pp - '0';
+ *pp += 2;
+ }
+ else
+ sp->field_width = NEXT;
+ }
+ else {
+ while (isdigit((unsigned char)**pp))
+ *pp += 1;
+ }
+
+ /* handle the precision */
+ sp->precision = MISSING;
+ if (**pp == '.') {
+ *pp += 1;
+ if (**pp == '*') {
+ *pp += 1;
+ if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
+ if (**pp == '0')
+ return 0;
+ sp->precision = **pp - '0';
+ *pp += 2;
+ }
+ else
+ sp->precision = NEXT;
+ }
+ else {
+ while (isdigit((unsigned char)**pp))
+ *pp += 1;
+ }
+ }
+ /* handle h l or L */
+
+ if (**pp == 'h' || **pp == 'l' || **pp == 'L') {
+ modifier = **pp;
+ *pp += 1;
+ }
+
+ switch (**pp) {
+ case 'd':
+ case 'i':
+ sp->type = modifier == 'l' ? LONG : INT;
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ sp->type = modifier == 'l' ? UNSIGNED_LONG : UNSIGNED;
+ break;
+#ifdef FP_SUPPORT
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ sp->type = modifier == 'L' ? LONG_DOUBLE : DOUBLE;
+ break;
+#endif /* FP_SUPPORT */
+ case 'c':
+ sp->type = INT;
+ break;
+ case 's':
+ sp->type = PCHAR;
+ break;
+ case 'p':
+ /* a pointer to void has the same representation as a pointer to char */
+ sp->type = PCHAR;
+ break;
+ case 'n':
+ if (modifier == 'h')
+ sp->type = PSHORT;
+ else if (modifier == 'l')
+ sp->type = PLONG;
+ else
+ sp->type = PINT;
+ break;
+ case '%':
+ sp->type = NONE;
+ break;
+ default:
+ return 0;
+ }
+ *pp += 1;
+ return 1;
+}
+
+
+static int find_arg_types(format, arg_type)
+ const char *format;
+ enum arg_type *arg_type;
+{
+ int i, pos;
+ const char *p;
+ struct spec spec;
+
+ for (i = 0; i < 9; i++)
+ arg_type[i] = NONE;
+
+ pos = 0;
+
+ p = format;
+ while (*p)
+ if (*p == '%') {
+ p++;
+ if (!parse_spec(&p, &spec))
+ return 0;
+ if (spec.type != NONE) {
+ int n;
+ if (spec.pos == NEXT)
+ n = pos++;
+ else
+ n = spec.pos - 1;
+ if (n < 9) {
+ enum arg_type t = arg_type[n];
+ if (t != NONE && t != spec.type)
+ return 0;
+ arg_type[n] = spec.type;
+ }
+ }
+ if (spec.field_width != MISSING) {
+ int n;
+ if (spec.field_width == NEXT)
+ n = pos++;
+ else
+ n = spec.field_width - 1;
+ if (n < 9) {
+ enum arg_type t = arg_type[n];
+ if (t != NONE && t != INT)
+ return 0;
+ arg_type[n] = INT;
+ }
+ }
+ if (spec.precision != MISSING) {
+ int n;
+ if (spec.precision == NEXT)
+ n = pos++;
+ else
+ n = spec.precision - 1;
+ if (n < 9) {
+ enum arg_type t = arg_type[n];
+ if (t != NONE && t != INT)
+ return 0;
+ arg_type[n] = INT;
+ }
+ }
+ }
+ else
+ p++;
+ return 1;
+}
+
+static void get_arg(arg_type, app, argp)
+ enum arg_type arg_type;
+ va_list *app;
+ union arg *argp;
+{
+ switch (arg_type) {
+ case NONE:
+ break;
+ case INT:
+ argp->i = va_arg(*app, int);
+ break;
+ case UNSIGNED:
+ argp->u = va_arg(*app, unsigned);
+ break;
+ case LONG:
+ argp->l = va_arg(*app, long);
+ break;
+ case UNSIGNED_LONG:
+ argp->ul = va_arg(*app, unsigned long);
+ break;
+#ifdef FP_SUPPORT
+ case DOUBLE:
+ argp->d = va_arg(*app, double);
+ break;
+ case LONG_DOUBLE:
+ argp->ld = va_arg(*app, long_double);
+ break;
+#endif /* FP_SUPPORT */
+ case PCHAR:
+ argp->pc = va_arg(*app, char *);
+ break;
+ case PINT:
+ argp->pi = va_arg(*app, int *);
+ break;
+ case PSHORT:
+ argp->ps = va_arg(*app, short *);
+ break;
+ case PLONG:
+ argp->pl = va_arg(*app, long *);
+ break;
+ default:
+ abort();
+ }
+}
+
+static int do_arg(handle, func, buf, arg_type, argp)
+ UNIV handle;
+ printer func;
+ const char *buf;
+ enum arg_type arg_type;
+ union arg *argp;
+{
+ switch (arg_type) {
+ case NONE:
+ return (*func)(handle, buf);
+ case INT:
+ return (*func)(handle, buf, argp->i);
+ case UNSIGNED:
+ return (*func)(handle, buf, argp->u);
+ case LONG:
+ return (*func)(handle, buf, argp->l);
+ case UNSIGNED_LONG:
+ return (*func)(handle, buf, argp->ul);
+#ifdef FP_SUPPORT
+ case DOUBLE:
+ return (*func)(handle, buf, argp->d);
+ case LONG_DOUBLE:
+ return (*func)(handle, buf, argp->ld);
+#endif /* FP_SUPPORT */
+ case PCHAR:
+ return (*func)(handle, buf, argp->pc);
+ case PINT:
+ return (*func)(handle, buf, argp->pi);
+ case PSHORT:
+ return (*func)(handle, buf, argp->ps);
+ case PLONG:
+ return (*func)(handle, buf, argp->pl);
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
+
+static int printit(handle, func, p, ap, nargs, arg)
+ UNIV handle;
+ printer func;
+ const char *p;
+ va_list ap;
+ int nargs;
+ union arg *arg;
+{
+ char buf[512]; /* enough for a spec */
+ int count = 0;
+ int pos = 0;
+
+ while (*p)
+ if (*p == '%') {
+ char *q;
+ struct spec spec;
+ const char *start;
+ int had_field_width;
+ union arg *argp;
+ union arg a;
+ int res;
+
+ start = ++p;
+ if (!parse_spec(&p, &spec))
+ abort(); /* should have caught it in find_arg_types */
+
+ buf[0] = '%';
+ q = buf + 1;
+
+ if (spec.pos != NEXT)
+ start += 2;
+
+ /* substitute in precision and field width if necessary */
+ had_field_width = 0;
+ while (start < p) {
+ if (*start == '*') {
+ char c;
+ int n, val;
+
+ start++;
+ if (!had_field_width && spec.field_width != MISSING) {
+ c = spec.field_width;
+ had_field_width = 1;
+ }
+ else
+ c = spec.precision;
+ if (c == NEXT)
+ n = pos++;
+ else {
+ start += 2;
+ n = c - 1;
+ }
+ if (n >= nargs)
+ val = va_arg(ap, int);
+ else
+ val = arg[n].i;
+
+ /* ignore negative precision */
+ if (val >= 0 || q[-1] != '.') {
+ (void)sprintf(q, "%d", val);
+ q = strchr(q, '\0');
+ }
+ }
+ else
+ *q++ = *start++;
+ }
+ *q++ = '\0';
+
+ argp = 0;
+ if (spec.type != NONE) {
+ int n = spec.pos == NEXT ? pos++ : spec.pos - 1;
+ if (n >= nargs) {
+ get_arg(spec.type, &ap, &a);
+ argp = &a;
+ }
+ else
+ argp = arg + n;
+ }
+
+ res = do_arg(handle, func, buf, spec.type, argp);
+ if (res < 0)
+ return -1;
+ count += res;
+ }
+ else {
+ if ((*func)(handle, "%c", *p++) < 0)
+ return -1;
+ count++;
+ }
+ return count;
+}
+
+/* Do a quick check to see if it may contains any positional thingies. */
+
+static int maybe_positional(format)
+ const char *format;
+{
+ const char *p;
+
+ p = format;
+ for (;;) {
+ p = strchr(p, '$');
+ if (!p)
+ return 0;
+ if (p - format >= 2
+ && isdigit((unsigned char)p[-1])
+ && (p[-2] == '%' || p[-2] == '*'))
+ break; /* might be a positional thingy */
+ }
+ return 1;
+}
+
+static int xdoprt(handle, func, format, ap)
+ UNIV handle;
+ printer func;
+ const char *format;
+ va_list ap;
+{
+ enum arg_type arg_type[9];
+ union arg arg[9];
+ int nargs, i;
+
+ if (!find_arg_types(format, arg_type))
+ return -1;
+
+ for (nargs = 0; nargs < 9; nargs++)
+ if (arg_type[nargs] == NONE)
+ break;
+
+ for (i = nargs; i < 9; i++)
+ if (arg_type[i] != NONE)
+ return -1;
+
+ for (i = 0; i < nargs; i++)
+ get_arg(arg_type[i], &ap, arg + i);
+
+ return printit(handle, func, format, ap, nargs, arg);
+}
+
+#ifdef VARARGS
+static int do_fprintf(va_alist) va_dcl
+#else
+static int do_fprintf(UNIV p, const char *format,...)
+#endif
+{
+#ifdef VARARGS
+ UNIV p;
+ const char *format;
+#endif
+ va_list ap;
+ int res;
+
+#ifdef VARARGS
+ va_start(ap);
+ p = va_arg(ap, UNIV);
+ format = va_arg(ap, char *);
+#else
+ va_start(ap, format);
+#endif
+
+ res = vfprintf((FILE *)p, format, ap);
+ va_end(ap);
+ return res;
+}
+
+#ifdef VARARGS
+int xfprintf(va_alist) va_dcl
+#else
+int xfprintf(FILE *fp, const char *format, ...)
+#endif
+{
+#ifdef VARARGS
+ FILE *fp;
+ char *format;
+#endif
+ va_list ap;
+ int res;
+
+#ifdef VARARGS
+ va_start(ap);
+ fp = va_arg(ap, FILE *);
+ format = va_arg(ap, char *);
+#else
+ va_start(ap, format);
+#endif
+ if (maybe_positional(format))
+ res = xdoprt((UNIV)fp, do_fprintf, format, ap);
+ else
+ res = vfprintf(fp, format, ap);
+ va_end(ap);
+ return res;
+}
+
+int xvfprintf(fp, format, ap)
+ FILE *fp;
+ const char *format;
+ va_list ap;
+{
+ int res;
+ if (maybe_positional(format))
+ res = xdoprt((UNIV)fp, do_fprintf, format, ap);
+ else
+ res = vfprintf(fp, format, ap);
+ return res;
+}
+
+#endif /* not HAVE_EXTENDED_PRINTF */
diff --git a/usr.bin/sgmls/unix.cfg b/usr.bin/sgmls/unix.cfg
new file mode 100644
index 0000000..4245511
--- /dev/null
+++ b/usr.bin/sgmls/unix.cfg
@@ -0,0 +1,165 @@
+/* unix.cfg: Configuration file for sgmls on Unix. */
+
+/* A list of filename templates to use for searching for external entities.
+The filenames are separated by the character specified in PATH_FILE_SEP.
+See sgmls.man for details. */
+#define DEFAULT_PATH "/usr/local/lib/sgml/%O/%C/%T:%N.%X:%N.%D"
+/* The character that separates the filenames templates. */
+#define PATH_FILE_SEP ':'
+/* The character that separates filenames in a system identifier.
+Usually the same as PATH_FILE_SEP. */
+#define SYSID_FILE_SEP ':'
+/* The environment variable that contains the list of filename templates. */
+#define PATH_ENV_VAR "SGML_PATH"
+/* A macro that returns non-zero if the filename is relative to the
+ current directory. */
+#define FILE_IS_RELATIVE(p) ((p)[0] != '/')
+/* A string containing the characters that can separate the directory
+ part of a filename from the basename. */
+#define DIR_BASE_SEP "/"
+/* The environment variable that contains the list of catalog entry files.
+ Filenames are separated by PATH_FILE_SEP. */
+#define CATALOG_FILES_ENV_VAR "SGML_CATALOG_FILES"
+/* Default list of catalog entry files. */
+#define DEFAULT_CATALOG_FILES "CATALOG:/usr/local/lib/sgml/CATALOG"
+
+/* MIN_DAT_SUBS_FROM and MIN_DATS_SUBS_TO tell sgmls how to transform a name
+or system identifier into a legal filename. A character in
+MIN_DAT_SUBS_FROM will be transformed into the character in the
+corresponding position in MIN_DAT_SUBS_TO. If there is no such
+position, then the character is removed. */
+/* This says that spaces should be transformed to underscores, and
+slashes to percents. */
+#define MIN_DAT_SUBS_FROM " /"
+#define MIN_DAT_SUBS_TO "_%"
+
+/* Define this to allow tracing. */
+/* #define TRACE 1 */
+
+/* Define this you want support for subdocuments. This is implemented
+using features that are not part of Standard C, so you might not want
+to define it if you are porting to a new system. Otherwise I suggest
+you leave it defined. */
+#define SUPPORT_SUBDOC 1
+
+/* Define HAVE_EXTENDED_PRINTF if your *printf functions supports
+X/Open extensions; if they do, then, for example,
+
+ printf("%2$s%1$s", "bar", "foo")
+
+should print `foobar'. */
+
+/* #define HAVE_EXTENDED_PRINTF 1 */
+
+/* Define HAVE_CAT if your system provides the X/Open message
+catalogue functions catopen() and catgets(), and you want to use them.
+An implementations of these functions is included and will be used if
+you don't define this. On SunOS 4.1.1, if you do define this you
+should set CC=/usr/xpg2bin/cc in the makefile. */
+
+/* #define HAVE_CAT 1 */
+
+#ifdef __STDC__
+/* Define this if your compiler supports prototypes. */
+#define USE_PROTOTYPES 1
+#endif
+
+/* Can't use <stdarg.h> without prototypes. */
+#ifndef USE_PROTOTYPES
+#define VARARGS 1
+#endif
+
+/* If your compiler defines __STDC__ but doesn't provide <stdarg.h>,
+you must define VARARGS yourself here. */
+/* #define VARARGS 1 */
+
+/* Define this if you do not have strerror(). */
+#define STRERROR_MISSING 1
+
+/* Define this unless the character testing functions in ctype.h
+are defined for all values representable as an unsigned char. You do
+not need to define this if your system is ANSI C conformant. You
+should define for old Unix systems. */
+/* #define USE_ISASCII 1 */
+
+/* Define this if your system provides the BSD style string operations
+rather than ANSI C ones (eg bcopy() rather than memcpy(), and index()
+rather than strchr()). */
+/* #define BSD_STRINGS 1 */
+
+/* Define this if you have getopt(). */
+#define HAVE_GETOPT 1
+
+/* Define this if you have access(). */
+#define HAVE_ACCESS 1
+
+/* Define this if you have <unistd.h>. */
+#define HAVE_UNISTD_H 1
+
+/* Define this if you have <sys/stat.h>. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define this if you have waitpid(). */
+#define HAVE_WAITPID 1
+
+/* Define this if your system is POSIX.1 (ISO 9945-1:1990) compliant. */
+#define POSIX 1
+
+/* Define this if you have the vfork() system call. */
+#define HAVE_VFORK 1
+
+/* Define this if you have <vfork.h>. */
+#define HAVE_VFORK_H 1
+
+/* Define this if you don't have <stdlib.h> */
+/* #define STDLIB_H_MISSING 1 */
+
+/* Define this if you don't have <stddef.h> */
+/* #define STDDEF_H_MISSING 1 */
+
+/* Define this if you don't have <limits.h> */
+/* #define LIMITS_H_MISSING 1 */
+
+/* Define this if you don't have remove(); unlink() will be used instead. */
+#define REMOVE_MISSING 1
+
+/* Define this if you don't have raise(); kill() will be used instead. */
+#define RAISE_MISSING 1
+
+/* Define this if you don't have fsetpos() and fgetpos(). */
+#define FPOS_MISSING 1
+
+/* Universal pointer type. */
+/* If your compiler doesn't fully support void *, change `void' to `char'. */
+typedef void *UNIV;
+
+/* If your compiler doesn't support void as a function return type,
+change `void' to `int'. */
+typedef void VOID;
+
+/* If your compiler doesn't understand const, define it to be nothing. */
+#ifndef __STDC__
+#ifndef const
+#define const /* as nothing */
+#endif
+#endif
+
+/* If you don't have an ANSI C conformant <limits.h>, define
+CHAR_SIGNED as 1 or 0 according to whether the `char' type is signed.
+The <limits.h> on some versions of System Release V 3.2 is not ANSI C
+conformant: the value of CHAR_MIN is 0 even though the `char' type is
+signed. */
+
+/* #define CHAR_SIGNED 1 */
+/* #define CHAR_SIGNED 0 */
+#ifndef CHAR_SIGNED
+#include <limits.h>
+#if CHAR_MIN < 0
+#define CHAR_SIGNED 1
+#else
+#define CHAR_SIGNED 0
+#endif
+#endif /* not CHAR_SIGNED */
+
+/* Assume the system character set is ISO Latin-1. */
+#include "latin1.h"
diff --git a/usr.bin/shar/Makefile b/usr.bin/shar/Makefile
index 2d8a5de..6d06623 100644
--- a/usr.bin/shar/Makefile
+++ b/usr.bin/shar/Makefile
@@ -1,16 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
-MAN1= shar.0
-
-all shar: ${MAN1}
-
-clean depend lint tags:
-
-cleandir:
- rm -f ${MAN1}
+MAN1= shar.1
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/shar.sh ${DESTDIR}/usr/bin/shar
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/shar.sh ${DESTDIR}${BINDIR}/shar
.include <bsd.prog.mk>
diff --git a/usr.bin/shar/shar.1 b/usr.bin/shar/shar.1
index 71202ee..b85f7ce 100644
--- a/usr.bin/shar/shar.1
+++ b/usr.bin/shar/shar.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)shar.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt SHAR 1
@@ -40,8 +41,9 @@
.Sh SYNOPSIS
.Nm shar Ar
.Sh DESCRIPTION
-.Nm Shar
-writes an
+The
+.Nm
+command writes a
.Xr sh 1
shell script to the standard output which will recreate the file
hierarchy specified by the command line operands.
@@ -50,29 +52,35 @@ files they contain (the
.Xr find 1
utility does this correctly).
.Pp
-.Nm Shar
-is normally used for distributing files by
+The
+.Nm
+command is normally used for distributing files by
.Xr ftp 1
or
.Xr mail 1 .
.Sh SEE ALSO
.Xr compress 1 ,
.Xr mail 1 ,
-.Xr uuencode 1 ,
-.Xr tar 1
+.Xr tar 1 ,
+.Xr uuencode 1
.Sh BUGS
-.Nm Shar
-makes no provisions for special types of files or files containing
+The
+.Nm
+command makes no provisions for special types of files or files containing
magic characters.
+The
+.Nm
+command cannot handle files without a newline ('\\n')
+as the last character.
.Pp
It is easy to insert trojan horses into
-.Nm shar
+.Nm
files.
It is strongly recommended that all shell archive files be examined
before running them through
.Xr sh 1 .
Archives produced using this implementation of
-.Nm shar
+.Nm
may be easily examined with the command:
.Bd -literal -offset indent
egrep -v '^[X#]' shar.file
@@ -98,5 +106,5 @@ sh archive
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/showmount/Makefile b/usr.bin/showmount/Makefile
index aa0074e..9bf4783 100644
--- a/usr.bin/showmount/Makefile
+++ b/usr.bin/showmount/Makefile
@@ -1,7 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= showmount
-DPADD= ${LIBRPC}
-LDADD= -lrpc
+MAN8= showmount.8
.include <bsd.prog.mk>
diff --git a/usr.bin/showmount/showmount.8 b/usr.bin/showmount/showmount.8
index b4d1be6..6c466da 100644
--- a/usr.bin/showmount/showmount.8
+++ b/usr.bin/showmount/showmount.8
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)showmount.8 8.3 (Berkeley) 3/29/95
+.\" @(#)showmount.8 8.2 (Berkeley) 12/11/93
.\"
-.Dd March 29, 1995
+.Dd December 11, 1993
.Dt SHOWMOUNT 8
.Os BSD 4
.Sh NAME
@@ -77,7 +77,7 @@ exports list
Use mount protocol Version 3, compatible with NFS Version 3.
.El
.Sh SEE ALSO
-.Xr mount 1 ,
+.Xr mount 8 ,
.Xr mountd 8
.Sh BUGS
The mount daemon running on the server only has an idea of the actual mounts,
@@ -90,4 +90,5 @@ as accurately as the mount daemon reports it.
.Sh HISTORY
The
.Nm showmount
-utility first appeared in 4.4BSD.
+utility first appeared in
+.Bx 4.4 .
diff --git a/usr.bin/showmount/showmount.c b/usr.bin/showmount/showmount.c
index 2eb07c2..b4896e2 100644
--- a/usr.bin/showmount/showmount.c
+++ b/usr.bin/showmount/showmount.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1989, 1993, 1995
+ * Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -36,29 +36,26 @@
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1989, 1993, 1995\n\
+"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif not lint
#ifndef lint
-static char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95";
+static char sccsid[] = "@(#)showmount.c 8.1 (Berkeley) 6/6/93";
#endif not lint
#include <sys/types.h>
+#include <sys/queue.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-
#include <netdb.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
#include <nfs/rpcv2.h>
-
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
/* Constant defs */
#define ALL 1
@@ -88,11 +85,7 @@ struct exportslist {
static struct mountlist *mntdump;
static struct exportslist *exports;
static int type = 0;
-
-void print_dump __P((struct mountlist *));
-void usage __P((void));
-int xdr_mntdump __P((XDR *, struct mountlist **));
-int xdr_exports __P((XDR *, struct exportslist **));
+int xdr_mntdump(), xdr_exports();
/*
* This command queries the NFS mount daemon for it's mount list and/or
@@ -101,17 +94,21 @@ int xdr_exports __P((XDR *, struct exportslist **));
* and the "Network File System Protocol XXX.."
* for detailed information on the protocol.
*/
-int
main(argc, argv)
int argc;
char **argv;
{
- struct exportslist *exp;
- struct grouplist *grp;
- int estat, rpcs = 0, mntvers = 1;
- char ch, *host;
+ register struct mountlist *mntp;
+ register struct exportslist *exp;
+ register struct grouplist *grp;
+ extern char *optarg;
+ extern int optind;
+ register int rpcs = 0, mntvers = 1;
+ char ch;
+ char *host;
+ int estat;
- while ((ch = getopt(argc, argv, "ade3")) != EOF)
+ while ((ch = getopt(argc, argv, "ade3")) != -1)
switch((char)ch) {
case 'a':
if (type == 0) {
@@ -153,7 +150,7 @@ main(argc, argv)
RPCMNT_DUMP, xdr_void, (char *)0,
xdr_mntdump, (char *)&mntdump)) != 0) {
clnt_perrno(estat);
- fprintf(stderr, ": Can't do Mountdump rpc\n");
+ fprintf(stderr, "Can't do Mountdump rpc\n");
exit(1);
}
if (rpcs & DOEXPORTS)
@@ -161,7 +158,7 @@ main(argc, argv)
RPCMNT_EXPORT, xdr_void, (char *)0,
xdr_exports, (char *)&exports)) != 0) {
clnt_perrno(estat);
- fprintf(stderr, ": Can't do Exports rpc\n");
+ fprintf(stderr, "Can't do Exports rpc\n");
exit(1);
}
@@ -198,20 +195,20 @@ main(argc, argv)
exp = exp->ex_next;
}
}
-
- exit(0);
}
/*
* Xdr routine for retrieving the mount dump list
*/
-int
xdr_mntdump(xdrsp, mlp)
XDR *xdrsp;
struct mountlist **mlp;
{
- struct mountlist *mp, **otp, *tp;
- int bool, val, val2;
+ register struct mountlist *mp;
+ register struct mountlist *tp;
+ register struct mountlist **otp;
+ int val, val2;
+ int bool;
char *strp;
*mlp = (struct mountlist *)0;
@@ -284,13 +281,12 @@ next:
/*
* Xdr routine to retrieve exports list
*/
-int
xdr_exports(xdrsp, exp)
XDR *xdrsp;
struct exportslist **exp;
{
- struct exportslist *ep;
- struct grouplist *gp;
+ register struct exportslist *ep;
+ register struct grouplist *gp;
int bool, grpbool;
char *strp;
@@ -327,18 +323,15 @@ xdr_exports(xdrsp, exp)
return (1);
}
-void
usage()
{
-
- fprintf(stderr, "usage: showmount [-ade] host\n");
+ fprintf(stderr, "usage: showmount [-ade3] host\n");
exit(1);
}
/*
* Print the binary tree in inorder so that output is sorted.
*/
-void
print_dump(mp)
struct mountlist *mp;
{
diff --git a/usr.bin/size/size.1 b/usr.bin/size/size.1
index 5f3b2fa..ee46bb2 100644
--- a/usr.bin/size/size.1
+++ b/usr.bin/size/size.1
@@ -57,4 +57,5 @@ attempts to report on the file
.Sh HISTORY
A
.Nm size
-command appeared in Version 6 AT&T Unix.
+command appeared in
+.At v6 .
diff --git a/usr.bin/size/size.1aout b/usr.bin/size/size.1aout
new file mode 100644
index 0000000..ee46bb2
--- /dev/null
+++ b/usr.bin/size/size.1aout
@@ -0,0 +1,61 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)size.1 8.2 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt SIZE 1
+.Os
+.Sh NAME
+.Nm size
+.Nd display object file segment sizes (text, data and bss)
+.Sh SYNOPSIS
+.Nm size
+.Op Ar object_file ...
+.Sh DESCRIPTION
+.Nm Size
+displays the text, data and bss segment sizes of the specified
+.Ar object_file
+in bytes (in decimal), and the sum of the three segments (in
+decimal and hexadecimal).
+If no
+.Ar object_file
+is specified
+.Nm
+attempts to report on the file
+.Pa a.out .
+.Sh SEE ALSO
+.Xr a.out 5
+.Sh HISTORY
+A
+.Nm size
+command appeared in
+.At v6 .
diff --git a/usr.bin/size/size.c b/usr.bin/size/size.c
index 674c3c8..b34e24c 100644
--- a/usr.bin/size/size.c
+++ b/usr.bin/size/size.c
@@ -61,7 +61,7 @@ main(argc, argv)
{
int ch, eval;
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/sort/sort.1 b/usr.bin/sort/sort.1
new file mode 100644
index 0000000..574efc3
--- /dev/null
+++ b/usr.bin/sort/sort.1
@@ -0,0 +1,310 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sort.1 8.2 (Berkeley) 5/4/95
+.\"
+.Dd May 4, 1995
+.Dt SORT 1
+.Os
+.Sh NAME
+.Nm sort
+.Nd sort or merge text files
+.Sh SYNOPSIS
+.Nm sort
+.Op Fl mubdfinrtx
+.Oo
+.Cm \(pl Ns Ar pos1
+.Op Fl Ns Ar pos2
+.Oc
+.Ar ...
+.Op Fl o Ar output
+.Op Fl T Ar directory
+.Op Ar file
+.Ar ...
+.Sh DESCRIPTION
+The
+.Nm sort
+utility
+sorts text files by lines.
+Comparisons are based on one or more sort keys (or fields) extracted
+from each line of input, and are performed
+lexicographically. By default, if keys are not given,
+.Nm sort
+regards each input line as a single field.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Check that the single input file is sorted lexicographically.
+If the file is not sorted,
+.Nm sort
+sorts it and writes the sorted output to the standard output or the
+filename specified by the
+.Fl o
+option.
+.It Fl m
+Merge only; the input files are assumed to be pre-sorted.
+.It Fl o Ar output
+The argument given is the name of an
+.Ar output
+file to
+be used instead of the standard output.
+This file
+can be the same as one of the input files.
+.It Fl T Ar directory
+The argument
+.Ar directory
+is used for creating temporary files.
+.It Fl u
+Unique: suppress all but one in each set of lines
+having equal keys.
+If used with the
+.Fl c
+option,
+check that there are no lines with duplicate keys.
+.El
+.Pp
+The following options override the default ordering rules.
+When ordering options appear independent of key field
+specifications, the requested field ordering rules are
+applied globally to all sort keys.
+.\" When attached to a
+.\" specific key
+.\" (see
+.\" .Fl k ) ,
+.\" the specified ordering options override
+.\" all global ordering options for that key.
+.Bl -tag -width indent
+.It Fl d
+Only blank space and alphanumeric characters
+.\" according
+.\" to the current setting of LC_CTYPE
+are used
+in making comparisons.
+.It Fl f
+Considers all lowercase characters that have uppercase
+equivalents to be the same for purposes of
+comparison.
+.It Fl i
+Ignore all non-printable characters.
+.It Fl n
+An initial numeric string, consisting of optional
+blank space, optional minus sign, and zero or more
+digits (including decimal point)
+.\" with
+.\" optional radix character and thousands
+.\" separator
+.\" (as defined in the current locale),
+is sorted by arithmetic value.
+The
+.Fl n
+option implies
+the
+.Fl b
+option. (See below.)
+Note that the
+.Fl b
+option
+is only effective when key fields have been specified
+and that
+.Fl \&0
+is considered equal to zero.
+.It Fl r
+Reverse the sense of comparisons.
+.El
+.Pp
+The treatment of field separators can be altered using the
+options:
+.Bl -tag -width indent
+.It Fl b
+Leading blank spaces are ignored when determining the starting
+ending positions of a restricted sort key.
+If the
+.Fl b
+option is specified before the first
+.Cm \(pl Ns Ar pos1
+argument, it shall be applied to all
+.Cm \(pl Ns Ar pos1
+arguments.
+Otherwise, the
+.Fl b
+option can be
+attached independently to each
+.Cm \(pl Ns Ar pos1
+or
+.Fl Ar pos2
+argument (see below).
+.It Fl t Ar char
+.Ar Char
+is used as the field separator character;
+.Ar char
+is not considered to be part of a field (although it
+can be included in a sort key).
+Each occurrence of
+.Ar char
+is significant (for example,
+.Dq Ar charchar
+delimits an empty field).
+If
+.Fl t
+is not specified,
+blank space characters are used as default field
+separators.
+.It Cm \(pl Ns Ar pos1
+Designates the start position of a key field.
+.It Fl Ns Ar pos1
+Designates the end position of a key field.
+.El
+.Pp
+The following operands are available:
+.Bl -tag -width indent
+.Ar file
+The pathname of a file to be sorted, merged, or checked.
+If no file
+operands are specified, or if
+a file operand is
+.Fl ,
+the standard input is used.
+.Pp
+A field is
+defined as a minimal sequence of characters followed by a
+field separator or a newline character.
+By default, the first
+blank space of a sequence of blank spaces acts as the field separator.
+All blank spaces in a sequence of blank spaces are considered
+to be part of the next field; for example, all blank spaces at
+the beginning of a line are considered to be part of the
+first field.
+.Pp
+Fields are specified
+by the
+.Cm \(pl Ns Ar pos1
+and
+.Fl Ar pos2
+arguments. A missing
+.Cm \(pl Ns Ar pos1
+argument defaults to the beginning of a line.
+A missing
+.Fl Ar pos2
+argument defaults to the end of a line.
+.Pp
+The arguments
+.Cm \(pl Ns Ar pos1
+and
+.Fl Ar pos2
+have the form
+.Em m.n
+followed by one or more of the options
+.Fl b , d , f , i ,
+.Fl n , r .
+A
+.Cm \(pl Ns Ar pos1
+position specified by
+.Em m.n
+is interpreted to
+mean the
+.Em n Ns th
+character in the
+.Em m Ns \(pl1th
+field.
+A missing
+.Em \&.n
+means
+.Ql \&.0 ,
+indicating the first character of the
+.Em m Ns \(pl1th
+field.
+If the
+.Fl b
+option is in effect,
+.Em n
+is counted from the first
+non-blank character in the
+.Em m Ns \(pl1th
+field;
+.Em m Ns \&.0b
+refers to the first
+non-blank character in the
+.Em m Ns \(pl1th
+field.
+.Pp
+A
+.Fl Ar pos2
+position specified by
+.Em m.n
+is interpreted to mean
+the
+.Em n Ns th
+character (including separators) after the last
+character of the
+.Em m Ns th
+field.
+A missing
+.Em \&.n
+means
+.Ql \&.0 ,
+indicating
+the last character of the
+.Em m Ns th
+field.
+If the
+.Fl b
+option
+is in effect,
+.Em n
+is counted from the last leading blank character in
+the
+.Em m Ns \(pl1th
+field;
+.Em m Ns \&.1b
+refers to the first non-blank character in the
+.Em m Ns \(pl1th
+field.
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/tmp/stm*, /tmp/*
+Default temporary directories (in order of search).
+.El
+.Sh SEE ALSO
+.Xr comm 1 ,
+.Xr uniq 1 ,
+.Xr join 1
+.Sh DIAGNOSTICS
+.Sh BUGS
+Lines which are longer than 4096 are discarded and processing continues.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
diff --git a/usr.bin/split/split.c b/usr.bin/split/split.c
index 221ee31..6b75c75 100644
--- a/usr.bin/split/split.c
+++ b/usr.bin/split/split.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)split.c 8.3 (Berkeley) 4/25/94";
+static char sccsid[] = "@(#)split.c 8.2 (Berkeley) 4/16/94";
#endif /* not lint */
#include <sys/param.h>
@@ -73,7 +73,7 @@ main(argc, argv)
int ch;
char *ep, *p;
- while ((ch = getopt(argc, argv, "-0123456789b:l:")) != EOF)
+ while ((ch = getopt(argc, argv, "-0123456789b:l:")) != -1)
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
diff --git a/usr.bin/strings/strings.1aout b/usr.bin/strings/strings.1aout
new file mode 100644
index 0000000..ceeae10
--- /dev/null
+++ b/usr.bin/strings/strings.1aout
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strings.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt STRINGS 1
+.Os BSD 3
+.Sh NAME
+.Nm strings
+.Nd find printable strings in a file
+.Sh SYNOPSIS
+.Nm strings
+.Op Fl afo
+.Op Fl n Ar number
+.Op Ar file ...
+.Sh DESCRIPTION
+.Nm Strings
+displays the sequences of printable characters in each of the specified
+files, or in the standard input, by default.
+By default, a sequence must be at least four characters in length
+before being displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+By default,
+.Nm strings
+only searches the text and data segments of object files.
+The
+.Fl a
+option causes
+.Nm strings
+to search the entire object file.
+.It Fl f
+Each string is preceded by the name of the file
+in which it was found.
+.It Fl n
+Specifies the minimum number of characters in a sequence to be
+.Ar number ,
+instead of four.
+.It Fl o
+Each string is preceded by its decimal offset in the
+file.
+.El
+.Pp
+.Nm Strings
+is useful for identifying random binaries, among other things.
+.Sh SEE ALSO
+.Xr hexdump 1
+.Sh BUGS
+The algorithm for identifying strings is extremely primitive.
+In particular, machine code instructions on certain architectures
+can resemble sequences of ASCII bytes, which
+will fool the algorithm.
+.Sh COMPATIBILITY
+Historic implementations of
+.Nm
+only search the initialized data portion of the object file.
+This was reasonable as strings were normally stored there.
+Given new compiler technology which installs strings in the
+text portion of the object file, the default behavior was
+changed.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/usr.bin/strings/strings.c b/usr.bin/strings/strings.c
index 398ccac..2ddeced 100644
--- a/usr.bin/strings/strings.c
+++ b/usr.bin/strings/strings.c
@@ -47,13 +47,16 @@ static char sccsid[] = "@(#)strings.c 8.2 (Berkeley) 1/28/94";
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define DEF_LEN 4 /* default minimum string length */
-#define ISSTR(ch) (isascii(ch) && (isprint(ch) || ch == '\t'))
+#define ISSTR(ch) (isalnum(ch) || ispunct(ch) || \
+ isspace(ch) && (!iscntrl(ch) || ch == '\t') || \
+ isascii(ch) && isprint(ch))
typedef struct exec EXEC; /* struct exec cast */
@@ -79,13 +82,15 @@ main(argc, argv)
u_char *bfr;
char *file, *p;
+ (void) setlocale(LC_CTYPE, "");
+
/*
* for backward compatibility, allow '-' to specify 'a' flag; no
* longer documented in the man page or usage string.
*/
asdata = exitcode = fflg = oflg = 0;
minlen = -1;
- while ((ch = getopt(argc, argv, "-0123456789an:of")) != EOF)
+ while ((ch = getopt(argc, argv, "-0123456789an:of")) != -1)
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@@ -123,7 +128,7 @@ main(argc, argv)
if (minlen == -1)
minlen = DEF_LEN;
- else {
+ else if (minlen < 1) {
(void)fprintf(stderr, "strings: length less than 1\n");
exit (1);
}
diff --git a/usr.bin/strip/Makefile b/usr.bin/strip/Makefile
index aedea50..3d19864 100644
--- a/usr.bin/strip/Makefile
+++ b/usr.bin/strip/Makefile
@@ -1,11 +1,21 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= strip
+MAN1= strip.1
+CLEANFILES += maybe_stripped
+
+all: maybe_stripped
+
+maybe_stripped: strip
+ cp -p strip maybe_stripped
+.if defined(STRIP)
+.if ${STRIP:M-s} != ""
+ ./strip maybe_stripped
+.endif
+.endif
install: maninstall
- install -c -o ${BINOWN} -g ${BINOWN} -m ${BINMODE} strip \
- ${DESTDIR}${BINDIR}
- ./strip ${DESTDIR}${BINDIR}/strip
- rm -f ./strip
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ maybe_stripped ${DESTDIR}${BINDIR}/strip
.include <bsd.prog.mk>
diff --git a/usr.bin/strip/strip.1 b/usr.bin/strip/strip.1
index b131004..d9252ac 100644
--- a/usr.bin/strip/strip.1
+++ b/usr.bin/strip/strip.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)strip.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt STRIP 1
@@ -40,6 +41,7 @@
.Sh SYNOPSIS
.Nm strip
.Op Fl d
+.Op Fl x
.Ar file ...
.Sh DESCRIPTION
The
@@ -54,6 +56,8 @@ The options are as follows:
.Bl -tag -width Ds
.It Fl d
Delete only debugging and empty symbols.
+.It Fl x
+Delete only debugging, compiler identification, and local symbols.
.El
.Pp
.Nm Strip
@@ -66,4 +70,4 @@ exits 0 on success and 1 if an error occurred.
A
.Nm
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/strip/strip.1aout b/usr.bin/strip/strip.1aout
new file mode 100644
index 0000000..d9252ac
--- /dev/null
+++ b/usr.bin/strip/strip.1aout
@@ -0,0 +1,73 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strip.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
+.\"
+.Dd June 6, 1993
+.Dt STRIP 1
+.Os
+.Sh NAME
+.Nm strip
+.Nd remove unnecessary information from executable files
+.Sh SYNOPSIS
+.Nm strip
+.Op Fl d
+.Op Fl x
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm strip
+utility
+deletes the relocation information and symbol table used by
+assemblers, loaders and debuggers.
+This significantly
+decreases the size of the installed binaries and saves disk space.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d
+Delete only debugging and empty symbols.
+.It Fl x
+Delete only debugging, compiler identification, and local symbols.
+.El
+.Pp
+.Nm Strip
+exits 0 on success and 1 if an error occurred.
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr ld 1 ,
+.Xr stab 5
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/strip/strip.c b/usr.bin/strip/strip.c
index 114d823..564a9a3 100644
--- a/usr.bin/strip/strip.c
+++ b/usr.bin/strip/strip.c
@@ -38,32 +38,36 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)strip.c 8.3 (Berkeley) 5/16/95";
+/*static char sccsid[] = "@(#)strip.c 8.1 (Berkeley) 6/6/93";*/
+static char RCSid[] = "$Id: strip.c,v 1.9 1997/02/22 19:57:14 peter Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <a.out.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <a.out.h>
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
typedef struct exec EXEC;
typedef struct nlist NLIST;
#define strx n_un.n_strx
+void err __P((int, const char *fmt, ...));
void s_stab __P((const char *, int, EXEC *));
void s_sym __P((const char *, int, EXEC *));
void usage __P((void));
+int xflag = 0;
+int err_val = 0;
+
int
main(argc, argv)
int argc;
@@ -72,12 +76,15 @@ main(argc, argv)
register int fd, nb;
EXEC head;
void (*sfcn)__P((const char *, int, EXEC *));
- int ch, eval;
+ int ch;
char *fn;
sfcn = s_sym;
- while ((ch = getopt(argc, argv, "d")) != EOF)
+ while ((ch = getopt(argc, argv, "dx")) != -1)
switch(ch) {
+ case 'x':
+ xflag = 1;
+ /*FALLTHROUGH*/
case 'd':
sfcn = s_stab;
break;
@@ -88,31 +95,25 @@ main(argc, argv)
argc -= optind;
argv += optind;
- for (eval = 0; (fn = *argv++) != NULL;) {
- if ((fd = open(fn, O_RDWR)) < 0) {
- warn("%s", fn);
- eval = 1;
- continue;
- }
- if ((nb = read(fd, &head, sizeof(EXEC))) == -1) {
- warn("%s", fn);
- (void)close(fd);
- eval = 1;
+ while ((fn = *argv++) != NULL) {
+ if ((fd = open(fn, O_RDWR)) < 0 ||
+ (nb = read(fd, &head, sizeof(EXEC))) == -1) {
+ err(0, "%s: %s", fn, strerror(errno));
+ if (fd >= 0 && close(fd))
+ err(0, "%s: %s", fn, strerror(errno));
continue;
}
if (nb != sizeof(EXEC) || N_BADMAG(head)) {
- warnx("%s: %s", fn, strerror(EFTYPE));
- (void)close(fd);
- eval = 1;
+ err(0, "%s: %s", fn, strerror(EFTYPE));
+ if (close(fd))
+ err(0, "%s: %s", fn, strerror(errno));
continue;
}
sfcn(fn, fd, &head);
- if (close(fd)) {
- warn("%s", fn);
- eval = 1;
- }
+ if (close(fd))
+ err(0, "%s: %s", fn, strerror(errno));
}
- exit(eval);
+ exit(err_val);
}
void
@@ -139,7 +140,7 @@ s_sym(fn, fd, ep)
if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) ||
ftruncate(fd, fsize))
- err(0, "%s: %s", fn, strerror(errno));
+ err(0, "%s: %s", fn, strerror(errno));
}
void
@@ -172,7 +173,7 @@ s_stab(fn, fd, ep)
/* Map the file. */
if ((ep = (EXEC *)mmap(NULL, (size_t)sb.st_size,
- PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)-1) {
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)MAP_FAILED) {
err(0, "%s: %s", fn, strerror(errno));
return;
}
@@ -190,8 +191,11 @@ s_stab(fn, fd, ep)
* of the string table.
*/
strbase = (char *)ep + N_STROFF(*ep);
- if ((nstrbase = malloc((u_int)*(u_long *)strbase)) == NULL)
- err(1, "%s", strerror(errno));
+ if ((nstrbase = malloc((size_t)*(u_long *)strbase)) == NULL) {
+ err(0, "%s", strerror(errno));
+ munmap((caddr_t)ep, sb.st_size);
+ return;
+ }
nstr = nstrbase + sizeof(u_long);
/*
@@ -204,6 +208,13 @@ s_stab(fn, fd, ep)
*nsym = *sym;
nsym->strx = nstr - nstrbase;
p = strbase + sym->strx;
+ if (xflag &&
+ (!(sym->n_type & N_EXT) ||
+ (sym->n_type & ~N_EXT) == N_FN ||
+ strcmp(p, "gcc_compiled.") == 0 ||
+ strcmp(p, "gcc2_compiled.") == 0 ||
+ strcmp(p, "___gnu_compiled_c") == 0))
+ continue;
len = strlen(p) + 1;
bcopy(p, nstr, len);
nstr += len;
@@ -231,6 +242,37 @@ s_stab(fn, fd, ep)
void
usage()
{
- (void)fprintf(stderr, "usage: strip [-d] file ...\n");
+ (void)fprintf(stderr, "usage: strip [-dx] file ...\n");
exit(1);
}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(int fatal, const char *fmt, ...)
+#else
+err(fatal, fmt, va_alist)
+ int fatal;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "strip: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ if (fatal)
+ exit(1);
+ err_val = 1;
+}
diff --git a/usr.bin/su/Makefile b/usr.bin/su/Makefile
index e3e023a..5c0782c 100644
--- a/usr.bin/su/Makefile
+++ b/usr.bin/su/Makefile
@@ -1,9 +1,35 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
PROG= su
+SRCS= su.c
+
+#LC_AUTH=-DLOGIN_CAP_AUTH
+COPTS+= -DLOGIN_CAP $(LC_AUTH)
+LDADD+= -lutil
+DPADD+= ${LIBUTIL}
+
+.if !defined(LC_AUTH)
+COPTS+= -DSKEY
+LDADD+= -lskey -lcrypt
+DPADD+= ${LIBSKEY} ${LIBCRYPT}
+.endif
+
+.if defined(WHEELSU)
+COPTS+= -DWHEELSU
+.endif
+CFLAGS+= -Wall
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
+ || defined(MAKE_EBONES)) && !defined(LC_AUTH)
CFLAGS+=-DKERBEROS
-DPADD= ${LIBKRB} ${LIBDES}
-LDADD= -lkrb -ldes
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+DISTRIBUTION= krb
+.endif
+
+LDADD+= -lmd
+DPADD+= ${LIBMD}
+
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
diff --git a/usr.bin/su/su.1 b/usr.bin/su/su.1
index ea9edcf..0c60ec7 100644
--- a/usr.bin/su/su.1
+++ b/usr.bin/su/su.1
@@ -30,7 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)su.1 8.2 (Berkeley) 4/18/94
+.\" $Id: su.1,v 1.7 1997/02/22 19:57:15 peter Exp $
.\"
+.\" this is for hilit19's braindeadness: "
.Dd April 18, 1994
.Dt SU 1
.Os
@@ -40,7 +42,7 @@
.Sh SYNOPSIS
.Nm su
.Op Fl Kflm
-.Op Ar login
+.Op Ar login Op Ar args
.Sh DESCRIPTION
.Nm Su
requests the Kerberos password for
@@ -75,6 +77,10 @@ in which case it is unmodified.
The invoked shell is the target login's.
This is the traditional behavior of
.Nm su .
+Resource limits and session priority applicable to the original user's
+login class (See
+.Xr login.conf 5 )
+are also normally retained unless the target login as a user ID of 0.
.Pp
The options are as follows:
.Bl -tag -width Ds
@@ -106,9 +112,13 @@ is set to
.Dq Pa /bin:/usr/bin .
.Ev TERM
is imported from your current environment.
+Envronment variables may be set or overridden from the login class
+capabilities database according to the class of the target login.
The invoked shell is the target login's, and
.Nm su
will change directory to the target login's home directory.
+Resource limits and session priority are modified to that for the
+target account's login class.
.It Fl m
Leave the environment unmodified.
The invoked shell is your login shell, and no directory changes are made.
@@ -128,12 +138,24 @@ and
options are mutually exclusive; the last one specified
overrides any previous ones.
.Pp
-Only users in group 0 (normally
+If the optional
+.Ar args
+are provided on the command line, they are passed to the login shell of
+the target login. This allows it to pass arbitrary commands via
+the
+.Fl c
+option as understood by most shells. Note that
+.Fl c
+usually expects a single argument only; you have to quote it when
+passing multiple words.
+.Pp
+Only users listed in group 0 (normally
.Dq wheel )
can
.Nm su
to
-.Dq root .
+.Dq root ,
+unless this group is empty.
.Pp
By default (unless the prompt is reset by a startup file) the super-user
prompt is set to
@@ -141,12 +163,13 @@ prompt is set to
to remind one of its awesome power.
.Sh SEE ALSO
.Xr csh 1 ,
+.Xr kerberos 1 ,
+.Xr kinit 1 ,
.Xr login 1 ,
.Xr sh 1 ,
-.Xr kinit 1 ,
-.Xr kerberos 1 ,
-.Xr passwd 5 ,
.Xr group 5 ,
+.Xr login.conf 5 ,
+.Xr passwd 5 ,
.Xr environ 7
.Sh ENVIRONMENT
Environment variables used by
@@ -165,8 +188,23 @@ The user ID is always the effective ID (the target user ID) after an
.Nm su
unless the user ID is 0 (root).
.El
+.Sh EXAMPLES
+.Bl -tag -width 5n -compact
+.It Li "su man -c catman"
+Runs the command
+.Li catman
+as user
+.Li man .
+You will be asked for man's password unless your real UID is 0.
+.It Li "su man -c 'catman /usr/share/man /usr/local/man /usr/X11R6/man'"
+Same as above, but the target command constitutes of more than a
+single word.
+.It Li "su -l foo"
+Pretend a login for user
+.Li foo .
+.El
.Sh HISTORY
A
.Nm
command appeared in
-.At v7 .
+.At v1 .
diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c
index f06ef2f..fb137d8 100644
--- a/usr.bin/su/su.c
+++ b/usr.bin/su/su.c
@@ -32,13 +32,17 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1988, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
+/*
static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";
+*/
+static const char rcsid[] =
+ "$Id: su.c,v 1.19 1997/03/29 04:32:40 imp Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -56,17 +60,32 @@ static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";
#include <syslog.h>
#include <unistd.h>
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#ifdef LOGIN_CAP_AUTH
+#undef SKEY
+#undef KERBEROS
+#endif
+#endif
+
+#ifdef SKEY
+#include <skey.h>
+#endif
+
#ifdef KERBEROS
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#include <netdb.h>
#define ARGSTR "-Kflm"
+static int kerberos(char *username, char *user, int uid, char *pword);
+static int koktologin(char *name, char *toname);
+
int use_kerberos = 1;
-#else
+#else /* !KERBEROS */
#define ARGSTR "-flm"
-#endif
+#endif /* KERBEROS */
char *ontty __P((void));
int chshell __P((char *));
@@ -78,17 +97,31 @@ main(argc, argv)
{
extern char **environ;
struct passwd *pwd;
- char *p, **g, *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
+#ifdef WHEELSU
+ char *targetpass;
+ int iswheelsu;
+#endif /* WHEELSU */
+ char *p, **g, *user, *shell=NULL, *username, *cleanenv[20], **nargv, **np;
struct group *gr;
uid_t ruid;
- int asme, ch, asthem, fastlogin, prio;
+ int asme, ch, asthem, fastlogin, prio, i;
enum { UNSET, YES, NO } iscsh = UNSET;
+#ifdef LOGIN_CAP
+ login_cap_t *lc;
+ int setwhat;
+#ifdef LOGIN_CAP_AUTH
+ char *style, *approvep, *auth_method = NULL;
+#endif
+#endif
char shellbuf[MAXPATHLEN];
- np = &nargv[3];
- *np-- = NULL;
+#ifdef WHEELSU
+ iswheelsu =
+#endif /* WHEELSU */
asme = asthem = fastlogin = 0;
- while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+ user = "root";
+ while(optind < argc)
+ if((ch = getopt(argc, argv, ARGSTR)) != -1)
switch((char)ch) {
#ifdef KERBEROS
case 'K':
@@ -110,9 +143,24 @@ main(argc, argv)
case '?':
default:
(void)fprintf(stderr, "usage: su [%s] [login]\n",
- ARGSTR);
+ ARGSTR);
exit(1);
- }
+ }
+ else
+ {
+ user = argv[optind++];
+ break;
+ }
+
+ if((nargv = malloc (sizeof (char *) * (argc + 4))) == NULL) {
+ errx(1, "malloc failure");
+ }
+
+ nargv[argc + 3] = NULL;
+ for (i = argc; i >= optind; i--)
+ nargv[i + 3] = argv[i];
+ np = &nargv[i + 3];
+
argv += optind;
errno = 0;
@@ -133,48 +181,138 @@ main(argc, argv)
username = strdup(pwd->pw_name);
if (username == NULL)
err(1, NULL);
- if (asme)
- if (pwd->pw_shell && *pwd->pw_shell)
- shell = strcpy(shellbuf, pwd->pw_shell);
- else {
+ if (asme) {
+ if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
+ /* copy: pwd memory is recycled */
+ shell = strncpy(shellbuf, pwd->pw_shell, sizeof shellbuf);
+ shellbuf[sizeof shellbuf - 1] = '\0';
+ } else {
shell = _PATH_BSHELL;
iscsh = NO;
}
+ }
+
+#ifdef LOGIN_CAP_AUTH
+ if (auth_method = strchr(user, ':')) {
+ *auth_method = '\0';
+ auth_method++;
+ if (*auth_method == '\0')
+ auth_method = NULL;
+ }
+#endif /* !LOGIN_CAP_AUTH */
/* get target login information, default to root */
- user = *argv ? *argv : "root";
if ((pwd = getpwnam(user)) == NULL) {
- fprintf(stderr, "su: unknown login %s\n", user);
- exit(1);
+ errx(1, "unknown login: %s", user);
}
+#ifdef LOGIN_CAP
+ lc = login_getpwclass(pwd);
+#endif
+
+#ifdef WHEELSU
+ targetpass = strdup(pwd->pw_passwd);
+#endif /* WHEELSU */
if (ruid) {
#ifdef KERBEROS
- if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
+ if (use_kerberos && koktologin(username, user)
+ && !pwd->pw_uid) {
+ warnx("kerberos: not in %s's ACL.", user);
+ use_kerberos = 0;
+ }
#endif
- {
- /* only allow those in group zero to su to root. */
- if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
- for (g = gr->gr_mem;; ++g) {
- if (!*g)
- errx(1,
+ {
+ /* only allow those in group zero to su to root. */
+ if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)) &&
+ gr->gr_mem && *(gr->gr_mem))
+ for (g = gr->gr_mem;; ++g) {
+ if (!*g)
+ errx(1,
"you are not in the correct group to su %s.",
- user);
- if (strcmp(username, *g) == 0)
- break;
+ user);
+ if (strcmp(username, *g) == 0) {
+#ifdef WHEELSU
+ iswheelsu = 1;
+#endif /* WHEELSU */
+ break;
+ }
+ }
}
/* if target requires a password, verify it */
if (*pwd->pw_passwd) {
- p = getpass("Password:");
- if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
+#ifdef LOGIN_CAP_AUTH
+ /*
+ * This hands off authorisation to an authorisation program,
+ * depending on the styles available for the "auth-su",
+ * authorisation styles.
+ */
+ if ((style = login_getstyle(lc, auth_method, "su")) == NULL)
+ errx(1, "auth method available for su.\n");
+ if (authenticate(user, lc ? lc->lc_class : "default", style, "su") != 0) {
+#ifdef WHEELSU
+ if (!iswheelsu || authenticate(username, lc ? lc->lc_class : "default", style, "su") != 0) {
+#endif /* WHEELSU */
+ {
+ fprintf(stderr, "Sorry\n");
+ syslog(LOG_AUTH|LOG_WARNING,"BAD SU %s to %s%s", username, user, ontty());
+ exit(1);
+ }
+ }
+
+ /*
+ * If authentication succeeds, run any approval
+ * program, if applicable for this class.
+ */
+ approvep = login_getcapstr(lc, "approve", NULL, NULL);
+ if (approvep==NULL || auth_script(approvep, approvep, username, lc->lc_class, 0) == 0) {
+ int r = auth_scan(AUTH_OKAY);
+ /* See what the authorise program says */
+ if (!(r & AUTH_ROOTOKAY) && pwd->pw_uid == 0) {
fprintf(stderr, "Sorry\n");
- syslog(LOG_AUTH|LOG_WARNING,
- "BAD SU %s to %s%s", username,
- user, ontty());
+ syslog(LOG_AUTH|LOG_WARNING,"UNAPPROVED ROOT SU %s%s", user, ontty());
exit(1);
}
}
- }
+#else /* !LOGIN_CAP_AUTH */
+#ifdef SKEY
+#ifdef WHEELSU
+ if (iswheelsu) {
+ pwd = getpwnam(username);
+ }
+#endif /* WHEELSU */
+ p = skey_getpass("Password:", pwd, 1);
+ if (!(!strcmp(pwd->pw_passwd, skey_crypt(p, pwd->pw_passwd, pwd, 1))
+#ifdef WHEELSU
+ || (iswheelsu && !strcmp(targetpass, crypt(p,targetpass)))
+#endif /* WHEELSU */
+ )) {
+#else
+ p = getpass("Password:");
+ if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
+#endif
+#ifdef KERBEROS
+ if (!use_kerberos || (use_kerberos && kerberos(username, user, pwd->pw_uid, p)))
+#endif
+ {
+ fprintf(stderr, "Sorry\n");
+ syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty());
+ exit(1);
+ }
+ }
+#ifdef WHEELSU
+ if (iswheelsu) {
+ pwd = getpwnam(user);
+ }
+#endif /* WHEELSU */
+#endif /* LOGIN_CAP_AUTH */
+ }
+ if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) {
+ fprintf(stderr, "Sorry - account expired\n");
+ syslog(LOG_AUTH|LOG_WARNING,
+ "BAD SU %s to %s%s", username,
+ user, ontty());
+ exit(1);
+ }
}
if (asme) {
@@ -191,13 +329,29 @@ main(argc, argv)
/* if we're forking a csh, we want to slightly muck the args */
if (iscsh == UNSET) {
- if (p = strrchr(shell, '/'))
+ p = strrchr(shell, '/');
+ if (p)
++p;
else
p = shell;
- iscsh = strcmp(p, "csh") ? NO : YES;
+ if ((iscsh = strcmp(p, "csh") ? NO : YES) == NO)
+ iscsh = strcmp(p, "tcsh") ? NO : YES;
}
+ (void)setpriority(PRIO_PROCESS, 0, prio);
+
+#ifdef LOGIN_CAP
+ /* Set everything now except the environment & umask */
+ setwhat = LOGIN_SETUSER|LOGIN_SETGROUP|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
+ /*
+ * Don't touch resource/priority settings if -m has been
+ * used or -l hasn't, and we're not su'ing to root.
+ */
+ if ((asme || !asthem) && pwd->pw_uid)
+ setwhat &= ~(LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
+ if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
+ err(1, "setusercontext");
+#else
/* set permissions */
if (setgid(pwd->pw_gid) < 0)
err(1, "setgid");
@@ -205,14 +359,21 @@ main(argc, argv)
errx(1, "initgroups failed");
if (setuid(pwd->pw_uid) < 0)
err(1, "setuid");
+#endif
if (!asme) {
if (asthem) {
p = getenv("TERM");
- cleanenv[0] = _PATH_DEFPATH;
- cleanenv[1] = NULL;
+ cleanenv[0] = NULL;
environ = cleanenv;
- (void)setenv("TERM", p, 1);
+#ifdef LOGIN_CAP
+ /* set the su'd user's environment & umask */
+ setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
+#else
+ (void)setenv("PATH", _PATH_DEFPATH, 1);
+#endif
+ if (p)
+ (void)setenv("TERM", p, 1);
if (chdir(pwd->pw_dir) < 0)
errx(1, "no directory");
}
@@ -221,7 +382,6 @@ main(argc, argv)
(void)setenv("HOME", pwd->pw_dir, 1);
(void)setenv("SHELL", shell, 1);
}
-
if (iscsh == YES) {
if (fastlogin)
*np-- = "-f";
@@ -236,7 +396,7 @@ main(argc, argv)
syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s",
username, user, ontty());
- (void)setpriority(PRIO_PROCESS, 0, prio);
+ login_close(lc);
execv(shell, np);
err(1, "%s", shell);
@@ -246,12 +406,14 @@ int
chshell(sh)
char *sh;
{
+ int r = 0;
char *cp;
- while ((cp = getusershell()) != NULL)
- if (strcmp(cp, sh) == 0)
- return (1);
- return (0);
+ setusershell();
+ while (!r && (cp = getusershell()) != NULL)
+ r = strcmp(cp, sh) == 0;
+ endusershell();
+ return r;
}
char *
@@ -261,34 +423,33 @@ ontty()
static char buf[MAXPATHLEN + 4];
buf[0] = 0;
- if (p = ttyname(STDERR_FILENO))
+ p = ttyname(STDERR_FILENO);
+ if (p)
snprintf(buf, sizeof(buf), " on %s", p);
return (buf);
}
#ifdef KERBEROS
-kerberos(username, user, uid)
+int
+kerberos(username, user, uid, pword)
char *username, *user;
int uid;
+ char *pword;
{
extern char *krb_err_txt[];
KTEXT_ST ticket;
AUTH_DAT authdata;
- struct hostent *hp;
- char *p;
int kerno;
u_long faddr;
+ struct sockaddr_in local_addr;
char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
char *krb_get_phost();
if (krb_get_lrealm(lrealm, 1) != KSUCCESS)
return (1);
- if (koktologin(username, lrealm, user) && !uid) {
- warnx("kerberos: not in %s's ACL.", user);
- return (1);
- }
- (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid());
+ (void)sprintf(krbtkfile, "%s_%s_%lu", TKT_ROOT, user,
+ (unsigned long)getuid());
(void)setenv("KRBTKFILE", krbtkfile, 1);
(void)krb_set_tkt_string(krbtkfile);
@@ -313,7 +474,7 @@ kerberos(username, user, uid)
*/
kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
(uid == 0 ? "root" : ""), lrealm,
- "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0);
+ "krbtgt", lrealm, DEFAULT_TKT_LIFE, pword);
if (kerno != KSUCCESS) {
if (kerno == KDC_PR_UNKNOWN) {
@@ -361,13 +522,13 @@ kerberos(username, user, uid)
dest_tkt();
return (1);
} else {
- if (!(hp = gethostbyname(hostname))) {
- warnx("can't get addr of %s", hostname);
+ if ((kerno = krb_get_local_addr(&local_addr)) != KSUCCESS) {
+ warnx("Unable to get our local address: %s",
+ krb_err_txt[kerno]);
dest_tkt();
return (1);
}
- memmove((char *)&faddr, (char *)hp->h_addr, sizeof(faddr));
-
+ faddr = local_addr.sin_addr.s_addr;
if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
&authdata, "")) != KSUCCESS) {
warnx("kerberos: unable to verify rcmd ticket: %s\n",
@@ -382,18 +543,22 @@ kerberos(username, user, uid)
return (0);
}
-koktologin(name, realm, toname)
- char *name, *realm, *toname;
+int
+koktologin(name, toname)
+ char *name, *toname;
{
AUTH_DAT *kdata;
AUTH_DAT kdata_st;
+ char realm[REALM_SZ];
+ if (krb_get_lrealm(realm, 1) != KSUCCESS)
+ return (1);
kdata = &kdata_st;
memset((char *)kdata, 0, sizeof(*kdata));
- (void)strcpy(kdata->pname, name);
- (void)strcpy(kdata->pinst,
- ((strcmp(toname, "root") == 0) ? "root" : ""));
- (void)strcpy(kdata->prealm, realm);
+ (void)strncpy(kdata->pname, name, sizeof kdata->pname - 1);
+ (void)strncpy(kdata->pinst,
+ ((strcmp(toname, "root") == 0) ? "root" : ""), sizeof kdata->pinst - 1);
+ (void)strncpy(kdata->prealm, realm, sizeof kdata->prealm - 1);
return (kuserok(kdata, toname));
}
#endif
diff --git a/usr.bin/symorder/Makefile b/usr.bin/symorder/Makefile
new file mode 100644
index 0000000..5fe1caf
--- /dev/null
+++ b/usr.bin/symorder/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 5.3 (Berkeley) 5/11/90
+
+PROG= symorder
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/symorder/symorder.1 b/usr.bin/symorder/symorder.1
new file mode 100644
index 0000000..a609799
--- /dev/null
+++ b/usr.bin/symorder/symorder.1
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1980, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)symorder.1 6.5 (Berkeley) 4/22/91
+.\"
+.Dd April 22, 1991
+.Dt SYMORDER 1
+.Os BSD 3
+.Sh NAME
+.Nm symorder
+.Nd rearrange name list
+.Sh SYNOPSIS
+.Nm symorder
+.Fl c
+.Fl m
+.Fl t
+.Fl x
+.Ar excludelist
+.Ar symlist file
+.Sh DESCRIPTION
+The file
+.Ar symlist
+contains a list of symbols to be found in
+.Ar file,
+one symbol per line.
+.Pp
+The symbol table of
+.Ar file
+is updated in place;
+symbols read from
+.Ar symlist
+are relocated to the beginning of the table and in the order given.
+.Bl -tag -width flag
+.It Fl c
+Makes all any symbols not in
+.Ar symlist
+local to this file.
+.It Fl t
+Restrict the symbol table to the symbols listed in
+.Ar symlist .
+.It Fl x Ar excludelist
+Exclude the symbols listed in
+.Ar excludelist
+from the symbol table.
+.It Fl m
+Exit with status zero, even if some symbols are missing.
+.El
+.Pp
+This program was specifically designed to cut down on the
+overhead of getting symbols from
+.Pa /kernel.
+.Sh DIAGNOSTICS
+The
+.Nm symorder
+utility exits 0 on success, 1 if a symbol
+listed in the
+.Ar symlist
+file was not found in the symbol
+table, and >1 if an error occurs.
+.Sh SEE ALSO
+.Xr nm 1 ,
+.Xr strip 1 ,
+.Xr nlist 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/usr.bin/symorder/symorder.c b/usr.bin/symorder/symorder.c
new file mode 100644
index 0000000..0686993
--- /dev/null
+++ b/usr.bin/symorder/symorder.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1980 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)symorder.c 5.8 (Berkeley) 4/1/91";
+#endif /* not lint */
+
+/*
+ * symorder - reorder symbol table
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <a.out.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SPACE 500
+
+#define OKEXIT 0
+#define NOTFOUNDEXIT 1
+#define ERREXIT 2
+
+char *exclude[SPACE];
+struct nlist order[SPACE];
+
+struct exec exec;
+struct stat stb;
+struct nlist *newtab, *symtab;
+off_t sa;
+int nexclude, nsym, strtabsize, symfound, symkept, small, missing, clean;
+char *kfile, *newstrings, *strings, asym[BUFSIZ];
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ register struct nlist *p, *symp;
+ register FILE *f, *xfile;
+ register int i;
+ register char *start, *t, *xfilename;
+ int ch, n, o;
+
+ xfilename = NULL;
+ while ((ch = getopt(argc, argv, "cmtx:")) != -1)
+ switch(ch) {
+ case 'c':
+ clean = 1;
+ break;
+ case 'm':
+ missing = 1;
+ break;
+ case 't':
+ small = 1;
+ break;
+ case 'x':
+ if (xfilename != NULL)
+ usage();
+ xfilename = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ if ((f = fopen(argv[0], "r")) == NULL)
+ error(argv[0]);
+
+ for (p = order; fgets(asym, sizeof(asym), f) != NULL;) {
+ for (t = asym; isspace(*t); ++t);
+ if (!*(start = t))
+ continue;
+ while (*++t);
+ if (*--t == '\n')
+ *t = '\0';
+ p->n_un.n_name = strdup(start);
+ ++p;
+ if (++nsym >= sizeof order / sizeof order[0])
+ break;
+ }
+ (void)fclose(f);
+
+ if (xfilename != NULL) {
+ if ((xfile = fopen(xfilename, "r")) == NULL)
+ error(xfilename);
+ for (; fgets(asym, sizeof(asym), xfile) != NULL;) {
+ for (t = asym; isspace(*t); ++t);
+ if (!*(start = t))
+ continue;
+ while (*++t);
+ if (*--t == '\n')
+ *t = '\0';
+ exclude[nexclude] = strdup(start);
+ if (++nexclude >= sizeof exclude / sizeof exclude[0])
+ break;
+ }
+ (void)fclose(xfile);
+ }
+
+ kfile = argv[1];
+ if ((f = fopen(kfile, "r")) == NULL)
+ error(kfile);
+ if ((o = open(kfile, O_WRONLY)) < 0)
+ error(kfile);
+
+ /* read exec header */
+ if ((fread(&exec, sizeof(exec), 1, f)) != 1)
+ badfmt("no exec header");
+ if (N_BADMAG(exec))
+ badfmt("bad magic number");
+ if (exec.a_syms == 0)
+ badfmt("stripped");
+ (void)fstat(fileno(f), &stb);
+ if (stb.st_size < N_STROFF(exec) + sizeof(off_t))
+ badfmt("no string table");
+
+ /* seek to and read the symbol table */
+ sa = N_SYMOFF(exec);
+ (void)fseek(f, sa, SEEK_SET);
+ n = exec.a_syms;
+ if (!(symtab = (struct nlist *)malloc(n)))
+ error(NULL);
+ if (fread((void *)symtab, 1, n, f) != n)
+ badfmt("corrupted symbol table");
+
+ /* read string table size and string table */
+ if (fread((void *)&strtabsize, sizeof(int), 1, f) != 1 ||
+ strtabsize <= 0)
+ badfmt("corrupted string table");
+ strings = malloc(strtabsize);
+ if (strings == NULL)
+ error(NULL);
+ /*
+ * Subtract four from strtabsize since strtabsize includes itself,
+ * and we've already read it.
+ */
+ if (fread(strings, 1, strtabsize - sizeof(int), f) !=
+ strtabsize - sizeof(int))
+ badfmt("corrupted string table");
+
+ i = n / sizeof(struct nlist);
+ if (!clean) {
+ newtab = (struct nlist *)malloc(n);
+ if (newtab == (struct nlist *)NULL)
+ error(NULL);
+ memset(newtab, 0, n);
+
+ reorder(symtab, newtab, i);
+ free((void *)symtab);
+ symtab = newtab;
+ } else {
+ symkept = i;
+ }
+
+ newstrings = malloc(strtabsize);
+ if (newstrings == NULL)
+ error(NULL);
+ t = newstrings;
+ for (symp = symtab; --i >= 0; symp++) {
+ if (symp->n_un.n_strx == 0)
+ continue;
+ if (inlist(symp) < 0) {
+ if (small)
+ continue;
+ if (clean && !savesymb(symp))
+ symp->n_type &= ~N_EXT;
+ } else if (clean)
+ symfound++;
+ symp->n_un.n_strx -= sizeof(int);
+ (void)strcpy(t, &strings[symp->n_un.n_strx]);
+ symp->n_un.n_strx = (t - newstrings) + sizeof(int);
+ t += strlen(t) + 1;
+ }
+
+ /* update shrunk sizes */
+ strtabsize = t - newstrings + sizeof(int);
+ n = symkept * sizeof(struct nlist);
+
+ /* fix exec sym size */
+ (void)lseek(o, (off_t)0, SEEK_SET);
+ exec.a_syms = n;
+ if (write(o, (void *)&exec, sizeof(exec)) != sizeof(exec))
+ error(kfile);
+
+ (void)lseek(o, sa, SEEK_SET);
+ if (write(o, (void *)symtab, n) != n)
+ error(kfile);
+ if (write(o, (void *)&strtabsize, sizeof(int)) != sizeof(int))
+ error(kfile);
+ if (write(o, newstrings, strtabsize - sizeof(int)) !=
+ strtabsize - sizeof(int))
+ error(kfile);
+
+ ftruncate(o, lseek(o, (off_t)0, SEEK_CUR));
+
+ if ((i = nsym - symfound) > 0) {
+ (void)printf("symorder: %d symbol%s not found:\n",
+ i, i == 1 ? "" : "s");
+ for (i = 0; i < nsym; i++)
+ if (order[i].n_value == 0)
+ printf("%s\n", order[i].n_un.n_name);
+ if (!missing)
+ exit(NOTFOUNDEXIT);
+ }
+ exit(OKEXIT);
+}
+
+savesymb(s)
+ register struct nlist *s;
+{
+ if ((s->n_type & N_EXT) != N_EXT)
+ return 0;
+ switch (s->n_type & N_TYPE) {
+ case N_TEXT:
+ case N_DATA:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+reorder(st1, st2, entries)
+ register struct nlist *st1, *st2;
+ int entries;
+{
+ register struct nlist *p;
+ register int i, n;
+
+ for (p = st1, n = entries; --n >= 0; ++p)
+ if (inlist(p) != -1)
+ ++symfound;
+ for (p = st2 + symfound, n = entries; --n >= 0; ++st1) {
+ if (excluded(st1))
+ continue;
+ i = inlist(st1);
+ if (i == -1)
+ *p++ = *st1;
+ else
+ st2[i] = *st1;
+ ++symkept;
+ }
+}
+
+inlist(p)
+ register struct nlist *p;
+{
+ register char *nam;
+ register struct nlist *op;
+
+ if (p->n_type & N_STAB || p->n_un.n_strx == 0)
+ return (-1);
+ if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
+ badfmt("corrupted symbol table");
+ nam = &strings[p->n_un.n_strx - sizeof(int)];
+ for (op = &order[nsym]; --op >= order; ) {
+ if (strcmp(op->n_un.n_name, nam) != 0)
+ continue;
+ op->n_value = 1;
+ return (op - order);
+ }
+ return (-1);
+}
+
+excluded(p)
+ register struct nlist *p;
+{
+ register char *nam;
+ register int x;
+
+ if (p->n_type & N_STAB || p->n_un.n_strx == 0)
+ return (0);
+ if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
+ badfmt("corrupted symbol table");
+ nam = &strings[p->n_un.n_strx - sizeof(int)];
+ for (x = nexclude; --x >= 0; )
+ if (strcmp(nam, exclude[x]) == 0)
+ return (1);
+ return (0);
+}
+
+badfmt(why)
+ char *why;
+{
+ (void)fprintf(stderr,
+ "symorder: %s: %s: %s\n", kfile, why, strerror(EFTYPE));
+ exit(ERREXIT);
+}
+
+error(n)
+ char *n;
+{
+ int sverr;
+
+ sverr = errno;
+ (void)fprintf(stderr, "symorder: ");
+ if (n)
+ (void)fprintf(stderr, "%s: ", n);
+ (void)fprintf(stderr, "%s\n", strerror(sverr));
+ exit(ERREXIT);
+}
+
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: symorder [-c] [-m] [-t] [-x excludelist] symlist file\n");
+ exit(ERREXIT);
+}
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
index 67e3624..eabc3ce 100644
--- a/usr.bin/systat/Makefile
+++ b/usr.bin/systat/Makefile
@@ -1,11 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= systat
-CFLAGS+=-I/sys -I${.CURDIR}/../vmstat
+CFLAGS+=-I${.CURDIR}/../../sys -I${.CURDIR}/../vmstat
SRCS= cmds.c cmdtab.c disks.c fetch.c iostat.c keyboard.c vmstat.c main.c \
mbufs.c netcmds.c netstat.c pigs.c swap.c
+DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM}
LDADD= -lcurses -ltermcap -lm -lkvm
-DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM}
BINGRP= kmem
BINMODE=2555
diff --git a/usr.bin/systat/cmds.c b/usr.bin/systat/cmds.c
index e374e3f..bbdb58e 100644
--- a/usr.bin/systat/cmds.c
+++ b/usr.bin/systat/cmds.c
@@ -32,7 +32,11 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/29/95";
+#endif
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <stdlib.h>
@@ -165,7 +169,7 @@ lookup(name)
nmatches++;
}
}
- if (nmatches != 1)
+ if (nmatches > 1)
return ((struct cmdtab *)-1);
return (found);
}
diff --git a/usr.bin/systat/disks.c b/usr.bin/systat/disks.c
index f412e30..f1ec4ab 100644
--- a/usr.bin/systat/disks.c
+++ b/usr.bin/systat/disks.c
@@ -35,8 +35,10 @@
static char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/buf.h>
+#include <sys/dkstat.h>
#include <nlist.h>
#include <ctype.h>
@@ -54,11 +56,17 @@ static struct nlist namelist[] = {
{ "_dk_ndrive" },
#define X_DK_WPMS 1
{ "_dk_wpms" },
-#ifdef vax
-#define X_MBDINIT (X_DK_WPMS+1)
- { "_mbdinit" },
-#define X_UBDINIT (X_DK_WPMS+2)
- { "_ubdinit" },
+#if defined(hp300) || defined(luna68k)
+#define X_HPDINIT (X_DK_WPMS+1)
+ { "_hp_dinit" },
+#endif
+#if defined(i386)
+#define X_DK_NAMES (X_DK_WPMS+1)
+ { "_dk_names" },
+#endif
+#ifdef mips
+#define X_SCSI_DINIT (X_DK_WPMS+1)
+ { "_scsi_dinit" },
#endif
#ifdef sun
#define X_MBDINIT (X_DK_WPMS+1)
@@ -68,13 +76,11 @@ static struct nlist namelist[] = {
#define X_VBDINIT (X_DK_WPMS+1)
{ "_vbdinit" },
#endif
-#if defined(hp300) || defined(luna68k)
-#define X_HPDINIT (X_DK_WPMS+1)
- { "_hp_dinit" },
-#endif
-#ifdef mips
-#define X_SCSI_DINIT (X_DK_WPMS+1)
- { "_scsi_dinit" },
+#ifdef vax
+#define X_MBDINIT (X_DK_WPMS+1)
+ { "_mbdinit" },
+#define X_UBDINIT (X_DK_WPMS+2)
+ { "_ubdinit" },
#endif
{ "" },
};
@@ -106,7 +112,7 @@ dkinit()
}
NREAD(X_DK_NDRIVE, &dk_ndrive, LONG);
if (dk_ndrive <= 0) {
- error("dk_ndrive=%d according to %s", dk_ndrive, _PATH_UNIX);
+ error("dk_ndrive=%d according to %s", dk_ndrive, getbootfile());
return(0);
}
dk_mspw = (float *)calloc(dk_ndrive, sizeof (float));
diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h
index 673278b..2e264f0 100644
--- a/usr.bin/systat/extern.h
+++ b/usr.bin/systat/extern.h
@@ -51,6 +51,7 @@ extern int *dk_select;
extern int CMDLINE;
extern int dk_ndrive;
extern int hz, stathz;
+extern double hertz; /* sampling frequency for cp_time and dk_time */
extern int naptime, col;
extern int nhosts;
extern int nports;
diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c
index 49b296c..ff69ac5 100644
--- a/usr.bin/systat/fetch.c
+++ b/usr.bin/systat/fetch.c
@@ -48,7 +48,7 @@ kvm_ckread(a, b, l)
if (verbose)
error("error reading kmem at %x\n", a);
return (0);
- }
+ }
else
return (1);
}
diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c
index b5412a5..33e9969 100644
--- a/usr.bin/systat/iostat.c
+++ b/usr.bin/systat/iostat.c
@@ -169,6 +169,7 @@ labeliostat()
mvwaddstr(wnd, row++, 0, "cpu user|");
mvwaddstr(wnd, row++, 0, " nice|");
mvwaddstr(wnd, row++, 0, " system|");
+ mvwaddstr(wnd, row++, 0, "interrupt|");
mvwaddstr(wnd, row++, 0, " idle|");
if (numbers)
row = numlabels(row + 1);
@@ -198,11 +199,11 @@ numlabels(row)
*/
if (linesperregion < 3)
linesperregion = 3;
- col = 0;
+ col = INSET;
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (col + COLWIDTH >= wnd->maxx - INSET) {
- col = 0, row += linesperregion + 1;
+ col = INSET, row += linesperregion + 1;
if (row > wnd->maxy - (linesperregion + 1))
break;
}
@@ -228,7 +229,7 @@ barlabels(row)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (row > wnd->maxy - linesperregion)
break;
- mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]);
+ mvwprintw(wnd, row++, 0, "%-4.4s bps|", dr_name[i]);
mvwaddstr(wnd, row++, 0, " tps|");
if (msps)
mvwaddstr(wnd, row++, 0, " msps|");
@@ -256,13 +257,9 @@ showiostat()
}
if (etime == 0.0)
etime = 1.0;
- etime /= (float) hz;
+ etime /= hertz;
row = 1;
-
- /*
- * Last CPU state not calculated yet.
- */
- for (i = 0; i < CPUSTATES - 1; i++)
+ for (i = 0; i < CPUSTATES; i++)
stat1(row++, i);
if (!numbers) {
row += 2;
@@ -274,15 +271,15 @@ showiostat()
}
return;
}
- col = 0;
+ col = INSET;
wmove(wnd, row + linesperregion, 0);
wdeleteln(wnd);
wmove(wnd, row + 3, 0);
winsertln(wnd);
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
- if (col + COLWIDTH >= wnd->maxx) {
- col = 0, row += linesperregion + 1;
+ if (col + COLWIDTH >= wnd->maxx - INSET) {
+ col = INSET, row += linesperregion + 1;
if (row > wnd->maxy - (linesperregion + 1))
break;
wmove(wnd, row + linesperregion, 0);
@@ -302,7 +299,7 @@ stats(row, col, dn)
double atime, words, xtime, itime;
atime = s.dk_time[dn];
- atime /= (float) hz;
+ atime /= hertz;
words = s.dk_wds[dn]*32.0; /* number of words transferred */
xtime = dk_mspw[dn]*words; /* transfer time */
itime = atime - xtime; /* time not transferring */
diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c
index f9f7672..78dd716 100644
--- a/usr.bin/systat/main.c
+++ b/usr.bin/systat/main.c
@@ -43,6 +43,7 @@ static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
#include <sys/param.h>
+#include <locale.h>
#include <nlist.h>
#include <signal.h>
#include <stdio.h>
@@ -66,6 +67,7 @@ int col;
int naptime = 5;
int verbose = 1; /* to report kvm read errs */
int hz, stathz;
+double hertz;
char c;
char *namp;
char hostname[MAXHOSTNAMELEN];
@@ -81,6 +83,8 @@ main(argc, argv)
{
char errbuf[80];
+ (void) setlocale(LC_TIME, "");
+
argc--, argv++;
while (argc > 0) {
if (argv[0][0] == '-') {
@@ -88,6 +92,11 @@ main(argc, argv)
p = lookup(&argv[0][1]);
if (p == (struct cmdtab *)-1) {
+ fprintf(stderr, "%s: ambiguous request\n",
+ &argv[0][1]);
+ exit(1);
+ }
+ if (p == (struct cmdtab *)0) {
fprintf(stderr, "%s: unknown request\n",
&argv[0][1]);
exit(1);
@@ -105,14 +114,6 @@ main(argc, argv)
error("%s", errbuf);
exit(1);
}
- if (kvm_nlist(kd, namelist)) {
- nlisterr(namelist);
- exit(1);
- }
- if (namelist[X_FIRST].n_type == 0) {
- fprintf(stderr, "couldn't read namelist.\n");
- exit(1);
- }
signal(SIGINT, die);
signal(SIGQUIT, die);
signal(SIGTERM, die);
@@ -135,9 +136,18 @@ main(argc, argv)
fprintf(stderr, "Couldn't set up load average window.\n");
die(0);
}
+ if (kvm_nlist(kd, namelist)) {
+ nlisterr(namelist);
+ exit(1);
+ }
+ if (namelist[X_FIRST].n_type == 0) {
+ fprintf(stderr, "couldn't read namelist.\n");
+ exit(1);
+ }
gethostname(hostname, sizeof (hostname));
NREAD(X_HZ, &hz, LONG);
NREAD(X_STATHZ, &stathz, LONG);
+ hertz = stathz ? stathz : hz;
(*curcmd->c_init)();
curcmd->c_flags |= CF_INIT;
labels();
diff --git a/usr.bin/systat/mbufs.c b/usr.bin/systat/mbufs.c
index 4b5ca66..8ee325f 100644
--- a/usr.bin/systat/mbufs.c
+++ b/usr.bin/systat/mbufs.c
@@ -33,15 +33,17 @@
#ifndef lint
static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93";
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mbuf.h>
+#include <sys/sysctl.h>
#include <stdlib.h>
#include <string.h>
-#include <nlist.h>
#include <paths.h>
#include "systat.h"
#include "extern.h"
@@ -101,12 +103,15 @@ showmbufs()
if (mb == 0)
return;
for (j = 0; j < wnd->maxy; j++) {
- max = 0, index = -1;
- for (i = 0; i < wnd->maxy; i++)
+ max = 0, index = -1;
+ for (i = 0; i < wnd->maxy; i++) {
+ if (i == MT_FREE)
+ continue;
if (mb->m_mtypes[i] > max) {
max = mb->m_mtypes[i];
index = i;
}
+ }
if (max == 0)
break;
if (j > NNAMES)
@@ -120,44 +125,62 @@ showmbufs()
while (max--)
waddch(wnd, 'X');
waddstr(wnd, buf);
- } else {
+ } else
while (max--)
waddch(wnd, 'X');
- wclrtoeol(wnd);
- }
+ wclrtoeol(wnd);
+ mb->m_mbufs -= mb->m_mtypes[index];
mb->m_mtypes[index] = 0;
}
+ if (mb->m_mbufs) {
+ mvwprintw(wnd, 1+j, 0, "%-10.10s", "free");
+ if (mb->m_mbufs > 60) {
+ sprintf(buf, " %d", mb->m_mbufs);
+ mb->m_mbufs = 60;
+ while (mb->m_mbufs--)
+ waddch(wnd, 'X');
+ waddstr(wnd, buf);
+ } else {
+ while(mb->m_mbufs--)
+ waddch(wnd, 'X');
+ }
+ wclrtoeol(wnd);
+ j++;
+ }
wmove(wnd, 1+j, 0); wclrtobot(wnd);
}
-static struct nlist namelist[] = {
-#define X_MBSTAT 0
- { "_mbstat" },
- { "" }
-};
-
int
initmbufs()
{
- if (namelist[X_MBSTAT].n_type == 0) {
- if (kvm_nlist(kd, namelist)) {
- nlisterr(namelist);
- return(0);
- }
- if (namelist[X_MBSTAT].n_type == 0) {
- error("namelist on %s failed", _PATH_UNIX);
- return(0);
- }
+ size_t len;
+ int name[3];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_IPC;
+ name[2] = KIPC_MBSTAT;
+ len = 0;
+ if (sysctl(name, 3, 0, &len, 0, 0) < 0) {
+ error("sysctl getting mbstat size failed");
+ return 0;
}
+
if (mb == 0)
- mb = (struct mbstat *)calloc(1, sizeof (*mb));
- return(1);
+ mb = (struct mbstat *)calloc(1, sizeof *mb);
+ return 1;
}
void
fetchmbufs()
{
- if (namelist[X_MBSTAT].n_type == 0)
+ int name[3];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_IPC;
+ name[2] = KIPC_MBSTAT;
+ len = sizeof *mb;
+
+ if (sysctl(name, 3, mb, &len, 0, 0) < 0)
return;
- NREAD(X_MBSTAT, mb, sizeof (*mb));
}
diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c
index 3790c2a..94dc3ca 100644
--- a/usr.bin/systat/netcmds.c
+++ b/usr.bin/systat/netcmds.c
@@ -32,16 +32,20 @@
*/
#ifndef lint
+/*
static char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93";
+*/
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
/*
* Common network command support routines.
*/
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <net/route.h>
diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c
index 0303bf5..b8be493 100644
--- a/usr.bin/systat/netstat.c
+++ b/usr.bin/systat/netstat.c
@@ -32,16 +32,20 @@
*/
#ifndef lint
+/*
static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
+*/
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
/*
* netstat
*/
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <netinet/in.h>
@@ -164,6 +168,7 @@ fetchnetstat()
{
register struct inpcb *prev, *next;
register struct netinfo *p;
+ struct inpcbhead head;
struct inpcb inpcb;
struct socket sockb;
struct tcpcb tcpcb;
@@ -175,11 +180,11 @@ fetchnetstat()
for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw)
p->ni_seen = 0;
if (protos&TCP) {
- off = NPTR(X_TCB);
+ off = NPTR(X_TCB);
istcp = 1;
}
else if (protos&UDP) {
- off = NPTR(X_UDB);
+ off = NPTR(X_UDB);
istcp = 0;
}
else {
@@ -187,18 +192,9 @@ fetchnetstat()
return;
}
again:
- KREAD(off, &inpcb, sizeof (struct inpcb));
- prev = off;
- for (; inpcb.inp_next != off; prev = next) {
- next = inpcb.inp_next;
+ KREAD(off, &head, sizeof (struct inpcbhead));
+ for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) {
KREAD(next, &inpcb, sizeof (inpcb));
- if (inpcb.inp_prev != prev) {
- p = netcb.ni_forw;
- for (; p != (struct netinfo *)&netcb; p = p->ni_forw)
- p->ni_seen = 1;
- error("Kernel state in transition");
- return;
- }
if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
continue;
if (nhosts && !checkhost(&inpcb))
@@ -288,7 +284,7 @@ labelnetstat()
mvwaddstr(wnd, 0, PROTO, "Proto");
mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
mvwaddstr(wnd, 0, SNDCC, "Send-Q");
- mvwaddstr(wnd, 0, STATE, "(state)");
+ mvwaddstr(wnd, 0, STATE, "(state)");
}
void
@@ -388,13 +384,13 @@ inetprint(in, port, proto)
cp = index(line, '\0');
while (cp - line < 22)
*cp++ = ' ';
- *cp = '\0';
+ line[22] = '\0';
waddstr(wnd, line);
}
/*
* Construct an Internet address representation.
- * If the nflag has been supplied, give
+ * If the nflag has been supplied, give
* numeric value, otherwise try for symbolic name.
*/
static char *
diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c
index 4c49494..fc12e51 100644
--- a/usr.bin/systat/pigs.c
+++ b/usr.bin/systat/pigs.c
@@ -41,9 +41,9 @@ static char sccsid[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93";
#include <sys/param.h>
#include <sys/dkstat.h>
-#include <sys/dir.h>
#include <sys/time.h>
#include <sys/proc.h>
+#include <sys/user.h>
#include <sys/sysctl.h>
#include <curses.h>
@@ -209,7 +209,7 @@ fetchpigs()
if (time == 0 || (pp->p_flag & P_INMEM) == 0)
*pctp = 0;
else
- *pctp = ((double) pp->p_pctcpu /
+ *pctp = ((double) pp->p_pctcpu /
fscale) / (1.0 - exp(time * lccpu));
}
/*
diff --git a/usr.bin/systat/swap.c b/usr.bin/systat/swap.c
index 4cefbd0..3c27e1c 100644
--- a/usr.bin/systat/swap.c
+++ b/usr.bin/systat/swap.c
@@ -32,7 +32,11 @@
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95";
+#endif
+static const char rcsid[] =
+ "$Id$";
#endif /* not lint */
/*
@@ -43,8 +47,8 @@ static char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95";
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/ioctl.h>
-#include <sys/map.h>
#include <sys/stat.h>
+#include <sys/rlist.h>
#include <kvm.h>
#include <nlist.h>
@@ -61,37 +65,34 @@ void showspace __P((char *header, int hlen, long blocksize));
kvm_t *kd;
struct nlist syms[] = {
- { "_swapmap" }, /* list of free swap areas */
-#define VM_SWAPMAP 0
- { "_nswapmap" },/* size of the swap map */
-#define VM_NSWAPMAP 1
+ { "_swaplist" },/* list of free swap areas */
+#define VM_SWAPLIST 0
{ "_swdevt" }, /* list of swap devices and sizes */
-#define VM_SWDEVT 2
+#define VM_SWDEVT 1
{ "_nswap" }, /* size of largest swap device */
-#define VM_NSWAP 3
+#define VM_NSWAP 2
{ "_nswdev" }, /* number of swap devices */
-#define VM_NSWDEV 4
+#define VM_NSWDEV 3
{ "_dmmax" }, /* maximum size of a swap block */
-#define VM_DMMAX 5
+#define VM_DMMAX 4
0
};
-static int nswap, nswdev, dmmax, nswapmap;
+static int nswap, nswdev, dmmax;
static struct swdevt *sw;
static long *perdev, blocksize;
-static struct map *swapmap, *kswapmap;
-static struct mapent *mp;
static int nfree, hlen;
+static struct rlisthdr swaplist;
#define SVAR(var) __STRING(var) /* to force expansion */
#define KGET(idx, var) \
- KGET1(idx, &var, sizeof(var), SVAR(var))
-#define KGET1(idx, p, s, msg) \
- KGET2(syms[idx].n_value, p, s, msg)
-#define KGET2(addr, p, s, msg) \
+ KGET1(idx, &var, sizeof(var), SVAR(var), (0))
+#define KGET1(idx, p, s, msg, rv) \
+ KGET2(syms[idx].n_value, p, s, msg, rv)
+#define KGET2(addr, p, s, msg, rv) \
if (kvm_read(kd, addr, p, s) != s) { \
error("cannot read %s: %s", msg, kvm_geterr(kd)); \
- return (0); \
+ return rv; \
}
WINDOW *
@@ -111,11 +112,18 @@ closeswap(w)
delwin(w);
}
+/*
+ * The meat of all the swap stuff is stolen from pstat(8)'s
+ * swapmode(), which is based on a program called swapinfo written by
+ * Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+
initswap()
{
int i;
char msgbuf[BUFSIZ];
static int once = 0;
+ u_long ptr;
if (once)
return (1);
@@ -133,15 +141,11 @@ initswap()
KGET(VM_NSWAP, nswap);
KGET(VM_NSWDEV, nswdev);
KGET(VM_DMMAX, dmmax);
- KGET(VM_NSWAPMAP, nswapmap);
- KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */
if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
- (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
- (mp = malloc(nswapmap * sizeof(*mp))) == NULL) {
- error("swap malloc");
- return (0);
- }
- KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
+ (perdev = malloc(nswdev * sizeof(*perdev))) == NULL)
+ err(1, "malloc");
+ KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt", (0));
+ KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt", (0));
once = 1;
return (1);
}
@@ -149,50 +153,49 @@ initswap()
void
fetchswap()
{
- int s, e, i;
+ struct rlist head;
+ struct rlist *swapptr;
- s = nswapmap * sizeof(*mp);
- if (kvm_read(kd, (long)kswapmap, mp, s) != s)
- error("cannot read swapmap: %s", kvm_geterr(kd));
+ /* Count up swap space. */
+ nfree = 0;
+ memset(perdev, 0, nswdev * sizeof(*perdev));
+ KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist", /* none */);
+ swapptr = swaplist.rlh_list;
+ while (swapptr) {
+ int top, bottom, next_block;
- /* first entry in map is `struct map'; rest are mapent's */
- swapmap = (struct map *)mp;
- if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
- error("panic: swap: nswapmap goof");
+ KGET2((unsigned long)swapptr, &head,
+ sizeof(struct rlist), "swapptr", /* none */);
- /*
- * Count up swap space.
- */
- nfree = 0;
- bzero(perdev, nswdev * sizeof(*perdev));
- for (mp++; mp->m_addr != 0; mp++) {
- s = mp->m_addr; /* start of swap region */
- e = mp->m_addr + mp->m_size; /* end of region */
- nfree += mp->m_size;
+ top = head.rl_end;
+ bottom = head.rl_start;
+
+ nfree += top - bottom + 1;
/*
* Swap space is split up among the configured disks.
- * The first dmmax blocks of swap space some from the
- * first disk, the next dmmax blocks from the next,
- * and so on. The list of free space joins adjacent
- * free blocks, ignoring device boundries. If we want
- * to keep track of this information per device, we'll
- * just have to extract it ourselves.
+ *
+ * For interleaved swap devices, the first dmmax blocks
+ * of swap space some from the first disk, the next dmmax
+ * blocks from the next, and so on up to nswap blocks.
+ *
+ * The list of free space joins adjacent free blocks,
+ * ignoring device boundries. If we want to keep track
+ * of this information per device, we'll just have to
+ * extract it ourselves.
*/
-
- /* calculate first device on which this falls */
- i = (s / dmmax) % nswdev;
- while (s < e) { /* XXX this is inefficient */
- int bound = roundup(s + 1, dmmax);
-
- if (bound > e)
- bound = e;
- perdev[i] += bound - s;
- if (++i >= nswdev)
- i = 0;
- s = bound;
+ while (top / dmmax != bottom / dmmax) {
+ next_block = ((bottom + dmmax) / dmmax);
+ perdev[(bottom / dmmax) % nswdev] +=
+ next_block * dmmax - bottom;
+ bottom = next_block * dmmax;
}
+ perdev[(bottom / dmmax) % nswdev] +=
+ top - bottom + 1;
+
+ swapptr = head.rl_next;
}
+
}
void
@@ -204,36 +207,43 @@ labelswap()
row = 0;
wmove(wnd, row, 0); wclrtobot(wnd);
header = getbsize(&hlen, &blocksize);
- mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s",
+ mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s",
"Disk", hlen, header, "Used",
- "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100%");
+ "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100");
for (i = 0; i < nswdev; i++) {
+ if (!sw[i].sw_freed)
+ continue;
p = devname(sw[i].sw_dev, S_IFBLK);
- mvwprintw(wnd, i + 1, 0, "%-5s", p == NULL ? "??" : p);
+ mvwprintw(wnd, i + 1, 0, "%-5s",
+ sw[i].sw_dev == NODEV ? "[NFS]" :
+ p == NULL ? "??" : p);
}
}
void
showswap()
{
- int col, row, div, i, j, avail, npfree, used, xsize, xfree;
+ int col, row, div, i, j, k, avail, npfree, used, xsize, xfree;
div = blocksize / 512;
avail = npfree = 0;
- for (i = 0; i < nswdev; i++) {
- col = 5;
- mvwprintw(wnd, i + 1, col, "%*d", hlen, sw[i].sw_nblks / div);
- col += hlen;
+ for (i = k = 0; i < nswdev; i++) {
/*
* Don't report statistics for partitions which have not
* yet been activated via swapon(8).
*/
- if (!sw[i].sw_freed) {
- mvwprintw(wnd, i + 1, col + 8,
- "0 *** not available for swapping ***");
+ if (!sw[i].sw_freed)
continue;
- }
- xsize = sw[i].sw_nblks;
+
+ col = 5;
+ mvwprintw(wnd, i + 1, col, "%*d", hlen, sw[i].sw_nblks / div);
+ col += hlen;
+
+ /*
+ * The first dmmax is never allocated to avoid trashing of
+ * disklabels
+ */
+ xsize = sw[i].sw_nblks - dmmax;
xfree = perdev[i];
used = xsize - xfree;
mvwprintw(wnd, i + 1, col, "%9d ", used / div);
@@ -241,14 +251,15 @@ showswap()
waddch(wnd, 'X');
npfree++;
avail += xsize;
+ k++;
}
- /*
+ /*
* If only one partition has been set up via swapon(8), we don't
* need to bother with totals.
*/
if (npfree > 1) {
used = avail - nfree;
- mvwprintw(wnd, i + 1, 0, "%-5s%*d%9d ",
+ mvwprintw(wnd, k + 1, 0, "%-5s%*d%9d ",
"Total", hlen, avail / div, used / div);
for (j = (100 * used / avail + 1) / 2; j > 0; j--)
waddch(wnd, 'X');
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
index 3b9a5d9..a487024 100644
--- a/usr.bin/systat/systat.1
+++ b/usr.bin/systat/systat.1
@@ -62,9 +62,9 @@ displays the processes getting the largest percentage of the processor
in the lower window. Other displays show swap space usage, disk
.Tn I/O
statistics (a la
-.Xr iostat 1 ) ,
+.Xr iostat 8 ) ,
virtual memory statistics (a la
-.Xr vmstat 1 ) ,
+.Xr vmstat 8 ) ,
network ``mbuf'' utilization, and network connections (a la
.Xr netstat 1 ) .
.Pp
@@ -158,7 +158,8 @@ Display, in the lower window, statistics about processor use
and disk throughput. Statistics on processor use appear as
bar graphs of the amount of time executing in user mode (``user''),
in user mode running low priority processes (``nice''), in
-system mode (``system''), and idle (``idle''). Statistics
+system mode (``system''), in interrupt mode (``interrupt''),
+and idle (``idle''). Statistics
on disk throughput show, for each drive, kilobytes of data transferred,
number of disk transactions performed, and average seek time
(in milliseconds). This information may be displayed as
@@ -223,30 +224,32 @@ needed if all processes had all of their pages.
Finally the last column shows the number of physical pages
on the free list.
.Pp
-Below the memory display is the disk usage display.
-It reports the number of seeks, transfers, and number
-of kilobyte blocks transferred per second averaged over the
-refresh period of the display (by default, five seconds).
-For some disks it also reports the average milliseconds per seek.
-Note that the system only keeps statistics on at most four disks.
-.Pp
-Below the disk display is a list of the
+Below the memory display is a list of the
average number of processes (over the last refresh interval)
that are runnable (`r'), in page wait (`p'),
in disk wait other than paging (`d'),
sleeping (`s'), and swapped out but desiring to run (`w').
Below the queue length listing is a numerical listing and
a bar graph showing the amount of
-system (shown as `='), user (shown as `>'),
+system (shown as `='), interrupt (shown as `+'), user (shown as `>'),
nice (shown as `-'), and idle time (shown as ` ').
.Pp
-At the bottom left are statistics on name translations.
+Below the process display are statistics on name translations.
It lists the number of names translated in the previous interval,
the number and percentage of the translations that were
handled by the system wide name translation cache, and
the number and percentage of the translations that were
handled by the per process name translation cache.
.Pp
+At the bottom left is the disk usage display.
+It reports the number of seeks, transfers, and number
+of kilobyte blocks transferred per second averaged over the
+refresh period of the display (by default, five seconds).
+For some disks it also reports the average milliseconds per seek.
+Note that the system only keeps statistics on at most eight disks
+(this is controlled by the constant DK_NDRIVE in /sys/dkstat.h as
+a kernel compile-time constant).
+.Pp
Under the date in the upper right hand quadrant are statistics
on paging and swapping activity.
The first two columns report the average number of pages
@@ -396,7 +399,7 @@ may be specified, separated by spaces.
.El
.Sh FILES
.Bl -tag -width /etc/networks -compact
-.It Pa /vmunix
+.It Pa /kernel
For the namelist.
.It Pa /dev/kmem
For information in main memory.
diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c
index 3558c50..1436234 100644
--- a/usr.bin/systat/vmstat.c
+++ b/usr.bin/systat/vmstat.c
@@ -44,11 +44,13 @@ static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
#include <sys/buf.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/user.h>
#include <sys/proc.h>
+#include <sys/uio.h>
#include <sys/namei.h>
#include <sys/sysctl.h>
-#include <vm/vm.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm_param.h>
#include <signal.h>
#include <nlist.h>
@@ -57,6 +59,7 @@ static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
#include <paths.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
#include <unistd.h>
#include "systat.h"
#include "extern.h"
@@ -73,6 +76,7 @@ static struct Info {
struct nchstats nchstats;
long nchcount;
long *intrcnt;
+ int bufspace;
} s, s1, s2, z;
#define cnt s.Cnt
@@ -96,7 +100,6 @@ static int ut;
static char buf[26];
static time_t t;
static double etime;
-static float hertz;
static int nintr;
static long *intrloc;
static char **intrname;
@@ -133,8 +136,8 @@ static struct nlist namelist[] = {
{ "_cp_time" },
#define X_CNT 1
{ "_cnt" },
-#define X_TOTAL 2
- { "_total" },
+#define X_BUFFERSPACE 2
+ { "_bufspace" },
#define X_DK_BUSY 3
{ "_dk_busy" },
#define X_DK_TIME 4
@@ -166,14 +169,14 @@ static struct nlist namelist[] = {
#define MEMROW 2 /* uses 4 rows and 31 cols */
#define MEMCOL 0
#define PAGEROW 2 /* uses 4 rows and 26 cols */
-#define PAGECOL 36
-#define INTSROW 2 /* uses all rows to bottom and 17 cols */
-#define INTSCOL 63
+#define PAGECOL 46
+#define INTSROW 6 /* uses all rows to bottom and 17 cols */
+#define INTSCOL 61
#define PROCSROW 7 /* uses 2 rows and 20 cols */
#define PROCSCOL 0
#define GENSTATROW 7 /* uses 2 rows and 30 cols */
#define GENSTATCOL 20
-#define VMSTATROW 7 /* uses 17 rows and 12 cols */
+#define VMSTATROW 6 /* uses 17 rows and 12 cols */
#define VMSTATCOL 48
#define GRAPHROW 10 /* uses 3 rows and 51 cols */
#define GRAPHCOL 0
@@ -207,7 +210,6 @@ initkre()
return(0);
}
}
- hertz = stathz ? stathz : hz;
if (! dkinit())
return(0);
if (dk_ndrive && !once) {
@@ -262,9 +264,11 @@ void
fetchkre()
{
time_t now;
+ struct tm *tp;
time(&now);
- strcpy(buf, ctime(&now));
+ tp = localtime(&now);
+ (void) strftime(buf, sizeof(buf), "%c", tp);
buf[16] = '\0';
getinfo(&s, state);
}
@@ -276,15 +280,15 @@ labelkre()
clear();
mvprintw(STATROW, STATCOL + 4, "users Load");
- mvprintw(MEMROW, MEMCOL, "Mem:KB REAL VIRTUAL");
- mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share");
+ mvprintw(MEMROW, MEMCOL, "Mem:KB REAL VIRTUAL");
+ mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share");
mvprintw(MEMROW + 2, MEMCOL, "Act");
mvprintw(MEMROW + 3, MEMCOL, "All");
- mvprintw(MEMROW + 1, MEMCOL + 31, "Free");
+ mvprintw(MEMROW + 1, MEMCOL + 41, "Free");
- mvprintw(PAGEROW, PAGECOL, " PAGING SWAPPING ");
- mvprintw(PAGEROW + 1, PAGECOL, " in out in out ");
+ mvprintw(PAGEROW, PAGECOL, " VN PAGER SWAP PAGER ");
+ mvprintw(PAGEROW + 1, PAGECOL, " in out in out ");
mvprintw(PAGEROW + 2, PAGECOL, "count");
mvprintw(PAGEROW + 3, PAGECOL, "pages");
@@ -292,35 +296,31 @@ labelkre()
mvprintw(INTSROW + 1, INTSCOL + 9, "total");
mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "cow");
- mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "objlk");
- mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "objht");
- mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "zfod");
- mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "nzfod");
- mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "%%zfod");
- mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "kern");
- mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "wire");
- mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "act");
- mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "inact");
- mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "free");
- mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "daefr");
- mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "prcfr");
- mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "react");
- mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "scan");
- mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "hdrev");
- if (LINES - 1 > VMSTATROW + 16)
- mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "intrn");
+ mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "zfod");
+ mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "wire");
+ mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "act");
+ mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "inact");
+ mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "cache");
+ mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "free");
+ mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "daefr");
+ mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "prcfr");
+ mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "react");
+ mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "pdwake");
+ mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "pdpgs");
+ mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "intrn");
+ mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "buf");
mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt");
mvprintw(GRAPHROW, GRAPHCOL,
- " . %% Sys . %% User . %% Nice . %% Idle");
+ " . %%Sys . %%Intr . %%User . %%Nice . %%Idle");
mvprintw(PROCSROW, PROCSCOL, "Proc:r p d s w");
mvprintw(GRAPHROW + 1, GRAPHCOL,
"| | | | | | | | | | |");
- mvprintw(NAMEIROW, NAMEICOL, "Namei Sys-cache Proc-cache");
+ mvprintw(NAMEIROW, NAMEICOL, "Namei Name-cache Dir-cache");
mvprintw(NAMEIROW + 1, NAMEICOL,
- " Calls hits %% hits %%");
+ " Calls hits %% hits %%");
mvprintw(DISKROW, DISKCOL, "Discs");
mvprintw(DISKROW + 1, DISKCOL, "seeks");
mvprintw(DISKROW + 2, DISKCOL, "xfers");
@@ -330,13 +330,13 @@ labelkre()
for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++)
if (dk_select[i]) {
mvprintw(DISKROW, DISKCOL + 5 + 5 * j,
- " %3.3s", dr_name[j]);
+ " %4.4s", dr_name[j]);
j++;
}
for (i = 0; i < nintr; i++) {
if (intrloc[i] == 0)
continue;
- mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", intrname[i]);
+ mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s", intrname[i]);
}
}
@@ -349,8 +349,9 @@ labelkre()
putint((int)((float)s.fld/etime + 0.5), l, c, w)
#define MAXFAIL 5
-static char cpuchar[CPUSTATES] = { '=' , '>', '-', ' ' };
-static char cpuorder[CPUSTATES] = { CP_SYS, CP_USER, CP_NICE, CP_IDLE };
+static char cpuchar[CPUSTATES] = { '=' , '+', '>', '-', ' ' };
+static char cpuorder[CPUSTATES] = { CP_SYS, CP_INTR, CP_USER, CP_NICE,
+ CP_IDLE };
void
showkre()
@@ -391,38 +392,32 @@ showkre()
if (nextintsrow == LINES)
continue;
intrloc[i] = nextintsrow++;
- mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s",
+ mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s",
intrname[i]);
}
X(intrcnt);
l = (int)((float)s.intrcnt[i]/etime + 0.5);
inttotal += l;
- putint(l, intrloc[i], INTSCOL, 8);
+ putint(l, intrloc[i], INTSCOL + 2, 6);
}
- putint(inttotal, INTSROW + 1, INTSCOL, 8);
+ putint(inttotal, INTSROW + 1, INTSCOL + 2, 6);
Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
- Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes);
+ Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); Z(ncs_neghits);
s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
- nchtotal.ncs_miss + nchtotal.ncs_long;
+ nchtotal.ncs_miss + nchtotal.ncs_long + nchtotal.ncs_neghits;
if (state == TIME)
s1.nchcount = s.nchcount;
psiz = 0;
f2 = 0.0;
-
- /*
- * Last CPU state not calculated yet.
- */
- for (c = 0; c < CPUSTATES - 1; c++) {
+ for (c = 0; c < CPUSTATES; c++) {
i = cpuorder[c];
f1 = cputime(i);
f2 += f1;
l = (int) ((f2 + 1.0) / 2.0) - psiz;
- if (c == 0)
- putfloat(f1, GRAPHROW, GRAPHCOL + 1, 5, 1, 0);
- else
- putfloat(f1, GRAPHROW, GRAPHCOL + 12 * c,
- 5, 1, 0);
+ if (f1 > 99.9)
+ f1 = 99.9; /* no room to display 100.0 */
+ putfloat(f1, GRAPHROW, GRAPHCOL + 10 * c, 4, 1, 0);
move(GRAPHROW + 2, psiz);
psiz += l;
while (l-- > 0)
@@ -435,68 +430,65 @@ showkre()
putfloat(avenrun[2], STATROW, STATCOL + 29, 6, 2, 0);
mvaddstr(STATROW, STATCOL + 53, buf);
#define pgtokb(pg) ((pg) * cnt.v_page_size / 1024)
- putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 3, 6);
- putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 9, 6);
- putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 15, 7);
- putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 22, 7);
- putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 3, 6);
- putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 9, 6);
- putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 15, 7);
- putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 22, 7);
- putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 29, 6);
+ putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 3, 8);
+ putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 11, 8);
+ putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 19, 9);
+ putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 28, 9);
+ putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 3, 8);
+ putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 11, 8);
+ putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 19, 9);
+ putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 28, 9);
+ putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 37, 8);
putint(total.t_rq - 1, PROCSROW + 1, PROCSCOL + 3, 3);
putint(total.t_pw, PROCSROW + 1, PROCSCOL + 6, 3);
putint(total.t_dw, PROCSROW + 1, PROCSCOL + 9, 3);
putint(total.t_sl, PROCSROW + 1, PROCSCOL + 12, 3);
putint(total.t_sw, PROCSROW + 1, PROCSCOL + 15, 3);
PUTRATE(Cnt.v_cow_faults, VMSTATROW + 0, VMSTATCOL + 3, 6);
- PUTRATE(Cnt.v_lookups, VMSTATROW + 1, VMSTATCOL + 3, 6);
- PUTRATE(Cnt.v_hits, VMSTATROW + 2, VMSTATCOL + 3, 6);
- PUTRATE(Cnt.v_zfod, VMSTATROW + 3, VMSTATCOL + 4, 5);
- PUTRATE(Cnt.v_nzfod, VMSTATROW + 4, VMSTATCOL + 3, 6);
- putfloat(cnt.v_nzfod == 0 ? 0.0 : (100.0 * cnt.v_zfod / cnt.v_nzfod),
- VMSTATROW + 5, VMSTATCOL + 2, 7, 2, 1);
- putint(pgtokb(cnt.v_kernel_pages), VMSTATROW + 6, VMSTATCOL, 9);
- putint(pgtokb(cnt.v_wire_count), VMSTATROW + 7, VMSTATCOL, 9);
- putint(pgtokb(cnt.v_active_count), VMSTATROW + 8, VMSTATCOL, 9);
- putint(pgtokb(cnt.v_inactive_count), VMSTATROW + 9, VMSTATCOL, 9);
- putint(pgtokb(cnt.v_free_count), VMSTATROW + 10, VMSTATCOL, 9);
- PUTRATE(Cnt.v_dfree, VMSTATROW + 11, VMSTATCOL, 9);
- PUTRATE(Cnt.v_pfree, VMSTATROW + 12, VMSTATCOL, 9);
- PUTRATE(Cnt.v_reactivated, VMSTATROW + 13, VMSTATCOL, 9);
- PUTRATE(Cnt.v_scan, VMSTATROW + 14, VMSTATCOL, 9);
- PUTRATE(Cnt.v_rev, VMSTATROW + 15, VMSTATCOL, 9);
- if (LINES - 1 > VMSTATROW + 16)
- PUTRATE(Cnt.v_intrans, VMSTATROW + 16, VMSTATCOL, 9);
- PUTRATE(Cnt.v_pageins, PAGEROW + 2, PAGECOL + 5, 5);
- PUTRATE(Cnt.v_pageouts, PAGEROW + 2, PAGECOL + 10, 5);
- PUTRATE(Cnt.v_swpin, PAGEROW + 2, PAGECOL + 15, 5); /* - */
- PUTRATE(Cnt.v_swpout, PAGEROW + 2, PAGECOL + 20, 5); /* - */
- PUTRATE(Cnt.v_pgpgin, PAGEROW + 3, PAGECOL + 5, 5); /* ? */
- PUTRATE(Cnt.v_pgpgout, PAGEROW + 3, PAGECOL + 10, 5); /* ? */
- PUTRATE(Cnt.v_pswpin, PAGEROW + 3, PAGECOL + 15, 5); /* - */
- PUTRATE(Cnt.v_pswpout, PAGEROW + 3, PAGECOL + 20, 5); /* - */
+ PUTRATE(Cnt.v_zfod, VMSTATROW + 1, VMSTATCOL + 4, 5);
+ putint(pgtokb(cnt.v_wire_count), VMSTATROW + 2, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_active_count), VMSTATROW + 3, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_inactive_count), VMSTATROW + 4, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_cache_count), VMSTATROW + 5, VMSTATCOL, 9);
+ putint(pgtokb(cnt.v_free_count), VMSTATROW + 6, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_dfree, VMSTATROW + 7, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_pfree, VMSTATROW + 8, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_reactivated, VMSTATROW + 9, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_pdwakeups, VMSTATROW + 10, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_pdpages, VMSTATROW + 11, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_intrans, VMSTATROW + 12, VMSTATCOL, 9);
+ putint(s.bufspace/1024, VMSTATROW + 13, VMSTATCOL, 9);
+ PUTRATE(Cnt.v_vnodein, PAGEROW + 2, PAGECOL + 5, 5);
+ PUTRATE(Cnt.v_vnodeout, PAGEROW + 2, PAGECOL + 10, 5);
+ PUTRATE(Cnt.v_swapin, PAGEROW + 2, PAGECOL + 17, 5);
+ PUTRATE(Cnt.v_swapout, PAGEROW + 2, PAGECOL + 22, 5);
+ PUTRATE(Cnt.v_vnodepgsin, PAGEROW + 3, PAGECOL + 5, 5);
+ PUTRATE(Cnt.v_vnodepgsout, PAGEROW + 3, PAGECOL + 10, 5);
+ PUTRATE(Cnt.v_swappgsin, PAGEROW + 3, PAGECOL + 17, 5);
+ PUTRATE(Cnt.v_swappgsout, PAGEROW + 3, PAGECOL + 22, 5);
PUTRATE(Cnt.v_swtch, GENSTATROW + 1, GENSTATCOL, 5);
PUTRATE(Cnt.v_trap, GENSTATROW + 1, GENSTATCOL + 5, 5);
PUTRATE(Cnt.v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 5);
PUTRATE(Cnt.v_intr, GENSTATROW + 1, GENSTATCOL + 15, 5);
PUTRATE(Cnt.v_soft, GENSTATROW + 1, GENSTATCOL + 20, 5);
- PUTRATE(Cnt.v_faults, GENSTATROW + 1, GENSTATCOL + 25, 5);
+ PUTRATE(Cnt.v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 5);
mvprintw(DISKROW, DISKCOL + 5, " ");
for (i = 0, c = 0; i < dk_ndrive && c < MAXDRIVES; i++)
if (dk_select[i]) {
mvprintw(DISKROW, DISKCOL + 5 + 5 * c,
- " %3.3s", dr_name[i]);
+ " %4.4s", dr_name[i]);
dinfo(i, ++c);
}
putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
- putint(nchtotal.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 9, 9);
+ putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits),
+ NAMEIROW + 2, NAMEICOL + 9, 9);
#define nz(x) ((x) ? (x) : 1)
- putfloat(nchtotal.ncs_goodhits * 100.0 / nz(s.nchcount),
+ putfloat((nchtotal.ncs_goodhits+nchtotal.ncs_neghits) *
+ 100.0 / nz(s.nchcount),
NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1);
putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 23, 9);
putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount),
- NAMEIROW + 2, NAMEICOL + 34, 4, 0, 1);
+ NAMEIROW + 2, NAMEICOL + 33, 4, 0, 1);
#undef nz
}
@@ -611,6 +603,7 @@ getinfo(s, st)
NREAD(X_CPTIME, s->time, sizeof s->time);
NREAD(X_CNT, &s->Cnt, sizeof s->Cnt);
+ NREAD(X_BUFFERSPACE, &s->bufspace, LONG);
NREAD(X_DK_BUSY, &s->dk_busy, LONG);
NREAD(X_DK_TIME, s->dk_time, dk_ndrive * LONG);
NREAD(X_DK_XFER, s->dk_xfer, dk_ndrive * LONG);
@@ -632,7 +625,7 @@ allocinfo(s)
struct Info *s;
{
- s->intrcnt = (long *) malloc(nintr * sizeof(long));
+ s->intrcnt = (long *) calloc(nintr, sizeof(long));
if (s->intrcnt == NULL) {
fprintf(stderr, "systat: out of memory\n");
exit(2);
@@ -648,7 +641,7 @@ copyinfo(from, to)
/*
* time, wds, seek, and xfer are malloc'd so we have to
- * save the pointers before the structure copy and then
+ * save the pointers before the structure copy and then
* copy by hand.
*/
time = to->dk_time; wds = to->dk_wds; seek = to->dk_seek;
diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h
index 65efc14..f9a8bdf 100644
--- a/usr.bin/tail/extern.h
+++ b/usr.bin/tail/extern.h
@@ -42,10 +42,9 @@ enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE };
void forward __P((FILE *, enum STYLE, long, struct stat *));
void reverse __P((FILE *, enum STYLE, long, struct stat *));
-void bytes __P((FILE *, off_t));
-void lines __P((FILE *, off_t));
+int bytes __P((FILE *, off_t));
+int lines __P((FILE *, off_t));
-void err __P((int fatal, const char *fmt, ...));
void ierr __P((void));
void oerr __P((void));
diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c
index 8e32cc4..b9457af 100644
--- a/usr.bin/tail/forward.c
+++ b/usr.bin/tail/forward.c
@@ -50,6 +50,7 @@ static char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <err.h>
#include "extern.h"
static void rlines __P((FILE *, long, struct stat *));
@@ -85,7 +86,6 @@ forward(fp, style, off, sbp)
{
register int ch;
struct timeval second;
- fd_set zero;
switch(style) {
case FBYTES:
@@ -136,7 +136,8 @@ forward(fp, style, off, sbp)
return;
}
} else
- bytes(fp, off);
+ if (bytes(fp, off))
+ return;
break;
case RLINES:
if (S_ISREG(sbp->st_mode))
@@ -154,7 +155,8 @@ forward(fp, style, off, sbp)
return;
}
} else
- lines(fp, off);
+ if (lines(fp, off))
+ return;
break;
}
@@ -162,11 +164,6 @@ forward(fp, style, off, sbp)
* We pause for one second after displaying any data that has
* accumulated since we read the file.
*/
- if (fflag) {
- FD_ZERO(&zero);
- second.tv_sec = 1;
- second.tv_usec = 0;
- }
for (;;) {
while ((ch = getc(fp)) != EOF)
@@ -179,9 +176,13 @@ forward(fp, style, off, sbp)
(void)fflush(stdout);
if (!fflag)
break;
+
/* Sleep(3) is eight system calls. Do it fast. */
- if (select(0, &zero, &zero, &zero, &second) == -1)
- err(1, "select: %s", strerror(errno));
+ second.tv_sec = 1;
+ second.tv_usec = 0;
+ if (select(0, NULL, NULL, NULL, &second) == -1)
+ if (errno != EINTR)
+ err(1, "select");
clearerr(fp);
}
}
@@ -203,13 +204,14 @@ rlines(fp, off, sbp)
return;
if (size > SIZE_T_MAX) {
- err(0, "%s: %s", fname, strerror(EFBIG));
+ errno = EFBIG;
+ ierr();
return;
}
if ((start = mmap(NULL, (size_t)size,
- PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) {
- err(0, "%s: %s", fname, strerror(EFBIG));
+ PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) {
+ ierr();
return;
}
@@ -228,7 +230,7 @@ rlines(fp, off, sbp)
return;
}
if (munmap(start, (size_t)sbp->st_size)) {
- err(0, "%s: %s", fname, strerror(errno));
+ ierr();
return;
}
}
diff --git a/usr.bin/tail/misc.c b/usr.bin/tail/misc.c
index 18fd63d..8891819 100644
--- a/usr.bin/tail/misc.c
+++ b/usr.bin/tail/misc.c
@@ -45,47 +45,18 @@ static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <err.h>
#include "extern.h"
void
ierr()
{
- err(0, "%s: %s", fname, strerror(errno));
+ warn("%s", fname);
+ rval = 1;
}
void
oerr()
{
- err(1, "stdout: %s", strerror(errno));
-}
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(int fatal, const char *fmt, ...)
-#else
-err(fatal, fmt, va_alist)
- int fatal;
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "tail: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- if (fatal)
- exit(1);
- rval = 1;
+ err(1, "stdout");
}
diff --git a/usr.bin/tail/read.c b/usr.bin/tail/read.c
index dc570a3..feecf3c 100644
--- a/usr.bin/tail/read.c
+++ b/usr.bin/tail/read.c
@@ -46,6 +46,7 @@ static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <err.h>
#include "extern.h"
/*
@@ -58,7 +59,7 @@ static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/6/93";
* it is displayed from the character closest to the beginning of the input to
* the end.
*/
-void
+int
bytes(fp, off)
register FILE *fp;
off_t off;
@@ -69,7 +70,7 @@ bytes(fp, off)
char *sp;
if ((sp = p = malloc(off)) == NULL)
- err(1, "%s", strerror(errno));
+ err(1, "malloc");
for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
*p = ch;
@@ -80,7 +81,7 @@ bytes(fp, off)
}
if (ferror(fp)) {
ierr();
- return;
+ return 1;
}
if (rflag) {
@@ -113,6 +114,7 @@ bytes(fp, off)
if (len = p - sp)
WR(sp, len);
}
+ return 0;
}
/*
@@ -125,7 +127,7 @@ bytes(fp, off)
* it is displayed from the line closest to the beginning of the input to
* the end.
*/
-void
+int
lines(fp, off)
register FILE *fp;
off_t off;
@@ -141,15 +143,15 @@ lines(fp, off)
char *sp;
if ((lines = malloc(off * sizeof(*lines))) == NULL)
- err(1, "%s", strerror(errno));
-
+ err(1, "malloc");
+ bzero(lines, off * sizeof(*lines));
sp = NULL;
blen = cnt = recno = wrap = 0;
while ((ch = getc(fp)) != EOF) {
if (++cnt > blen) {
if ((sp = realloc(sp, blen += 1024)) == NULL)
- err(1, "%s", strerror(errno));
+ err(1, "realloc");
p = sp + cnt - 1;
}
*p++ = ch;
@@ -158,7 +160,7 @@ lines(fp, off)
lines[recno].blen = cnt + 256;
if ((lines[recno].l = realloc(lines[recno].l,
lines[recno].blen)) == NULL)
- err(1, "%s", strerror(errno));
+ err(1, "realloc");
}
bcopy(sp, lines[recno].l, lines[recno].len = cnt);
cnt = 0;
@@ -171,7 +173,7 @@ lines(fp, off)
}
if (ferror(fp)) {
ierr();
- return;
+ return 1;
}
if (cnt) {
lines[recno].l = sp;
@@ -195,4 +197,5 @@ lines(fp, off)
for (cnt = 0; cnt < recno; ++cnt)
WR(lines[cnt].l, lines[cnt].len);
}
+ return 0;
}
diff --git a/usr.bin/tail/reverse.c b/usr.bin/tail/reverse.c
index 34cd980..0a07f4f 100644
--- a/usr.bin/tail/reverse.c
+++ b/usr.bin/tail/reverse.c
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <err.h>
#include "extern.h"
static void r_buf __P((FILE *));
@@ -118,13 +119,14 @@ r_reg(fp, style, off, sbp)
return;
if (size > SIZE_T_MAX) {
- err(0, "%s: %s", fname, strerror(EFBIG));
+ errno = EFBIG;
+ ierr();
return;
}
if ((start = mmap(NULL, (size_t)size,
- PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) {
- err(0, "%s: %s", fname, strerror(EFBIG));
+ PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) {
+ ierr();
return;
}
p = start + size - 1;
@@ -145,7 +147,7 @@ r_reg(fp, style, off, sbp)
if (llen)
WR(p, llen);
if (munmap(start, (size_t)sbp->st_size))
- err(0, "%s: %s", fname, strerror(errno));
+ ierr();
}
typedef struct bf {
@@ -184,7 +186,7 @@ r_buf(fp)
if (enomem || (tl = malloc(sizeof(BF))) == NULL ||
(tl->l = malloc(BSZ)) == NULL) {
if (!mark)
- err(1, "%s", strerror(errno));
+ err(1, "malloc");
tl = enomem ? tl->next : mark;
enomem += tl->len;
} else if (mark) {
@@ -200,6 +202,11 @@ r_buf(fp)
len < BSZ && (ch = getc(fp)) != EOF; ++len)
*p++ = ch;
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+
/*
* If no input data for this block and we tossed some data,
* recover it.
@@ -217,8 +224,7 @@ r_buf(fp)
}
if (enomem) {
- (void)fprintf(stderr,
- "tail: warning: %ld bytes discarded\n", enomem);
+ warnx("warning: %ld bytes discarded\n", enomem);
rval = 1;
}
diff --git a/usr.bin/tail/tail.c b/usr.bin/tail/tail.c
index cc8ea14..4c7ea6f 100644
--- a/usr.bin/tail/tail.c
+++ b/usr.bin/tail/tail.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)tail.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <err.h>
#include "extern.h"
int fflag, rflag, rval;
@@ -88,7 +89,7 @@ main(argc, argv)
usage(); \
off = strtol(optarg, &p, 10) * (units); \
if (*p) \
- err(1, "illegal offset -- %s", optarg); \
+ errx(1, "illegal offset -- %s", optarg); \
switch(optarg[0]) { \
case '+': \
if (off) \
@@ -106,7 +107,7 @@ main(argc, argv)
obsolete(argv);
style = NOTSET;
- while ((ch = getopt(argc, argv, "b:c:fn:r")) != EOF)
+ while ((ch = getopt(argc, argv, "b:c:fn:r")) != -1)
switch(ch) {
case 'b':
ARG(512, FBYTES, RBYTES);
@@ -131,7 +132,7 @@ main(argc, argv)
argv += optind;
if (fflag && argc > 1)
- err(1, "-f option only appropriate for a single file");
+ errx(1, "-f option only appropriate for a single file");
/*
* If displaying in reverse, don't permit follow option, and convert
@@ -234,7 +235,7 @@ obsolete(argv)
/* Malloc space for dash, new option and argument. */
len = strlen(*argv);
if ((start = p = malloc(len + 3)) == NULL)
- err(1, "%s", strerror(errno));
+ err(1, "malloc");
*p++ = '-';
/*
@@ -264,7 +265,7 @@ obsolete(argv)
*p++ = 'n';
break;
default:
- err(1, "illegal option -- %s", *argv);
+ errx(1, "illegal option -- %s", *argv);
}
*p++ = *argv[0];
(void)strcpy(p, ap);
diff --git a/usr.bin/talk/Makefile b/usr.bin/talk/Makefile
index d86cd02..921a12e 100644
--- a/usr.bin/talk/Makefile
+++ b/usr.bin/talk/Makefile
@@ -1,9 +1,11 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
PROG= talk
-DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBCOMPAT}
-LDADD= -lcurses -ltermlib -lcompat
-SRCS= ctl.c ctl_transact.c display.c get_addrs.c get_names.c \
+DPADD= ${LIBCURSES} ${LIBTERMCAP}
+LDADD= -lcurses -ltermcap
+CFLAGS+= -Wall -Wstrict-prototypes -Wno-unused
+SRCS= ctl.c ctl_transact.c display.c get_addrs.c get_iface.c get_names.c \
init_disp.c invite.c io.c look_up.c msgs.c talk.c
.include <bsd.prog.mk>
diff --git a/usr.bin/talk/ctl.c b/usr.bin/talk/ctl.c
index 250cbc1..2f77608 100644
--- a/usr.bin/talk/ctl.c
+++ b/usr.bin/talk/ctl.c
@@ -64,6 +64,7 @@ int invitation_waiting = 0;
CTL_MSG msg;
+void
open_sockt()
{
int length;
@@ -81,7 +82,8 @@ open_sockt()
}
/* open the ctl socket */
-open_ctl()
+void
+open_ctl()
{
int length;
@@ -100,13 +102,14 @@ open_ctl()
}
/* print_addr is a debug print routine */
+void
print_addr(addr)
struct sockaddr_in addr;
{
int i;
- printf("addr = %x, port = %o, family = %o zero = ",
- addr.sin_addr, addr.sin_port, addr.sin_family);
+ printf("addr = %lx, port = %o, family = %o zero = ",
+ addr.sin_addr.s_addr, addr.sin_port, addr.sin_family);
for (i = 0; i<8;i++)
printf("%o ", (int)addr.sin_zero[i]);
putchar('\n');
diff --git a/usr.bin/talk/ctl_transact.c b/usr.bin/talk/ctl_transact.c
index 73ee23b..2cd4dce 100644
--- a/usr.bin/talk/ctl_transact.c
+++ b/usr.bin/talk/ctl_transact.c
@@ -35,12 +35,9 @@
static char sccsid[] = "@(#)ctl_transact.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <protocols/talkd.h>
#include <errno.h>
+#include <string.h>
+#include "talk.h"
#include "talk_ctl.h"
#define CTL_WAIT 2 /* time to wait for a response, in seconds */
@@ -50,19 +47,22 @@ static char sccsid[] = "@(#)ctl_transact.c 8.1 (Berkeley) 6/6/93";
* not recieved an acknowledgement within a reasonable amount
* of time
*/
+void
ctl_transact(target, msg, type, rp)
struct in_addr target;
CTL_MSG msg;
int type;
CTL_RESPONSE *rp;
{
- int read_mask, ctl_mask, nready, cc;
+ fd_set read_mask, ctl_mask;
+ int nready = 0, cc;
struct timeval wait;
msg.type = type;
daemon_addr.sin_addr = target;
daemon_addr.sin_port = daemon_port;
- ctl_mask = 1 << ctl_sockt;
+ FD_ZERO(&ctl_mask);
+ FD_SET(ctl_sockt, &ctl_mask);
/*
* Keep sending the message until a response of
@@ -90,7 +90,7 @@ ctl_transact(target, msg, type, rp)
}
} while (nready == 0);
/*
- * Keep reading while there are queued messages
+ * Keep reading while there are queued messages
* (this is not necessary, it just saves extra
* request/acknowledgements being sent)
*/
diff --git a/usr.bin/talk/display.c b/usr.bin/talk/display.c
index e5c059e..7b43d46 100644
--- a/usr.bin/talk/display.c
+++ b/usr.bin/talk/display.c
@@ -40,6 +40,7 @@ static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
* displaying of text
*/
#include "talk.h"
+#include <ctype.h>
xwin_t my_win;
xwin_t his_win;
@@ -51,6 +52,7 @@ int curses_initialized = 0;
* max HAS to be a function, it is called with
* a argument of the form --foo at least once.
*/
+int
max(a,b)
int a, b;
{
@@ -62,6 +64,7 @@ max(a,b)
* Display some text on somebody's window, processing some control
* characters while we are at it.
*/
+void
display(win, text, size)
register xwin_t *win;
register char *text;
@@ -71,13 +74,17 @@ display(win, text, size)
char cch;
for (i = 0; i < size; i++) {
- if (*text == '\n') {
- xscroll(win, 0);
+ if (*text == '\n' || *text == '\r') {
+ waddch(win->x_win, '\n');
+ getyx(win->x_win, win->x_line, win->x_col);
text++;
continue;
}
/* erase character */
- if (*text == win->cerase) {
+ if ( *text == win->cerase
+ || *text == 010 /* BS */
+ || *text == 0177 /* DEL */
+ ) {
wmove(win->x_win, win->x_line, max(--win->x_col, 0));
getyx(win->x_win, win->x_line, win->x_col);
waddch(win->x_win, ' ');
@@ -91,7 +98,9 @@ display(win, text, size)
* the beginning of a word or the beginning of
* the line.
*/
- if (*text == win->werase) {
+ if ( *text == win->werase
+ || *text == 027 /* ^W */
+ ) {
int endcol, xcol, i, c;
endcol = win->x_col;
@@ -117,7 +126,9 @@ display(win, text, size)
continue;
}
/* line kill */
- if (*text == win->kill) {
+ if ( *text == win->kill
+ || *text == 025 /* ^U */
+ ) {
wmove(win->x_win, win->x_line, 0);
wclrtoeol(win->x_win);
getyx(win->x_win, win->x_line, win->x_col);
@@ -130,19 +141,18 @@ display(win, text, size)
text++;
continue;
}
- if (win->x_col == COLS-1) {
- /* check for wraparound */
- xscroll(win, 0);
+ if (*text == '\7') {
+ write(STDOUT_FILENO, text, 1);
+ text++;
+ continue;
}
- if (*text < ' ' && *text != '\t') {
+ if (!isprint((unsigned char)*text) && *text != '\t') {
waddch(win->x_win, '^');
getyx(win->x_win, win->x_line, win->x_col);
- if (win->x_col == COLS-1) /* check for wraparound */
- xscroll(win, 0);
cch = (*text & 63) + 64;
waddch(win->x_win, cch);
} else
- waddch(win->x_win, *text);
+ waddch(win->x_win, (unsigned char)*text);
getyx(win->x_win, win->x_line, win->x_col);
text++;
}
@@ -152,8 +162,11 @@ display(win, text, size)
/*
* Read the character at the indicated position in win
*/
+int
readwin(win, line, col)
WINDOW *win;
+ int line;
+ int col;
{
int oldline, oldcol;
register int c;
@@ -164,27 +177,3 @@ readwin(win, line, col)
wmove(win, oldline, oldcol);
return (c);
}
-
-/*
- * Scroll a window, blanking out the line following the current line
- * so that the current position is obvious
- */
-xscroll(win, flag)
- register xwin_t *win;
- int flag;
-{
-
- if (flag == -1) {
- wmove(win->x_win, 0, 0);
- win->x_line = 0;
- win->x_col = 0;
- return;
- }
- win->x_line = (win->x_line + 1) % win->x_nlines;
- win->x_col = 0;
- wmove(win->x_win, win->x_line, win->x_col);
- wclrtoeol(win->x_win);
- wmove(win->x_win, (win->x_line + 1) % win->x_nlines, win->x_col);
- wclrtoeol(win->x_win);
- wmove(win->x_win, win->x_line, win->x_col);
-}
diff --git a/usr.bin/talk/get_addrs.c b/usr.bin/talk/get_addrs.c
index b9db4a6..7ac9267 100644
--- a/usr.bin/talk/get_addrs.c
+++ b/usr.bin/talk/get_addrs.c
@@ -35,14 +35,13 @@
static char sccsid[] = "@(#)get_addrs.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <protocols/talkd.h>
+#include <string.h>
#include <netdb.h>
#include <stdio.h>
+#include "talk.h"
#include "talk_ctl.h"
+void
get_addrs(my_machine_name, his_machine_name)
char *my_machine_name, *his_machine_name;
{
@@ -50,28 +49,18 @@ get_addrs(my_machine_name, his_machine_name)
struct servent *sp;
msg.pid = htonl(getpid());
- /* look up the address of the local host */
- hp = gethostbyname(my_machine_name);
+
+ hp = gethostbyname(his_machine_name);
if (hp == NULL) {
- fprintf(stderr, "talk: %s: ", my_machine_name);
+ fprintf(stderr, "talk: %s: ", his_machine_name);
herror((char *)NULL);
exit(-1);
}
- bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length);
- /*
- * If the callee is on-machine, just copy the
- * network address, otherwise do a lookup...
- */
- if (strcmp(his_machine_name, my_machine_name)) {
- hp = gethostbyname(his_machine_name);
- if (hp == NULL) {
- fprintf(stderr, "talk: %s: ", his_machine_name);
- herror((char *)NULL);
- exit(-1);
- }
- bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length);
- } else
- his_machine_addr = my_machine_addr;
+ bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length);
+ if (get_iface(&his_machine_addr, &my_machine_addr) == -1) {
+ perror("failed to find my interface address");
+ exit(-1);
+ }
/* find the server's port */
sp = getservbyname("ntalk", "udp");
if (sp == 0) {
diff --git a/usr.bin/talk/get_iface.c b/usr.bin/talk/get_iface.c
new file mode 100644
index 0000000..3aef9b2
--- /dev/null
+++ b/usr.bin/talk/get_iface.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1994, 1995 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From:
+ * Id: find_interface.c,v 1.1 1995/08/14 16:08:39 wollman Exp
+ *
+ * $Id$
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "talk.h"
+
+/*
+ * Try to find the interface address that is used to route an IP
+ * packet to a remote peer.
+ */
+
+int
+get_iface(dst, iface)
+ struct in_addr *dst;
+ struct in_addr *iface;
+{
+ static struct sockaddr_in local;
+ struct sockaddr_in remote;
+ struct hostent *hp;
+ int s, rv, namelen;
+
+ memcpy(&remote.sin_addr, dst, sizeof remote.sin_addr);
+ remote.sin_port = htons(60000);
+ remote.sin_family = AF_INET;
+ remote.sin_len = sizeof remote;
+
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(60000);
+ local.sin_family = AF_INET;
+ local.sin_len = sizeof local;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return -1;
+
+ do {
+ rv = bind(s, (struct sockaddr *)&local, sizeof local);
+ local.sin_port = htons(ntohs(local.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0) {
+ close(s);
+ return -1;
+ }
+
+ do {
+ rv = connect(s, (struct sockaddr *)&remote, sizeof remote);
+ remote.sin_port = htons(ntohs(remote.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0) {
+ close(s);
+ return -1;
+ }
+
+ namelen = sizeof local;
+ rv = getsockname(s, (struct sockaddr *)&local, &namelen);
+ close(s);
+ if (rv < 0)
+ return -1;
+
+ memcpy(iface, &local.sin_addr, sizeof local.sin_addr);
+ return 0;
+}
diff --git a/usr.bin/talk/get_names.c b/usr.bin/talk/get_names.c
index 9d3cc04..793ce72 100644
--- a/usr.bin/talk/get_names.c
+++ b/usr.bin/talk/get_names.c
@@ -35,20 +35,18 @@
static char sccsid[] = "@(#)get_names.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#include <unistd.h>
+#include <string.h>
#include <sys/param.h>
-#include <sys/socket.h>
-#include <protocols/talkd.h>
#include <pwd.h>
#include "talk.h"
-char *getlogin();
-char *ttyname();
-char *rindex();
extern CTL_MSG msg;
/*
* Determine the local and remote user, tty, and machines
*/
+void
get_names(argc, argv)
int argc;
char *argv[];
@@ -79,7 +77,7 @@ get_names(argc, argv)
gethostname(hostname, sizeof (hostname));
my_machine_name = hostname;
/* check for, and strip out, the machine name of the target */
- for (cp = argv[1]; *cp && !index("@:!.", *cp); cp++)
+ for (cp = argv[1]; *cp && !index("@:!", *cp); cp++)
;
if (*cp == '\0') {
/* this is a local to local talk */
@@ -91,7 +89,7 @@ get_names(argc, argv)
his_name = argv[1];
his_machine_name = cp;
} else {
- /* host.user or host!user or host:user */
+ /* host!user or host:user */
his_name = cp;
his_machine_name = argv[1];
}
diff --git a/usr.bin/talk/init_disp.c b/usr.bin/talk/init_disp.c
index 517e51c..7eded28 100644
--- a/usr.bin/talk/init_disp.c
+++ b/usr.bin/talk/init_disp.c
@@ -40,27 +40,47 @@ static char sccsid[] = "@(#)init_disp.c 8.2 (Berkeley) 2/16/94";
* as well as the signal handling routines.
*/
-#include <sys/ioctl.h>
-#include <sys/ioctl_compat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/ttydefaults.h>
+#include <unistd.h>
#include <signal.h>
#include <err.h>
#include "talk.h"
-/*
+/*
+ * Make sure the callee can write to the screen
+ */
+void
+check_writeable()
+{
+ char *tty;
+ struct stat sb;
+
+ if ((tty = ttyname(STDERR_FILENO)) == NULL)
+ err(1, "ttyname");
+ if (stat(tty, &sb) < 0)
+ err(1, "%s", tty);
+ if (!(sb.st_mode & S_IWGRP))
+ errx(1, "The callee cannot write to this terminal, use \"mesg y\".");
+}
+
+/*
* Set up curses, catch the appropriate signals,
* and build the various windows.
*/
+void
init_display()
{
- void sig_sent();
- struct sigvec sigv;
+ struct sigaction sa;
if (initscr() == NULL)
errx(1, "Terminal type unset or lacking necessary features.");
- (void) sigvec(SIGTSTP, (struct sigvec *)0, &sigv);
- sigv.sv_mask |= sigmask(SIGALRM);
- (void) sigvec(SIGTSTP, &sigv, (struct sigvec *)0);
+ (void) sigaction(SIGTSTP, (struct sigaction *)0, &sa);
+ sigaddset(&sa.sa_mask, SIGALRM);
+ (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
curses_initialized = 1;
clear();
refresh();
@@ -72,18 +92,24 @@ init_display()
my_win.x_nlines = LINES / 2;
my_win.x_ncols = COLS;
my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
- scrollok(my_win.x_win, FALSE);
+ idlok(my_win.x_win, TRUE);
+ scrollok(my_win.x_win, TRUE);
wclear(my_win.x_win);
his_win.x_nlines = LINES / 2 - 1;
his_win.x_ncols = COLS;
his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
my_win.x_nlines+1, 0);
- scrollok(his_win.x_win, FALSE);
+ idlok(my_win.x_win, TRUE);
+ scrollok(his_win.x_win, TRUE);
wclear(his_win.x_win);
line_win = newwin(1, COLS, my_win.x_nlines, 0);
+#if defined(hline) || defined(whline) || defined(NCURSES_VERSION)
+ whline(line_win, 0, COLS);
+#else
box(line_win, '-', '-');
+#endif
wrefresh(line_win);
/* let them know we are working on it */
current_state = "No connection yet";
@@ -94,21 +120,23 @@ init_display()
* the first three characters each talk transmits after
* connection are the three edit characters.
*/
+void
set_edit_chars()
{
char buf[3];
int cc;
- struct sgttyb tty;
- struct ltchars ltc;
-
- ioctl(0, TIOCGETP, &tty);
- ioctl(0, TIOCGLTC, (struct sgttyb *)&ltc);
- my_win.cerase = tty.sg_erase;
- my_win.kill = tty.sg_kill;
- if (ltc.t_werasc == (char) -1)
- my_win.werase = '\027'; /* control W */
- else
- my_win.werase = ltc.t_werasc;
+ struct termios tio;
+
+ tcgetattr(0, &tio);
+ my_win.cerase = tio.c_cc[VERASE];
+ my_win.kill = tio.c_cc[VKILL];
+ my_win.werase = tio.c_cc[VWERASE];
+ if (my_win.cerase == (char)_POSIX_VDISABLE)
+ my_win.kill = CERASE;
+ if (my_win.kill == (char)_POSIX_VDISABLE)
+ my_win.kill = CKILL;
+ if (my_win.werase == (char)_POSIX_VDISABLE)
+ my_win.werase = CWERASE;
buf[0] = my_win.cerase;
buf[1] = my_win.kill;
buf[2] = my_win.werase;
@@ -123,8 +151,10 @@ set_edit_chars()
his_win.werase = buf[2];
}
+/* ARGSUSED */
void
-sig_sent()
+sig_sent(signo)
+ int signo;
{
message("Connection closing. Exiting");
@@ -134,6 +164,7 @@ sig_sent()
/*
* All done talking...hang up the phone and reset terminal thingy's
*/
+void
quit()
{
diff --git a/usr.bin/talk/invite.c b/usr.bin/talk/invite.c
index ae73539..579aed0 100644
--- a/usr.bin/talk/invite.c
+++ b/usr.bin/talk/invite.c
@@ -49,19 +49,19 @@ static char sccsid[] = "@(#)invite.c 8.1 (Berkeley) 6/6/93";
/*
* There wasn't an invitation waiting, so send a request containing
* our sockt address to the remote talk daemon so it can invite
- * him
+ * him
*/
/*
* The msg.id's for the invitations
* on the local and remote machines.
- * These are used to delete the
+ * These are used to delete the
* invitations.
*/
int local_id, remote_id;
-void re_invite();
jmp_buf invitebuf;
+void
invite_remote()
{
int nfd, read_mask, template, new_sockt;
@@ -117,12 +117,16 @@ invite_remote()
/*
* Routine called on interupt to re-invite the callee
*/
+/* ARGSUSED */
void
-re_invite()
+re_invite(signo)
+ int signo;
{
message("Ringing your party again");
- current_line++;
+ waddch(my_win.x_win, '\n');
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
/* force a re-announce */
msg.id_num = htonl(remote_id + 1);
announce_invite();
@@ -145,6 +149,7 @@ static char *answers[] = {
/*
* Transmit the invitation and process the response
*/
+void
announce_invite()
{
CTL_RESPONSE response;
@@ -165,6 +170,7 @@ announce_invite()
/*
* Tell the daemon to remove your invitation
*/
+void
send_delete()
{
diff --git a/usr.bin/talk/io.c b/usr.bin/talk/io.c
index 5ba6f97..7b8ead8 100644
--- a/usr.bin/talk/io.c
+++ b/usr.bin/talk/io.c
@@ -36,7 +36,7 @@ static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
- * This file contains the I/O handling and the exchange of
+ * This file contains the I/O handling and the exchange of
* edit characters. This connection itself is established in
* ctl.c
*/
@@ -49,28 +49,30 @@ static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
#include "talk.h"
#define A_LONG_TIME 10000000
-#define STDIN_MASK (1<<fileno(stdin)) /* the bit mask for standard
- input */
/*
* The routine to do the actual talking
*/
+void
talk()
{
- register int read_template, sockt_mask;
- int read_set, nb;
+ int nb;
+ fd_set read_set, read_template;
char buf[BUFSIZ];
struct timeval wait;
- message("Connection established\007\007\007");
+ message("Connection established");
+ write(STDOUT_FILENO, "\007\007\007", 3);
+
current_line = 0;
- sockt_mask = (1<<sockt);
/*
- * Wait on both the other process (sockt_mask) and
+ * Wait on both the other process (sockt_mask) and
* standard input ( STDIN_MASK )
*/
- read_template = sockt_mask | STDIN_MASK;
+ FD_ZERO(&read_template);
+ FD_SET(sockt, &read_template);
+ FD_SET(fileno(stdin), &read_template);
for (;;) {
read_set = read_template;
wait.tv_sec = A_LONG_TIME;
@@ -85,7 +87,7 @@ talk()
p_error("Unexpected error from select");
quit();
}
- if (read_set & sockt_mask) {
+ if (FD_ISSET(sockt, &read_set)) {
/* There is data on sockt */
nb = read(sockt, buf, sizeof buf);
if (nb <= 0) {
@@ -94,7 +96,7 @@ talk()
}
display(&his_win, buf, nb);
}
- if (read_set & STDIN_MASK) {
+ if (FD_ISSET(fileno(stdin), &read_set)) {
/*
* We can't make the tty non_blocking, because
* curses's output routines would screw up
@@ -115,10 +117,11 @@ extern int sys_nerr;
* p_error prints the system error message on the standard location
* on the screen and then exits. (i.e. a curses version of perror)
*/
-p_error(string)
+void
+p_error(string)
char *string;
{
- wmove(my_win.x_win, current_line%my_win.x_nlines, 0);
+ wmove(my_win.x_win, current_line, 0);
wprintw(my_win.x_win, "[%s : %s (%d)]\n",
string, strerror(errno), errno);
wrefresh(my_win.x_win);
@@ -130,13 +133,13 @@ p_error(string)
/*
* Display string in the standard location
*/
+void
message(string)
char *string;
{
- wmove(my_win.x_win, current_line % my_win.x_nlines, 0);
- wprintw(my_win.x_win, "[%s]", string);
- wclrtoeol(my_win.x_win);
- current_line++;
- wmove(my_win.x_win, current_line % my_win.x_nlines, 0);
+ wmove(my_win.x_win, current_line, 0);
+ wprintw(my_win.x_win, "[%s]\n", string);
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
wrefresh(my_win.x_win);
}
diff --git a/usr.bin/talk/look_up.c b/usr.bin/talk/look_up.c
index 9c335ae..62356ea 100644
--- a/usr.bin/talk/look_up.c
+++ b/usr.bin/talk/look_up.c
@@ -46,6 +46,7 @@ static char sccsid[] = "@(#)look_up.c 8.1 (Berkeley) 6/6/93";
/*
* See if the local daemon has an invitation for us.
*/
+int
check_local()
{
CTL_RESPONSE response;
@@ -63,8 +64,8 @@ check_local()
if (!look_for_invite(rp))
return (0);
/*
- * There was an invitation waiting for us,
- * so connect with the other (hopefully waiting) party
+ * There was an invitation waiting for us,
+ * so connect with the other (hopefully waiting) party
*/
current_state = "Waiting to connect with caller";
do {
@@ -78,7 +79,7 @@ check_local()
if (errno == ECONNREFUSED) {
/*
* The caller gave up, but his invitation somehow
- * was not cleared. Clear it and initiate an
+ * was not cleared. Clear it and initiate an
* invitation. (We know there are no newer invitations,
* the talkd works LIFO.)
*/
@@ -89,11 +90,13 @@ check_local()
}
p_error("Unable to connect with initiator");
/*NOTREACHED*/
+ return (0);
}
/*
* Look for an invitation on 'machine'
*/
+int
look_for_invite(rp)
CTL_RESPONSE *rp;
{
diff --git a/usr.bin/talk/msgs.c b/usr.bin/talk/msgs.c
index 733c207..0b3eeee 100644
--- a/usr.bin/talk/msgs.c
+++ b/usr.bin/talk/msgs.c
@@ -35,7 +35,7 @@
static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
-/*
+/*
* A package to display what is happening every MSG_INTERVAL seconds
* if we are slow connecting.
*/
@@ -50,12 +50,15 @@ static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
char *current_state;
int current_line = 0;
+/* ARGSUSED */
void
-disp_msg()
+disp_msg(signo)
+ int signo;
{
message(current_state);
}
+void
start_msgs()
{
struct itimerval itimer;
@@ -67,6 +70,7 @@ start_msgs()
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
}
+void
end_msgs()
{
struct itimerval itimer;
diff --git a/usr.bin/talk/talk.1 b/usr.bin/talk/talk.1
index 18c3304..2f40fa6 100644
--- a/usr.bin/talk/talk.1
+++ b/usr.bin/talk/talk.1
@@ -55,7 +55,11 @@ is just the person's login name. If you wish to talk to a user on
another host, then
.Ar person
is of the form
-.Ql user@host .
+.Ql user@host
+or
+.Ql host!user
+or
+.Ql host:user .
.It Ar ttyname
If you wish to talk to a user who is logged in more than once, the
.Ar ttyname
diff --git a/usr.bin/talk/talk.c b/usr.bin/talk/talk.c
index 702df16..68b9d57 100644
--- a/usr.bin/talk/talk.c
+++ b/usr.bin/talk/talk.c
@@ -42,26 +42,34 @@ static char sccsid[] = "@(#)talk.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "talk.h"
+#include <locale.h>
/*
- * talk: A visual form of write. Using sockets, a two way
- * connection is set up between the two people talking.
- * With the aid of curses, the screen is split into two
+ * talk: A visual form of write. Using sockets, a two way
+ * connection is set up between the two people talking.
+ * With the aid of curses, the screen is split into two
* windows, and each users text is added to the window,
* one character at a time...
*
* Written by Kipp Hickman
- *
+ *
* Modified to run under 4.1a by Clem Cole and Peter Moore
* Modified to run between hosts by Peter Moore, 8/19/82
* Modified to run under 4.1c by Peter Moore 3/17/83
+ * Fixed to not run with unwriteable terminals MRVM 28/12/94
*/
+int main __P((int, char **));
+
+int
main(argc, argv)
int argc;
char *argv[];
{
+ (void) setlocale(LC_CTYPE, "");
+
get_names(argc, argv);
+ check_writeable();
init_display();
open_ctl();
open_sockt();
@@ -71,4 +79,5 @@ main(argc, argv)
end_msgs();
set_edit_chars();
talk();
+ return 0;
}
diff --git a/usr.bin/talk/talk.h b/usr.bin/talk/talk.h
index 98a7118..63bd373 100644
--- a/usr.bin/talk/talk.h
+++ b/usr.bin/talk/talk.h
@@ -33,7 +33,15 @@
* @(#)talk.h 8.1 (Berkeley) 6/6/93
*/
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <protocols/talkd.h>
#include <curses.h>
+#include <unistd.h>
extern int sockt;
extern int curses_initialized;
@@ -56,3 +64,31 @@ typedef struct xwin {
extern xwin_t my_win;
extern xwin_t his_win;
extern WINDOW *line_win;
+
+extern void announce_invite __P((void));
+extern int check_local __P((void));
+extern void check_writeable __P((void));
+extern void ctl_transact __P((struct in_addr,CTL_MSG,int,CTL_RESPONSE *));
+extern void disp_msg __P((int));
+extern void display __P((xwin_t *, char *, int));
+extern void end_msgs __P((void));
+extern void get_addrs __P((char *, char *));
+extern int get_iface __P((struct in_addr *, struct in_addr *));
+extern void get_names __P((int, char **));
+extern void init_display __P((void));
+extern void invite_remote __P((void));
+extern int look_for_invite __P((CTL_RESPONSE *));
+extern int max __P((int, int));
+extern void message __P((char *));
+extern void open_ctl __P((void));
+extern void open_sockt __P((void));
+extern void p_error __P((char *));
+extern void print_addr __P((struct sockaddr_in));
+extern void quit __P((void));
+extern int readwin __P((WINDOW *, int, int));
+extern void re_invite __P((int));
+extern void send_delete __P((void));
+extern void set_edit_chars __P((void));
+extern void sig_sent __P((int));
+extern void start_msgs __P((void));
+extern void talk __P((void));
diff --git a/usr.bin/tclsh/Makefile b/usr.bin/tclsh/Makefile
new file mode 100644
index 0000000..db56a03
--- /dev/null
+++ b/usr.bin/tclsh/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+PROG= tclsh
+SRCS= tclAppInit.c
+
+BINDIR= /usr/bin
+
+.PATH: ${DESTDIR}/usr/libdata/tcl
+
+MAN1= tclsh.1
+
+CLEANFILES= ${MAN1}
+
+tclsh.1: ${.CURDIR}/../../contrib/tcl/doc/tclsh.1
+ sed '/\.so *man.macros/s;.*;.so /usr/share/tmac/tcl.macros;' < $> > $@
+
+LDADD+= -ltcl -lm
+DPADD+= ${LIBTCL} ${LIBM}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/tconv/Makefile b/usr.bin/tconv/Makefile
new file mode 100644
index 0000000..0a4af30
--- /dev/null
+++ b/usr.bin/tconv/Makefile
@@ -0,0 +1,12 @@
+# Makefile for tconv
+# $Id$
+
+PROG= tconv
+SRCS= tconv.c quit.c
+MLINKS= tconv.1 tic.1 tconv.1 captoinfo.1
+LINKS= ${BINDIR}/tconv ${BINDIR}/tic ${BINDIR}/tconv ${BINDIR}/captoinfo
+CFLAGS+= -I${.CURDIR}/../../lib/libmytinfo -Wall
+DPADD= $(LIBMYTINFO)
+LDADD= -lmytinfo
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/tconv/quit.c b/usr.bin/tconv/quit.c
new file mode 100644
index 0000000..f30fb50
--- /dev/null
+++ b/usr.bin/tconv/quit.c
@@ -0,0 +1,72 @@
+/*
+ * quit.c
+ *
+ * By Ross Ridge
+ * Public Domain
+ * 92/02/01 07:30:14
+ *
+ * quit with a diagnostic message printed on stderr
+ *
+ */
+
+#define NOTLIB
+#include "defs.h"
+
+#ifdef USE_SCCS_IDS
+static const char SCCSid[] = "@(#) mytinfo quit.c 3.2 92/02/01 public domain, By Ross Ridge";
+#endif
+
+char *prg_name;
+
+#if defined(USE_PROTOTYPES) && !defined(lint)
+void (*cleanup)(int);
+#else
+void (*cleanup)();
+#endif
+
+/* PRINTFLIKE2 */
+noreturn
+#ifdef USE_STDARG
+#ifdef USE_PROTOTYPES
+void
+quit(int e, char *fmt, ...)
+#else
+void quit(e, fmt)
+int e;
+char *fmt;
+#endif
+#else
+void quit(va_alist)
+va_dcl
+#endif
+{
+#ifndef USE_STDARG
+ int e;
+ char *fmt;
+#endif
+ va_list ap;
+
+#ifdef USE_STDARG
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+ e = va_arg(ap, int);
+ fmt = va_arg(ap, char *);
+#endif
+
+ (*cleanup)(e);
+
+ if (e != 0)
+ fprintf(stderr, "%s: ", prg_name);
+#ifdef USE_DOPRNT
+ _doprnt(fmt, ap, stderr);
+#else
+ vfprintf(stderr, fmt, ap);
+#endif
+ putc('\n', stderr);
+ if (e > 0 && e < sys_nerr) {
+ fprintf(stderr, "%d - %s\n", e, sys_errlist[e]);
+ }
+ fflush(stderr);
+ exit(e);
+}
diff --git a/usr.bin/tconv/tconv.1 b/usr.bin/tconv/tconv.1
new file mode 100644
index 0000000..d7e1224
--- /dev/null
+++ b/usr.bin/tconv/tconv.1
@@ -0,0 +1,179 @@
+.\" @(#) mytinfo tconv.1 3.2 92/02/01 public domain, By Ross Ridge
+.\" $Id$
+.\"
+.TH TCONV 1 "92/02/01" "mytinfo"
+.SH NAME
+tconv \- convert between termcap, terminfo source and terminfo binary
+.SH SYNOPSIS
+.B tconv
+[\fB\-b\fR]
+[\fB\-c\fR\ [\fB\-OUGd\fR]]
+[\fB\-i\fR]
+[\fB\-B\fR\ [\fB\-D\fR\ dir]]
+[\fB\-I\fR]
+[\fB\-k\fR]
+[\fB\-V\fR]
+[\fB\-t\fR\ term]
+[file]
+.br
+.B tic
+[file]
+.br
+.B captoinfo
+[\fB\-t\fR\ term]
+[\fB\-OUGdk\fR]]
+[file]
+.SH DESCRIPTION
+.I tconv
+converts between the three terminal descriptions,
+termcap, terminfo source, and terminfo binary,
+that the
+.I tinfo
+library uses.
+It performs the same functions of
+.IR captoinfo (1M)
+and
+.IR tic (1M)
+of System V.
+It also can be used to generate a terminfo source listing from a terminfo
+binary, one of the functions of System V's
+.IR infocmp (1M).
+.SS Translation Options
+.PD 0
+.TP
+.B \-c
+convert from termcap
+.TP
+.B \-i
+convert from terminfo source
+.TP
+.B \-b
+convert from terminfo binary
+.TP
+.B \-B
+convert to terminfo binary
+.TP
+.B \-I
+convert to terminfo source
+.PD
+.PP
+If a file is specified, one of
+.B \-c
+or
+.B \-i
+must specified and the whole file while be translated.
+If no file is specified then the input options will only restrict looking
+for the terminal to be translated in places likely have descriptions
+of the desired type
+(ie. with the
+.B -c
+option in the
+.B TERMCAP
+environment variable, and in
+.IR /usr/share/misc/termcap ,
+with the
+.B -i
+option in the
+.B TERMINFO
+environment variable, and in
+.IR /usr/lib/terminfo ),
+otherwise
+.I tconv
+will look in all available databases.
+If neither
+.B \-I
+or
+.B \-B
+are given the
+.B \-I
+option will be assumed.
+If the
+.B \-B
+option is used, the compiled output will be put in the
+terminfo database, otherwise standard output is used.
+.PP
+You cannot translate from terminfo binary to terminfo binary.
+Translating from terminfo source to terminfo source is possible,
+but not of much use in most cases, as
+.B use=
+fields will be followed and incorporated into the output terminal
+description.
+.PP
+.I tconv
+should be able translate all standard termcap parameterized strings
+terminfo format, but complex strings using GNU's %a code may be
+too hard to translate.
+If
+.I tconv
+thinks a termcap string is already in terminfo format (if a %p
+code appears in the string), it won't try to translate it.
+String capabilities that don't take parameters won't be translated.
+.PP
+.B
+.SS Termcap options
+The following options are available when translating termcap entries
+(\fB\-c\fR options is used).
+.PP
+.PD 0
+.TP
+.B \-d
+don't supply any defaults for missing capabilities
+.TP
+.B \-O
+include obsolete termcap capabilities
+.TP
+.B \-G
+include GNU capabilities
+.TP
+.B \-U
+include UW capabilities
+.PD
+.SS Other Options
+.PD 0
+.TP
+.B \-k
+keep comments when translating a file
+.TP
+.B \-V
+print version information and exit
+.TP
+.BI \-D " " dir
+directory to put terminfo binaries in
+.TP
+.BI \-t " " term
+terminal name to translate
+.PD
+.PP
+If no terminal specified with the
+.B \-t
+option, then the terminal name to to translate will be taken from the
+environment variable
+.BR TERM .
+.SH FILES
+.PD 0
+.TP 2i
+.B /usr/lib/terminfo
+The default location to get and put terminfo binaries.
+.TP
+.B /usr/lib/terminfo/terminfo.src
+The default filename of the terminfo source file.
+.TP
+.B /etc/termcap
+The default filename of the termcap database.
+.PD
+.SH "SEE ALSO"
+termcap(3),
+curses(3),
+term(5),
+termcap(5),
+terminfo(5).
+.SH DIAGNOSTICS
+The line number of a warning message when translating a file
+may refer to the last line of an entry instead of the line in the entry
+that generated the warning.
+.SH BUGS
+More warning messages could be generated.
+.I tconv
+can't translate to termcap. Binaries generated will have canceled
+capabilities marked as canceled, which is incompatible with
+System V Release 2.0 terminfo.
diff --git a/usr.bin/tconv/tconv.c b/usr.bin/tconv/tconv.c
new file mode 100644
index 0000000..2c281994
--- /dev/null
+++ b/usr.bin/tconv/tconv.c
@@ -0,0 +1,1384 @@
+/*
+ * tconv.c
+ *
+ * Ross Ridge
+ * Public Domain
+ * 92/02/01 07:30:23
+ *
+ * tconv [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V] [-t term] [file]
+ *
+ * -c convert from termcap
+ * -i convert from terminfo source
+ * -b convert from terminfo binary
+ * -B convert to terminfo binary
+ * -I convert to terminfo source
+ * -V print version info
+ *
+ * The following switches are available when converting from termcap:
+ * -d don't supply any defaults for missing capabilities
+ * -O include obsolete termcap capabilities
+ * -G include GNU capabilities
+ * -U include UW capabilities
+ *
+ * -k keep comments
+ * -D dir directory to put terminfo binaries in
+ *
+ * -t term name of terminal to translate
+ * file filename of termcap/terminfo database to use
+ *
+ * If a file is specifed and no terminal is given the entire file we be
+ * translated.
+ * If no terminal and no file is specified then the terminal name will be
+ * taken from the environment variable TERM.
+ * Unless compiling to a terminfo binary, output is to stdout.
+ *
+ */
+
+#define NOTLIB
+#include "defs.h"
+#define SINGLE
+#include <term.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#ifdef USE_STDDEF
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <unistd.h>
+#endif
+
+#ifndef __FreeBSD__
+#include "strtok.c"
+#include "mkdir.c"
+#endif
+
+#ifndef lint
+static const char SCCSid[] = "@(#) mytinfo tconv.c 3.2 92/02/01 public domain, By Ross Ridge";
+#endif
+
+extern int errno;
+
+/* the right margin of the output */
+#define LINELEN 76
+
+struct term_path *path; /* returned from _buildpath */
+
+TERMINAL _term_buf;
+char buf[MAX_BUF+1]; /* buffer for the termcap entry */
+
+int noOT = 1; /* -O */
+int noGNU = 1; /* -G */
+int noUW = 1; /* -W */
+int dodefault = 1; /* -d */
+int keepcomments = 0; /* -k */
+int compile = 0; /* -B */
+int from_tcap = 0; /* -c */
+int from_tinfo = 0; /* -i */
+int from_tbin = 0; /* -b */
+char *directory = NULL; /* -D */
+
+int continued = 0;
+int termcap = 1;
+
+int lineno = 0; /* current line number */
+
+/* print the first part of a warning message */
+void
+warn() {
+ if (lineno == 0)
+ fprintf(stderr, "warning: ");
+ else
+ fprintf(stderr, "(%s)%d: warning: ",
+ _term_buf.name_long, lineno);
+}
+
+/* output a string indenting at the beginning of a line, and wraping
+ * at the right margin.
+ */
+void
+putstr(s)
+char *s; {
+ static pos = 0;
+ int l;
+
+ if (s == NULL) {
+ if (pos != 0) {
+ pos = 0;
+ putchar('\n');
+ }
+ return;
+ }
+
+ if (termcap && noOT && *s == 'O')
+ return;
+ if (termcap && noGNU && *s == 'G')
+ return;
+ if (termcap && noUW && *s == 'U')
+ return;
+
+ l = strlen(s) + 2;
+
+ if (l + pos > LINELEN && pos != 0) {
+ putchar('\n');
+ pos = 0;
+ }
+
+ if (pos == 0) {
+ putchar('\t');
+ pos = 8;
+ } else
+ putchar(' ');
+
+ printf("%s,", s);
+
+ pos += l;
+}
+
+#ifndef MAX_PUSHED
+/* maximum # of parameters that can be pushed onto the stack */
+#define MAX_PUSHED 16
+#endif
+
+int stack[MAX_PUSHED]; /* the stack */
+int stackptr; /* the next empty place on the stack */
+int onstack; /* the top of stack */
+int seenm; /* seen a %m */
+int seenn; /* seen a %n */
+int seenr; /* seen a %r */
+int param; /* current parameter */
+char *dp; /* pointer to the end of the converted string */
+
+/* push onstack on to the stack */
+void
+push() {
+ if (stackptr > MAX_PUSHED) {
+ warn();
+ fprintf(stderr, "string to complex to covert\n");
+ } else
+ stack[stackptr++] = onstack;
+}
+
+/* pop the top of the stack into onstack */
+void
+pop() {
+ if (stackptr == 0)
+ if (onstack == 0) {
+ warn();
+ fprintf(stderr, "I'm confused\n");
+ } else
+ onstack = 0;
+ else
+ onstack = stack[--stackptr];
+ param++;
+}
+
+/* convert a character to a terminfo push */
+static int
+cvtchar(sp)
+register char *sp; {
+ char c;
+ int l;
+
+ switch(*sp) {
+ case '\\':
+ switch(*++sp) {
+ case '\'':
+ case '$':
+ case '\\':
+ case '%':
+ c = *sp;
+ l = 2;
+ break;
+ case '\0':
+ c = '\\';
+ l = 1;
+ break;
+ case '0':
+ if (sp[1] == '0' && sp[2] == '0') {
+ c = '\0';
+ l = 4;
+ } else {
+ c = '\200'; /* '\0' ???? */
+ l = 2;
+ }
+ break;
+ default:
+ c = *sp;
+ l = 2;
+ break;
+ }
+ break;
+ default:
+ c = *sp;
+ l = 1;
+ }
+ c &= 0177;
+ if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
+ *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
+ } else {
+ *dp++ = '%'; *dp++ = '{';
+ if (c > 99)
+ *dp++ = c / 100 + '0';
+ if (c > 9)
+ *dp++ = (c / 10) % 10 + '0';
+ *dp++ = c % 10 + '0';
+ *dp++ = '}';
+ }
+ return l;
+}
+
+/* push n copies of param on the terminfo stack if not already there */
+void
+getparm(parm, n)
+int parm;
+int n; {
+ if (seenr) {
+ if (parm == 1)
+ parm = 2;
+ else if (parm == 2)
+ parm = 1;
+ }
+ if (onstack == parm) {
+ if (n > 1) {
+ warn();
+ fprintf(stderr, "string may not be optimal");
+ *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
+ while(n--) {
+ *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
+ }
+ }
+ return;
+ }
+ if (onstack != 0)
+ push();
+
+ onstack = parm;
+
+ while(n--) { /* %p0 */
+ *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
+ }
+
+ if (seenn && parm < 3) { /* %{96}%^ */
+ *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
+ *dp++ = '%'; *dp++ = '^';
+ }
+
+ if (seenm && parm < 3) { /* %{127}%^ */
+ *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
+ *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
+ }
+}
+
+/* convert a string to terminfo format */
+char *
+convstr(s, i)
+register char *s;
+int i; {
+ static char line[MAX_LINE];
+ register char *cap;
+ int nocode = 0;
+
+ stackptr = 0;
+ onstack = 0;
+ seenm = 0;
+ seenn = 0;
+ seenr = 0;
+ param = 1;
+
+ dp = line;
+ cap = strnames[i];
+#if 0
+ if (cap[0] == 'k'
+ || ((cap[0] == 'i' || cap[0] == 'r') && cap[1] == 's'
+ && (cap[2] == '1' || cap[2] == '2' || cap[2] == '3')))
+ /* if (k.* || [ir]s[123]) */
+ nocode = 1;
+#else
+ if (_strflags[i] != 'G')
+ nocode = 1;
+#endif
+ if (!nocode) {
+ char *d = s;
+ while(*s != '\0') {
+ if (s[0] == '\\' && s[1] != '\0')
+ s++;
+ else if (s[0] == '%' && s[1] != '\0') {
+ if (s[1] == 'p') {
+ if (termcap) {
+ warn();
+ fprintf(stderr,
+"string '%s' already in terminfo format\n", strcodes[i]);
+ nocode = 1;
+ break;
+ } else
+ nocode = 1;
+ }
+ s++;
+ }
+ s++;
+ }
+ if (!nocode && !termcap) {
+ warn();
+ fprintf(stderr,
+"string '%s' not in terminfo format, converting...\n", cap);
+ }
+ s = d;
+ }
+ while(*s != '\0') {
+ switch(*s) {
+ case '%':
+ s++;
+ if (nocode) {
+ *dp++ = '%';
+ break;
+ }
+ switch(*s++) {
+ case '%': *dp++ = '%'; break;
+ case 'r':
+ if (seenr++ == 1) {
+ warn();
+ fprintf(stderr, "seen %%r twice\n");
+ }
+ break;
+ case 'm':
+ if (seenm++ == 1) {
+ warn();
+ fprintf(stderr, "seen %%m twice\n");
+ }
+ break;
+ case 'n':
+ if (seenn++ == 1) {
+ warn();
+ fprintf(stderr, "seen %%n twice\n");
+ }
+ break;
+ case 'i': *dp++ = '%'; *dp++ = 'i'; break;
+ case '6':
+ case 'B':
+ getparm(param, 2);
+ /* %{6}%*%+ */
+ *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
+ *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
+ *dp++ = '%'; *dp++ = '+';
+ break;
+ case '8':
+ case 'D':
+ getparm(param, 2);
+ /* %{2}%*%- */
+ *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
+ *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
+ *dp++ = '%'; *dp++ = '-';
+ break;
+ case '>':
+ getparm(param, 2);
+ /* %?%{x}%>%t%{y}%+%; */
+ *dp++ = '%'; *dp++ = '?';
+ s += cvtchar(s);
+ *dp++ = '%'; *dp++ = '>';
+ *dp++ = '%'; *dp++ = 't';
+ s += cvtchar(s);
+ *dp++ = '%'; *dp++ = '+';
+ *dp++ = '%'; *dp++ = ';';
+ break;
+ case 'a':
+ if ((*s == '=' || *s == '+' || *s == '-'
+ || *s == '*' || *s == '/')
+ && (s[1] == 'p' || s[1] == 'c')
+ && s[2] != '\0') {
+ int l;
+ l = 2;
+ if (*s != '=')
+ getparm(param, 1);
+ if (s[1] == 'p') {
+ getparm(param + s[2] - '@', 1);
+ if (param != onstack) {
+ pop();
+ param--;
+ }
+ l++;
+ } else
+ l += cvtchar(s + 2);
+ switch(*s) {
+ case '+':
+ *dp++ = '%'; *dp++ = '+';
+ break;
+ case '-':
+ *dp++ = '%'; *dp++ = '-';
+ break;
+ case '*':
+ *dp++ = '%'; *dp++ = '*';
+ break;
+ case '/':
+ *dp++ = '%'; *dp++ = '/';
+ break;
+ case '=':
+ if (seenr)
+ if (param == 1)
+ onstack = 2;
+ else if (param == 2)
+ onstack = 1;
+ else
+ onstack = param;
+ else
+ onstack = param;
+ break;
+ }
+ s += l;
+ break;
+ }
+ getparm(param, 1);
+ s += cvtchar(s);
+ *dp++ = '%'; *dp++ = '+';
+ break;
+ case '+':
+ getparm(param, 1);
+ s += cvtchar(s);
+ *dp++ = '%'; *dp++ = '+';
+ *dp++ = '%'; *dp++ = 'c';
+ pop();
+ break;
+ case 's':
+ s += cvtchar(s);
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = '-';
+ break;
+ case '-':
+ s += cvtchar(s);
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = '-';
+ *dp++ = '%'; *dp++ = 'c';
+ pop();
+ break;
+ case '.':
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = 'c';
+ pop();
+ break;
+ case '2':
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = '0';
+ *dp++ = '2'; *dp++ = 'd';
+ pop();
+ break;
+ case '3':
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = '0';
+ *dp++ = '3'; *dp++ = 'd';
+ pop();
+ break;
+ case 'd':
+ getparm(param, 1);
+ *dp++ = '%'; *dp++ = 'd';
+ pop();
+ break;
+ case 'f':
+ param++;
+ break;
+ case 'b':
+ param--;
+ break;
+ default:
+ warn();
+ *dp++ = '%';
+ s--;
+ fprintf(stderr, "'%s' unknown %% code %c",
+ strcodes[i], *s);
+ if (*s >= 0 && *s < 32)
+ fprintf(stderr, "^%c\n", *s + '@');
+ else if (*s < 0 || *s >= 127)
+ fprintf(stderr, "\\%03o\n", *s & 0377);
+ else
+ fprintf(stderr, "%c\n", *s);
+ break;
+ }
+ break;
+ case '\\':
+ if (!compile) {*dp++ = *s++; *dp++ = *s++; break;}
+ /* FALLTHROUGH */
+ case '\n':
+ if (!compile) {*dp++ = '\\'; *dp++ = 'n'; s++; break;}
+ /* FALLTHROUGH */
+ case '\t':
+ if (!compile) {*dp++ = '\\'; *dp++ = 't'; s++; break;}
+ /* FALLTHROUGH */
+ case '\r':
+ if (!compile) {*dp++ = '\\'; *dp++ = 'r'; s++; break;}
+ /* FALLTHROUGH */
+ case '\200':
+ if (!compile) {*dp++ = '\\'; *dp++ = '0'; s++; break;}
+ /* FALLTHROUGH */
+ case '\f':
+ if (!compile) {*dp++ = '\\'; *dp++ = 'f'; s++; break;}
+ /* FALLTHROUGH */
+ case '\b':
+ if (!compile) {*dp++ = '\\'; *dp++ = 'b'; s++; break;}
+ /* FALLTHROUGH */
+ case ' ':
+ if (!compile) {*dp++ = '\\'; *dp++ = 's'; s++; break;}
+ /* FALLTHROUGH */
+ case '^':
+ if (!compile) {*dp++ = '\\'; *dp++ = '^'; s++; break;}
+ /* FALLTHROUGH */
+ case ':':
+ if (!compile) {*dp++ = '\\'; *dp++ = ':'; s++; break;}
+ /* FALLTHROUGH */
+ case ',':
+ if (!compile) {*dp++ = '\\'; *dp++ = ','; s++; break;}
+ /* FALLTHROUGH */
+#if 0
+ case '\'':
+ if (!compile) {*dp++ = '\\'; *dp++ = '\''; s++; break;}
+ /* FALLTHROUGH */
+#endif
+ default:
+ if (compile)
+ *dp++ = *s++;
+ else if (*s > 0 && *s < 32) {
+ *dp++ = '^';
+ *dp++ = *s + '@';
+ s++;
+ } else if (*s <= 0 || *s >= 127) {
+ *dp++ = '\\';
+ *dp++ = ((*s & 0300) >> 6) + '0';
+ *dp++ = ((*s & 0070) >> 3) + '0';
+ *dp++ = (*s & 0007) + '0';
+ s++;
+ } else
+ *dp++ = *s++;
+ break;
+ }
+ }
+ *dp = '\0';
+ return line;
+}
+
+#define LSB(n) ((unsigned) (n) & 0377)
+#define MSB(n) (((unsigned) (n) >> 8) & 0377)
+
+void
+writebin(fd, name)
+int fd;
+char *name; {
+ static char bin[MAX_BUF + 1];
+ register char *s;
+ register char *d;
+ register int i;
+ register char *t;
+ register int n;
+ char *strtbl;
+ int sz_name, n_bools, n_nums, n_offs, sz_strs;
+ extern int _boolorder[], _numorder[], _strorder[];
+
+ strncpy(bin + 12, name, 127);
+ bin[12 + 128] = '\0';
+ sz_name = strlen(name) + 1;
+ if (sz_name > 128)
+ sz_name = 128;
+
+ s = bin + 12 + sz_name;
+ for(i = 0; _boolorder[i] != -1; i++) {
+ switch(_term_buf.bools[i]) {
+ case -1: *s++ = 0; break;
+ case 0: *s++ = 0377; break;
+ default: *s++ = 1; break;
+ }
+ }
+ n_bools = i;
+ if ((sz_name + n_bools) & 1)
+ n_bools++;
+
+ s = bin + 12 + sz_name + n_bools;
+ for(i = 0; _numorder[i] != -1; i++) {
+ n = _term_buf.nums[_numorder[i]];
+ switch(n) {
+ case -2: *s++ = 0377; *s++ = 0377; break;
+ case -1: *s++ = 0376; *s++ = 0377; break;
+ default:
+ *s++ = LSB(n);
+ *s++ = MSB(n);
+ }
+ }
+ n_nums = i;
+
+ s = bin + 12 + sz_name + n_bools + n_nums * 2;
+ for(i = 0; _strorder[i] != -1; i++) {
+ if (_term_buf.strs[_strorder[i]] == (char *) 0) {
+ *s++ = 0376; *s++ = 0377;
+ } else {
+ *s++ = 0377; *s++ = 0377;
+ }
+ }
+ n_offs = i;
+
+ s = bin + 12 + sz_name + n_bools + n_nums * 2;
+ strtbl = d = s + n_offs * 2;
+ for(i = 0; _strorder[i] != -1; i++) {
+ t = _term_buf.strs[_strorder[i]];
+ if (t == (char *) -1 || t == (char *) 0)
+ s += 2;
+ else {
+ n = d - strtbl;
+ *s++ = LSB(n);
+ *s++ = MSB(n);
+ t = convstr(t, _strorder[i]);
+ while(*t != '\0') {
+ *d++ = *t++;
+ if (d >= bin + MAX_BUF - 1) {
+ warn();
+ fprintf(stderr,
+ "compiled entry to big\n");
+ *d++ = '\0';
+ goto toobig;
+ }
+ }
+ *d++ = '\0';
+ }
+ }
+
+toobig:
+ sz_strs = d - strtbl;
+
+ bin[0] = 032;
+ bin[1] = 01;
+ bin[2] = LSB(sz_name);
+ bin[3] = MSB(sz_name);
+ bin[4] = LSB(n_bools);
+ bin[5] = MSB(n_bools);
+ bin[6] = LSB(n_nums);
+ bin[7] = MSB(n_nums);
+ bin[8] = LSB(n_offs);
+ bin[9] = MSB(n_offs);
+ bin[10] = LSB(sz_strs);
+ bin[11] = MSB(sz_strs);
+
+ if (write(fd, bin, d - bin) == -1)
+ quit(errno, "can't write binary file");
+
+ return;
+}
+
+void
+find_directory() {
+ struct term_path *p;
+ struct stat st;
+
+ if (directory != NULL)
+ return;
+
+ p = path;
+ while(p->type != -1 && p->file != NULL) {
+ if (stat(p->file, &st) == 0) {
+ if ((st.st_mode & 0170000) == 0040000) {
+ directory = p->file;
+ return;
+ }
+ }
+ p++;
+ }
+ quit(-1, "can't find a terminfo directory");
+}
+
+/* convert a terminal name to a binary filename */
+char *
+binfile(name)
+char *name; {
+ static char line[MAX_LINE+1];
+
+ sprintf(line, "%s/%c/%s", directory, *name, name);
+ return line;
+}
+
+char *
+bindir(name)
+char *name; {
+ static char line[MAX_LINE+1];
+
+ sprintf(line, "%s/%c", directory, *name);
+ return line;
+}
+
+int
+badname(name)
+char *name; {
+ while(*name) {
+ if (*name == '/' || !isgraph(*name))
+ return 1;
+ name++;
+ }
+ return 0;
+}
+
+/* output a terminfo binary */
+void
+outputbin(name)
+char *name; {
+ register char *s, *d, *last;
+ char tmp[MAX_LINE+1];
+ char line[MAX_LINE+1];
+ int fd;
+
+ find_directory();
+
+ s = name;
+ d = line;
+ while(*s != '\0' && d < line + MAX_LINE) {
+ *d++ = *s++;
+ }
+
+ while(d > line && d[-1] == '|') {
+ d--;
+ }
+
+ *d = '\0';
+
+ s = strtok(line, "|");
+ last = NULL;
+
+ while(s != NULL && last == NULL) {
+ if (*s == '\0') {
+ ;
+ } else if (badname(s)) {
+ if (lineno)
+ warn();
+ fprintf(stderr, "bad terminal name '%s', ingored.\n",
+ s);
+ } else {
+ if (access(bindir(s), 2) == -1) {
+ if (errno != ENOENT)
+ quit(errno,
+ "can't access directory '%s'",
+ bindir(s));
+ if (mkdir(bindir(s), 0777) == -1)
+ quit(errno, "can't make directory '%s'",
+ bindir(s));
+ }
+ fd = open(binfile(s), O_WRONLY | O_CREAT | O_EXCL,
+ 0666);
+ if (fd == -1) {
+ if (errno != EEXIST)
+ quit(errno, "can't open file '%s'",
+ binfile(s));
+ if (unlink(binfile(s)) == -1)
+ quit(errno, "can't unlink file '%s'",
+ binfile(s));
+ fd = open(binfile(s),
+ O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd == -1)
+ quit(errno, "can't create file '%s'",
+ binfile(s));
+ }
+ writebin(fd, name);
+ close(fd);
+ last = s;
+ }
+ s = strtok(NULL, "|");
+ }
+
+ if (last == NULL) {
+ if (lineno)
+ warn();
+ fprintf(stderr, "no terminal name, entry ignored.\n");
+ return;
+ }
+
+ while(s != NULL && s + strlen(s) != d) {
+ if (*s == '\0' || strcmp(s, last) == 0) {
+ ;
+ } else if (badname(s)) {
+ if (lineno)
+ warn();
+ fprintf(stderr, "bad terminal name '%s', ingored.\n",
+ s);
+ } else {
+ if (access(bindir(s), 2) == -1) {
+ if (errno != ENOENT)
+ quit(errno,
+ "can't access directory '%s'",
+ bindir(s));
+ if (mkdir(bindir(s), 0777) == -1)
+ quit(errno, "can't make directory '%s'",
+ bindir(s));
+ }
+ if (access(binfile(s), 0) == -1) {
+ if (errno != ENOENT)
+ quit(errno, "can't access file '%s'",
+ binfile(s));
+ } else if (unlink(binfile(s)) == -1) {
+ quit(errno, "can't unlink file '%s'",
+ binfile(s));
+ }
+ strcpy(tmp, binfile(last));
+ if (link(tmp, binfile(s)) == -1) {
+ quit(errno, "can't link '%s' to '%s'",
+ last, binfile(s));
+ }
+ }
+ s = strtok(NULL, "|");
+ }
+ return;
+}
+
+/* output an entry in terminfo source format */
+void
+outputinfo(name)
+char *name; {
+ int i;
+ char line[MAX_LINE];
+
+ printf("%s,\n", name);
+
+ for(i = 0; i < NUM_OF_BOOLS; i++)
+ if (_term_buf.bools[i] == 0) {
+ sprintf(line, "%s@", boolnames[i]);
+ putstr(line);
+ } else if (_term_buf.bools[i] != -1)
+ putstr(boolnames[i]);
+
+ for(i = 0; i < NUM_OF_NUMS; i++)
+ if (_term_buf.nums[i] == -1) {
+ sprintf(line, "%s@", numnames[i]);
+ putstr(line);
+ } else if (_term_buf.nums[i] != -2) {
+ sprintf(line, "%s#%d", numnames[i], _term_buf.nums[i]);
+ putstr(line);
+ }
+
+ for(i = 0; i < NUM_OF_STRS; i++)
+ if (_term_buf.strs[i] == NULL) {
+ sprintf(line, "%s@", strnames[i]);
+ putstr(line);
+ } else if (_term_buf.strs[i] != (char *) -1) {
+ sprintf(line, "%s=%s", strnames[i],
+ convstr(_term_buf.strs[i], i));
+ putstr(line);
+ }
+ putstr(NULL);
+}
+
+/* convert a terminfo entry to binary format */
+void
+convtinfo() {
+ int i, r;
+
+ termcap = 0;
+
+ for(i = 0; i < NUM_OF_BOOLS; i++)
+ _term_buf.bools[i] = -1;
+ for(i = 0; i < NUM_OF_NUMS; i++)
+ _term_buf.nums[i] = -2;
+ for(i = 0; i < NUM_OF_STRS; i++)
+ _term_buf.strs[i] = (char *) -1;
+
+ _term_buf.name_all = NULL;
+
+ r = _gettinfo(buf, &_term_buf, path);
+ if (r != 0) {
+ if (lineno == 0)
+ quit(-1, "problem reading entry");
+ else {
+ warn();
+ fprintf(stderr, "problem reading entry\n");
+ }
+ }
+
+ if (compile)
+ outputbin(_term_buf.name_all);
+ else
+ outputinfo(_term_buf.name_all);
+ return;
+}
+
+/* convert a terminfo binary to terminfo source */
+void
+convtbin() {
+ int i, r;
+
+ termcap = 0;
+
+ for(i = 0; i < NUM_OF_BOOLS; i++)
+ _term_buf.bools[i] = -1;
+ for(i = 0; i < NUM_OF_NUMS; i++)
+ _term_buf.nums[i] = -2;
+ for(i = 0; i < NUM_OF_STRS; i++)
+ _term_buf.strs[i] = (char *) -1;
+
+ _term_buf.name_all = NULL;
+
+ r = _gettbin(buf, &_term_buf);
+ if (r != 0) {
+ if (lineno == 0)
+ quit(-1, "problem reading entry");
+ else {
+ warn();
+ fprintf(stderr, "problem reading entry\n");
+ }
+ }
+
+ outputinfo(_term_buf.name_all);
+
+ return;
+}
+
+/* convert a termcap entry to terminfo format */
+void
+convtcap() {
+ int i, r;
+ char *name;
+
+ termcap = 1;
+
+ for(i = 0; i < NUM_OF_BOOLS; i++)
+ _term_buf.bools[i] = -1;
+ for(i = 0; i < NUM_OF_NUMS; i++)
+ _term_buf.nums[i] = -2;
+ for(i = 0; i < NUM_OF_STRS; i++)
+ _term_buf.strs[i] = (char *) -1;
+
+ _term_buf.name_all = NULL;
+
+
+#if DEBUG
+ printf("%s\n", buf);
+#endif
+ r = _gettcap(buf, &_term_buf, path);
+ if (r != 0) {
+ if (lineno == 0)
+ quit(-1, "problem reading entry");
+ else {
+ warn();
+ fprintf(stderr, "problem reading entry\n");
+ }
+ }
+
+ if (dodefault && !continued)
+ _tcapdefault();
+
+ _tcapconv();
+
+ name = _term_buf.name_all;
+#if DEBUG
+ printf("...%s\n", name);
+#endif
+ if (name[0] != '\0' && name[1] != '\0' && name[2] == '|')
+ name += 3; /* skip the 2 letter code */
+
+ if (compile)
+ outputbin(name);
+ else
+ outputinfo(name);
+}
+
+void
+convbinfile(file)
+char *file; {
+ register FILE *f;
+ int r;
+
+ f = fopen(file, "r");
+
+ if (f == NULL)
+ quit(errno, "can't open '%s'", file);
+
+ r = fread(buf, sizeof(char), MAX_BUF, f);
+ if (r < 12 || buf[0] != 032 || buf[1] != 01)
+ quit(-1, "file '%s' corrupted", file);
+
+ convtbin();
+}
+
+/* convert a termcap file to terminfo format */
+void
+convtcfile(file)
+char *file; {
+ int nocolon;
+ register int c;
+ register char *d;
+ register FILE *f;
+
+ f = fopen(file, "r");
+
+ if (f == NULL)
+ quit(errno, "can't open '%s'", file);
+
+ d = buf;
+ c = getc(f);
+ while(c != EOF) {
+ lineno++;
+ if (c == '#') {
+ if (keepcomments) {
+ do {
+ putchar(c);
+ c = getc(f);
+ } while(c != '\n' && c != EOF);
+ putchar('\n');
+ } else
+ do
+ c = getc(f);
+ while(c != '\n' && c != EOF);
+ if (c != EOF)
+ c = getc(f);
+ continue;
+ }
+ while(isspace(c) && c != '\n')
+ c = getc(f);
+ if (c == '\n' && buf == d) {
+ c = getc(f);
+ continue;
+ }
+
+ while(c != EOF) {
+ if (c == '\\') {
+ c = getc(f);
+ if (c == EOF)
+ break;
+ if (c == '\n') {
+ c = getc(f);
+ break;
+ }
+ *d++ = '\\';
+ *d++ = c;
+ } else if (c == '\n') {
+ *d = '\0';
+ if (*--d == ':') {
+ nocolon = 0;
+ *d-- = '\0';
+ } else {
+ nocolon = 1;
+ }
+ while(d > buf && *d != ':')
+ d--;
+ if (d[1] == 't' && d[2] == 'c' && d[3] == '=') {
+ continued = 1;
+ d[1] = '\0';
+ } else
+ continued = 0;
+ convtcap();
+ if (nocolon) {
+ warn();
+ fprintf(stderr,
+ "entry doesn't end with :\n");
+ }
+ _term_buf.strbuf = _endstr();
+ _del_strs(&_term_buf);
+ if (continued) {
+ printf("\tuse=%s,\n", d + 4);
+ }
+ d = buf;
+ c = getc(f);
+ break;
+ } else
+ *d++ = c;
+ c = getc(f);
+ }
+ }
+}
+
+static int
+getln(f, buf, len)
+FILE *f;
+register char *buf;
+int len; {
+ register int c, i = 0;
+
+ while((c = getc(f)) == '#') {
+ lineno++;
+ if (keepcomments) {
+ putchar('#');
+ while((c = getc(f)) != '\n') {
+ if (c == EOF)
+ return -1;
+ putchar(c);
+ }
+ putchar('\n');
+ } else {
+ while((c = getc(f)) != '\n')
+ if (c == EOF)
+ return -1;
+ }
+ }
+
+ lineno++;
+ while(c != '\n') {
+ if (c == EOF)
+ return -1;
+ if (i < len) {
+ i++;
+ *buf++ = c;
+ }
+ c = getc(f);
+ }
+
+ while(isspace(*(buf-1))) {
+ buf--;
+ i--;
+ }
+
+ *buf = '\0';
+ return i;
+}
+
+void
+convtifile(file)
+char *file; {
+ static char line[MAX_LINE+1];
+ int l;
+ int n;
+ register FILE *f;
+
+ f = fopen(file, "r");
+
+ if (f == NULL)
+ quit(errno, "can't open '%s'", file);
+
+ lineno = 0;
+
+ l = getln(f, line, MAX_LINE);
+ while(l != -1) {
+ if (line[l-1] == ':') {
+ strncpy(buf, line, MAX_BUF);
+ convtcap();
+ } else if (line[l-1] == '\\') {
+ n = MAX_BUF;
+ do {
+ line[--l] = '\0';
+ if (n > 0)
+ strncpy(buf + MAX_BUF - n, line, n);
+ n -= l;
+ l = getln(f, line, MAX_LINE);
+ } while(l != -1 && line[l-1] == '\\');
+ if (n > 0 && l != -1)
+ strncpy(buf + MAX_BUF - n, line, n);
+ convtcap();
+ } else if (line[l-1] == ',') {
+ n = MAX_BUF;
+ do {
+ if (n > 0)
+ strncpy(buf + MAX_BUF - n, line, n);
+ n -= l;
+ l = getln(f, line, MAX_LINE);
+ } while(l != -1 && isspace(line[0]));
+#if 0
+ printf("buf = '%s'\n", buf);
+#endif
+ convtinfo();
+ continue;
+ } else if (line[0] != '\0') {
+ warn();
+ fprintf(stderr, "malformed line\n");
+ if (keepcomments) {
+ printf("%s\n", line);
+ }
+ }
+ l = getln(f, line, MAX_LINE);
+ }
+ return;
+}
+
+/* dummy routine for quit */
+/* ARGSUSED */
+void
+do_cleanup(e)
+int e; {
+ return;
+}
+
+/* print out usage, called by quit */
+/* ARGSUSED */
+void
+usage(e)
+int e; {
+ fprintf(stderr,
+"usage: %s [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V]\n\t[-t term] [file]\n",
+ prg_name);
+ return;
+}
+
+int
+main(argc, argv)
+int argc;
+char **argv; {
+ extern char *optarg;
+ extern int optind;
+ extern int opterr;
+ char *term = NULL;
+ char *file = NULL;
+ int r;
+ char c;
+ int pversion = 0;
+
+ prg_name = strrchr(argv[0], '/');
+ if (prg_name == NULL)
+ prg_name = argv[0];
+ else
+ prg_name++;
+
+ cleanup = usage;
+
+ opterr = 0;
+
+ if (strcmp(prg_name, "tic") == 0)
+ compile = 1;
+
+ while ((c = getopt(argc, argv, "bciBIOGUdkVD:t:")) != -1) {
+ switch(c) {
+ case 'O':
+ noOT = 0;
+ break;
+ case 'G':
+ noGNU = 0;
+ break;
+ case 'U':
+ noUW = 0;
+ break;
+ case 'D':
+ if (directory != NULL)
+ quit(-1, "more than one directory specified");
+ directory = optarg;
+ break;
+ case 't':
+ if (term != NULL)
+ quit(-1, "more than one terminal specified");
+ term = optarg;
+ break;
+ case 'd': dodefault = 0; break;
+ case 'k': keepcomments = 1; break;
+ case 'b': from_tbin = 1; break;
+ case 'c': from_tcap = 1; break;
+ case 'i': from_tinfo = 1; break;
+ case 'B': compile = 1; break;
+ case 'I': compile = 0; break;
+ case 'V': pversion = 1; break;
+ case '?':
+ default:
+ quit(-1, "bad or missing command line argument");
+ }
+ }
+
+ if (pversion) {
+ quit(0, "%s\n%s", _mytinfo_version, SCCSid);
+ }
+
+ if (optind == argc - 1)
+ file = argv[optind];
+ else if (optind != argc)
+ quit(-1, "wrong number of arguments");
+
+ if (from_tbin + from_tcap + from_tinfo > 1)
+ quit(-1, "more than one input file type specified");
+
+ if (!from_tcap && !from_tinfo && !from_tbin && file != NULL) {
+ if (strcmp(prg_name, "cap2info") == 0
+ || strcmp(prg_name, "captoinfo") == 0)
+ from_tcap = 1;
+ else if (strcmp(prg_name, "tic") == 0)
+ from_tinfo = 1;
+ else
+ quit(-1, "no input file type specified");
+ }
+
+ if (from_tbin && compile)
+ quit(-1, "can't convert from binary to binary");
+
+ if (file != NULL) {
+ if (from_tbin) {
+ cleanup = do_cleanup;
+ convbinfile(file);
+ exit(0);
+ }
+ if (!compile)
+ path = _buildpath(file, 0, NULL, -1);
+ else {
+ path = _buildpath(file, 0,
+ "$TERMINFO", 2,
+ "$MYTERMINFO", 2,
+#ifdef TERMINFODIR
+ TERMINFODIR, 0,
+#endif
+ NULL, -1);
+ }
+ if (path == NULL)
+ quit(-1, "can't build path");
+ if (term == NULL) {
+ cleanup = do_cleanup;
+ if (from_tcap && !compile)
+ convtcfile(file);
+ else
+ convtifile(file);
+ exit(0);
+ }
+ } else if (from_tcap && !compile)
+ path = _buildpath("$TERMCAP", 1,
+#ifdef TERMCAPFILE
+ TERMCAPFILE, 0,
+#endif
+ NULL, -1);
+ else if (from_tinfo || from_tbin)
+ path = _buildpath("$TERMINFO", 2,
+ "$MYTERMINFO", 2,
+#ifdef TERMINFODIR
+ TERMINFODIR, 0,
+#endif
+#ifdef TERMINFOSRC
+ TERMINFOSRC, 0,
+#endif
+ NULL, -1);
+ else if (from_tcap)
+ path = _buildpath("$TERMCAP", 1,
+#ifdef TERMCAPFILE
+ TERMCAPFILE, 0,
+#endif
+ "$TERMINFO", 2,
+ "$MYTERMINFO", 2,
+#ifdef TERMINFODIR
+ TERMINFODIR, 0,
+#endif
+ NULL, -1);
+ else
+ path = _buildpath(
+#ifdef USE_TERMINFO
+ "$MYTERMINFO", 2,
+ "$TERMINFO", 2,
+#ifdef TERMINFODIR
+ TERMINFODIR, 0,
+#endif
+#ifdef TERMINFOSRC
+ TERMINFOSRC, 0,
+#endif
+#endif
+#ifdef USE_TERMCAP
+ "$TERMCAP", 1,
+#ifdef TERMCAPFILE
+ TERMCAPFILE, 0,
+#endif
+#endif
+ NULL, -1);
+ if (term == NULL) {
+ term = getenv("TERM");
+ if (term == NULL)
+ quit(-1, "no terminal type given");
+ }
+
+ cleanup = do_cleanup;
+
+ r = _findterm(term, path, buf);
+ switch(r) {
+ case 1:
+ convtcap();
+ break;
+ case 2:
+ convtinfo();
+ break;
+ case 3:
+ if (compile)
+ quit(-1, "entry is already compiled");
+ convtbin();
+ break;
+ default:
+ quit(-1, "can't find a terminal entry for '%s'", term);
+ }
+
+ exit(0);
+ return 0;
+}
diff --git a/usr.bin/tcopy/tcopy.c b/usr.bin/tcopy/tcopy.c
index d54fc68..3508372 100644
--- a/usr.bin/tcopy/tcopy.c
+++ b/usr.bin/tcopy/tcopy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1985, 1987, 1993, 1995
+ * Copyright (c) 1985, 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95";
+static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94";
#endif /* not lint */
#include <sys/types.h>
@@ -46,7 +46,6 @@ static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95";
#include <sys/ioctl.h>
#include <sys/mtio.h>
-#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
@@ -61,8 +60,7 @@ static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95";
#define NOCOUNT (-2)
int filen, guesslen, maxblk = MAXREC;
-long lastrec, record;
-off_t size, tsize;
+u_long lastrec, record, size, tsize;
FILE *msg = stdout;
void *getspace __P((int));
@@ -76,14 +74,14 @@ main(argc, argv)
int argc;
char *argv[];
{
- int ch, needeof, nw, inp, outp;
- ssize_t lastnread, nread;
+ register int lastnread, nread, nw, inp, outp;
enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
sig_t oldsig;
+ int ch, needeof;
char *buff, *inf;
guesslen = 1;
- while ((ch = getopt(argc, argv, "cs:vx")) != EOF)
+ while ((ch = getopt(argc, argv, "cs:vx")) != -1)
switch((char)ch) {
case 'c':
op = COPYVERIFY;
@@ -91,7 +89,7 @@ main(argc, argv)
case 's':
maxblk = atoi(optarg);
if (maxblk <= 0) {
- warnx("illegal block size");
+ fprintf(stderr, "tcopy: illegal block size\n");
usage();
}
guesslen = 0;
@@ -126,15 +124,18 @@ main(argc, argv)
inf = argv[0];
if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
- err(3, argv[1]);
+ perror(argv[1]);
+ exit(3);
}
break;
default:
usage();
}
- if ((inp = open(inf, O_RDONLY, 0)) < 0)
- err(1, inf);
+ if ((inp = open(inf, O_RDONLY, 0)) < 0) {
+ perror(inf);
+ exit(1);
+ }
buff = getspace(maxblk);
@@ -154,8 +155,10 @@ main(argc, argv)
if (nread >= 0)
goto r1;
}
- err(1, "read error, file %d, record %ld",
+ fprintf(stderr, "read error, file %d, record %ld: ",
filen, record);
+ perror("");
+ exit(1);
} else if (nread != lastnread) {
if (lastnread != 0 && lastnread != NOCOUNT) {
if (lastrec == 0 && nread == 0)
@@ -181,13 +184,11 @@ r1: guesslen = 0;
}
nw = write(outp, buff, nread);
if (nw != nread) {
- int error = errno;
fprintf(stderr,
"write error, file %d, record %ld: ",
filen, record);
if (nw == -1)
- fprintf(stderr,
- ": %s", strerror(error));
+ perror("");
else
fprintf(stderr,
"write (%d) != read (%d)\n",
@@ -204,7 +205,7 @@ r1: guesslen = 0;
break;
}
fprintf(msg,
- "file %d: eof after %ld records: %qd bytes\n",
+ "file %d: eof after %lu records: %lu bytes\n",
filen, record, size);
needeof = 1;
filen++;
@@ -214,7 +215,7 @@ r1: guesslen = 0;
}
lastnread = nread;
}
- fprintf(msg, "total length: %qd bytes\n", tsize);
+ fprintf(msg, "total length: %lu bytes\n", tsize);
(void)signal(SIGINT, oldsig);
if (op == COPY || op == COPYVERIFY) {
writeop(outp, MTWEOF);
@@ -230,11 +231,11 @@ r1: guesslen = 0;
void
verify(inp, outp, outb)
- int inp, outp;
- char *outb;
+ register int inp, outp;
+ register char *outb;
{
- int eot, inmaxblk, inn, outmaxblk, outn;
- char *inb;
+ register int eot, inmaxblk, inn, outmaxblk, outn;
+ register char *inb;
inb = getspace(maxblk);
inmaxblk = outmaxblk = maxblk;
@@ -246,7 +247,7 @@ verify(inp, outp, outb)
if (inn >= 0)
goto r1;
}
- warn("read error");
+ perror("tcopy: read error");
break;
}
r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
@@ -256,7 +257,7 @@ r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
if (outn >= 0)
goto r2;
}
- warn("read error");
+ perror("tcopy: read error");
break;
}
r2: if (inn != outn) {
@@ -267,15 +268,13 @@ r2: if (inn != outn) {
}
if (!inn) {
if (eot++) {
- fprintf(msg, "%s: tapes are identical.\n",
- "tcopy");
+ fprintf(msg, "tcopy: tapes are identical.\n");
return;
}
} else {
if (bcmp(inb, outb, inn)) {
fprintf(msg,
- "%s: tapes have different data.\n",
- "tcopy");
+ "tcopy: tapes have different data.\n");
break;
}
eot = 0;
@@ -294,7 +293,7 @@ intr(signo)
else
fprintf(msg, "record %ld\n", lastrec);
fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
- fprintf(msg, "total length: %qd bytes\n", tsize + size);
+ fprintf(msg, "total length: %ld bytes\n", tsize + size);
exit(1);
}
@@ -304,9 +303,10 @@ getspace(blk)
{
void *bp;
- if ((bp = malloc((size_t)blk)) == NULL)
- errx(11, "no memory");
-
+ if ((bp = malloc((size_t)blk)) == NULL) {
+ fprintf(stderr, "tcopy: no memory\n");
+ exit(11);
+ }
return (bp);
}
@@ -318,14 +318,15 @@ writeop(fd, type)
op.mt_op = type;
op.mt_count = (daddr_t)1;
- if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
- err(6, "tape op");
+ if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
+ perror("tcopy: tape op");
+ exit(6);
+ }
}
void
usage()
{
-
fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
exit(1);
}
diff --git a/usr.bin/tee/tee.c b/usr.bin/tee/tee.c
index ad1110a..1008973 100644
--- a/usr.bin/tee/tee.c
+++ b/usr.bin/tee/tee.c
@@ -74,7 +74,7 @@ main(argc, argv)
#define BSIZE (8 * 1024)
append = 0;
- while ((ch = getopt(argc, argv, "ai")) != EOF)
+ while ((ch = getopt(argc, argv, "ai")) != -1)
switch((char)ch) {
case 'a':
append = 1;
diff --git a/usr.bin/telnet/Makefile b/usr.bin/telnet/Makefile
index 2e38a28..a7a1f02 100644
--- a/usr.bin/telnet/Makefile
+++ b/usr.bin/telnet/Makefile
@@ -35,15 +35,17 @@
PROG= telnet
-CFLAGS+=-DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DAUTHENTICATION -DENCRYPTION
+CFLAGS+=-DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO #-DAUTHENTICATION -DENCRYPTION
CFLAGS+=-DENV_HACK
+CFLAGS+=-DSKEY
CFLAGS+=-I${.CURDIR}/../../lib
-CFLAGS+= -DKRB4
+#CFLAGS+= -DKRB4
+DPADD= ${LIBTERMCAP} ${LIBTELNET}
LDADD= -ltermcap -ltelnet
-LDADD+= -lkrb -ldes
-DPADD= ${LIBTERMCAP}
+#DPADD+= ${LIBKRB} ${LIBDES}
+#LDADD+= -lkrb -ldes
SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c telnet.c \
terminal.c tn3270.c utilities.c
@@ -56,18 +58,4 @@ NOCRYPT_DIR=${.CURDIR}/Nocrypt
.include <bsd.prog.mk>
nocrypt:
-#ifdef ENCRYPTION
- @for i in ${CRYPT_SRC}; do \
- if [ ! -d ${NOCRYPT_DIR} ]; then \
- echo Creating subdirectory ${NOCRYPT_DIR}; \
- mkdir ${NOCRYPT_DIR}; \
- fi; \
- echo ${NOCRYPT_DIR}/$$i; \
- unifdef -UENCRYPTION ${.CURDIR}/$$i | \
- sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \
- done
-
-placeholder:
-#else /* ENCRYPTION */
@echo "Encryption code already removed."
-#endif /* ENCRYPTION */
diff --git a/usr.bin/telnet/authenc.c b/usr.bin/telnet/authenc.c
index 545df78..941a202 100644
--- a/usr.bin/telnet/authenc.c
+++ b/usr.bin/telnet/authenc.c
@@ -35,7 +35,7 @@
static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
#include <sys/types.h>
#include <arpa/telnet.h>
#include <libtelnet/encrypt.h>
@@ -64,12 +64,6 @@ net_write(str, len)
void
net_encrypt()
{
-#ifdef ENCRYPTION
- if (encrypt_output)
- ring_encrypt(&netoring, encrypt_output);
- else
- ring_clearto(&netoring);
-#endif /* ENCRYPTION */
}
int
@@ -108,4 +102,4 @@ telnet_gets(prompt, result, length, echo)
TerminalNewMode(om);
return(res);
}
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+#endif /* defined(AUTHENTICATION) */
diff --git a/usr.bin/telnet/commands.c b/usr.bin/telnet/commands.c
index 41ef5cd..6e955de 100644
--- a/usr.bin/telnet/commands.c
+++ b/usr.bin/telnet/commands.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)commands.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#if defined(unix)
@@ -76,9 +76,9 @@ static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
#include <netinet/ip.h>
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 64
-#endif MAXHOSTNAMELEN
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif MAXHOSTNAMELEN
#if defined(IPPROTO_IP) && defined(IP_TOS)
int tos = -1;
@@ -107,6 +107,37 @@ static char saveline[256];
static int margc;
static char *margv[20];
+#if defined(SKEY)
+#include <sys/wait.h>
+#define PATH_SKEY "/usr/bin/key"
+ int
+skey_calc(argc, argv)
+ int argc;
+ char **argv;
+{
+ int status;
+
+ if(argc != 3) {
+ printf("%s sequence challenge\n", argv[0]);
+ return;
+ }
+
+ switch(fork()) {
+ case 0:
+ execv(PATH_SKEY, argv);
+ exit (1);
+ case -1:
+ perror("fork");
+ break;
+ default:
+ (void) wait(&status);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ return (0);
+ }
+}
+#endif
+
static void
makeargv()
{
@@ -499,7 +530,7 @@ togdebug()
}
#else /* NOT43 */
if (debug) {
- if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+ if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
perror("setsockopt (SO_DEBUG)");
} else
printf("Cannot turn off socket debugging\n");
@@ -619,12 +650,6 @@ static int togglehelp P((void));
#if defined(AUTHENTICATION)
extern int auth_togdebug P((int));
#endif
-#ifdef ENCRYPTION
-extern int EncryptAutoEnc P((int));
-extern int EncryptAutoDec P((int));
-extern int EncryptDebug P((int));
-extern int EncryptVerbose P((int));
-#endif /* ENCRYPTION */
struct togglelist {
char *name; /* name of toggle */
@@ -657,28 +682,6 @@ static struct togglelist Togglelist[] = {
0,
"print authentication debugging information" },
#endif
-#ifdef ENCRYPTION
- { "autoencrypt",
- "automatic encryption of data stream",
- EncryptAutoEnc,
- 0,
- "automatically encrypt output" },
- { "autodecrypt",
- "automatic decryption of data stream",
- EncryptAutoDec,
- 0,
- "automatically decrypt input" },
- { "verbose_encrypt",
- "Toggle verbose encryption output",
- EncryptVerbose,
- 0,
- "print verbose encryption output" },
- { "encdebug",
- "Toggle encryption debugging",
- EncryptDebug,
- 0,
- "print encryption debugging information" },
-#endif /* ENCRYPTION */
{ "skiprc",
"don't read ~/.telnetrc file",
0,
@@ -1296,9 +1299,6 @@ display(argc, argv)
}
}
/*@*/optionstatus();
-#ifdef ENCRYPTION
- EncryptStatus();
-#endif /* ENCRYPTION */
return 1;
#undef doset
#undef dotog
@@ -1363,7 +1363,7 @@ suspend()
(void) kill(0, SIGTSTP);
/*
* If we didn't get the window size before the SUSPEND, but we
- * can get them now (?), then send the NAWS to make sure that
+ * can get them now (???), then send the NAWS to make sure that
* we are set up for the right window size.
*/
if (TerminalWindowSize(&newrows, &newcols) && connected &&
@@ -1403,12 +1403,12 @@ shell(argc, argv)
* Fire up the shell in the child.
*/
register char *shellp, *shellname;
- extern char *strrchr();
+ extern char *rindex();
shellp = getenv("SHELL");
if (shellp == NULL)
shellp = "/bin/sh";
- if ((shellname = strrchr(shellp, '/')) == 0)
+ if ((shellname = rindex(shellp, '/')) == 0)
shellname = shellp;
else
shellname++;
@@ -1448,9 +1448,9 @@ bye(argc, argv)
(void) NetClose(net);
connected = 0;
resettermname = 1;
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
auth_encrypt_connect(connected);
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+#endif /* defined(AUTHENTICATION) */
/* reset options */
tninit();
#if defined(TN3270)
@@ -1544,14 +1544,14 @@ slccmd(argc, argv)
}
c = getslc(argv[1]);
if (c == 0) {
- fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
+ fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
if (Ambiguous(c)) {
- fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
+ fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
(*c->handler)(c->arg);
slcstate();
@@ -1640,14 +1640,14 @@ env_cmd(argc, argv)
}
c = getenvcmd(argv[1]);
if (c == 0) {
- fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
+ fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
if (Ambiguous(c)) {
- fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
+ fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
if (c->narg + 2 != argc) {
fprintf(stderr,
@@ -1690,10 +1690,10 @@ env_init()
extern char **environ;
register char **epp, *cp;
register struct env_lst *ep;
- extern char *strchr();
+ extern char *index();
for (epp = environ; *epp; epp++) {
- if (cp = strchr(*epp, '=')) {
+ if (cp = index(*epp, '=')) {
*cp = '\0';
ep = env_define((unsigned char *)*epp,
(unsigned char *)cp+1);
@@ -1708,9 +1708,9 @@ env_init()
*/
if ((ep = env_find("DISPLAY"))
&& ((*ep->value == ':')
- || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
+ || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
char hbuf[256+1];
- char *cp2 = strchr((char *)ep->value, ':');
+ char *cp2 = index((char *)ep->value, ':');
gethostname(hbuf, 256);
hbuf[256] = '\0';
@@ -1802,7 +1802,7 @@ env_send(var)
{
register struct env_lst *ep;
- if (my_state_is_wont(TELOPT_NEW_ENVIRON)
+ if (my_state_is_wont(TELOPT_NEW_ENVIRON)
#ifdef OLD_ENVIRON
&& my_state_is_wont(TELOPT_OLD_ENVIRON)
#endif
@@ -1915,8 +1915,8 @@ struct authlist {
};
extern int
- auth_enable P((char *)),
- auth_disable P((char *)),
+ auth_enable P((int)),
+ auth_disable P((int)),
auth_status P((void));
static int
auth_help P((void));
@@ -1955,23 +1955,17 @@ auth_cmd(argc, argv)
{
struct authlist *c;
- if (argc < 2) {
- fprintf(stderr,
- "Need an argument to 'auth' command. 'auth ?' for help.\n");
- return 0;
- }
-
c = (struct authlist *)
genget(argv[1], (char **) AuthList, sizeof(struct authlist));
if (c == 0) {
- fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
+ fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
if (Ambiguous(c)) {
- fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
+ fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
argv[1]);
- return 0;
+ return 0;
}
if (c->narg + 2 != argc) {
fprintf(stderr,
@@ -1984,126 +1978,6 @@ auth_cmd(argc, argv)
}
#endif
-#ifdef ENCRYPTION
-/*
- * The ENCRYPT command.
- */
-
-struct encryptlist {
- char *name;
- char *help;
- int (*handler)();
- int needconnect;
- int minarg;
- int maxarg;
-};
-
-extern int
- EncryptEnable P((char *, char *)),
- EncryptDisable P((char *, char *)),
- EncryptType P((char *, char *)),
- EncryptStart P((char *)),
- EncryptStartInput P((void)),
- EncryptStartOutput P((void)),
- EncryptStop P((char *)),
- EncryptStopInput P((void)),
- EncryptStopOutput P((void)),
- EncryptStatus P((void));
-static int
- EncryptHelp P((void));
-
-struct encryptlist EncryptList[] = {
- { "enable", "Enable encryption. ('encrypt enable ?' for more)",
- EncryptEnable, 1, 1, 2 },
- { "disable", "Disable encryption. ('encrypt enable ?' for more)",
- EncryptDisable, 0, 1, 2 },
- { "type", "Set encryption type. ('encrypt type ?' for more)",
- EncryptType, 0, 1, 1 },
- { "start", "Start encryption. ('encrypt start ?' for more)",
- EncryptStart, 1, 0, 1 },
- { "stop", "Stop encryption. ('encrypt stop ?' for more)",
- EncryptStop, 1, 0, 1 },
- { "input", "Start encrypting the input stream",
- EncryptStartInput, 1, 0, 0 },
- { "-input", "Stop encrypting the input stream",
- EncryptStopInput, 1, 0, 0 },
- { "output", "Start encrypting the output stream",
- EncryptStartOutput, 1, 0, 0 },
- { "-output", "Stop encrypting the output stream",
- EncryptStopOutput, 1, 0, 0 },
-
- { "status", "Display current status of authentication information",
- EncryptStatus, 0, 0, 0 },
- { "help", 0, EncryptHelp, 0, 0, 0 },
- { "?", "Print help information", EncryptHelp, 0, 0, 0 },
- { 0 },
-};
-
- static int
-EncryptHelp()
-{
- struct encryptlist *c;
-
- for (c = EncryptList; c->name; c++) {
- if (c->help) {
- if (*c->help)
- printf("%-15s %s\n", c->name, c->help);
- else
- printf("\n");
- }
- }
- return 0;
-}
-
-encrypt_cmd(argc, argv)
- int argc;
- char *argv[];
-{
- struct encryptlist *c;
-
- if (argc < 2) {
- fprintf(stderr,
- "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n");
- return 0;
- }
-
- c = (struct encryptlist *)
- genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
- if (c == 0) {
- fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
- argv[1]);
- return 0;
- }
- if (Ambiguous(c)) {
- fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
- argv[1]);
- return 0;
- }
- argc -= 2;
- if (argc < c->minarg || argc > c->maxarg) {
- if (c->minarg == c->maxarg) {
- fprintf(stderr, "Need %s%d argument%s ",
- c->minarg < argc ? "only " : "", c->minarg,
- c->minarg == 1 ? "" : "s");
- } else {
- fprintf(stderr, "Need %s%d-%d arguments ",
- c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
- }
- fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
- c->name);
- return 0;
- }
- if (c->needconnect && !connected) {
- if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
- printf("?Need to be connected first.\n");
- return 0;
- }
- }
- return ((*c->handler)(argc > 0 ? argv[2] : 0,
- argc > 1 ? argv[3] : 0,
- argc > 2 ? argv[4] : 0));
-}
-#endif /* ENCRYPTION */
#if defined(unix) && defined(TN3270)
static void
@@ -2170,9 +2044,6 @@ status(argc, argv)
printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
if (my_want_state_is_will(TELOPT_LFLOW))
printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
-#ifdef ENCRYPTION
- encrypt_display();
-#endif /* ENCRYPTION */
}
} else {
printf("No connection.\n");
@@ -2240,7 +2111,7 @@ tn(argc, argv)
char *cmd, *hostp = 0, *portp = 0, *user = 0;
/* clear the socket address prior to use */
- memset((char *)&sin, 0, sizeof(sin));
+ bzero((char *)&sin, sizeof(sin));
if (connected) {
printf("?Already connected to %s\n", hostname);
@@ -2258,7 +2129,7 @@ tn(argc, argv)
cmd = *argv;
--argc; ++argv;
while (argc) {
- if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
+ if (isprefix(*argv, "help") || isprefix(*argv, "?"))
goto usage;
if (strcmp(*argv, "-l") == 0) {
--argc; ++argv;
@@ -2313,10 +2184,15 @@ tn(argc, argv)
} else {
#endif
temp = inet_addr(hostp);
- if (temp != (unsigned long) -1) {
+ if (temp != INADDR_NONE) {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
- (void) strcpy(_hostname, hostp);
+ host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
+ if (host)
+ (void) strncpy(_hostname, host->h_name, sizeof(_hostname));
+ else
+ (void) strncpy(_hostname, hostp, sizeof(_hostname));
+ _hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
host = gethostbyname(hostp);
@@ -2333,7 +2209,7 @@ tn(argc, argv)
hostname = _hostname;
} else {
herror(hostp);
- setuid(getuid());
+ setuid(getuid());
return 0;
}
}
@@ -2353,7 +2229,7 @@ tn(argc, argv)
sin.sin_port = sp->s_port;
else {
printf("%s: bad port number\n", portp);
- setuid(getuid());
+ setuid(getuid());
return 0;
}
} else {
@@ -2367,7 +2243,7 @@ tn(argc, argv)
sp = getservbyname("telnet", "tcp");
if (sp == 0) {
fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
- setuid(getuid());
+ setuid(getuid());
return 0;
}
sin.sin_port = sp->s_port;
@@ -2394,7 +2270,7 @@ tn(argc, argv)
tos = tp->t_tos;
# endif
if (tos < 0)
- tos = 020; /* Low Delay bit */
+ tos = IPTOS_LOWDELAY;
if (tos
&& (setsockopt(net, IPPROTO_IP, IP_TOS,
(char *)&tos, sizeof(int)) < 0)
@@ -2417,7 +2293,7 @@ tn(argc, argv)
errno = oerrno;
perror((char *)0);
host->h_addr_list++;
- memmove((caddr_t)&sin.sin_addr,
+ memcpy((caddr_t)&sin.sin_addr,
host->h_addr_list[0], host->h_length);
(void) NetClose(net);
continue;
@@ -2427,9 +2303,9 @@ tn(argc, argv)
return 0;
}
connected++;
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
auth_encrypt_connect(connected);
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+#endif /* defined(AUTHENTICATION) */
} while (connected == 0);
cmdrc(hostp, hostname);
if (autologin && user == NULL) {
@@ -2477,12 +2353,12 @@ static char
#if defined(AUTHENTICATION)
authhelp[] = "turn on (off) authentication ('auth ?' for more)",
#endif
-#ifdef ENCRYPTION
- encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
-#endif /* ENCRYPTION */
#if defined(unix)
zhelp[] = "suspend telnet",
#endif /* defined(unix) */
+#if defined(SKEY)
+ skeyhelp[] = "compute response to s/key challenge",
+#endif
shellhelp[] = "invoke a subshell",
envhelp[] = "change environment variables ('environ ?' for more)",
modestring[] = "try to enter line or character mode ('mode ?' for more)";
@@ -2494,6 +2370,7 @@ static Command cmdtab[] = {
{ "logout", logouthelp, logout, 1 },
{ "display", displayhelp, display, 0 },
{ "mode", modestring, modecmd, 0 },
+ { "telnet", openhelp, tn, 0 },
{ "open", openhelp, tn, 0 },
{ "quit", quithelp, quit, 0 },
{ "send", sendhelp, sendcmd, 0 },
@@ -2508,9 +2385,6 @@ static Command cmdtab[] = {
#if defined(AUTHENTICATION)
{ "auth", authhelp, auth_cmd, 0 },
#endif
-#ifdef ENCRYPTION
- { "encrypt", encrypthelp, encrypt_cmd, 0 },
-#endif /* ENCRYPTION */
#if defined(unix)
{ "z", zhelp, suspend, 0 },
#endif /* defined(unix) */
@@ -2521,6 +2395,9 @@ static Command cmdtab[] = {
#endif
{ "environ", envhelp, env_cmd, 0 },
{ "?", helphelp, help, 0 },
+#if defined(SKEY)
+ { "skey", skeyhelp, skey_calc, 0 },
+#endif
0
};
@@ -2601,7 +2478,7 @@ command(top, tbuf, cnt)
goto getline;
*cp = '\0';
if (rlogin == _POSIX_VDISABLE)
- printf("%s\n", line);
+ printf("%s\n", line);
} else {
getline:
if (rlogin != _POSIX_VDISABLE)
@@ -2706,7 +2583,7 @@ cmdrc(m1, m2)
if (rcname == 0) {
rcname = getenv("HOME");
- if (rcname)
+ if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
strcpy(rcbuf, rcname);
else
rcbuf[0] = '\0';
@@ -2901,16 +2778,16 @@ sourceroute(arg, cpp, lenp)
sin_addr.s_addr = tmp;
} else if (host = gethostbyname(cp)) {
#if defined(h_addr)
- memmove((caddr_t)&sin_addr,
+ memcpy((caddr_t)&sin_addr,
host->h_addr_list[0], host->h_length);
#else
- memmove((caddr_t)&sin_addr, host->h_addr, host->h_length);
+ memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
#endif
} else {
*cpp = cp;
return(0);
}
- memmove(lsrp, (char *)&sin_addr, 4);
+ memcpy(lsrp, (char *)&sin_addr, 4);
lsrp += 4;
if (cp2)
cp = cp2;
diff --git a/usr.bin/telnet/externs.h b/usr.bin/telnet/externs.h
index 83ba07b..43fdb43 100644
--- a/usr.bin/telnet/externs.h
+++ b/usr.bin/telnet/externs.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)externs.h 8.3 (Berkeley) 5/30/95
+ * @(#)externs.h 8.2 (Berkeley) 12/15/93
*/
#ifndef BSD
@@ -83,9 +83,8 @@ typedef unsigned char cc_t;
#ifndef NO_STRING_H
#include <string.h>
-#else
-#include <strings.h>
#endif
+#include <strings.h>
#ifndef _POSIX_VDISABLE
# ifdef sun
@@ -119,12 +118,12 @@ extern int
flushout, /* flush output */
connected, /* Are we connected to the other side? */
globalmode, /* Mode tty should be in */
- In3270, /* Are we in 3270 mode? */
+ In3270, /* Are we in 3270 mode? */
telnetport, /* Are we connected to the telnet port? */
localflow, /* Flow control handled locally */
restartany, /* If flow control, restart output on any character */
localchars, /* we recognize interrupt/quit */
- donelclchars, /* the user has set "localchars" */
+ donelclchars, /* the user has set "localchars" */
showoptions,
net, /* Network file descriptor */
tin, /* Terminal input file descriptor */
@@ -145,7 +144,8 @@ extern int
#endif /* defined(TN3270) */
termdata, /* Print out terminal data flow */
#endif /* defined(unix) */
- debug; /* Debug level */
+ debug, /* Debug level */
+ clienteof; /* Client received EOF */
extern cc_t escape; /* Escape to command mode */
extern cc_t rlogin; /* Rlogin mode escape character */
@@ -163,10 +163,6 @@ extern char
wont[],
options[], /* All the little options */
*hostname; /* Who are we connected to? */
-#ifdef ENCRYPTION
-extern void (*encrypt_output) P((unsigned char *, int));
-extern int (*decrypt_input) P((int));
-#endif /* ENCRYPTION */
/*
* We keep track of each side of the option negotiation.
diff --git a/usr.bin/telnet/main.c b/usr.bin/telnet/main.c
index 6073dbf..3c4d8df 100644
--- a/usr.bin/telnet/main.c
+++ b/usr.bin/telnet/main.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include <sys/types.h>
@@ -49,8 +49,8 @@ static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
/* These values need to be the same as defined in libtelnet/kerberos5.c */
/* Either define them in both places, or put in some common header file. */
-#define OPTS_FORWARD_CREDS 0x00000002
-#define OPTS_FORWARDABLE_CREDS 0x00000001
+#define OPTS_FORWARD_CREDS 0x00000002
+#define OPTS_FORWARDABLE_CREDS 0x00000001
#if 0
#define FORWARD
@@ -96,11 +96,7 @@ usage()
#else
"[-r] ",
#endif
-#ifdef ENCRYPTION
- "[-x] [host-name [port]]"
-#else /* ENCRYPTION */
"[host-name [port]]"
-#endif /* ENCRYPTION */
);
exit(1);
}
@@ -139,7 +135,7 @@ main(argc, argv)
rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
autologin = -1;
- while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) {
+ while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != -1) {
switch(ch) {
case '8':
eight = 3; /* binary output and input */
@@ -267,14 +263,9 @@ main(argc, argv)
#endif
break;
case 'x':
-#ifdef ENCRYPTION
- encrypt_auto(1);
- decrypt_auto(1);
-#else /* ENCRYPTION */
fprintf(stderr,
"%s: Warning: -x ignored, no ENCRYPT support.\n",
prompt);
-#endif /* ENCRYPTION */
break;
case '?':
default:
diff --git a/usr.bin/telnet/network.c b/usr.bin/telnet/network.c
index 0fe5cee..60e8591 100644
--- a/usr.bin/telnet/network.c
+++ b/usr.bin/telnet/network.c
@@ -128,10 +128,6 @@ netflush()
{
register int n, n1;
-#ifdef ENCRYPTION
- if (encrypt_output)
- ring_encrypt(&netoring, encrypt_output);
-#endif /* ENCRYPTION */
if ((n1 = n = ring_full_consecutive(&netoring)) > 0) {
if (!ring_at_mark(&netoring)) {
n = send(net, (char *)netoring.consume, n, 0); /* normal write */
diff --git a/usr.bin/telnet/ring.c b/usr.bin/telnet/ring.c
index 37dfda8..6de5a67 100644
--- a/usr.bin/telnet/ring.c
+++ b/usr.bin/telnet/ring.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)ring.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
@@ -112,9 +112,6 @@ Ring *ring;
ring->top = ring->bottom+ring->size;
-#ifdef ENCRYPTION
- ring->clearto = 0;
-#endif /* ENCRYPTION */
return 1;
}
@@ -185,15 +182,6 @@ ring_consumed(ring, count)
(ring_subtract(ring, ring->mark, ring->consume) < count)) {
ring->mark = 0;
}
-#ifdef ENCRYPTION
- if (ring->consume < ring->clearto &&
- ring->clearto <= ring->consume + count)
- ring->clearto = 0;
- else if (ring->consume + count > ring->top &&
- ring->bottom <= ring->clearto &&
- ring->bottom + ((ring->consume + count) - ring->top))
- ring->clearto = 0;
-#endif /* ENCRYPTION */
ring->consume = ring_increment(ring, ring->consume, count);
ring->consumetime = ++ring_clock;
/*
@@ -295,7 +283,7 @@ ring_supply_data(ring, buffer, count)
while (count) {
i = MIN(count, ring_empty_consecutive(ring));
- memmove(ring->supply, buffer, i);
+ memcpy(ring->supply, buffer, i);
ring_supplied(ring, i);
count -= i;
buffer += i;
@@ -317,7 +305,7 @@ ring_consume_data(ring, buffer, count)
while (count) {
i = MIN(count, ring_full_consecutive(ring));
- memmove(buffer, ring->consume, i);
+ memcpy(buffer, ring->consume, i);
ring_consumed(ring, i);
count -= i;
buffer += i;
@@ -325,38 +313,3 @@ ring_consume_data(ring, buffer, count)
}
#endif
-#ifdef ENCRYPTION
- void
-ring_encrypt(ring, encryptor)
- Ring *ring;
- void (*encryptor)();
-{
- unsigned char *s, *c;
-
- if (ring_empty(ring) || ring->clearto == ring->supply)
- return;
-
- if (!(c = ring->clearto))
- c = ring->consume;
-
- s = ring->supply;
-
- if (s <= c) {
- (*encryptor)(c, ring->top - c);
- (*encryptor)(ring->bottom, s - ring->bottom);
- } else
- (*encryptor)(c, s - c);
-
- ring->clearto = ring->supply;
-}
-
- void
-ring_clearto(ring)
- Ring *ring;
-{
- if (!ring_empty(ring))
- ring->clearto = ring->supply;
- else
- ring->clearto = 0;
-}
-#endif /* ENCRYPTION */
diff --git a/usr.bin/telnet/ring.h b/usr.bin/telnet/ring.h
index 2a36781..cc2cb12 100644
--- a/usr.bin/telnet/ring.h
+++ b/usr.bin/telnet/ring.h
@@ -59,10 +59,6 @@ typedef struct {
*bottom, /* lowest address in buffer */
*top, /* highest address+1 in buffer */
*mark; /* marker (user defined) */
-#ifdef ENCRYPTION
- unsigned char *clearto; /* Data to this point is clear text */
- unsigned char *encryyptedto; /* Data is encrypted to here */
-#endif /* ENCRYPTION */
int size; /* size in bytes of buffer */
u_long consumetime, /* help us keep straight full, empty, etc. */
supplytime;
@@ -94,11 +90,6 @@ extern int
ring_full_count P((Ring *ring)),
ring_full_consecutive P((Ring *ring));
-#ifdef ENCRYPTION
-extern void
- ring_encrypt P((Ring *ring, void (*func)())),
- ring_clearto P((Ring *ring));
-#endif /* ENCRYPTION */
extern void
ring_clear_mark(),
diff --git a/usr.bin/telnet/sys_bsd.c b/usr.bin/telnet/sys_bsd.c
index 281b8bd..beddb64 100644
--- a/usr.bin/telnet/sys_bsd.c
+++ b/usr.bin/telnet/sys_bsd.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)sys_bsd.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
/*
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
#include <signal.h>
#include <errno.h>
#include <arpa/telnet.h>
+#include <unistd.h>
#include "ring.h"
@@ -328,7 +329,7 @@ TerminalDefaultChars()
nttyb.sg_kill = ottyb.sg_kill;
nttyb.sg_erase = ottyb.sg_erase;
#else /* USE_TERMIO */
- memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
+ memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
# ifndef VDISCARD
termFlushChar = CONTROL('O');
# endif
@@ -669,11 +670,7 @@ TerminalNewMode(f)
#endif
#ifdef SIGTSTP
(void) signal(SIGTSTP, SIG_DFL);
-# ifndef SOLARIS
(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
-# else SOLARIS
- (void) sigrelse(SIGTSTP);
-# endif SOLARIS
#endif /* SIGTSTP */
#ifndef USE_TERMIO
ltc = oltc;
@@ -716,43 +713,14 @@ TerminalNewMode(f)
#endif
#ifdef DECODE_BAUD
-#ifndef B7200
-#define B7200 B4800
-#endif
-
-#ifndef B14400
-#define B14400 B9600
-#endif
-
#ifndef B19200
-# define B19200 B14400
-#endif
-
-#ifndef B28800
-#define B28800 B19200
+# define B19200 B9600
#endif
#ifndef B38400
-# define B38400 B28800
-#endif
-
-#ifndef B57600
-#define B57600 B38400
-#endif
-
-#ifndef B76800
-#define B76800 B57600
-#endif
-
-#ifndef B115200
-#define B115200 B76800
-#endif
-
-#ifndef B230400
-#define B230400 B115200
+# define B38400 B19200
#endif
-
/*
* This code assumes that the values B0, B50, B75...
* are in ascending order. They do not have to be
@@ -762,14 +730,12 @@ struct termspeeds {
long speed;
long value;
} termspeeds[] = {
- { 0, B0 }, { 50, B50 }, { 75, B75 },
- { 110, B110 }, { 134, B134 }, { 150, B150 },
- { 200, B200 }, { 300, B300 }, { 600, B600 },
- { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
- { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 },
- { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 },
- { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 },
- { 230400, B230400 }, { -1, B230400 }
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 },
+ { 38400, B38400 }, { -1, B38400 }
};
#endif /* DECODE_BAUD */
@@ -1051,7 +1017,7 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll)
}
# endif /* defined(TN3270) */
/* I don't like this, does it ever happen? */
- printf("sleep(5) from telnet, after select\r\n");
+ printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
sleep(5);
}
return 0;
@@ -1136,7 +1102,7 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll)
int i;
i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
if (i == c &&
- memcmp(netiring.supply, netiring.supply + c, i) == 0) {
+ bcmp(netiring.supply, netiring.supply + c, i) == 0) {
bogus_oob = 1;
first = 0;
} else if (i < 0) {
@@ -1190,14 +1156,19 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll)
if (c < 0 && errno == EWOULDBLOCK) {
c = 0;
} else {
- /* EOF detection for line mode!!!! */
- if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
+ if (c < 0) {
+ return -1;
+ }
+ if (c == 0) {
/* must be an EOF... */
+ if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
*ttyiring.supply = termEofChar;
c = 1;
+ } else {
+ clienteof = 1;
+ shutdown(net, 1);
+ return 0;
}
- if (c <= 0) {
- return -1;
}
if (termdata) {
Dump('<', ttyiring.supply, c);
diff --git a/usr.bin/telnet/telnet.1 b/usr.bin/telnet/telnet.1
index b996fea..0db8a39 100644
--- a/usr.bin/telnet/telnet.1
+++ b/usr.bin/telnet/telnet.1
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94
+.\" @(#)telnet.1 8.5 (Berkeley) 3/1/94
+.\" $Id$
.\"
-.Dd June 1, 1994
+.Dd March 1, 1994
.Dt TELNET 1
.Os BSD 4.2
.Sh NAME
@@ -139,7 +140,6 @@ there will be no escape character.
If Kerberos V5 authentication is being used, the
.Fl f
option allows the local credentials to be forwarded to the remote system.
-.ne 1i
.It Fl k Ar realm
If Kerberos authentication is being used, the
.Fl k
@@ -509,7 +509,6 @@ option.
This requires that the
.Dv LINEMODE
option be enabled.
-.ne 1i
.It Ic litecho Pq Ic \-litecho
Attempt to enable (disable) the
.Dv LIT_ECHO
@@ -643,7 +642,6 @@ command,
.Ic getstatus
will send the subnegotiation to request that the server send
its current option status.
-.ne 1i
.It Ic ip
Sends the
.Dv TELNET IP
@@ -969,7 +967,6 @@ The initial value for the suspend character is taken to be
the terminal's
.Ic suspend
character.
-.ne 1i
.It Ic tracefile
This is the file to which the output, caused by
.Ic netdata
@@ -1003,7 +1000,7 @@ commands.
The
.Ic slc
command (Set Local Characters) is used to set
-or change the state of the the special
+or change the state of the special
characters when the
.Dv TELNET LINEMODE
option has
@@ -1112,7 +1109,6 @@ stream does not start automatically. The autoencrypt
(autodecrypt) command states that encryption of the
output (input) stream should be enabled as soon as
possible.
-.sp
.Pp
Note: Because of export controls, the
.Dv TELNET ENCRYPT
@@ -1268,7 +1264,6 @@ protocol processing (having to do with
options).
The initial value for this toggle is
.Dv FALSE .
-.ne 1i
.It Ic prettydump
When the
.Ic netdata
@@ -1343,6 +1338,13 @@ Other environment variables may be propagated
to the other side via the
.Dv TELNET ENVIRON
option.
+
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr hosts 5 ,
+.Xr nologin 5 ,
+.Xr telnetd 8
.Sh FILES
.Bl -tag -width ~/.telnetrc -compact
.It Pa ~/.telnetrc
diff --git a/usr.bin/telnet/telnet.c b/usr.bin/telnet/telnet.c
index e792262..3f735a8 100644
--- a/usr.bin/telnet/telnet.c
+++ b/usr.bin/telnet/telnet.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)telnet.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include <sys/types.h>
@@ -57,7 +57,7 @@ static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95";
#include "general.h"
-#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
+#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
static unsigned char subbuffer[SUBBUFSIZE],
*subpointer, *subend; /* buffer for sub-options */
@@ -104,7 +104,8 @@ int
donelclchars, /* the user has set "localchars" */
donebinarytoggle, /* the user has put us in binary */
dontlecho, /* do we suppress local echoing right now? */
- globalmode;
+ globalmode,
+ clienteof = 0;
char *prompt = 0;
@@ -177,9 +178,9 @@ init_telnet()
ClearArray(options);
connected = In3270 = ISend = localflow = donebinarytoggle = 0;
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
auth_encrypt_connect(connected);
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+#endif /* defined(AUTHENTICATION) */
restartany = -1;
SYNCHing = 0;
@@ -369,9 +370,6 @@ willoption(option)
#if defined(AUTHENTICATION)
case TELOPT_AUTHENTICATION:
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
-#endif /* ENCRYPTION */
new_state_ok = 1;
break;
@@ -401,10 +399,6 @@ willoption(option)
}
}
set_my_state_do(option);
-#ifdef ENCRYPTION
- if (option == TELOPT_ENCRYPT)
- encrypt_send_support();
-#endif /* ENCRYPTION */
}
void
@@ -492,9 +486,6 @@ dooption(option)
case TELOPT_LFLOW: /* local flow control */
case TELOPT_TTYPE: /* terminal type option */
case TELOPT_SGA: /* no big deal */
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT: /* encryption variable option */
-#endif /* ENCRYPTION */
new_state_ok = 1;
break;
@@ -623,7 +614,7 @@ mklist(buf, name)
register char c, *cp, **argvp, *cp2, **argv, **avt;
if (name) {
- if ((int)strlen(name) > 40) {
+ if (strlen(name) > 40) {
name = 0;
unknown[0] = name_unknown;
} else {
@@ -782,7 +773,7 @@ gettermname()
(setupterm(tname, 1, &err) == 0)) {
tnamep = mklist(termbuf, tname);
} else {
- if (tname && ((int)strlen(tname) <= 40)) {
+ if (tname && (strlen(tname) <= 40)) {
unknown[0] = tname;
upcase(tname);
} else
@@ -1004,67 +995,6 @@ suboption()
}
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- if (SB_EOF())
- return;
- switch(SB_GET()) {
- case ENCRYPT_START:
- if (my_want_state_is_dont(TELOPT_ENCRYPT))
- return;
- encrypt_start(subpointer, SB_LEN());
- break;
- case ENCRYPT_END:
- if (my_want_state_is_dont(TELOPT_ENCRYPT))
- return;
- encrypt_end();
- break;
- case ENCRYPT_SUPPORT:
- if (my_want_state_is_wont(TELOPT_ENCRYPT))
- return;
- encrypt_support(subpointer, SB_LEN());
- break;
- case ENCRYPT_REQSTART:
- if (my_want_state_is_wont(TELOPT_ENCRYPT))
- return;
- encrypt_request_start(subpointer, SB_LEN());
- break;
- case ENCRYPT_REQEND:
- if (my_want_state_is_wont(TELOPT_ENCRYPT))
- return;
- /*
- * We can always send an REQEND so that we cannot
- * get stuck encrypting. We should only get this
- * if we have been able to get in the correct mode
- * anyhow.
- */
- encrypt_request_end();
- break;
- case ENCRYPT_IS:
- if (my_want_state_is_dont(TELOPT_ENCRYPT))
- return;
- encrypt_is(subpointer, SB_LEN());
- break;
- case ENCRYPT_REPLY:
- if (my_want_state_is_wont(TELOPT_ENCRYPT))
- return;
- encrypt_reply(subpointer, SB_LEN());
- break;
- case ENCRYPT_ENC_KEYID:
- if (my_want_state_is_dont(TELOPT_ENCRYPT))
- return;
- encrypt_enc_keyid(subpointer, SB_LEN());
- break;
- case ENCRYPT_DEC_KEYID:
- if (my_want_state_is_wont(TELOPT_ENCRYPT))
- return;
- encrypt_dec_keyid(subpointer, SB_LEN());
- break;
- default:
- break;
- }
- break;
-#endif /* ENCRYPTION */
default:
break;
}
@@ -1746,10 +1676,6 @@ telrcv()
}
c = *sbp++ & 0xff, scc--; count++;
-#ifdef ENCRYPTION
- if (decrypt_input)
- c = (*decrypt_input)(c);
-#endif /* ENCRYPTION */
switch (telrcv_state) {
@@ -1774,10 +1700,6 @@ telrcv()
*Ifrontp++ = c;
while (scc > 0) {
c = *sbp++ & 0377, scc--; count++;
-#ifdef ENCRYPTION
- if (decrypt_input)
- c = (*decrypt_input)(c);
-#endif /* ENCRYPTION */
if (c == IAC) {
telrcv_state = TS_IAC;
break;
@@ -1796,10 +1718,6 @@ telrcv()
if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
if (scc > 0) {
c = *sbp&0xff;
-#ifdef ENCRYPTION
- if (decrypt_input)
- c = (*decrypt_input)(c);
-#endif /* ENCRYPTION */
if (c == 0) {
sbp++, scc--; count++;
/* a "true" CR */
@@ -1809,10 +1727,6 @@ telrcv()
sbp++, scc--; count++;
TTYADD('\n');
} else {
-#ifdef ENCRYPTION
- if (decrypt_input)
- (*decrypt_input)(-1);
-#endif /* ENCRYPTION */
TTYADD('\r');
if (crmod) {
@@ -2184,9 +2098,9 @@ Scheduler(block)
ttyout = ring_full_count(&ttyoring);
#if defined(TN3270)
- ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
+ ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0);
#else /* defined(TN3270) */
- ttyin = ring_empty_count(&ttyiring);
+ ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
#endif /* defined(TN3270) */
#if defined(TN3270)
@@ -2220,7 +2134,7 @@ Scheduler(block)
ring_full_consecutive(&ttyiring));
if (c) {
returnValue = 1;
- ring_consumed(&ttyiring, c);
+ ring_consumed(&ttyiring, c);
}
} else {
# endif /* defined(TN3270) */
@@ -2249,7 +2163,7 @@ telnet(user)
{
sys_telnet_init();
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
{
static char local_host[256] = { 0 };
@@ -2260,17 +2174,13 @@ telnet(user)
auth_encrypt_init(local_host, hostname, "TELNET", 0);
auth_encrypt_user(user);
}
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+#endif /* defined(AUTHENTICATION) */
# if !defined(TN3270)
if (telnetport) {
#if defined(AUTHENTICATION)
if (autologin)
send_will(TELOPT_AUTHENTICATION, 1);
#endif
-#ifdef ENCRYPTION
- send_do(TELOPT_ENCRYPT, 1);
- send_will(TELOPT_ENCRYPT, 1);
-#endif /* ENCRYPTION */
send_do(TELOPT_SGA, 1);
send_will(TELOPT_TTYPE, 1);
send_will(TELOPT_NAWS, 1);
@@ -2431,7 +2341,7 @@ netclear()
next = nextitem(next);
} while (wewant(next) && (nfrontp > next));
length = next-thisitem;
- memmove(good, thisitem, length);
+ memcpy(good, thisitem, length);
good += length;
thisitem = next;
} else {
diff --git a/usr.bin/telnet/terminal.c b/usr.bin/telnet/terminal.c
index b5ceeda..aeacbb0 100644
--- a/usr.bin/telnet/terminal.c
+++ b/usr.bin/telnet/terminal.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95";
+static char sccsid[] = "@(#)terminal.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <arpa/telnet.h>
@@ -206,29 +206,12 @@ getconnmode()
setconnmode(force)
int force;
{
-#ifdef ENCRYPTION
- static int enc_passwd = 0;
-#endif /* ENCRYPTION */
register int newmode;
newmode = getconnmode()|(force?MODE_FORCE:0);
TerminalNewMode(newmode);
-#ifdef ENCRYPTION
- if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
- if (my_want_state_is_will(TELOPT_ENCRYPT)
- && (enc_passwd == 0) && !encrypt_output) {
- encrypt_request_start(0, 0);
- enc_passwd = 1;
- }
- } else {
- if (enc_passwd) {
- encrypt_request_end();
- enc_passwd = 0;
- }
- }
-#endif /* ENCRYPTION */
}
diff --git a/usr.bin/telnet/utilities.c b/usr.bin/telnet/utilities.c
index 06d08a4..b645192 100644
--- a/usr.bin/telnet/utilities.c
+++ b/usr.bin/telnet/utilities.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)utilities.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#define TELOPTS
@@ -486,76 +486,6 @@ printsub(direction, pointer, length)
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- fprintf(NetTrace, "ENCRYPT");
- if (length < 2) {
- fprintf(NetTrace, " (empty suboption??\?)");
- break;
- }
- switch (pointer[1]) {
- case ENCRYPT_START:
- fprintf(NetTrace, " START");
- break;
-
- case ENCRYPT_END:
- fprintf(NetTrace, " END");
- break;
-
- case ENCRYPT_REQSTART:
- fprintf(NetTrace, " REQUEST-START");
- break;
-
- case ENCRYPT_REQEND:
- fprintf(NetTrace, " REQUEST-END");
- break;
-
- case ENCRYPT_IS:
- case ENCRYPT_REPLY:
- fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
- "IS" : "REPLY");
- if (length < 3) {
- fprintf(NetTrace, " (partial suboption??\?)");
- break;
- }
- if (ENCTYPE_NAME_OK(pointer[2]))
- fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
- else
- fprintf(NetTrace, " %d (unknown)", pointer[2]);
-
- encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
- fprintf(NetTrace, "%s", buf);
- break;
-
- case ENCRYPT_SUPPORT:
- i = 2;
- fprintf(NetTrace, " SUPPORT ");
- while (i < length) {
- if (ENCTYPE_NAME_OK(pointer[i]))
- fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
- else
- fprintf(NetTrace, "%d ", pointer[i]);
- i++;
- }
- break;
-
- case ENCRYPT_ENC_KEYID:
- fprintf(NetTrace, " ENC_KEYID ");
- goto encommon;
-
- case ENCRYPT_DEC_KEYID:
- fprintf(NetTrace, " DEC_KEYID ");
- goto encommon;
-
- default:
- fprintf(NetTrace, " %d (unknown)", pointer[1]);
- encommon:
- for (i = 2; i < length; i++)
- fprintf(NetTrace, " %d", pointer[i]);
- break;
- }
- break;
-#endif /* ENCRYPTION */
case TELOPT_LINEMODE:
fprintf(NetTrace, "LINEMODE ");
diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c
index f99e7f6..4763f43 100644
--- a/usr.bin/tftp/main.c
+++ b/usr.bin/tftp/main.c
@@ -97,7 +97,7 @@ void settrace __P((int, char **));
void setverbose __P((int, char **));
void status __P((int, char **));
-static __dead void command __P((void));
+static void command __P((void)) __dead2;
static void getusage __P((char *));
static void makeargv __P((void));
@@ -195,7 +195,7 @@ setpeer(argc, argv)
if (argc < 2) {
strcpy(line, "Connect ");
printf("(to) ");
- gets(&line[strlen(line)]);
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
makeargv();
argc = margc;
argv = margv;
@@ -284,7 +284,7 @@ void
setbinary(argc, argv)
int argc;
char *argv[];
-{
+{
settftpmode("octet");
}
@@ -323,7 +323,7 @@ put(argc, argv)
if (argc < 2) {
strcpy(line, "send ");
printf("(file) ");
- gets(&line[strlen(line)]);
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
makeargv();
argc = margc;
argv = margv;
@@ -376,7 +376,7 @@ put(argc, argv)
}
/* this assumes the target is a directory */
/* on a remote unix system. hmmmm. */
- cp = index(targ, '\0');
+ cp = index(targ, '\0');
*cp++ = '/';
for (n = 1; n < argc - 1; n++) {
strcpy(cp, tail(argv[n]));
@@ -417,7 +417,7 @@ get(argc, argv)
if (argc < 2) {
strcpy(line, "get ");
printf("(files) ");
- gets(&line[strlen(line)]);
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
makeargv();
argc = margc;
argv = margv;
@@ -501,7 +501,7 @@ setrexmt(argc, argv)
if (argc < 2) {
strcpy(line, "Rexmt-timeout ");
printf("(value) ");
- gets(&line[strlen(line)]);
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
makeargv();
argc = margc;
argv = margv;
@@ -529,7 +529,7 @@ settimeout(argc, argv)
if (argc < 2) {
strcpy(line, "Maximum-timeout ");
printf("(value) ");
- gets(&line[strlen(line)]);
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
makeargv();
argc = margc;
argv = margv;
@@ -574,7 +574,7 @@ tail(filename)
char *filename;
{
register char *s;
-
+
while (*filename) {
s = rindex(filename, '/');
if (s == NULL)
@@ -589,20 +589,23 @@ tail(filename)
/*
* Command parser.
*/
-static __dead void
+static void
command()
{
register struct cmd *c;
+ char *cp;
for (;;) {
printf("%s> ", prompt);
- if (gets(line) == 0) {
+ if (fgets(line, sizeof line , stdin) == 0) {
if (feof(stdin)) {
exit(0);
} else {
continue;
}
}
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
if (line[0] == 0)
continue;
makeargv();
@@ -660,6 +663,8 @@ makeargv()
register char **argp = margv;
margc = 0;
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
for (cp = line; *cp;) {
while (isspace(*cp))
cp++;
diff --git a/usr.bin/time/time.1 b/usr.bin/time/time.1
index f68c6f4..52b555e 100644
--- a/usr.bin/time/time.1
+++ b/usr.bin/time/time.1
@@ -87,11 +87,9 @@ The granularity of seconds on micro processors is crude and
can result in times being reported for CPU usage which are too large by
a second.
.Sh SEE ALSO
-.Xr csh 1
-.Sh FILES
-.Bl -tag -width /usr/include/sys/h/resource.h -compact
-.It Pa /usr/include/sys/h/resource.h
-.El
+.Xr csh 1 ,
+.Xr getrusage 2 ,
+.Xr wait 2
.Sh HISTORY
A
.Nm
diff --git a/usr.bin/time/time.c b/usr.bin/time/time.c
index 72c3766..52a5709 100644
--- a/usr.bin/time/time.c
+++ b/usr.bin/time/time.c
@@ -45,8 +45,15 @@ static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93";
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/signal.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include <err.h>
#include <stdio.h>
+static int getstathz __P((void));
+
main(argc, argv)
int argc;
char **argv;
@@ -58,7 +65,7 @@ main(argc, argv)
struct rusage ru;
lflag = 0;
- while ((ch = getopt(argc, argv, "l")) != EOF)
+ while ((ch = getopt(argc, argv, "l")) != -1)
switch((char)ch) {
case 'l':
lflag = 1;
@@ -102,11 +109,19 @@ main(argc, argv)
fprintf(stderr, "%9ld.%02ld sys\n",
ru.ru_stime.tv_sec, ru.ru_stime.tv_usec/10000);
if (lflag) {
- int hz = 100; /* XXX */
- long ticks;
+ int hz = getstathz();
+ u_long ticks;
ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) +
hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000;
+
+ /*
+ * If our round-off on the tick calculation still puts us at 0,
+ * then always assume at least one tick.
+ */
+ if (ticks == 0)
+ ticks = 1;
+
fprintf(stderr, "%10ld %s\n",
ru.ru_maxrss, "maximum resident set size");
fprintf(stderr, "%10ld %s\n",
@@ -136,5 +151,23 @@ main(argc, argv)
fprintf(stderr, "%10ld %s\n",
ru.ru_nivcsw, "involuntary context switches");
}
- exit (status>>8);
+ exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+}
+
+/*
+ * Return the frequency of the kernel's statistics clock.
+ */
+static int
+getstathz()
+{
+ struct clockinfo clockrate;
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ size = sizeof clockrate;
+ if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1)
+ err(1, "sysctl kern.clockrate");
+ return clockrate.stathz;
}
diff --git a/usr.bin/tip/Makefile b/usr.bin/tip/Makefile
index 21514ed5..b8d5b38 100644
--- a/usr.bin/tip/Makefile
+++ b/usr.bin/tip/Makefile
@@ -1,52 +1,5 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-#
-# Files are:
-# /etc/remote remote host description file
-# /etc/phones phone number file, owned by ${OWNER} and
-# mode 6??
-# /var/log/aculog ACU accounting file, owned by ${OWNER} and
-# mode 6?? {if ACULOG defined}
-# Presently supports:
-# BIZCOMP
-# DEC DF02-AC, DF03-AC
-# DEC DN-11/Able Quadracall
-# HAYES and Hayes emulators
-# USR COURIER (2400 baud)
-# VENTEL 212+
-# VADIC 831 RS232 adaptor
-# VADIC 3451
-# TELEBIT T3000
-#
-# Configuration defines:
-# DF02, DF03, DN11 ACU's supported
-# BIZ1031, BIZ1022, VENTEL, V831, V3451, HAYES, COURIER, T3000
-# ACULOG turn on tip logging of ACU use
-# PRISTINE no phone #'s put in ACU log file
-# CONNECT worthless command
-# DEFBR default baud rate to make connection at
-# DEFFS default frame size for FTP buffering of
-# writes on local side
-# BUFSIZ buffer sizing from stdio, must be fed
-# explicitly to remcap.c if not 1024
-# CONNECT enable ~C command (connect pgm to remote)
+SUBDIR=libacu tip
-PROG= tip
-CFLAGS+=-I${.CURDIR} \
- -DDEFBR=1200 -DDEFFS=BUFSIZ -DACULOG -DPRISTINE -DCONNECT \
- -DV831 -DVENTEL -DHAYES -DCOURIER -DT3000
-.PATH: ${.CURDIR}/aculib
-BINOWN= uucp
-BINGRP= dialer
-BINMODE=4510
-LINKS= ${BINDIR}/tip ${BINDIR}/cu
-MLINKS= tip.1 cu.1
-SRCS= acu.c acutab.c cmds.c cmdtab.c cu.c hunt.c log.c partab.c \
- remote.c tip.c tipout.c uucplock.c value.c vars.c \
- biz22.c courier.c df.c dn11.c hayes.c t3000.c v3451.c v831.c ventel.c
+TAGS= yes
-# -- acutab is configuration dependent, and so depends on the Makefile
-# -- remote.o depends on the Makefile because of DEFBR and DEFFS
-# -- log.o depends on the Makefile because of ACULOG
-acutab.o log.o remote.o: Makefile
-
-.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/usr.bin/tip/Makefile.inc b/usr.bin/tip/Makefile.inc
new file mode 100644
index 0000000..4a9bb26
--- /dev/null
+++ b/usr.bin/tip/Makefile.inc
@@ -0,0 +1,5 @@
+# These are mostly just for tip, but they're more visible up here.
+BINDIR?= /usr/bin
+BINOWN?= uucp
+BINGRP?= dialer
+BINMODE?= 4510
diff --git a/usr.bin/tip/NEWS b/usr.bin/tip/NEWS
new file mode 100644
index 0000000..9e37d42
--- /dev/null
+++ b/usr.bin/tip/NEWS
@@ -0,0 +1,65 @@
+Sat Mar 25 16:06:31 PST 1995
+
+hw_flow_control (boolean) capability added to modem configuration
+data base (/etc/modems).
+
+Configurable unidialer driver compiled in by default. Builtin
+ACU drivers no longer compiled in by default.
+
+All configuration details isolated in tipconf.h (with exception of
+pathnames.h).
+
+Made corrections to and updated manual page for tip.
+
+Conditional compilation of cu interface for systems that provide
+a separate cu implementation (e.g. FreeBSD).
+
+Sat Mar 25 00:35:08 PST 1995
+
+Corrected entry in man file to identify the lockfile dir as /var/spool/locks
+instead of /var/spool/uucp.
+
+xfer and transfer in cmds.c use standard C runtime buffered output.
+Eliminates a bug: buffer overruns when FRAMESIZE > BUFSIZ.
+
+Added xfer routine for doing cu style take commands.
+
+Thu Mar 16 08:17:57 PST 1995
+
+Added support for termios.
+
+Renamed acunap.* to acucommon.*. Moved common acu routines
+to it. Modified acu drivers to use common routines.
+
+Sat Mar 11 20:17:58 PST 1995
+
+Default nap function uses select call in preference to
+usleep or old, handrolled code.
+
+tip makefile does not create a link to cu by default.
+
+Wed Mar 8 00:11:04 PST 1995
+
+Reduced sleep time in finish () in cmds.c from 5 seconds to two.
+
+Sat Mar 4 19:00:34 PST 1995
+
+Added table-driven modem driver (unidialer) that fetches modem
+characteristics from a modem database ("/etc/modems").
+
+Removed common "nap" code from individual ACU drivers into a
+separate module.
+
+Added login script capability to remote database.
+
+Sun Feb 26 23:07:56 PST 1995
+
+Use HoneyDanber style locks by default (ASCII PIDs written to lock files).
+
+Changed default uucp file lock directory to "/var/spool/locks"
+to be consistent with default build of Taylor uucp.
+
+Reorganized build environment for tip into a master directory
+and two subdirectories. The master Makefile builds a library
+of ACU "drivers" in the directory libacu. Tip only links in
+drivers that it will actually use.
diff --git a/usr.bin/tip/README b/usr.bin/tip/README
new file mode 100644
index 0000000..12d45b2
--- /dev/null
+++ b/usr.bin/tip/README
@@ -0,0 +1,63 @@
+[See NEWS file for much more up-to-date information]
+
+Tip can be configured in a number of ways:
+
+ACU's:
+-----
+
+ACU Define in makefile
+-------------------- ---------------
+BIZCOMP 1022, 1031 BIZ1022, BIZ1031
+DEC DF02-AC, DF03-AC DF02, DF03
+DEC DN-11/Able Quadracall DN11
+Ventel VENTEL
+Vadic 831 V831
+
+New ACU's may be added by editing the ACU description table
+in acutab.c and writing a ``driver''.
+
+ACU usage can be monitored by defining ACULOG in the makefile.
+If this is done and no phone numbers should appear in the
+log file, define PRISTINE in the makefile.
+
+Variables:
+---------
+
+Tip's internal workings revolve around a set of (possibly)
+user defined variables. These are statically initialized
+in vars.c, and from the remote file.
+
+Note that adding or deleting variables requires tip to be completedly
+recompiled, as indexes into the variable table are used to avoid
+expensive lookups. These defines are set in tip.h.
+
+Commands:
+--------
+
+The command dispatch table is defined in cmdtab.c. Commands
+may have attributes such as EXPerimental and PRIVileged (only
+root may execute).
+
+
+
+--------------------------------------------------------------------------
+
+Recent changes about Jan 82
+
+A new, improved version of tip is now available. The most important
+addition is the capacility to specify a phone number with tip. The
+default baud rate is 1200. To use it do:
+
+ tip phone-number
+or
+ tip -300 phone-number
+
+for 300 baud.
+
+A ~^Z command has been added to tip as well.
+
+A new cu program is available that interfaces to the tip program.
+It attempts to give the same user interface as cu but it is really
+the tip program so you have all the advantages of tip. This allows
+cu (actually tip) to search for a free ACU instead of having the
+user specify which one he wants.
diff --git a/usr.bin/tip/TODO b/usr.bin/tip/TODO
new file mode 100644
index 0000000..41e2d6e
--- /dev/null
+++ b/usr.bin/tip/TODO
@@ -0,0 +1,38 @@
+x Fix "hangup failed" in unidialer
+x Genericize tty code and/or support termios
+x Fixup uucplock conventions for FreeBSD (including reference in tip man pages).
+Sanity check for ttys
+x Rename pathnames.h
+x Qualify on USR
+Use select call to merge tipin / tipout
+
+x Finish table-driven modem driver
+x Move HAVE_USLEEP to pathhnames.h
+x Add variable for login and logout scripts (connect with Perl???)
+x redials / redial delay (see dial shell script)
+
+Add debug log capabilities for table-driven modem driver (command mode modem I/Owith timestamps).
+
+Use select in modem drivers.
+Consolidate consh()-derived code in cmds.c
+Screen-oriented command menu?
+Add external file-transfer protocol implementations to command menu (rz, sz, others?)
+
+1. Rethink protection glitches on REMOTE & PHONES
+ files (setuid/setgid??).
+
+2. Make clean fix for scripting being set in .tiprc
+
+3. change EOFREAD to recognize more general strings.
+
+4. add an option that returns an exit status based on
+ whether resources for the requested operation are available.
+
+5. write a program to list known systems (a quick shell script
+ should do it); people keep forgetting the names.
+
+6. change remote file descriptions so that acu attributes are
+ are attached to a device so that several different devices
+ can be used to get to the same system (perhaps hardwired
+ and phone line). got any ideas here? I'm looking at something
+ like dv=cua1,cul1,dn11;cua2,,df03.
diff --git a/usr.bin/tip/libacu/Makefile b/usr.bin/tip/libacu/Makefile
new file mode 100644
index 0000000..77a95cd
--- /dev/null
+++ b/usr.bin/tip/libacu/Makefile
@@ -0,0 +1,12 @@
+LIB= acu
+CFLAGS+= -I${.CURDIR}/../tip
+SRCS= acucommon.c biz22.c courier.c df.c dn11.c hayes.c \
+ multitech.c t3000.c tod.c unidialer.c v3451.c v831.c ventel.c
+NOPROFILE= yes
+
+$(OBJS): ${.CURDIR}/../tip/tipconf.h
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/usr.bin/tip/libacu/acucommon.c b/usr.bin/tip/libacu/acucommon.c
new file mode 100644
index 0000000..479e9a3
--- /dev/null
+++ b/usr.bin/tip/libacu/acucommon.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)acucommon.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Courier modem.
+ * Derived from Hayes driver.
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+#if HAVE_SELECT
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+
+void acu_nap (unsigned int how_long)
+{
+ struct timeval t;
+ t.tv_usec = (how_long % 1000) * 1000;
+ t.tv_sec = how_long / 1000;
+ (void) select (0, NULL, NULL, NULL, &t);
+}
+
+#elif HAVE_USLEEP
+void acu_nap (unsigned int how_long)
+{
+ (void) usleep (how_long * 1000);
+}
+
+#else
+
+/*
+ * Code stolen from /usr/src/lib/libc/gen/sleep.c
+ */
+#define mask(s) (1<<((s)-1))
+#define setvec(vec, a) \
+ vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
+
+static int ringring;
+
+static void acunap_napx()
+{
+ ringring = 1;
+}
+
+void acu_nap (unsigned int how_long)
+{
+ int omask;
+ struct itimerval itv, oitv;
+ register struct itimerval *itp = &itv;
+ struct sigvec vec, ovec;
+
+ timerclear(&itp->it_interval);
+ timerclear(&itp->it_value);
+ if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
+ return;
+ setvec(ovec, SIG_DFL);
+ omask = sigblock(mask(SIGALRM));
+ itp->it_value.tv_sec = how_long / 1000;
+ itp->it_value.tv_usec = ((how_long % 1000) * 1000);
+ setvec(vec, acunap_napx);
+ ringring = 0;
+ (void) sigvec(SIGALRM, &vec, &ovec);
+ (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
+ while (!ringring)
+ sigpause(omask &~ mask(SIGALRM));
+ (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
+ (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
+ (void) sigsetmask(omask);
+}
+
+#endif /* HAVE_USLEEP */
+
+void acu_hw_flow_control (hw_flow_control)
+{
+#if HAVE_TERMIOS
+ struct termios t;
+ if (tcgetattr (FD, &t) == 0) {
+ if (hw_flow_control)
+ t.c_cflag |= CRTSCTS;
+ else
+ t.c_cflag &= ~CRTSCTS;
+ tcsetattr (FD, TCSANOW, &t);
+ }
+#endif /* HAVE_TERMIOS */
+}
+
+int acu_flush ()
+{
+#ifdef TIOCFLUSH
+ int flags = 0;
+ return (ioctl (FD, TIOCFLUSH, &flags) == 0); /* flush any clutter */
+#elif !HAVE_TERMIOS
+ struct sgttyb buf;
+ return (ioctl (FD, TIOCGETP, &buf) == 0 && ioctl (FD, TIOCSETP, &buf) == 0);
+#endif
+}
+
+int acu_getspeed ()
+{
+#if HAVE_TERMIOS
+ struct termios term;
+ tcgetattr (FD, &term);
+ return (term.c_ospeed);
+#else /* HAVE_TERMIOS */
+ struct sgttyb buf;
+ ioctl (FD, TIOCGETP, &buf);
+ return (buf.sg_ospeed);
+#endif
+}
+
+int acu_setspeed (int speed)
+{
+ int rc = 0;
+#if HAVE_TERMIOS
+ struct termios term;
+ if (tcgetattr (FD, &term) == 0) {
+#ifndef _POSIX_SOURCE
+ cfsetspeed (&term, speed);
+#else
+ cfsetispeed (&term, speed);
+ cfsetospeed (&term, speed);
+#endif
+ if (tcsetattr (FD, TCSANOW, &term) == 0)
+ ++rc;
+ }
+#else /* HAVE TERMIOS */
+ struct sgttyb sb;
+ if (ioctl(FD, TIOCGETP, &sb) < 0) {
+ perror("TIOCGETP");
+ }
+ else {
+ sb.sg_ispeed = sb.sg_ospeed = speed;
+ if (ioctl(FD, TIOCSETP, &sb) < 0) {
+ perror("TIOCSETP");
+ }
+ else
+ ++rc;
+ }
+#endif /* HAVE TERMIOS */
+ return (rc);
+}
+
+void acu_hupcl ()
+{
+#if HAVE_TERMIOS
+ struct termios term;
+ tcgetattr (FD, &term);
+ term.c_cflag |= HUPCL;
+ tcsetattr (FD, TCSANOW, &term);
+#elif defined(TIOCHPCL)
+ ioctl(FD, TIOCHPCL, 0);
+#endif
+}
+
+/* end of acucommon.c */
diff --git a/usr.bin/tip/libacu/acucommon.h b/usr.bin/tip/libacu/acucommon.h
new file mode 100644
index 0000000..50d28cd
--- /dev/null
+++ b/usr.bin/tip/libacu/acucommon.h
@@ -0,0 +1,6 @@
+void acu_nap (unsigned int how_long);
+void acu_hw_flow_control (int hw_flow_control);
+int acu_flush ();
+void acu_hupcl ();
+int acu_setspeed (int speed);
+/* end of acucommon.h */
diff --git a/usr.bin/tip/libacu/biz22.c b/usr.bin/tip/libacu/biz22.c
new file mode 100644
index 0000000..63fb11c
--- /dev/null
+++ b/usr.bin/tip/libacu/biz22.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)biz22.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+#define DISCONNECT_CMD "\20\04" /* disconnection string */
+
+static void sigALRM();
+static int timeout = 0;
+static jmp_buf timeoutbuf;
+
+/*
+ * Dial up on a BIZCOMP Model 1022 with either
+ * tone dialing (mod = "V")
+ * pulse dialing (mod = "W")
+ */
+static int
+biz_dialer(num, mod)
+ char *num, *mod;
+{
+ register int connected = 0;
+ char cbuf[40];
+ static int cmd(), detect();
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ /*
+ * Disable auto-answer and configure for tone/pulse
+ * dialing
+ */
+ if (cmd("\02K\r")) {
+ printf("can't initialize bizcomp...");
+ return (0);
+ }
+ strcpy(cbuf, "\02.\r");
+ cbuf[1] = *mod;
+ if (cmd(cbuf)) {
+ printf("can't set dialing mode...");
+ return (0);
+ }
+ strcpy(cbuf, "\02D");
+ strcat(cbuf, num);
+ strcat(cbuf, "\r");
+ write(FD, cbuf, strlen(cbuf));
+ if (!detect("7\r")) {
+ printf("can't get dial tone...");
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("ringing...");
+ /*
+ * The reply from the BIZCOMP should be:
+ * 2 \r or 7 \r failure
+ * 1 \r success
+ */
+ connected = detect("1\r");
+#if ACULOG
+ if (timeout) {
+ char line[80];
+
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "biz1022", line);
+ }
+#endif
+ if (timeout)
+ biz22_disconnect(); /* insurance */
+ return (connected);
+}
+
+biz22w_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "W"));
+}
+
+biz22f_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "V"));
+}
+
+biz22_disconnect()
+{
+ int rw = 2;
+
+ write(FD, DISCONNECT_CMD, 4);
+ sleep(2);
+ ioctl(FD, TIOCFLUSH, &rw);
+}
+
+biz22_abort()
+{
+
+ write(FD, "\02", 1);
+}
+
+static void
+sigALRM()
+{
+
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int
+cmd(s)
+ register char *s;
+{
+ sig_t f;
+ char c;
+
+ write(FD, s, strlen(s));
+ f = signal(SIGALRM, sigALRM);
+ if (setjmp(timeoutbuf)) {
+ biz22_abort();
+ signal(SIGALRM, f);
+ return (1);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ signal(SIGALRM, f);
+ c &= 0177;
+ return (c != '\r');
+}
+
+static int
+detect(s)
+ register char *s;
+{
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ while (*s) {
+ if (setjmp(timeoutbuf)) {
+ biz22_abort();
+ break;
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+ if (c != *s++)
+ return (0);
+ }
+ signal(SIGALRM, f);
+ return (timeout == 0);
+}
diff --git a/usr.bin/tip/libacu/biz31.c b/usr.bin/tip/libacu/biz31.c
new file mode 100644
index 0000000..9553a6d
--- /dev/null
+++ b/usr.bin/tip/libacu/biz31.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)biz31.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+#define MAXRETRY 3 /* sync up retry count */
+#define DISCONNECT_CMD "\21\25\11\24" /* disconnection string */
+
+static void sigALRM();
+static int timeout = 0;
+static jmp_buf timeoutbuf;
+
+/*
+ * Dial up on a BIZCOMP Model 1031 with either
+ * tone dialing (mod = "f")
+ * pulse dialing (mod = "w")
+ */
+static int
+biz_dialer(num, mod)
+ char *num, *mod;
+{
+ register int connected = 0;
+
+ if (!bizsync(FD)) {
+ logent(value(HOST), "", "biz", "out of sync");
+ printf("bizcomp out of sync\n");
+ delock(uucplock);
+ exit(0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ echo("#\rk$\r$\n"); /* disable auto-answer */
+ echo("$>$.$ #\r"); /* tone/pulse dialing */
+ echo(mod);
+ echo("$\r$\n");
+ echo("$>$.$ #\re$ "); /* disconnection sequence */
+ echo(DISCONNECT_CMD);
+ echo("\r$\n$\r$\n");
+ echo("$>$.$ #\rr$ "); /* repeat dial */
+ echo(num);
+ echo("\r$\n");
+ if (boolean(value(VERBOSE)))
+ printf("ringing...");
+ /*
+ * The reply from the BIZCOMP should be:
+ * `^G NO CONNECTION\r\n^G\r\n' failure
+ * ` CONNECTION\r\n^G' success
+ */
+ connected = detect(" ");
+#if ACULOG
+ if (timeout) {
+ char line[80];
+
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "biz", line);
+ }
+#endif
+ if (!connected)
+ flush(" NO CONNECTION\r\n\07\r\n");
+ else
+ flush("CONNECTION\r\n\07");
+ if (timeout)
+ biz31_disconnect(); /* insurance */
+ return (connected);
+}
+
+biz31w_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "w"));
+}
+
+biz31f_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "f"));
+}
+
+biz31_disconnect()
+{
+
+ write(FD, DISCONNECT_CMD, 4);
+ sleep(2);
+ ioctl(FD, TIOCFLUSH);
+}
+
+biz31_abort()
+{
+
+ write(FD, "\33", 1);
+}
+
+static int
+echo(s)
+ register char *s;
+{
+ char c;
+
+ while (c = *s++) switch (c) {
+
+ case '$':
+ read(FD, &c, 1);
+ s++;
+ break;
+
+ case '#':
+ c = *s++;
+ write(FD, &c, 1);
+ break;
+
+ default:
+ write(FD, &c, 1);
+ read(FD, &c, 1);
+ }
+}
+
+static void
+sigALRM()
+{
+
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int
+detect(s)
+ register char *s;
+{
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ while (*s) {
+ if (setjmp(timeoutbuf)) {
+ printf("\07timeout waiting for reply\n");
+ biz31_abort();
+ break;
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ if (c != *s++)
+ break;
+ }
+ signal(SIGALRM, f);
+ return (timeout == 0);
+}
+
+static int
+flush(s)
+ register char *s;
+{
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ while (*s++) {
+ if (setjmp(timeoutbuf))
+ break;
+ alarm(10);
+ read(FD, &c, 1);
+ alarm(0);
+ }
+ signal(SIGALRM, f);
+ timeout = 0; /* guard against disconnection */
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the bizcomp in sync. If you don't have the capacity or nread
+ * call there are gory ways to simulate this.
+ */
+static int
+bizsync(fd)
+{
+#ifdef FIOCAPACITY
+ struct capacity b;
+# define chars(b) ((b).cp_nbytes)
+# define IOCTL FIOCAPACITY
+#endif
+#ifdef FIONREAD
+ long b;
+# define chars(b) (b)
+# define IOCTL FIONREAD
+#endif
+ register int already = 0;
+ char buf[10];
+
+retry:
+ if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0 && chars(b) > 0)
+ ioctl(fd, TIOCFLUSH);
+ write(fd, "\rp>\r", 4);
+ sleep(1);
+ if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0) {
+ if (chars(b) != 10) {
+ nono:
+ if (already > MAXRETRY)
+ return (0);
+ write(fd, DISCONNECT_CMD, 4);
+ sleep(2);
+ already++;
+ goto retry;
+ } else {
+ read(fd, buf, 10);
+ if (strncmp(buf, "p >\r\n\r\n>", 8))
+ goto nono;
+ }
+ }
+ return (1);
+}
diff --git a/usr.bin/tip/libacu/courier.c b/usr.bin/tip/libacu/courier.c
new file mode 100644
index 0000000..84c710f
--- /dev/null
+++ b/usr.bin/tip/libacu/courier.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Courier modem.
+ * Derived from Hayes driver.
+ */
+#include "tipconf.h"
+#include "tip.h"
+#include "acucommon.h"
+#include <stdio.h>
+
+#define MAXRETRY 5
+
+static void sigALRM();
+static int timeout = 0;
+static int connected = 0;
+static jmp_buf timeoutbuf, intbuf;
+static int coursync();
+
+cour_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ register char *cp;
+#if ACULOG
+ char line[80];
+#endif
+ static int cour_connect(), cour_swallow();
+
+ if (boolean(value(VERBOSE)))
+ printf("Using \"%s\"\n", acu);
+
+ acu_hupcl ();
+
+ /*
+ * Get in synch.
+ */
+ if (!coursync()) {
+badsynch:
+ printf("can't synchronize with courier\n");
+#if ACULOG
+ logent(value(HOST), num, "courier", "can't synch up");
+#endif
+ return (0);
+ }
+ cour_write(FD, "AT E0\r", 6); /* turn off echoing */
+ sleep(1);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ cour_verbose_read();
+#endif
+ ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
+ cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
+ if (!cour_swallow("\r\nOK\r\n"))
+ goto badsynch;
+ fflush(stdout);
+ cour_write(FD, "AT D", 4);
+ for (cp = num; *cp; cp++)
+ if (*cp == '=')
+ *cp = ',';
+ cour_write(FD, num, strlen(num));
+ cour_write(FD, "\r", 1);
+ connected = cour_connect();
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "cour", line);
+ }
+#endif
+ if (timeout)
+ cour_disconnect();
+ return (connected);
+}
+
+cour_disconnect()
+{
+ /* first hang up the modem*/
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ coursync(); /* reset */
+ close(FD);
+}
+
+cour_abort()
+{
+ cour_write(FD, "\r", 1); /* send anything to abort the call */
+ cour_disconnect();
+}
+
+static void
+sigALRM()
+{
+ printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int
+cour_swallow(match)
+ register char *match;
+ {
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ do {
+ if (*match =='\0') {
+ signal(SIGALRM, f);
+ return (1);
+ }
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ } while (c == *match++);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ fflush(stdout);
+#endif
+ signal(SIGALRM, SIG_DFL);
+ return (0);
+}
+
+struct baud_msg {
+ char *msg;
+ int baud;
+} baud_msg[] = {
+ "", B300,
+ " 1200", B1200,
+ " 2400", B2400,
+ " 9600", B9600,
+ " 9600/ARQ", B9600,
+ 0, 0,
+};
+
+static int
+cour_connect()
+{
+ char c;
+ int nc, nl, n;
+ char dialer_buf[64];
+ struct baud_msg *bm;
+ sig_t f;
+
+ if (cour_swallow("\r\n") == 0)
+ return (0);
+ f = signal(SIGALRM, sigALRM);
+again:
+ nc = 0; nl = sizeof(dialer_buf)-1;
+ bzero(dialer_buf, sizeof(dialer_buf));
+ timeout = 0;
+ for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
+ if (setjmp(timeoutbuf))
+ break;
+ alarm(number(value(DIALTIMEOUT)));
+ n = read(FD, &c, 1);
+ alarm(0);
+ if (n <= 0)
+ break;
+ c &= 0x7f;
+ if (c == '\r') {
+ if (cour_swallow("\n") == 0)
+ break;
+ if (!dialer_buf[0])
+ goto again;
+ if (strcmp(dialer_buf, "RINGING") == 0 &&
+ boolean(value(VERBOSE))) {
+#ifdef DEBUG
+ printf("%s\r\n", dialer_buf);
+#endif
+ goto again;
+ }
+ if (strncmp(dialer_buf, "CONNECT",
+ sizeof("CONNECT")-1) != 0)
+ break;
+ for (bm = baud_msg ; bm->msg ; bm++)
+ if (strcmp(bm->msg,
+ dialer_buf+sizeof("CONNECT")-1) == 0) {
+ if (!acu_setspeed(bm->baud))
+ goto error;
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ break;
+ }
+ dialer_buf[nc] = c;
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ }
+error1:
+ printf("%s\r\n", dialer_buf);
+error:
+ signal(SIGALRM, f);
+ return (0);
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the courier in sync.
+ */
+static int
+coursync()
+{
+ int already = 0;
+ int len;
+ char buf[40];
+
+ while (already++ < MAXRETRY) {
+ ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
+ cour_write(FD, "\rAT Z\r", 6); /* reset modem */
+ bzero(buf, sizeof(buf));
+ sleep(1);
+ ioctl(FD, FIONREAD, &len);
+ if (len) {
+ len = read(FD, buf, sizeof(buf));
+#ifdef DEBUG
+ buf[len] = '\0';
+ printf("coursync: (\"%s\")\n\r", buf);
+#endif
+ if (index(buf, '0') ||
+ (index(buf, 'O') && index(buf, 'K')))
+ return(1);
+ }
+ /*
+ * If not strapped for DTR control,
+ * try to get command mode.
+ */
+ sleep(1);
+ cour_write(FD, "+++", 3);
+ sleep(1);
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected.
+ */
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ }
+ cour_write(FD, "\rAT Z\r", 6);
+ return (0);
+}
+
+cour_write(fd, cp, n)
+int fd;
+char *cp;
+int n;
+{
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ write(1, cp, n);
+#endif
+ acu_flush ();
+ cour_nap();
+ for ( ; n-- ; cp++) {
+ write(fd, cp, 1);
+ acu_flush ();
+ cour_nap();
+ }
+}
+
+#ifdef DEBUG
+cour_verbose_read()
+{
+ int n = 0;
+ char buf[BUFSIZ];
+
+ if (ioctl(FD, FIONREAD, &n) < 0)
+ return;
+ if (n <= 0)
+ return;
+ if (read(FD, buf, n) != n)
+ return;
+ write(1, buf, n);
+}
+#endif
+
+cour_nap()
+{
+ acu_nap (50);
+}
+
+/* end of courier.c */
diff --git a/usr.bin/tip/libacu/df.c b/usr.bin/tip/libacu/df.c
new file mode 100644
index 0000000..fc60ad3
--- /dev/null
+++ b/usr.bin/tip/libacu/df.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)df.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Dial the DF02-AC or DF03-AC
+ */
+
+#include "tipconf.h"
+#include "tip.h"
+
+static jmp_buf Sjbuf;
+static void timeout();
+
+df02_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (df_dialer(num, acu, 0));
+}
+
+df03_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (df_dialer(num, acu, 1));
+}
+
+df_dialer(num, acu, df03)
+ char *num, *acu;
+ int df03;
+{
+ register int f = FD;
+ int speed = 0, rw = 2;
+ char c = '\0';
+
+ acu_hupcl ();
+
+ if (setjmp(Sjbuf)) {
+ printf("connection timed out\r\n");
+ df_disconnect();
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+#ifdef TIOCMSET
+ if (df03) {
+ int st = TIOCM_ST; /* secondary Transmit flag */
+
+ if ((speed = acu_getspeed ()) != B1200) { /* must dial at 1200 baud */
+ acu_setspeed (B1200);
+ ioctl(f, TIOCMBIC, &st); /* clear ST for 300 baud */
+ } else
+ ioctl(f, TIOCMBIS, &st); /* set ST for 1200 baud */
+ }
+#endif
+ signal(SIGALRM, timeout);
+ alarm(5 * strlen(num) + 10);
+ ioctl(f, TIOCFLUSH, &rw);
+ write(f, "\001", 1);
+ sleep(1);
+ write(f, "\002", 1);
+ write(f, num, strlen(num));
+ read(f, &c, 1);
+#ifdef TIOCMSET
+ if (df03 && speed) {
+ acu_setspeed (speed);
+ }
+#endif
+ return (c == 'A');
+}
+
+df_disconnect()
+{
+ int rw = 2;
+
+ write(FD, "\001", 1);
+ sleep(1);
+ ioctl(FD, TIOCFLUSH, &rw);
+}
+
+
+df_abort()
+{
+
+ df_disconnect();
+}
+
+
+static void
+timeout()
+{
+
+ longjmp(Sjbuf, 1);
+}
diff --git a/usr.bin/tip/libacu/dn11.c b/usr.bin/tip/libacu/dn11.c
new file mode 100644
index 0000000..52749da
--- /dev/null
+++ b/usr.bin/tip/libacu/dn11.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dn11.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for dialing up on DN-11
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+int dn_abort();
+void alarmtr();
+static jmp_buf jmpbuf;
+static int child = -1, dn;
+
+dn_dialer(num, acu)
+ char *num, *acu;
+{
+ extern errno;
+ char *p, *q, phone[40];
+ int lt, nw, connected = 1;
+ register int timelim;
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ if ((dn = open(acu, 1)) < 0) {
+ if (errno == EBUSY)
+ printf("line busy...");
+ else
+ printf("acu open error...");
+ return (0);
+ }
+ if (setjmp(jmpbuf)) {
+ kill(child, SIGKILL);
+ close(dn);
+ return (0);
+ }
+ signal(SIGALRM, alarmtr);
+ timelim = 5 * strlen(num);
+ alarm(timelim < 30 ? 30 : timelim);
+ if ((child = fork()) == 0) {
+ /*
+ * ignore this stuff for aborts
+ */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ sleep(2);
+ nw = write(dn, num, lt = strlen(num));
+ exit(nw != lt);
+ }
+ /*
+ * open line - will return on carrier
+ */
+ if ((FD = open(DV, 2)) < 0) {
+ if (errno == EIO)
+ printf("lost carrier...");
+ else
+ printf("dialup line open failed...");
+ alarm(0);
+ kill(child, SIGKILL);
+ close(dn);
+ return (0);
+ }
+ alarm(0);
+
+#if HAVE_TERMIOS
+ {
+ struct termios term;
+ tcgetattr (dn, &term);
+ term.c_cflag |= HUPCL;
+ tcsetattr (dn, TCSANOW, &term);
+ }
+#elif defined(TIOCHPCL)
+ ioctl(dn, TIOCHPCL, 0);
+#endif
+
+ signal(SIGALRM, SIG_DFL);
+ while ((nw = wait(&lt)) != child && nw != -1)
+ ;
+ fflush(stdout);
+ close(dn);
+ if (lt != 0) {
+ close(FD);
+ return (0);
+ }
+ return (1);
+}
+
+void
+alarmtr()
+{
+ alarm(0);
+ longjmp(jmpbuf, 1);
+}
+
+/*
+ * Insurance, for some reason we don't seem to be
+ * hanging up...
+ */
+dn_disconnect()
+{
+
+ sleep(2);
+ if (FD > 0)
+ ioctl(FD, TIOCCDTR, 0);
+ close(FD);
+}
+
+dn_abort()
+{
+
+ sleep(2);
+ if (child > 0)
+ kill(child, SIGKILL);
+ if (dn > 0)
+ close(dn);
+ if (FD > 0)
+ ioctl(FD, TIOCCDTR, 0);
+ close(FD);
+}
diff --git a/usr.bin/tip/libacu/hayes.c b/usr.bin/tip/libacu/hayes.c
new file mode 100644
index 0000000..dcce6a5
--- /dev/null
+++ b/usr.bin/tip/libacu/hayes.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Hayes Modem
+ * (based on the old VenTel driver).
+ * The modem is expected to be strapped for "echo".
+ * Also, the switches enabling the DTR and CD lines
+ * must be set correctly.
+ * NOTICE:
+ * The easy way to hang up a modem is always simply to
+ * clear the DTR signal. However, if the +++ sequence
+ * (which switches the modem back to local mode) is sent
+ * before modem is hung up, removal of the DTR signal
+ * has no effect (except that it prevents the modem from
+ * recognizing commands).
+ * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
+ */
+/*
+ * TODO:
+ * It is probably not a good idea to switch the modem
+ * state between 'verbose' and terse (status messages).
+ * This should be kicked out and we should use verbose
+ * mode only. This would make it consistent with normal
+ * interactive use thru the command 'tip dialer'.
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+#define min(a,b) ((a < b) ? a : b)
+
+static void sigALRM();
+static int timeout = 0;
+static jmp_buf timeoutbuf;
+static char gobble();
+#define DUMBUFLEN 40
+static char dumbuf[DUMBUFLEN];
+
+#define DIALING 1
+#define IDLE 2
+#define CONNECTED 3
+#define FAILED 4
+static int state = IDLE;
+
+hay_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ register char *cp;
+ register int connected = 0;
+ char dummy;
+#if ACULOG
+ char line[80];
+#endif
+ if (hay_sync() == 0) /* make sure we can talk to the modem */
+ return(0);
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+ acu_hupcl ();
+ acu_flush ();
+ write(FD, "ATv0\r", 5); /* tell modem to use short status codes */
+ gobble("\r");
+ gobble("\r");
+ write(FD, "ATTD", 4); /* send dial command */
+ write(FD, num, strlen(num));
+ state = DIALING;
+ write(FD, "\r", 1);
+ connected = 0;
+ if (gobble("\r")) {
+ if ((dummy = gobble("01234")) != '1')
+ error_rep(dummy);
+ else
+ connected = 1;
+ }
+ if (connected)
+ state = CONNECTED;
+ else {
+ state = FAILED;
+ return (connected); /* lets get out of here.. */
+ }
+ ioctl(FD, TIOCFLUSH, 0);
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "hayes", line);
+ }
+#endif
+ if (timeout)
+ hay_disconnect(); /* insurance */
+ return (connected);
+}
+
+
+hay_disconnect()
+{
+ char c;
+ int len, rlen;
+
+ /* first hang up the modem*/
+#ifdef DEBUG
+ printf("\rdisconnecting modem....\n\r");
+#endif
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ goodbye();
+}
+
+hay_abort()
+{
+
+ char c;
+
+ write(FD, "\r", 1); /* send anything to abort the call */
+ hay_disconnect();
+}
+
+static void
+sigALRM()
+{
+
+ printf("\07timeout waiting for reply\n\r");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static char
+gobble(match)
+ register char *match;
+{
+ char c;
+ sig_t f;
+ int i, status = 0;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+#ifdef DEBUG
+ printf("\ngobble: waiting for %s\n", match);
+#endif
+ do {
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+#ifdef DEBUG
+ printf("%c 0x%x ", c, c);
+#endif
+ for (i = 0; i < strlen(match); i++)
+ if (c == match[i])
+ status = c;
+ } while (status == 0);
+ signal(SIGALRM, SIG_DFL);
+#ifdef DEBUG
+ printf("\n");
+#endif
+ return (status);
+}
+
+error_rep(c)
+ register char c;
+{
+ printf("\n\r");
+ switch (c) {
+
+ case '0':
+ printf("OK");
+ break;
+
+ case '1':
+ printf("CONNECT");
+ break;
+
+ case '2':
+ printf("RING");
+ break;
+
+ case '3':
+ printf("NO CARRIER");
+ break;
+
+ case '4':
+ printf("ERROR in input");
+ break;
+
+ case '5':
+ printf("CONNECT 1200");
+ break;
+
+ default:
+ printf("Unknown Modem error: %c (0x%x)", c, c);
+ }
+ printf("\n\r");
+ return;
+}
+
+/*
+ * set modem back to normal verbose status codes.
+ */
+goodbye()
+{
+ int len, rlen;
+ char c;
+
+ ioctl(FD, TIOCFLUSH, &len); /* get rid of trash */
+ if (hay_sync()) {
+ sleep(1);
+#ifndef DEBUG
+ ioctl(FD, TIOCFLUSH, 0);
+#endif
+ write(FD, "ATH0\r", 5); /* insurance */
+#ifndef DEBUG
+ c = gobble("03");
+ if (c != '0' && c != '3') {
+ printf("cannot hang up modem\n\r");
+ printf("please use 'tip dialer' to make sure the line is hung up\n\r");
+ }
+#endif
+ sleep(1);
+ ioctl(FD, FIONREAD, &len);
+#ifdef DEBUG
+ printf("goodbye1: len=%d -- ", len);
+ rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
+ dumbuf[rlen] = '\0';
+ printf("read (%d): %s\r\n", rlen, dumbuf);
+#endif
+ write(FD, "ATv1\r", 5);
+ sleep(1);
+#ifdef DEBUG
+ ioctl(FD, FIONREAD, &len);
+ printf("goodbye2: len=%d -- ", len);
+ rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
+ dumbuf[rlen] = '\0';
+ printf("read (%d): %s\r\n", rlen, dumbuf);
+#endif
+ }
+ ioctl(FD, TIOCFLUSH, 0); /* clear the input buffer */
+ ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */
+ close(FD);
+}
+
+#define MAXRETRY 5
+
+hay_sync()
+{
+ int len, retry = 0;
+
+ while (retry++ <= MAXRETRY) {
+ write(FD, "AT\r", 3);
+ sleep(1);
+ ioctl(FD, FIONREAD, &len);
+ if (len) {
+ len = read(FD, dumbuf, min(len, DUMBUFLEN));
+ if (index(dumbuf, '0') ||
+ (index(dumbuf, 'O') && index(dumbuf, 'K')))
+ return(1);
+#ifdef DEBUG
+ dumbuf[len] = '\0';
+ printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
+#endif
+ }
+ ioctl(FD, TIOCCDTR, 0);
+ ioctl(FD, TIOCSDTR, 0);
+ }
+ printf("Cannot synchronize with hayes...\n\r");
+ return(0);
+}
diff --git a/usr.bin/tip/libacu/multitech.c b/usr.bin/tip/libacu/multitech.c
new file mode 100644
index 0000000..41d42b3
--- /dev/null
+++ b/usr.bin/tip/libacu/multitech.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)multitech.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Courier modem.
+ * Derived from Hayes driver.
+ */
+#include "tipconf.h"
+#include "tip.h"
+#include "acucommon.h"
+
+#include <stdio.h>
+
+/* #define DEBUG */
+#define MAXRETRY 5
+/*
+ Configuration
+*/
+static CONST char *dial_command = "ATDT";
+static CONST char *hangup_command = "ATH\r";
+static CONST char *echo_off_command = "ATE0\r";
+static CONST char *reset_command = "\rATZ\r";
+static CONST char *init_string = "AT$BA0$SB38400&E1&E4&E13&E15Q0V1X4E0S0=0\r";
+static CONST char *escape_sequence = "+++"; /* return to command escape sequence */
+static CONST int lock_baud = 1;
+static CONST unsigned int intercharacter_delay = 20;
+static CONST unsigned int intercommand_delay = 250;
+static CONST unsigned int escape_guard_time = 250;
+static CONST unsigned int reset_delay = 2000;
+
+/*
+ Forward declarations
+*/
+void multitech_write (int fd, CONST char *cp, int n);
+void multitech_write_str (int fd, CONST char *cp);
+void multitech_disconnect ();
+void acu_nap (unsigned int how_long);
+static void sigALRM ();
+static int multitechsync ();
+static int multitech_swallow (register char *match);
+
+/*
+ Global vars
+*/
+static int timeout = 0;
+static int connected = 0;
+static jmp_buf timeoutbuf, intbuf;
+
+int multitech_dialer (register char *num, char *acu)
+{
+ register char *cp;
+#if ACULOG
+ char line [80];
+#endif
+ static int multitech_connect(), multitech_swallow();
+
+ if (lock_baud)
+ {
+ int i;
+ if ((i = speed(number(value(BAUDRATE)))) == NULL)
+ return 0;
+ ttysetup (i);
+ }
+
+ if (boolean(value(VERBOSE)))
+ printf("Using \"%s\"\n", acu);
+
+ acu_hupcl ();
+
+ /*
+ * Get in synch.
+ */
+ if (!multitechsync()) {
+badsynch:
+ printf("can't synchronize with multitech\n");
+#if ACULOG
+ logent(value(HOST), num, "multitech", "can't synch up");
+#endif
+ return (0);
+ }
+ acu_nap (intercommand_delay);
+
+ multitech_write_str (FD, echo_off_command); /* turn off echoing */
+
+ sleep(1);
+
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ multitech_verbose_read();
+#endif
+
+ acu_flush ();
+
+ acu_nap (intercommand_delay);
+ multitech_write_str (FD, init_string);
+
+ if (!multitech_swallow ("\r\nOK\r\n"))
+ goto badsynch;
+
+ fflush (stdout);
+
+ acu_nap (intercommand_delay);
+ multitech_write_str (FD, dial_command);
+
+ for (cp = num; *cp; cp++)
+ if (*cp == '=')
+ *cp = ',';
+
+ multitech_write_str (FD, num);
+
+ multitech_write_str (FD, "\r");
+
+ connected = multitech_connect();
+
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "multitech", line);
+ }
+#endif
+ if (timeout)
+ multitech_disconnect ();
+ return (connected);
+}
+
+void multitech_disconnect ()
+{
+ int okay, retries;
+ for (retries = okay = 0; retries < 3 && !okay; retries++)
+ {
+ /* first hang up the modem*/
+ ioctl (FD, TIOCCDTR, 0);
+ acu_nap (escape_guard_time);
+ ioctl (FD, TIOCSDTR, 0);
+ acu_nap (escape_guard_time);
+ /*
+ * If not strapped for DTR control, try to get command mode.
+ */
+ acu_nap (escape_guard_time);
+ multitech_write_str (FD, escape_sequence);
+ acu_nap (escape_guard_time);
+ multitech_write_str (FD, hangup_command);
+ okay = multitech_swallow ("\r\nOK\r\n");
+ }
+ if (!okay)
+ {
+ #if ACULOG
+ logent(value(HOST), "", "multitech", "can't hang up modem");
+ #endif
+ if (boolean(value(VERBOSE)))
+ printf("hang up failed\n");
+ }
+ close (FD);
+}
+
+void multitech_abort ()
+{
+ multitech_write_str (FD, "\r"); /* send anything to abort the call */
+ multitech_disconnect ();
+}
+
+static void sigALRM ()
+{
+ (void) printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int multitech_swallow (register char *match)
+ {
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ do {
+ if (*match =='\0') {
+ signal(SIGALRM, f);
+ return (1);
+ }
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ } while (c == *match++);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ fflush (stdout);
+#endif
+ signal(SIGALRM, SIG_DFL);
+ return (0);
+}
+
+static struct baud_msg {
+ char *msg;
+ int baud;
+} baud_msg[] = {
+ "", B300,
+ " 1200", B1200,
+ " 2400", B2400,
+ " 9600", B9600,
+ " 9600/ARQ", B9600,
+ 0, 0,
+};
+
+static int multitech_connect ()
+{
+ char c;
+ int nc, nl, n;
+ char dialer_buf[64];
+ struct baud_msg *bm;
+ sig_t f;
+
+ if (multitech_swallow("\r\n") == 0)
+ return (0);
+ f = signal(SIGALRM, sigALRM);
+again:
+ nc = 0; nl = sizeof(dialer_buf)-1;
+ bzero(dialer_buf, sizeof(dialer_buf));
+ timeout = 0;
+ for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
+ if (setjmp(timeoutbuf))
+ break;
+ alarm(number(value(DIALTIMEOUT)));
+ n = read(FD, &c, 1);
+ alarm(0);
+ if (n <= 0)
+ break;
+ c &= 0x7f;
+ if (c == '\r') {
+ if (multitech_swallow("\n") == 0)
+ break;
+ if (!dialer_buf[0])
+ goto again;
+ if (strcmp(dialer_buf, "RINGING") == 0 &&
+ boolean(value(VERBOSE))) {
+#ifdef DEBUG
+ printf("%s\r\n", dialer_buf);
+#endif
+ goto again;
+ }
+ if (strncmp(dialer_buf, "CONNECT",
+ sizeof("CONNECT")-1) != 0)
+ break;
+ if (lock_baud) {
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ for (bm = baud_msg ; bm->msg ; bm++)
+ if (strcmp(bm->msg, dialer_buf+sizeof("CONNECT")-1) == 0) {
+ if (!acu_setspeed (bm->baud))
+ goto error;
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ break;
+ }
+ dialer_buf[nc] = c;
+ }
+error1:
+ printf("%s\r\n", dialer_buf);
+error:
+ signal(SIGALRM, f);
+ return (0);
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the multitech in sync.
+ */
+static int multitechsync ()
+{
+ int already = 0;
+ int len;
+ char buf[40];
+
+ while (already++ < MAXRETRY) {
+ acu_nap (intercommand_delay);
+ ioctl (FD, TIOCFLUSH, 0); /* flush any clutter */
+ multitech_write_str (FD, reset_command); /* reset modem */
+ bzero(buf, sizeof(buf));
+ acu_nap (reset_delay);
+ ioctl (FD, FIONREAD, &len);
+ if (len) {
+ len = read(FD, buf, sizeof(buf));
+#ifdef DEBUG
+ buf [len] = '\0';
+ printf("multitechsync: (\"%s\")\n\r", buf);
+#endif
+ if (index(buf, '0') ||
+ (index(buf, 'O') && index(buf, 'K')))
+ return(1);
+ }
+ /*
+ * If not strapped for DTR control,
+ * try to get command mode.
+ */
+ acu_nap (escape_guard_time);
+ multitech_write_str (FD, escape_sequence);
+ acu_nap (escape_guard_time);
+ multitech_write_str (FD, hangup_command);
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected.
+ */
+ acu_nap (escape_guard_time);
+ ioctl (FD, TIOCCDTR, 0);
+ acu_nap (escape_guard_time);
+ ioctl (FD, TIOCSDTR, 0);
+ }
+ acu_nap (intercommand_delay);
+ multitech_write_str (FD, reset_command);
+ return (0);
+}
+
+void multitech_write_str (int fd, const char *cp)
+{
+#ifdef DEBUG
+ printf ("multitech: sending %s\n", cp);
+#endif
+ multitech_write (fd, cp, strlen (cp));
+}
+
+void multitech_write (int fd, const char *cp, int n)
+{
+ acu_flush ();
+ acu_nap (intercharacter_delay);
+ for ( ; n-- ; cp++) {
+ write (fd, cp, 1);
+ acu_flush ();
+ acu_nap (intercharacter_delay);
+ }
+}
+
+#ifdef DEBUG
+multitech_verbose_read()
+{
+ int n = 0;
+ char buf[BUFSIZ];
+
+ if (ioctl(FD, FIONREAD, &n) < 0)
+ return;
+ if (n <= 0)
+ return;
+ if (read(FD, buf, n) != n)
+ return;
+ write(1, buf, n);
+}
+#endif
+
+/* end of multitech.c */
diff --git a/usr.bin/tip/libacu/t3000.c b/usr.bin/tip/libacu/t3000.c
new file mode 100644
index 0000000..1c9f472
--- /dev/null
+++ b/usr.bin/tip/libacu/t3000.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Telebit T3000 modem.
+ * Derived from Courier driver.
+ */
+#include "tipconf.h"
+#include "tip.h"
+#include "acucommon.h"
+#include <stdio.h>
+
+#define MAXRETRY 5
+
+static void sigALRM();
+static int timeout = 0;
+static int connected = 0;
+static jmp_buf timeoutbuf, intbuf;
+static int t3000_sync();
+
+t3000_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ register char *cp;
+#if ACULOG
+ char line[80];
+#endif
+ static int t3000_connect(), t3000_swallow();
+
+ if (boolean(value(VERBOSE)))
+ printf("Using \"%s\"\n", acu);
+
+ acu_hupcl ();
+ /*
+ * Get in synch.
+ */
+ if (!t3000_sync()) {
+badsynch:
+ printf("can't synchronize with t3000\n");
+#if ACULOG
+ logent(value(HOST), num, "t3000", "can't synch up");
+#endif
+ return (0);
+ }
+ t3000_write(FD, "AT E0\r", 6); /* turn off echoing */
+ sleep(1);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ t3000_verbose_read();
+#endif
+ ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
+ t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
+ if (!t3000_swallow("\r\nOK\r\n"))
+ goto badsynch;
+ fflush(stdout);
+ t3000_write(FD, "AT D", 4);
+ for (cp = num; *cp; cp++)
+ if (*cp == '=')
+ *cp = ',';
+ t3000_write(FD, num, strlen(num));
+ t3000_write(FD, "\r", 1);
+ connected = t3000_connect();
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "t3000", line);
+ }
+#endif
+ if (timeout)
+ t3000_disconnect();
+ return (connected);
+}
+
+t3000_disconnect()
+{
+ /* first hang up the modem*/
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ t3000_sync(); /* reset */
+ close(FD);
+}
+
+t3000_abort()
+{
+ t3000_write(FD, "\r", 1); /* send anything to abort the call */
+ t3000_disconnect();
+}
+
+static void
+sigALRM()
+{
+ printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int
+t3000_swallow(match)
+ register char *match;
+ {
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ do {
+ if (*match =='\0') {
+ signal(SIGALRM, f);
+ return (1);
+ }
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ } while (c == *match++);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ fflush(stdout);
+#endif
+ signal(SIGALRM, SIG_DFL);
+ return (0);
+}
+
+#ifndef B19200 /* XXX */
+#define B19200 EXTA
+#define B38400 EXTB
+#endif
+
+struct tbaud_msg {
+ char *msg;
+ int baud;
+ int baud2;
+} tbaud_msg[] = {
+ "", B300, 0,
+ " 1200", B1200, 0,
+ " 2400", B2400, 0,
+ " 4800", B4800, 0,
+ " 9600", B9600, 0,
+ " 14400", B19200, B9600,
+ " 19200", B19200, B9600,
+ " 38400", B38400, B9600,
+ " 57600", B38400, B9600,
+ " 7512", B9600, 0,
+ " 1275", B2400, 0,
+ " 7200", B9600, 0,
+ " 12000", B19200, B9600,
+ 0, 0, 0,
+};
+
+static int
+t3000_connect()
+{
+ char c;
+ int nc, nl, n;
+ char dialer_buf[64];
+ struct tbaud_msg *bm;
+ sig_t f;
+
+ if (t3000_swallow("\r\n") == 0)
+ return (0);
+ f = signal(SIGALRM, sigALRM);
+again:
+ nc = 0; nl = sizeof(dialer_buf)-1;
+ bzero(dialer_buf, sizeof(dialer_buf));
+ timeout = 0;
+ for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
+ if (setjmp(timeoutbuf))
+ break;
+ alarm(number(value(DIALTIMEOUT)));
+ n = read(FD, &c, 1);
+ alarm(0);
+ if (n <= 0)
+ break;
+ c &= 0x7f;
+ if (c == '\r') {
+ if (t3000_swallow("\n") == 0)
+ break;
+ if (!dialer_buf[0])
+ goto again;
+ if (strcmp(dialer_buf, "RINGING") == 0 &&
+ boolean(value(VERBOSE))) {
+#ifdef DEBUG
+ printf("%s\r\n", dialer_buf);
+#endif
+ goto again;
+ }
+ if (strncmp(dialer_buf, "CONNECT",
+ sizeof("CONNECT")-1) != 0)
+ break;
+ for (bm = tbaud_msg ; bm->msg ; bm++)
+ if (strcmp(bm->msg,
+ dialer_buf+sizeof("CONNECT")-1) == 0) {
+ if (!(acu_setspeed (bm->baud) || (bm->baud2 && acu_setspeed (bm->baud2))))
+ goto error;
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ break;
+ }
+ dialer_buf[nc] = c;
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ }
+error1:
+ printf("%s\r\n", dialer_buf);
+error:
+ signal(SIGALRM, f);
+ return (0);
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the t3000 in sync.
+ */
+static int
+t3000_sync()
+{
+ int already = 0;
+ int len;
+ char buf[40];
+
+ while (already++ < MAXRETRY) {
+ ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
+ t3000_write(FD, "\rAT Z\r", 6); /* reset modem */
+ bzero(buf, sizeof(buf));
+ sleep(2);
+ ioctl(FD, FIONREAD, &len);
+#if 1
+if (len == 0) len = 1;
+#endif
+ if (len) {
+ len = read(FD, buf, sizeof(buf));
+#ifdef DEBUG
+ buf[len] = '\0';
+ printf("t3000_sync: (\"%s\")\n\r", buf);
+#endif
+ if (index(buf, '0') ||
+ (index(buf, 'O') && index(buf, 'K')))
+ return(1);
+ }
+ /*
+ * If not strapped for DTR control,
+ * try to get command mode.
+ */
+ sleep(1);
+ t3000_write(FD, "+++", 3);
+ sleep(1);
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected.
+ */
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ }
+ t3000_write(FD, "\rAT Z\r", 6);
+ return (0);
+}
+
+t3000_write(fd, cp, n)
+int fd;
+char *cp;
+int n;
+{
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ write(1, cp, n);
+#endif
+ acu_flush ();
+ t3000_nap();
+ for ( ; n-- ; cp++) {
+ write(fd, cp, 1);
+ acu_flush ();
+ t3000_nap();
+ }
+}
+
+#ifdef DEBUG
+t3000_verbose_read()
+{
+ int n = 0;
+ char buf[BUFSIZ];
+
+ if (ioctl(FD, FIONREAD, &n) < 0)
+ return;
+ if (n <= 0)
+ return;
+ if (read(FD, buf, n) != n)
+ return;
+ write(1, buf, n);
+}
+#endif
+
+t3000_nap()
+{
+ acu_nap (50);
+}
+
+/* end of t3000.c */
diff --git a/usr.bin/tip/libacu/tod.c b/usr.bin/tip/libacu/tod.c
new file mode 100644
index 0000000..f585063
--- /dev/null
+++ b/usr.bin/tip/libacu/tod.c
@@ -0,0 +1,107 @@
+/*
+ * tod.c -- time of day pseudo-class implementation
+ *
+ * Copyright (c) 1995 John H. Poplett
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author
+ * John H. Poplett.
+ * 4. This work was done expressly for inclusion into FreeBSD. Other use
+ * is allowed if this notation is included.
+ * 5. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "tod.h"
+
+#define USP 1000000
+
+int tod_cmp (const struct timeval *a, const struct timeval *b)
+{
+ int rc;
+ assert (a->tv_usec <= USP);
+ assert (b->tv_usec <= USP);
+ rc = a->tv_sec - b->tv_sec;
+ if (rc == 0)
+ rc = a->tv_usec - b->tv_usec;
+ return rc;
+}
+
+/*
+ TOD < command
+*/
+int tod_lt (const struct timeval *a, const struct timeval *b)
+{
+ return tod_cmp (a, b) < 0;
+}
+
+int tod_gt (const struct timeval *a, const struct timeval *b)
+{
+ return tod_cmp (a, b) > 0;
+}
+
+int tod_lte (const struct timeval *a, const struct timeval *b)
+{
+ return tod_cmp (a, b) <= 0;
+}
+
+int tod_gte (const struct timeval *a, const struct timeval *b)
+{
+ return tod_cmp (a, b) >= 0;
+}
+
+int tod_eq (const struct timeval *a, const struct timeval *b)
+{
+ return tod_cmp (a, b) == 0;
+}
+
+/*
+ TOD += command
+*/
+void tod_addto (struct timeval *a, const struct timeval *b)
+{
+ a->tv_usec += b->tv_usec;
+ a->tv_sec += b->tv_sec + a->tv_usec / USP;
+ a->tv_usec %= USP;
+}
+
+/*
+ TOD -= command
+*/
+void tod_subfrom (struct timeval *a, struct timeval b)
+{
+ assert (a->tv_usec <= USP);
+ assert (b.tv_usec <= USP);
+ if (b.tv_usec > a->tv_usec)
+ {
+ a->tv_usec += USP;
+ a->tv_sec -= 1;
+ }
+ a->tv_usec -= b.tv_usec;
+ a->tv_sec -= b.tv_sec;
+}
+
+void tod_gettime (struct timeval *tp)
+{
+ gettimeofday (tp, NULL);
+ tp->tv_sec += tp->tv_usec / USP;
+ tp->tv_usec %= USP;
+}
+
+/* end of tod.c */
diff --git a/usr.bin/tip/libacu/tod.h b/usr.bin/tip/libacu/tod.h
new file mode 100644
index 0000000..d772230
--- /dev/null
+++ b/usr.bin/tip/libacu/tod.h
@@ -0,0 +1,9 @@
+int tod_cmp (const struct timeval *a, const struct timeval *b);
+int tod_lt (const struct timeval *a, const struct timeval *b) ;
+int tod_gt (const struct timeval *a, const struct timeval *b);
+int tod_lte (const struct timeval *a, const struct timeval *b);
+int tod_gte (const struct timeval *a, const struct timeval *b);
+int tod_eq (const struct timeval *a, const struct timeval *b);
+void tod_addto (struct timeval *a, const struct timeval *b);
+void tod_subfrom (struct timeval *a, struct timeval b);
+void tod_gettime (struct timeval *tp);
diff --git a/usr.bin/tip/libacu/unidialer.c b/usr.bin/tip/libacu/unidialer.c
new file mode 100644
index 0000000..4f8a1f5
--- /dev/null
+++ b/usr.bin/tip/libacu/unidialer.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)unidialer.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Generalized routines for calling up on a Hayes AT command set based modem.
+ * Control variables are pulled out of a modem caps-style database to
+ * configure the driver for a particular modem.
+ */
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+#include <sys/times.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "acucommon.h"
+#include "tod.h"
+
+/* #define DEBUG */
+#define MAXRETRY 5
+
+typedef enum
+{
+ mpt_notype, mpt_string, mpt_number, mpt_boolean
+} modem_parm_type_t;
+
+typedef struct {
+ modem_parm_type_t modem_parm_type;
+ const char *name;
+ union {
+ char **string;
+ unsigned int *number;
+ } value;
+ union {
+ char *string;
+ unsigned int number;
+ } default_value;
+} modem_parm_t;
+
+/*
+ Configuration
+*/
+static char modem_name [80];
+static char *dial_command;
+static char *hangup_command;
+static char *echo_off_command;
+static char *reset_command;
+static char *init_string;
+static char *escape_sequence;
+static int hw_flow_control;
+static int lock_baud;
+static unsigned int intercharacter_delay;
+static unsigned int intercommand_delay;
+static unsigned int escape_guard_time;
+static unsigned int reset_delay;
+
+static int unidialer_dialer (register char *num, char *acu);
+static void unidialer_disconnect ();
+static void unidialer_abort ();
+
+static acu_t unidialer =
+{
+ modem_name,
+ unidialer_dialer,
+ unidialer_disconnect,
+ unidialer_abort
+};
+
+/*
+ Table of parameters kept in modem database
+*/
+modem_parm_t modem_parms [] = {
+ { mpt_string, "dial_command", &dial_command, "ATDT%s\r" },
+ { mpt_string, "hangup_command", &hangup_command, "ATH\r", },
+ { mpt_string, "echo_off_command", &echo_off_command, "ATE0\r" },
+ { mpt_string, "reset_command", &reset_command, "ATZ\r" },
+ { mpt_string, "init_string", &init_string, "AT&F\r", },
+ { mpt_string, "escape_sequence", &escape_sequence, "+++" },
+ { mpt_boolean, "hw_flow_control", (char **)&hw_flow_control, NULL },
+ { mpt_boolean, "lock_baud", (char **)&lock_baud, NULL },
+ { mpt_number, "intercharacter_delay", (char **)&intercharacter_delay, (char *)50 },
+ { mpt_number, "intercommand_delay", (char **)&intercommand_delay, (char *)300 },
+ { mpt_number, "escape_guard_time", (char **)&escape_guard_time, (char *)300 },
+ { mpt_number, "reset_delay", (char **)&reset_delay, (char *)3000 },
+ { mpt_notype, NULL, NULL, NULL }
+};
+
+/*
+ Forward declarations
+*/
+static void unidialer_verbose_read ();
+static void unidialer_modem_cmd (int fd, CONST char *cmd);
+static void unidialer_write (int fd, CONST char *cp, int n);
+static void unidialer_write_str (int fd, CONST char *cp);
+static void unidialer_disconnect ();
+static void sigALRM ();
+static int unidialersync ();
+static int unidialer_swallow (register char *match);
+
+/*
+ Global vars
+*/
+static int timeout = 0;
+static int connected = 0;
+static jmp_buf timeoutbuf, intbuf;
+
+#define cgetflag(f) (cgetcap(bp, f, ':') != NULL)
+
+#ifdef DEBUG
+
+#define print_str(x) printf (#x " = %s\n", x)
+#define print_num(x) printf (#x " = %d\n", x)
+
+void dumpmodemparms (char *modem)
+{
+ printf ("modem parms for %s\n", modem);
+ print_str (dial_command);
+ print_str (hangup_command);
+ print_str (echo_off_command);
+ print_str (reset_command);
+ print_str (init_string);
+ print_str (escape_sequence);
+ print_num (lock_baud);
+ print_num (intercharacter_delay);
+ print_num (intercommand_delay);
+ print_num (escape_guard_time);
+ print_num (reset_delay);
+ printf ("\n");
+}
+#endif
+
+static int getmodemparms (const char *modem)
+{
+ char *bp, *db_array [3], *modempath;
+ int ndx, stat;
+ modem_parm_t *mpp;
+
+ modempath = getenv ("MODEMS");
+
+ ndx = 0;
+
+ if (modempath != NULL)
+ db_array [ndx++] = modempath;
+
+ db_array [ndx++] = _PATH_MODEMS;
+ db_array [ndx] = NULL;
+
+ if ((stat = cgetent (&bp, db_array, (char *)modem)) < 0) {
+ switch (stat) {
+ case -1:
+ fprintf (stderr, "tip: unknown modem %s\n", modem);
+ break;
+ case -2:
+ fprintf (stderr, "tip: can't open modem description file\n");
+ break;
+ case -3:
+ fprintf (stderr, "tip: possible reference loop in modem description file\n");
+ break;
+ }
+ return 0;
+ }
+ for (mpp = modem_parms; mpp->name; mpp++)
+ {
+ switch (mpp->modem_parm_type)
+ {
+ case mpt_string:
+ if (cgetstr (bp, (char *)mpp->name, mpp->value.string) == -1)
+ *mpp->value.string = mpp->default_value.string;
+ break;
+
+ case mpt_number:
+ {
+ long l;
+ if (cgetnum (bp, (char *)mpp->name, &l) == -1)
+ *mpp->value.number = mpp->default_value.number;
+ else
+ *mpp->value.number = (unsigned int)l;
+ }
+ break;
+
+ case mpt_boolean:
+ *mpp->value.number = cgetflag ((char *)mpp->name);
+ break;
+ }
+ }
+ strncpy (modem_name, modem, sizeof (modem_name) - 1);
+ modem_name [sizeof (modem_name) - 1] = '\0';
+ return 1;
+}
+
+/*
+*/
+acu_t* unidialer_getmodem (const char *modem_name)
+{
+ acu_t* rc = NOACU;
+ if (getmodemparms (modem_name))
+ rc = &unidialer;
+ return rc;
+}
+
+static int unidialer_modem_ready ()
+{
+#ifdef TIOCMGET
+ int state;
+ ioctl (FD, TIOCMGET, &state);
+ return (state & TIOCM_DSR) ? 1 : 0;
+#else
+ return (1);
+#endif
+}
+
+static int unidialer_waitfor_modem_ready (int ms)
+{
+#ifdef TIOCMGET
+ int count;
+ for (count = 0; count < ms; count += 100)
+ {
+ if (unidialer_modem_ready ())
+ {
+#ifdef DEBUG
+ printf ("unidialer_waitfor_modem_ready: modem ready.\n");
+#endif
+ break;
+ }
+ acu_nap (100);
+ }
+ return (count < ms);
+#else
+ acu_nap (250);
+ return (1);
+#endif
+}
+
+int unidialer_tty_clocal (int flag)
+{
+#if HAVE_TERMIOS
+ struct termios t;
+ tcgetattr (FD, &t);
+ if (flag)
+ t.c_cflag |= CLOCAL;
+ else
+ t.c_cflag &= ~CLOCAL;
+ tcsetattr (FD, TCSANOW, &t);
+#elif defined(TIOCMSET)
+ int state;
+ /*
+ Don't have CLOCAL so raise CD in software to
+ get the same effect.
+ */
+ ioctl (FD, TIOCMGET, &state);
+ if (flag)
+ state |= TIOCM_CD;
+ else
+ state &= ~TIOCM_CD;
+ ioctl (FD, TIOCMSET, &state);
+#endif
+}
+
+int unidialer_get_modem_response (char *buf, int bufsz, int response_timeout)
+{
+ sig_t f;
+ char c, *p = buf, *lid = buf + bufsz - 1;
+ int state;
+
+ assert (bufsz > 0);
+
+ f = signal (SIGALRM, sigALRM);
+
+ timeout = 0;
+
+ if (setjmp (timeoutbuf)) {
+ signal (SIGALRM, f);
+ *p = '\0';
+#ifdef DEBUG
+ printf ("get_response: timeout buf=%s, state=%d\n", buf, state);
+#endif
+ return (0);
+ }
+
+ ualarm (response_timeout * 1000, 0);
+
+ state = 0;
+
+ while (1)
+ {
+ switch (state)
+ {
+ case 0:
+ if (read (FD, &c, 1) == 1)
+ {
+ if (c == '\r')
+ {
+ ++state;
+ }
+ else
+ {
+#ifdef DEBUG
+ printf ("get_response: unexpected char %s.\n", ctrl (c));
+#endif
+ }
+ }
+ break;
+
+ case 1:
+ if (read (FD, &c, 1) == 1)
+ {
+ if (c == '\n')
+ {
+#ifdef DEBUG
+ printf ("get_response: <CRLF> encountered.\n", buf);
+#endif
+ ++state;
+ }
+ else
+ {
+ state = 0;
+#ifdef DEBUG
+ printf ("get_response: unexpected char %s.\n", ctrl (c));
+#endif
+ }
+ }
+ break;
+
+ case 2:
+ if (read (FD, &c, 1) == 1)
+ {
+ if (c == '\r')
+ ++state;
+ else if (c >= ' ' && p < lid)
+ *p++ = c;
+ }
+ break;
+
+ case 3:
+ if (read (FD, &c, 1) == 1)
+ {
+ if (c == '\n')
+ {
+ signal (SIGALRM, f);
+ /* ualarm (0, 0); */
+ alarm (0);
+ *p = '\0';
+#ifdef DEBUG
+ printf ("get_response: %s\n", buf);
+#endif
+ return (1);
+ }
+ else
+ {
+ state = 0;
+ p = buf;
+ }
+ }
+ break;
+ }
+ }
+}
+
+int unidialer_get_okay (int ms)
+{
+ int okay;
+ char buf [BUFSIZ];
+ okay = unidialer_get_modem_response (buf, sizeof (buf), ms) &&
+ strcmp (buf, "OK") == 0;
+ return okay;
+}
+
+static int unidialer_dialer (register char *num, char *acu)
+{
+ register char *cp;
+ char dial_string [80];
+#if ACULOG
+ char line [80];
+#endif
+ static int unidialer_connect(), unidialer_swallow();
+
+ #ifdef DEBUG
+ dumpmodemparms (modem_name);
+ #endif
+
+ if (lock_baud) {
+ int i;
+ if ((i = speed(number(value(BAUDRATE)))) == NULL)
+ return 0;
+ ttysetup (i);
+ }
+
+ if (boolean(value(VERBOSE)))
+ printf("Using \"%s\"\n", acu);
+
+ acu_hupcl ();
+
+ /*
+ * Get in synch.
+ */
+ if (!unidialersync()) {
+badsynch:
+ printf("tip: can't synchronize with %s\n", modem_name);
+#if ACULOG
+ logent(value(HOST), num, modem_name, "can't synch up");
+#endif
+ return (0);
+ }
+
+ unidialer_modem_cmd (FD, echo_off_command); /* turn off echoing */
+
+ sleep(1);
+
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ unidialer_verbose_read();
+#endif
+
+ acu_flush (); /* flush any clutter */
+
+ unidialer_modem_cmd (FD, init_string);
+
+ if (!unidialer_get_okay (reset_delay))
+ goto badsynch;
+
+ fflush (stdout);
+
+ for (cp = num; *cp; cp++)
+ if (*cp == '=')
+ *cp = ',';
+
+ (void) sprintf (dial_string, dial_command, num);
+
+ unidialer_modem_cmd (FD, dial_string);
+
+ connected = unidialer_connect ();
+
+ if (connected && hw_flow_control) {
+ acu_hw_flow_control (hw_flow_control);
+ }
+
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, modem_name, line);
+ }
+#endif
+
+ if (timeout)
+ unidialer_disconnect ();
+
+ return (connected);
+}
+
+static void unidialer_disconnect ()
+{
+ int okay, retries;
+
+ acu_flush (); /* flush any clutter */
+
+ unidialer_tty_clocal (TRUE);
+
+ /* first hang up the modem*/
+ ioctl (FD, TIOCCDTR, 0);
+ acu_nap (250);
+ ioctl (FD, TIOCSDTR, 0);
+
+ /*
+ * If AT&D2, then dropping DTR *should* just hangup the modem. But
+ * some modems reset anyway; also, the modem may be programmed to reset
+ * anyway with AT&D3. Play it safe and wait for the full reset time before
+ * proceeding.
+ */
+ acu_nap (reset_delay);
+
+ if (!unidialer_waitfor_modem_ready (reset_delay))
+ {
+#ifdef DEBUG
+ printf ("unidialer_disconnect: warning CTS low.\r\n");
+#endif
+ }
+
+ /*
+ * If not strapped for DTR control, try to get command mode.
+ */
+ for (retries = okay = 0; retries < MAXRETRY && !okay; retries++)
+ {
+ int timeout_value;
+ /* flush any clutter */
+ if (!acu_flush ())
+ {
+#ifdef DEBUG
+ printf ("unidialer_disconnect: warning flush failed.\r\n");
+#endif
+ }
+ timeout_value = escape_guard_time;
+ timeout_value += (timeout_value * retries / MAXRETRY);
+ acu_nap (timeout_value);
+ acu_flush (); /* flush any clutter */
+ unidialer_modem_cmd (FD, escape_sequence);
+ acu_nap (timeout_value);
+ unidialer_modem_cmd (FD, hangup_command);
+ okay = unidialer_get_okay (reset_delay);
+ }
+ if (!okay)
+ {
+ #if ACULOG
+ logent(value(HOST), "", modem_name, "can't hang up modem");
+ #endif
+ if (boolean(value(VERBOSE)))
+ printf("hang up failed\n");
+ }
+ (void) acu_flush ();
+ close (FD);
+}
+
+static void unidialer_abort ()
+{
+ unidialer_write_str (FD, "\r"); /* send anything to abort the call */
+ unidialer_disconnect ();
+}
+
+static void sigALRM ()
+{
+ (void) printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int unidialer_swallow (register char *match)
+{
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+
+ timeout = 0;
+
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+
+ alarm(number(value(DIALTIMEOUT)));
+
+ do {
+ if (*match =='\0') {
+ signal(SIGALRM, f);
+ alarm (0);
+ return (1);
+ }
+ do {
+ read (FD, &c, 1);
+ } while (c == '\0');
+ c &= 0177;
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ {
+ /* putchar(c); */
+ printf (ctrl (c));
+ }
+#endif
+ } while (c == *match++);
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ fflush (stdout);
+#endif
+ return (0);
+}
+
+static struct baud_msg {
+ char *msg;
+ int baud;
+} baud_msg[] = {
+ "", B300,
+ " 1200", B1200,
+ " 2400", B2400,
+ " 9600", B9600,
+ " 9600/ARQ", B9600,
+ 0, 0,
+};
+
+static int unidialer_connect ()
+{
+ char c;
+ int nc, nl, n;
+ char dialer_buf[64];
+ struct baud_msg *bm;
+ sig_t f;
+
+ if (unidialer_swallow("\r\n") == 0)
+ return (0);
+ f = signal(SIGALRM, sigALRM);
+again:
+ nc = 0; nl = sizeof(dialer_buf)-1;
+ bzero(dialer_buf, sizeof(dialer_buf));
+ timeout = 0;
+ for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
+ if (setjmp(timeoutbuf))
+ break;
+ alarm(number(value(DIALTIMEOUT)));
+ n = read(FD, &c, 1);
+ alarm(0);
+ if (n <= 0)
+ break;
+ c &= 0x7f;
+ if (c == '\r') {
+ if (unidialer_swallow("\n") == 0)
+ break;
+ if (!dialer_buf[0])
+ goto again;
+ if (strcmp(dialer_buf, "RINGING") == 0 &&
+ boolean(value(VERBOSE))) {
+#ifdef DEBUG
+ printf("%s\r\n", dialer_buf);
+#endif
+ goto again;
+ }
+ if (strncmp(dialer_buf, "CONNECT",
+ sizeof("CONNECT")-1) != 0)
+ break;
+ if (lock_baud) {
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ for (bm = baud_msg ; bm->msg ; bm++)
+ if (strcmp(bm->msg, dialer_buf+sizeof("CONNECT")-1) == 0) {
+ if (!acu_setspeed (bm->baud))
+ goto error;
+ signal(SIGALRM, f);
+#ifdef DEBUG
+ if (boolean(value(VERBOSE)))
+ printf("%s\r\n", dialer_buf);
+#endif
+ return (1);
+ }
+ break;
+ }
+ dialer_buf[nc] = c;
+ }
+error1:
+ printf("%s\r\n", dialer_buf);
+error:
+ signal(SIGALRM, f);
+ return (0);
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the unidialer in sync.
+ */
+static int unidialersync ()
+{
+ int already = 0;
+ int len;
+ char buf[40];
+
+ while (already++ < MAXRETRY) {
+ acu_nap (intercommand_delay);
+ acu_flush (); /* flush any clutter */
+ unidialer_write_str (FD, reset_command); /* reset modem */
+ bzero(buf, sizeof(buf));
+ acu_nap (reset_delay);
+ ioctl (FD, FIONREAD, &len);
+ if (len) {
+ len = read(FD, buf, sizeof(buf));
+#ifdef DEBUG
+ buf [len] = '\0';
+ printf("unidialersync (%s): (\"%s\")\n\r", modem_name, buf);
+#endif
+ if (index(buf, '0') ||
+ (index(buf, 'O') && index(buf, 'K')))
+ return(1);
+ }
+ /*
+ * If not strapped for DTR control,
+ * try to get command mode.
+ */
+ acu_nap (escape_guard_time);
+ unidialer_write_str (FD, escape_sequence);
+ acu_nap (escape_guard_time);
+ unidialer_write_str (FD, hangup_command);
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected.
+ */
+ acu_nap (escape_guard_time);
+ ioctl (FD, TIOCCDTR, 0);
+ acu_nap (1000);
+ ioctl (FD, TIOCSDTR, 0);
+ }
+ acu_nap (intercommand_delay);
+ unidialer_write_str (FD, reset_command);
+ return (0);
+}
+
+/*
+ Send commands to modem; impose delay between commands.
+*/
+static void unidialer_modem_cmd (int fd, const char *cmd)
+{
+ static struct timeval oldt = { 0, 0 };
+ struct timeval newt;
+ tod_gettime (&newt);
+ if (tod_lt (&newt, &oldt))
+ {
+ unsigned int naptime;
+ tod_subfrom (&oldt, newt);
+ naptime = oldt.tv_sec * 1000 + oldt.tv_usec / 1000;
+ if (naptime > intercommand_delay)
+ {
+#ifdef DEBUG
+ printf ("unidialer_modem_cmd: suspicious naptime (%u ms)\r\n", naptime);
+#endif
+ naptime = intercommand_delay;
+ }
+#ifdef DEBUG
+ printf ("unidialer_modem_cmd: delaying %u ms\r\n", naptime);
+#endif
+ acu_nap (naptime);
+ }
+ unidialer_write_str (fd, cmd);
+ tod_gettime (&oldt);
+ newt.tv_sec = 0;
+ newt.tv_usec = intercommand_delay;
+ tod_addto (&oldt, &newt);
+}
+
+static void unidialer_write_str (int fd, const char *cp)
+{
+#ifdef DEBUG
+ printf ("unidialer (%s): sending %s\n", modem_name, cp);
+#endif
+ unidialer_write (fd, cp, strlen (cp));
+}
+
+static void unidialer_write (int fd, const char *cp, int n)
+{
+ acu_nap (intercharacter_delay);
+ for ( ; n-- ; cp++) {
+ write (fd, cp, 1);
+ acu_nap (intercharacter_delay);
+ }
+}
+
+#ifdef DEBUG
+static void unidialer_verbose_read()
+{
+ int n = 0;
+ char buf[BUFSIZ];
+
+ if (ioctl(FD, FIONREAD, &n) < 0)
+ return;
+ if (n <= 0)
+ return;
+ if (read(FD, buf, n) != n)
+ return;
+ write(1, buf, n);
+}
+#endif
+
+/* end of unidialer.c */
diff --git a/usr.bin/tip/libacu/v3451.c b/usr.bin/tip/libacu/v3451.c
new file mode 100644
index 0000000..a98c4d4
--- /dev/null
+++ b/usr.bin/tip/libacu/v3451.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v3451.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Vadic 3451 Modem
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+static jmp_buf Sjbuf;
+
+v3451_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ sig_t func;
+ int ok;
+ int slow = number(value(BAUDRATE)) < 1200, rw = 2;
+ char phone[50];
+#if ACULOG
+ char line[80];
+#endif
+ static int expect();
+ static void vawrite();
+
+ /*
+ * Get in synch
+ */
+ vawrite("I\r", 1 + slow);
+ vawrite("I\r", 1 + slow);
+ vawrite("I\r", 1 + slow);
+ vawrite("\005\r", 2 + slow);
+ if (!expect("READY")) {
+ printf("can't synchronize with vadic 3451\n");
+#if ACULOG
+ logent(value(HOST), num, "vadic", "can't synch up");
+#endif
+ return (0);
+ }
+ acu_hupcl ();
+ sleep(1);
+ vawrite("D\r", 2 + slow);
+ if (!expect("NUMBER?")) {
+ printf("Vadic will not accept dial command\n");
+#if ACULOG
+ logent(value(HOST), num, "vadic", "will not accept dial");
+#endif
+ return (0);
+ }
+ strcpy(phone, num);
+ strcat(phone, "\r");
+ vawrite(phone, 1 + slow);
+ if (!expect(phone)) {
+ printf("Vadic will not accept phone number\n");
+#if ACULOG
+ logent(value(HOST), num, "vadic", "will not accept number");
+#endif
+ return (0);
+ }
+ func = signal(SIGINT,SIG_IGN);
+ /*
+ * You cannot interrupt the Vadic when its dialing;
+ * even dropping DTR does not work (definitely a
+ * brain damaged design).
+ */
+ vawrite("\r", 1 + slow);
+ vawrite("\r", 1 + slow);
+ if (!expect("DIALING:")) {
+ printf("Vadic failed to dial\n");
+#if ACULOG
+ logent(value(HOST), num, "vadic", "failed to dial");
+#endif
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ ok = expect("ON LINE");
+ signal(SIGINT, func);
+ if (!ok) {
+ printf("call failed\n");
+#if ACULOG
+ logent(value(HOST), num, "vadic", "call failed");
+#endif
+ return (0);
+ }
+ ioctl(FD, TIOCFLUSH, &rw);
+ return (1);
+}
+
+v3451_disconnect()
+{
+
+ close(FD);
+}
+
+v3451_abort()
+{
+
+ close(FD);
+}
+
+static void
+vawrite(cp, delay)
+ register char *cp;
+ int delay;
+{
+
+ for (; *cp; sleep(delay), cp++)
+ write(FD, cp, 1);
+}
+
+static
+expect(cp)
+ register char *cp;
+{
+ char buf[300];
+ register char *rp = buf;
+ int timeout = 30, online = 0;
+ static int notin();
+ static void alarmtr();
+
+ if (strcmp(cp, "\"\"") == 0)
+ return (1);
+ *rp = 0;
+ /*
+ * If we are waiting for the Vadic to complete
+ * dialing and get a connection, allow more time
+ * Unfortunately, the Vadic times out 24 seconds after
+ * the last digit is dialed
+ */
+ online = strcmp(cp, "ON LINE") == 0;
+ if (online)
+ timeout = number(value(DIALTIMEOUT));
+ signal(SIGALRM, alarmtr);
+ if (setjmp(Sjbuf))
+ return (0);
+ alarm(timeout);
+ while (notin(cp, buf) && rp < buf + sizeof (buf) - 1) {
+ if (online && notin("FAILED CALL", buf) == 0)
+ return (0);
+ if (read(FD, rp, 1) < 0) {
+ alarm(0);
+ return (0);
+ }
+ if (*rp &= 0177)
+ rp++;
+ *rp = '\0';
+ }
+ alarm(0);
+ return (1);
+}
+
+static void
+alarmtr()
+{
+ longjmp(Sjbuf, 1);
+}
+
+static int
+notin(sh, lg)
+ char *sh, *lg;
+{
+ static int prefix();
+
+ for (; *lg; lg++)
+ if (prefix(sh, lg))
+ return (0);
+ return (1);
+}
+
+static
+prefix(s1, s2)
+ register char *s1, *s2;
+{
+ register char c;
+
+ while ((c = *s1++) == *s2++)
+ if (c == '\0')
+ return (1);
+ return (c == '\0');
+}
diff --git a/usr.bin/tip/libacu/v831.c b/usr.bin/tip/libacu/v831.c
new file mode 100644
index 0000000..b670c2a
--- /dev/null
+++ b/usr.bin/tip/libacu/v831.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v831.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for dialing up on Vadic 831
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+int v831_abort();
+static void alarmtr();
+extern int errno;
+
+static jmp_buf jmpbuf;
+static int child = -1;
+
+v831_dialer(num, acu)
+ char *num, *acu;
+{
+ int status, pid, connected = 1;
+ register int timelim;
+ static int dialit();
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+#ifdef DEBUG
+ printf ("(acu=%s)\n", acu);
+#endif
+ if ((AC = open(acu, O_RDWR)) < 0) {
+ if (errno == EBUSY)
+ printf("line busy...");
+ else
+ printf("acu open error...");
+ return (0);
+ }
+ if (setjmp(jmpbuf)) {
+ kill(child, SIGKILL);
+ close(AC);
+ return (0);
+ }
+ signal(SIGALRM, alarmtr);
+ timelim = 5 * strlen(num);
+ alarm(timelim < 30 ? 30 : timelim);
+ if ((child = fork()) == 0) {
+ /*
+ * ignore this stuff for aborts
+ */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ sleep(2);
+ exit(dialit(num, acu) != 'A');
+ }
+ /*
+ * open line - will return on carrier
+ */
+ if ((FD = open(DV, O_RDWR)) < 0) {
+#ifdef DEBUG
+ printf("(after open, errno=%d)\n", errno);
+#endif
+ if (errno == EIO)
+ printf("lost carrier...");
+ else
+ printf("dialup line open failed...");
+ alarm(0);
+ kill(child, SIGKILL);
+ close(AC);
+ return (0);
+ }
+ alarm(0);
+#ifdef notdef
+ ioctl(AC, TIOCHPCL, 0);
+#endif
+ signal(SIGALRM, SIG_DFL);
+ while ((pid = wait(&status)) != child && pid != -1)
+ ;
+ if (status) {
+ close(AC);
+ return (0);
+ }
+ return (1);
+}
+
+static void
+alarmtr()
+{
+ alarm(0);
+ longjmp(jmpbuf, 1);
+}
+
+/*
+ * Insurance, for some reason we don't seem to be
+ * hanging up...
+ */
+v831_disconnect()
+{
+ sleep(2);
+#ifdef DEBUG
+ printf("[disconnect: FD=%d]\n", FD);
+#endif
+ if (FD > 0) {
+ ioctl(FD, TIOCCDTR, 0);
+ acu_setspeec (0);
+ ioctl(FD, TIOCNXCL, 0);
+ }
+ close(FD);
+}
+
+v831_abort()
+{
+
+#ifdef DEBUG
+ printf("[abort: AC=%d]\n", AC);
+#endif
+ sleep(2);
+ if (child > 0)
+ kill(child, SIGKILL);
+ if (AC > 0)
+ ioctl(FD, TIOCNXCL, 0);
+ close(AC);
+ if (FD > 0)
+ ioctl(FD, TIOCCDTR, 0);
+ close(FD);
+}
+
+/*
+ * Sigh, this probably must be changed at each site.
+ */
+struct vaconfig {
+ char *vc_name;
+ char vc_rack;
+ char vc_modem;
+} vaconfig[] = {
+ { "/dev/cua0",'4','0' },
+ { "/dev/cua1",'4','1' },
+ { 0 }
+};
+
+#define pc(x) (c = x, write(AC,&c,1))
+#define ABORT 01
+#define SI 017
+#define STX 02
+#define ETX 03
+
+static int
+dialit(phonenum, acu)
+ register char *phonenum;
+ char *acu;
+{
+ register struct vaconfig *vp;
+ char c;
+ int i, two = 2;
+ static char *sanitize();
+
+ phonenum = sanitize(phonenum);
+#ifdef DEBUG
+ printf ("(dial phonenum=%s)\n", phonenum);
+#endif
+ if (*phonenum == '<' && phonenum[1] == 0)
+ return ('Z');
+ for (vp = vaconfig; vp->vc_name; vp++)
+ if (strcmp(vp->vc_name, acu) == 0)
+ break;
+ if (vp->vc_name == 0) {
+ printf("Unable to locate dialer (%s)\n", acu);
+ return ('K');
+ }
+ {
+#if HAVE_TERMIOS
+ struct termios termios;
+ tcgetattr (AC, &termios);
+ termios.c_iflag = 0;
+#ifndef _POSIX_SOURCE
+ termios.c_lflag = (PENDIN|ECHOKE|ECHOE);
+#else
+ termios.c_lflag = (PENDIN|ECHOE);
+#endif
+ termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
+ termios.c_ispeed = termios.c_ospeed = B2400;
+ tcsetattr (AC, TCSANOW, &termios);
+#else /* HAVE_TERMIOS */
+ struct sgttyb cntrl;
+ ioctl(AC, TIOCGETP, &cntrl);
+ cntrl.sg_ispeed = cntrl.sg_ospeed = B2400;
+ cntrl.sg_flags = RAW | EVENP | ODDP;
+ ioctl(AC, TIOCSETP, &cntrl);
+ #endif
+ }
+ ioctl(AC, TIOCFLUSH, &two);
+ pc(STX);
+ pc(vp->vc_rack);
+ pc(vp->vc_modem);
+ while (*phonenum && *phonenum != '<')
+ pc(*phonenum++);
+ pc(SI);
+ pc(ETX);
+ sleep(1);
+ i = read(AC, &c, 1);
+#ifdef DEBUG
+ printf("read %d chars, char=%c, errno %d\n", i, c, errno);
+#endif
+ if (i != 1)
+ c = 'M';
+ if (c == 'B' || c == 'G') {
+ char cc, oc = c;
+
+ pc(ABORT);
+ read(AC, &cc, 1);
+#ifdef DEBUG
+ printf("abort response=%c\n", cc);
+#endif
+ c = oc;
+ v831_disconnect();
+ }
+ close(AC);
+#ifdef DEBUG
+ printf("dialit: returns %c\n", c);
+#endif
+ return (c);
+}
+
+static char *
+sanitize(s)
+ register char *s;
+{
+ static char buf[128];
+ register char *cp;
+
+ for (cp = buf; *s; s++) {
+ if (!isdigit(*s) && *s == '<' && *s != '_')
+ continue;
+ if (*s == '_')
+ *s = '=';
+ *cp++ = *s;
+ }
+ *cp++ = 0;
+ return (buf);
+}
diff --git a/usr.bin/tip/libacu/ventel.c b/usr.bin/tip/libacu/ventel.c
new file mode 100644
index 0000000..73733e5
--- /dev/null
+++ b/usr.bin/tip/libacu/ventel.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ventel.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Routines for calling up on a Ventel Modem
+ * The Ventel is expected to be strapped for local echo (just like uucp)
+ */
+#include "tipconf.h"
+#include "tip.h"
+
+#define MAXRETRY 5
+
+static void sigALRM();
+static int timeout = 0;
+static jmp_buf timeoutbuf;
+
+/*
+ * some sleep calls have been replaced by this macro
+ * because some ventel modems require two <cr>s in less than
+ * a second in order to 'wake up'... yes, it is dirty...
+ */
+#define delay(num,denom) busyloop(CPUSPEED*num/denom)
+#define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
+#define DELAY(n) { register long N = (n); while (--N > 0); }
+busyloop(n) { DELAY(n); }
+
+ven_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ register char *cp;
+ register int connected = 0;
+ char *msg, *index(), line[80];
+ static int gobble(), vensync();
+ static void echo();
+
+ /*
+ * Get in synch with a couple of carriage returns
+ */
+ if (!vensync(FD)) {
+ printf("can't synchronize with ventel\n");
+#if ACULOG
+ logent(value(HOST), num, "ventel", "can't synch up");
+#endif
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+ acu_hupcl ();
+ echo("#k$\r$\n$D$I$A$L$:$ ");
+ for (cp = num; *cp; cp++) {
+ delay(1, 10);
+ write(FD, cp, 1);
+ }
+ delay(1, 10);
+ write(FD, "\r", 1);
+ gobble('\n', line);
+ if (gobble('\n', line))
+ connected = gobble('!', line);
+ acu_flush ();
+#if ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "ventel", line);
+ }
+#endif
+ if (timeout)
+ ven_disconnect(); /* insurance */
+ if (connected || timeout || !boolean(value(VERBOSE)))
+ return (connected);
+ /* call failed, parse response for user */
+ cp = index(line, '\r');
+ if (cp)
+ *cp = '\0';
+ for (cp = line; cp = index(cp, ' '); cp++)
+ if (cp[1] == ' ')
+ break;
+ if (cp) {
+ while (*cp == ' ')
+ cp++;
+ msg = cp;
+ while (*cp) {
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ cp++;
+ }
+ printf("%s...", msg);
+ }
+ return (connected);
+}
+
+ven_disconnect()
+{
+
+ close(FD);
+}
+
+ven_abort()
+{
+
+ write(FD, "\03", 1);
+ close(FD);
+}
+
+static void
+echo(s)
+ register char *s;
+{
+ char c;
+
+ while (c = *s++) switch (c) {
+
+ case '$':
+ read(FD, &c, 1);
+ s++;
+ break;
+
+ case '#':
+ c = *s++;
+ write(FD, &c, 1);
+ break;
+
+ default:
+ write(FD, &c, 1);
+ read(FD, &c, 1);
+ }
+}
+
+static void
+sigALRM()
+{
+ printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+static int
+gobble(match, response)
+ register char match;
+ char response[];
+{
+ register char *cp = response;
+ sig_t f;
+ char c;
+
+ f = signal(SIGALRM, sigALRM);
+ timeout = 0;
+ do {
+ if (setjmp(timeoutbuf)) {
+ signal(SIGALRM, f);
+ *cp = '\0';
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, cp, 1);
+ alarm(0);
+ c = (*cp++ &= 0177);
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ } while (c != '\n' && c != match);
+ signal(SIGALRM, SIG_DFL);
+ *cp = '\0';
+ return (c == match);
+}
+
+#define min(a,b) ((a)>(b)?(b):(a))
+/*
+ * This convoluted piece of code attempts to get
+ * the ventel in sync. If you don't have FIONREAD
+ * there are gory ways to simulate this.
+ */
+static int
+vensync(fd)
+{
+ int already = 0, nread;
+ char buf[60];
+
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected, and insure a consistent state
+ * to start from.
+ *
+ * If you don't have the ioctl calls to diddle directly
+ * with DTR, you can always try setting the baud rate to 0.
+ */
+ ioctl(FD, TIOCCDTR, 0);
+ sleep(1);
+ ioctl(FD, TIOCSDTR, 0);
+ while (already < MAXRETRY) {
+ /*
+ * After reseting the modem, send it two \r's to
+ * autobaud on. Make sure to delay between them
+ * so the modem can frame the incoming characters.
+ */
+ write(fd, "\r", 1);
+ delay(1,10);
+ write(fd, "\r", 1);
+ sleep(2);
+ if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) {
+ perror("tip: ioctl");
+ continue;
+ }
+ while (nread > 0) {
+ read(fd, buf, min(nread, 60));
+ if ((buf[nread - 1] & 0177) == '$')
+ return (1);
+ nread -= min(nread, 60);
+ }
+ sleep(1);
+ already++;
+ }
+ return (0);
+}
+
diff --git a/usr.bin/tip/tip/Makefile b/usr.bin/tip/tip/Makefile
new file mode 100644
index 0000000..af720f3
--- /dev/null
+++ b/usr.bin/tip/tip/Makefile
@@ -0,0 +1,25 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+#
+# Files are:
+# /etc/remote remote host description file
+# /etc/phones phone number file, owned by ${OWNER} and
+# mode 6??
+# /var/log/aculog ACU accounting file, owned by ${OWNER} and
+# mode 6?? {if ACULOG defined}
+
+.if exists(${.OBJDIR}/../libacu)
+LIBACU=${.OBJDIR}/../libacu/libacu.a
+.else
+LIBACU=${.CURDIR}/../libacu/libacu.a
+.endif
+
+PROG= tip
+DPADD= ${LIBACU} ${LIBUTIL}
+LDADD= ${LIBACU} -lutil
+LINKS= ${BINDIR}/tip
+MAN1= tip.1
+MAN5= modems.5
+SRCS= acu.c acutab.c cmds.c cmdtab.c cu.c hunt.c log.c partab.c \
+ remote.c tip.c tipout.c value.c vars.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/tip/tip/acu.c b/usr.bin/tip/tip/acu.c
new file mode 100644
index 0000000..d320249
--- /dev/null
+++ b/usr.bin/tip/tip/acu.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)acu.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+#if UNIDIALER
+acu_t* unidialer_getmodem (const char *modem_name);
+#endif
+
+static acu_t *acu = NOACU;
+static int conflag;
+static void acuabort();
+static acu_t *acutype();
+static jmp_buf jmpbuf;
+/*
+ * Establish connection for tip
+ *
+ * If DU is true, we should dial an ACU whose type is AT.
+ * The phone numbers are in PN, and the call unit is in CU.
+ *
+ * If the PN is an '@', then we consult the PHONES file for
+ * the phone numbers. This file is /etc/phones, unless overriden
+ * by an exported shell variable.
+ *
+ * The data base files must be in the format:
+ * host-name[ \t]*phone-number
+ * with the possibility of multiple phone numbers
+ * for a single host acting as a rotary (in the order
+ * found in the file).
+ */
+char *
+connect()
+{
+ register char *cp = PN;
+ char *phnum, string[256];
+ FILE *fd;
+ int tried = 0;
+
+ if (!DU) { /* regular connect message */
+ if (CM != NOSTR)
+ pwrite(FD, CM, size(CM));
+ logent(value(HOST), "", DV, "call completed");
+ return (NOSTR);
+ }
+ /*
+ * @ =>'s use data base in PHONES environment variable
+ * otherwise, use /etc/phones
+ */
+ signal(SIGINT, acuabort);
+ signal(SIGQUIT, acuabort);
+ if (setjmp(jmpbuf)) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ printf("\ncall aborted\n");
+ logent(value(HOST), "", "", "call aborted");
+ if (acu != NOACU) {
+ boolean(value(VERBOSE)) = FALSE;
+ if (conflag)
+ disconnect(NOSTR);
+ else
+ (*acu->acu_abort)();
+ }
+ return ("interrupt");
+ }
+ if ((acu = acutype(AT)) == NOACU)
+ return ("unknown ACU type");
+ if (*cp != '@') {
+ while (*cp) {
+ for (phnum = cp; *cp && *cp != ','; cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+
+ if (conflag = (*acu->acu_dialer)(phnum, CU)) {
+ if (CM != NOSTR)
+ pwrite(FD, CM, size(CM));
+ logent(value(HOST), phnum, acu->acu_name,
+ "call completed");
+ return (NOSTR);
+ } else
+ logent(value(HOST), phnum, acu->acu_name,
+ "call failed");
+ tried++;
+ }
+ } else {
+ if ((fd = fopen(PH, "r")) == NOFILE) {
+ printf("%s: ", PH);
+ return ("can't open phone number file");
+ }
+ while (fgets(string, sizeof(string), fd) != NOSTR) {
+ for (cp = string; !any(*cp, " \t\n"); cp++)
+ ;
+ if (*cp == '\n') {
+ fclose(fd);
+ return ("unrecognizable host name");
+ }
+ *cp++ = '\0';
+ if (strcmp(string, value(HOST)))
+ continue;
+ while (any(*cp, " \t"))
+ cp++;
+ if (*cp == '\n') {
+ fclose(fd);
+ return ("missing phone number");
+ }
+ for (phnum = cp; *cp && *cp != ',' && *cp != '\n'; cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+
+ if (conflag = (*acu->acu_dialer)(phnum, CU)) {
+ fclose(fd);
+ if (CM != NOSTR)
+ pwrite(FD, CM, size(CM));
+ logent(value(HOST), phnum, acu->acu_name,
+ "call completed");
+ return (NOSTR);
+ } else
+ logent(value(HOST), phnum, acu->acu_name,
+ "call failed");
+ tried++;
+ }
+ fclose(fd);
+ }
+ if (!tried)
+ logent(value(HOST), "", acu->acu_name, "missing phone number");
+ else
+ (*acu->acu_abort)();
+ return (tried ? "call failed" : "missing phone number");
+}
+
+disconnect(reason)
+ char *reason;
+{
+ if (!conflag) {
+ logent(value(HOST), "", DV, "call terminated");
+ return;
+ }
+ if (reason == NOSTR) {
+ logent(value(HOST), "", acu->acu_name, "call terminated");
+ if (boolean(value(VERBOSE)))
+ printf("\r\ndisconnecting...");
+ } else
+ logent(value(HOST), "", acu->acu_name, reason);
+ (*acu->acu_disconnect)();
+}
+
+static void
+acuabort(s)
+{
+ signal(s, SIG_IGN);
+ longjmp(jmpbuf, 1);
+}
+
+static acu_t *
+acutype(s)
+ register char *s;
+{
+ register acu_t *p;
+ extern acu_t acutable[];
+
+ for (p = acutable; p->acu_name != '\0'; p++)
+ if (!strcmp(s, p->acu_name))
+ return (p);
+
+ #if UNIDIALER
+ return unidialer_getmodem (s);
+ #else
+ return (NOACU);
+ #endif
+}
diff --git a/usr.bin/tip/tip/acutab.c b/usr.bin/tip/tip/acutab.c
new file mode 100644
index 0000000..c482493
--- /dev/null
+++ b/usr.bin/tip/tip/acutab.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)acutab.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+extern int df02_dialer(), df03_dialer(),
+ biz31f_dialer(),
+ biz31w_dialer(),
+ biz22f_dialer(),
+ biz22w_dialer(),
+ ven_dialer(),
+ hay_dialer(),
+ cour_dialer(),
+ multitech_dialer(),
+ t3000_dialer(),
+ v3451_dialer(),
+ v831_dialer(),
+ dn_dialer();
+
+extern void df_disconnect(), df_abort(),
+ biz31_disconnect(), biz31_abort(),
+ biz22_disconnect(), biz22_abort(),
+ ven_disconnect(), ven_abort(),
+ hay_disconnect(), hay_abort(),
+ cour_disconnect(), cour_abort(),
+ multitech_disconnect(), multitech_abort(),
+ t3000_disconnect(), t3000_abort(),
+ v3451_disconnect(), v3451_abort(),
+ v831_disconnect(), v831_abort(),
+ dn_disconnect(), dn_abort();
+
+acu_t acutable[] = {
+#if BIZ1031
+ "biz31f", biz31f_dialer, biz31_disconnect, biz31_abort,
+ "biz31w", biz31w_dialer, biz31_disconnect, biz31_abort,
+#endif
+#if BIZ1022
+ "biz22f", biz22f_dialer, biz22_disconnect, biz22_abort,
+ "biz22w", biz22w_dialer, biz22_disconnect, biz22_abort,
+#endif
+#if DF02
+ "df02", df02_dialer, df_disconnect, df_abort,
+#endif
+#if DF03
+ "df03", df03_dialer, df_disconnect, df_abort,
+#endif
+#if DN11
+ "dn11", dn_dialer, dn_disconnect, dn_abort,
+#endif
+#if VENTEL
+ "ventel",ven_dialer, ven_disconnect, ven_abort,
+#endif
+#if HAYES
+ "hayes",hay_dialer, hay_disconnect, hay_abort,
+#endif
+#if COURIER
+ "courier",cour_dialer, cour_disconnect, cour_abort,
+#endif
+#if MULTITECH
+ "multitech",multitech_dialer, multitech_disconnect, multitech_abort,
+#endif
+#if T3000
+ "t3000",t3000_dialer, t3000_disconnect, t3000_abort,
+#endif
+#if V3451
+#if !V831
+ "vadic",v3451_dialer, v3451_disconnect, v3451_abort,
+#endif
+ "v3451",v3451_dialer, v3451_disconnect, v3451_abort,
+#endif
+#if V831
+#if !V3451
+ "vadic",v831_dialer, v831_disconnect, v831_abort,
+#endif
+ "v831",v831_dialer, v831_disconnect, v831_abort,
+#endif
+ 0, 0, 0, 0
+};
+
diff --git a/usr.bin/tip/tip/cmds.c b/usr.bin/tip/tip/cmds.c
new file mode 100644
index 0000000..9ce6bff
--- /dev/null
+++ b/usr.bin/tip/tip/cmds.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+#include <stdio.h>
+
+/*
+ * tip
+ *
+ * miscellaneous commands
+ */
+
+int quant[] = { 60, 60, 24 };
+
+char null = '\0';
+char *sep[] = { "second", "minute", "hour" };
+static char *argv[10]; /* argument vector for take and put */
+
+void timeout(); /* timeout function called on alarm */
+void stopsnd(); /* SIGINT handler during file transfers */
+void intcopy(); /* interrupt routine for file transfers */
+
+void
+usedefchars ()
+{
+#if HAVE_TERMIOS
+ int cnt;
+ struct termios ttermios;
+ ttermios = ctermios;
+ for (cnt = 0; cnt < NCCS; cnt++)
+ ttermios.c_cc [cnt] = otermios.c_cc [cnt];
+ tcsetattr (0, TCSANOW, &ttermios);
+#else
+ ioctl(0, TIOCSETC, &defchars);
+#endif
+}
+
+void
+usetchars ()
+{
+#if HAVE_TERMIOS
+ tcsetattr (0, TCSANOW, &ctermios);
+#else
+ ioctl(0, TIOCSETC, &tchars);
+#endif
+}
+
+void
+flush_remote ()
+{
+#ifdef TIOCFLUSH
+ int cmd = 0;
+ ioctl (FD, TIOCFLUSH, &cmd);
+#else
+ struct sgttyb buf;
+ ioctl (FD, TIOCGETP, &buf); /* this does a */
+ ioctl (FD, TIOCSETP, &buf); /* wflushtty */
+#endif
+}
+
+/*
+ * FTP - remote ==> local
+ * get a file from the remote host
+ */
+getfl(c)
+ char c;
+{
+ char buf[256], *cp, *expand();
+
+ putchar(c);
+ /*
+ * get the UNIX receiving file's name
+ */
+ if (prompt("Local file name? ", copyname))
+ return;
+ cp = expand(copyname);
+ if ((sfd = creat(cp, 0666)) < 0) {
+ printf("\r\n%s: cannot creat\r\n", copyname);
+ return;
+ }
+
+ /*
+ * collect parameters
+ */
+ if (prompt("List command for remote system? ", buf)) {
+ unlink(copyname);
+ return;
+ }
+ transfer(buf, sfd, value(EOFREAD));
+}
+
+/*
+ * Cu-like take command
+ */
+cu_take(cc)
+ char cc;
+{
+ int fd, argc;
+ char line[BUFSIZ], *expand(), *cp;
+
+ if (prompt("[take] ", copyname))
+ return;
+ if ((argc = args(copyname, argv)) < 1 || argc > 2) {
+ printf("usage: <take> from [to]\r\n");
+ return;
+ }
+ if (argc == 1)
+ argv[1] = argv[0];
+ cp = expand(argv[1]);
+ if ((fd = creat(cp, 0666)) < 0) {
+ printf("\r\n%s: cannot create\r\n", argv[1]);
+ return;
+ }
+ (void)sprintf(line, "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
+ xfer(line, fd, "\n___tip_end_of_file_marker___\n");
+}
+
+extern jmp_buf intbuf;
+
+xfer(buf, fd, eofchars)
+ char *buf, *eofchars;
+{
+ register int ct;
+ char c, *match;
+ register int cnt, eof, v;
+ time_t start;
+ sig_t f;
+ char r;
+ FILE *ff;
+
+ v = boolean(value(VERBOSE));
+
+ if ((ff = fdopen (fd, "w")) == NULL) {
+ perror("file open");
+ return;
+ }
+ if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
+ if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
+ perror("file allocation");
+ (void)fclose(ff);
+ return;
+ }
+
+ pwrite(FD, buf, size(buf));
+ quit = 0;
+ kill(pid, SIGIOT);
+ read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
+
+ /*
+ * finish command
+ */
+ r = '\r';
+ pwrite(FD, &r, 1);
+ do
+ read(FD, &c, 1);
+ while ((c&0177) != '\n');
+
+ usedefchars ();
+
+ (void) setjmp(intbuf);
+ f = signal(SIGINT, intcopy);
+ start = time(0);
+ match = eofchars;
+ for (ct = 0; !quit;) {
+ eof = read(FD, &c, 1) <= 0;
+ c &= 0177;
+ if (quit)
+ continue;
+ if (eof)
+ break;
+ if (c == 0)
+ continue; /* ignore nulls */
+ if (c == '\r')
+ continue;
+ if (c != *match && match > eofchars) {
+ register char *p = eofchars;
+ while (p < match) {
+ if (*p == '\n'&& v)
+ (void)printf("\r%d", ++ct);
+ fputc(*p++, ff);
+ }
+ match = eofchars;
+ }
+ if (c == *match) {
+ if (*++match == '\0')
+ break;
+ } else {
+ if (c == '\n' && v)
+ (void)printf("\r%d", ++ct);
+ fputc(c, ff);
+ }
+ }
+ if (v)
+ prtime(" lines transferred in ", time(0)-start);
+ usetchars ();
+ write(fildes[1], (char *)&ccc, 1);
+ signal(SIGINT, f);
+ (void)fclose(ff);
+}
+
+static jmp_buf intbuf;
+/*
+ * Bulk transfer routine --
+ * used by getfl(), cu_take(), and pipefile()
+ */
+transfer(buf, fd, eofchars)
+ char *buf, *eofchars;
+{
+ register int ct;
+ char c, buffer[BUFSIZ];
+ register char *p = buffer;
+ register int cnt, eof, v;
+ time_t start;
+ sig_t f;
+ char r;
+ FILE *ff;
+
+ v = boolean(value(VERBOSE));
+
+ if ((ff = fdopen (fd, "w")) == NULL) {
+ perror("file open");
+ return;
+ }
+ if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
+ if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
+ perror("file allocation");
+ (void)fclose(ff);
+ return;
+ }
+
+ pwrite(FD, buf, size(buf));
+ quit = 0;
+ kill(pid, SIGIOT);
+ read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
+
+ /*
+ * finish command
+ */
+ r = '\r';
+ pwrite(FD, &r, 1);
+ do
+ read(FD, &c, 1);
+ while ((c&0177) != '\n');
+ usedefchars ();
+ (void) setjmp(intbuf);
+ f = signal(SIGINT, intcopy);
+ start = time(0);
+ for (ct = 0; !quit;) {
+ eof = read(FD, &c, 1) <= 0;
+ c &= 0177;
+ if (quit)
+ continue;
+ if (eof || any(c, eofchars))
+ break;
+ if (c == 0)
+ continue; /* ignore nulls */
+ if (c == '\r')
+ continue;
+ if (c == '\n' && v)
+ printf("\r%d", ++ct);
+ fputc(c, ff);
+ }
+ if (v)
+ prtime(" lines transferred in ", time(0)-start);
+ usetchars ();
+ write(fildes[1], (char *)&ccc, 1);
+ signal(SIGINT, f);
+ (void)fclose(ff);
+}
+
+/*
+ * FTP - remote ==> local process
+ * send remote input to local process via pipe
+ */
+pipefile()
+{
+ int cpid, pdes[2];
+ char buf[256];
+ int status, p;
+ extern int errno;
+
+ if (prompt("Local command? ", buf))
+ return;
+
+ if (pipe(pdes)) {
+ printf("can't establish pipe\r\n");
+ return;
+ }
+
+ if ((cpid = fork()) < 0) {
+ printf("can't fork!\r\n");
+ return;
+ } else if (cpid) {
+ if (prompt("List command for remote system? ", buf)) {
+ close(pdes[0]), close(pdes[1]);
+ kill (cpid, SIGKILL);
+ } else {
+ close(pdes[0]);
+ signal(SIGPIPE, intcopy);
+ transfer(buf, pdes[1], value(EOFREAD));
+ signal(SIGPIPE, SIG_DFL);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ }
+ } else {
+ register int f;
+
+ dup2(pdes[0], 0);
+ close(pdes[0]);
+ for (f = 3; f < 20; f++)
+ close(f);
+ execute(buf);
+ printf("can't execl!\r\n");
+ exit(0);
+ }
+}
+
+/*
+ * Interrupt service routine for FTP
+ */
+void
+stopsnd()
+{
+
+ stop = 1;
+ signal(SIGINT, SIG_IGN);
+}
+
+/*
+ * FTP - local ==> remote
+ * send local file to remote host
+ * terminate transmission with pseudo EOF sequence
+ */
+sendfile(cc)
+ char cc;
+{
+ FILE *fd;
+ char *fnamex;
+ char *expand();
+
+ putchar(cc);
+ /*
+ * get file name
+ */
+ if (prompt("Local file name? ", fname))
+ return;
+
+ /*
+ * look up file
+ */
+ fnamex = expand(fname);
+ if ((fd = fopen(fnamex, "r")) == NULL) {
+ printf("%s: cannot open\r\n", fname);
+ return;
+ }
+ transmit(fd, value(EOFWRITE), NULL);
+ if (!boolean(value(ECHOCHECK))) {
+ flush_remote ();
+ }
+}
+
+/*
+ * Bulk transfer routine to remote host --
+ * used by sendfile() and cu_put()
+ */
+transmit(fd, eofchars, command)
+ FILE *fd;
+ char *eofchars, *command;
+{
+ char *pc, lastc;
+ int c, ccount, lcount;
+ time_t start_t, stop_t;
+ sig_t f;
+
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ stop = 0;
+ f = signal(SIGINT, stopsnd);
+ usedefchars ();
+ read(repdes[0], (char *)&ccc, 1);
+ if (command != NULL) {
+ for (pc = command; *pc; pc++)
+ send(*pc);
+ if (boolean(value(ECHOCHECK)))
+ read(FD, (char *)&c, 1); /* trailing \n */
+ else {
+ flush_remote ();
+ sleep(5); /* wait for remote stty to take effect */
+ }
+ }
+ lcount = 0;
+ lastc = '\0';
+ start_t = time(0);
+ while (1) {
+ ccount = 0;
+ do {
+ c = getc(fd);
+ if (stop)
+ goto out;
+ if (c == EOF)
+ goto out;
+ if (c == 0177 && !boolean(value(RAWFTP)))
+ continue;
+ lastc = c;
+ if (c < 040) {
+ if (c == '\n') {
+ if (!boolean(value(RAWFTP)))
+ c = '\r';
+ }
+ else if (c == '\t') {
+ if (!boolean(value(RAWFTP))) {
+ if (boolean(value(TABEXPAND))) {
+ send(' ');
+ while ((++ccount % 8) != 0)
+ send(' ');
+ continue;
+ }
+ }
+ } else
+ if (!boolean(value(RAWFTP)))
+ continue;
+ }
+ send(c);
+ } while (c != '\r' && !boolean(value(RAWFTP)));
+ if (boolean(value(VERBOSE)))
+ printf("\r%d", ++lcount);
+ if (boolean(value(ECHOCHECK))) {
+ timedout = 0;
+ alarm((int)value(ETIMEOUT));
+ do { /* wait for prompt */
+ read(FD, (char *)&c, 1);
+ if (timedout || stop) {
+ if (timedout)
+ printf("\r\ntimed out at eol\r\n");
+ alarm(0);
+ goto out;
+ }
+ } while ((c&0177) != character(value(PROMPT)));
+ alarm(0);
+ }
+ }
+out:
+ if (lastc != '\n' && !boolean(value(RAWFTP)))
+ send('\r');
+ for (pc = eofchars; *pc; pc++)
+ send(*pc);
+ stop_t = time(0);
+ fclose(fd);
+ signal(SIGINT, f);
+ if (boolean(value(VERBOSE)))
+ if (boolean(value(RAWFTP)))
+ prtime(" chars transferred in ", stop_t-start_t);
+ else
+ prtime(" lines transferred in ", stop_t-start_t);
+ write(fildes[1], (char *)&ccc, 1);
+ usetchars ();
+}
+
+/*
+ * Cu-like put command
+ */
+cu_put(cc)
+ char cc;
+{
+ FILE *fd;
+ char line[BUFSIZ];
+ int argc;
+ char *expand();
+ char *copynamex;
+
+ if (prompt("[put] ", copyname))
+ return;
+ if ((argc = args(copyname, argv)) < 1 || argc > 2) {
+ printf("usage: <put> from [to]\r\n");
+ return;
+ }
+ if (argc == 1)
+ argv[1] = argv[0];
+ copynamex = expand(argv[0]);
+ if ((fd = fopen(copynamex, "r")) == NULL) {
+ printf("%s: cannot open\r\n", copynamex);
+ return;
+ }
+ if (boolean(value(ECHOCHECK)))
+ sprintf(line, "cat>%s\r", argv[1]);
+ else
+ sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
+ transmit(fd, "\04", line);
+}
+
+/*
+ * FTP - send single character
+ * wait for echo & handle timeout
+ */
+send(c)
+ char c;
+{
+ char cc;
+ int retry = 0;
+
+ cc = c;
+ pwrite(FD, &cc, 1);
+#ifdef notdef
+ if (number(value(CDELAY)) > 0 && c != '\r')
+ nap(number(value(CDELAY)));
+#endif
+ if (!boolean(value(ECHOCHECK))) {
+#ifdef notdef
+ if (number(value(LDELAY)) > 0 && c == '\r')
+ nap(number(value(LDELAY)));
+#endif
+ return;
+ }
+tryagain:
+ timedout = 0;
+ alarm((int)value(ETIMEOUT));
+ read(FD, &cc, 1);
+ alarm(0);
+ if (timedout) {
+ printf("\r\ntimeout error (%s)\r\n", ctrl(c));
+ if (retry++ > 3)
+ return;
+ pwrite(FD, &null, 1); /* poke it */
+ goto tryagain;
+ }
+}
+
+void
+timeout()
+{
+ signal(SIGALRM, timeout);
+ timedout = 1;
+}
+
+/*
+ * Stolen from consh() -- puts a remote file on the output of a local command.
+ * Identical to consh() except for where stdout goes.
+ */
+pipeout(c)
+{
+ char buf[256];
+ int cpid, status, p;
+ time_t start;
+
+ putchar(c);
+ if (prompt("Local command? ", buf))
+ return;
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ usedefchars ();
+ read(repdes[0], (char *)&ccc, 1);
+ /*
+ * Set up file descriptors in the child and
+ * let it go...
+ */
+ if ((cpid = fork()) < 0)
+ printf("can't fork!\r\n");
+ else if (cpid) {
+ start = time(0);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ } else {
+ register int i;
+
+ dup2(FD, 1);
+ for (i = 3; i < 20; i++)
+ close(i);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ execute(buf);
+ printf("can't find `%s'\r\n", buf);
+ exit(0);
+ }
+ if (boolean(value(VERBOSE)))
+ prtime("away for ", time(0)-start);
+ write(fildes[1], (char *)&ccc, 1);
+ usetchars ();
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+}
+
+#if CONNECT
+
+int
+tiplink (char *cmd, unsigned int flags)
+{
+ int cpid, status, p;
+ time_t start;
+
+ if (flags & TL_SIGNAL_TIPOUT) {
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ usedefchars ();
+ read(repdes[0], (char *)&ccc, 1);
+ }
+
+ /*
+ * Set up file descriptors in the child and
+ * let it go...
+ */
+ if ((cpid = fork()) < 0)
+ printf("can't fork!\r\n");
+ else if (cpid) {
+ start = time(0);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ } else {
+ register int fd;
+
+ dup2(FD, 0);
+ dup2(3, 1);
+ for (fd = 3; fd < 20; fd++)
+ close (fd);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ execute (cmd);
+ printf("can't find `%s'\r\n", cmd);
+ exit(0);
+ }
+
+ if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
+ prtime("away for ", time(0)-start);
+
+ if (flags & TL_SIGNAL_TIPOUT) {
+ write(fildes[1], (char *)&ccc, 1);
+ usetchars ();
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ }
+
+ return 0;
+}
+
+/*
+ * Fork a program with:
+ * 0 <-> remote tty in
+ * 1 <-> remote tty out
+ * 2 <-> local tty out
+ */
+consh(c)
+{
+ char buf[256];
+ putchar(c);
+ if (prompt("Local command? ", buf))
+ return;
+ tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
+}
+#endif
+
+/*
+ * Escape to local shell
+ */
+shell()
+{
+ int shpid, status;
+ extern char **environ;
+ char *cp;
+
+ printf("[sh]\r\n");
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ unraw();
+ if (shpid = fork()) {
+ while (shpid != wait(&status));
+ raw();
+ printf("\r\n!\r\n");
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ return;
+ } else {
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ if ((cp = rindex(value(SHELL), '/')) == NULL)
+ cp = value(SHELL);
+ else
+ cp++;
+ shell_uid();
+ execl(value(SHELL), cp, 0);
+ printf("\r\ncan't execl!\r\n");
+ exit(1);
+ }
+}
+
+/*
+ * TIPIN portion of scripting
+ * initiate the conversation with TIPOUT
+ */
+setscript()
+{
+ char c;
+ /*
+ * enable TIPOUT side for dialogue
+ */
+ kill(pid, SIGEMT);
+ if (boolean(value(SCRIPT)))
+ write(fildes[1], value(RECORD), size(value(RECORD)));
+ write(fildes[1], "\n", 1);
+ /*
+ * wait for TIPOUT to finish
+ */
+ read(repdes[0], &c, 1);
+ if (c == 'n')
+ printf("can't create %s\r\n", value(RECORD));
+}
+
+/*
+ * Change current working directory of
+ * local portion of tip
+ */
+chdirectory()
+{
+ char dirname[80];
+ register char *cp = dirname;
+
+ if (prompt("[cd] ", dirname)) {
+ if (stoprompt)
+ return;
+ cp = value(HOME);
+ }
+ if (chdir(cp) < 0)
+ printf("%s: bad directory\r\n", cp);
+ printf("!\r\n");
+}
+
+tipabort(msg)
+ char *msg;
+{
+
+ kill(pid, SIGTERM);
+ disconnect(msg);
+ if (msg != NOSTR)
+ printf("\r\n%s", msg);
+ printf("\r\n[EOT]\r\n");
+ daemon_uid();
+ (void)uu_unlock(uucplock);
+ unraw();
+ exit(0);
+}
+
+finish()
+{
+ char *abortmsg = NOSTR, *dismsg;
+
+ if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
+ abortmsg = "logout failed";
+ }
+
+ if ((dismsg = value(DISCONNECT)) != NOSTR) {
+ write(FD, dismsg, strlen(dismsg));
+ sleep (2);
+ }
+ tipabort(abortmsg);
+}
+
+void
+intcopy()
+{
+ raw();
+ quit = 1;
+ longjmp(intbuf, 1);
+}
+
+execute(s)
+ char *s;
+{
+ register char *cp;
+
+ if ((cp = rindex(value(SHELL), '/')) == NULL)
+ cp = value(SHELL);
+ else
+ cp++;
+ shell_uid();
+ execl(value(SHELL), cp, "-c", s, 0);
+}
+
+args(buf, a)
+ char *buf, *a[];
+{
+ register char *p = buf, *start;
+ register char **parg = a;
+ register int n = 0;
+
+ do {
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+ start = p;
+ if (*p)
+ *parg = p;
+ while (*p && (*p != ' ' && *p != '\t'))
+ p++;
+ if (p != start)
+ parg++, n++;
+ if (*p)
+ *p++ = '\0';
+ } while (*p);
+
+ return(n);
+}
+
+prtime(s, a)
+ char *s;
+ time_t a;
+{
+ register i;
+ int nums[3];
+
+ for (i = 0; i < 3; i++) {
+ nums[i] = (int)(a % quant[i]);
+ a /= quant[i];
+ }
+ printf("%s", s);
+ while (--i >= 0)
+ if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
+ printf("%d %s%c ", nums[i], sep[i],
+ nums[i] == 1 ? '\0' : 's');
+ printf("\r\n!\r\n");
+}
+
+variable()
+{
+ char buf[256];
+
+ if (prompt("[set] ", buf))
+ return;
+ vlex(buf);
+ if (vtable[BEAUTIFY].v_access&CHANGED) {
+ vtable[BEAUTIFY].v_access &= ~CHANGED;
+ kill(pid, SIGSYS);
+ }
+ if (vtable[SCRIPT].v_access&CHANGED) {
+ vtable[SCRIPT].v_access &= ~CHANGED;
+ setscript();
+ /*
+ * So that "set record=blah script" doesn't
+ * cause two transactions to occur.
+ */
+ if (vtable[RECORD].v_access&CHANGED)
+ vtable[RECORD].v_access &= ~CHANGED;
+ }
+ if (vtable[RECORD].v_access&CHANGED) {
+ vtable[RECORD].v_access &= ~CHANGED;
+ if (boolean(value(SCRIPT)))
+ setscript();
+ }
+ if (vtable[TAND].v_access&CHANGED) {
+ vtable[TAND].v_access &= ~CHANGED;
+ if (boolean(value(TAND)))
+ tandem("on");
+ else
+ tandem("off");
+ }
+ if (vtable[LECHO].v_access&CHANGED) {
+ vtable[LECHO].v_access &= ~CHANGED;
+ HD = boolean(value(LECHO));
+ }
+ if (vtable[PARITY].v_access&CHANGED) {
+ vtable[PARITY].v_access &= ~CHANGED;
+ setparity();
+ }
+}
+
+/*
+ * Turn tandem mode on or off for remote tty.
+ */
+tandem(option)
+ char *option;
+{
+#if HAVE_TERMIOS
+ struct termios ttermios;
+ tcgetattr (FD, &ttermios);
+ if (strcmp(option,"on") == 0) {
+ ttermios.c_iflag |= IXOFF;
+ ctermios.c_iflag |= IXOFF;
+ }
+ else {
+ ttermios.c_iflag &= ~IXOFF;
+ ctermios.c_iflag &= ~IXOFF;
+ }
+ tcsetattr (FD, TCSANOW, &ttermios);
+ tcsetattr (0, TCSANOW, &ctermios);
+#else /* HAVE_TERMIOS */
+ struct sgttyb rmtty;
+
+ ioctl(FD, TIOCGETP, &rmtty);
+ if (strcmp(option,"on") == 0) {
+ rmtty.sg_flags |= TANDEM;
+ arg.sg_flags |= TANDEM;
+ } else {
+ rmtty.sg_flags &= ~TANDEM;
+ arg.sg_flags &= ~TANDEM;
+ }
+ ioctl(FD, TIOCSETP, &rmtty);
+ ioctl(0, TIOCSETP, &arg);
+#endif /* HAVE_TERMIOS */
+}
+
+/*
+ * Send a break.
+ */
+genbrk()
+{
+
+ ioctl(FD, TIOCSBRK, NULL);
+ sleep(1);
+ ioctl(FD, TIOCCBRK, NULL);
+}
+
+/*
+ * Suspend tip
+ */
+suspend(c)
+ char c;
+{
+
+ unraw();
+ kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
+ raw();
+}
+
+/*
+ * expand a file name if it includes shell meta characters
+ */
+
+char *
+expand(name)
+ char name[];
+{
+ static char xname[BUFSIZ];
+ char cmdbuf[BUFSIZ];
+ register int pid, l, rc;
+ register char *cp, *Shell;
+ int s, pivec[2], (*sigint)();
+
+ if (!anyof(name, "~{[*?$`'\"\\"))
+ return(name);
+ /* sigint = signal(SIGINT, SIG_IGN); */
+ if (pipe(pivec) < 0) {
+ perror("pipe");
+ /* signal(SIGINT, sigint) */
+ return(name);
+ }
+ sprintf(cmdbuf, "echo %s", name);
+ if ((pid = vfork()) == 0) {
+ Shell = value(SHELL);
+ if (Shell == NOSTR)
+ Shell = _PATH_BSHELL;
+ close(pivec[0]);
+ close(1);
+ dup(pivec[1]);
+ close(pivec[1]);
+ close(2);
+ shell_uid();
+ execl(Shell, Shell, "-c", cmdbuf, 0);
+ _exit(1);
+ }
+ if (pid == -1) {
+ perror("fork");
+ close(pivec[0]);
+ close(pivec[1]);
+ return(NOSTR);
+ }
+ close(pivec[1]);
+ l = read(pivec[0], xname, BUFSIZ);
+ close(pivec[0]);
+ while (wait(&s) != pid);
+ ;
+ s &= 0377;
+ if (s != 0 && s != SIGPIPE) {
+ fprintf(stderr, "\"Echo\" failed\n");
+ return(NOSTR);
+ }
+ if (l < 0) {
+ perror("read");
+ return(NOSTR);
+ }
+ if (l == 0) {
+ fprintf(stderr, "\"%s\": No match\n", name);
+ return(NOSTR);
+ }
+ if (l == BUFSIZ) {
+ fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
+ return(NOSTR);
+ }
+ xname[l] = 0;
+ for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+ ;
+ *++cp = '\0';
+ return(xname);
+}
+
+/*
+ * Are any of the characters in the two strings the same?
+ */
+
+anyof(s1, s2)
+ register char *s1, *s2;
+{
+ register int c;
+
+ while (c = *s1++)
+ if (any(c, s2))
+ return(1);
+ return(0);
+}
diff --git a/usr.bin/tip/tip/cmdtab.c b/usr.bin/tip/tip/cmdtab.c
new file mode 100644
index 0000000..12ecc07
--- /dev/null
+++ b/usr.bin/tip/tip/cmdtab.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+extern int shell(), getfl(), sendfile(), chdirectory();
+extern int finish(), help(), pipefile(), pipeout(), consh(), variable();
+extern int cu_take(), cu_put(), dollar(), genbrk(), suspend();
+
+esctable_t etable[] = {
+ { '!', NORM, "shell", shell },
+ { '<', NORM, "receive file from remote host", getfl },
+ { '>', NORM, "send file to remote host", sendfile },
+ { 't', NORM, "take file from remote UNIX", cu_take },
+ { 'p', NORM, "put file to remote UNIX", cu_put },
+ { '|', NORM, "pipe remote file", pipefile },
+ { '$', NORM, "pipe local command to remote host", pipeout },
+#if CONNECT
+ { 'C', NORM, "connect program to remote host",consh },
+#endif
+ { 'c', NORM, "change directory", chdirectory },
+ { '.', NORM, "exit from tip", finish },
+ {CTRL('d'),NORM,"exit from tip", finish },
+ {CTRL('y'),NORM,"suspend tip (local+remote)", suspend },
+ {CTRL('z'),NORM,"suspend tip (local only)", suspend },
+ { 's', NORM, "set variable", variable },
+ { '?', NORM, "get this summary", help },
+ { '#', NORM, "send break", genbrk },
+ { 0, 0, 0 }
+};
diff --git a/usr.bin/tip/tip/cu.c b/usr.bin/tip/tip/cu.c
new file mode 100644
index 0000000..bab8492
--- /dev/null
+++ b/usr.bin/tip/tip/cu.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cu.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+void cleanup();
+
+#if INCLUDE_CU_INTERFACE
+
+/*
+ * Botch the interface to look like cu's
+ */
+cumain(argc, argv)
+ char *argv[];
+{
+ register int i;
+ static char sbuf[12];
+
+ if (argc < 2) {
+ printf("usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n");
+ exit(8);
+ }
+ CU = DV = NOSTR;
+ BR = DEFBR;
+ for (; argc > 1; argv++, argc--) {
+ if (argv[1][0] != '-')
+ PN = argv[1];
+ else switch (argv[1][1]) {
+
+ case 't':
+ HW = 1, DU = -1;
+ --argc;
+ continue;
+
+ case 'a':
+ CU = argv[2]; ++argv; --argc;
+ break;
+
+ case 's':
+ if (argc < 3 || speed(atoi(argv[2])) == 0) {
+ fprintf(stderr, "cu: unsupported speed %s\n",
+ argv[2]);
+ exit(3);
+ }
+ BR = atoi(argv[2]); ++argv; --argc;
+ break;
+
+ case 'l':
+ DV = argv[2]; ++argv; --argc;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (CU)
+ CU[strlen(CU)-1] = argv[1][1];
+ if (DV)
+ DV[strlen(DV)-1] = argv[1][1];
+ break;
+
+ default:
+ printf("Bad flag %s", argv[1]);
+ break;
+ }
+ }
+ signal(SIGINT, cleanup);
+ signal(SIGQUIT, cleanup);
+ signal(SIGHUP, cleanup);
+ signal(SIGTERM, cleanup);
+
+ /*
+ * The "cu" host name is used to define the
+ * attributes of the generic dialer.
+ */
+ (void)sprintf(sbuf, "cu%d", BR);
+ if ((i = hunt(sbuf)) == 0) {
+ printf("all ports busy\n");
+ exit(3);
+ }
+ if (i == -1) {
+ printf("link down\n");
+ (void)uu_unlock(uucplock);
+ exit(3);
+ }
+ setbuf(stdout, NULL);
+ loginit();
+ user_uid();
+ vinit();
+ setparity("none");
+ boolean(value(VERBOSE)) = 0;
+ if (HW)
+ ttysetup(speed(BR));
+ if (connect()) {
+ printf("Connect failed\n");
+ daemon_uid();
+ (void)uu_unlock(uucplock);
+ exit(1);
+ }
+ if (!HW)
+ ttysetup(speed(BR));
+}
+#endif /* INCLUDE_CU_INTERFACE */
diff --git a/usr.bin/tip/tip/dial.sh b/usr.bin/tip/tip/dial.sh
new file mode 100755
index 0000000..ed30da5
--- /dev/null
+++ b/usr.bin/tip/tip/dial.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# @(#)dial.sh -- dialup remote using tip
+#
+
+#set -x
+
+if [ $# -lt 1 ] ; then
+ echo "$0: not enough arguments" 1>&2
+ exit 1
+fi
+
+x=0
+
+while ! tip $* && test $x -lt 3
+do
+ sleep 5
+ x=$(($x+1))
+done
+
+exit 0
diff --git a/usr.bin/tip/uucplock.c b/usr.bin/tip/tip/hunt.c
index 6761857..52d35c7 100644
--- a/usr.bin/tip/uucplock.c
+++ b/usr.bin/tip/tip/hunt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1988, 1993
+ * Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,78 +32,81 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)hunt.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/dir.h>
-#include <errno.h>
-#include "pathnames.h"
+#include <libutil.h>
+#include "tipconf.h"
+#include "tip.h"
-/*
- * uucp style locking routines
- * return: 0 - success
- * -1 - failure
- */
+extern char *getremote();
+extern char *rindex();
+
+static jmp_buf deadline;
+static int deadfl;
-uu_lock(ttyname)
- char *ttyname;
+void
+dead()
{
- extern int errno;
- int fd, pid;
- char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN];
- off_t lseek();
+ deadfl = 1;
+ longjmp(deadline, 1);
+}
- (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname);
- fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0660);
- if (fd < 0) {
- /*
- * file is already locked
- * check to see if the process holding the lock still exists
- */
- fd = open(tbuf, O_RDWR, 0);
- if (fd < 0) {
- perror("lock open");
- return(-1);
- }
- if (read(fd, &pid, sizeof(pid)) != sizeof(pid)) {
- (void)close(fd);
- perror("lock read");
- return(-1);
- }
+hunt(name)
+ char *name;
+{
+ register char *cp;
+ sig_t f;
+ int res;
- if (kill(pid, 0) == 0 || errno != ESRCH) {
- (void)close(fd); /* process is still running */
- return(-1);
+ f = signal(SIGALRM, dead);
+ while (cp = getremote(name)) {
+ deadfl = 0;
+ uucplock = rindex(cp, '/')+1;
+ if ((res = uu_lock(uucplock)) != UU_LOCK_OK) {
+ if (res != UU_LOCK_INUSE)
+ fprintf(stderr, "uu_lock: %s\n", uu_lockerr(res));
+ continue;
}
/*
- * The process that locked the file isn't running, so
- * we'll lock it ourselves
+ * Straight through call units, such as the BIZCOMP,
+ * VADIC and the DF, must indicate they're hardwired in
+ * order to get an open file descriptor placed in FD.
+ * Otherwise, as for a DN-11, the open will have to
+ * be done in the "open" routine.
*/
- if (lseek(fd, 0L, L_SET) < 0) {
- (void)close(fd);
- perror("lock lseek");
- return(-1);
+ if (!HW)
+ break;
+ if (setjmp(deadline) == 0) {
+ alarm(10);
+ FD = open(cp, O_RDWR);
}
- /* fall out and finish the locking process */
- }
- pid = getpid();
- if (write(fd, (char *)&pid, sizeof(pid)) != sizeof(pid)) {
- (void)close(fd);
- (void)unlink(tbuf);
- perror("lock write");
- return(-1);
+ alarm(0);
+ if (FD < 0) {
+ perror(cp);
+ deadfl = 1;
+ }
+ if (!deadfl) {
+ ioctl(FD, TIOCEXCL, 0);
+#if HAVE_TERMIOS
+ {
+ struct termios t;
+ if (tcgetattr(FD, &t) == 0) {
+ t.c_cflag |= HUPCL;
+ (void)tcsetattr(FD, TCSANOW, &t);
+ }
+ }
+#else /* HAVE_TERMIOS */
+#ifdef TIOCHPCL
+ ioctl(FD, TIOCHPCL, 0);
+#endif
+#endif /* HAVE_TERMIOS */
+ signal(SIGALRM, SIG_DFL);
+ return ((int)cp);
+ }
+ (void)uu_unlock(uucplock);
}
- (void)close(fd);
- return(0);
-}
-
-uu_unlock(ttyname)
- char *ttyname;
-{
- char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN];
-
- (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname);
- return(unlink(tbuf));
+ signal(SIGALRM, f);
+ return (deadfl ? -1 : (int)cp);
}
diff --git a/usr.bin/tip/tip/log.c b/usr.bin/tip/tip/log.c
new file mode 100644
index 0000000..16e918a
--- /dev/null
+++ b/usr.bin/tip/tip/log.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)log.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+
+#if ACULOG
+static FILE *flog = NULL;
+
+/*
+ * Log file maintenance routines
+ */
+
+logent(group, num, acu, message)
+ char *group, *num, *acu, *message;
+{
+ char *user, *timestamp;
+ struct passwd *pwd;
+ long t;
+
+ if (flog == NULL)
+ return;
+ if (flock(fileno(flog), LOCK_EX) < 0) {
+ perror("tip: flock");
+ return;
+ }
+ if ((user = getlogin()) == NOSTR)
+ if ((pwd = getpwuid(getuid())) == NOPWD)
+ user = "???";
+ else
+ user = pwd->pw_name;
+ t = time(0);
+ timestamp = ctime(&t);
+ timestamp[24] = '\0';
+ fprintf(flog, "%s (%s) <%s, %s, %s> %s\n",
+ user, timestamp, group,
+#if PRISTINE
+ "",
+#else
+ num,
+#endif
+ acu, message);
+ (void) fflush(flog);
+ (void) flock(fileno(flog), LOCK_UN);
+}
+
+loginit()
+{
+ flog = fopen(value(LOG), "a");
+ if (flog == NULL)
+ fprintf(stderr, "can't open log file %s.\r\n", value(LOG));
+}
+#endif
diff --git a/usr.bin/tip/tip/modems.5 b/usr.bin/tip/tip/modems.5
new file mode 100644
index 0000000..f23e7d9
--- /dev/null
+++ b/usr.bin/tip/tip/modems.5
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)modems.5 3/24/95
+.\"
+.Dd March 24, 1995
+.Dt MODEMS 5
+.Os BSD 4.4
+.Sh NAME
+.Nm modems
+.Nd modem configuration data base
+.Sh DESCRIPTION
+The modems known by
+.Xr tip 1
+and their attributes are stored in an
+.Tn ASCII
+file which
+is structured somewhat like the
+.Xr termcap 5
+file. Each line in the file provides a description for a single
+.Em modem .
+Fields are separated by a colon (``:'').
+Lines ending in a \e character with an immediately following newline are
+continued on the next line.
+.Pp
+The first entry is the name(s) of the modem. If there is more
+than one name for a system, the names are separated by vertical bars.
+After the name of the system comes the fields of the description. A
+field name followed by an `=' sign indicates a string value follows. A field
+name followed by a `#' sign indicates a following numeric value.
+.Pp
+When
+.Xr tip 1
+is invoked, an entry for a remote system is looked up in the
+.Pa /etc/remote database.
+If the entry includes an "ACU" type capability (abbreviated at),
+.Xr tip 1
+looks up the specified modem in
+.Pa /etc/modems.
+If a modem entry is found,
+the corresponding capabilities determine how
+.Xr tip 1
+programs the modem when connecting to and disconnecting from the
+remote system.
+.Sh CAPABILITIES
+Capabilities are either strings (str), numbers (num), or boolean
+flags (bool). A string capability is specified by
+.Em capability Ns Ar = Ns Em value ;
+for example, ``reset_command=ATZ\\r''. A numeric capability is specified by
+.Em capability Ns Ar # Ns Em value ;
+for example, ``intercharacter_delay#50''. A boolean capability is specified
+by simply listing the capability.
+.Bl -tag -width intercharacter_delay indent
+.It Cm \&dial_command
+(str)
+AT command used to dial remote system (typically, "ATDT")
+.It Cm \&echo_off_command
+(str)
+AT command to turn off command echo.
+.It Cm \&escape_guard_time
+(num)
+The delay, expressed in milliseconds, used to frame return-to-command
+escape sequences.
+.It Cm \&escape_sequence
+(str)
+The return-to-command escape sequence.
+.It Cm \&hangup_command
+(str)
+AT command used to hangup modem.
+.It Cm \&hw_flow_control
+(bool)
+Enable hardware (RTS/CTS) flow control between computer and modem (DTE/DCE).
+.It Cm \&init_string
+(str)
+AT command used to initialize modem before dialing.
+.It Cm \&intercharacter_delay
+(num)
+Delay value, expressed in milliseconds, between characters when sending commands
+to the modem.
+.It Cm \&intercommand_delay
+(num)
+Minimum delay value, expressed in milliseconds, to impose between commands
+issued to the modem.
+.It Cm \&lock_baud
+(bool)
+Use a fixed bit rate between the computer and the modem (DTE / DCE). The
+bit rate is specified in
+.Pa /etc/remote.
+.It Cm \&reset_command
+(str)
+AT command to reset the modem.
+.It Cm \&reset_delay
+(num)
+The time, expressed in milliseconds, required by the modem to complete
+a reset and return to a ready condition.
+.Sh FILES
+.Bl -tag -width /etc/modems -compact
+.It Pa /etc/modems
+The
+.Nm modems
+configuration database file
+resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr tip 1 ,
+.Xr remote 5
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.4 .
diff --git a/usr.bin/tip/tip/partab.c b/usr.bin/tip/tip/partab.c
new file mode 100644
index 0000000..1da4e23
--- /dev/null
+++ b/usr.bin/tip/tip/partab.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)partab.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Even parity table for 0-0177
+ */
+char evenpartab[] = {
+ 0000,0201,0202,0003,0204,0005,0006,0207,
+ 0210,0011,0012,0213,0014,0215,0216,0017,
+ 0220,0021,0022,0223,0024,0225,0226,0027,
+ 0030,0231,0232,0033,0234,0035,0036,0237,
+ 0240,0041,0042,0243,0044,0245,0246,0047,
+ 0050,0251,0252,0053,0254,0055,0056,0257,
+ 0060,0261,0262,0063,0264,0065,0066,0267,
+ 0270,0071,0072,0273,0074,0275,0276,0077,
+ 0300,0101,0102,0303,0104,0305,0306,0107,
+ 0110,0311,0312,0113,0314,0115,0116,0317,
+ 0120,0321,0322,0123,0324,0125,0126,0327,
+ 0330,0131,0132,0333,0134,0335,0336,0137,
+ 0140,0341,0342,0143,0344,0145,0146,0347,
+ 0350,0151,0152,0353,0154,0355,0356,0157,
+ 0360,0161,0162,0363,0164,0365,0366,0167,
+ 0170,0371,0372,0173,0374,0175,0176,0377,
+};
diff --git a/usr.bin/tip/tip/pathnames.h b/usr.bin/tip/tip/pathnames.h
new file mode 100644
index 0000000..0f9a15b
--- /dev/null
+++ b/usr.bin/tip/tip/pathnames.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+/*
+ Specify path to ACU (modem) log
+*/
+#define _PATH_ACULOG "/var/log/aculog"
+
+/*
+ Specify path and format of lock files
+*/
+/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/etc/locks/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/usr/spool/locks/LCK..%s" */
+/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK/LCK..%s" */
+#define _PATH_LOCKDIRNAME _PATH_UUCPLOCK "LCK..%s"
+
+/*
+ Specify location for system wide databases
+*/
+#define _PATH_MODEMS "/etc/modems"
+#define _PATH_PHONES "/etc/phones"
+#define _PATH_REMOTE "/etc/remote"
+
diff --git a/usr.bin/tip/tip/remcap.c b/usr.bin/tip/tip/remcap.c
new file mode 100644
index 0000000..7a7e0c2
--- /dev/null
+++ b/usr.bin/tip/tip/remcap.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remcap.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+#define tgetent rgetent
+#define tnchktc rnchktc
+#define tnamatch rnamatch
+#define tgetnum rgetnum
+#define tgetflag rgetflag
+#define tgetstr rgetstr
+#define E_TERMCAP RM = _PATH_REMOTE
+#define V_TERMCAP "REMOTE"
+#define V_TERM "HOST"
+
+char *RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+static char *tskip();
+char *tgetstr();
+static char *tdecode();
+static char *remotefile;
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name)
+ char *bp, *name;
+{
+ char lbuf[BUFSIZ], *cp, *p;
+ int rc1, rc2;
+
+ remotefile = cp = getenv(V_TERMCAP);
+ if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) {
+ remotefile = cp = _PATH_REMOTE;
+ return (getent(bp, name, cp));
+ } else {
+ if ((rc1 = getent(bp, name, cp)) != 1)
+ *bp = '\0';
+ remotefile = cp = _PATH_REMOTE;
+ rc2 = getent(lbuf, name, cp);
+ if (rc1 != 1 && rc2 != 1)
+ return (rc2);
+ if (rc2 == 1) {
+ p = lbuf;
+ if (rc1 == 1)
+ while (*p++ != ':')
+ ;
+ if (strlen(bp) + strlen(p) > BUFSIZ) {
+ write(2, "Remcap entry too long\n", 23);
+ return (-1);
+ }
+ strcat(bp, p);
+ }
+ tbuf = bp;
+ return (1);
+ }
+}
+
+getent(bp, name, cp)
+ char *bp, *name, *cp;
+{
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ], *cp2;
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ if (*cp!='/') {
+ cp2 = getenv(V_TERM);
+ if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
+ strcpy(bp,cp);
+ return (tnchktc());
+ } else
+ tf = open(E_TERMCAP, O_RDONLY);
+ } else
+ tf = open(RM = cp, O_RDONLY);
+ }
+ if (tf == 0)
+ tf = open(E_TERMCAP, O_RDONLY);
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\') {
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Remcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return (tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+ char *cp;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p<tbuf) {
+ write(2, "Bad remcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return (1);
+ strcpy(tcname, p+3);
+ q = tcname;
+ while (*q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (getent(tcbuf, tcname, remotefile) != 1) {
+ if (strcmp(remotefile, _PATH_REMOTE) == 0)
+ return (0);
+ else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1)
+ return (0);
+ }
+ for (q = tcbuf; *q++ != ':'; )
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Remcap entry too long\n", 23);
+ q[BUFSIZ - (p-holdtbuf)] = 0;
+ }
+ strcpy(p, q);
+ tbuf = holdtbuf;
+ return (1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/usr.bin/tip/tip/remote.c b/usr.bin/tip/tip/remote.c
new file mode 100644
index 0000000..1c6e2d4
--- /dev/null
+++ b/usr.bin/tip/tip/remote.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)remote.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/syslimits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+/*
+ * Attributes to be gleened from remote host description
+ * data base.
+ */
+static char **caps[] = {
+ &AT, &DV, &CM, &CU, &EL, &IE, &OE, &PN, &PR, &DI,
+ &ES, &EX, &FO, &RC, &RE, &PA, &LI, &LO
+};
+
+static char *capstrings[] = {
+ "at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr",
+ "di", "es", "ex", "fo", "rc", "re", "pa", "li", "lo", 0
+};
+
+static char *db_array[3] = { _PATH_REMOTE, 0, 0 };
+
+#define cgetflag(f) (cgetcap(bp, f, ':') != NULL)
+
+/*
+ Expand the start tilde sequence at the start of the
+ specified path. Optionally, free space allocated to
+ path before reinitializing it.
+*/
+static int
+expand_tilde (char **path, void (*free) (char *p))
+{
+ int rc = 0;
+ char buffer [PATH_MAX];
+ char *tailp;
+ if ((tailp = strchr (*path + 1, '/')) != NULL)
+ {
+ struct passwd *pwd;
+ *tailp++ = '\0';
+ if (*(*path + 1) == '\0')
+ strcpy (buffer, getlogin ());
+ else
+ strcpy (buffer, *path + 1);
+ if ((pwd = getpwnam (buffer)) != NULL)
+ {
+ strcpy (buffer, pwd->pw_dir);
+ strcat (buffer, "/");
+ strcat (buffer, tailp);
+ if (free)
+ free (*path);
+ *path = strdup (buffer);
+ rc++;
+ }
+ return rc;
+ }
+}
+
+static
+getremcap(host)
+ register char *host;
+{
+ register char **p, ***q;
+ char *bp;
+ char *rempath;
+ int stat;
+
+ rempath = getenv("REMOTE");
+ if (rempath != NULL)
+ if (*rempath != '/')
+ /* we have an entry */
+ cgetset(rempath);
+ else { /* we have a path */
+ db_array[1] = rempath;
+ db_array[2] = _PATH_REMOTE;
+ }
+
+ if ((stat = cgetent(&bp, db_array, host)) < 0) {
+ if (DV ||
+ host[0] == '/' && access(DV = host, R_OK | W_OK) == 0) {
+ CU = DV;
+ HO = host;
+ HW = 1;
+ DU = 0;
+ if (!BR)
+ BR = DEFBR;
+ FS = DEFFS;
+ return;
+ }
+ switch(stat) {
+ case -1:
+ fprintf(stderr, "tip: unknown host %s\n", host);
+ break;
+ case -2:
+ fprintf(stderr,
+ "tip: can't open host description file\n");
+ break;
+ case -3:
+ fprintf(stderr,
+ "tip: possible reference loop in host description file\n");
+ break;
+ }
+ exit(3);
+ }
+
+ for (p = capstrings, q = caps; *p != NULL; p++, q++)
+ if (**q == NULL)
+ cgetstr(bp, *p, *q);
+ if (!BR && (cgetnum(bp, "br", &BR) == -1))
+ BR = DEFBR;
+ if (cgetnum(bp, "fs", &FS) == -1)
+ FS = DEFFS;
+ if (DU < 0)
+ DU = 0;
+ else
+ DU = cgetflag("du");
+ if (DV == NOSTR) {
+ fprintf(stderr, "%s: missing device spec\n", host);
+ exit(3);
+ }
+ if (DU && CU == NOSTR)
+ CU = DV;
+ if (DU && PN == NOSTR) {
+ fprintf(stderr, "%s: missing phone number\n", host);
+ exit(3);
+ }
+
+ HD = cgetflag("hd");
+
+ /*
+ * This effectively eliminates the "hw" attribute
+ * from the description file
+ */
+ if (!HW)
+ HW = (CU == NOSTR) || (DU && equal(DV, CU));
+ HO = host;
+
+ /*
+ If login script, verify access
+ */
+ if (LI != NOSTR) {
+ if (*LI == '~')
+ (void) expand_tilde (&LI, NULL);
+ if (access (LI, F_OK | X_OK) != 0) {
+ printf("tip (warning): can't open login script \"%s\"\n", LI);
+ LI = NOSTR;
+ }
+ }
+
+ /*
+ If logout script, verify access
+ */
+ if (LO != NOSTR) {
+ if (*LO == '~')
+ (void) expand_tilde (&LO, NULL);
+ if (access (LO, F_OK | X_OK) != 0) {
+ printf("tip (warning): can't open logout script \"%s\"\n", LO);
+ LO = NOSTR;
+ }
+ }
+
+ /*
+ * see if uppercase mode should be turned on initially
+ */
+ if (cgetflag("ra"))
+ boolean(value(RAISE)) = 1;
+ if (cgetflag("ec"))
+ boolean(value(ECHOCHECK)) = 1;
+ if (cgetflag("be"))
+ boolean(value(BEAUTIFY)) = 1;
+ if (cgetflag("nb"))
+ boolean(value(BEAUTIFY)) = 0;
+ if (cgetflag("sc"))
+ boolean(value(SCRIPT)) = 1;
+ if (cgetflag("tb"))
+ boolean(value(TABEXPAND)) = 1;
+ if (cgetflag("vb"))
+ boolean(value(VERBOSE)) = 1;
+ if (cgetflag("nv"))
+ boolean(value(VERBOSE)) = 0;
+ if (cgetflag("ta"))
+ boolean(value(TAND)) = 1;
+ if (cgetflag("nt"))
+ boolean(value(TAND)) = 0;
+ if (cgetflag("rw"))
+ boolean(value(RAWFTP)) = 1;
+ if (cgetflag("hd"))
+ boolean(value(HALFDUPLEX)) = 1;
+ if (RE == NOSTR)
+ RE = (char *)"tip.record";
+ if (EX == NOSTR)
+ EX = (char *)"\t\n\b\f";
+ if (ES != NOSTR)
+ vstring("es", ES);
+ if (FO != NOSTR)
+ vstring("fo", FO);
+ if (PR != NOSTR)
+ vstring("pr", PR);
+ if (RC != NOSTR)
+ vstring("rc", RC);
+ if (cgetnum(bp, "dl", &DL) == -1)
+ DL = 0;
+ if (cgetnum(bp, "cl", &CL) == -1)
+ CL = 0;
+ if (cgetnum(bp, "et", &ET) == -1)
+ ET = 10;
+}
+
+char *
+getremote(host)
+ char *host;
+{
+ register char *cp;
+ static char *next;
+ static int lookedup = 0;
+
+ if (!lookedup) {
+ if (host == NOSTR && (host = getenv("HOST")) == NOSTR) {
+ fprintf(stderr, "tip: no host specified\n");
+ exit(3);
+ }
+ getremcap(host);
+ next = DV;
+ lookedup++;
+ }
+ /*
+ * We return a new device each time we're called (to allow
+ * a rotary action to be simulated)
+ */
+ if (next == NOSTR)
+ return (NOSTR);
+ if ((cp = index(next, ',')) == NULL) {
+ DV = next;
+ next = NOSTR;
+ } else {
+ *cp++ = '\0';
+ DV = next;
+ next = cp;
+ }
+ return (DV);
+}
diff --git a/usr.bin/tip/tip/tip.1 b/usr.bin/tip/tip/tip.1
new file mode 100644
index 0000000..687fda9
--- /dev/null
+++ b/usr.bin/tip/tip/tip.1
@@ -0,0 +1,442 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tip.1 8.4 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt TIP 1
+.Os BSD 4
+.Sh NAME
+.Nm tip
+.Nd connect to a remote system
+.Sh SYNOPSIS
+.Nm tip
+.Op Fl v
+.Fl Ns Ns Ar speed
+.Ar system\-name
+.Nm tip
+.Op Fl v
+.Fl Ns Ns Ar speed
+.Ar phone\-number
+.Sh DESCRIPTION
+.Nm Tip
+establish a full-duplex connection to another machine,
+giving the appearance of being logged in directly on the
+remote cpu. It goes without saying that you must have a login
+on the machine (or equivalent) to which you wish to connect.
+.Pp
+Available Option:
+.Bl -tag -width indent
+.It Fl v
+Set verbose mode.
+.El
+.Pp
+Typed characters are normally transmitted directly to the remote
+machine (which does the echoing as well). A tilde (`~') appearing
+as the first character of a line is an escape signal; the following
+are recognized:
+.Bl -tag -width flag
+.It Ic \&~^D No or Ic \&~ .
+Drop the connection and exit
+(you may still be logged in on the
+remote machine).
+.It Ic \&~c Op Ar name
+Change directory to
+.Ar name
+(no argument
+implies change to your home directory).
+.It Ic \&~!
+Escape to a shell (exiting the shell will
+return you to tip).
+.It Ic \&~>
+Copy file from local to remote.
+.Nm Tip
+prompts for the name of a local file to transmit.
+.It Ic \&~<
+Copy file from remote to local.
+.Nm Tip
+prompts first for the name of the file to be sent, then for
+a command to be executed on the remote machine.
+.It Ic \&~p Ar from Op Ar to
+Send a file to a remote
+.Ux
+host. The put command causes the remote
+.Ux
+system to run the command string ``cat > 'to''', while
+.Nm tip
+sends it the ``from''
+file. If the ``to'' file isn't specified the ``from'' file name is used.
+This command is actually a
+.Ux
+specific version of the ``~>'' command.
+.It Ic \&~t Ar from Op Ar to
+Take a file from a remote
+.Ux
+host.
+As in the put command the ``to'' file
+defaults to the ``from'' file name if it isn't specified.
+The remote host
+executes the command string ``cat 'from';echo ^A'' to send the file to
+.Nm tip .
+.It Ic \&~|
+Pipe the output from a remote command to a local
+.Ux
+process.
+The command string sent to the local
+.Ux
+system is processed by the shell.
+.It Ic \&~$
+Pipe the output from a local
+.Ux
+process to the remote host.
+The command string sent to the local
+.Ux
+system is processed by the shell.
+.It Ic \&~C
+Fork a child process on the local system to perform special protocols
+such as \s-1XMODEM\s+1. The child program will be run with the following
+somewhat unusual arrangement of file descriptors:
+.nf
+.in +1i
+0 <-> local tty in
+1 <-> local tty out
+2 <-> local tty out
+3 <-> remote tty in
+4 <-> remote tty out
+.in -1i
+.fi
+.It Ic \&~#
+Send a
+.Dv BREAK
+to the remote system.
+For systems which don't support the
+necessary
+.Ar ioctl
+call the break is simulated by a sequence of line speed changes
+and
+.Dv DEL
+characters.
+.It Ic \&~s
+Set a variable (see the discussion below).
+.It Ic \&~^Z
+Stop
+.Nm tip
+(only available with job control).
+.It Ic \&~^Y
+Stop only the ``local side'' of
+.Nm tip
+(only available with job control);
+the ``remote side'' of
+.Nm tip ,
+the side that displays output from the remote host, is left running.
+.It Ic \&~?
+Get a summary of the tilde escapes
+.El
+.Pp
+.Nm Tip
+uses the file
+.Pa /etc/remote
+to find how to reach a particular
+system and to find out how it should operate while talking
+to the system;
+refer to
+.Xr remote 5
+for a full description.
+Each system has a default baud rate with which to
+establish a connection. If this value is not suitable, the baud rate
+to be used may be specified on the command line, e.g.
+.Ql "tip -300 mds" .
+.Pp
+When
+.Nm tip
+establishes a connection it sends out a
+connection message to the remote system; the default value, if any,
+is defined in
+.Pa /etc/remote
+(see
+.Xr remote 5 ) .
+.Pp
+When
+.Nm tip
+prompts for an argument (e.g. during setup of
+a file transfer) the line typed may be edited with the standard
+erase and kill characters. A null line in response to a prompt,
+or an interrupt, will abort the dialogue and return you to the
+remote machine.
+.Pp
+.Nm Tip
+guards against multiple users connecting to a remote system
+by opening modems and terminal lines with exclusive access,
+and by honoring the locking protocol used by
+.Xr uucico 8 .
+.Pp
+During file transfers
+.Nm tip
+provides a running count of the number of lines transferred.
+When using the ~> and ~< commands, the ``eofread'' and ``eofwrite''
+variables are used to recognize end-of-file when reading, and
+specify end-of-file when writing (see below). File transfers
+normally depend on tandem mode for flow control. If the remote
+system does not support tandem mode, ``echocheck'' may be set
+to indicate
+.Nm tip
+should synchronize with the remote system on the echo of each
+transmitted character.
+.Pp
+When
+.Nm tip
+must dial a phone number to connect to a system it will print
+various messages indicating its actions.
+.Nm Tip
+supports modems that use the AT command set.
+.Nm Tip
+uses the file
+.Pa /etc/modems
+to find out how to operate with a particular
+modem; refer to
+.Xr modems 5
+for a full description.
+.Ss VARIABLES
+.Nm Tip
+maintains a set of
+.Ar variables
+which control its operation.
+Some of these variables are read-only to normal users (root is allowed
+to change anything of interest). Variables may be displayed
+and set through the ``s'' escape. The syntax for variables is patterned
+after
+.Xr vi 1
+and
+.Xr Mail 1 .
+Supplying ``all''
+as an argument to the set command displays all variables readable by
+the user. Alternatively, the user may request display of a particular
+variable by attaching a `?' to the end. For example ``escape?''
+displays the current escape character.
+.Pp
+Variables are numeric, string, character, or boolean values. Boolean
+variables are set merely by specifying their name; they may be reset
+by prepending a `!' to the name. Other variable types are set by
+concatenating an `=' and the value. The entire assignment must not
+have any blanks in it. A single set command may be used to interrogate
+as well as set a number of variables.
+Variables may be initialized at run time by placing set commands
+(without the ``~s'' prefix in a file
+.Pa .tiprc
+in one's home directory). The
+.Fl v
+option causes
+.Nm tip
+to display the sets as they are made.
+Certain common variables have abbreviations.
+The following is a list of common variables,
+their abbreviations, and their default values.
+.Bl -tag -width Ar
+.It Ar beautify
+(bool) Discard unprintable characters when a session is being scripted;
+abbreviated
+.Ar be .
+.It Ar baudrate
+(num) The baud rate at which the connection was established;
+abbreviated
+.Ar ba .
+.It Ar dialtimeout
+(num) When dialing a phone number, the time (in seconds)
+to wait for a connection to be established; abbreviated
+.Ar dial .
+.It Ar echocheck
+(bool) Synchronize with the remote host during file transfer by
+waiting for the echo of the last character transmitted; default is
+.Ar off .
+.It Ar eofread
+(str) The set of characters which signify an end-of-transmission
+during a ~< file transfer command; abbreviated
+.Ar eofr .
+.It Ar eofwrite
+(str) The string sent to indicate end-of-transmission during
+a ~> file transfer command; abbreviated
+.Ar eofw .
+.It Ar eol
+(str) The set of characters which indicate an end-of-line.
+.Nm Tip
+will recognize escape characters only after an end-of-line.
+.It Ar escape
+(char) The command prefix (escape) character; abbreviated
+.Ar es ;
+default value is `~'.
+.It Ar exceptions
+(str) The set of characters which should not be discarded
+due to the beautification switch; abbreviated
+.Ar ex ;
+default value is ``\et\en\ef\eb''.
+.It Ar force
+(char) The character used to force literal data transmission;
+abbreviated
+.Ar fo ;
+default value is `^P'.
+.It Ar framesize
+(num) The amount of data (in bytes) to buffer between file system
+writes when receiving files; abbreviated
+.Ar fr .
+.It Ar host
+(str) The name of the host to which you are connected; abbreviated
+.Ar ho .
+.It Ar login
+(str) Pathname of a login shell script to run once connected; standard input
+and output are redirected to the remote host. Leading tildes in the pathname
+are expanded expansion; abbreviated
+.Ar li .
+.It Ar logout
+(str) Pathname of a shell script to run before disconnecting; standard input
+and output are redirected to the remote host. Leading tildes in the pathname
+are expanded expansion; abbreviated
+.Ar lo .
+.It Ar prompt
+(char) The character which indicates an end-of-line on the remote
+host; abbreviated
+.Ar pr ;
+default value is `\en'. This value is used to synchronize during
+data transfers. The count of lines transferred during a file transfer
+command is based on receipt of this character.
+.It Ar raise
+(bool) Upper case mapping mode; abbreviated
+.Ar ra ;
+default value is
+.Ar off .
+When this mode is enabled, all lower case letters will be mapped to
+upper case by
+.Nm tip
+for transmission to the remote machine.
+.It Ar raisechar
+(char) The input character used to toggle upper case mapping mode;
+abbreviated
+.Ar rc ;
+default value is `^A'.
+.It Ar record
+(str) The name of the file in which a session script is recorded;
+abbreviated
+.Ar rec ;
+default value is ``tip.record''.
+.It Ar script
+(bool) Session scripting mode; abbreviated
+.Ar sc ;
+default is
+.Ar off .
+When
+.Ar script
+is
+.Li true ,
+.Nm tip
+will record everything transmitted by the remote machine in
+the script record file specified in
+.Ar record .
+If the
+.Ar beautify
+switch is on, only printable
+.Tn ASCII
+characters will be included in
+the script file (those characters between 040 and 0177). The
+variable
+.Ar exceptions
+is used to indicate characters which are an exception to the normal
+beautification rules.
+.It Ar tabexpand
+(bool) Expand tabs to spaces during file transfers; abbreviated
+.Ar tab ;
+default value is
+.Ar false .
+Each tab is expanded to 8 spaces.
+.It Ar verbose
+(bool) Verbose mode; abbreviated
+.Ar verb ;
+default is
+.Ar true .
+When verbose mode is enabled,
+.Nm tip
+prints messages while dialing, shows the current number
+of lines transferred during a file transfer operations,
+and more.
+.El
+.Sh ENVIRONMENT
+.Nm Tip
+uses the following environment variables:
+.Bl -tag -width Fl
+.It Ev SHELL
+(str) The name of the shell to use for the ~! command; default
+value is ``/bin/sh'', or taken from the environment.
+.It Ev HOME
+(str) The home directory to use for the ~c command; default
+value is taken from the environment.
+.It Ev HOST
+Check for a default host if none specified.
+.El
+.Pp
+The variables
+.Ev ${REMOTE}
+and
+.Ev ${PHONES}
+are also exported.
+.Sh FILES
+.Bl -tag -width /var/spool/lock/LCK..* -compact
+.It Pa /etc/modems
+Global modem configuration data base.
+.It Pa /etc/remote
+Global system descriptions.
+.It Pa /etc/phones
+Global phone number data base.
+.It ${REMOTE}
+Private system descriptions.
+.It ${PHONES}
+Private phone numbers.
+.It ~/.tiprc
+Initialization file.
+.It Pa tip.record
+Record file.
+.It /var/log/aculog
+Line access log.
+.It Pa /var/spool/lock/LCK..*
+Lock file to avoid conflicts with
+.Xr uucp .
+.El
+.Sh DIAGNOSTICS
+Diagnostics are, hopefully, self explanatory.
+.Sh SEE ALSO
+.Xr cu 1 ,
+.Xr phones 5 ,
+.Xr remote 5
+.Sh HISTORY
+The
+.Nm tip
+appeared command in
+.Bx 4.2 .
+.Sh BUGS
+The full set of variables is undocumented and should, probably, be
+pared down.
diff --git a/usr.bin/tip/tip.c b/usr.bin/tip/tip/tip.c
index b09cde7..b50f4c3 100644
--- a/usr.bin/tip/tip.c
+++ b/usr.bin/tip/tip/tip.c
@@ -42,29 +42,43 @@ static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
+ Forward declarations
+*/
+void ttysetup (int speed);
+
+/*
* tip - UNIX link to other systems
* tip [-v] [-speed] system-name
* or
* cu phone-number [-s speed] [-l line] [-a acu]
*/
+
+#include "tipconf.h"
#include "tip.h"
#include "pathnames.h"
/*
* Baud rate mapping table
*/
-int bauds[] = {
+#if !HAVE_TERMIOS
+CONST int bauds[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600,
- 1200, 1800, 2400, 4800, 9600, 19200, -1
+ 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1
};
+#endif
+#if !HAVE_TERMIOS
int disc = OTTYDISC; /* tip normally runs this way */
+#endif
+
void intprompt();
void timeout();
void cleanup();
+void tipdone();
char *sname();
char PNbuf[256]; /* This limits the size of a number */
+void
main(argc, argv)
char *argv[];
{
@@ -77,11 +91,14 @@ main(argc, argv)
egid = getegid();
uid = getuid();
euid = geteuid();
+
+#if INCLUDE_CU_INTERFACE
if (equal(sname(argv[0]), "cu")) {
cumode = 1;
cumain(argc, argv);
goto cucommon;
}
+#endif /* INCLUDE_CU_INTERFACE */
if (argc > 4) {
fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
@@ -138,6 +155,7 @@ notnumber:
(void)signal(SIGQUIT, cleanup);
(void)signal(SIGHUP, cleanup);
(void)signal(SIGTERM, cleanup);
+ (void)signal(SIGUSR1, tipdone);
if ((i = hunt(system)) == 0) {
printf("all ports busy\n");
@@ -195,6 +213,21 @@ cucommon:
* the "cu" version of tip.
*/
+#if HAVE_TERMIOS
+ tcgetattr (0, &otermios);
+ ctermios = otermios;
+#ifndef _POSIX_SOURCE
+ ctermios.c_iflag = (IMAXBEL|IXANY|ISTRIP|IXON|BRKINT);
+ ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOCTL|ECHOE|ECHOKE);
+#else
+ ctermios.c_iflag = (ISTRIP|IXON|BRKINT);
+ ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOE);
+#endif
+ ctermios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
+ ctermios.c_cc[VINTR] = ctermios.c_cc[VQUIT] = -1;
+ ctermios.c_cc[VSUSP] = ctermios.c_cc[VDSUSP] = ctermios.c_cc[VDISCARD] =
+ ctermios.c_cc[VLNEXT] = -1;
+#else /* HAVE_TERMIOS */
ioctl(0, TIOCGETP, (char *)&defarg);
ioctl(0, TIOCGETC, (char *)&defchars);
ioctl(0, TIOCGLTC, (char *)&deflchars);
@@ -206,6 +239,7 @@ cucommon:
ltchars = deflchars;
ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
= ltchars.t_lnextc = -1;
+#endif /* HAVE_TERMIOS */
raw();
pipe(fildes); pipe(repdes);
@@ -219,6 +253,11 @@ cucommon:
* so, fork one process for local side and one for remote.
*/
printf(cumode ? "Connected\r\n" : "\07connected\r\n");
+
+ if (LI != NOSTR && tiplink (LI, 0) != 0) {
+ tipabort ("login failed");
+ }
+
if (pid = fork())
tipin();
else
@@ -232,11 +271,18 @@ cleanup()
daemon_uid();
(void)uu_unlock(uucplock);
+#if !HAVE_TERMIOS
if (odisc)
ioctl(0, TIOCSETD, (char *)&odisc);
+#endif
exit(0);
}
+void
+tipdone()
+{
+ tipabort("Hangup.");
+}
/*
* Muck with user ID's. We are setuid to the owner of the lock
* directory when we start. user_uid() reverses real and effective
@@ -273,13 +319,18 @@ shell_uid()
/*
* put the controlling keyboard into raw mode
*/
-raw()
+void
+raw ()
{
+#if HAVE_TERMIOS
+ tcsetattr (0, TCSANOW, &ctermios);
+#else /* HAVE_TERMIOS */
ioctl(0, TIOCSETP, &arg);
ioctl(0, TIOCSETC, &tchars);
ioctl(0, TIOCSLTC, &ltchars);
ioctl(0, TIOCSETD, (char *)&disc);
+#endif /* HAVE_TERMIOS */
}
@@ -288,11 +339,15 @@ raw()
*/
unraw()
{
+#if HAVE_TERMIOS
+ tcsetattr (0, TCSANOW, &otermios);
+#else /* HAVE_TERMIOS */
ioctl(0, TIOCSETD, (char *)&odisc);
ioctl(0, TIOCSETP, (char *)&defarg);
ioctl(0, TIOCSETC, (char *)&defchars);
ioctl(0, TIOCSLTC, (char *)&deflchars);
+#endif /* HAVE_TERMIOS */
}
static jmp_buf promptbuf;
@@ -343,6 +398,7 @@ intprompt()
*/
tipin()
{
+ int i;
char gch, bol = 1;
/*
@@ -358,7 +414,10 @@ tipin()
}
while (1) {
- gch = getchar()&0177;
+ i = getchar();
+ if (i == EOF)
+ break;
+ gch = i&0177;
if ((gch == character(value(ESCAPE))) && bol) {
if (!(gch = escape()))
continue;
@@ -371,8 +430,12 @@ tipin()
if (boolean(value(HALFDUPLEX)))
printf("\r\n");
continue;
- } else if (!cumode && gch == character(value(FORCE)))
- gch = getchar()&0177;
+ } else if (!cumode && gch == character(value(FORCE))) {
+ i = getchar();
+ if (i == EOF)
+ break;
+ gch = i & 0177;
+ }
bol = any(gch, value(EOL));
if (boolean(value(RAISE)) && islower(gch))
gch = toupper(gch);
@@ -393,8 +456,12 @@ escape()
register char gch;
register esctable_t *p;
char c = character(value(ESCAPE));
+ int i;
- gch = (getchar()&0177);
+ i = getchar();
+ if (i == EOF)
+ return 0;
+ gch = (i&0177);
for (p = etable; p->e_char; p++)
if (p->e_char == gch) {
if ((p->e_flags&PRIV) && uid)
@@ -412,12 +479,16 @@ escape()
speed(n)
int n;
{
- register int *p;
+#if HAVE_TERMIOS
+ return (n);
+#else
+ register CONST int *p;
for (p = bauds; *p != -1; p++)
if (*p == n)
return (p - bauds);
return (NULL);
+#endif
}
any(c, p)
@@ -503,9 +574,25 @@ help(c)
/*
* Set up the "remote" tty's state
*/
-ttysetup(speed)
- int speed;
+void
+ttysetup (int speed)
{
+#if HAVE_TERMIOS
+ struct termios termios;
+ tcgetattr (FD, &termios);
+ if (boolean(value(TAND)))
+ termios.c_iflag = IXOFF;
+ else
+ termios.c_iflag = 0;
+#ifndef _POSIX_SOURCE
+ termios.c_lflag = (PENDIN|ECHOKE|ECHOE);
+#else
+ termios.c_lflag = (PENDIN|ECHOE);
+#endif
+ termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
+ termios.c_ispeed = termios.c_ospeed = speed;
+ tcsetattr (FD, TCSANOW, &termios);
+#else /* HAVE_TERMIOS */
unsigned bits = LDECCTQ;
arg.sg_ispeed = arg.sg_ospeed = speed;
@@ -514,6 +601,7 @@ ttysetup(speed)
arg.sg_flags |= TANDEM;
ioctl(FD, TIOCSETP, (char *)&arg);
ioctl(FD, TIOCLBIS, (char *)&bits);
+#endif /* HAVE_TERMIOS */
}
/*
@@ -558,8 +646,9 @@ pwrite(fd, buf, n)
if (write(fd, buf, n) < 0) {
if (errno == EIO)
tipabort("Lost carrier.");
- /* this is questionable */
- perror("write");
+ if (errno == ENODEV)
+ tipabort("tty not available.");
+ tipabort("Something wrong...");
}
}
diff --git a/usr.bin/tip/tip.h b/usr.bin/tip/tip/tip.h
index 403e17f..fb45ce0 100644
--- a/usr.bin/tip/tip.h
+++ b/usr.bin/tip/tip/tip.h
@@ -43,7 +43,14 @@
#include <sys/file.h>
#include <sys/time.h>
+#if HAVE_TERMIOS
+#include <sys/ioctl.h> /* for TIOCHPCL */
+#include <sys/filio.h> /* for FIONREAD */
+#include <sys/termios.h>
+#else
#include <sgtty.h>
+#endif
+
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -72,6 +79,9 @@ char *PH; /* phone number file */
char *RM; /* remote file name */
char *HO; /* host name */
+char *LI; /* login script */
+char *LO; /* logout script */
+
long BR; /* line speed for conversation */
long FS; /* frame size for transfers */
@@ -129,8 +139,8 @@ typedef
struct {
char *acu_name;
int (*acu_dialer)();
- int (*acu_disconnect)();
- int (*acu_abort)();
+ void (*acu_disconnect)();
+ void (*acu_abort)();
}
acu_t;
@@ -189,7 +199,7 @@ typedef
extern int vflag; /* verbose during reading of .tiprc file */
extern value_t vtable[]; /* variable table */
-#ifndef ACULOG
+#if !ACULOG
#define logent(a, b, c, d)
#define loginit()
#endif
@@ -199,52 +209,62 @@ extern value_t vtable[]; /* variable table */
* value(DEFINE) turns into a static address.
*/
-#define BEAUTIFY 0
-#define BAUDRATE 1
-#define DIALTIMEOUT 2
-#define EOFREAD 3
-#define EOFWRITE 4
-#define EOL 5
-#define ESCAPE 6
-#define EXCEPTIONS 7
-#define FORCE 8
-#define FRAMESIZE 9
-#define HOST 10
-#define LOG 11
-#define PHONES 12
-#define PROMPT 13
-#define RAISE 14
-#define RAISECHAR 15
-#define RECORD 16
-#define REMOTE 17
-#define SCRIPT 18
-#define TABEXPAND 19
-#define VERBOSE 20
-#define SHELL 21
-#define HOME 22
-#define ECHOCHECK 23
-#define DISCONNECT 24
-#define TAND 25
-#define LDELAY 26
-#define CDELAY 27
-#define ETIMEOUT 28
-#define RAWFTP 29
-#define HALFDUPLEX 30
-#define LECHO 31
-#define PARITY 32
+/*
+'a,.!awk '{ printf("\%s \%s \%d\n", $1, $2, NR - 1); }'
+*/
+#define BEAUTIFY 0
+#define BAUDRATE 1
+#define DIALTIMEOUT 2
+#define EOFREAD 3
+#define EOFWRITE 4
+#define EOL 5
+#define ESCAPE 6
+#define EXCEPTIONS 7
+#define FORCE 8
+#define FRAMESIZE 9
+#define HOST 10
+#define LOG 11
+#define LOGIN 12
+#define LOGOUT 13
+#define PHONES 14
+#define PROMPT 15
+#define RAISE 16
+#define RAISECHAR 17
+#define RECORD 18
+#define REMOTE 19
+#define SCRIPT 20
+#define TABEXPAND 21
+#define VERBOSE 22
+#define SHELL 23
+#define HOME 24
+#define ECHOCHECK 25
+#define DISCONNECT 26
+#define TAND 27
+#define LDELAY 28
+#define CDELAY 29
+#define ETIMEOUT 30
+#define RAWFTP 31
+#define HALFDUPLEX 32
+#define LECHO 33
+#define PARITY 34
#define NOVAL ((value_t *)NULL)
#define NOACU ((acu_t *)NULL)
#define NOSTR ((char *)NULL)
#define NOFILE ((FILE *)NULL)
#define NOPWD ((struct passwd *)0)
+#if HAVE_TERMIOS
+struct termios otermios;
+struct termios ctermios;
+#else /* HAVE_TERMIOS */
struct sgttyb arg; /* current mode of local terminal */
struct sgttyb defarg; /* initial mode of local terminal */
struct tchars tchars; /* current state of terminal */
struct tchars defchars; /* initial state of terminal */
struct ltchars ltchars; /* current local characters of terminal */
struct ltchars deflchars; /* initial local characters of terminal */
+#endif /* HAVE_TERMIOS */
FILE *fscript; /* FILE for scripting */
@@ -276,3 +296,13 @@ extern int disc; /* current tty discpline */
extern char *ctrl();
extern char *vinterp();
extern char *connect();
+
+int tipabort __P((char *));
+
+#define TL_VERBOSE 0x00000001
+#define TL_SIGNAL_TIPOUT 0x00000002
+
+int tiplink (char *cmd, unsigned int flags);
+void raw ();
+
+/* end of tip.h */
diff --git a/usr.bin/tip/tip/tipconf.h b/usr.bin/tip/tip/tipconf.h
new file mode 100644
index 0000000..f21be62
--- /dev/null
+++ b/usr.bin/tip/tip/tipconf.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tipconf.h 8.1 (Berkeley) 3/25/95
+ */
+
+#ifndef tipconf_h_included
+#define tipconf_h_included
+
+/*
+ Define constness
+*/
+#define CONST const
+
+/*
+ Specify default bit rate for connections
+*/
+#define DEFBR 1200
+
+/*
+ Default frame size for file transfer buffering of writes
+ on local side
+*/
+#ifndef BUFSIZ
+#define DEFFS 1024
+#else
+#define DEFFS BUFSIZ
+#endif
+
+/*
+ Enable logging of ACU use
+*/
+#define ACULOG 1
+
+/*
+ Strip phone #s from ACU log file
+*/
+#define PRISTINE 1
+
+/*
+ Enable command to "connect" remote with local process
+*/
+#define CONNECT 1
+
+/*
+ Specify style of UUCP lock files
+*/
+#define HAVE_V2_LOCKFILES 0
+#define HAVE_HDB_LOCKFILES 1
+
+/*
+ System has a millisecond based sleep function
+*/
+#define HAVE_USLEEP 0
+
+/*
+ System has select
+*/
+#define HAVE_SELECT 1
+
+/*
+ System has termios tty interface
+*/
+#define HAVE_TERMIOS 1
+
+/*
+ Include configurable modem driver
+*/
+#define UNIDIALER 1
+
+/*
+ Specify builtin modem drivers to include
+*/
+#define BIZ1031 0
+#define BIZ1022 0
+#define COURIER 0
+#define DF02 0
+#define DF03 0
+#define DN11 0
+#define HAYES 0
+#define MULTITECH 0
+#define T3000 0
+#define V3451 0
+#define V831 0
+#define VENTEL 0
+
+/*
+ Include cu interface so that, when tip is linked to cu and then
+ invoked as cu, it behaves like cu.
+*/
+#define INCLUDE_CU_INTERFACE 0
+
+#endif
+
+/* end of tipconf.h */
diff --git a/usr.bin/tip/tipout.c b/usr.bin/tip/tip/tipout.c
index 7288eb8..3464dd5 100644
--- a/usr.bin/tip/tipout.c
+++ b/usr.bin/tip/tip/tipout.c
@@ -136,6 +136,18 @@ tipout()
sigblock(sigmask(SIGTERM));
intTERM();
/*NOTREACHED*/
+ } else if (cnt == 0 && errno == ENOENT) {
+ if (getppid() != 1)
+ kill(getppid(),SIGUSR1);
+ sigblock(sigmask(SIGTERM));
+ intTERM();
+ /*NOTREACHED*/
+ } else if (cnt < 0) {
+ if (getppid() != 1)
+ kill(getppid(),SIGUSR1);
+ sigblock(sigmask(SIGTERM));
+ intTERM();
+ /*NOTREACHED*/
}
continue;
}
diff --git a/usr.bin/tip/tip/value.c b/usr.bin/tip/tip/value.c
new file mode 100644
index 0000000..7823805
--- /dev/null
+++ b/usr.bin/tip/tip/value.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)value.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tip.h"
+
+#define MIDDLE 35
+
+static value_t *vlookup();
+static int col = 0;
+
+/*
+ * Variable manipulation
+ */
+vinit()
+{
+ register value_t *p;
+ register char *cp;
+ FILE *f;
+ char file[256];
+
+ for (p = vtable; p->v_name != NULL; p++) {
+ if (p->v_type&ENVIRON)
+ if (cp = getenv(p->v_name))
+ p->v_value = cp;
+ if (p->v_type&IREMOTE)
+ number(p->v_value) = *address(p->v_value);
+ }
+ /*
+ * Read the .tiprc file in the HOME directory
+ * for sets
+ */
+ strcpy(file, value(HOME));
+ strcat(file, "/.tiprc");
+ if ((f = fopen(file, "r")) != NULL) {
+ register char *tp;
+
+ while (fgets(file, sizeof(file)-1, f) != NULL) {
+ if (vflag)
+ printf("set %s", file);
+ if (tp = rindex(file, '\n'))
+ *tp = '\0';
+ vlex(file);
+ }
+ fclose(f);
+ }
+ /*
+ * To allow definition of exception prior to fork
+ */
+ vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
+}
+
+static int vaccess();
+
+/*VARARGS1*/
+vassign(p, v)
+ register value_t *p;
+ char *v;
+{
+
+ if (!vaccess(p->v_access, WRITE)) {
+ printf("access denied\r\n");
+ return;
+ }
+ switch (p->v_type&TMASK) {
+
+ case STRING:
+ if (p->v_value && equal(p->v_value, v))
+ return;
+ if (!(p->v_type&(ENVIRON|INIT)))
+ free(p->v_value);
+ if ((p->v_value = malloc(size(v)+1)) == NOSTR) {
+ printf("out of core\r\n");
+ return;
+ }
+ p->v_type &= ~(ENVIRON|INIT);
+ strcpy(p->v_value, v);
+ break;
+
+ case NUMBER:
+ if (number(p->v_value) == number(v))
+ return;
+ number(p->v_value) = number(v);
+ break;
+
+ case BOOL:
+ if (boolean(p->v_value) == (*v != '!'))
+ return;
+ boolean(p->v_value) = (*v != '!');
+ break;
+
+ case CHAR:
+ if (character(p->v_value) == *v)
+ return;
+ character(p->v_value) = *v;
+ }
+ p->v_access |= CHANGED;
+}
+
+static void vprint();
+
+vlex(s)
+ register char *s;
+{
+ register value_t *p;
+ static void vtoken();
+
+ if (equal(s, "all")) {
+ for (p = vtable; p->v_name; p++)
+ if (vaccess(p->v_access, READ))
+ vprint(p);
+ } else {
+ register char *cp;
+
+ do {
+ if (cp = vinterp(s, ' '))
+ cp++;
+ vtoken(s);
+ s = cp;
+ } while (s);
+ }
+ if (col > 0) {
+ printf("\r\n");
+ col = 0;
+ }
+}
+
+static void
+vtoken(s)
+ register char *s;
+{
+ register value_t *p;
+ register char *cp;
+ char *expand();
+
+ if (cp = index(s, '=')) {
+ *cp = '\0';
+ if (p = vlookup(s)) {
+ cp++;
+ if (p->v_type&NUMBER)
+ vassign(p, atoi(cp));
+ else {
+ if (strcmp(s, "record") == 0)
+ cp = expand(cp);
+ vassign(p, cp);
+ }
+ return;
+ }
+ } else if (cp = index(s, '?')) {
+ *cp = '\0';
+ if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
+ vprint(p);
+ return;
+ }
+ } else {
+ if (*s != '!')
+ p = vlookup(s);
+ else
+ p = vlookup(s+1);
+ if (p != NOVAL) {
+ vassign(p, s);
+ return;
+ }
+ }
+ printf("%s: unknown variable\r\n", s);
+}
+
+static void
+vprint(p)
+ register value_t *p;
+{
+ register char *cp;
+ extern char *interp(), *ctrl();
+
+ if (col > 0 && col < MIDDLE)
+ while (col++ < MIDDLE)
+ putchar(' ');
+ col += size(p->v_name);
+ switch (p->v_type&TMASK) {
+
+ case BOOL:
+ if (boolean(p->v_value) == FALSE) {
+ col++;
+ putchar('!');
+ }
+ printf("%s", p->v_name);
+ break;
+
+ case STRING:
+ printf("%s=", p->v_name);
+ col++;
+ if (p->v_value) {
+ cp = interp(p->v_value, NULL);
+ col += size(cp);
+ printf("%s", cp);
+ }
+ break;
+
+ case NUMBER:
+ col += 6;
+ printf("%s=%-5d", p->v_name, number(p->v_value));
+ break;
+
+ case CHAR:
+ printf("%s=", p->v_name);
+ col++;
+ if (p->v_value) {
+ cp = ctrl(character(p->v_value));
+ col += size(cp);
+ printf("%s", cp);
+ }
+ break;
+ }
+ if (col >= MIDDLE) {
+ col = 0;
+ printf("\r\n");
+ return;
+ }
+}
+
+
+static int
+vaccess(mode, rw)
+ register unsigned mode, rw;
+{
+ if (mode & (rw<<PUBLIC))
+ return (1);
+ if (mode & (rw<<PRIVATE))
+ return (1);
+ return ((mode & (rw<<ROOT)) && getuid() == 0);
+}
+
+static value_t *
+vlookup(s)
+ register char *s;
+{
+ register value_t *p;
+
+ for (p = vtable; p->v_name; p++)
+ if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
+ return (p);
+ return (NULL);
+}
+
+char *
+vinterp(s, stop)
+ register char *s;
+ char stop;
+{
+ register char *p = s, c;
+ int num;
+
+ while ((c = *s++) && c != stop)
+ switch (c) {
+
+ case '^':
+ if (*s)
+ *p++ = *s++ - 0100;
+ else
+ *p++ = c;
+ break;
+
+ case '\\':
+ num = 0;
+ c = *s++;
+ if (c >= '0' && c <= '7')
+ num = (num<<3)+(c-'0');
+ else {
+ register char *q = "n\nr\rt\tb\bf\f";
+
+ for (; *q; q++)
+ if (c == *q++) {
+ *p++ = *q;
+ goto cont;
+ }
+ *p++ = c;
+ cont:
+ break;
+ }
+ if ((c = *s++) >= '0' && c <= '7') {
+ num = (num<<3)+(c-'0');
+ if ((c = *s++) >= '0' && c <= '7')
+ num = (num<<3)+(c-'0');
+ else
+ s--;
+ } else
+ s--;
+ *p++ = num;
+ break;
+
+ default:
+ *p++ = c;
+ }
+ *p = '\0';
+ return (c == stop ? s-1 : NULL);
+}
+
+/*
+ * assign variable s with value v (for NUMBER or STRING or CHAR types)
+ */
+
+vstring(s,v)
+ register char *s;
+ register char *v;
+{
+ register value_t *p;
+ char *expand();
+
+ p = vlookup(s);
+ if (p == 0)
+ return (1);
+ if (p->v_type&NUMBER)
+ vassign(p, atoi(v));
+ else {
+ if (strcmp(s, "record") == 0)
+ v = expand(v);
+ vassign(p, v);
+ }
+ return (0);
+}
diff --git a/usr.bin/tip/tip/vars.c b/usr.bin/tip/tip/vars.c
new file mode 100644
index 0000000..5fad05a
--- /dev/null
+++ b/usr.bin/tip/tip/vars.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "tipconf.h"
+#include "tip.h"
+#include "pathnames.h"
+
+/*
+ * Definition of variables
+ */
+value_t vtable[] = {
+ { "beautify", BOOL, (READ|WRITE)<<PUBLIC,
+ "be", (char *)TRUE },
+ { "baudrate", NUMBER|IREMOTE|INIT, (READ<<PUBLIC)|(WRITE<<ROOT),
+ "ba", (char *)&BR },
+ { "dialtimeout",NUMBER, (READ<<PUBLIC)|(WRITE<<ROOT),
+ "dial", (char *)60 },
+ { "eofread", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "eofr", (char *)&IE },
+ { "eofwrite", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "eofw", (char *)&OE },
+ { "eol", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ NOSTR, (char *)&EL },
+ { "escape", CHAR, (READ|WRITE)<<PUBLIC,
+ "es", (char *)'~' },
+ { "exceptions", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "ex", (char *)&EX },
+ { "force", CHAR, (READ|WRITE)<<PUBLIC,
+ "fo", (char *)CTRL('p') },
+ { "framesize", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "fr", (char *)&FS },
+ { "host", STRING|IREMOTE|INIT, READ<<PUBLIC,
+ "ho", (char *)&HO },
+ { "log", STRING|INIT, (READ|WRITE)<<ROOT,
+ NOSTR, _PATH_ACULOG },
+ { "login", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "li", (char *)&LI },
+ { "logout", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "lo", (char *)&LO },
+ { "phones", STRING|INIT|IREMOTE, READ<<PUBLIC,
+ NOSTR, (char *)&PH },
+ { "prompt", CHAR, (READ|WRITE)<<PUBLIC,
+ "pr", (char *)'\n' },
+ { "raise", BOOL, (READ|WRITE)<<PUBLIC,
+ "ra", (char *)FALSE },
+ { "raisechar", CHAR, (READ|WRITE)<<PUBLIC,
+ "rc", (char *)CTRL('a') },
+ { "record", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "rec", (char *)&RE },
+ { "remote", STRING|INIT|IREMOTE, READ<<PUBLIC,
+ NOSTR, (char *)&RM },
+ { "script", BOOL, (READ|WRITE)<<PUBLIC,
+ "sc", (char *)FALSE },
+ { "tabexpand", BOOL, (READ|WRITE)<<PUBLIC,
+ "tab", (char *)FALSE },
+ { "verbose", BOOL, (READ|WRITE)<<PUBLIC,
+ "verb", (char *)TRUE },
+ { "SHELL", STRING|ENVIRON|INIT, (READ|WRITE)<<PUBLIC,
+ NULL, _PATH_BSHELL },
+ { "HOME", STRING|ENVIRON, (READ|WRITE)<<PUBLIC,
+ NOSTR, NOSTR },
+ { "echocheck", BOOL, (READ|WRITE)<<PUBLIC,
+ "ec", (char *)FALSE },
+ { "disconnect", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "di", (char *)&DI },
+ { "tandem", BOOL, (READ|WRITE)<<PUBLIC,
+ "ta", (char *)TRUE },
+ { "linedelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "ldelay", (char *)&DL },
+ { "chardelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "cdelay", (char *)&CL },
+ { "etimeout", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "et", (char *)&ET },
+ { "rawftp", BOOL, (READ|WRITE)<<PUBLIC,
+ "raw", (char *)FALSE },
+ { "halfduplex", BOOL, (READ|WRITE)<<PUBLIC,
+ "hdx", (char *)FALSE },
+ { "localecho", BOOL, (READ|WRITE)<<PUBLIC,
+ "le", (char *)FALSE },
+ { "parity", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "par", (char *)&PA },
+ { NOSTR, NULL, NULL, NOSTR, NOSTR }
+};
diff --git a/usr.bin/tn3270/Makefile b/usr.bin/tn3270/Makefile
index 009e31f..2997c41 100644
--- a/usr.bin/tn3270/Makefile
+++ b/usr.bin/tn3270/Makefile
@@ -1,9 +1,17 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
-SUBDIR= tn3270 mset
-
-.if !make(install)
-SUBDIR+=tools
+.if !make(install) && !make(distribute)
+# Build tools first so that things don't get built using stale tools and
+# then built again after the tools are freshened.
+#
+# XXX this doesn't fix the problem if the tools are built by running make
+# in the tn3270 subdir, because the Makefile doesn't give the full
+# dependencies of the tools.
+#
+# XXX this doesn't fix the problem for `make depend' either.
+SUBDIR= tools
.endif
+SUBDIR+=tn3270 mset
+
.include <bsd.subdir.mk>
diff --git a/usr.bin/tn3270/api/asc_ebc.c b/usr.bin/tn3270/api/asc_ebc.c
index 14061f0..1e999dc 100644
--- a/usr.bin/tn3270/api/asc_ebc.c
+++ b/usr.bin/tn3270/api/asc_ebc.c
@@ -77,7 +77,7 @@ unsigned char ebc_asc[NEBC] = {
/* 38 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
/* 40 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
-/* 48 */ ' ', ' ',
+/* 48 */ ' ', ' ',
#if !defined(MSDOS)
/* 4A */ '\\',
#else /* !defined(MSDOS) */
diff --git a/usr.bin/tn3270/ascii/map3270.c b/usr.bin/tn3270/ascii/map3270.c
index 0295509..9ae1b2a 100644
--- a/usr.bin/tn3270/ascii/map3270.c
+++ b/usr.bin/tn3270/ascii/map3270.c
@@ -441,7 +441,7 @@ EatToNL()
lex = Get();
- while (!((lex.type != LEX_ESCAPED) && (lex.type != LEX_CARETED) &&
+ while (!((lex.type != LEX_ESCAPED) && (lex.type != LEX_CARETED) &&
(lex.value == '\n')) && (!(lex.type == LEX_END_OF_FILE))) {
lex = Get();
}
diff --git a/usr.bin/tn3270/ascii/mset.c b/usr.bin/tn3270/ascii/mset.c
index 508fe66..b87a1ec 100644
--- a/usr.bin/tn3270/ascii/mset.c
+++ b/usr.bin/tn3270/ascii/mset.c
@@ -286,7 +286,7 @@ char *begin, *tc_name;
case '\\':
case '\'':
if (toshell) {
- numbchars += 2;
+ numbchars += 2;
printf("%c%c", '\\', pchar);
}
else {
@@ -397,7 +397,7 @@ char *argv[];
recurse(0, head);
/* now print them out */
for (rptr = regstates[0].forward; rptr->result != 0;
- rptr = rptr->forward) {
+ rptr = rptr->forward) {
printString(rptr->match_end, rptr->match_start, rptr->result);
}
if (toshell) {
diff --git a/usr.bin/tn3270/ctlr/api.c b/usr.bin/tn3270/ctlr/api.c
index 1113295..801e0ee 100644
--- a/usr.bin/tn3270/ctlr/api.c
+++ b/usr.bin/tn3270/ctlr/api.c
@@ -305,7 +305,7 @@ struct SREGS *sregs;
parms.rc = 0;
if (parms.options == OPTION_SINGLE_KEYSTROKE) {
KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry;
-
+
if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) {
parms.rc = 0x10; /* XXX needs 0x12 too! */
}
@@ -749,7 +749,12 @@ struct SREGS *sregs;
Dump('>', (char *)regs, sizeof *regs);
Dump('>', (char *)sregs, sizeof *sregs);
#ifdef MSDOS
- { char buf[10]; gets(buf); }
+ {
+ int ch;
+
+ while ((ch = getchar()) != '\n' && ch != EOF)
+ ;
+ }
#endif /* MSDOS */
}
}
diff --git a/usr.bin/tn3270/ctlr/api.h b/usr.bin/tn3270/ctlr/api.h
index 8004f34..ba0df8d 100644
--- a/usr.bin/tn3270/ctlr/api.h
+++ b/usr.bin/tn3270/ctlr/api.h
@@ -264,7 +264,7 @@ typedef struct {
short
begin; /* Offset within buffer */
} BufferDescriptor;
-
+
typedef struct {
char
rc,
@@ -345,7 +345,7 @@ typedef struct {
#if defined(vax) || defined(ns32000) || defined(i386) || (defined(mips)&&defined(MIPSEL))
#define BYTE_ORDER LITTLE_ENDIAN
-#endif /* defined(vax) || defined(ns32000) */
+#endif /* defined(vax) || defined(ns32000) */
#if defined(sun) || defined(tahoe) || defined(ibm032) || defined(pyr) || defined(gould) || (defined(mips)&&defined(MIPSEB))
#define BYTE_ORDER BIG_ENDIAN
diff --git a/usr.bin/tn3270/ctlr/inbound.c b/usr.bin/tn3270/ctlr/inbound.c
index fe8d142..6f530c3 100644
--- a/usr.bin/tn3270/ctlr/inbound.c
+++ b/usr.bin/tn3270/ctlr/inbound.c
@@ -210,7 +210,7 @@ EraseEndOfField()
AddHost(i, 0);
i = ScreenInc(i);
} while (i != HighestScreen());
- }
+ }
}
}
diff --git a/usr.bin/tn3270/distribution/makefile_4.2 b/usr.bin/tn3270/distribution/makefile_4.2
index b8e5eb8e..9f35a6c 100644
--- a/usr.bin/tn3270/distribution/makefile_4.2
+++ b/usr.bin/tn3270/distribution/makefile_4.2
@@ -106,7 +106,7 @@ BINDIR = $(DESTDIR)/usr/ucb
# Names for the terminal libraries...
LIBCURSES = -lcurses
-LIBTERM = -ltermlib
+LIBTERMCAP = -ltermcap
#PC_LIBCURSES =
#PC_LIBTERM =
@@ -156,7 +156,7 @@ FRC:
tn3270$X: telnet/telprog.o ${SUBLIB} api/apilib.a
${CC} ${CFLAGS} -o tn3270 telnet/telprog.o \
- $L ${SUBLIB} api/apilib.a $(LIBCURSES) $(LIBTERM)
+ $L ${SUBLIB} api/apilib.a ${LIBCURSES} ${LIBTERMCAP}
#PC_tn3270$X:
#PC_ link <@<
diff --git a/usr.bin/tn3270/distribution/sys_dos/system.c b/usr.bin/tn3270/distribution/sys_dos/system.c
index 864926b..06c2194 100644
--- a/usr.bin/tn3270/distribution/sys_dos/system.c
+++ b/usr.bin/tn3270/distribution/sys_dos/system.c
@@ -74,7 +74,7 @@ shell_continue()
handle_api(&spinted.regs, &spinted.sregs);
spint_continue(&spinted);
} else {
- char inputbuffer[100];
+ int ch;
if (spinted.rc != 0) {
fprintf(stderr, "Process generated a return code of 0x%x.\n",
@@ -82,7 +82,8 @@ shell_continue()
}
printf("[Hit return to continue]");
fflush(stdout);
- (void) gets(inputbuffer);
+ while ((ch = getchar()) != '\n' && ch != EOF)
+ ;
shell_active = 0;
setconnmode();
ConnectScreen();
diff --git a/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c
index fedeb69..6b71090 100644
--- a/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c
+++ b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c
@@ -118,7 +118,7 @@ FILE *fp;
if(extract(name, size, mode, mtime, fp))
skip = 0;
-
+
if (verbose)
printf("\n");
break;
@@ -171,7 +171,7 @@ FILE *ifp;
return (0);
}
}
-
+
for(copied = 0; copied < size; copied += TBLOCK) {
if(fread(fbuf, TBLOCK, 1, ifp) != 1) {
perror("fread");
diff --git a/usr.bin/tn3270/general/general.h b/usr.bin/tn3270/general/general.h
index 8fee245..b098041 100644
--- a/usr.bin/tn3270/general/general.h
+++ b/usr.bin/tn3270/general/general.h
@@ -54,7 +54,7 @@
#define memset(s,c,n) if (c == 0) { \
bzero(s,n); \
} else { \
- register char *src = s; \
+ register char *src = (char *)s; \
register int count = n; \
\
while (count--) { \
diff --git a/usr.bin/tn3270/mset/Makefile b/usr.bin/tn3270/mset/Makefile
index 0094fc8..db31b2e 100644
--- a/usr.bin/tn3270/mset/Makefile
+++ b/usr.bin/tn3270/mset/Makefile
@@ -3,8 +3,8 @@
PROG= mset
CFLAGS+=-I${.CURDIR} -I.
SRCS+= astosc.c map3270.c mset.c
-MAN1= mset.0
-MAN5= map3270.0
+MAN1= mset.1
+MAN5= map3270.5
.PATH: ${.CURDIR}/../api ${.CURDIR}/../ascii
CLEANFILES+= astosc.OUT astosc.out
@@ -14,16 +14,22 @@ CLEANFILES+= astosc.OUT astosc.out
DEPSRCS+= astosc.OUT map3270.c mset.c
+.if exists(${.OBJDIR}/../tools/mkastosc)
+MKOBJ=${.OBJDIR}/../tools/mkastosc
+.else
+MKOBJ=${.CURDIR}/../tools/mkastosc
+.endif
+
astosc.o: astosc.OUT
astosc.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h
-astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${.CURDIR}/../tools/mkastosc/obj/mkastosc
- ${.CURDIR}/../tools/mkastosc/obj/mkastosc \
- ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h \
- < ${.CURDIR}/../ctlr/${KBD} > ${.TARGET}
+astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${MKOBJ}/mkastosc
+ ${MKOBJ}/mkastosc ${.CURDIR}/../ctlr/hostctlr.h \
+ ${.CURDIR}/../ctlr/function.h \
+ < ${.CURDIR}/../ctlr/${KBD} > ${.TARGET}
rm -f astosc.out; ln -s astosc.OUT astosc.out
# astosc.out
-${.CURDIR}/../tools/mkastosc/obj/mkastosc:
+${MKOBJ}/mkastosc:
cd ${.CURDIR}/../tools/mkastosc; make
depend: .depend
diff --git a/usr.bin/tn3270/sys_curses/system.c b/usr.bin/tn3270/sys_curses/system.c
index 14a99bd..67b31af 100644
--- a/usr.bin/tn3270/sys_curses/system.c
+++ b/usr.bin/tn3270/sys_curses/system.c
@@ -593,7 +593,7 @@ child_died(code)
while ((pid = wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
if (pid == shell_pid) {
- char inputbuffer[100];
+ int ch;
extern void setconnmode();
extern void ConnectScreen();
@@ -604,7 +604,8 @@ child_died(code)
}
printf("[Hit return to continue]");
fflush(stdout);
- (void) gets(inputbuffer);
+ while ((ch = getchar()) != '\n' && ch != EOF)
+ ;
setconnmode();
ConnectScreen(); /* Turn screen on (if need be) */
(void) close(serversock);
diff --git a/usr.bin/tn3270/sys_curses/termout.c b/usr.bin/tn3270/sys_curses/termout.c
index 5dbe311..128d7e5 100644
--- a/usr.bin/tn3270/sys_curses/termout.c
+++ b/usr.bin/tn3270/sys_curses/termout.c
@@ -37,18 +37,10 @@ static char sccsid[] = "@(#)termout.c 8.1 (Berkeley) 6/6/93";
#if defined(unix)
#include <signal.h>
-#include <sgtty.h>
+#include <termios.h>
#endif
#include <stdio.h>
#include <curses.h>
-#if defined(ultrix)
-/* Some version of this OS has a bad definition for nonl() */
-#undef nl
-#undef nonl
-
-#define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
-#define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
-#endif /* defined(ultrix) */
#include "../general/general.h"
@@ -204,7 +196,7 @@ SlowScreen()
register int fieldattr, termattr;
register int columnsleft;
-#define NORMAL 0
+#define NORMAL 0
#define HIGHLIGHT 1 /* Mask bits */
#define NONDISPLAY 4 /* Mask bits */
#define UNDETERMINED 8 /* Mask bits */
@@ -628,12 +620,11 @@ void
InitTerminal()
{
#if defined(unix)
- struct sgttyb ourttyb;
- static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
- 2400, 4800, 9600 };
+ struct termios termios_info;
+ speed_t speed;
#endif
extern void InitMapping();
-
+
InitMapping(); /* Go do mapping file (MAP3270) first */
if (!screenInitd) { /* not initialized */
#if defined(unix)
@@ -657,14 +648,14 @@ InitTerminal()
TryToSend = FastScreen;
#if defined(unix)
- ioctl(1, TIOCGETP, (char *) &ourttyb);
- if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
+ (void) tcgetattr(1, &termios_info);
+ speed = cfgetospeed(&termios_info);
+ if (speed > 19200) {
max_changes_before_poll = 1920;
} else {
- max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
- if (max_changes_before_poll < 40) {
+ max_changes_before_poll = speed/10;
+ if (max_changes_before_poll < 40)
max_changes_before_poll = 40;
- }
TryToSend = SlowScreen;
HaveInput = 1; /* get signals going */
}
diff --git a/usr.bin/tn3270/tn3270/Makefile b/usr.bin/tn3270/tn3270/Makefile
index a9f1641..df18677 100644
--- a/usr.bin/tn3270/tn3270/Makefile
+++ b/usr.bin/tn3270/tn3270/Makefile
@@ -2,13 +2,13 @@
PROG= tn3270
CFLAGS+=-I${.CURDIR} -I.
-LDADD+= -lcurses -ltermcap -ltelnet
-DPADD+= ${LIBCURSES} /usr/lib/libtermcap.a /usr/lib/libtelnet.a
+DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBTELNET} ${LIBCRYPT}
+LDADD= -lcurses -ltermcap -ltelnet -lcrypt
CLEANFILES+= asc_disp.OUT asc_disp.out disp_asc.OUT disp_asc.out TMPfunc.out
.PATH: ${.CURDIR}/../api ${.CURDIR}/../ascii ${.CURDIR}/../ctlr
.PATH: ${.CURDIR}/../general ${.CURDIR}/../sys_curses ${.CURDIR}/../../telnet
-MAN1= tn3270.0
+MAN1= tn3270.1
SRCS+= apilib.c api_bsd.c api_exch.c asc_ebc.c astosc.c dctype.c
SRCS+= disp_asc.c ebc_disp.c
@@ -30,31 +30,55 @@ DEPSRCS+= genbsubs.c globals.c system.c termout.c
DEPSRCS+= commands.c main.c network.c ring.c sys_bsd.c telnet.c terminal.c
DEPSRCS+= tn3270.c utilities.c
+.if exists(${.OBJDIR}/../tools/mkastosc)
+MKASTOSCDIR= ${.OBJDIR}/../tools/mkastosc
+.else
+MKASTOSCDIR= ${.CURDIR}/../tools/mkastosc
+.endif
+
+.if exists(${.OBJDIR}/../tools/mkastods)
+MKASTODSDIR= ${.OBJDIR}/../tools/mkastods
+.else
+MKASTODSDIR= ${.CURDIR}/../tools/mkastods
+.endif
+
+.if exists(${.OBJDIR}/../tools/mkdstoas)
+MKDSTOASDIR= ${.OBJDIR}/../tools/mkdstoas
+.else
+MKDSTOASDIR= ${.CURDIR}/../tools/mkdstoas
+.endif
+
+.if exists(${.OBJDIR}/../tools/mkhits)
+MKHITSDIR= ${.OBJDIR}/../tools/mkhits
+.else
+MKHITSDIR= ${.CURDIR}/../tools/mkhits
+.endif
+
astosc.o: astosc.OUT
CLEANFILES+= astosc.OUT astosc.out
astosc.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h
-astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${.CURDIR}/../tools/mkastosc/obj/mkastosc
- ${.CURDIR}/../tools/mkastosc/obj/mkastosc \
+astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${MKASTOSCDIR}/mkastosc
+ ${MKASTOSCDIR}/mkastosc \
${.CURDIR}/../ctlr/hostctlr.h \
${.CURDIR}/../ctlr/function.h < ${.CURDIR}/../ctlr/${KBD} \
> ${.TARGET}
rm -f astosc.out; ln -s astosc.OUT astosc.out
disp_asc.o: asc_disp.OUT disp_asc.OUT
-asc_disp.OUT: ${.CURDIR}/../tools/mkastods/obj/mkastods
- ${.CURDIR}/../tools/mkastods/obj/mkastods > ${.TARGET}
+asc_disp.OUT: ${MKASTODSDIR}/mkastods
+ ${MKASTODSDIR}/mkastods > ${.TARGET}
rm -f asc_disp.out; ln -s asc_disp.OUT asc_disp.out
-disp_asc.OUT: ${.CURDIR}/../tools/mkdstoas/obj/mkdstoas
- ${.CURDIR}/../tools/mkdstoas/obj/mkdstoas > ${.TARGET}
+disp_asc.OUT: ${MKDSTOASDIR}/mkdstoas
+ ${MKDSTOASDIR}/mkdstoas > ${.TARGET}
rm -f disp_asc.out; ln -s disp_asc.OUT disp_asc.out
inbound.o: kbd.OUT
CLEANFILES += kbd.OUT kbd.out
kbd.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/${KBD}
-kbd.OUT: ${.CURDIR}/../tools/mkhits/obj/mkhits
+kbd.OUT: ${MKHITSDIR}/mkhits
${CC} ${CFLAGS} -E ${.CURDIR}/../ctlr/function.c > TMPfunc.out
- ${.CURDIR}/../tools/mkhits/obj/mkhits ${.CURDIR}/../ctlr/hostctlr.h \
+ ${MKHITSDIR}/mkhits ${.CURDIR}/../ctlr/hostctlr.h \
TMPfunc.out < ${.CURDIR}/../ctlr/${KBD} > ${.TARGET}
rm -f kbd.out; ln -s kbd.OUT kbd.out
@@ -63,13 +87,13 @@ kbd.OUT: ${.CURDIR}/../tools/mkhits/obj/mkhits
# default.map
# kbd.out
-${.CURDIR}/../tools/mkastosc/obj/mkastosc:
+${MKASTOSCDIR}/mkastosc:
cd ${.CURDIR}/../tools/mkastosc; make
-${.CURDIR}/../tools/mkastods/obj/mkastods:
+${MKASTODSDIR}/mkastods:
cd ${.CURDIR}/../tools/mkastods; make
-${.CURDIR}/../tools/mkdstoas/obj/mkdstoas:
+${MKDSTOASDIR}/mkdstoas:
cd ${.CURDIR}/../tools/mkdstoas; make
-${.CURDIR}/../tools/mkhits/obj/mkhits:
+${MKHITSDIR}/mkhits:
cd ${.CURDIR}/../tools/mkhits; make
depend: .depend
diff --git a/usr.bin/tn3270/tn3270/tn3270.1 b/usr.bin/tn3270/tn3270/tn3270.1
index 778302e..a2aba2f 100644
--- a/usr.bin/tn3270/tn3270/tn3270.1
+++ b/usr.bin/tn3270/tn3270/tn3270.1
@@ -316,8 +316,8 @@ and
.Xr telnet 1 ,
.Xr curses 3 ,
.Xr termcap 3 ,
-.Xr termcap 5 ,
.Xr map3270 5 ,
+.Xr termcap 5
.Rs
.%T "Yale ASCII Terminal Communication"
.%B "System II Program Description/Operator's Manual"
diff --git a/usr.bin/tn3270/tools/mkastods/Makefile b/usr.bin/tn3270/tools/mkastods/Makefile
index a2d36a1..f7c6608 100644
--- a/usr.bin/tn3270/tools/mkastods/Makefile
+++ b/usr.bin/tn3270/tools/mkastods/Makefile
@@ -2,7 +2,7 @@
PROG= mkastods
SRCS= mkastods.c asc_ebc.c ebc_disp.c
-CFLAGS+=-I${.CURDIR}/.. -I.
+CFLAGS+=-I${.CURDIR}/..
NOMAN= noman
.PATH: ${.CURDIR}/../../api
diff --git a/usr.bin/tn3270/tools/mkastosc/Makefile b/usr.bin/tn3270/tools/mkastosc/Makefile
index a6268f5..c06d075 100644
--- a/usr.bin/tn3270/tools/mkastosc/Makefile
+++ b/usr.bin/tn3270/tools/mkastosc/Makefile
@@ -2,7 +2,7 @@
PROG= mkastosc
SRCS= mkastosc.c dohits.c asc_ebc.c ebc_disp.c
-CFLAGS+=-I${.CURDIR}/../mkhits -I${.CURDIR}/.. -I.
+CFLAGS+=-I${.CURDIR}/../mkhits -I${.CURDIR}/..
NOMAN= noman
.PATH: ${.CURDIR}/../mkhits ${.CURDIR}/../../api
diff --git a/usr.bin/tn3270/tools/mkastosc/mkastosc.c b/usr.bin/tn3270/tools/mkastosc/mkastosc.c
index 697122d..932a388 100644
--- a/usr.bin/tn3270/tools/mkastosc/mkastosc.c
+++ b/usr.bin/tn3270/tools/mkastosc/mkastosc.c
@@ -133,7 +133,7 @@ char *argv[];
}
printf(" */\n");
}
-
+
for (attable = &table[0]; attable <= &table[highestof(table)]; attable++) {
for (this = *attable; this; this = this->next) {
diff --git a/usr.bin/tn3270/tools/mkdctype/Makefile b/usr.bin/tn3270/tools/mkdctype/Makefile
index 818bb52..363eb01 100644
--- a/usr.bin/tn3270/tools/mkdctype/Makefile
+++ b/usr.bin/tn3270/tools/mkdctype/Makefile
@@ -2,7 +2,7 @@
PROG= mkdctype
SRCS= mkdctype.c ebc_disp.c ectype.c
-CFLAGS+=-I${.CURDIR}/.. -I.
+CFLAGS+=-I${.CURDIR}/..
NOMAN= noman
.PATH: ${.CURDIR}/../../api
diff --git a/usr.bin/tn3270/tools/mkdstoas/Makefile b/usr.bin/tn3270/tools/mkdstoas/Makefile
index b2abeb3..53ecd70 100644
--- a/usr.bin/tn3270/tools/mkdstoas/Makefile
+++ b/usr.bin/tn3270/tools/mkdstoas/Makefile
@@ -2,7 +2,7 @@
PROG= mkdstoas
SRCS= mkdstoas.c asc_ebc.c ebc_disp.c
-CFLAGS+=-I${.CURDIR}/.. -I.
+CFLAGS+=-I${.CURDIR}/..
NOMAN= noman
.PATH: ${.CURDIR}/../../api
diff --git a/usr.bin/tn3270/tools/mkhits/Makefile b/usr.bin/tn3270/tools/mkhits/Makefile
index c7c8802..169e6c4 100644
--- a/usr.bin/tn3270/tools/mkhits/Makefile
+++ b/usr.bin/tn3270/tools/mkhits/Makefile
@@ -2,7 +2,7 @@
PROG= mkhits
SRCS= mkhits.c dohits.c asc_ebc.c ebc_disp.c
-CFLAGS+=-I${.CURDIR}/.. -I.
+CFLAGS+=-I${.CURDIR}/..
NOMAN= noman
.PATH: ${.CURDIR}/../../api
diff --git a/usr.bin/tn3270/tools/mkhits/dohits.c b/usr.bin/tn3270/tools/mkhits/dohits.c
index d2d576e..7f75569 100644
--- a/usr.bin/tn3270/tools/mkhits/dohits.c
+++ b/usr.bin/tn3270/tools/mkhits/dohits.c
@@ -101,6 +101,7 @@ int value;
item = &firstentry(second);
this = (struct thing *) malloc(sizeof *this);
+ memset(this, 0, sizeof *this);
this->next = *item;
*item = this;
this->value = value;
@@ -257,7 +258,7 @@ char *aidfile, *fcnfile;
}
scanwhite(fcnfile, "FCN_");
- while (gets(line) != NULL) {
+ while (fgets(line, sizeof line, stdin) != NULL) {
if (!isdigit(line[0])) {
continue;
}
diff --git a/usr.bin/top/Makefile b/usr.bin/top/Makefile
new file mode 100644
index 0000000..7d93a45
--- /dev/null
+++ b/usr.bin/top/Makefile
@@ -0,0 +1,28 @@
+PROG= top
+
+TOPDIR= ${.CURDIR}/../../contrib/top
+.PATH: ${TOPDIR}
+
+CFLAGS+= -DHAVE_GETOPT -I${.CURDIR} -I${TOPDIR}
+
+#
+# The table size should be a prime number approximately twice as
+# large as the number of lines in /etc/passwd. The default number
+# is 20011, use /etc/make.conf to override this.
+#
+.if defined(TOP_TABLE_SIZE)
+CFLAGS+= -D"Table_size=${TOP_TABLE_SIZE}"
+.endif
+
+SRCS= commands.c display.c machine.c screen.c top.c \
+ username.c utils.c version.c
+
+DPADD= ${LIBTERMCAP} ${LIBM} ${LIBKVM}
+LDADD= -ltermcap -lm -lkvm
+BINGRP= kmem
+BINMODE=2555
+
+top.1: ${TOPDIR}/top.X top.local.1
+ cat ${.ALLSRC} > top.1
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c
new file mode 100644
index 0000000..57d3175
--- /dev/null
+++ b/usr.bin/top/machine.c
@@ -0,0 +1,935 @@
+/*
+ * top - a top users display for Unix
+ *
+ * SYNOPSIS: For FreeBSD-2.x system
+ *
+ * DESCRIPTION:
+ * Originally written for BSD4.4 system by Christos Zoulas.
+ * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
+ *
+ * This is the machine-dependent module for FreeBSD 2.2
+ * Works for:
+ * FreeBSD 2.2, and probably FreeBSD 2.1.x
+ *
+ * LIBS: -lkvm
+ *
+ * AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
+ * Steven Wallace <swallace@freebsd.org>
+ * Wolfram Schneider <wosch@FreeBSD.org>
+ *
+ * $Id: machine.c,v 1.2 1997/04/19 20:28:50 peter Exp $
+ */
+
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/param.h>
+
+#include "os.h"
+#include <stdio.h>
+#include <nlist.h>
+#include <math.h>
+#include <kvm.h>
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <sys/dkstat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/vmmeter.h>
+
+/* Swap */
+#include <stdlib.h>
+#include <sys/rlist.h>
+#include <sys/conf.h>
+
+#include <osreldate.h> /* for changes in kernel structures */
+
+#include "top.h"
+#include "machine.h"
+
+static int check_nlist __P((struct nlist *));
+static int getkval __P((unsigned long, int *, int, char *));
+extern char* printable __P((char *));
+int swapmode __P((int *retavail, int *retfree));
+
+
+
+/* get_process_info passes back a handle. This is what it looks like: */
+
+struct handle
+{
+ struct kinfo_proc **next_proc; /* points to next valid proc pointer */
+ int remaining; /* number of pointers remaining */
+};
+
+/* declarations for load_avg */
+#include "loadavg.h"
+
+#define PP(pp, field) ((pp)->kp_proc . field)
+#define EP(pp, field) ((pp)->kp_eproc . field)
+#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
+
+/* define what weighted cpu is. */
+#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
+ ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))
+
+/* what we consider to be process size: */
+#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
+
+/* definitions for indices in the nlist array */
+
+
+static struct nlist nlst[] = {
+#define X_CCPU 0
+ { "_ccpu" }, /* 0 */
+#define X_CP_TIME 1
+ { "_cp_time" }, /* 1 */
+#define X_HZ 2
+ { "_hz" }, /* 2 */
+#define X_STATHZ 3
+ { "_stathz" }, /* 3 */
+#define X_AVENRUN 4
+ { "_averunnable" }, /* 4 */
+
+/* Swap */
+#define VM_SWAPLIST 5
+ { "_swaplist" },/* list of free swap areas */
+#define VM_SWDEVT 6
+ { "_swdevt" }, /* list of swap devices and sizes */
+#define VM_NSWAP 7
+ { "_nswap" }, /* size of largest swap device */
+#define VM_NSWDEV 8
+ { "_nswdev" }, /* number of swap devices */
+#define VM_DMMAX 9
+ { "_dmmax" }, /* maximum size of a swap block */
+#define X_BUFSPACE 10
+ { "_bufspace" }, /* K in buffer cache */
+#define X_CNT 11
+ { "_cnt" }, /* struct vmmeter cnt */
+
+/* Last pid */
+#define X_LASTPID 12
+ { "_nextpid" },
+ { 0 }
+};
+
+/*
+ * These definitions control the format of the per-process area
+ */
+
+#ifdef P_IDLEPROC /* FreeBSD SMP kernel */
+
+static char header[] =
+ " PID X PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND";
+/* 0123456 -- field to fill in starts at header+6 */
+#define UNAME_START 6
+
+#define Proc_format \
+ "%5d %-16.16s%3d%3d%7s %6s %-6.6s%1x%7s %5.2f%% %5.2f%% %.6s"
+
+#else /* Standard kernel */
+
+static char header[] =
+ " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
+/* 0123456 -- field to fill in starts at header+6 */
+#define UNAME_START 6
+
+#define Proc_format \
+ "%5d %-16.16s%3d %3d%7s %6s %-6.6s%7s %5.2f%% %5.2f%% %.6s"
+
+#endif
+
+
+/* process state names for the "STATE" column of the display */
+/* the extra nulls in the string "run" are for adding a slash and
+ the processor number when needed */
+
+char *state_abbrev[] =
+{
+ "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB",
+};
+
+
+static kvm_t *kd;
+
+/* values that we stash away in _init and use in later routines */
+
+static double logcpu;
+
+/* these are retrieved from the kernel in _init */
+
+static long hz;
+static load_avg ccpu;
+
+/* these are offsets obtained via nlist and used in the get_ functions */
+
+static unsigned long cp_time_offset;
+static unsigned long avenrun_offset;
+static unsigned long lastpid_offset;
+static long lastpid;
+static unsigned long cnt_offset;
+static unsigned long bufspace_offset;
+static long cnt;
+
+/* these are for calculating cpu state percentages */
+
+static long cp_time[CPUSTATES];
+static long cp_old[CPUSTATES];
+static long cp_diff[CPUSTATES];
+
+/* these are for detailing the process states */
+
+int process_states[6];
+char *procstatenames[] = {
+ "", " starting, ", " running, ", " sleeping, ", " stopped, ",
+ " zombie, ",
+ NULL
+};
+
+/* these are for detailing the cpu states */
+
+int cpu_states[CPUSTATES];
+char *cpustatenames[] = {
+ "user", "nice", "system", "interrupt", "idle", NULL
+};
+
+/* these are for detailing the memory statistics */
+
+int memory_stats[7];
+char *memorynames[] = {
+ "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
+ NULL
+};
+
+int swap_stats[7];
+char *swapnames[] = {
+/* 0 1 2 3 4 5 */
+ "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
+ NULL
+};
+
+
+/* these are for keeping track of the proc array */
+
+static int nproc;
+static int onproc = -1;
+static int pref_len;
+static struct kinfo_proc *pbase;
+static struct kinfo_proc **pref;
+
+/* these are for getting the memory statistics */
+
+static int pageshift; /* log base 2 of the pagesize */
+
+/* define pagetok in terms of pageshift */
+
+#define pagetok(size) ((size) << pageshift)
+
+/* useful externals */
+long percentages();
+
+int
+machine_init(statics)
+
+struct statics *statics;
+
+{
+ register int i = 0;
+ register int pagesize;
+
+ if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
+ return -1;
+
+
+ /* get the list of symbols we want to access in the kernel */
+ (void) kvm_nlist(kd, nlst);
+ if (nlst[0].n_type == 0)
+ {
+ fprintf(stderr, "top: nlist failed\n");
+ return(-1);
+ }
+
+ /* make sure they were all found */
+ if (i > 0 && check_nlist(nlst) > 0)
+ {
+ return(-1);
+ }
+
+ /* get the symbol values out of kmem */
+ (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
+ if (!hz) {
+ (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
+ nlst[X_HZ].n_name);
+ }
+
+ (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
+ nlst[X_CCPU].n_name);
+
+ /* stash away certain offsets for later use */
+ cp_time_offset = nlst[X_CP_TIME].n_value;
+ avenrun_offset = nlst[X_AVENRUN].n_value;
+ lastpid_offset = nlst[X_LASTPID].n_value;
+ cnt_offset = nlst[X_CNT].n_value;
+ bufspace_offset = nlst[X_BUFSPACE].n_value;
+
+ /* this is used in calculating WCPU -- calculate it ahead of time */
+ logcpu = log(loaddouble(ccpu));
+
+ pbase = NULL;
+ pref = NULL;
+ nproc = 0;
+ onproc = -1;
+ /* get the page size with "getpagesize" and calculate pageshift from it */
+ pagesize = getpagesize();
+ pageshift = 0;
+ while (pagesize > 1)
+ {
+ pageshift++;
+ pagesize >>= 1;
+ }
+
+ /* we only need the amount of log(2)1024 for our conversion */
+ pageshift -= LOG1024;
+
+ /* fill in the statics information */
+ statics->procstate_names = procstatenames;
+ statics->cpustate_names = cpustatenames;
+ statics->memory_names = memorynames;
+ statics->swap_names = swapnames;
+
+ /* all done! */
+ return(0);
+}
+
+char *format_header(uname_field)
+
+register char *uname_field;
+
+{
+ register char *ptr;
+
+ ptr = header + UNAME_START;
+ while (*uname_field != '\0')
+ {
+ *ptr++ = *uname_field++;
+ }
+
+ return(header);
+}
+
+static int swappgsin = -1;
+static int swappgsout = -1;
+extern struct timeval timeout;
+
+void
+get_system_info(si)
+
+struct system_info *si;
+
+{
+ long total;
+ load_avg avenrun[3];
+
+ /* get the cp_time array */
+ (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
+ nlst[X_CP_TIME].n_name);
+ (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
+ nlst[X_AVENRUN].n_name);
+
+ (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
+ "!");
+
+ /* convert load averages to doubles */
+ {
+ register int i;
+ register double *infoloadp;
+ load_avg *avenrunp;
+
+#ifdef notyet
+ struct loadavg sysload;
+ int size;
+ getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
+#endif
+
+ infoloadp = si->load_avg;
+ avenrunp = avenrun;
+ for (i = 0; i < 3; i++)
+ {
+#ifdef notyet
+ *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
+#endif
+ *infoloadp++ = loaddouble(*avenrunp++);
+ }
+ }
+
+ /* convert cp_time counts to percentages */
+ total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
+
+ /* sum memory & swap statistics */
+ {
+ struct vmmeter sum;
+ static unsigned int swap_delay = 0;
+ static int swapavail = 0;
+ static int swapfree = 0;
+ static int bufspace = 0;
+
+ (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
+ "_cnt");
+ (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace),
+ "_bufspace");
+
+ /* convert memory stats to Kbytes */
+ memory_stats[0] = pagetok(sum.v_active_count);
+ memory_stats[1] = pagetok(sum.v_inactive_count);
+ memory_stats[2] = pagetok(sum.v_wire_count);
+ memory_stats[3] = pagetok(sum.v_cache_count);
+ memory_stats[4] = bufspace / 1024;
+ memory_stats[5] = pagetok(sum.v_free_count);
+ memory_stats[6] = -1;
+
+ /* first interval */
+ if (swappgsin < 0) {
+ swap_stats[4] = 0;
+ swap_stats[5] = 0;
+ }
+
+ /* compute differences between old and new swap statistic */
+ else {
+ swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin)));
+ swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout)));
+ }
+
+ swappgsin = sum.v_swappgsin;
+ swappgsout = sum.v_swappgsout;
+
+ /* call CPU heavy swapmode() only for changes */
+ if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
+ swap_stats[3] = swapmode(&swapavail, &swapfree);
+ swap_stats[0] = swapavail;
+ swap_stats[1] = swapavail - swapfree;
+ swap_stats[2] = swapfree;
+ }
+ swap_delay = 1;
+ swap_stats[6] = -1;
+ }
+
+ /* set arrays and strings */
+ si->cpustates = cpu_states;
+ si->memory = memory_stats;
+ si->swap = swap_stats;
+
+
+ if(lastpid > 0) {
+ si->last_pid = lastpid;
+ } else {
+ si->last_pid = -1;
+ }
+}
+
+static struct handle handle;
+
+caddr_t get_process_info(si, sel, compare)
+
+struct system_info *si;
+struct process_select *sel;
+int (*compare)();
+
+{
+ register int i;
+ register int total_procs;
+ register int active_procs;
+ register struct kinfo_proc **prefp;
+ register struct kinfo_proc *pp;
+
+ /* these are copied out of sel for speed */
+ int show_idle;
+ int show_system;
+ int show_uid;
+ int show_command;
+
+
+ pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
+ if (nproc > onproc)
+ pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
+ * (onproc = nproc));
+ if (pref == NULL || pbase == NULL) {
+ (void) fprintf(stderr, "top: Out of memory.\n");
+ quit(23);
+ }
+ /* get a pointer to the states summary array */
+ si->procstates = process_states;
+
+ /* set up flags which define what we are going to select */
+ show_idle = sel->idle;
+ show_system = sel->system;
+ show_uid = sel->uid != -1;
+ show_command = sel->command != NULL;
+
+ /* count up process states and get pointers to interesting procs */
+ total_procs = 0;
+ active_procs = 0;
+ memset((char *)process_states, 0, sizeof(process_states));
+ prefp = pref;
+ for (pp = pbase, i = 0; i < nproc; pp++, i++)
+ {
+ /*
+ * Place pointers to each valid proc structure in pref[].
+ * Process slots that are actually in use have a non-zero
+ * status field. Processes with P_SYSTEM set are system
+ * processes---these get ignored unless show_sysprocs is set.
+ */
+ if (PP(pp, p_stat) != 0 &&
+ (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
+ {
+ total_procs++;
+ process_states[(unsigned char) PP(pp, p_stat)]++;
+ if ((PP(pp, p_stat) != SZOMB) &&
+ (show_idle || (PP(pp, p_pctcpu) != 0) ||
+ (PP(pp, p_stat) == SRUN)) &&
+ (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
+ {
+ *prefp++ = pp;
+ active_procs++;
+ }
+ }
+ }
+
+ /* if requested, sort the "interesting" processes */
+ if (compare != NULL)
+ {
+ qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
+ }
+
+ /* remember active and total counts */
+ si->p_total = total_procs;
+ si->p_active = pref_len = active_procs;
+
+ /* pass back a handle */
+ handle.next_proc = pref;
+ handle.remaining = active_procs;
+ return((caddr_t)&handle);
+}
+
+char fmt[128]; /* static area where result is built */
+
+char *format_next_process(handle, get_userid)
+
+caddr_t handle;
+char *(*get_userid)();
+
+{
+ register struct kinfo_proc *pp;
+ register long cputime;
+ register double pct;
+ struct handle *hp;
+ char status[16];
+
+ /* find and remember the next proc structure */
+ hp = (struct handle *)handle;
+ pp = *(hp->next_proc++);
+ hp->remaining--;
+
+
+ /* get the process's user struct and set cputime */
+ if ((PP(pp, p_flag) & P_INMEM) == 0) {
+ /*
+ * Print swapped processes as <pname>
+ */
+ char *comm = PP(pp, p_comm);
+#define COMSIZ sizeof(PP(pp, p_comm))
+ char buf[COMSIZ];
+ (void) strncpy(buf, comm, COMSIZ);
+ comm[0] = '<';
+ (void) strncpy(&comm[1], buf, COMSIZ - 2);
+ comm[COMSIZ - 2] = '\0';
+ (void) strncat(comm, ">", COMSIZ - 1);
+ comm[COMSIZ - 1] = '\0';
+ }
+
+#if 0
+ /* This does not produce the correct results */
+ cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
+#endif
+ cputime = PP(pp, p_rtime).tv_sec; /* This does not count interrupts */
+
+ /* calculate the base for cpu percentages */
+ pct = pctdouble(PP(pp, p_pctcpu));
+
+ /* generate "STATE" field */
+ switch (PP(pp, p_stat)) {
+ case SRUN:
+#ifdef P_IDLEPROC /* FreeBSD SMP kernel */
+ if (PP(pp, p_oncpu) >= 0)
+ sprintf(status, "CPU%d", PP(pp, p_oncpu));
+ else
+#endif
+ strcpy(status, "RUN");
+ break;
+ case SSLEEP:
+ if (PP(pp, p_wmesg) != NULL) {
+ sprintf(status, "%.6s", EP(pp, e_wmesg));
+ break;
+ }
+ /* fall through */
+ default:
+ sprintf(status, "%.6s", state_abbrev[(unsigned char) PP(pp, p_stat)]);
+ break;
+ }
+
+ /* format this entry */
+ sprintf(fmt,
+ Proc_format,
+ PP(pp, p_pid),
+ (*get_userid)(EP(pp, e_pcred.p_ruid)),
+ PP(pp, p_priority) - PZERO,
+ PP(pp, p_nice) - NZERO,
+ format_k2(pagetok(PROCSIZE(pp))),
+ format_k2(pagetok(VP(pp, vm_rssize))),
+ status,
+#ifdef P_IDLEPROC /* FreeBSD SMP kernel */
+ PP(pp, p_lastcpu),
+#endif
+ format_time(cputime),
+ 10000.0 * weighted_cpu(pct, pp) / hz,
+ 10000.0 * pct / hz,
+ printable(PP(pp, p_comm)));
+
+ /* return the result */
+ return(fmt);
+}
+
+
+/*
+ * check_nlist(nlst) - checks the nlist to see if any symbols were not
+ * found. For every symbol that was not found, a one-line
+ * message is printed to stderr. The routine returns the
+ * number of symbols NOT found.
+ */
+
+static int check_nlist(nlst)
+
+register struct nlist *nlst;
+
+{
+ register int i;
+
+ /* check to see if we got ALL the symbols we requested */
+ /* this will write one line to stderr for every symbol not found */
+
+ i = 0;
+ while (nlst->n_name != NULL)
+ {
+ if (nlst->n_type == 0)
+ {
+ /* this one wasn't found */
+ (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
+ nlst->n_name);
+ i = 1;
+ }
+ nlst++;
+ }
+
+ return(i);
+}
+
+
+/*
+ * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
+ * "offset" is the byte offset into the kernel for the desired value,
+ * "ptr" points to a buffer into which the value is retrieved,
+ * "size" is the size of the buffer (and the object to retrieve),
+ * "refstr" is a reference string used when printing error meessages,
+ * if "refstr" starts with a '!', then a failure on read will not
+ * be fatal (this may seem like a silly way to do things, but I
+ * really didn't want the overhead of another argument).
+ *
+ */
+
+static int getkval(offset, ptr, size, refstr)
+
+unsigned long offset;
+int *ptr;
+int size;
+char *refstr;
+
+{
+ if (kvm_read(kd, offset, (char *) ptr, size) != size)
+ {
+ if (*refstr == '!')
+ {
+ return(0);
+ }
+ else
+ {
+ fprintf(stderr, "top: kvm_read for %s: %s\n",
+ refstr, strerror(errno));
+ quit(23);
+ }
+ }
+ return(1);
+}
+
+/* comparison routine for qsort */
+
+/*
+ * proc_compare - comparison function for "qsort"
+ * Compares the resource consumption of two processes using five
+ * distinct keys. The keys (in descending order of importance) are:
+ * percent cpu, cpu ticks, state, resident set size, total virtual
+ * memory usage. The process states are ordered as follows (from least
+ * to most important): WAIT, zombie, sleep, stop, start, run. The
+ * array declaration below maps a process state index into a number
+ * that reflects this ordering.
+ */
+
+static unsigned char sorted_state[] =
+{
+ 0, /* not used */
+ 3, /* sleep */
+ 1, /* ABANDONED (WAIT) */
+ 6, /* run */
+ 5, /* start */
+ 2, /* zombie */
+ 4 /* stop */
+};
+
+int
+proc_compare(pp1, pp2)
+
+struct proc **pp1;
+struct proc **pp2;
+
+{
+ register struct kinfo_proc *p1;
+ register struct kinfo_proc *p2;
+ register int result;
+ register pctcpu lresult;
+
+ /* remove one level of indirection */
+ p1 = *(struct kinfo_proc **) pp1;
+ p2 = *(struct kinfo_proc **) pp2;
+
+ /* compare percent cpu (pctcpu) */
+ if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
+ {
+ /* use cpticks to break the tie */
+ if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
+ {
+ /* use process state to break the tie */
+ if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
+ sorted_state[(unsigned char) PP(p1, p_stat)]) == 0)
+ {
+ /* use priority to break the tie */
+ if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
+ {
+ /* use resident set size (rssize) to break the tie */
+ if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
+ {
+ /* use total memory to break the tie */
+ result = PROCSIZE(p2) - PROCSIZE(p1);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ result = lresult < 0 ? -1 : 1;
+ }
+
+ return(result);
+}
+
+
+/*
+ * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
+ * the process does not exist.
+ * It is EXTREMLY IMPORTANT that this function work correctly.
+ * If top runs setuid root (as in SVR4), then this function
+ * is the only thing that stands in the way of a serious
+ * security problem. It validates requests for the "kill"
+ * and "renice" commands.
+ */
+
+int proc_owner(pid)
+
+int pid;
+
+{
+ register int cnt;
+ register struct kinfo_proc **prefp;
+ register struct kinfo_proc *pp;
+
+ prefp = pref;
+ cnt = pref_len;
+ while (--cnt >= 0)
+ {
+ pp = *prefp++;
+ if (PP(pp, p_pid) == (pid_t)pid)
+ {
+ return((int)EP(pp, e_pcred.p_ruid));
+ }
+ }
+ return(-1);
+}
+
+
+/*
+ * swapmode is based on a program called swapinfo written
+ * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+
+#define SVAR(var) __STRING(var) /* to force expansion */
+#define KGET(idx, var) \
+ KGET1(idx, &var, sizeof(var), SVAR(var))
+#define KGET1(idx, p, s, msg) \
+ KGET2(nlst[idx].n_value, p, s, msg)
+#define KGET2(addr, p, s, msg) \
+ if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
+ warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
+ return (0); \
+ }
+#define KGETRET(addr, p, s, msg) \
+ if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
+ warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
+ return (0); \
+ }
+
+
+int
+swapmode(retavail, retfree)
+ int *retavail;
+ int *retfree;
+{
+ char *header;
+ int hlen, nswap, nswdev, dmmax;
+ int i, div, avail, nfree, npfree, used;
+ struct swdevt *sw;
+ long blocksize, *perdev;
+ u_long ptr;
+ struct rlist head;
+#if __FreeBSD_version >= 220000
+ struct rlisthdr swaplist;
+#else
+ struct rlist *swaplist;
+#endif
+ struct rlist *swapptr;
+
+ /*
+ * Counter for error messages. If we reach the limit,
+ * stop reading information from swap devices and
+ * return zero. This prevent endless 'bad address'
+ * messages.
+ */
+ static warning = 10;
+
+ if (warning <= 0) {
+ /* a single warning */
+ if (!warning) {
+ warning--;
+ fprintf(stderr,
+ "Too much errors, stop reading swap devices ...\n");
+ (void)sleep(3);
+ }
+ return(0);
+ }
+ warning--; /* decrease counter, see end of function */
+
+ KGET(VM_NSWAP, nswap);
+ if (!nswap) {
+ fprintf(stderr, "No swap space available\n");
+ return(0);
+ }
+
+ KGET(VM_NSWDEV, nswdev);
+ KGET(VM_DMMAX, dmmax);
+ KGET1(VM_SWAPLIST, &swaplist, sizeof(swaplist), "swaplist");
+ if ((sw = (struct swdevt *)malloc(nswdev * sizeof(*sw))) == NULL ||
+ (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
+ err(1, "malloc");
+ KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
+ KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
+
+ /* Count up swap space. */
+ nfree = 0;
+ memset(perdev, 0, nswdev * sizeof(*perdev));
+#if __FreeBSD_version >= 220000
+ swapptr = swaplist.rlh_list;
+ while (swapptr) {
+#else
+ while (swaplist) {
+#endif
+ int top, bottom, next_block;
+#if __FreeBSD_version >= 220000
+ KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
+#else
+ KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
+#endif
+
+ top = head.rl_end;
+ bottom = head.rl_start;
+
+ nfree += top - bottom + 1;
+
+ /*
+ * Swap space is split up among the configured disks.
+ *
+ * For interleaved swap devices, the first dmmax blocks
+ * of swap space some from the first disk, the next dmmax
+ * blocks from the next, and so on up to nswap blocks.
+ *
+ * The list of free space joins adjacent free blocks,
+ * ignoring device boundries. If we want to keep track
+ * of this information per device, we'll just have to
+ * extract it ourselves.
+ */
+ while (top / dmmax != bottom / dmmax) {
+ next_block = ((bottom + dmmax) / dmmax);
+ perdev[(bottom / dmmax) % nswdev] +=
+ next_block * dmmax - bottom;
+ bottom = next_block * dmmax;
+ }
+ perdev[(bottom / dmmax) % nswdev] +=
+ top - bottom + 1;
+
+#if __FreeBSD_version >= 220000
+ swapptr = head.rl_next;
+#else
+ swaplist = head.rl_next;
+#endif
+ }
+
+ header = getbsize(&hlen, &blocksize);
+ div = blocksize / 512;
+ avail = npfree = 0;
+ for (i = 0; i < nswdev; i++) {
+ int xsize, xfree;
+
+ /*
+ * Don't report statistics for partitions which have not
+ * yet been activated via swapon(8).
+ */
+
+ xsize = sw[i].sw_nblks;
+ xfree = perdev[i];
+ used = xsize - xfree;
+ npfree++;
+ avail += xsize;
+ }
+
+ /*
+ * If only one partition has been set up via swapon(8), we don't
+ * need to bother with totals.
+ */
+ *retavail = avail / 2;
+ *retfree = nfree / 2;
+ used = avail - nfree;
+ free(sw); free(perdev);
+
+ /* increase counter, no errors occurs */
+ warning++;
+
+ return (int)(((double)used / (double)avail * 100.0) + 0.5);
+}
diff --git a/usr.bin/top/sigdesc.h b/usr.bin/top/sigdesc.h
new file mode 100644
index 0000000..75bc9d7
--- /dev/null
+++ b/usr.bin/top/sigdesc.h
@@ -0,0 +1,42 @@
+/* This file was automatically generated */
+/* by the awk script "sigconv.awk". */
+
+struct sigdesc {
+ char *name;
+ int number;
+};
+
+struct sigdesc sigdesc[] = {
+ "HUP", 1,
+ "INT", 2,
+ "QUIT", 3,
+ "ILL", 4,
+ "TRAP", 5,
+ "ABRT", 6,
+ "EMT", 7,
+ "FPE", 8,
+ "KILL", 9,
+ "BUS", 10,
+ "SEGV", 11,
+ "SYS", 12,
+ "PIPE", 13,
+ "ALRM", 14,
+ "TERM", 15,
+ "URG", 16,
+ "STOP", 17,
+ "TSTP", 18,
+ "CONT", 19,
+ "CHLD", 20,
+ "TTIN", 21,
+ "TTOU", 22,
+ "IO", 23,
+ "XCPU", 24,
+ "XFSZ", 25,
+ "VTALRM", 26,
+ "PROF", 27,
+ "WINCH", 28,
+ "INFO", 29,
+ "USR1", 30,
+ "USR2", 31,
+ NULL, 0
+};
diff --git a/usr.bin/top/top.local.1 b/usr.bin/top/top.local.1
new file mode 100644
index 0000000..6f3ae17
--- /dev/null
+++ b/usr.bin/top/top.local.1
@@ -0,0 +1,47 @@
+.SH "FreeBSD 2.x NOTES"
+
+.SH DESCRIPTION OF MEMORY
+Mem: 9220K Active, 1032K Inact, 3284K Wired, 1MB Cache, 2M Buf, 1320K Free
+Swap: 91M Total, 79M Free, 13% Inuse, 80K In, 104 K Out
+
+.B K:
+Kilobyte
+.TP
+.B M:
+Megabyte
+.TP
+.B %:
+1/100
+.TP
+.B Active:
+number of pages active
+.TP
+.B Inact:
+number of pages inactive
+.TP
+.B Wired:
+number of pages wired down, including cached file data pages
+.TP
+.B Cache:
+number of pages used for VM-level disk caching
+.TP
+.B Buf:
+number of pages used for BIO-level disk caching
+.TP
+.B Free:
+number of pages free
+.TP
+.B Total:
+total available swap usage
+.TP
+.B Free:
+total free swap usage
+.TP
+.B Inuse:
+swap usage
+.TP
+.B In:
+pages paged in from swap devices (last interval)
+.TP
+.B Out:
+pages paged out to swap devices (last interval)
diff --git a/usr.bin/top/top.local.h b/usr.bin/top/top.local.h
new file mode 100644
index 0000000..202f6a1
--- /dev/null
+++ b/usr.bin/top/top.local.h
@@ -0,0 +1,68 @@
+/*
+ * Top - a top users display for Berkeley Unix
+ *
+ * Definitions for things that might vary between installations.
+ */
+
+/*
+ * The space command forces an immediate update. Sometimes, on loaded
+ * systems, this update will take a significant period of time (because all
+ * the output is buffered). So, if the short-term load average is above
+ * "LoadMax", then top will put the cursor home immediately after the space
+ * is pressed before the next update is attempted. This serves as a visual
+ * acknowledgement of the command. On Suns, "LoadMax" will get multiplied by
+ * "FSCALE" before being compared to avenrun[0]. Therefore, "LoadMax"
+ * should always be specified as a floating point number.
+ */
+#ifndef LoadMax
+#define LoadMax 5.0
+#endif
+
+/*
+ * "Table_size" defines the size of the hash tables used to map uid to
+ * username. The number of users in /etc/passwd CANNOT be greater than
+ * this number. If the error message "table overflow: too many users"
+ * is printed by top, then "Table_size" needs to be increased. Things will
+ * work best if the number is a prime number that is about twice the number
+ * of lines in /etc/passwd.
+ */
+#ifndef Table_size
+#define Table_size 20011
+#endif
+
+/*
+ * "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity
+ * and the output is a dumb terminal. If we didn't do this, then
+ * installations who use a default TOPN of Infinity will get every
+ * process in the system when running top on a dumb terminal (or redirected
+ * to a file). Note that Nominal_TOPN is a default: it can still be
+ * overridden on the command line, even with the value "infinity".
+ */
+#ifndef Nominal_TOPN
+#define Nominal_TOPN 18
+#endif
+
+#ifndef Default_TOPN
+#define Default_TOPN -1
+#endif
+
+#ifndef Default_DELAY
+#define Default_DELAY 2
+#endif
+
+/*
+ * If the local system's getpwnam interface uses random access to retrieve
+ * a record (i.e.: 4.3 systems, Sun "yellow pages"), then defining
+ * RANDOM_PW will take advantage of that fact. If RANDOM_PW is defined,
+ * then getpwnam is used and the result is cached. If not, then getpwent
+ * is used to read and cache the password entries sequentially until the
+ * desired one is found.
+ *
+ * We initially set RANDOM_PW to something which is controllable by the
+ * Configure script. Then if its value is 0, we undef it.
+ */
+
+#define RANDOM_PW 1
+#if RANDOM_PW == 0
+#undef RANDOM_PW
+#endif
diff --git a/usr.bin/touch/touch.1 b/usr.bin/touch/touch.1
index c620931..38b9ebc 100644
--- a/usr.bin/touch/touch.1
+++ b/usr.bin/touch/touch.1
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)touch.1 8.3 (Berkeley) 4/28/95
+.\" @(#)touch.1 8.2 (Berkeley) 12/30/93
.\"
-.Dd April 28, 1995
+.Dd December 30, 1993
.Dt TOUCH 1
.Os
.Sh NAME
@@ -44,7 +44,7 @@
.Nm touch
.Op Fl acfm
.Op Fl r Ar file
-.Op Fl t Ar [[CC]YY]MMDDhhmm[.SS]
+.Op Fl t [[CC]YY]MMDDhhmm[.SS]
.Ar file ...
.Sh DESCRIPTION
The
@@ -95,10 +95,10 @@ is specified, but
is not, a value for
.Dq YY
between 69 and 99 results in a
-.Dq YY
+.Dq CC
value of 19.
Otherwise, a
-.Dq YY
+.Dq CC
value of 20 is used.
.It Ar MM
The month of the year, from 1 to 12.
diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c
index afaa537..32a7319 100644
--- a/usr.bin/touch/touch.c
+++ b/usr.bin/touch/touch.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)touch.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/types.h>
@@ -74,7 +74,7 @@ main(argc, argv)
if (gettimeofday(&tv[0], NULL))
err(1, "gettimeofday");
- while ((ch = getopt(argc, argv, "acfmr:t:")) != EOF)
+ while ((ch = getopt(argc, argv, "acfmr:t:")) != -1)
switch(ch) {
case 'a':
aflag = 1;
@@ -199,7 +199,7 @@ stime_arg1(arg, tvp)
*p++ = '\0';
t->tm_sec = ATOI2(p);
}
-
+
yearset = 0;
switch(strlen(arg)) {
case 12: /* CCYYMMDDhhmm */
@@ -333,7 +333,7 @@ err: rval = 1;
return (rval);
}
-__dead void
+void
usage()
{
(void)fprintf(stderr,
diff --git a/usr.bin/tput/Makefile b/usr.bin/tput/Makefile
index abec983..441305c 100644
--- a/usr.bin/tput/Makefile
+++ b/usr.bin/tput/Makefile
@@ -6,7 +6,7 @@ LDADD= -ltermcap
MLINKS= tput.1 clear.1
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/clear.sh ${DESTDIR}/usr/bin/clear
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/clear.sh ${DESTDIR}${BINDIR}/clear
.include <bsd.prog.mk>
diff --git a/usr.bin/tput/tput.1 b/usr.bin/tput/tput.1
index 9a348431..403f4cc 100644
--- a/usr.bin/tput/tput.1
+++ b/usr.bin/tput/tput.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)tput.1 8.2 (Berkeley) 3/19/94
+.\" $Id$
.\"
.Dd March 19, 1994
.Dt TPUT 1
@@ -38,32 +39,37 @@
.Nm tput
.Nd terminal capability interface
.Sh SYNOPSIS
-.Nm tput
+.Nm
.Op Fl T Ar term
.Ar attribute
.Sh DESCRIPTION
-.Nm Tput
-makes terminal-dependent information available to users or shell
+The
+.Nm
+command makes terminal-dependent information available to users or shell
applications.
The options are as follows:
.Bl -tag -width Ds
.It Fl T
The terminal name as specified in the
.Xr termcap
-database, for example, ``vt100'' or ``xterm''.
+database, for example,
+.Dq vt100
+or
+.Dq xterm .
If not specified,
-.Nm tput
+.Nm
retrieves the
.Dq Ev TERM
variable from the environment.
.El
.Pp
-.Nm Tput
-outputs a string if the
+The
+.Nm
+command outputs a string if the
.Ar attribute
is of type string; a number if it is of type integer.
Otherwise,
-.Nm tput
+.Nm
exits 0 if the terminal has the capability and 1 if it does not,
without further action.
.Pp
@@ -80,38 +86,51 @@ The following special attributes are available:
.It clear
Clear the screen (the
.Xr termcap
-``cl'' sequence).
+.Dq cl
+sequence).
.It init
Initialize the terminal (the
.Xr termcap
-``is'' sequence).
+.Dq is
+sequence).
.It longname
Print the descriptive name of the user's terminal type.
.It reset
Reset the terminal (the
.Xr termcap
-``rs'' sequence).
+.Dq rs
+sequence).
.Sh DIAGNOSTICS
The exit value of
-.Nm tput
+.Nm
is based on the last attribute specified.
If the attribute is of type string or of type integer,
-.Nm tput
+.Nm
exits 0 if the attribute is defined for this terminal type and 1
if it is not.
If the attribute is of type boolean,
-.Nm tput
+.Nm
exits 0 if the terminal has this attribute, and 1 if it does not.
-.Nm Tput
-exits 2 if any error occurred.
+The
+.Nm
+command exits 2 if any error occurred.
.Sh SEE ALSO
.Xr termcap 3 ,
.Xr termcap 5
.Sh BUGS
-.Nm Tput
-can't really distinguish between different types of attributes.
+The
+.Nm
+command can't really distinguish between different types of attributes.
+.Pp
+Some termcap entries depend upon having a
+.Sq %
+in them that is just a
+.Sq %
+and nothing more. Right now we just warn about them if they don't
+have a valid type declaration. These warnings are sent to
+stderr.
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/tput/tput.c b/usr.bin/tput/tput.c
index f587492..2eb3e46 100644
--- a/usr.bin/tput/tput.c
+++ b/usr.bin/tput/tput.c
@@ -38,20 +38,21 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)tput.c 8.3 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)tput.c 8.2 (Berkeley) 3/19/94";
#endif /* not lint */
-#include <sys/termios.h>
+#include <termios.h>
#include <err.h>
-#include <curses.h>
+#include <termcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#undef putchar
+#define outc putchar
+
static void prlongname __P((char *));
-static void setospeed __P((void));
-static void outc __P((int));
static void usage __P((void));
static char **process __P((char *, char *, char **));
@@ -66,7 +67,7 @@ main(argc, argv)
char *cptr, *p, *term, buf[1024], tbuf[1024];
term = NULL;
- while ((ch = getopt(argc, argv, "T:")) != EOF)
+ while ((ch = getopt(argc, argv, "T:")) != -1)
switch(ch) {
case 'T':
term = optarg;
@@ -82,7 +83,6 @@ main(argc, argv)
errx(2, "no terminal type specified and no TERM environmental variable.");
if (tgetent(tbuf, term) != 1)
err(2, "tgetent failure");
- setospeed();
for (exitval = 0; (p = *argv) != NULL; ++argv) {
switch (*p) {
case 'c':
@@ -94,9 +94,11 @@ errx(2, "no terminal type specified and no TERM environmental variable.");
p = "is";
break;
case 'l':
- if (!strcmp(p, "longname"))
+ if (!strcmp(p, "longname")) {
prlongname(tbuf);
- continue;
+ continue;
+ }
+ break;
case 'r':
if (!strcmp(p, "reset"))
p = "rs";
@@ -163,7 +165,7 @@ process(cap, str, argv)
/*
* hpux has lot's of them, but we complain
*/
- errx(2, erresc, *cp, cap);
+ warnx(erresc, *cp, cap);
}
/* And print them. */
@@ -183,11 +185,11 @@ process(cap, str, argv)
case 2:
if (*++argv == NULL || *argv[0] == '\0')
errx(2, errfew, 2, cap);
- arg_rows = atoi(*argv);
+ arg_cols = atoi(*argv);
if (*++argv == NULL || *argv[0] == '\0')
errx(2, errfew, 2, cap);
- arg_cols = atoi(*argv);
+ arg_rows = atoi(*argv);
(void) tputs(tgoto(str, arg_cols, arg_rows), arg_rows, outc);
break;
@@ -199,26 +201,6 @@ process(cap, str, argv)
}
static void
-setospeed()
-{
-#undef ospeed
- extern short ospeed;
- struct termios t;
-
- if (tcgetattr(STDOUT_FILENO, &t) != -1)
- ospeed = 0;
- else
- ospeed = cfgetospeed(&t);
-}
-
-static void
-outc(c)
- int c;
-{
- (void)putchar(c);
-}
-
-static void
usage()
{
(void)fprintf(stderr, "usage: tput [-T term] attribute ...\n");
diff --git a/usr.bin/tr/str.c b/usr.bin/tr/str.c
index 367e1b1..7c0fd7c 100644
--- a/usr.bin/tr/str.c
+++ b/usr.bin/tr/str.c
@@ -43,6 +43,7 @@ static char sccsid[] = "@(#)str.c 8.2 (Berkeley) 4/28/95";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "extern.h"
@@ -66,7 +67,7 @@ next(s)
case INFINITE:
return (1);
case NORMAL:
- switch (ch = *s->str) {
+ switch (ch = (u_char)*s->str) {
case '\0':
s->state = EOS;
return (0);
@@ -143,19 +144,6 @@ bracket(s)
/* NOTREACHED */
}
-int isalnum __P((int)),
- isalpha __P((int)),
- isblank __P((int)),
- isspace __P((int)),
- iscntrl __P((int)),
- isdigit __P((int)),
- isgraph __P((int)),
- islower __P((int)),
- isprint __P((int)),
- ispunct __P((int)),
- isupper __P((int)),
- isxdigit __P((int));
-
typedef struct {
char *name;
int (*func) __P((int));
@@ -163,17 +151,29 @@ typedef struct {
} CLASS;
static CLASS classes[] = {
+#undef isalnum
{ "alnum", isalnum, },
+#undef isalpha
{ "alpha", isalpha, },
+#undef isblank
{ "blank", isblank, },
+#undef iscntrl
{ "cntrl", iscntrl, },
+#undef isdigit
{ "digit", isdigit, },
+#undef isgraph
{ "graph", isgraph, },
+#undef islower
{ "lower", islower, },
- { "print", isupper, },
+#undef isprint
+ { "print", isprint, },
+#undef ispunct
{ "punct", ispunct, },
+#undef isspace
{ "space", isspace, },
+#undef isupper
{ "upper", isupper, },
+#undef isxdigit
{ "xdigit", isxdigit, },
};
@@ -241,7 +241,7 @@ genrange(s)
char *savestart;
savestart = s->str;
- stopval = *++s->str == '\\' ? backslash(s) : *s->str++;
+ stopval = *++s->str == '\\' ? backslash(s) : (u_char)*s->str++;
if (stopval < (u_char)s->lastch) {
s->str = savestart;
return (0);
@@ -277,7 +277,7 @@ genseq(s)
++s->str;
break;
default:
- if (isdigit(*s->str)) {
+ if (isdigit((u_char)*s->str)) {
s->cnt = strtol(s->str, &ep, 0);
if (*ep == ']') {
s->str = ep + 1;
@@ -291,9 +291,6 @@ genseq(s)
s->state = s->cnt ? SEQUENCE : INFINITE;
}
-/* Use the #defines isXXX() here, DON'T use them above. */
-#include <ctype.h>
-
/*
* Translate \??? into a character. Up to 3 octal digits, if no digits either
* an escape code or a literal character.
@@ -305,7 +302,7 @@ backslash(s)
register int ch, cnt, val;
for (cnt = val = 0;;) {
- ch = *++s->str;
+ ch = (u_char)*++s->str;
if (!isascii(ch) || !isdigit(ch))
break;
val = val * 8 + ch - '0';
diff --git a/usr.bin/tr/tr.c b/usr.bin/tr/tr.c
index c34e51d..50b9d7c 100644
--- a/usr.bin/tr/tr.c
+++ b/usr.bin/tr/tr.c
@@ -41,6 +41,7 @@ static char copyright[] =
static char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
+#include <locale.h>
#include <sys/types.h>
#include <stdio.h>
@@ -99,8 +100,10 @@ main(argc, argv)
register int ch, cnt, lastch, *p;
int cflag, dflag, sflag, isstring2;
+ (void) setlocale(LC_CTYPE, "");
+
cflag = dflag = sflag = 0;
- while ((ch = getopt(argc, argv, "cds")) != EOF)
+ while ((ch = getopt(argc, argv, "cds")) != -1)
switch((char)ch) {
case 'c':
cflag = 1;
@@ -142,7 +145,7 @@ main(argc, argv)
setup(string1, argv[0], &s1, cflag);
setup(string2, argv[1], &s2, 0);
-
+
for (lastch = OOBCH; (ch = getchar()) != EOF;)
if (!string1[ch] && (!string2[ch] || lastch != ch)) {
lastch = ch;
diff --git a/usr.bin/true/true.1 b/usr.bin/true/true.1
index fc15a4e..cbdb103 100644
--- a/usr.bin/true/true.1
+++ b/usr.bin/true/true.1
@@ -50,8 +50,8 @@ tests for the appropriate status "false" before running
(or failing to run) a list of commands.
.Sh SEE ALSO
.Xr csh 1 ,
-.Xr sh 1 ,
-.Xr false 1
+.Xr false 1 ,
+.Xr sh 1
.Sh DIAGNOSTICS
The
.Nm true
diff --git a/usr.bin/tset/extern.h b/usr.bin/tset/extern.h
index 0465a66..29acfac 100644
--- a/usr.bin/tset/extern.h
+++ b/usr.bin/tset/extern.h
@@ -33,15 +33,7 @@
* @(#)extern.h 8.1 (Berkeley) 6/9/93
*/
-/* This should be in <termcap.h> instead. */
-extern char PC;
-extern short ospeed;
-int tgetent __P((char *, char *));
-int tgetflag __P((char *));
-int tgetnum __P((char *));
-char *tgetstr __P((char *, char **));
-char *tgoto __P((char *, int, int));
-int tputs __P((char *, int, void (*) __P((int))));
+#include <termcap.h>
extern struct termios mode, oldmode;
extern int columns, isreset, lines;
@@ -52,7 +44,7 @@ void cat __P((char *));
void err __P((const char *, ...));
char *get_termcap_entry __P((char *, char **));
char *mapped __P((char *));
-void outc __P((int));
+int outc __P((int));
void reset_mode __P((void));
void set_control_chars __P((void));
void set_conversions __P((int));
diff --git a/usr.bin/tset/map.c b/usr.bin/tset/map.c
index 56cb725..2e71d2c 100644
--- a/usr.bin/tset/map.c
+++ b/usr.bin/tset/map.c
@@ -42,7 +42,8 @@ static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/9/93";
#include <string.h>
#include "extern.h"
-int baudrate __P((char *));
+extern speed_t Ospeed;
+speed_t baudrate __P((char *));
/* Baud rate conditionals for mapping. */
#define GT 0x01
@@ -57,7 +58,7 @@ typedef struct map {
char *porttype; /* Port type, or "" for any. */
char *type; /* Terminal type to select. */
int conditional; /* Baud rate conditionals bitmask. */
- int speed; /* Baud rate to compare against. */
+ speed_t speed; /* Baud rate to compare against. */
} MAP;
MAP *cur, *maplist;
@@ -195,19 +196,19 @@ mapped(type)
match = 1;
break;
case EQ:
- match = (ospeed == mapp->speed);
+ match = (Ospeed == mapp->speed);
break;
case GE:
- match = (ospeed >= mapp->speed);
+ match = (Ospeed >= mapp->speed);
break;
case GT:
- match = (ospeed > mapp->speed);
+ match = (Ospeed > mapp->speed);
break;
case LE:
- match = (ospeed <= mapp->speed);
+ match = (Ospeed <= mapp->speed);
break;
case LT:
- match = (ospeed < mapp->speed);
+ match = (Ospeed < mapp->speed);
break;
}
if (match)
@@ -219,37 +220,23 @@ mapped(type)
typedef struct speeds {
char *string;
- int speed;
+ speed_t speed;
} SPEEDS;
SPEEDS speeds[] = {
"0", B0,
- "50", B50,
- "75", B75,
- "110", B110,
- "134", B134,
"134.5", B134,
- "150", B150,
- "200", B200,
- "300", B300,
- "600", B600,
- "1200", B1200,
- "1800", B1800,
- "2400", B2400,
- "4800", B4800,
- "9600", B9600,
- "19200", B19200,
- "38400", B38400,
"exta", B19200,
"extb", B38400,
NULL
};
-int
+speed_t
baudrate(rate)
char *rate;
{
SPEEDS *sp;
+ speed_t speed;
/* The baudrate number can be preceded by a 'B', which is ignored. */
if (*rate == 'B')
@@ -258,6 +245,8 @@ baudrate(rate)
for (sp = speeds; sp->string; ++sp)
if (!strcasecmp(rate, sp->string))
return (sp->speed);
- err("unknown baud rate %s", rate);
- /* NOTREACHED */
+ speed = atol(rate);
+ if (speed == 0)
+ err("unknown baud rate %s", rate);
+ return speed;
}
diff --git a/usr.bin/tset/misc.c b/usr.bin/tset/misc.c
index c96c48c..27a2bf6 100644
--- a/usr.bin/tset/misc.c
+++ b/usr.bin/tset/misc.c
@@ -61,11 +61,11 @@ cat(file)
(void)close(fd);
}
-void
+int
outc(c)
int c;
{
- (void)putc(c, stderr);
+ return putc(c, stderr);
}
#if __STDC__
diff --git a/usr.bin/tset/set.c b/usr.bin/tset/set.c
index b279a1c..e55ebbd 100644
--- a/usr.bin/tset/set.c
+++ b/usr.bin/tset/set.c
@@ -165,10 +165,8 @@ set_control_chars()
else
bs_char = 0;
- if (erasechar == 0 && !tgetflag("os") && mode.c_cc[VERASE] != CERASE) {
- if (tgetflag("bs") || bs_char != 0)
- erasechar = -1;
- }
+ if (erasechar == 0 && bs_char != 0 && !tgetflag("os"))
+ erasechar = -1;
if (erasechar < 0)
erasechar = (bs_char != 0) ? bs_char : CTRL('h');
diff --git a/usr.bin/tset/tset.c b/usr.bin/tset/tset.c
index 7198e96..b25398b 100644
--- a/usr.bin/tset/tset.c
+++ b/usr.bin/tset/tset.c
@@ -63,6 +63,7 @@ int intrchar; /* new interrupt character */
int isreset; /* invoked as reset */
int killchar; /* new kill character */
int lines, columns; /* window size */
+speed_t Ospeed;
int
main(argc, argv)
@@ -79,7 +80,7 @@ main(argc, argv)
err("standard error: %s", strerror(errno));
oldmode = mode;
- ospeed = cfgetospeed(&mode);
+ Ospeed = cfgetospeed(&mode);
if (p = strrchr(*argv, '/'))
++p;
@@ -93,7 +94,7 @@ main(argc, argv)
obsolete(argv);
noinit = noset = quiet = Sflag = sflag = showterm = 0;
- while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != EOF) {
+ while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != -1) {
switch (ch) {
case '-': /* display term only */
noset = 1;
@@ -180,19 +181,6 @@ main(argc, argv)
tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
}
- /* Get the terminal name from the entry. */
- p = tcapbuf;
- if (p != NULL && *p != ':') {
- t = p;
- if (p = strpbrk(p, "|:")) {
- savech = *p;
- *p = '\0';
- if ((ttype = strdup(t)) == NULL)
- err("%s", strerror(errno));
- *p = savech;
- }
- }
-
if (noset)
(void)printf("%s\n", ttype);
else {
@@ -245,7 +233,6 @@ report(name, which, def)
u_int def;
{
u_int old, new;
- char *bp, buf[1024];
new = mode.c_cc[which];
old = oldmode.c_cc[which];
@@ -255,8 +242,7 @@ report(name, which, def)
(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
- bp = buf;
- if (tgetstr("kb", &bp) && new == buf[0] && buf[1] == '\0')
+ if (new == 010)
(void)fprintf(stderr, "backspace.\n");
else if (new == 0177)
(void)fprintf(stderr, "delete.\n");
diff --git a/usr.bin/tsort/tsort.1 b/usr.bin/tsort/tsort.1
index f3eb74b..3b57da5b 100644
--- a/usr.bin/tsort/tsort.1
+++ b/usr.bin/tsort/tsort.1
@@ -42,7 +42,9 @@
.Nd topological sort of a directed graph
.Sh SYNOPSIS
.Nm tsort
+.Op Fl d
.Op Fl l
+.Op Fl q
.Op Ar file
.Sh DESCRIPTION
.Nm Tsort
@@ -66,9 +68,15 @@ Cycles are reported on standard error.
.Pp
The options are as follows:
.Bl -tag -width Ds
+.It Fl d
+Turn on debugging.
.It Fl l
Search for and display the longest cycle.
Can take a very long time.
+.It Fl q
+Do not display informational messages about cycles. This is primarily
+intended for building libraries, where optimal ordering is not critical,
+and cycles occur often.
.El
.Sh SEE ALSO
.Xr ar 1
diff --git a/usr.bin/tsort/tsort.c b/usr.bin/tsort/tsort.c
index efcb910..591ad16 100644
--- a/usr.bin/tsort/tsort.c
+++ b/usr.bin/tsort/tsort.c
@@ -32,6 +32,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: tsort.c,v 1.7 1997/03/11 14:48:14 peter Exp $
*/
#ifndef lint
@@ -62,7 +64,7 @@ static char sccsid[] = "@(#)tsort.c 8.3 (Berkeley) 5/4/95";
* standard output in sorted order, one per line.
*
* usage:
- * tsort [-l] [inputfile]
+ * tsort [-dlq] [inputfile]
* If no input file is specified, standard input is read.
*
* Should be compatable with AT&T tsort HOWEVER the output is not identical
@@ -99,7 +101,7 @@ typedef struct _buf {
DB *db;
NODE *graph, **cycle_buf, **longest_cycle;
-int debug, longest;
+int debug, longest, quiet;
void add_arc __P((char *, char *));
int find_cycle __P((NODE *, NODE *, int, int));
@@ -120,7 +122,7 @@ main(argc, argv)
int bsize, ch, nused;
BUF bufs[2];
- while ((ch = getopt(argc, argv, "dl")) != EOF)
+ while ((ch = getopt(argc, argv, "dlq")) != -1)
switch (ch) {
case 'd':
debug = 1;
@@ -128,6 +130,9 @@ main(argc, argv)
case 'l':
longest = 1;
break;
+ case 'q':
+ quiet = 1;
+ break;
case '?':
default:
usage();
@@ -336,11 +341,13 @@ tsort()
}
for (n = graph; n != NULL; n = n->n_next)
if (!(n->n_flags & NF_ACYCLIC))
- if (cnt = find_cycle(n, n, 0, 0)) {
- warnx("cycle in data");
- for (i = 0; i < cnt; i++)
- warnx("%s",
- longest_cycle[i]->n_name);
+ if ((cnt = find_cycle(n, n, 0, 0))) {
+ if (!quiet) {
+ warnx("cycle in data");
+ for (i = 0; i < cnt; i++)
+ warnx("%s",
+ longest_cycle[i]->n_name);
+ }
remove_node(n);
clear_cycle();
break;
@@ -425,6 +432,6 @@ find_cycle(from, to, longest_len, depth)
void
usage()
{
- (void)fprintf(stderr, "usage: tsort [-l] [file]\n");
+ (void)fprintf(stderr, "usage: tsort [-dlq] [file]\n");
exit(1);
}
diff --git a/usr.bin/tty/tty.1 b/usr.bin/tty/tty.1
index 9607c11..9c47b70 100644
--- a/usr.bin/tty/tty.1
+++ b/usr.bin/tty/tty.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)tty.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt TTY 1
@@ -76,3 +77,8 @@ The
function is expected to be
.St -p1003.2
compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/tty/tty.c b/usr.bin/tty/tty.c
index d07cab7..88cd60a 100644
--- a/usr.bin/tty/tty.c
+++ b/usr.bin/tty/tty.c
@@ -51,7 +51,7 @@ main(argc, argv)
char *t, *ttyname();
sflag = 0;
- while ((ch = getopt(argc, argv, "s")) != EOF)
+ while ((ch = getopt(argc, argv, "s")) != -1)
switch((char)ch) {
case 's':
sflag = 1;
diff --git a/usr.bin/ul/ul.1 b/usr.bin/ul/ul.1
index 701797a..953dd17 100644
--- a/usr.bin/ul/ul.1
+++ b/usr.bin/ul/ul.1
@@ -89,15 +89,16 @@ specified in
or as set during the login process by the user in their
.Pa login
file (see
-.Xr setenv 1 ) .
+.Xr environ 7 ) .
.El
.Sh SEE ALSO
+.Xr colcrt 1 ,
.Xr man 1 ,
-.Xr nroff 1 ,
-.Xr colcrt 1
+.Xr nroff 1
.Sh BUGS
-.Xr Nroff
-usually outputs a series of backspaces and underlines intermixed
+The
+.Xr nroff 1
+command usually outputs a series of backspaces and underlines intermixed
with the text to indicate underlining. No attempt is made to optimize
the backward motion.
.Sh HISTORY
diff --git a/usr.bin/ul/ul.c b/usr.bin/ul/ul.c
index 75e6f95..cf9f9ef 100644
--- a/usr.bin/ul/ul.c
+++ b/usr.bin/ul/ul.c
@@ -93,7 +93,7 @@ main(argc, argv)
termtype = getenv("TERM");
if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
termtype = "lpr";
- while ((c=getopt(argc, argv, "it:T:")) != EOF)
+ while ((c=getopt(argc, argv, "it:T:")) != -1)
switch(c) {
case 't':
@@ -424,7 +424,7 @@ initcap()
ENTER_REVERSE = ENTER_STANDOUT;
if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
EXIT_ATTRIBUTES = EXIT_STANDOUT;
-
+
/*
* Note that we use REVERSE for the alternate character set,
* not the as/ae capabilities. This is because we are modelling
diff --git a/usr.bin/uname/uname.1 b/usr.bin/uname/uname.1
index 50e0c52..c4d4b4b 100644
--- a/usr.bin/uname/uname.1
+++ b/usr.bin/uname/uname.1
@@ -31,7 +31,7 @@
.\"
.\" @(#)uname.1 8.3 (Berkeley) 4/8/94
.\"
-.Dd "April 8, 1994"
+.Dd April 8, 1994
.Dt UNAME 1
.Os
.Sh NAME
@@ -82,13 +82,14 @@ The
.Nm uname
utility exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
-.Xr sysctl 8 ,
.Xr sysctl 3 ,
-.Xr uname 3
+.Xr uname 3 ,
+.Xr sysctl 8
.Sh HISTORY
The
.Nm uname
-command appeared in 4.4BSD.
+command appeared in
+.Bx 4.4 .
.Sh STANDARDS
The
.Nm uname
diff --git a/usr.bin/uname/uname.c b/usr.bin/uname/uname.c
index 86b5dce..1245560 100644
--- a/usr.bin/uname/uname.c
+++ b/usr.bin/uname/uname.c
@@ -67,7 +67,7 @@ main(argc, argv)
char *p, *prefix, buf[1024];
flags = 0;
- while ((ch = getopt(argc, argv, "amnrsv")) != EOF)
+ while ((ch = getopt(argc, argv, "amnrsv")) != -1)
switch(ch) {
case 'a':
flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG);
diff --git a/usr.bin/uniq/uniq.c b/usr.bin/uniq/uniq.c
index b2b85e1..25350d7 100644
--- a/usr.bin/uniq/uniq.c
+++ b/usr.bin/uniq/uniq.c
@@ -74,7 +74,7 @@ main (argc, argv)
char *prevline, *thisline, *p;
obsolete(argv);
- while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF)
+ while ((ch = getopt(argc, argv, "-cdf:s:u")) != -1)
switch (ch) {
case '-':
--optind;
diff --git a/usr.bin/units/Makefile b/usr.bin/units/Makefile
new file mode 100644
index 0000000..b414356
--- /dev/null
+++ b/usr.bin/units/Makefile
@@ -0,0 +1,9 @@
+# $Id$
+
+PROG= units
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/units.lib ${DESTDIR}/usr/share/misc
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/units/README b/usr.bin/units/README
new file mode 100644
index 0000000..b7a173a
--- /dev/null
+++ b/usr.bin/units/README
@@ -0,0 +1,18 @@
+# $Id$
+
+This is a program which I wrote as a clone of the UNIX 'units'
+command. I threw it together in a couple days, but it seems to work,
+with some restrictions. I have tested it under DOS with Borland C and
+Ultrix 4.2, and SunOS 4.1.
+
+This program differs from the unix units program in the following
+ways:
+ it can gracefully handle exponents larger than 9 in output
+ it uses 'e' to denote exponentiation in numbers
+ prefixes are listed in the units file
+ it tries both -s and -es plurals
+ it allows use of * for multiply and ^ for exponentiation in the input
+ the output format is somewhat different
+
+Adrian Mariano (adrian@cam.cornell.edu or mariano@geom.umn.edu)
+
diff --git a/usr.bin/units/pathnames.h b/usr.bin/units/pathnames.h
new file mode 100644
index 0000000..f41f207
--- /dev/null
+++ b/usr.bin/units/pathnames.h
@@ -0,0 +1,33 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _PATH_UNITSLIB "/usr/share/misc/units.lib"
diff --git a/usr.bin/units/units.1 b/usr.bin/units/units.1
new file mode 100644
index 0000000..4ca4aca
--- /dev/null
+++ b/usr.bin/units/units.1
@@ -0,0 +1,158 @@
+.\" $Id: units.1,v 1.4 1997/02/22 19:57:31 peter Exp $
+.TH UNITS 1 "14 July 1993"
+.SH NAME
+units - conversion program
+.SH SYNTAX
+.B units
+[-f filename] [-q] [to-unit from-unit]
+.SH SUMMARY
+.TP 4
+.B -f filename
+Specifies the name of the units data file to load.
+.LP
+.TP 4
+.B -q
+Suppresses prompting of the user for units and the display of statistics
+about the number of units loaded.
+.LP
+.TP 4
+.B from-unit to-unit
+Allows a single unit conversion to be done directly from the command
+line. The program will not print prompts. It will print out the
+result of the single specified conversion.
+
+
+.SH DESCRIPTION
+The units program converts quantities expressed in various scales to
+their equivalents in other scales. The units program can only
+handle multiplicative scale changes. It cannot convert Centigrade
+to Fahrenheit, for example. It works interactively by prompting
+the user for input:
+.nf
+
+ You have: meters
+ You want: feet
+ * 3.2808399
+ / 0.3048
+
+ You have: cm^3
+ You want: gallons
+ * 0.00026417205
+ / 3785.4118
+
+ You have: meters/s
+ You want: furlongs/fortnight
+ * 6012.8848
+ / 0.00016630952
+
+ You have: 1|2 inch
+ You want: cm
+ * 1.27
+ / 0.78740157
+
+.fi
+Powers of units can be specified using the '^' character as shown in
+the example, or by simple concatenation: 'cm3' is equivalent to 'cm^3'.
+Multiplication of units can be specified by using spaces, a dash or
+an asterisk. Division of units is indicated by the slash ('/').
+Note that multiplication has a higher precedence than division,
+so 'm/s/s' is the same as 'm/s^2' or 'm/s s'. Division of numbers
+must be indicated using the vertical bar ('|'). To convert half a
+meter, you would write '1|2 meter'. If you write '1/2 meter' then the
+units program would interpret that as equivalent to '0.5/meter'.
+If you enter incompatible unit types, the units program will
+print a message indicating that the units are not conformable and
+it will display the reduced form for each unit:
+.nf
+
+ You have: ergs/hour
+ You want: fathoms kg^2 / day
+ conformability error
+ 2.7777778e-11 kg m^2 / sec^3
+ 2.1166667e-05 kg^2 m / sec
+.fi
+.LP
+The conversion information is read from a units data file. The default
+file includes definitions for most familiar units, abbreviations and
+metric prefixes. Some constants of nature included are:
+.in +4m
+.ta
+.ta 9m +
+.nf
+
+pi ratio of circumference to diameter
+c speed of light
+e charge on an electron
+g acceleration of gravity
+force same as g
+mole Avogadro's number
+water pressure per unit height of water
+mercury pressure per unit height of mercury
+au astronomical unit
+
+.fi
+.in -4m
+The unit 'pound' is a unit of mass. Compound names are run together
+so 'poundforce' is a unit of force. The unit 'ounce' is also a unit
+of mass. The fluid ounce is 'floz'. British units that differ from
+their US counterparts are prefixed with 'br', and currency is prefixed
+with its country name: 'belgiumfranc', 'britainpound'. When searching
+for a unit, if the specified string does not appear exactly as a unit
+name, then the units program will try to remove a trailing 's' or a
+trailing 'es' and check again for a match.
+.LP
+To find out what units are available read the standard units file.
+If you want to add your own units you can supply your own file.
+A unit is specified on a single line by
+giving its name and an equivalence. Be careful to define
+new units in terms of old ones so that a reduction leads to the
+primitive units which are marked with '!' characters.
+The units program will not detect infinite loops that could be caused
+by careless unit definitions. Comments in the unit definition file
+begin with a '/' character at the beginning of a line.
+.LP
+Prefixes are defined in the same was as standard units, but with
+a trailing dash at the end of the prefix name. If a unit is not found
+even after removing trailing 's' or 'es', then it will be checked
+against the list of prefixes. Prefixes will be removed until a legal
+base unit is identified.
+.LP
+Here is an example of a short units file that defines some basic
+units.
+.in 17m
+.ta
+.ta 9m +
+.nf
+
+m !a!
+sec !b!
+micro- 1e-6
+minute 60 sec
+hour 60 min
+inch 0.0254 m
+ft 12 inches
+mile 5280 ft
+.fi
+.in -17m
+
+.SH BUGS
+.LP
+The effect of including a '/' in a prefix is surprising.
+.LP
+Exponents entered by the user can be only one digit.
+You can work around this by multiplying several terms.
+.LP
+The user must use | to indicate division of numbers and / to
+indicate division of symbols. This distinction should not
+be necessary.
+.LP
+The program contains various arbitrary limits on the length
+of the units converted and on the length of the data file.
+.LP
+The program should use a hash table to store units so that
+it doesn't take so long to load the units list and check
+for duplication.
+.SH FILES
+/usr/share/misc/units.lib - the standard units library
+.SH AUTHOR
+Adrian Mariano (adrian@cam.cornell.edu)
diff --git a/usr.bin/units/units.c b/usr.bin/units/units.c
new file mode 100644
index 0000000..8ecc077
--- /dev/null
+++ b/usr.bin/units/units.c
@@ -0,0 +1,708 @@
+/* $Id$ */
+
+/*
+ * units.c Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * Disclaimer: This software is provided by the author "as is". The author
+ * shall not be liable for any damages caused in any way by this software.
+ *
+ * I would appreciate (though I do not require) receiving a copy of any
+ * improvements you might make to this program.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pathnames.h"
+
+#define VERSION "1.0"
+
+#ifndef UNITSFILE
+#define UNITSFILE _PATH_UNITSLIB
+#endif
+
+#define MAXUNITS 1000
+#define MAXPREFIXES 50
+
+#define MAXSUBUNITS 500
+
+#define PRIMITIVECHAR '!'
+
+char *powerstring = "^";
+
+struct {
+ char *uname;
+ char *uval;
+} unittable[MAXUNITS];
+
+struct unittype {
+ char *numerator[MAXSUBUNITS];
+ char *denominator[MAXSUBUNITS];
+ double factor;
+};
+
+struct {
+ char *prefixname;
+ char *prefixval;
+} prefixtable[MAXPREFIXES];
+
+
+char *NULLUNIT = "";
+
+int unitcount;
+int prefixcount;
+
+
+char *
+dupstr(char *str)
+{
+ char *ret;
+
+ ret = malloc(strlen(str) + 1);
+ if (!ret) {
+ fprintf(stderr, "Memory allocation error\n");
+ exit(3);
+ }
+ strcpy(ret, str);
+ return (ret);
+}
+
+
+void
+readerror(int linenum)
+{
+ fprintf(stderr, "Error in units file '%s' line %d\n", UNITSFILE,
+ linenum);
+}
+
+
+void
+readunits(char *userfile)
+{
+ FILE *unitfile;
+ char line[80], *lineptr;
+ int len, linenum, i;
+
+ unitcount = 0;
+ linenum = 0;
+
+ if (userfile) {
+ unitfile = fopen(userfile, "rt");
+ if (!unitfile) {
+ fprintf(stderr, "Unable to open units file '%s'\n",
+ userfile);
+ exit(1);
+ }
+ }
+ else {
+ unitfile = fopen(UNITSFILE, "rt");
+ if (!unitfile) {
+ char *direc, *env;
+ char filename[1000];
+ char separator[2];
+
+ env = getenv("PATH");
+ if (env) {
+ if (strchr(env, ';'))
+ strcpy(separator, ";");
+ else
+ strcpy(separator, ":");
+ direc = strtok(env, separator);
+ while (direc) {
+ strcpy(filename, "");
+ strncat(filename, direc, 999);
+ strncat(filename, "/",
+ 999 - strlen(filename));
+ strncat(filename, UNITSFILE,
+ 999 - strlen(filename));
+ unitfile = fopen(filename, "rt");
+ if (unitfile)
+ break;
+ direc = strtok(NULL, separator);
+ }
+ }
+ if (!unitfile) {
+ fprintf(stderr, "Can't find units file '%s'\n",
+ UNITSFILE);
+ exit(1);
+ }
+ }
+ }
+ while (!feof(unitfile)) {
+ if (!fgets(line, 79, unitfile))
+ break;
+ linenum++;
+ lineptr = line;
+ if (*lineptr == '/')
+ continue;
+ lineptr += strspn(lineptr, " \n\t");
+ len = strcspn(lineptr, " \n\t");
+ lineptr[len] = 0;
+ if (!strlen(lineptr))
+ continue;
+ if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
+ if (prefixcount == MAXPREFIXES) {
+ fprintf(stderr, "Memory for prefixes exceeded in line %d\n",
+ linenum);
+ continue;
+ }
+ lineptr[strlen(lineptr) - 1] = 0;
+ prefixtable[prefixcount].prefixname = dupstr(lineptr);
+ for (i = 0; i < prefixcount; i++)
+ if (!strcmp(prefixtable[i].prefixname, lineptr)) {
+ fprintf(stderr, "Redefinition of prefix '%s' on line %d ignored\n",
+ lineptr, linenum);
+ continue;
+ }
+ lineptr += len + 1;
+ if (!strlen(lineptr)) {
+ readerror(linenum);
+ continue;
+ }
+ lineptr += strspn(lineptr, " \n\t");
+ len = strcspn(lineptr, "\n\t");
+ lineptr[len] = 0;
+ prefixtable[prefixcount++].prefixval = dupstr(lineptr);
+ }
+ else { /* it's not a prefix */
+ if (unitcount == MAXUNITS) {
+ fprintf(stderr, "Memory for units exceeded in line %d\n",
+ linenum);
+ continue;
+ }
+ unittable[unitcount].uname = dupstr(lineptr);
+ for (i = 0; i < unitcount; i++)
+ if (!strcmp(unittable[i].uname, lineptr)) {
+ fprintf(stderr, "Redefinition of unit '%s' on line %d ignored\n",
+ lineptr, linenum);
+ continue;
+ }
+ lineptr += len + 1;
+ lineptr += strspn(lineptr, " \n\t");
+ if (!strlen(lineptr)) {
+ readerror(linenum);
+ continue;
+ }
+ len = strcspn(lineptr, "\n\t");
+ lineptr[len] = 0;
+ unittable[unitcount++].uval = dupstr(lineptr);
+ }
+ }
+ fclose(unitfile);
+}
+
+void
+initializeunit(struct unittype * theunit)
+{
+ theunit->factor = 1.0;
+ theunit->numerator[0] = theunit->denominator[0] = NULL;
+}
+
+
+int
+addsubunit(char *product[], char *toadd)
+{
+ char **ptr;
+
+ for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
+ if (ptr >= product + MAXSUBUNITS) {
+ fprintf(stderr, "Memory overflow in unit reduction\n");
+ return 1;
+ }
+ if (!*ptr)
+ *(ptr + 1) = 0;
+ *ptr = dupstr(toadd);
+ return 0;
+}
+
+
+void
+showunit(struct unittype * theunit)
+{
+ char **ptr;
+ int printedslash;
+ int counter = 1;
+
+ printf("\t%.8g", theunit->factor);
+ for (ptr = theunit->numerator; *ptr; ptr++) {
+ if (ptr > theunit->numerator && **ptr &&
+ !strcmp(*ptr, *(ptr - 1)))
+ counter++;
+ else {
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ if (**ptr)
+ printf(" %s", *ptr);
+ counter = 1;
+ }
+ }
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ counter = 1;
+ printedslash = 0;
+ for (ptr = theunit->denominator; *ptr; ptr++) {
+ if (ptr > theunit->denominator && **ptr &&
+ !strcmp(*ptr, *(ptr - 1)))
+ counter++;
+ else {
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ if (**ptr) {
+ if (!printedslash)
+ printf(" /");
+ printedslash = 1;
+ printf(" %s", *ptr);
+ }
+ counter = 1;
+ }
+ }
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ printf("\n");
+}
+
+
+void
+zeroerror()
+{
+ fprintf(stderr, "Unit reduces to zero\n");
+}
+
+/*
+ Adds the specified string to the unit.
+ Flip is 0 for adding normally, 1 for adding reciprocal.
+
+ Returns 0 for successful addition, nonzero on error.
+*/
+
+int
+addunit(struct unittype * theunit, char *toadd, int flip)
+{
+ char *scratch, *savescr;
+ char *item;
+ char *divider, *slash;
+ int doingtop;
+
+ savescr = scratch = dupstr(toadd);
+ for (slash = scratch + 1; *slash; slash++)
+ if (*slash == '-' &&
+ (tolower(*(slash - 1)) != 'e' ||
+ !strchr(".0123456789", *(slash + 1))))
+ *slash = ' ';
+ slash = strchr(scratch, '/');
+ if (slash)
+ *slash = 0;
+ doingtop = 1;
+ do {
+ item = strtok(scratch, " *\t\n/");
+ while (item) {
+ if (strchr("0123456789.", *item)) { /* item is a number */
+ double num;
+
+ divider = strchr(item, '|');
+ if (divider) {
+ *divider = 0;
+ num = atof(item);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip)
+ theunit->factor *= num;
+ else
+ theunit->factor /= num;
+ num = atof(divider + 1);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip)
+ theunit->factor /= num;
+ else
+ theunit->factor *= num;
+ }
+ else {
+ num = atof(item);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip)
+ theunit->factor *= num;
+ else
+ theunit->factor /= num;
+
+ }
+ }
+ else { /* item is not a number */
+ int repeat = 1;
+
+ if (strchr("23456789",
+ item[strlen(item) - 1])) {
+ repeat = item[strlen(item) - 1] - '0';
+ item[strlen(item) - 1] = 0;
+ }
+ for (; repeat; repeat--)
+ if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
+ return 1;
+ }
+ item = strtok(NULL, " *\t/\n");
+ }
+ doingtop--;
+ if (slash) {
+ scratch = slash + 1;
+ }
+ else
+ doingtop--;
+ } while (doingtop >= 0);
+ free(savescr);
+ return 0;
+}
+
+
+int
+compare(const void *item1, const void *item2)
+{
+ return strcmp(*(char **) item1, *(char **) item2);
+}
+
+
+void
+sortunit(struct unittype * theunit)
+{
+ char **ptr;
+ int count;
+
+ for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
+ qsort(theunit->numerator, count, sizeof(char *), compare);
+ for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
+ qsort(theunit->denominator, count, sizeof(char *), compare);
+}
+
+
+void
+cancelunit(struct unittype * theunit)
+{
+ char **den, **num;
+ int comp;
+
+ den = theunit->denominator;
+ num = theunit->numerator;
+
+ while (*num && *den) {
+ comp = strcmp(*den, *num);
+ if (!comp) {
+/* if (*den!=NULLUNIT) free(*den);
+ if (*num!=NULLUNIT) free(*num);*/
+ *den++ = NULLUNIT;
+ *num++ = NULLUNIT;
+ }
+ else if (comp < 0)
+ den++;
+ else
+ num++;
+ }
+}
+
+
+
+
+/*
+ Looks up the definition for the specified unit.
+ Returns a pointer to the definition or a null pointer
+ if the specified unit does not appear in the units table.
+*/
+
+static char buffer[100]; /* buffer for lookupunit answers with
+ prefixes */
+
+char *
+lookupunit(char *unit)
+{
+ int i;
+ char *copy;
+
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, unit))
+ return unittable[i].uval;
+ }
+
+ if (unit[strlen(unit) - 1] == '^') {
+ copy = dupstr(unit);
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strcpy(buffer, copy);
+ free(copy);
+ return buffer;
+ }
+ }
+ free(copy);
+ }
+ if (unit[strlen(unit) - 1] == 's') {
+ copy = dupstr(unit);
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strcpy(buffer, copy);
+ free(copy);
+ return buffer;
+ }
+ }
+ if (copy[strlen(copy) - 1] == 'e') {
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strcpy(buffer, copy);
+ free(copy);
+ return buffer;
+ }
+ }
+ }
+ free(copy);
+ }
+ for (i = 0; i < prefixcount; i++) {
+ if (!strncmp(prefixtable[i].prefixname, unit,
+ strlen(prefixtable[i].prefixname))) {
+ unit += strlen(prefixtable[i].prefixname);
+ if (!strlen(unit) || lookupunit(unit)) {
+ strcpy(buffer, prefixtable[i].prefixval);
+ strcat(buffer, " ");
+ strcat(buffer, unit);
+ return buffer;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+/*
+ reduces a product of symbolic units to primitive units.
+ The three low bits are used to return flags:
+
+ bit 0 (1) set on if reductions were performed without error.
+ bit 1 (2) set on if no reductions are performed.
+ bit 2 (4) set on if an unknown unit is discovered.
+*/
+
+
+#define ERROR 4
+
+int
+reduceproduct(struct unittype * theunit, int flip)
+{
+
+ char *toadd;
+ char **product;
+ int didsomething = 2;
+
+ if (flip)
+ product = theunit->denominator;
+ else
+ product = theunit->numerator;
+
+ for (; *product; product++) {
+
+ for (;;) {
+ if (!strlen(*product))
+ break;
+ toadd = lookupunit(*product);
+ if (!toadd) {
+ printf("unknown unit '%s'\n", *product);
+ return ERROR;
+ }
+ if (strchr(toadd, PRIMITIVECHAR))
+ break;
+ didsomething = 1;
+ if (*product != NULLUNIT) {
+ free(*product);
+ *product = NULLUNIT;
+ }
+ if (addunit(theunit, toadd, flip))
+ return ERROR;
+ }
+ }
+ return didsomething;
+}
+
+
+/*
+ Reduces numerator and denominator of the specified unit.
+ Returns 0 on success, or 1 on unknown unit error.
+*/
+
+int
+reduceunit(struct unittype * theunit)
+{
+ int ret;
+
+ ret = 1;
+ while (ret & 1) {
+ ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
+ if (ret & 4)
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+compareproducts(char **one, char **two)
+{
+ while (*one || *two) {
+ if (!*one && *two != NULLUNIT)
+ return 1;
+ if (!*two && *one != NULLUNIT)
+ return 1;
+ if (*one == NULLUNIT)
+ one++;
+ else if (*two == NULLUNIT)
+ two++;
+ else if (strcmp(*one, *two))
+ return 1;
+ else
+ one++, two++;
+ }
+ return 0;
+}
+
+
+/* Return zero if units are compatible, nonzero otherwise */
+
+int
+compareunits(struct unittype * first, struct unittype * second)
+{
+ return
+ compareproducts(first->numerator, second->numerator) ||
+ compareproducts(first->denominator, second->denominator);
+}
+
+
+int
+completereduce(struct unittype * unit)
+{
+ if (reduceunit(unit))
+ return 1;
+ sortunit(unit);
+ cancelunit(unit);
+ return 0;
+}
+
+
+void
+showanswer(struct unittype * have, struct unittype * want)
+{
+ if (compareunits(have, want)) {
+ printf("conformability error\n");
+ showunit(have);
+ showunit(want);
+ }
+ else
+ printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
+ want->factor / have->factor);
+}
+
+
+void
+usage()
+{
+ fprintf(stderr, "\nunits [-f unitsfile] [-q] [-v] [from-unit to-unit]\n");
+ fprintf(stderr, "\n -f specify units file\n");
+ fprintf(stderr, " -q supress prompting (quiet)\n");
+ fprintf(stderr, " -v print version number\n");
+ exit(3);
+}
+
+
+int
+main(int argc, char **argv)
+{
+
+ struct unittype have, want;
+ char havestr[81], wantstr[81];
+ int optchar;
+ char *userfile = 0;
+ int quiet = 0;
+
+ extern char *optarg;
+ extern int optind;
+
+ while ((optchar = getopt(argc, argv, "vqf:")) != -1) {
+ switch (optchar) {
+ case 'f':
+ userfile = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'v':
+ fprintf(stderr, "\n units version %s Copyright (c) 1993 by Adrian Mariano\n",
+ VERSION);
+ fprintf(stderr, " This program may be freely distributed\n");
+ usage();
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind != argc - 2 && optind != argc)
+ usage();
+
+ readunits(userfile);
+
+ if (optind == argc - 2) {
+ strcpy(havestr, argv[optind]);
+ strcpy(wantstr, argv[optind + 1]);
+ initializeunit(&have);
+ addunit(&have, havestr, 0);
+ completereduce(&have);
+ initializeunit(&want);
+ addunit(&want, wantstr, 0);
+ completereduce(&want);
+ showanswer(&have, &want);
+ }
+ else {
+ if (!quiet)
+ printf("%d units, %d prefixes\n\n", unitcount,
+ prefixcount);
+ for (;;) {
+ do {
+ initializeunit(&have);
+ if (!quiet)
+ printf("You have: ");
+ if (!fgets(havestr, 80, stdin)) {
+ if (!quiet)
+ putchar('\n');
+ exit(0);
+ }
+ } while (addunit(&have, havestr, 0) ||
+ completereduce(&have));
+ do {
+ initializeunit(&want);
+ if (!quiet)
+ printf("You want: ");
+ if (!fgets(wantstr, 80, stdin)) {
+ if (!quiet)
+ putchar('\n');
+ exit(0);
+ }
+ } while (addunit(&want, wantstr, 0) ||
+ completereduce(&want));
+ showanswer(&have, &want);
+ }
+ }
+
+ return(0);
+}
diff --git a/usr.bin/units/units.lib b/usr.bin/units/units.lib
new file mode 100644
index 0000000..9fcacc4
--- /dev/null
+++ b/usr.bin/units/units.lib
@@ -0,0 +1,610 @@
+/ $Id$
+
+/ primitive units
+
+m !a!
+kg !b!
+sec !c!
+coul !d!
+candela !e!
+dollar !f!
+bit !h!
+erlang !i!
+K !j!
+
+/ prefixes
+
+yotta- 1e24
+zetta- 1e21
+exa- 1e18
+peta- 1e15
+tera- 1e12
+giga- 1e9
+mega- 1e6
+myria- 1e4
+kilo- 1e3
+hecto- 1e2
+deka- 1e1
+deci- 1e-1
+centi- 1e-2
+milli- 1e-3
+micro- 1e-6
+nano- 1e-9
+pico- 1e-12
+femto- 1e-15
+atto- 1e-18
+zopto- 1e-21
+yocto- 1e-24
+
+semi- .5
+demi- .5
+
+Y- yotta
+Z- zetta
+E- exa
+P- peta
+T- tera
+G- giga
+M- mega
+k- kilo
+h- hecto
+da- deka
+d- deci
+c- centi
+m- milli
+p- pico
+f- femto
+a- atto
+z- zopto
+y- yocto
+
+/ constants
+
+fuzz 1
+pi 3.14159265358979323846
+c 2.99792458e+8 m/sec fuzz
+g 9.80665 m/sec2
+au 1.49597871e+11 m fuzz
+mole 6.022169e+23 fuzz
+e 1.6021917e-19 coul fuzz
+energy c2
+force g
+mercury 1.33322e+5 kg/m2-sec2
+hg mercury
+
+/ dimensionless
+
+radian .5 / pi
+degree 1|180 pi-radian
+circle 2 pi-radian
+turn 2 pi-radian
+revolution turn
+rev turn
+grade .9 degree
+arcdeg 1 degree
+arcmin 1|60 arcdeg
+ccs 1|36 erlang
+arcsec 1|60 arcmin
+
+steradian radian2
+sphere 4 pi-steradian
+sr steradian
+
+/ Time
+
+second sec
+s sec
+minute 60 sec
+min minute
+hour 60 min
+hr hour
+day 24 hr
+da day
+week 7 day
+year 365.24219879 day fuzz
+yr year
+month 1|12 year
+ms millisec
+us microsec
+
+/ Mass
+
+gram millikg
+gm gram
+mg milligram
+metricton kilokg
+
+/ Avoirdupois
+
+lb .45359237 kg
+pound lb
+lbf lb g
+ounce 1|16 lb
+oz ounce
+dram 1|16 oz
+dr dram
+grain 1|7000 lb
+gr grain
+shortton 2000 lb
+ton shortton
+longton 2240 lb
+
+/ Apothecary
+
+scruple 20 grain
+apdram 60 grain
+apounce 480 grain
+appound 5760 grain
+troypound appound
+
+/ Length
+
+meter m
+cm centimeter
+mm millimeter
+km kilometer
+nm nanometer
+micron micrometer
+angstrom decinanometer
+
+inch 2.54 cm
+in inch
+foot 12 in
+feet foot
+ft foot
+yard 3 ft
+yd yard
+rod 5.5 yd
+rd rod
+mile 5280 ft
+mi mile
+
+british 1200|3937 m/ft
+nmile 1852 m
+
+acre 4840 yd2
+
+cc cm3
+liter kilocc
+ml milliliter
+
+/ US Liquid
+
+gallon 231 in3
+imperial 1.20095
+gal gallon
+quart 1|4 gal
+qt quart
+pint 1|2 qt
+pt pint
+
+floz 1|16 pt
+fldr 1|8 floz
+
+/ US Dry
+
+dry 268.8025 in3/gallon fuzz
+peck 8 dry-quart
+pk peck
+bushel 4 peck
+bu bushel
+chaldron 36 bushel
+
+/ British
+
+brgallon 277.420 in3 fuzz
+brquart 1|4 brgallon
+brpint 1|2 brquart
+brfloz 1|20 brpint
+brpeck 554.84 in3 fuzz
+brbushel 4 brpeck
+
+/ Energy Work
+
+newton kg-m/sec2
+nt newton
+N newton
+joule nt-m
+cal 4.1868 joule
+
+/ Electrical
+
+coulomb coul
+C coul
+ampere coul/sec
+amp ampere
+watt joule/sec
+volt watt/amp
+ohm volt/amp
+mho /ohm
+farad coul/volt
+henry sec2/farad
+weber volt-sec
+
+/ Light
+
+cd candela
+lumen cd sr
+lux cd sr/m2
+
+/ Wall Street Journal, July 2, 1993
+
+$ dollar
+argentinapeso $
+australiadollar .66 $
+austriaschilling .83 $
+bahraindinar 2.6522 $
+belgiumfranc .028 $
+brazilcruzeiro .000019 $
+britainpound 1.49 $
+canadadollar .77 $
+czechkoruna .034 $
+chilepeso .0025 $
+chinarenminbi .174856 $
+colombiapeso .001495 $
+denmarkkrone .15 $
+ecuadorsucre .000539 $
+finlandmarkka .17 $
+francefranc .17 $
+germanymark .58 $
+greatbritainpound britainpound
+greecedrachma .0043 $
+hongkongdollar .13 $
+hungaryforint .011 $
+indiarupee .03211 $
+indonesiarupiah .0004782 $
+irelandpunt 1.43 $
+israelshekel .3642 $
+italylira .00064 $
+japanyen .0093 $
+jordandinar 1.4682 $
+kuwaitdinar 3.3173 $
+lebanonpound .000578 $
+malaysiaringgit .338 $
+maltalira 2.6042 $
+mexicopeso .3205128 $
+netherlandguilder .52 $
+newzealanddollar .539 $
+norwaykrone .139 $
+pakistanrupee .037 $
+perunewsol .5065 $
+philippinespeso .03738 $
+polandzloty .000059 $
+portugalescudo .00617 $
+saudiarabiariyal .26702 $
+singaporedollar .6157 $
+slovakkoruna .034 $
+southamericarand .21 $
+southkoreawon .001 $
+spainpeseta .007 $
+swedenkrona .13 $
+switzerlandfranc .66 $
+taiwandollar .038285 $
+thailandbaht .03962 $
+turkeylira .0000929 $
+unitedarabdirham .2723 $
+uruguaynewpeso .246852 $
+venezuelabolivar .011 $
+
+mark germanymark
+bolivar venezuelabolivar
+peseta spainpeseta
+rand southafricarand
+escudo portugalescudo
+sol perusol
+guilder netherlandsguilder
+hollandguilder netherlandsguilder
+peso mexicopeso
+yen japanyen
+lira italylira
+rupee indiarupee
+drachma greecedrachma
+franc francefranc
+markka finlandmarkka
+sucre ecuadorsucre
+poundsterling britainpound
+cruzeiro brazilcruzeiro
+
+/ computer
+
+baud bit/sec
+byte 8 bit
+block 512 byte
+kbyte 1024 byte
+megabyte 1024 kbyte
+gigabyte 1024 megabyte
+meg megabyte
+
+
+/ Trivia
+
+% 1|100
+admiraltyknot 6080 ft/hr
+apostilb cd/pi-m2
+are 1e+2 m2
+arpentcan 27.52 mi
+arpentlin 191.835 ft
+astronomicalunit au
+atmosphere 1.01325e+5 nt/m2
+atm atmosphere
+atomicmassunit 1.66044e-27 kg fuzz
+amu atomicmassunit
+bag 94 lb
+bakersdozen 13
+bar 1e+5 nt/m2
+barie 1e-1 nt/m2
+barleycorn 1|3 in
+barn 1e-28 m2
+barrel 42 gal
+barye 1e-1 nt/m2
+bev 1e+9 e-volt
+biot 10 amp
+blondel cd/pi-m2
+boardfoot 144 in3
+bolt 40 yd
+bottommeasure 1|40 in
+britishthermalunit 1.05506e+3 joule fuzz
+btu britishthermalunit
+refrigeration 12000 btu/ton-hour
+buck dollar
+cable 720 ft
+caliber 1e-2 in
+calorie cal
+carat 205 mg
+caratgold 1|24
+cent centidollar
+cental 100 lb
+centesimalminute 1e-2 grade
+centesimalsecond 1e-4 grade
+century 100 year
+cfs ft3/sec
+chain 66 ft
+circularinch 1|4 pi-in2
+circularmil 1e-6|4 pi-in2
+clusec 1e-8 mm-hg m3/s
+coomb 4 bu
+cord 128 ft3
+cordfoot cord
+crith 9.06e-2 gm
+cubit 18 in
+cup 1|2 pt
+curie 3.7e+10 /sec
+dalton amu
+decade 10 yr
+dipotre /m
+displacementton 35 ft3
+doppelzentner 100 kg
+dozen 12
+drop .03 cm3
+dyne cm-gm/sec2
+electronvolt e-volt
+ell 45 in
+engineerschain 100 ft
+engineerslink 100|100 ft
+equivalentfootcandle lumen/pi-ft2
+equivalentlux lumen/pi-m2
+equivalentphot cd/pi-cm2
+erg cm2-gm/sec2
+ev e-volt
+faraday 9.652e+4 coul
+fathom 6 ft
+fermi 1e-15 m
+fifth 4|5 qt
+fin 5 dollar
+finger 7|8 in
+firkin 9 gal
+footcandle lumen/ft2
+footlambert cd/pi-ft2
+fortnight 14 da
+franklin 3.33564e-10 coul
+frigorie kilocal
+furlong 220 yd
+galileo 1e-2 m/sec2
+gamma 1e-9 weber/m2
+gauss 1e-4 weber/m2
+geodeticfoot british-ft
+geographicalmile 1852 m
+gilbert 7.95775e-1 amp
+gill 1|4 pt
+gross 144
+gunterschain 22 yd
+hand 4 in
+hectare 1e+4 m2
+hefnercandle .92 cd
+hertz /sec
+Hz hertz
+hogshead 2 barrel
+hd hogshead
+homestead 1|4 mi2
+horsepower 550 ft-lb-g/sec
+hp horsepower
+hyl gm force sec2/m
+hz /sec
+imaginarycubicfoot 1.4 ft3
+jeroboam 4|5 gal
+karat 1|24
+kcal kilocal
+kcalorie kilocal
+kev 1e+3 e-volt
+key kg
+khz 1e+3 /sec
+kilderkin 18 gal
+knot nmile/hr
+lambert cd/pi-cm2
+langley cal/cm2
+last 80 bu
+league 3 mi
+lightyear c-yr
+line 1|12 in
+link 66|100 ft
+longhundredweight 112 lb
+longquarter 28 lb
+lusec 1e-6 mm-hg m3/s
+mach 331.46 m/sec
+magnum 2 qt
+marineleague 3 nmile
+maxwell 1e-8 weber
+metriccarat 200 mg
+mgd megagal/day
+mh millihenry
+mhz 1e+6 /sec
+mil 1e-3 in
+millenium 1000 year
+minersinch 1.5 ft3/min
+minim 1|60 fldr
+mo month
+mpg mile/gal
+mph mile/hr
+nail 1|16 yd
+nauticalmile nmile
+nit cd/m2
+noggin 1|8 qt
+nox 1e-3 lux
+ns nanosec
+oersted 2.5e+2 pi-amp/m
+oe oersted
+pace 36 in
+palm 3 in
+parasang 3.5 mi
+parsec au-radian/arcsec
+pascal nt/m2
+pc parsec
+pennyweight 1|20 oz
+pwt pennyweight
+percent %
+perch rd
+pf picofarad
+phot lumen/cm2
+pica 1|6 in
+pieze 1e+3 nt/m2
+pipe 4 barrel
+point 1|72 in
+poise gm/cm-sec
+pole rd
+poundal ft-lb/sec2
+pdl poundal
+proof 1|200
+psi lb-g/in2
+quarter 9 in
+quartersection 1|4 mi2
+quintal 100 kg
+quire 25
+rad 100 erg/gm
+ream 500
+registerton 100 ft3
+rehoboam 156 floz
+rhe 10 m2/nt-sec
+rontgen 2.58e-4 curie/kg
+rood 1.21e+3 yd
+rope 20 ft
+rutherford 1e+6 /sec
+rydberg 1.36054e+1 ev
+sabin 1 ft2
+sack 3 bu
+seam 8 bu
+section mi2
+shippington 40 ft3
+shorthundredweight 100 lb
+shortquarter 25 lb
+siemens /ohm
+sigma microsec
+skein 120 yd
+skot 1e-3 apostilb
+slug lb-g-sec2/ft
+span 9 in
+spat 4 pi sr
+spindle 14400 yd
+square 100 ft2
+stere m3
+sthene 1e+3 nt
+stilb cd/cm2
+stoke 1e-4 m2/sec
+stone 14 lb
+strike 2 bu
+surveyfoot british-ft
+surveyyard 3 surveyfoot
+surveyorschain 66 ft
+surveyorslink 66|100 ft
+tablespoon 4 fldr
+teaspoon 4|3 fldr
+tesla weber/m2
+therm 1e+5 btu
+thermie 1e+6 cal
+timberfoot ft3
+tnt 4.6e+6 m2/sec2
+tonne 1e+6 gm
+torr mm hg
+township 36 mi2
+tun 8 barrel
+water gram g / cc
+wey 40 bu
+weymass 252 lb
+Xunit 1.00202e-13 m
+k 1.38047e-16 erg/degC
+
+
+degC K
+kelvin K
+brewster 1e-12 m2/newton
+degF 5|9 degC
+degreesrankine degF
+degrankine degreesrankine
+degreerankine degF
+degreaumur 10|8 degC
+drachm 60 grain
+poncelet 100 kg m g / sec
+denier .05|450 gram / m
+tex .001 gram / m
+englishell 45 inch
+scottishell 37.2 inch
+flemishell 27 inch
+planck 6.626e-34 joule-sec
+hbar 1.055e-34 joule-sec
+electronmass 9.1095e-31 kg
+protonmass 1.6726e-27 kg
+neutronmass 1.6606e-27 kg
+V volt
+eV e V
+bohrradius hbar2-C2/8.988e9 N m2-e2-electronmass
+becquerel 1|3.7e10 curie
+fresnel 1e12 hertz
+statcoul 1|2.99792458e9 coul
+statamp 1|2.99792458e9 amp
+statvolt 2.99792458e2 volt
+statcoulomb statcoul
+statampere statamp
+debye 3.336e-30 coul-m
+pulsatance 2 pi/sec
+rpm rev/minute
+rps rev/sec
+kilohm kiloohm
+megohm megaohm
+siderealyear 365.256360417 day
+siderealday 23.934469444 hour
+siderealhour 1|24 sidereal day
+lunarmonth 29.5305555 day
+synodicmonth lunarmonth
+siderealmonth 27.32152777 day
+tropicalyear year
+solaryear year
+lunaryear 12 lunarmonth
+cran 37.5 brgallon
+kip 1000 lbf
+frenchfoot 16|15 ft
+frenchfeet frenchfoot
+toise 6 frenchfeet
+sievert 8.4 rontgen
+candle 1.02 candela
+militarypace 2.5 feet
+metre meter
+litre liter
+gramme gram
+iudiptheria 62.8 microgram
+iupenicillin .6 microgram
+iuinsulin 41.67 microgram
+cottonyarncount 2520 ft/pound
+linenyarncount 900 ft/pound
+worstedyarncount 1680 ft/pound
+metricyarncount meter/gram
+jewlerspoint 2 milligram
+
diff --git a/usr.bin/unvis/unvis.1 b/usr.bin/unvis/unvis.1
index 5d531af..4f6a832 100644
--- a/usr.bin/unvis/unvis.1
+++ b/usr.bin/unvis/unvis.1
@@ -53,5 +53,5 @@ a visual representation of data back to its original form on standard output.
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/unvis/unvis.c b/usr.bin/unvis/unvis.c
index 82cad81..5ea689b 100644
--- a/usr.bin/unvis/unvis.c
+++ b/usr.bin/unvis/unvis.c
@@ -57,7 +57,7 @@ main(argc, argv)
int ch;
Program = argv[0];
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch((char)ch) {
case '?':
default:
diff --git a/usr.bin/users/users.1 b/usr.bin/users/users.1
index 0dd1b0f..57ae2db 100644
--- a/usr.bin/users/users.1
+++ b/usr.bin/users/users.1
@@ -44,8 +44,8 @@
lists the login names of the users currently on the system,
in sorted order, space separated, on a single line.
.Sh FILES
-.Bl -tag -width /etc/utmp
-.It Pa /etc/utmp
+.Bl -tag -width /var/run/utmp
+.It Pa /var/run/utmp
.El
.Sh SEE ALSO
.Xr finger 1 ,
diff --git a/usr.bin/users/users.c b/usr.bin/users/users.c
index 11571f2..48a584a 100644
--- a/usr.bin/users/users.c
+++ b/usr.bin/users/users.c
@@ -57,7 +57,7 @@ main(argc, argv)
char names[MAXUSERS][UT_NAMESIZE];
int ch, scmp();
- while ((ch = getopt(argc, argv, "")) != EOF)
+ while ((ch = getopt(argc, argv, "")) != -1)
switch(ch) {
case '?':
default:
diff --git a/usr.bin/uucp/acucntrl/Makefile b/usr.bin/uucp/acucntrl/Makefile
deleted file mode 100644
index 85bbfe4..0000000
--- a/usr.bin/uucp/acucntrl/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-
-PROG= acucntrl
-CFLAGS+=-I${.CURDIR}/../includes
-BINDIR= ${LIBDIR}
-BINOWN= root
-BINMODE=6550
-MAN8= acucntrl.0
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/uucp/acucntrl/acucntrl.8 b/usr.bin/uucp/acucntrl/acucntrl.8
deleted file mode 100644
index 7b6753d..0000000
--- a/usr.bin/uucp/acucntrl/acucntrl.8
+++ /dev/null
@@ -1,165 +0,0 @@
-.\" Copyright (c) 1985, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)acucntrl.8 8.3 (Berkeley) 6/1/94
-.\"
-.TH ACUCNTRL 8 "June 1, 1994"
-.UC 6
-.SH NAME
-acucntrl \- turn around tty line between dialin and dialout
-.SH SYNOPSIS
-.B /usr/lib/uucp/acucntrl
-keyword ttyline
-.SH DESCRIPTION
-.PP
-.I Acucntrl
-turns around the terminal line,
-enabling it to be used for both dialin and dialout.
-On dialin a terminal line is assumed to have modem control enabled and a getty
-process in existence waiting for logins. On dialout modem control is disabled
-and there is no getty process.
-.PP
-This program must be run setuid to root.
-.PP
-.I keyword
-is chosen from the list:
-.I disable
-or
-.IR dialout ,
-to condition a line for dialout;
-and
-.I enable
-or
-.IR dialin ,
-to condition a line for dialin.
-.PP
-When the line is conditioned for dialing out, the login name of the real uid
-of the process is placed in /etc/utmp in capitals.
-This declares that the line is in use and acts as an additional locking
-mechanism.
-.I Acucntrl
-will refuse to act if the /etc/utmp entry for the line is not null,
-is not the the user's login name (capitalized or not),
-and if the process is not running as the superuser.
-The last condition is to allow the superuser to clear the state of the line.
-.PP
-Turning modem control on or off is handled by poking into /dev/kmem.
-It is currently implemented for dz, dh, and dmf lines.
-.PP
-Under 4.2 BSD the program will also refuse to disable a line if carrier is
-sensed on it. This is to avoid the dead period where someone has just dialed
-in and made the connection but has not yet logged in.
-.PP
-.I Ttyline
-can be either of the form tty* or /dev/tty*.
-Enabling/disabling a line whose name does not begin with ttyd? is prohibited
-unless the real uid of the process is 0 or if the login name corresponding to
-the real uid is uucp. This is a security precaution.
-.PP
-Steps taken when disabling
-.RI ( i . e .
-setup for dialing out)
-.IP 1)
-check input arguments
-.IP 2)
-look in /etc/utmp to check that the line is not in use by another user
-.IP 3)
-disable modem control on line
-.IP 4)
-check for carrier on device
-.IP 5)
-change owner of device to real uid
-.IP 6)
-edit /etc/ttys, changing the first character of the appropriate line to 0
-.IP 7)
-send a hangup to process 1 to poke init to disable getty
-.IP 8)
-post uid name in capitals in /etc/utmp to let world know device has been grabbed
-.IP 9)
-make sure that DTR is on
-.PP
-Steps taken when enabling
-.RI ( i . e .
-setup for dialing in)
-.IP 1)
-check input arguments
-.IP 2)
-look in /etc/utmp to check that the line is not in use by another user
-.IP 3)
-make sure modem control on line is disabled
-.IP 4)
-turn off DTR to make sure line is hung up
-.IP 5)
-condition line: clear exclusive use and set hangup on close modes
-.IP 6)
-turn on modem control
-.IP 7)
-edit /etc/ttys, changing the first character of the appropriate line to 1
-.ne 1i
-.IP 8)
-send a hangup to process 1 to poke init to enable getty
-.IP 9)
-clear uid name for /etc/utmp
-.SH HISTORY
-.PP
-First written by Allan Wilkes (fisher!allan)
-.PP
-Modified June 8,1983 by W.Sebok (astrovax!wls) to poke the kernel rather
-than use a kernel hack to turn on/off modem control, using a subroutine
-stolen from a program written by Tsutomu Shimomura {astrovax,escher}!tsutomu
-.PP
-Worked over many times by W.Sebok
-.RI ( i . e .
-hacked to death)
-.SH FILES
-/dev/kmem, /vmunix, /etc/ttys, /etc/utmp, /dev/tty*
-.SH BUGS
-.PP
-Sensing carrier requires the 4.2 BSD TIOCMGET ioctl call. Unfortunately this
-ioctl is not implemented in the vanilla 4.2 BSD dh driver even though the
-dz and dmf drivers use an emulation of the DH11's modem control bits. This
-has been fixed here.
-.PP
-Some time (currently 2 seconds) is required between disabling modem control
-and opening the device. This is probably because of a race with getty whose
-open is finally being allowed to complete. This time interval may not be
-enough on a loaded system. Because of this problem and the above problem with
-the dh driver there is deliberately no error message given when the TIOCMGET
-ioctl fails.
-.PP
-Previously there were similar synchronization problems with the init process.
-When dialins are disabled the capitalized name of the process cannot be posted
-into /etc/utmp until init has finished clearing /etc/utmp. However one does
-not know how long that will take, and, on a loaded system, it can take quite
-a while. This was solved by the strategy of 1) posting the name, 2) poking
-init, 3) going into a loop where the process repeatedly waits a second and
-checks whether the entry has been cleared from /etc/utmp, and 4) posting the
-name again.
diff --git a/usr.bin/uucp/uupoll/Makefile b/usr.bin/uucp/uupoll/Makefile
deleted file mode 100644
index fd39c3c..0000000
--- a/usr.bin/uucp/uupoll/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-
-PROG= uupoll
-CFLAGS+=-I${.CURDIR}/../includes
-BINMODE=6555
-DPADD= ${LIBCOMPAT}
-LDADD= ${LIBUU} -lcompat
-MAN8= uupoll.0
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/uucp/uusnap/Makefile b/usr.bin/uucp/uusnap/Makefile
deleted file mode 100644
index 6bf9137..0000000
--- a/usr.bin/uucp/uusnap/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-
-PROG= uusnap
-CFLAGS+=-I${.CURDIR}/../includes
-BINMODE=6555
-MAN8= uusnap.0
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/uudecode/uudecode.c b/usr.bin/uudecode/uudecode.c
index af87847..1667e01 100644
--- a/usr.bin/uudecode/uudecode.c
+++ b/usr.bin/uudecode/uudecode.c
@@ -50,11 +50,20 @@ static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94";
#include <sys/param.h>
#include <sys/stat.h>
+#include <fnmatch.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
char *filename;
+int cflag, pflag;
+
+void usage __P((void));
+int decode __P((void));
+int decode2 __P((int));
+
+extern int optind;
int
main(argc, argv)
@@ -62,9 +71,25 @@ main(argc, argv)
char *argv[];
{
extern int errno;
- int rval;
+ int rval, ch;
+
+ while ((ch = getopt(argc, argv, "cp")) != -1) {
+ switch(ch) {
+ case 'c':
+ cflag = 1; /* multiple uudecode'd files */
+ break;
+ case 'p':
+ pflag = 1; /* print output to stdout */
+ break;
+ default:
+ (void)usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
- if (*++argv) {
+
+ if (*argv) {
rval = 0;
do {
if (!freopen(filename = *argv, "r", stdin)) {
@@ -82,7 +107,28 @@ main(argc, argv)
exit(rval);
}
-decode()
+int
+decode ()
+{
+ int flag;
+
+ /* decode only one file per input stream */
+ if (!cflag)
+ return(decode2(0));
+
+ /* multiple uudecode'd files */
+ for (flag = 0; ; flag++)
+ if (decode2(flag))
+ return(1);
+ else if (feof(stdin))
+ break;
+
+ return(0);
+}
+
+int
+decode2(flag)
+ int flag;
{
extern int errno;
struct passwd *pw;
@@ -90,15 +136,22 @@ decode()
register char ch, *p;
int mode, n1;
char buf[MAXPATHLEN];
+ char buffn[MAXPATHLEN]; /* file name buffer */
+
/* search for header line */
do {
if (!fgets(buf, sizeof(buf), stdin)) {
+ if (flag) /* no error */
+ return(0);
+
(void)fprintf(stderr,
"uudecode: %s: no \"begin\" line\n", filename);
return(1);
}
- } while (strncmp(buf, "begin ", 6));
+ } while (strncmp(buf, "begin ", 6) ||
+ fnmatch("begin [0-7]* *", buf, 0));
+
(void)sscanf(buf, "begin %o %s", &mode, buf);
/* handle ~user/file format */
@@ -127,12 +180,16 @@ decode()
}
/* create output file, set mode */
- if (!freopen(buf, "w", stdout) ||
+ if (pflag)
+ ; /* print to stdout */
+
+ else if (!freopen(buf, "w", stdout) ||
fchmod(fileno(stdout), mode&0666)) {
(void)fprintf(stderr, "uudecode: %s: %s: %s\n", buf,
filename, strerror(errno));
return(1);
}
+ strcpy(buffn, buf); /* store file name from header line */
/* for each input line */
for (;;) {
@@ -142,6 +199,18 @@ decode()
return(1);
}
#define DEC(c) (((c) - ' ') & 077) /* single character decode */
+#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
+/* #define IS_DEC(c) (1) */
+
+#define OUT_OF_RANGE \
+{ \
+ (void)fprintf(stderr, \
+ "uudecode:\n\tinput file: %s\n\tencoded file: %s\n\t%s: [%d-%d]\n", \
+ filename, buffn, "character out of range", 1 + ' ', 077 + ' ' + 1); \
+ return(1); \
+}
+
+
/*
* `n' is used to avoid writing out all the characters
* at the end of the file.
@@ -150,29 +219,45 @@ decode()
break;
for (++p; n > 0; p += 4, n -= 3)
if (n >= 3) {
+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
+ IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
+ OUT_OF_RANGE
+
ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
putchar(ch);
ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
putchar(ch);
ch = DEC(p[2]) << 6 | DEC(p[3]);
putchar(ch);
+
}
else {
if (n >= 1) {
+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
+ OUT_OF_RANGE
ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
putchar(ch);
}
if (n >= 2) {
+ if (!(IS_DEC(*(p + 1)) &&
+ IS_DEC(*(p + 2))))
+ OUT_OF_RANGE
+
ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
putchar(ch);
}
if (n >= 3) {
+ if (!(IS_DEC(*(p + 2)) &&
+ IS_DEC(*(p + 3))))
+ OUT_OF_RANGE
ch = DEC(p[2]) << 6 | DEC(p[3]);
putchar(ch);
}
}
}
- if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) {
+ if (fgets(buf, sizeof(buf), stdin) == NULL ||
+ (strcmp(buf, "end") && strcmp(buf, "end\n") &&
+ strcmp(buf, "end\r\n"))) {
(void)fprintf(stderr, "uudecode: %s: no \"end\" line.\n",
filename);
return(1);
@@ -180,8 +265,9 @@ decode()
return(0);
}
+void
usage()
{
- (void)fprintf(stderr, "usage: uudecode [file ...]\n");
+ (void)fprintf(stderr, "usage: uudecode [-cp] [file ...]\n");
exit(1);
}
diff --git a/usr.bin/uuencode/Makefile b/usr.bin/uuencode/Makefile
index 051a6fe..cf14277 100644
--- a/usr.bin/uuencode/Makefile
+++ b/usr.bin/uuencode/Makefile
@@ -1,8 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= uuencode
-MAN1= uuencode.0
-MAN5= uuencode.format.0
-MLINKS= uuencode.1 uudecode.1
+MAN1= uuencode.1
+MAN5= uuencode.format.5
+MLINKS= uuencode.1 uudecode.1 \
+ uuencode.format.5 uuencode.5
.include <bsd.prog.mk>
diff --git a/usr.bin/uuencode/uuencode.1 b/usr.bin/uuencode/uuencode.1
index df1ebf2..3dd1e68 100644
--- a/usr.bin/uuencode/uuencode.1
+++ b/usr.bin/uuencode/uuencode.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)uuencode.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt UUENCODE 1
@@ -43,6 +44,7 @@
.Op Ar file
.Ar name
.Nm uudecode
+.Op Fl cp
.Op Ar file ...
.Sh DESCRIPTION
.Nm Uuencode
@@ -76,6 +78,18 @@ and will have the mode of the original file except that setuid
and execute bits are not retained.
.Nm Uudecode
ignores any leading and trailing lines.
+.Pp
+The following options are available for
+.Nm uudecode :
+.Bl -tag -width ident
+.It Fl c
+Decode more than one uuencode'd file from
+.Ar file
+if possible.
+.It Fl p
+Decode
+.Ar file
+and write output to standard output.
.Sh EXAMPLES
The following example packages up a source tree, compresses it,
uuencodes it and mails it to a user on another system.
@@ -89,12 +103,25 @@ tree.
tar cf \- src_tree \&| compress \&|
uuencode src_tree.tar.Z \&| mail sys1!sys2!user
.Ed
+
+The following example unpack all uuencode'd
+files from your mailbox into your current working directory.
+.Pp
+.Bd -literal -offset indent -compact
+uudecode -c < $MAIL
+.Ed
+
+The following example extract a compress'ed tar
+archive from your mailbox
+.Pp
+.Bd -literal -offset indent -compact
+uudecode -p < $MAIL | zcat | tar xfv -
+.Ed
.Sh SEE ALSO
.Xr compress 1 ,
.Xr mail 1 ,
.Xr uucp 1 ,
-.Xr uuencode 5 ,
-.Xr format 5
+.Xr uuencode 5
.Sh BUGS
The encoded form of the file is expanded by 35% (3 bytes become 4 plus
control information).
diff --git a/usr.bin/uuencode/uuencode.c b/usr.bin/uuencode/uuencode.c
index 774cee9..8580624 100644
--- a/usr.bin/uuencode/uuencode.c
+++ b/usr.bin/uuencode/uuencode.c
@@ -62,7 +62,7 @@ main(argc, argv)
int mode;
char *strerror();
- while (getopt(argc, argv, "") != EOF)
+ while (getopt(argc, argv, "") != -1)
usage();
argv += optind;
argc -= optind;
diff --git a/usr.bin/uuencode/uuencode.format.5 b/usr.bin/uuencode/uuencode.format.5
index 81591b8..c2a89e1 100644
--- a/usr.bin/uuencode/uuencode.format.5
+++ b/usr.bin/uuencode/uuencode.format.5
@@ -69,12 +69,15 @@ followed by a newline.
The character count is a single printing character,
and represents an integer, the number of bytes
the rest of the line represents.
-Such integers are always in the range from 0 to 63 and can
+Such integers are always in the range from 1 to 45 or 64 and can
be determined by subtracting the character space (octal 40)
from the character.
+Character 64 represents a count of zero.
.Pp
Groups of 3 bytes are stored in 4 characters, 6 bits per character.
-All are offset by a space to make the characters printing.
+All characters are always in range from 1 to 64 and are offset by a
+space (octal 40) to make the characters printing. Character
+64 represents a count of zero.
The last line may be shorter than the normal 45 bytes.
If the size is not a multiple of 3, this fact can be determined
by the value of the count on the last line.
@@ -83,17 +86,16 @@ of 4.
The body is terminated by a line with a count of zero.
This line consists of one
.Tn ASCII
-space.
+backquote (octal 140) character.
.Pp
The trailer line consists of
.Dq end
on a line by itself.
.Sh SEE ALSO
-.Xr uuencode 1 ,
-.Xr uudecode 1 ,
-.Xr uusend 1 ,
+.Xr mail 1 ,
.Xr uucp 1 ,
-.Xr mail 1
+.Xr uudecode 1 ,
+.Xr uuencode 1
.Sh HISTORY
The
.Nm uuencode
diff --git a/usr.bin/vacation/Makefile b/usr.bin/vacation/Makefile
index 130d439..6fc4795 100644
--- a/usr.bin/vacation/Makefile
+++ b/usr.bin/vacation/Makefile
@@ -1,6 +1,7 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id$
PROG= vacation
-DPADD= ${LIBDBM}
+CFLAGS+= -Wall
.include <bsd.prog.mk>
diff --git a/usr.bin/vacation/vacation.1 b/usr.bin/vacation/vacation.1
index f70d16c..8ce05e0 100644
--- a/usr.bin/vacation/vacation.1
+++ b/usr.bin/vacation/vacation.1
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)vacation.1 8.2 (Berkeley) 4/28/95
+.\" From: @(#)vacation.1 8.1 (Berkeley) 6/16/93
+.\" $Id$
.\"
-.Dd April 28, 1995
+.Dd June 16, 1993
.Dt VACATION 1
.Os BSD 4.3
.Sh NAME
@@ -42,6 +43,8 @@
.Fl i
.Op Fl r Ar interval
.Nm vacation
+.Fl l
+.Nm vacation
.Op Fl a Ar alias
.Ar login
.Sh DESCRIPTION
@@ -88,6 +91,10 @@ are quite
dangerous, as it allows mailers to get into
.Dq I am on vacation
loops.
+.It Fl l
+Print the contents of the vacation database files. For each entry,
+the address the reply has been sent to and the associated time will
+be printed to standard output.
.El
.Pp
No message will be sent unless
@@ -115,7 +122,7 @@ or
.Dq Precedence: junk
line is included in the mail headers.
The people who have sent you messages are maintained as a
-.Xr db 3
+.Xr hash 3
database in the file
.Pa .vacation.db
in your home directory.
@@ -153,7 +160,7 @@ Fatal errors, such as calling
with incorrect arguments, or with non-existent
.Ar login Ns Ar s ,
are logged in the system log file, using
-.Xr syslog 8 .
+.Xr syslog 3 .
.Sh FILES
.Bl -tag -width "vacation.dirxxx" -compact
.It Pa ~/.vacation.db
@@ -162,8 +169,9 @@ database file
message to send
.El
.Sh SEE ALSO
+.Xr syslog 3 ,
.Xr sendmail 8 ,
-.Xr syslog 8
+.Xr syslogd 8
.Sh HISTORY
The
.Nm vacation
diff --git a/usr.bin/vacation/vacation.c b/usr.bin/vacation/vacation.c
index 025eb98..6cfdfc8 100644
--- a/usr.bin/vacation/vacation.c
+++ b/usr.bin/vacation/vacation.c
@@ -38,7 +38,9 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94";
+static char sccsid[] = "From: @(#)vacation.c 8.2 (Berkeley) 1/26/94";
+static char rcsid[] =
+ "$Id: vacation.c,v 1.8 1997/04/23 22:36:51 ache Exp $";
#endif /* not lint */
/*
@@ -54,7 +56,6 @@ static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94";
#include <db.h>
#include <time.h>
#include <syslog.h>
-#include <tzfile.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -86,6 +87,18 @@ DB *db;
char from[MAXLINE];
+static int isdelim __P((int));
+static int junkmail __P((void));
+static void listdb __P((void));
+static int nsearch __P((char *, char *));
+static void readheaders __P((void));
+static int recent __P((void));
+static void sendmessage __P((char *));
+static void setinterval __P((time_t));
+static void setreply __P((void));
+static void usage __P((void));
+
+int
main(argc, argv)
int argc;
char **argv;
@@ -95,11 +108,11 @@ main(argc, argv)
struct passwd *pw;
ALIAS *cur;
time_t interval;
- int ch, iflag;
+ int ch, iflag, lflag;
- opterr = iflag = 0;
+ opterr = iflag = lflag = 0;
interval = -1;
- while ((ch = getopt(argc, argv, "a:Iir:")) != EOF)
+ while ((ch = getopt(argc, argv, "a:Iilr:")) != -1)
switch((char)ch) {
case 'a': /* alias */
if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
@@ -112,9 +125,12 @@ main(argc, argv)
case 'i': /* init the database */
iflag = 1;
break;
+ case 'l':
+ lflag = 1; /* list the database */
+ break;
case 'r':
if (isdigit(*optarg)) {
- interval = atol(optarg) * SECSPERDAY;
+ interval = atol(optarg) * 86400;
if (interval < 0)
usage();
}
@@ -129,7 +145,7 @@ main(argc, argv)
argv += optind;
if (argc != 1) {
- if (!iflag)
+ if (!iflag && !lflag)
usage();
if (!(pw = getpwuid(getuid()))) {
syslog(LOG_ERR,
@@ -154,10 +170,12 @@ main(argc, argv)
exit(1);
}
- if (interval != -1)
+ if (lflag)
+ listdb();
+ else if (interval != -1)
setinterval(interval);
- if (iflag) {
+ if (iflag || lflag) {
(void)(db->close)(db);
exit(0);
}
@@ -184,6 +202,7 @@ main(argc, argv)
* readheaders --
* read mail headers
*/
+static void
readheaders()
{
register ALIAS *cur;
@@ -200,7 +219,7 @@ readheaders()
for (p = buf + 5; *p && *p != ' '; ++p);
*p = '\0';
(void)strcpy(from, buf + 5);
- if (p = index(from, '\n'))
+ if ((p = index(from, '\n')))
*p = '\0';
if (junkmail())
exit(0);
@@ -209,7 +228,7 @@ readheaders()
case 'P': /* "Precedence:" */
cont = 0;
if (strncasecmp(buf, "Precedence", 10) ||
- buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t')
+ (buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t'))
break;
if (!(p = index(buf, ':')))
break;
@@ -251,13 +270,16 @@ findme: for (cur = names; !tome && cur; cur = cur->next)
* nsearch --
* do a nice, slow, search of a string for a substring.
*/
+static int
nsearch(name, str)
register char *name, *str;
{
register int len;
for (len = strlen(name); *str; ++str)
- if (*str == *name && !strncasecmp(name, str, len))
+ if (*str == *name &&
+ !strncasecmp(name, str, len) &&
+ isdelim((unsigned char)str[len]))
return(1);
return(0);
}
@@ -266,15 +288,16 @@ nsearch(name, str)
* junkmail --
* read the header and return if automagic/junk/bulk/list mail
*/
+static int
junkmail()
{
static struct ignore {
char *name;
int len;
} ignore[] = {
- "-request", 8, "postmaster", 10, "uucp", 4,
- "mailer-daemon", 13, "mailer", 6, "-relay", 6,
- NULL, NULL,
+ {"-request", 8}, {"postmaster", 10}, {"uucp", 4},
+ {"mailer-daemon", 13}, {"mailer", 6}, {"-relay", 6},
+ {NULL, NULL},
};
register struct ignore *cur;
register int len;
@@ -288,8 +311,8 @@ junkmail()
* From site!site!SENDER%site.domain%site.domain@site.domain
*/
if (!(p = index(from, '%')))
- if (!(p = index(from, '@'))) {
- if (p = rindex(from, '!'))
+ if (!((p = index(from, '@')))) {
+ if ((p = rindex(from, '!')))
++p;
else
p = from;
@@ -310,6 +333,7 @@ junkmail()
* find out if user has gotten a vacation message recently.
* use bcopy for machines with alignment restrictions
*/
+static int
recent()
{
DBT key, data;
@@ -319,7 +343,7 @@ recent()
key.data = VIT;
key.size = sizeof(VIT);
if ((db->get)(db, &key, &data, 0))
- next = SECSPERDAY * DAYSPERWEEK;
+ next = 86400 * 7;
else
bcopy(data.data, &next, sizeof(next));
@@ -338,6 +362,7 @@ recent()
* setinterval --
* store the reply interval
*/
+static void
setinterval(interval)
time_t interval;
{
@@ -354,6 +379,7 @@ setinterval(interval)
* setreply --
* store that this user knows about the vacation.
*/
+static void
setreply()
{
DBT key, data;
@@ -371,6 +397,7 @@ setreply()
* sendmessage --
* exec sendmail to send the vacation file to sender
*/
+static void
sendmessage(myname)
char *myname;
{
@@ -397,11 +424,11 @@ sendmessage(myname)
dup2(pvect[0], 0);
close(pvect[0]);
close(pvect[1]);
- fclose(mfp);
+ close(fileno(mfp));
execl(_PATH_SENDMAIL, "sendmail", "-f", myname, from, NULL);
syslog(LOG_ERR, "vacation: can't exec %s: %s",
_PATH_SENDMAIL, strerror(errno));
- exit(1);
+ _exit(1);
}
close(pvect[0]);
sfp = fdopen(pvect[1], "w");
@@ -412,9 +439,48 @@ sendmessage(myname)
fclose(sfp);
}
+static void
usage()
{
- syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] login\n",
+ syslog(LOG_NOTICE, "uid %u: usage: vacation [-i [-rinterval]] [-l] [-a alias] login\n",
getuid());
exit(1);
}
+
+static void
+listdb()
+{
+ DBT key, data;
+ int rv;
+ time_t t;
+ char user[MAXLINE];
+
+ while((rv = db->seq(db, &key, &data, R_NEXT)) == 0) {
+ bcopy(key.data, user, key.size);
+ user[key.size] = '\0';
+ if (strcmp(user, VIT) == 0)
+ continue;
+ bcopy(data.data, &t, data.size);
+ printf("%-40s %-10s", user, ctime(&t));
+ }
+ if (rv == -1)
+ perror("IO error in database");
+}
+
+/*
+ * Is `c' a delimiting character for a recipient name?
+ */
+static int
+isdelim(c)
+ int c;
+{
+ /*
+ * NB: don't use setlocale() before, headers are supposed to
+ * consist only of ASCII (aka. C locale) characters.
+ */
+ if (isalnum(c))
+ return(0);
+ if (c == '_' || c == '-' || c == '.')
+ return(0);
+ return(1);
+}
diff --git a/usr.bin/vgrind/Makefile b/usr.bin/vgrind/Makefile
index 0bd4f00..5682b25 100644
--- a/usr.bin/vgrind/Makefile
+++ b/usr.bin/vgrind/Makefile
@@ -2,20 +2,26 @@
PROG= vfontedpr
SRCS= regexp.c vfontedpr.c
-MAN1= vgrind.0
-MAN5= vgrindefs.0
+MAN1= vgrind.1
+MAN5= vgrindefs.5
BINDIR= /usr/libexec
-CLEANFILES+=vgrindefs.src.db
+BIN2DIR=/usr/bin
+EXTRA= vgrindefs.src.db
+CLEANFILES+= ${EXTRA}
-beforeinstall:
+all: ${EXTRA}
+
+${EXTRA}: ${.CURDIR}/vgrindefs.src
cap_mkdb -f vgrindefs.src ${.CURDIR}/vgrindefs.src
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
- ${.CURDIR}/vgrind.sh ${DESTDIR}/usr/bin/vgrind
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/vgrindefs.src \
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/vgrind.sh ${DESTDIR}${BIN2DIR}/vgrind
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/vgrindefs.src \
${DESTDIR}/usr/share/misc/vgrindefs
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
vgrindefs.src.db ${DESTDIR}/usr/share/misc/vgrindefs.db
- install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/tmac.vgrind \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/tmac.vgrind \
${DESTDIR}/usr/share/tmac
.include <bsd.prog.mk>
diff --git a/usr.bin/vgrind/regexp.c b/usr.bin/vgrind/regexp.c
index 978af65..d606620 100644
--- a/usr.bin/vgrind/regexp.c
+++ b/usr.bin/vgrind/regexp.c
@@ -135,7 +135,7 @@ STRNCMP(s1, s2, len)
#define SNEXT(A) (A+2+*(A+1)) /* character following the string */
/*
- * bit flags in the descriptor
+ * bit flags in the descriptor
*/
#define OPT 1
#define STR 2
@@ -196,7 +196,7 @@ expconv()
*cs = STR;
SCNT(cs) = 1;
ccre += 2;
- } else
+ } else
SCNT(cs)++;
*ccre++ = c;
break;
@@ -209,7 +209,7 @@ expconv()
if (acs != NIL && acs != cs) {
do {
temp = OCNT(acs);
- OCNT(acs) = ccre - acs;
+ OCNT(acs) = ccre - acs;
acs -= temp;
} while (temp != 0);
acs = NIL;
@@ -221,7 +221,7 @@ expconv()
break;
}
break;
-
+
/* just put the symbol in */
case '^':
case '$':
@@ -263,7 +263,7 @@ expconv()
OCNT(cs) = ccre - cs; /* offset to next symbol */
break;
- /* reurn from a recursion */
+ /* return from a recursion */
case ')':
if (acs != NIL) {
do {
@@ -339,7 +339,7 @@ expconv()
* The irregular expression must be translated to internal form
* prior to calling this routine
*
- * The value returned is the pointer to the first non \a
+ * The value returned is the pointer to the first non \a
* character matched.
*/
@@ -458,7 +458,12 @@ expmatch (s, re, mstring)
/* not optional and we still matched */
return (NIL);
}
- if (!isalnum(*s1) && *s1 != '_')
+ if (!(isalnum(*s1) || *s1 == '_' ||
+ /* C++ destructor */
+ *s1 == '~' ||
+ /* C++ scope operator */
+ (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' &&
+ (s1++, TRUE))))
return (NIL);
if (*s1 == '\\')
_escaped = _escaped ? FALSE : TRUE;
@@ -501,7 +506,7 @@ expmatch (s, re, mstring)
case 'e':
if (_escaped)
return(NIL);
- cs = MNEXT(cs);
+ cs = MNEXT(cs);
break;
/* match any number of tabs and spaces */
@@ -513,12 +518,12 @@ expmatch (s, re, mstring)
/* match, be happy */
matched = 1;
- cs = MNEXT(cs);
+ cs = MNEXT(cs);
} else if (*s == '\n' || *s == '\0') {
/* match, be happy */
matched = 1;
- cs = MNEXT(cs);
+ cs = MNEXT(cs);
} else if (*cs & ALT) {
/* try the next part */
diff --git a/usr.bin/vgrind/vfontedpr.c b/usr.bin/vgrind/vfontedpr.c
index 30320c6..b471044 100644
--- a/usr.bin/vgrind/vfontedpr.c
+++ b/usr.bin/vgrind/vfontedpr.c
@@ -98,7 +98,7 @@ static char *defsfile[2] = { _PATH_VGRINDEFS, 0 };
/* name of language definitions file */
static int margin;
static int plstack[PSMAX]; /* the procedure nesting level stack */
-static char pname[BUFSIZ+1];
+static char pname[BUFSIZ+1];
static boolean prccont; /* continue last procedure */
static int psptr; /* the stack index of the current procedure */
static char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */
@@ -117,6 +117,7 @@ char *l_combeg; /* string introducing a comment */
char *l_comend; /* string ending a comment */
char l_escape; /* character used to escape characters */
char *l_keywds[BUFSIZ/2]; /* keyword table address */
+char *l_nocom; /* regexp for non-comments */
char *l_prcbeg; /* regular expr for procedure begin */
char *l_strbeg; /* delimiter for string constant */
char *l_strend; /* delimiter for string constant */
@@ -228,12 +229,12 @@ main(argc, argv)
if (i == -1) {
fprintf (stderr, "no entry for language %s\n", language);
exit (0);
- } else if (i == -2) { fprintf(stderr,
+ } else if (i == -2) { fprintf(stderr,
"cannot find vgrindefs file %s\n", defsfile[0]);
exit (0);
- } else if (i == -3) { fprintf(stderr,
- "potential reference loop detected in vgrindefs file %s\n",
- defsfile[0]);
+ } else if (i == -3) { fprintf(stderr,
+ "potential reference loop detected in vgrindefs file %s\n",
+ defsfile[0]);
exit(0);
}
if (cgetustr(defs, "kw", &cp) == -1)
@@ -274,6 +275,8 @@ main(argc, argv)
l_chrbeg = convexp(cp);
cgetustr(defs, "le", &cp);
l_chrend = convexp(cp);
+ if (cgetustr(defs, "nc", &cp) >= 0)
+ l_nocom = convexp(cp);
l_escape = '\\';
l_onecase = (cgetcap(defs, "oc", ':') != NULL);
l_toplex = (cgetcap(defs, "tl", ':') != NULL);
@@ -358,6 +361,7 @@ putScp(os)
char *chrptr; /* end of a character const delimiter */
char *blksptr; /* end of a lexical block start */
char *blkeptr; /* end of a lexical block end */
+ char *nocomptr; /* end of a non-comment delimiter */
_start = os; /* remember the start for expmatch */
_escaped = FALSE;
@@ -370,10 +374,10 @@ putScp(os)
if (psptr < PSMAX) {
++psptr;
strncpy (pstack[psptr], pname, PNAMELEN);
- pstack[psptr][PNAMELEN] = NULL;
+ pstack[psptr][PNAMELEN] = '\0';
plstack[psptr] = blklevel;
}
- }
+ }
skip:
do {
/* check for string, comment, blockstart, etc */
@@ -385,6 +389,17 @@ skip:
acmptr = expmatch (s, l_acmbeg, dummy);
strptr = expmatch (s, l_strbeg, dummy);
chrptr = expmatch (s, l_chrbeg, dummy);
+ nocomptr = expmatch (s, l_nocom, dummy);
+
+ /* start of non-comment? */
+ if (nocomptr != NIL)
+ if ((nocomptr <= comptr || comptr == NIL)
+ && (nocomptr <= acmptr || acmptr == NIL)) {
+ /* continue after non-comment */
+ putKcp (s, nocomptr-1, FALSE);
+ s = nocomptr;
+ continue;
+ }
/* start of a comment? */
if (comptr != NIL)
@@ -445,7 +460,8 @@ skip:
if (blkeptr < blksptr || blksptr == NIL) {
putKcp (s, blkeptr - 1, FALSE);
s = blkeptr;
- blklevel--;
+ if (blklevel > 0 /* sanity */)
+ blklevel--;
if (psptr >= 0 && plstack[psptr] >= blklevel) {
/* end of current procedure */
@@ -539,8 +555,8 @@ putKcp (start, end, force)
while (start <= end) {
if (idx) {
if (*start == ' ' || *start == '\t') {
- if (xfld == 0)
- printf("");
+ if (xfld == 0)
+ printf("\001");
printf("\t");
xfld = 1;
while (*start == ' ' || *start == '\t')
@@ -559,20 +575,20 @@ putKcp (start, end, force)
}
if (!nokeyw && !force)
- if ((*start == '#' || isidchr(*start))
+ if ((*start == '#' || isidchr(*start))
&& (start == _start || !isidchr(start[-1]))) {
i = iskw(start);
if (i > 0) {
ps("\\*(+K");
- do
- putcp(*start++);
+ do
+ putcp((unsigned char)*start++);
while (--i > 0);
ps("\\*(-K");
continue;
}
}
- putcp (*start++);
+ putcp ((unsigned char)*start++);
}
}
@@ -619,6 +635,9 @@ putcp(c)
case '\f':
break;
+ case '\r':
+ break;
+
case '{':
ps("\\*(+K{\\*(-K");
break;
diff --git a/usr.bin/vgrind/vgrind.1 b/usr.bin/vgrind/vgrind.1
index 97ba7e2..a866103 100644
--- a/usr.bin/vgrind/vgrind.1
+++ b/usr.bin/vgrind/vgrind.1
@@ -44,8 +44,9 @@
.Op Fl d Ar file
.Op Fl f
.Op Fl h Ar header
-.Op Fl l Ar language
+.Op Fl l Ns Ar language
.Op Fl n
+.Op Fl p Ar postproc
.Op Fl sn
.Op Fl t
.Op Fl x
@@ -87,9 +88,10 @@ or
.Pp
In regular mode
.Nm vgrind
-accepts input files, processes them, and passes them to
-.Xr troff 1
-for output.
+accepts input files, processes them, and passes them to the postprocessor
+for output,
+.Xr psroff 1
+by default.
.Pp
In both modes
.Nm vgrind
@@ -122,6 +124,8 @@ specifies the language to use. Currently known are
C
.Pf ( Fl l Ns Ar c
or the default),
+.Tn C++
+.Pq Fl l Ns Ar c++ ,
.Tn CSH
.Pq Fl l Ns Ar csh ,
.Tn SHELL
@@ -134,11 +138,19 @@ or the default),
.Pq Fl l Ns Ar yacc ,
.Tn LISP
.Pq Fl l Ns Ar isp ,
-and
.Tn ICON
-.Pq Fl l Ns Ar I .
+.Pq Fl l Ns Ar I ,
+and
+.Tn PERL
+.Pq Fl l Ns Ar perl .
.It Fl n
forces no keyword bolding
+.It Fl p Ar postproc
+use
+.Ar postproc
+to post-process the output,
+.Xr psroff 1
+by default.
.It Fl s
specifies a point size to use on output (exactly the same as the argument
of a .ps)
diff --git a/usr.bin/vgrind/vgrind.sh b/usr.bin/vgrind/vgrind.sh
index fc05461..ad459c5 100644
--- a/usr.bin/vgrind/vgrind.sh
+++ b/usr.bin/vgrind/vgrind.sh
@@ -41,6 +41,7 @@ set f=''
set head=""
set vf=/usr/libexec/vfontedpr
set tm=/usr/share/tmac
+set postproc=psroff
top:
if ($#argv > 0) then
switch ($1:q)
@@ -88,6 +89,17 @@ if ($#argv > 0) then
goto top
endif
+ case -p:
+ if ($#argv < 2) then
+ echo "vgrind: $1:q option must have argument"
+ goto done
+ else
+ set postproc="$2"
+ shift
+ shift
+ goto top
+ endif
+
case -*:
set options = "$options $1:q"
shift
@@ -116,10 +128,10 @@ if (-r index) then
else
if ("$head" != "") then
$vf $options -h "$head" $files | \
- sh -c "psroff -rx1 $voptions -i -mvgrind 2>> xindex"
+ sh -c "$postproc -rx1 $voptions -i -mvgrind 2>> xindex"
else
$vf $options $files | \
- sh -c "psroff -rx1 $voptions -i -mvgrind 2>> xindex"
+ sh -c "$postproc -rx1 $voptions -i -mvgrind 2>> xindex"
endif
endif
sort -df +0 -2 xindex >index
@@ -133,9 +145,9 @@ else
endif
else
if ("$head" != "") then
- $vf $options -h "$head" $files | psroff -i $voptions -mvgrind
+ $vf $options -h "$head" $files | $postproc -i $voptions -mvgrind
else
- $vf $options $files | psroff -i $voptions -mvgrind
+ $vf $options $files | $postproc -i $voptions -mvgrind
endif
endif
endif
diff --git a/usr.bin/vgrind/vgrindefs.5 b/usr.bin/vgrind/vgrindefs.5
index 4ac7522..9b65c2c 100644
--- a/usr.bin/vgrind/vgrindefs.5
+++ b/usr.bin/vgrind/vgrindefs.5
@@ -54,6 +54,8 @@ The following table names and describes each field.
.Pp
.Bl -column Namexxx Tpexxx
.Sy Name Type Description
+.It "ab str regular expression for the start of an alternate comment"
+.It "ae str regular expression for the end of an alternate comment"
.It "pb str regular expression for start of a procedure"
.It "bb str regular expression for start of a lexical block"
.It "be str regular expression for the end of a lexical block"
@@ -63,11 +65,20 @@ The following table names and describes each field.
.It "se str regular expression for the end of a string"
.It "lb str regular expression for the start of a character constant"
.It "le str regular expression for the end of a character constant"
+.It "nc str regular expression for a non-comment (see below)"
.It "tl bool present means procedures are only defined at the top lexical level"
.It "oc bool present means upper and lower case are equivalent"
.It "kw str a list of keywords separated by spaces"
.El
.Pp
+Non-comments are required to describe a certain context where a
+sequence that would normally start a comment loses its special
+meaning. A typical example for this can be found in Perl, where
+comments are normally starting with
+.Ql # ,
+while the string
+.Ql $#
+is an operator on an array.
.Sh EXAMPLES
The following entry, which describes the C language, is
typical of a language entry.
@@ -149,8 +160,8 @@ specified in lower case.
File containing terminal descriptions.
.El
.Sh SEE ALSO
-.Xr vgrind 1 ,
-.Xr troff 1
+.Xr troff 1 ,
+.Xr vgrind 1
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/vgrind/vgrindefs.src b/usr.bin/vgrind/vgrindefs.src
index 91ef58f..c19e836 100644
--- a/usr.bin/vgrind/vgrindefs.src
+++ b/usr.bin/vgrind/vgrindefs.src
@@ -33,7 +33,8 @@
#
C|c:\
- :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:cb=/*:ce=*/:sb=":se=\e":lb=':\
+ :pb=^\a?\d?*?\d?\p\d?\(\a?\)(\d|{):\
+ :bb={:be=}:cb=/*:ce=*/:sb=":se=\e":lb=':\
:le=\e':tl:\
:kw=asm auto break case char continue default do double else enum\
extern float for fortran goto if int long register return short\
@@ -134,7 +135,8 @@ yacc|Yacc|y:\
#else #endif #if #ifdef #ifndef #include #undef # define else endif\
if ifdef ifndef include undef:
C++|c++:\
- :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:cb=/*:ce=*/:ab=//:\
+ :pb=^\a?\d?*?\d?\p\d?\(\a?\)(\d|{):\
+ :bb={:be=}:cb=/*:ce=*/:ab=//:\
:ae=$:sb=":se=\e":lb=':\
:le=\e':tl:\
:kw=asm auto break case char continue default do double else enum\
@@ -144,3 +146,14 @@ C++|c++:\
ifdef ifndef include undef defined\
class const delete friend inline new operator overload private\
protected public virtual:
+#
+# Hack alert: defining function calls as `alternate comments' (ab/ae) seems
+# to be the only way to avoid major confusion inside vfontedpr for calls like:
+# &packagename'function;
+#
+Perl|perl|pl:\
+ :pb=sub\d\p\d:bb={:be=}:cb=#:ce=$:nc=\$#:tl:\
+ :ab=&:ae=(;|\d|,):\
+ :sb=":se=(\e"|$):lb=':le=(\e'|$):\
+ :kw=do if unless while until else elsif for foreach continue\
+ next redo sub last goto return die exit require:
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile
new file mode 100644
index 0000000..d05179d
--- /dev/null
+++ b/usr.bin/vi/Makefile
@@ -0,0 +1,202 @@
+#
+# $Id: Makefile,v 1.16 1997/04/12 14:34:02 peter Exp $
+#
+# This has most of the glue needed to compile tknvi and the perl hooks,
+# but not all.
+#
+
+SRCDIR= ${.CURDIR}/../../contrib/nvi
+
+.if defined(RELEASE_BUILD_FIXIT)
+# When building `vi' for the fixit floppy, don't include any of the
+# API stuff.
+APISTUFF= ex_notcl.c ex_noperl.c
+
+.else
+
+.if !defined(NOTCL)
+TCLINTERP= yes #we have it in the base tree, little cost to vi
+.endif
+#TKNVI= yes #not ready, needs X11, tk, doesn't quite work yet
+#PERLINTERP= yes #needs the perl5 v5.003 port
+
+APISTUFF= ex_tcl.c ex_perl.c
+
+# Any better ideas?
+#PERL= /usr/local/bin/perl5.003
+#CFLAGS+= -DHAVE_PERL_5_003_01 # If perl >= 5.03.01
+
+.endif
+
+CFLAGS+= -DGTAGS
+
+#if using ncurses:
+#CFLAGS+= -DSYSV_CURSES
+
+VI= nvi
+EX= nex
+VIEW= nview
+
+PROG= nvi
+
+LINKS= ${BINDIR}/${VI} ${BINDIR}/${EX} ${BINDIR}/${VI} ${BINDIR}/${VIEW}
+LINKS+= ${BINDIR}/${VI} ${BINDIR}/vi ${BINDIR}/${EX} ${BINDIR}/ex
+LINKS+= ${BINDIR}/${VI} ${BINDIR}/view
+
+MAN1= ${SRCDIR}/docs/USD.doc/vi.man/vi.1
+MLINKS+=vi.1 ex.1 vi.1 view.1
+MLINKS+=vi.1 nex.1 vi.1 nview.1 vi.1 nvi.1
+
+CATALOGS= dutch english french german ru_SU.KOI8-R spanish swedish
+NLLINKS= nl_NL
+ENLINKS= en_AU en_CA en_GB en_US
+FRLINKS= fr_BE fr_CA fr_CH fr_FR
+DELINKS= de_AT de_CH de_DE
+ESLINKS= es_ES
+SVLINKS= sv_SE
+
+.PATH: ${SRCDIR}/common
+.PATH: ${SRCDIR}/ex
+.PATH: ${SRCDIR}/cl
+.PATH: ${SRCDIR}/vi
+
+CFLAGS+=-I${.CURDIR} -I${SRCDIR} -I${SRCDIR}/include
+
+.if !defined(TKNVI)
+DPADD+= ${LIBCURSES} ${LIBTERMCAP}
+LDADD+= -lcurses -ltermcap
+.endif
+
+.if defined(TKNVI)
+.PATH: ${SRCDIR}/tk
+LDADD+= -L/usr/local/lib -L/usr/X11R6/lib -ltk41 -lX11
+CFLAGS+= -I/usr/local/include -I/usr/X11R6/include
+.endif
+
+.if defined(TCLINTERP)
+.PATH: ${SRCDIR}/tcl_api
+DPADD+= ${LIBTCL} ${LIBM}
+LDADD+= -ltcl -lm
+CFLAGS+= -DHAVE_TCL_INTERP
+.endif
+
+.if defined(PERLINTERP)
+.PATH: ${SRCDIR}/perl_api
+
+# Perl "knows" how to compile it's components. Ask it for details...
+PERLLIB!= ${PERL} -MConfig -e 'print $$Config{privlib}'
+PERLCPPFLAGS!= cd ${SRCDIR}/build; ${PERL} -MExtUtils::Embed -e 'ccflags;perl_inc'
+PERLLIBS!= cd ${SRCDIR}/build; ${PERL} -MExtUtils::Embed -e 'ldopts'
+PERLLDFLAGS!= cd ${SRCDIR}/build; ${PERL} -MExtUtils::Embed -e 'ccdlflags'
+
+LDADD+= ${PERLLDFLAGS} ${PERLLIBS}
+CFLAGS+= -DHAVE_PERL_INTERP ${PERLCPPFLAGS}
+
+.endif
+
+CLEANFILES+=${EX}
+
+# Vi curses sources
+.if !defined(TKNVI)
+SRCS+= cl_bsd.c cl_funcs.c cl_main.c cl_read.c cl_screen.c cl_term.c
+.endif
+
+# Vi Tk sources
+.if defined(TKNVI)
+SRCS+= tk_funcs.c tk_main.c tk_read.c tk_screen.c tk_term.c tk_util.c
+.endif
+
+# Vi Tcl/Perl interpreter sources
+.if defined(TCLINTERP) || defined(PERLINTERP)
+SRCS+= api.c
+.endif
+.if defined(TCLINTERP)
+SRCS+= tcl.c
+.endif
+.if defined(PERLINTERP)
+# perl.c is generated
+SRCS+= perl.c perlsfio.c
+.endif
+
+# General sources.
+SRCS+= cut.c delete.c exf.c key.c line.c log.c main.c mark.c msg.c options.c \
+ options_f.c put.c screen.c search.c seq.c recover.c util.c
+
+# Ex source.
+SRCS+= ex.c ex_abbrev.c ex_append.c ex_args.c ex_argv.c ex_at.c ex_bang.c \
+ ex_cd.c ex_cmd.c ex_cscope.c ex_delete.c ex_display.c \
+ ex_edit.c ex_equal.c ex_file.c ex_filter.c ex_global.c \
+ ex_init.c ex_join.c ex_map.c ex_mark.c ex_mkexrc.c ex_move.c \
+ ex_open.c ex_preserve.c ex_print.c ex_put.c ex_quit.c \
+ ex_read.c ex_screen.c ex_script.c ex_set.c ex_shell.c \
+ ex_shift.c ex_source.c ex_stop.c ex_subst.c ex_tag.c \
+ ex_txt.c ex_undo.c ex_usage.c ex_util.c ex_version.c ex_visual.c \
+ ex_write.c ex_yank.c ex_z.c ${APISTUFF}
+
+# Vi source.
+SRCS+= getc.c v_at.c v_ch.c v_cmd.c v_delete.c v_ex.c v_increment.c v_init.c \
+ v_itxt.c v_left.c v_mark.c v_match.c v_paragraph.c v_put.c v_redraw.c \
+ v_replace.c v_right.c v_screen.c v_scroll.c v_search.c v_section.c \
+ v_sentence.c v_status.c v_txt.c v_ulcase.c v_undo.c \
+ v_util.c v_word.c v_xchar.c v_yank.c v_z.c v_zexit.c vi.c
+
+# Vi screen source.
+SRCS+= vs_line.c vs_msg.c vs_refresh.c vs_relative.c vs_smap.c vs_split.c
+
+# Generate perl.c
+.if defined(PERLINTERP)
+perl.c: perl.xs typemap
+ echo "#define _PATH_PERLSCRIPTS \"/usr/share/vi/perl\"" > $@
+ $(PERL) $(PERLLIB)/ExtUtils/xsubpp -typemap \
+ $(PERLLIB)/ExtUtils/typemap $(SRCDIR)/perl_api/perl.xs >> $@
+ ($(PERL) -ne 'print "sub $$1 {\$$curscr->$$1(\@_)}\n" \
+ if /newXS\("VI::([^":]*)"/;' $@ ; echo "1;") > VI.pm
+
+CLEANFILES+= VI.pm perl.c
+.endif
+
+# unifdef has some *weird* exit codes, sigh! RTFM unifdef(1)...
+ex_notcl.c: ex_tcl.c
+ -unifdef -UHAVE_TCL_INTERP ${SRCDIR}/ex/ex_tcl.c > ${.TARGET}
+
+ex_noperl.c: ex_perl.c
+ -unifdef -UHAVE_PERL_INTERP ${SRCDIR}/ex/ex_perl.c > ${.TARGET}
+
+CLEANFILES+= ex_notcl.c ex_noperl.c
+
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${CATALOGS:S;^;${SRCDIR}/catalog/;} \
+ ${DESTDIR}/usr/share/vi/catalog
+ for l in ${NLLINKS}; do \
+ ln -fs dutch ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ for l in ${ENLINKS}; do \
+ ln -fs english ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ ln -fs english ${DESTDIR}/usr/share/vi/catalog/us-ascii
+ for l in ${FRLINKS}; do \
+ ln -fs french ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ for l in ${DELINKS}; do \
+ ln -fs german ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ for l in ${ESLINKS}; do \
+ ln -fs spanish ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ for l in ${SVLINKS}; do \
+ ln -fs swedish ${DESTDIR}/usr/share/vi/catalog/$$l.ISO_8859-1; \
+ done
+ ln -fs ru_SU.KOI8-R ${DESTDIR}/usr/share/vi/catalog/ru_RU.KOI8-R
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${SRCDIR}/tcl_scripts/*.tcl \
+ ${DESTDIR}/usr/share/vi/tcl
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${SRCDIR}/perl_scripts/*.pl \
+ ${DESTDIR}/usr/share/vi/perl
+.if defined(PERLINTERP)
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 VI.pm \
+ ${DESTDIR}/usr/share/vi/perl
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/vi/config.h b/usr.bin/vi/config.h
new file mode 100644
index 0000000..5a867f1
--- /dev/null
+++ b/usr.bin/vi/config.h
@@ -0,0 +1,194 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define if your struct stat has st_blksize. */
+#define HAVE_ST_BLKSIZE 1
+
+/* Define if you have <vfork.h>. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if your <sys/time.h> declares struct tm. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define vfork as fork if vfork does not work. */
+/* #undef vfork */
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef ssize_t */
+
+/* Define if you want a debugging version. */
+/* #undef DEBUG */
+
+/* Define if you have a System V-style (broken) gettimeofday. */
+/* #undef HAVE_BROKEN_GETTIMEOFDAY */
+
+/* Define if you have a Ultrix-style (broken) vdisable. */
+/* #undef HAVE_BROKEN_VDISABLE */
+
+/* Define if you have a BSD version of curses. */
+#ifndef SYSV_CURSES
+#define HAVE_BSD_CURSES 1
+#endif
+
+/* Define if you have the curses(3) addnstr function. */
+#define HAVE_CURSES_ADDNSTR 1
+
+/* Define if you have the curses(3) beep function. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_BEEP 1
+#endif
+
+/* Define if you have the curses(3) flash function. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_FLASH 1
+#endif
+
+/* Define if you have the curses(3) idlok function. */
+#define HAVE_CURSES_IDLOK 1
+
+/* Define if you have the curses(3) keypad function. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_KEYPAD 1
+#endif
+
+/* Define if you have the curses(3) newterm function. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_NEWTERM 1
+#endif
+
+/* Define if you have the curses(3) setupterm function. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_SETUPTERM 1
+#endif
+
+/* Define if you have the curses(3) tigetstr/tigetnum functions. */
+#ifdef SYSV_CURSES
+#define HAVE_CURSES_TIGETSTR 1
+#endif
+
+/* Define if you have the chsize(2) system call. */
+/* #undef HAVE_FTRUNCATE_CHSIZE */
+
+/* Define if you have the ftruncate(2) system call. */
+#define HAVE_FTRUNCATE_FTRUNCATE 1
+
+/* Define if you have fcntl(2) style locking. */
+/* #undef HAVE_LOCK_FCNTL */
+
+/* Define if you have flock(2) style locking. */
+#define HAVE_LOCK_FLOCK 1
+
+/* Define if you want to compile in the Perl interpreter. */
+/* #undef HAVE_PERL_INTERP */ /* XXX: SET IN Makefile CFLAGS */
+
+/* Define if your Perl is at least 5.003_01. */
+/* #undef HAVE_PERL_5_003_01 */ /* XXX: SET IN Makefile CFLAGS */
+
+/* Define if you have the Berkeley style revoke(2) system call. */
+#define HAVE_REVOKE 1
+
+/* Define if you have <sys/mman.h> */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define if you have <sys/select.h> */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the System V style pty calls. */
+/* #undef HAVE_SYS5_PTY */
+
+/* Define if you want to compile in the Tcl interpreter. */
+/* #define HAVE_TCL_INTERP */ /* XXX: SET IN Makefile CFLAGS */
+
+/* Define if your sprintf returns a pointer, not a length. */
+/* #undef SPRINTF_RET_CHARPNT */
+
+/* Define if you have the bsearch function. */
+#define HAVE_BSEARCH 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getopt function. */
+#define HAVE_GETOPT 1
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the memchr function. */
+#define HAVE_MEMCHR 1
+
+/* Define if you have the memcpy function. */
+#define HAVE_MEMCPY 1
+
+/* Define if you have the memmove function. */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the memset function. */
+#define HAVE_MEMSET 1
+
+/* Define if you have the mkstemp function. */
+#define HAVE_MKSTEMP 1
+
+/* Define if you have the mmap function. */
+#define HAVE_MMAP 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setenv function. */
+#define HAVE_SETENV 1
+
+/* Define if you have the snprintf function. */
+#define HAVE_SNPRINTF 1
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strpbrk function. */
+#define HAVE_STRPBRK 1
+
+/* Define if you have the strsep function. */
+#define HAVE_STRSEP 1
+
+/* Define if you have the strtol function. */
+#define HAVE_STRTOL 1
+
+/* Define if you have the strtoul function. */
+#define HAVE_STRTOUL 1
+
+/* Define if you have the unsetenv function. */
+#define HAVE_UNSETENV 1
+
+/* Define if you have the valloc function. */
+#define HAVE_VALLOC 1
+
+/* Define if you have the vsnprintf function. */
+#define HAVE_VSNPRINTF 1
diff --git a/usr.bin/vi/pathnames.h b/usr.bin/vi/pathnames.h
new file mode 100644
index 0000000..f469351
--- /dev/null
+++ b/usr.bin/vi/pathnames.h
@@ -0,0 +1,45 @@
+/* @(#)pathnames.h.in 8.4 (Berkeley) 6/26/96 */
+
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef _PATH_EXRC
+#define _PATH_EXRC ".exrc"
+#endif
+
+#ifndef _PATH_MSGCAT
+#define _PATH_MSGCAT "/usr/share/vi/catalog/"
+#endif
+
+#ifndef _PATH_NEXRC
+#define _PATH_NEXRC ".nexrc"
+#endif
+
+#ifndef _PATH_PRESERVE
+#define _PATH_PRESERVE "/var/tmp/vi.recover"
+#endif
+
+#ifndef _PATH_SYSV_PTY
+#define _PATH_SYSV_PTY "/dev/ptmx"
+#endif
+
+#ifndef _PATH_SENDMAIL
+#define _PATH_SENDMAIL "/usr/sbin/sendmail"
+#endif
+
+#ifndef _PATH_SYSEXRC
+#define _PATH_SYSEXRC "/etc/vi.exrc"
+#endif
+
+#ifndef _PATH_TAGS
+#define _PATH_TAGS "tags"
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp"
+#endif
+
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
diff --git a/usr.bin/vi/port.h b/usr.bin/vi/port.h
new file mode 100644
index 0000000..21f16c9
--- /dev/null
+++ b/usr.bin/vi/port.h
@@ -0,0 +1,185 @@
+/* @(#)port.h.in 8.13 (Berkeley) 6/12/96 */
+
+/*
+ * Declare the basic types, if they aren't already declared. Named and
+ * some system's db.h files protect them with __BIT_TYPES_DEFINED__.
+ */
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+
+
+
+
+#endif
+
+
+
+
+
+
+/*
+ * XXX
+ * Handle function prototypes. This steps on name space that vi doesn't
+ * control, but all of the other solutions are worse.
+ */
+#undef __P
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* ANSI C prototypes */
+#else
+#define __P(protos) () /* K&R C preprocessor */
+#endif
+
+/*
+ * XXX
+ * Some versions of System V changed the number of arguments to gettimeofday
+ * without changing the name.
+ */
+#ifdef HAVE_BROKEN_GETTIMEOFDAY
+#define gettimeofday(tv, tz) gettimeofday(tv)
+#endif
+
+/*
+ * XXX
+ * If we don't have mmap, we fake it with read and write, but we'll
+ * still need the header information.
+ */
+#ifndef HAVE_SYS_MMAN_H
+#define MAP_SHARED 1 /* share changes */
+#define MAP_PRIVATE 2 /* changes are private */
+#define PROT_READ 0x1 /* pages can be read */
+#define PROT_WRITE 0x2 /* pages can be written */
+#define PROT_EXEC 0x4 /* pages can be executed */
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.1 names for file descriptors.
+ */
+#ifndef STDERR_FILENO
+#define STDIN_FILENO 0 /* ANSI C #defines */
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.1 names for seek settings.
+ */
+#ifndef SEEK_END
+#define SEEK_SET 0 /* POSIX 1003.1 seek values */
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+/*
+ * Hack _POSIX_VDISABLE to \377 since Ultrix doesn't honor _POSIX_VDISABLE
+ * (treats it as ^@). The symptom is that the ^@ keystroke immediately
+ * drops core.
+ */
+#ifdef HAVE_BROKEN_VDISABLE
+#undef _POSIX_VDISABLE
+#define _POSIX_VDISABLE ((unsigned char)'\377')
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.1 tty disabling character.
+ */
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE 0 /* Some systems used 0. */
+#endif
+
+/*
+ * XXX
+ * 4.4BSD extension to only set the software termios bits.
+ */
+#ifndef TCSASOFT /* 4.4BSD extension. */
+#define TCSASOFT 0
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.1 maximum path length.
+ */
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else
+#define MAXPATHLEN 1024
+#endif
+#endif
+
+/*
+ * XXX
+ * MIN, MAX, historically in <sys/param.h>
+ */
+#ifndef MAX
+#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a))
+#endif
+#ifndef MIN
+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+#endif
+
+/*
+ * XXX
+ * "DB" isn't always portable, and we want the private information.
+ */
+#define DB L__DB
+#undef pgno_t /* IRIX has its own version. */
+#define pgno_t L__db_pgno_t
+
+/*
+ * XXX
+ * 4.4BSD extension to provide lock values in the open(2) call.
+ */
+#ifndef O_EXLOCK
+#define O_EXLOCK 0
+#endif
+
+#ifndef O_SHLOCK
+#define O_SHLOCK 0
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.1 bad file format errno.
+ */
+#ifndef EFTYPE
+#define EFTYPE EINVAL
+#endif
+
+/*
+ * XXX
+ * POSIX 1003.2 RE length limit.
+ */
+#ifndef _POSIX2_RE_DUP_MAX
+#define _POSIX2_RE_DUP_MAX 255
+#endif
+
+/*
+ * XXX
+ * 4.4BSD extension to determine if a program dropped core from the exit
+ * status.
+ */
+#ifndef WCOREDUMP
+#define WCOREDUMP(a) 0
+#endif
+
+/*
+ * XXX
+ * Endian-ness of the machine.
+ */
+#if !defined(LITTLE_ENDIAN)
+#define LITTLE_ENDIAN 1234
+#endif
+#if !defined(BIG_ENDIAN)
+#define BIG_ENDIAN 4321
+#endif
+#if !defined(BYTE_ORDER)
+#if WORDS_BIGENDIAN == 1
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#endif
diff --git a/usr.bin/vis/foldit.c b/usr.bin/vis/foldit.c
index 2682e85..86f360c 100644
--- a/usr.bin/vis/foldit.c
+++ b/usr.bin/vis/foldit.c
@@ -65,7 +65,7 @@ again:
printf("\\\n");
col = 0;
goto again;
- }
+ }
cp++;
}
return (col);
diff --git a/usr.bin/vis/vis.1 b/usr.bin/vis/vis.1
index 784e56c..6adb4e0 100644
--- a/usr.bin/vis/vis.1
+++ b/usr.bin/vis/vis.1
@@ -101,6 +101,7 @@ an invertible version of the
.Xr fold 1
utility. That is, the output
can be unfolded by running the output through
+.Xr unvis 1 .
.It Fl o
Request a format which displays non-printable characters as
an octal number, \eddd.
@@ -108,7 +109,6 @@ an octal number, \eddd.
Only characters considered unsafe to send to a terminal are encoded.
This flag allows backspace, bell, and carriage return in addition
to the default space, tab and newline.
-.Xr unvis 1 .
.It Fl t
Tabs are also encoded.
.It Fl w
@@ -120,5 +120,5 @@ White space (space-tab-newline) is also encoded.
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/vis/vis.c b/usr.bin/vis/vis.c
index 94c9d41..93bda20 100644
--- a/usr.bin/vis/vis.c
+++ b/usr.bin/vis/vis.c
@@ -43,10 +43,11 @@ static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 6/6/93";
#include <stdio.h>
#include <vis.h>
+#include <locale.h>
int eflags, fold, foldwidth=80, none, markeol, debug;
-main(argc, argv)
+main(argc, argv)
char *argv[];
{
extern char *optarg;
@@ -55,7 +56,9 @@ main(argc, argv)
FILE *fp;
int ch;
- while ((ch = getopt(argc, argv, "nwctsobfF:ld")) != EOF)
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "nwctsobfF:ld")) != -1)
switch((char)ch) {
case 'n':
none++;
@@ -80,7 +83,7 @@ main(argc, argv)
break;
case 'F':
if ((foldwidth = atoi(optarg))<5) {
- fprintf(stderr,
+ fprintf(stderr,
"vis: can't fold lines to less than 5 cols\n");
exit(1);
}
@@ -98,7 +101,7 @@ main(argc, argv)
#endif
case '?':
default:
- fprintf(stderr,
+ fprintf(stderr,
"usage: vis [-nwctsobf] [-F foldwidth]\n");
exit(1);
}
@@ -118,17 +121,17 @@ main(argc, argv)
process(stdin, "<stdin>");
exit(0);
}
-
+
process(fp, filename)
FILE *fp;
char *filename;
{
static int col = 0;
register char *cp = "\0"+1; /* so *(cp-1) starts out != '\n' */
- register int c, rachar;
+ register int c, rachar;
register char nc;
char buff[5];
-
+
c = getc(fp);
while (c != EOF) {
rachar = getc(fp);
@@ -145,7 +148,7 @@ process(fp, filename)
*cp++ = '$';
*cp++ = '\n';
*cp = '\0';
- } else
+ } else
(void) vis(buff, (char)c, eflags, (char)rachar);
cp = buff;
diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile
index 8e1a860..117c30d 100644
--- a/usr.bin/vmstat/Makefile
+++ b/usr.bin/vmstat/Makefile
@@ -1,11 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= vmstat
-CFLAGS+=-I/sys
-MAN8= vmstat.0
+CFLAGS+=-I${.CURDIR}/../../sys
+MAN8= vmstat.8
BINGRP= kmem
BINMODE=2555
-DPADD= names.c ${LIBKVM}
+DPADD= ${LIBKVM}
LDADD= -lkvm
.include <bsd.prog.mk>
diff --git a/usr.bin/vmstat/names.c b/usr.bin/vmstat/names.c
index ba16804..90c95f9 100644
--- a/usr.bin/vmstat/names.c
+++ b/usr.bin/vmstat/names.c
@@ -34,10 +34,39 @@
*/
#if !defined(hp300) && !defined(tahoe) && !defined(vax) && \
- !defined(luna68k) && !defined(mips)
+ !defined(luna68k) && !defined(mips) && !defined(i386)
char *defdrives[] = { 0 };
#endif
+#if defined(i386)
+/*
+ * i386 support added by Rodney W. Grimes.
+ */
+#include <i386/isa/isa_device.h>
+
+char *defdrives[] = { "wd0", "wd1", "sd0", "sd1" };
+
+int
+read_names()
+{
+ u_long dk_names;
+ static char thenames[DK_NDRIVE][DK_NAMELEN];
+ int i;
+
+ dk_names = namelist[X_DK_NAMES].n_value;
+ if (dk_names == 0) {
+ warnx("disk name info not in namelist");
+ return(0);
+ }
+
+ kvm_read(kd, dk_names, thenames, sizeof thenames);
+ for(i = 0; thenames[i][0]; i++) {
+ dr_name[i] = thenames[i];
+ }
+ return(1);
+}
+#endif /* i386 */
+
#if defined(hp300) || defined(luna68k)
#if defined(hp300)
#include <hp/dev/device.h>
diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8
index d2eb074..ca6eb41 100644
--- a/usr.bin/vmstat/vmstat.8
+++ b/usr.bin/vmstat/vmstat.8
@@ -31,176 +31,189 @@
.\"
.\" @(#)vmstat.8 8.1 (Berkeley) 6/6/93
.\"
-.TH VMSTAT 1 "June 6, 1993"
-.UC 4
-.SH NAME
-vmstat \- report virtual memory statistics
-.SH SYNOPSIS
-.nf
-.ft B
-vmstat [ \-fimst ] [ \-c count ] [ \-M core ] [ \-N system ]
-.ti +5
-[ \-w wait ] [ disks ]
-.ft R
-.fi
-.SH DESCRIPTION
-.I Vmstat
+.Dd June 6, 1996
+.Dt VMSTAT 8
+.Os BSD 4
+.Sh NAME
+.Nm vmstat
+.Nd report virtual memory statistics
+.Sh SYNOPSIS
+.Nm vmstat
+.Op Fl fimst
+.Op Fl c Ar count
+.Op Fl M core
+.Op Fl N system
+.Op Fl w wait
+.Op Ar disks
+.Sh DESCRIPTION
+.Nm Vmstat
reports certain kernel statistics kept about process, virtual memory,
disk, trap and cpu activity.
-.PP
+.Pp
The options are as follows:
-.TP
-\-c
+.Bl -tag -width indent
+.It Fl c
Repeat the display
-.I count
+.Ar count
times.
The first display is for the time since a reboot and each subsequent report
is for the time period since the last display.
If no
-.I wait
+.Ar wait
interval is specified, the default is 1 second.
-.TP
-\-f
-Report on the number
-.IR fork (2)
-and
-.IR vfork (2)
-system calls since system startup, and the number of pages of virtual memory
-involved in each.
-.TP
-\-i
+.\" .It Fl f
+.\" Report on the number
+.\" .Xr fork 2
+.\" and
+.\" .Xr vfork 2
+.\" system calls since system startup, and the number of pages of virtual memory
+.\" involved in each.
+.It Fl i
Report on the number of interrupts taken by each device since system
startup.
-.TP
-\-M
-Extract values associated with the name list from the specified core
-instead of the default ``/dev/kmem''.
-.TP
-\-N
-Extract the name list from the specified system instead of the default
-``/vmunix''.
-.TP
-\-m
+.It Fl M
+Extract values associated with the name list from the specified
+.Ar core
+instead of the default
+.Pa /dev/kmem .
+.It Fl N
+Extract the name list from the specified
+.Ar system
+instead of the default
+.Pa /kernel .
+.It Fl m
Report on the usage of kernel dynamic memory listed first by size of
allocation and then by type of usage.
-.TP
-\-s
+.It Fl s
Display the contents of the
-.I sum
+.Em sum
structure, giving the total number of several kinds of paging related
events which have occurred since system startup.
-.TP
-\-t
-Report on the number of page in and page reclaims since system startup,
-and the amount of time required by each.
-.TP
-\-w
+.\" .It Fl t
+.\" Report on the number of page in and page reclaims since system startup,
+.\" and the amount of time required by each.
+.It Fl w
Pause
-.I wait
+.Ar wait
seconds between each display.
If no repeat
-.I count
+.Ar count
is specified, the default is infinity.
-.PP
+.El
+.Pp
By default,
-.I vmstat
+.Nm vmstat
displays the following information:
-.PP
-.TP
-procs
+.Pp
+.Bl -tag -width indent
+.It procs
Information about the numbers of processes in various states.
-.sp
-.RS
-.nf
-r in run queue
-b blocked for resources (i/o, paging, etc.)
-w runnable or short sleeper (< 20 secs) but swapped
-.fi
-.RE
-.TP
-memory
+.Pp
+.Bl -tag -width indent -compact
+.It r
+in run queue
+.It b
+blocked for resources (i/o, paging, etc.)
+.It w
+runnable or short sleeper (< 20 secs) but swapped
+.El
+.It memory
Information about the usage of virtual and real memory.
Virtual pages (reported in units of 1024 bytes) are considered active if
they belong to processes which are running or have run in the last 20
seconds.
-.sp
-.RS
-.nf
-avm active virtual pages
-fre size of the free list
-.fi
-.RE
-.TP
-page
+.Pp
+.Bl -tag -width indent -compact
+.It avm
+active virtual pages
+.It fre
+size of the free list
+.El
+.It page
Information about page faults and paging activity.
These are averaged each five seconds, and given in units per second.
-.sp
-.RS
-.nf
-re page reclaims (simulating reference bits)
-at pages attached (found in free list)
-pi pages paged in
-po pages paged out
-fr pages freed per second
-de anticipated short term memory shortfall
-sr pages scanned by clock algorithm, per-second
-.fi
-.RE
-.TP
-disks
+.Pp
+.Bl -tag -width indent -compact
+.It flt
+total number of page faults
+.It re
+page reclaims (simulating reference bits)
+.\" .It at
+.\" pages attached (found in free list)
+.It pi
+pages paged in
+.It po
+pages paged out
+.It fr
+pages freed per second
+.\" .It de
+.\" anticipated short term memory shortfall
+.It sr
+pages scanned by clock algorithm, per-second
+.El
+.It disks
Disk operations per second (this field is system dependent).
Typically paging will be split across the available drives.
The header of the field is the first character of the disk name and
the unit number.
If more than four disk drives are configured in the system,
-.I vmstat
+.Nm vmstat
displays only the first four drives.
To force
-.I vmstat
+.Nm vmstat
to display specific drives, their names may be supplied on the command line.
-.TP
-faults
+.It faults
Trap/interrupt rate averages per second over last 5 seconds.
-.sp
-.RS
-.nf
-in device interrupts per interval (including clock interrupts)
-sy system calls per interval
-cs cpu context switch rate (switches/interval)
-.fi
-.RE
-.TP
-cpu
+.Pp
+.Bl -tag -width indent -compact
+.It in
+device interrupts per interval (including clock interrupts)
+.It sy
+system calls per interval
+.It cs
+cpu context switch rate (switches/interval)
+.El
+.It cpu
Breakdown of percentage usage of CPU time.
-.sp
-.RS
-.nf
-us user time for normal and low priority processes
-sy system time
-id cpu idle
-.fi
-.RE
-.SH EXAMPLES
-The command ``vmstat -i 5'' will print what the system is doing every five
+.Pp
+.Bl -tag -width indent -compact
+.It us
+user time for normal and low priority processes
+.It sy
+system time
+.It id
+cpu idle
+.El
+.El
+.Sh EXAMPLES
+The command:
+.Dl vmstat -w 5
+will print what the system is doing every five
seconds; this is a good choice of printing interval since this is how often
some of the statistics are sampled in the system.
Others vary every second and running the output for a while will make it
apparent which are recomputed every second.
-.SH FILES
-.ta \w'/dev/kmem 'u
-/vmunix default kernel namelist
-.br
-/dev/kmem default memory file
-.SH SEE ALSO
-.IR fstat (1),
-.IR netstat (1),
-.IR nfsstat (1),
-.IR ps (1),
-.IR systat (1),
-.IR iostat (8),
-.IR pstat (8)
-.sp
+.Sh FILES
+.Bl -tag -width /dev/kmemxxx -compact
+.It Pa /kernel
+default kernel namelist
+.It Pa /dev/kmem
+default memory file
+.El
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr netstat 1 ,
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr systat 1 ,
+.Xr iostat 8 ,
+.Xr pstat 8
+.Pp
The sections starting with ``Interpreting system activity'' in
-.IR "Installing and Operating 4.3BSD" .
+.%T "Installing and Operating 4.3BSD" .
.SH BUGS
-The \-c and \-w options are only available with the default output.
+The
+.Fl c
+and
+.Fl w
+options are only available with the default output.
diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c
index 92c0dad..fe363a2 100644
--- a/usr.bin/vmstat/vmstat.c
+++ b/usr.bin/vmstat/vmstat.c
@@ -38,22 +38,25 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
+static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
-#include <sys/user.h>
#include <sys/dkstat.h>
#include <sys/buf.h>
+#include <sys/uio.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/signal.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
-#include <vm/vm.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm_param.h>
+
#include <time.h>
#include <nlist.h>
#include <kvm.h>
@@ -66,7 +69,6 @@ static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
#include <paths.h>
#include <limits.h>
-#define NEWVM /* XXX till old has been updated or purged */
struct nlist namelist[] = {
#define X_CPTIME 0
{ "_cp_time" },
@@ -107,7 +109,7 @@ struct nlist namelist[] = {
{ "_pgintime" },
#define X_XSTATS 18
{ "_xstats" },
-#define X_END 18
+#define X_END 19
#else
#define X_END 14
#endif
@@ -115,6 +117,10 @@ struct nlist namelist[] = {
#define X_HPDINIT (X_END)
{ "_hp_dinit" },
#endif
+#if defined(i386)
+#define X_DK_NAMES (X_END)
+ { "_dk_names" },
+#endif
#ifdef mips
#define X_SCSI_DINIT (X_END)
{ "_scsi_dinit" },
@@ -178,7 +184,7 @@ main(argc, argv)
memf = nlistf = NULL;
interval = reps = todo = 0;
- while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != EOF) {
+ while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != -1) {
switch (c) {
case 'c':
reps = atoi(optarg);
@@ -307,7 +313,7 @@ getdrivedata(argv)
char buf[30];
kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
- if (dk_ndrive <= 0) {
+ if (dk_ndrive < 0) {
(void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
exit(1);
}
@@ -420,29 +426,17 @@ dovmstat(interval, reps)
total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
#define pgtok(a) ((a) * sum.v_page_size >> 10)
#define rate(x) (((x) + halfuptime) / uptime) /* round */
- (void)printf("%6ld%6ld ",
+ (void)printf("%8ld%6ld ",
pgtok(total.t_avm), pgtok(total.t_free));
-#ifdef NEWVM
- (void)printf("%4lu ", rate(sum.v_faults - osum.v_faults));
+ (void)printf("%4lu ", rate(sum.v_vm_faults - osum.v_vm_faults));
(void)printf("%3lu ",
rate(sum.v_reactivated - osum.v_reactivated));
- (void)printf("%3lu ", rate(sum.v_pageins - osum.v_pageins));
- (void)printf("%3lu %3lu ",
- rate(sum.v_pageouts - osum.v_pageouts), 0);
-#else
- (void)printf("%3lu %2lu ",
- rate(sum.v_pgrec - (sum.v_xsfrec+sum.v_xifrec) -
- (osum.v_pgrec - (osum.v_xsfrec+osum.v_xifrec))),
- rate(sum.v_xsfrec + sum.v_xifrec -
- osum.v_xsfrec - osum.v_xifrec));
- (void)printf("%3lu ",
- rate(pgtok(sum.v_pgpgin - osum.v_pgpgin)));
- (void)printf("%3lu %3lu ",
- rate(pgtok(sum.v_pgpgout - osum.v_pgpgout)),
- rate(pgtok(sum.v_dfree - osum.v_dfree)));
- (void)printf("%3d ", pgtok(deficit));
-#endif
- (void)printf("%3lu ", rate(sum.v_scan - osum.v_scan));
+ (void)printf("%3lu ", rate(sum.v_swapin + sum.v_vnodein -
+ (osum.v_swapin + osum.v_vnodein)));
+ (void)printf("%3lu ", rate(sum.v_swapout + sum.v_vnodeout -
+ (osum.v_swapout + osum.v_vnodeout)));
+ (void)printf("%3lu ", rate(sum.v_tfree - osum.v_tfree));
+ (void)printf("%3lu ", rate(sum.v_pdpages - osum.v_pdpages));
dkstats();
(void)printf("%4lu %4lu %3lu ",
rate(sum.v_intr - osum.v_intr),
@@ -459,7 +453,10 @@ dovmstat(interval, reps)
* We round upward to avoid losing low-frequency events
* (i.e., >= 1 per interval but < 1 per second).
*/
- halfuptime = (uptime + 1) / 2;
+ if (interval != 1)
+ halfuptime = (uptime + 1) / 2;
+ else
+ halfuptime = 0;
(void)sleep(interval);
}
}
@@ -468,17 +465,13 @@ printhdr()
{
register int i;
- (void)printf(" procs memory page%*s", 20, "");
+ (void)printf(" procs memory page%*s", 20, "");
if (ndrives > 1)
(void)printf("disks %*s faults cpu\n",
ndrives * 3 - 6, "");
else
(void)printf("%*s faults cpu\n", ndrives * 3, "");
-#ifndef NEWVM
- (void)printf(" r b w avm fre re at pi po fr de sr ");
-#else
- (void)printf(" r b w avm fre flt re pi po fr sr ");
-#endif
+ (void)printf(" r b w avm fre flt re pi po fr sr ");
for (i = 0; i < dk_ndrive; i++)
if (dr_select[i])
(void)printf("%c%c ", dr_name[i][0],
@@ -538,9 +531,6 @@ void
dosum()
{
struct nchstats nchstats;
-#ifndef NEWVM
- struct xstats xstats;
-#endif
long nchtotal;
#if defined(tahoe)
struct keystats keystats;
@@ -555,61 +545,37 @@ dosum()
#endif
(void)printf("%9u traps\n", sum.v_trap);
(void)printf("%9u system calls\n", sum.v_syscall);
- (void)printf("%9u total faults taken\n", sum.v_faults);
- (void)printf("%9u swap ins\n", sum.v_swpin);
- (void)printf("%9u swap outs\n", sum.v_swpout);
- (void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
- (void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
- (void)printf("%9u page ins\n", sum.v_pageins);
- (void)printf("%9u page outs\n", sum.v_pageouts);
- (void)printf("%9u pages paged in\n", sum.v_pgpgin);
- (void)printf("%9u pages paged out\n", sum.v_pgpgout);
+ (void)printf("%9u swap pager pageins\n", sum.v_swapin);
+ (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
+ (void)printf("%9u swap pager pageouts\n", sum.v_swapout);
+ (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
+ (void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
+ (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
+ (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
+ (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
+ (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
+ (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
(void)printf("%9u pages reactivated\n", sum.v_reactivated);
+ (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
+ (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
- (void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
- (void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
- (void)printf("%9u pages examined by the clock daemon\n", sum.v_scan);
- (void)printf("%9u revolutions of the clock hand\n", sum.v_rev);
-#ifdef NEWVM
- (void)printf("%9u VM object cache lookups\n", sum.v_lookups);
- (void)printf("%9u VM object hits\n", sum.v_hits);
(void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
- (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
+ (void)printf("%9u pages freed\n", sum.v_tfree);
(void)printf("%9u pages freed by daemon\n", sum.v_dfree);
(void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
- (void)printf("%9u pages free\n", sum.v_free_count);
- (void)printf("%9u pages wired down\n", sum.v_wire_count);
(void)printf("%9u pages active\n", sum.v_active_count);
(void)printf("%9u pages inactive\n", sum.v_inactive_count);
+ (void)printf("%9u pages in VM cache\n", sum.v_cache_count);
+ (void)printf("%9u pages wired down\n", sum.v_wire_count);
+ (void)printf("%9u pages free\n", sum.v_free_count);
(void)printf("%9u bytes per page\n", sum.v_page_size);
- (void)printf("%9u target inactive pages\n", sum.v_inactive_target);
- (void)printf("%9u target free pages\n", sum.v_free_target);
- (void)printf("%9u minimum free pages\n", sum.v_free_min);
-#else
- (void)printf("%9u sequential process pages freed\n", sum.v_seqfree);
- (void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
- PCT(sum.v_fastpgrec, sum.v_pgrec));
- (void)printf("%9u reclaims from free list\n", sum.v_pgfrec);
- (void)printf("%9u executable fill pages created\n",
- sum.v_nexfod / CLSIZE);
- (void)printf("%9u executable fill page faults\n",
- sum.v_exfod / CLSIZE);
- (void)printf("%9u swap text pages found in free list\n",
- sum.v_xsfrec);
- (void)printf("%9u inode text pages found in free list\n",
- sum.v_xifrec);
- (void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
- (void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
- (void)printf("%9u pages freed by the clock daemon\n",
- sum.v_dfree / CLSIZE);
-#endif
kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
nchstats.ncs_badhits + nchstats.ncs_falsehits +
nchstats.ncs_miss + nchstats.ncs_long;
(void)printf("%9ld total name lookups\n", nchtotal);
(void)printf(
- "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
+ "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-directory\n",
"", PCT(nchstats.ncs_goodhits, nchtotal),
PCT(nchstats.ncs_neghits, nchtotal),
PCT(nchstats.ncs_pass2, nchtotal));
@@ -617,16 +583,6 @@ dosum()
PCT(nchstats.ncs_badhits, nchtotal),
PCT(nchstats.ncs_falsehits, nchtotal),
PCT(nchstats.ncs_long, nchtotal));
-#ifndef NEWVM
- kread(X_XSTATS, &xstats, sizeof(xstats));
- (void)printf("%9lu total calls to xalloc (cache hits %d%%)\n",
- xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
- (void)printf("%9s sticky %lu flushed %lu unused %lu\n", "",
- xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
- (void)printf("%9lu total calls to xfree", xstats.free);
- (void)printf(" (sticky %lu cached %lu swapped %lu)\n",
- xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
-#endif
#if defined(tahoe)
kread(X_CKEYSTATS, &keystats, sizeof(keystats));
(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
@@ -758,12 +714,16 @@ domem()
kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
(void)printf("Memory statistics by bucket size\n");
(void)printf(
- " Size In Use Free Requests HighWater Couldfree\n");
+ "Size In Use Free Requests HighWater Couldfree\n");
for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
if (kp->kb_calls == 0)
continue;
size = 1 << i;
- (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
+ if(size < 1024)
+ (void)printf("%4d",size);
+ else
+ (void)printf("%3dK",size>>10);
+ (void)printf(" %8ld %6ld %10ld %7ld %10ld\n",
kp->kb_total - kp->kb_totalfree,
kp->kb_totalfree, kp->kb_calls,
kp->kb_highwat, kp->kb_couldfree);
@@ -772,7 +732,7 @@ domem()
kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
(void)printf("\nMemory usage type by bucket size\n");
- (void)printf(" Size Type(s)\n");
+ (void)printf("Size Type(s)\n");
kp = &buckets[MINBUCKET];
for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
if (kp->kb_calls == 0)
@@ -786,11 +746,13 @@ domem()
continue;
name = kmemnames[i] ? kmemnames[i] : "undefined";
len += 2 + strlen(name);
- if (first)
- printf("%8d %s", j, name);
+ if (first && j < 1024)
+ printf("%4d %s", j, name);
+ else if (first)
+ printf("%3dK %s", j>>10, name);
else
printf(",");
- if (len >= 80) {
+ if (len >= 79) {
printf("\n\t ");
len = 10 + strlen(name);
}
@@ -802,13 +764,13 @@ domem()
}
(void)printf(
- "\nMemory statistics by type Type Kern\n");
+ "\nMemory statistics by type Type Kern\n");
(void)printf(
-" Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
+" Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
if (ks->ks_calls == 0)
continue;
- (void)printf("%11s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
+ (void)printf("%13s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
kmemnames[i] ? kmemnames[i] : "undefined",
ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
(ks->ks_maxused + 1023) / 1024,
@@ -819,9 +781,13 @@ domem()
if ((ks->ks_size & j) == 0)
continue;
if (first)
- printf(" %d", j);
+ printf(" ");
+ else
+ printf(",");
+ if(j<1024)
+ printf("%d",j);
else
- printf(",%d", j);
+ printf("%dK",j>>10);
first = 0;
}
printf("\n");
@@ -865,12 +831,7 @@ void
usage()
{
(void)fprintf(stderr,
-#ifndef NEWVM
- "usage: vmstat [-fimst] [-c count] [-M core] \
-[-N system] [-w wait] [disks]\n");
-#else
"usage: vmstat [-ims] [-c count] [-M core] \
[-N system] [-w wait] [disks]\n");
-#endif
exit(1);
}
diff --git a/usr.bin/w/Makefile b/usr.bin/w/Makefile
index 6217753..c7296b0 100644
--- a/usr.bin/w/Makefile
+++ b/usr.bin/w/Makefile
@@ -2,10 +2,10 @@
PROG= w
SRCS= fmt.c pr_time.c proc_compare.c w.c
-MAN1= w.0 uptime.0
+MAN1= w.1 uptime.1
DPADD= ${LIBKVM}
LDADD= -lkvm
-BINGRP= kmem
+BINGRP= kmem
BINMODE=2555
LINKS= ${BINDIR}/w ${BINDIR}/uptime
diff --git a/usr.bin/w/extern.h b/usr.bin/w/extern.h
index 1ee237c..7cb4ed0 100644
--- a/usr.bin/w/extern.h
+++ b/usr.bin/w/extern.h
@@ -35,5 +35,5 @@
struct proc;
void pr_attime __P((time_t *, time_t *));
-void pr_idle __P((time_t));
+int pr_idle __P((time_t));
int proc_compare __P((struct proc *, struct proc *));
diff --git a/usr.bin/w/pr_time.c b/usr.bin/w/pr_time.c
index 87fffb3..c48f6a7 100644
--- a/usr.bin/w/pr_time.c
+++ b/usr.bin/w/pr_time.c
@@ -40,13 +40,12 @@ static char sccsid[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94";
#include <stdio.h>
#include <string.h>
-#include <tzfile.h>
#include "extern.h"
/*
* pr_attime --
- * Print the time since the user logged in.
+ * Print the time since the user logged in.
*
* Note: SCCS forces the bizarre string manipulation, things like
* 8.2 get replaced in the source code.
@@ -64,11 +63,11 @@ pr_attime(started, now)
diff = *now - *started;
/* If more than a week, use day-month-year. */
- if (diff > SECSPERDAY * DAYSPERWEEK)
+ if (diff > 86400 * 7)
(void)strcpy(fmt, "%d%b%y");
/* If not today, use day-hour-am/pm. */
- else if (*now / SECSPERDAY != *started / SECSPERDAY) {
+ else if (*now / 86400 != *started / 86400) {
(void)strcpy(fmt, __CONCAT("%a%", "I%p"));
}
@@ -77,7 +76,8 @@ pr_attime(started, now)
(void)strcpy(fmt, __CONCAT("%l:%", "M%p"));
}
- (void)strftime(buf, sizeof(buf), fmt, tp);
+ (void)strftime(buf, sizeof(buf) - 1, fmt, tp);
+ buf[sizeof(buf) - 1] = '\0';
(void)printf("%s", buf);
}
@@ -85,20 +85,29 @@ pr_attime(started, now)
* pr_idle --
* Display the idle time.
*/
-void
+int
pr_idle(idle)
time_t idle;
{
/* If idle more than 36 hours, print as a number of days. */
- if (idle >= 36 * SECSPERHOUR)
- (void)printf(" %ddays ", idle / SECSPERDAY);
+ if (idle >= 36 * 3600) {
+ int days = idle / 86400;
+ (void)printf(" %dday%s ", days, days > 1 ? "s" : " " );
+ if (days >= 10)
+ return(1);
+ }
/* If idle more than an hour, print as HH:MM. */
- else if (idle >= SECSPERHOUR)
+ else if (idle >= 3600)
(void)printf(" %2d:%02d ",
- idle / SECSPERHOUR, (idle % SECSPERHOUR) / SECSPERMIN);
+ idle / 3600, (idle % 3600) / 60);
+
+ else if (idle / 60 == 0)
+ (void)printf(" - ");
/* Else print the minutes idle. */
else
- (void)printf(" %2d ", idle / SECSPERMIN);
+ (void)printf(" %2d ", idle / 60);
+
+ return(0); /* not idle longer than 9 days */
}
diff --git a/usr.bin/w/uptime.1 b/usr.bin/w/uptime.1
index a5eb169..8589bbc 100644
--- a/usr.bin/w/uptime.1
+++ b/usr.bin/w/uptime.1
@@ -47,8 +47,8 @@ the length of time the system has been up,
the number of users, and the load average of the system over the last
1, 5, and 15 minutes.
.Sh FILES
-.Bl -tag -width /vmunix
-.It Pa /vmunix
+.Bl -tag -width /kernel
+.It Pa /kernel
system name list
.El
.Sh SEE ALSO
diff --git a/usr.bin/w/w.1 b/usr.bin/w/w.1
index 4e4f5d3..b0a03f6 100644
--- a/usr.bin/w/w.1
+++ b/usr.bin/w/w.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)w.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
.Dd June 6, 1993
.Dt W 1
@@ -72,7 +73,7 @@ core instead of the default
.It Fl N
Extract the name list from the specified system instead of the
default
-.Dq /vmunix .
+.Dq /kernel .
.It Fl n
Show network addresses as numbers (normally
.Nm w
@@ -88,10 +89,10 @@ name is specified, the output is restricted to that user.
list of users on the system
.El
.Sh SEE ALSO
-.Xr who 1 ,
.Xr finger 1 ,
.Xr ps 1 ,
.Xr uptime 1 ,
+.Xr who 1
.Sh BUGS
The notion of the
.Dq current process
diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c
index 501938a..251cde0 100644
--- a/usr.bin/w/w.c
+++ b/usr.bin/w/w.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)w.c 8.6 (Berkeley) 6/30/94";
+static char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
#endif /* not lint */
/*
@@ -72,10 +72,13 @@ static char sccsid[] = "@(#)w.c 8.6 (Berkeley) 6/30/94";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <tzfile.h>
#include <unistd.h>
#include <utmp.h>
#include <vis.h>
+#include <locale.h>
+
+#include <arpa/nameser.h>
+#include <resolv.h>
#include "extern.h"
@@ -124,10 +127,12 @@ main(argc, argv)
FILE *ut;
u_long l;
size_t arglen;
- int ch, i, nentries, nusers, wcmd;
+ int ch, i, nentries, nusers, wcmd, longidle;
char *memf, *nlistf, *p, *vis_args, *x;
char buf[MAXHOSTNAMELEN], errbuf[256];
+ (void) setlocale(LC_ALL, "");
+
/* Are we w(1) or uptime(1)? */
p = __progname;
if (*p == '-')
@@ -141,7 +146,7 @@ main(argc, argv)
}
memf = nlistf = NULL;
- while ((ch = getopt(argc, argv, p)) != EOF)
+ while ((ch = getopt(argc, argv, p)) != -1)
switch (ch) {
case 'h':
header = 0;
@@ -169,6 +174,18 @@ main(argc, argv)
argc -= optind;
argv += optind;
+ if (!(_res.options & RES_INIT))
+ res_init();
+ _res.retrans = 2; /* resolver timeout to 2 seconds per try */
+ _res.retry = 1; /* only try once.. */
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ setgid(getgid());
+
if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
errx(1, "%s", errbuf);
@@ -191,8 +208,7 @@ main(argc, argv)
*nextp = ep;
nextp = &(ep->next);
memmove(&(ep->utmp), &utmp, sizeof(struct utmp));
- if (!(stp = ttystat(ep->utmp.ut_line)))
- continue;
+ stp = ttystat(ep->utmp.ut_line);
ep->tdev = stp->st_rdev;
#ifdef CPU_CONSDEV
/*
@@ -218,11 +234,11 @@ main(argc, argv)
pr_header(&now, nusers);
if (wcmd == 0)
exit (0);
- }
-#define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n"
+#define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n"
#define WUSED (sizeof (HEADER) - sizeof ("WHAT\n"))
- (void)printf(HEADER);
+ (void)printf(HEADER);
+ }
if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
err(1, "%s", kvm_geterr(kd));
@@ -266,7 +282,7 @@ main(argc, argv)
/* sort by idle time */
if (sortidle && ehead != NULL) {
struct entry *from = ehead, *save;
-
+
ehead = NULL;
while (from != NULL) {
for (nextp = &ehead;
@@ -279,7 +295,7 @@ main(argc, argv)
*nextp = save;
}
}
-
+
if (!nflag)
if (gethostname(domain, sizeof(domain) - 1) < 0 ||
(p = strchr(domain, '.')) == 0)
@@ -307,18 +323,31 @@ main(argc, argv)
}
p = hp->h_name;
}
+ if (nflag && *p && strcmp(p, "-") && inet_addr(p) == INADDR_NONE) {
+ hp = gethostbyname(p);
+
+ if (hp != NULL) {
+ struct in_addr in;
+
+ memmove(&in, hp->h_addr, sizeof(in));
+ p = inet_ntoa(in);
+ }
+ }
if (x) {
(void)snprintf(buf, sizeof(buf), "%s:%.*s", p,
- ep->utmp.ut_host + UT_HOSTSIZE - x, x);
+ ep->utmp.ut_host + UT_HOSTSIZE - x, x);
p = buf;
}
- (void)printf("%-*.*s %-2.2s %-*.*s ",
+ (void)printf("%-*.*s %-3.3s %-*.*s ",
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
- strncmp(ep->utmp.ut_line, "tty", 3) ?
+ strncmp(ep->utmp.ut_line, "tty", 3) &&
+ strncmp(ep->utmp.ut_line, "cua", 3) ?
ep->utmp.ut_line : ep->utmp.ut_line + 3,
UT_HOSTSIZE, UT_HOSTSIZE, *p ? p : "-");
pr_attime(&ep->utmp.ut_time, &now);
- pr_idle(ep->idle);
+ longidle=pr_idle(ep->idle);
+ if (longidle)
+ argwidth--;
if (ep->args != NULL) {
arglen = strlen(ep->args);
strvisx(vis_args, ep->args,
@@ -348,8 +377,9 @@ pr_header(nowp, nusers)
* SCCS forces the string manipulation below, as it replaces
* %, M, and % in a character string with the file name.
*/
- (void)strftime(buf, sizeof(buf),
+ (void)strftime(buf, sizeof(buf) - 1,
__CONCAT("%l:%","M%p"), localtime(nowp));
+ buf[sizeof(buf) - 1] = '\0';
(void)printf("%s ", buf);
/*
@@ -363,11 +393,11 @@ pr_header(nowp, nusers)
boottime.tv_sec != 0) {
uptime = now - boottime.tv_sec;
uptime += 30;
- days = uptime / SECSPERDAY;
- uptime %= SECSPERDAY;
- hrs = uptime / SECSPERHOUR;
- uptime %= SECSPERHOUR;
- mins = uptime / SECSPERMIN;
+ days = uptime / 86400;
+ uptime %= 86400;
+ hrs = uptime / 3600;
+ uptime %= 3600;
+ mins = uptime / 60;
(void)printf(" up");
if (days > 0)
(void)printf(" %d day%s,", days, days > 1 ? "s" : "");
@@ -384,7 +414,7 @@ pr_header(nowp, nusers)
}
/* Print number of users logged in to system */
- (void)printf(" %d user%s", nusers, nusers > 1 ? "s" : "");
+ (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
/*
* Print 1, 5, and 15 minute load averages.
@@ -411,7 +441,7 @@ ttystat(line)
(void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", _PATH_DEV, line);
if (stat(ttybuf, &sb))
- return (NULL);
+ err(1, "%s", ttybuf);
return (&sb);
}
diff --git a/usr.bin/wall/wall.c b/usr.bin/wall/wall.c
index 9b120ed..f2b8a9d 100644
--- a/usr.bin/wall/wall.c
+++ b/usr.bin/wall/wall.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93";
#include <sys/time.h>
#include <sys/uio.h>
+#include <locale.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
@@ -81,7 +82,9 @@ main(argc, argv)
char *p, *ttymsg();
char line[sizeof(utmp.ut_line) + 1];
- while ((ch = getopt(argc, argv, "n")) != EOF)
+ (void)setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "n")) != -1)
switch (ch) {
case 'n':
/* undoc option for shutdown: suppress banner */
@@ -124,7 +127,8 @@ void
makemsg(fname)
char *fname;
{
- register int ch, cnt;
+ register int cnt;
+ register unsigned char ch;
struct tm *lt;
struct passwd *pw;
struct stat sbuf;
@@ -172,12 +176,25 @@ makemsg(fname)
}
while (fgets(lbuf, sizeof(lbuf), stdin))
for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+ again:
if (cnt == 79 || ch == '\n') {
for (; cnt < 79; ++cnt)
putc(' ', fp);
putc('\r', fp);
putc('\n', fp);
cnt = 0;
+ } else if ( ( (ch & 0x7F) < ' ' /* locale-independent */
+ || (!isprint(ch) && !isspace(ch))
+ )
+ && strchr("\a\f\t\v\b\r\n", ch) == NULL
+ ) {
+ if (ch & 0x80) {
+ ch &= 0x7F;
+ (void)fprintf(fp, "M-");
+ goto again;
+ }
+ putc('^', fp);
+ putc(ch^0x40, fp); /* DEL to ?, others to alpha */
} else
putc(ch, fp);
}
diff --git a/usr.bin/wc/wc.1 b/usr.bin/wc/wc.1
index 64c047b..f081b6b 100644
--- a/usr.bin/wc/wc.1
+++ b/usr.bin/wc/wc.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)wc.1 8.2 (Berkeley) 4/19/94
+.\" $Id$
.\"
.Dd April 19, 1994
.Dt WC 1
@@ -107,3 +108,8 @@ The
.Nm wc
function conforms to
.St -p1003.2 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c
index d37f494..1670f1b 100644
--- a/usr.bin/wc/wc.c
+++ b/usr.bin/wc/wc.c
@@ -32,30 +32,36 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 5/2/95";
+#if 0
+static const char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93";
+#else
+static const char rcsid[] =
+ "$Id: wc.c,v 1.6 1997/02/22 19:57:44 peter Exp $";
+#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
+#include <unistd.h>
u_long tlinect, twordct, tcharct;
int doline, doword, dochar;
-void cnt __P((char *));
-void err __P((const char *, ...));
+int cnt __P((char *));
void usage __P((void));
int
@@ -64,9 +70,11 @@ main(argc, argv)
char *argv[];
{
register int ch;
- int total;
+ int errors, total;
- while ((ch = getopt(argc, argv, "lwc")) != EOF)
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "lwc")) != -1)
switch((char)ch) {
case 'l':
doline = 1;
@@ -88,14 +96,19 @@ main(argc, argv)
if (doline + doword + dochar == 0)
doline = doword = dochar = 1;
+ errors = 0;
total = 0;
if (!*argv) {
- cnt(NULL);
- (void)printf("\n");
+ if (cnt((char *)NULL) != 0)
+ ++errors;
+ else
+ (void)printf("\n");
}
else do {
- cnt(*argv);
- (void)printf(" %s\n", *argv);
+ if (cnt(*argv) != 0)
+ ++errors;
+ else
+ (void)printf(" %s\n", *argv);
++total;
} while(*++argv);
@@ -108,26 +121,30 @@ main(argc, argv)
(void)printf(" %7ld", tcharct);
(void)printf(" total\n");
}
- exit(0);
+ exit(errors == 0 ? 0 : 1);
}
-void
+int
cnt(file)
char *file;
{
- register u_char *p;
+ register u_char *p, ch;
register short gotsp;
- register int ch, len;
+ register int len;
register u_long linect, wordct, charct;
struct stat sb;
int fd;
u_char buf[MAXBSIZE];
- fd = STDIN_FILENO;
linect = wordct = charct = 0;
- if (file) {
- if ((fd = open(file, O_RDONLY, 0)) < 0)
- err("%s: %s", file, strerror(errno));
+ if (file == NULL) {
+ file = "stdin";
+ fd = STDIN_FILENO;
+ } else {
+ if ((fd = open(file, O_RDONLY, 0)) < 0) {
+ warn("%s: open", file);
+ return (1);
+ }
if (doword)
goto word;
/*
@@ -137,8 +154,11 @@ cnt(file)
*/
if (doline) {
while (len = read(fd, buf, MAXBSIZE)) {
- if (len == -1)
- err("%s: %s", file, strerror(errno));
+ if (len == -1) {
+ warn("%s: read", file);
+ (void)close(fd);
+ return (1);
+ }
charct += len;
for (p = buf; len--; ++p)
if (*p == '\n')
@@ -151,28 +171,34 @@ cnt(file)
(void)printf(" %7lu", charct);
}
(void)close(fd);
- return;
+ return (0);
}
/*
* If all we need is the number of characters and it's a
* regular or linked file, just stat the puppy.
*/
if (dochar) {
- if (fstat(fd, &sb))
- err("%s: %s", file, strerror(errno));
- if (S_ISREG(sb.st_mode)) {
+ if (fstat(fd, &sb)) {
+ warn("%s: fstat", file);
+ (void)close(fd);
+ return (1);
+ }
+ if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
(void)printf(" %7qu", sb.st_size);
tcharct += sb.st_size;
(void)close(fd);
- return;
+ return (0);
}
}
}
/* Do it the hard way... */
word: for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
- if (len == -1)
- err("%s: %s", file, strerror(errno));
+ if (len == -1) {
+ warn("%s: read", file);
+ (void)close(fd);
+ return (1);
+ }
/*
* This loses in the presence of multi-byte characters.
* To do it right would require a function to return a
@@ -204,6 +230,7 @@ word: for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
(void)printf(" %7lu", charct);
}
(void)close(fd);
+ return (0);
}
void
@@ -212,32 +239,3 @@ usage()
(void)fprintf(stderr, "usage: wc [-clw] [files]\n");
exit(1);
}
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "wc: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- exit(1);
- /* NOTREACHED */
-}
diff --git a/usr.bin/what/what.1 b/usr.bin/what/what.1
index e3556cc..e8bb617 100644
--- a/usr.bin/what/what.1
+++ b/usr.bin/what/what.1
@@ -31,6 +31,8 @@
.\"
.\" @(#)what.1 8.1 (Berkeley) 6/6/93
.\"
+.\" $Id: what.1,v 1.4 1997/02/22 19:57:46 peter Exp $
+.\"
.Dd June 6, 1993
.Dt WHAT 1
.Os BSD 4
@@ -49,7 +51,8 @@ and searches for sequences of the form
as inserted by the source code control system. It prints the remainder
of the string following this marker, up to a null character, newline, double
quote, or
-.Dq \&> character.
+.Dq \&>
+character.
.Sh BUGS
As
.Bx
@@ -61,6 +64,8 @@ command which is part of
.Tn SCCS ,
and may not behave exactly the same as that
command does.
+.Sh SEE ALSO
+.Xr ident 1
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/what/what.c b/usr.bin/what/what.c
index 769f6d5..ee90cee 100644
--- a/usr.bin/what/what.c
+++ b/usr.bin/what/what.c
@@ -51,7 +51,7 @@ main(argc, argv)
int argc;
char **argv;
{
- if (!*++argv)
+ if (!*++argv)
search();
else do {
if (!freopen(*argv, "r", stdin)) {
diff --git a/usr.bin/whereis/Makefile b/usr.bin/whereis/Makefile
index 87bc659..b4a4df1 100644
--- a/usr.bin/whereis/Makefile
+++ b/usr.bin/whereis/Makefile
@@ -1,5 +1,7 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+MAN1= whereis.1
-PROG= whereis
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/whereis.pl ${DESTDIR}${BINDIR}/whereis
.include <bsd.prog.mk>
diff --git a/usr.bin/whereis/whereis.1 b/usr.bin/whereis/whereis.1
new file mode 100644
index 0000000..6c5a4f7
--- /dev/null
+++ b/usr.bin/whereis/whereis.1
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)whereis.1 8.2 (Berkeley) 12/30/93
+.\"
+.\" $Id$
+.\"
+.Dd June 15, 1996
+.Dt WHEREIS 1
+.Os FreeBSD
+.Sh NAME
+.Nm whereis
+.Nd locate programs
+.Sh SYNOPSIS
+.Nm whereis
+.Op Fl bms
+.Op Fl u
+.Op Fl BMS dir ... Fl f
+.Ar program ...
+.Sh DESCRIPTION
+The
+.Nm whereis
+utility checks the standard binary, manual page, and source
+directories for the specified programs, printing out the paths of any
+it finds. The supplied names are first stripped of leading path name
+components, any single trailing extension of the form
+.Ql .ext ,
+and the leading
+.Ql s.
+or trailing
+.Ql ,v
+from a source code control system.
+.Pp
+The default path searched is the string returned by the
+.Xr sysctl 8
+utility for the
+.Dq user.cs_path
+string, with
+.Pa /usr/libexec
+and the current user's
+.Ev $PATH
+appended. Manual pages are searched by default along the
+.Ev $MANPATH .
+Program sources are located in a list of known standard places,
+including all the subdirectories of
+.Pa /usr/src
+and
+.Pa /usr/ports .
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl B
+Specify directories to search for binaries. Requires the
+.Fl f
+option.
+.It Fl M
+Specify directories to search for manual pages. Requires the
+.Fl f
+option.
+.It Fl S
+Specify directories to search for program sources. Requires the
+.Fl f
+option.
+.It Fl b
+Search for binaries.
+.It Fl f
+Delimits the list of directories after the
+.Fl B ,
+.Fl M ,
+or
+.Fl S
+options, and indicates the beginning of the
+.Ar name
+list.
+.It Fl m
+Search for manual pages.
+.It Fl s
+Search for source directories.
+.It Fl u
+Search for
+.Dq unusual
+entries. A file is said to be unusual if it does not have one entry
+of each requested type.
+.El
+.Sh EXAMPLE
+The following finds all utilities under
+.Pa /usr/bin
+that do not have documentation:
+.Dl whereis -m -u /usr/bin/*
+.Sh SEE ALSO
+.Xr locate 1 ,
+.Xr man 1 ,
+.Xr sysctl 8
+.Sh BUGS
+The search for sources is implemented as a quick search as the
+first-level subdirectory of each element of the list of source
+directories first. If this didn't succeed, the utility
+.Xr locate 1
+is requested to do the search in deeper nested subdirectories. This
+might take some time, and will only succeed if the locate database is
+up-to-date.
+.Sh HISTORY
+The
+.Nm whereis
+command appeared in
+.Bx 3.0 .
+This version re-implements the historical
+functionality that was lost in
+.Bx 4.4 .
diff --git a/usr.bin/whereis/whereis.pl b/usr.bin/whereis/whereis.pl
new file mode 100644
index 0000000..12b3997
--- /dev/null
+++ b/usr.bin/whereis/whereis.pl
@@ -0,0 +1,243 @@
+#!/usr/bin/perl
+#
+# Copyright © 1995, 1996 Jörg Wunsch
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# whereis -- search for binaries, man pages and source directories.
+#
+# Rewritten from scratch for FreeBSD after the 4.3BSD manual page.
+#
+# $Id$
+#
+
+sub usage
+{
+ print STDERR "usage: $0 [-bms] [-u] [-BMS dir... -f] name ...\n";
+ exit 1;
+}
+
+sub scanopts
+{
+ local($i, $j);
+ arg:
+ while ($ARGV[$i] =~ /^-/) {
+ opt:
+ for ($j = 1; $j < length($ARGV[$i]); $j++) {
+ local($_) = substr($ARGV[$i], $j, 1);
+ local($what, @list);
+ $opt_b++, next opt if /b/;
+ $opt_m++, next opt if /m/;
+ $opt_s++, next opt if /s/;
+ $opt_u++, next opt if /u/;
+ &usage unless /[BMS]/;
+
+ # directory list processing
+ $what = $_; @list = ();
+ push(@list, substr($ARGV[$i], $j+1)) if $j+1 < length($ARGV[$i]);
+ $i++;
+ while ($i <= $#ARGV && $ARGV[$i] !~ /^-/) {
+ push(@list, $ARGV[$i++]);
+ }
+ if ($what eq "B") {@binaries = @list;}
+ elsif ($what eq "M") {@manuals = @list;}
+ elsif ($what eq "S") {@sources = @list;}
+
+ $i++, last arg if $ARGV[$i] =~ /^-f$/;
+ next arg;
+ }
+ $i++;
+ }
+ &usage if $i > $#ARGV;
+
+ while ($ARGV[$i]) {
+ push(@names, $ARGV[$i++]);
+ }
+}
+
+
+sub decolonify
+{
+ local($list) = @_;
+ local($_, @rv);
+ foreach(split(/:/, $list)) {
+ push(@rv, $_);
+ }
+ return @rv;
+}
+
+
+&scanopts;
+
+# default to all if no type requested
+if ($opt_b + $opt_m + $opt_s == 0) {$opt_b = $opt_m = $opt_s = 1;}
+
+if (!defined(@binaries)) {
+ #
+ # first, use default path, then append /usr/libexec and the user's path
+ #
+ local($cs_path) = `/usr/sbin/sysctl -n user.cs_path`;
+ local(@list, %path);
+
+ chop($cs_path);
+
+ @list = &decolonify($cs_path);
+ push(@list, "/usr/libexec");
+ push(@list, &decolonify($ENV{'PATH'}));
+
+ # resolve ~, remove duplicates
+ foreach (@list) {
+ s/^~/$ENV{'HOME'}/ if /^~/;
+ push(@binaries, $_) if !$path{$_};
+ $path{$_}++;
+ }
+}
+
+if (!defined(@manuals)) {
+ #
+ # first, use default manpath, then append user's $MANPATH
+ #
+ local($usermanpath) = $ENV{'MANPATH'};
+ delete $ENV{'MANPATH'};
+ local($manpath) = `/usr/bin/manpath`;
+ local(@list, %path, $i);
+
+ chop($manpath);
+
+ @list = &decolonify($manpath);
+ push(@list, &decolonify($usermanpath));
+
+ # remove duplicates
+ foreach (@list) {
+ push(@manuals, $_) if !$path{$_};
+ $path{$_}++;
+ }
+}
+
+if (!defined(@sources)) {
+ #
+ # default command sources
+ #
+ local($_);
+
+ @sources = ("/usr/src/bin", "/usr/src/usr.bin", "/usr/src/sbin",
+ "/usr/src/usr.sbin", "/usr/src/libexec",
+ "/usr/src/gnu/bin", "/usr/src/gnu/usr.bin",
+ "/usr/src/gnu/sbin", "/usr/src/gnu/usr.sbin",
+ "/usr/src/gnu/libexec");
+
+ #
+ # if /usr/ports exists, look in all its subdirs, too
+ #
+ if (-d "/usr/ports" && opendir(PORTS, "/usr/ports")) {
+ while ($_ = readdir(PORTS)) {
+ next if /^\.\.?$/;
+ next if /^distfiles$/; # magic
+ next if ! -d "/usr/ports/$_";
+ push(@sources, "/usr/ports/$_");
+ }
+ closedir(PORTS);
+ }
+}
+
+if ($opt_m) {
+ # construct a new MANPATH
+ foreach (@manuals) {
+ next if ! -d $_;
+ if ($manpath) { $manpath .= ":$_"; }
+ else { $manpath = $_; }
+ }
+}
+
+#
+# main loop
+#
+foreach $name (@names) {
+ $name =~ s|^.*/||; # strip leading path name component
+ $name =~ s/,v$//; $name =~ s/^s\.//; # RCS or SCCS suffix/prefix
+ $name =~ s/\.(Z|z|gz)$//; # compression suffix
+ $name =~ s/\.[^.]+//; # any other suffix
+
+ $line = "";
+ $unusual = 0;
+
+ if ($opt_b) {
+ #
+ # Binaries have to match exactly, and must be regular executable
+ # files.
+ #
+ $unusual++;
+ foreach (@binaries) {
+ $line .= " $_/$name", $unusual--, last if -f "$_/$name" && -x _;
+ }
+ }
+
+ if ($opt_m) {
+ #
+ # Ask the man command to do the search for us.
+ #
+ $unusual++;
+ chop($result = `man -S 1:8 -M $manpath -w $name 2> /dev/null`);
+ if ($result ne '') {
+ $unusual--;
+ ($cat, $junk, $src) = split(/[() \t\n]+/, $result);
+ if ($src ne '') { $line .= " $src"; }
+ else { $line .= " $cat"; }
+ }
+ }
+
+ if ($opt_s) {
+ #
+ # Sources match if a subdir with the exact name is found.
+ #
+ $found = 0;
+ $unusual++;
+ foreach (@sources) {
+ $line .= " $_/$name", $unusual--, $found++, last if -d "$_/$name";
+ }
+ #
+ # If not yet found, ask locate(1) to do the search for us.
+ # This will find sources for things like lpr, but take longer.
+ # Do only match locate output that starts with one of our
+ # source directories, and at least one further level of
+ # subdirectories.
+ #
+ if (!$found && open(LOCATE, "locate */$name 2>/dev/null |")) {
+ locate_item:
+ while (chop($loc = <LOCATE>)) {
+ foreach (@sources) {
+ $line .= " $loc", $unusual--, last locate_item
+ if $loc =~ m|^$_/[^/]+/|;
+ }
+ }
+ close(LOCATE);
+ }
+ }
+
+ if ($opt_u) {
+ print "$name:\n" if $unusual;
+ } else {
+ print "$name:$line\n";
+ }
+}
+
diff --git a/usr.bin/which/Makefile b/usr.bin/which/Makefile
new file mode 100644
index 0000000..af5532e
--- /dev/null
+++ b/usr.bin/which/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+MAN1= which.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/which.pl ${DESTDIR}${BINDIR}/which
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/which/which.1 b/usr.bin/which/which.1
new file mode 100644
index 0000000..e62c91e
--- /dev/null
+++ b/usr.bin/which/which.1
@@ -0,0 +1,65 @@
+.\" Manpage Copyright (c) 1995, Jordan Hubbard <jkh@freebsd.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the FreeBSD Project
+.\" its contributors.
+.\" 4. Neither the name of the FreeBSD Project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.Dd January 26, 1995
+.Dt WHICH 1
+.Os FreeBSD
+.Sh NAME
+.Nm which
+.Nd "locate a program file in the user's path"
+.Sh SYNOPSIS
+.Nm which
+.Op Fl as
+.Op Ar command
+.Ar ...
+.Sh DESCRIPTION
+.Nm Which
+takes a list of command names and searches the path for each executable
+file that would be run had these commands actually been invoked.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+List all instances of executables found (instead of just the first one
+of each).
+.It Fl s
+No output, just return 0 if any of the executables are found, or 1 if
+none are found.
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 2.1 .
+.Sh SEE ALSO
+.Xr perl 1
+.Sh AUTHOR
+The PERL script for this more modern version of
+.Nm which
+was written by Wolfram Schneider <wosch@FreeBSD.org>.
diff --git a/usr.bin/which/which.pl b/usr.bin/which/which.pl
new file mode 100755
index 0000000..991e551
--- /dev/null
+++ b/usr.bin/which/which.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $Id$
+
+$all = $silent = $found = 0;
+@path = split(/:/, $ENV{'PATH'});
+
+if ($ARGV[0] eq "-a") {
+ $all = 1; shift @ARGV;
+} elsif ($ARGV[0] eq "-s") {
+ $silent = 1; shift @ARGV;
+} elsif ($ARGV[0] =~ /^-(h|help|\?)$/) {
+ die "usage:\n\twhich [-a] [-s] program ...\n";
+}
+
+foreach $prog (@ARGV) {
+ if ("$prog" =~ '/' && -x "$prog") {
+ print "$prog\n" unless $silent;
+ $found = 1;
+ } else {
+ foreach $e (@path) {
+ if (-x "$e/$prog") {
+ print "$e/$prog\n" unless $silent;
+ $found = 1;
+ last unless $all;
+ }
+ }
+ }
+}
+
+exit (!$found);
diff --git a/usr.bin/who/who.1 b/usr.bin/who/who.1
index f8ac307..27dc5cd 100644
--- a/usr.bin/who/who.1
+++ b/usr.bin/who/who.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)who.1 8.2 (Berkeley) 12/30/93
+.\" $Id$
.\"
.Dd December 30, 1993
.Dt WHO 1
@@ -102,4 +103,4 @@ special characters, see
A
.Nm
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/who/who.c b/usr.bin/who/who.c
index d1e6eb9..e16a7b9 100644
--- a/usr.bin/who/who.c
+++ b/usr.bin/who/who.c
@@ -46,10 +46,11 @@ static char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93";
#include <sys/types.h>
#include <sys/file.h>
-#include <sys/time.h>
+#include <time.h>
#include <pwd.h>
#include <utmp.h>
#include <stdio.h>
+#include <locale.h>
main(argc, argv)
int argc;
@@ -60,7 +61,8 @@ main(argc, argv)
struct passwd *pw;
FILE *ufp, *file();
char *t, *rindex(), *strcpy(), *strncpy(), *ttyname();
- time_t time();
+
+ (void) setlocale(LC_TIME, "");
switch (argc) {
case 1: /* who */
@@ -85,7 +87,7 @@ main(argc, argv)
if (t = rindex(p, '/'))
p = t + 1;
while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
- if (usr.ut_name && !strcmp(usr.ut_line, p)) {
+ if (*usr.ut_name && !strcmp(usr.ut_line, p)) {
output(&usr);
exit(0);
}
@@ -109,11 +111,13 @@ main(argc, argv)
output(up)
struct utmp *up;
{
- char *ctime();
+ char buf[80];
(void)printf("%-*.*s %-*.*s", UT_NAMESIZE, UT_NAMESIZE, up->ut_name,
UT_LINESIZE, UT_LINESIZE, up->ut_line);
- (void)printf("%.12s", ctime(&up->ut_time) + 4);
+ (void)strftime(buf, sizeof(buf), "%c", localtime(&up->ut_time));
+ buf[sizeof(buf) - 1] = '\0';
+ (void)printf("%.12s", buf + 4);
if (*up->ut_host)
printf("\t(%.*s)", UT_HOSTSIZE, up->ut_host);
(void)putchar('\n');
diff --git a/usr.bin/whois/Makefile b/usr.bin/whois/Makefile
index e6ab08f..3b6e7aa 100644
--- a/usr.bin/whois/Makefile
+++ b/usr.bin/whois/Makefile
@@ -2,4 +2,11 @@
PROG= whois
+.if defined(SOCKS)
+CFLAGS+=-DSOCKS
+CFLAGS+=-Dconnect=Rconnect -Dgetsockname=Rgetsockname -Dlisten=Rlisten \
+ -Daccept=Raccept -Drcmd=Rrcmd -Dbind=Rbind -Dselect=Rselect
+LDADD+= -lsocks
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1
index 628a2a7..6a974b4 100644
--- a/usr.bin/whois/whois.1
+++ b/usr.bin/whois/whois.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)whois.1 8.2 (Berkeley) 6/20/94
+.\" @(#)whois.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd June 20, 1994
+.Dd June 6, 1993
.Dt WHOIS 1
.Os BSD 4.3
.Sh NAME
diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c
index 77d6c50..a70301a 100644
--- a/usr.bin/whois/whois.c
+++ b/usr.bin/whois/whois.c
@@ -63,8 +63,12 @@ main(argc, argv)
int s;
char *host;
+#ifdef SOCKS
+ SOCKSinit(argv[0]);
+#endif
+
host = NICHOST;
- while ((ch = getopt(argc, argv, "h:")) != EOF)
+ while ((ch = getopt(argc, argv, "h:")) != -1)
switch((char)ch) {
case 'h':
host = optarg;
@@ -93,10 +97,6 @@ main(argc, argv)
}
bzero((caddr_t)&sin, sizeof (sin));
sin.sin_family = hp->h_addrtype;
- if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- perror("whois: bind");
- exit(1);
- }
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
sp = getservbyname("whois", "tcp");
if (sp == NULL) {
diff --git a/usr.bin/window/Makefile b/usr.bin/window/Makefile
index 53ab6da..fba3587 100644
--- a/usr.bin/window/Makefile
+++ b/usr.bin/window/Makefile
@@ -1,7 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= window
-CFLAGS+=-R -DVMIN_BUG
SRCS= char.c cmd.c cmd1.c cmd2.c cmd3.c cmd4.c cmd5.c cmd6.c cmd7.c \
context.c error.c lcmd.c lcmd1.c lcmd2.c main.c mloop.c parser1.c \
parser2.c parser3.c parser4.c parser5.c scanner.c startup.c string.c \
@@ -15,7 +14,7 @@ SRCS= char.c cmd.c cmd1.c cmd2.c cmd3.c cmd4.c cmd5.c cmd6.c cmd7.c \
wwredrawwin.c wwrint.c wwscroll.c wwsize.c wwspawn.c wwsuspend.c \
wwterminfo.c wwtty.c wwunframe.c wwupdate.c wwwrite.c xx.c xxflush.c \
compress.c
-MAN= window.0
+MAN= window.1
DPADD= ${LIBTERMCAP}
LDADD= -ltermcap
diff --git a/usr.bin/window/char.c b/usr.bin/window/char.c
index 34bea59..670d5f1 100644
--- a/usr.bin/window/char.c
+++ b/usr.bin/window/char.c
@@ -40,80 +40,6 @@ static char sccsid[] = "@(#)char.c 8.1 (Berkeley) 6/6/93";
#include "char.h"
-char _cmap[] = {
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^@ - ^C */
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^D - ^G */
- _C, _C|_P, _C, _C|_U, /* ^H - ^K */
- _C|_U, _C, _C|_U, _C|_U, /* ^L - ^O */
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^P - ^S */
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^T - ^W */
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^U - ^[ */
- _C|_U, _C|_U, _C|_U, _C|_U, /* ^\ - ^_ */
-
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
-
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
-
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _P|_U,
- _P|_U, _P|_U, _P|_U, _C|_U,
-
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
-
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
-
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
-
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U,
- _C|_U, _C|_U, _C|_U, _C|_U
-};
-
char *_unctrl[] = {
"^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G",
"^H", "^I", "^J", "^K", "^L", "^M", "^N", "^O",
diff --git a/usr.bin/window/char.h b/usr.bin/window/char.h
index eb4774f..dd4ad27 100644
--- a/usr.bin/window/char.h
+++ b/usr.bin/window/char.h
@@ -49,13 +49,13 @@
* using unctrl() by wwwrite() if ww_unctrl is set.
*/
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
extern char *_unctrl[];
-extern char _cmap[];
#define ctrl(c) (c & 0x1f)
#define unctrl(c) (_unctrl[(unsigned char) (c)])
-#define _C 0x01
-#define _P 0x02
-#define _U 0x04
-#define isctrl(c) (_cmap[(unsigned char) (c)] & _C)
-#define isprt(c) (_cmap[(unsigned char) (c)] & _P)
-#define isunctrl(c) (_cmap[(unsigned char) (c)] & _U)
+#define isctrl(c) iscntrl((unsigned char)(c))
+#define isprt(c) isprint((unsigned char)(c))
+#define isunctrl(c) (strchr("\b\t\n\r", (c)) == NULL && isctrl(c))
diff --git a/usr.bin/window/cmd.c b/usr.bin/window/cmd.c
index cd105ea..391e346 100644
--- a/usr.bin/window/cmd.c
+++ b/usr.bin/window/cmd.c
@@ -43,7 +43,7 @@ static char sccsid[] = "@(#)cmd.c 8.1 (Berkeley) 6/6/93";
docmd()
{
- register char c;
+ register c;
register struct ww *w;
char out = 0;
diff --git a/usr.bin/window/cmd1.c b/usr.bin/window/cmd1.c
index df6deb9..6fdc9da 100644
--- a/usr.bin/window/cmd1.c
+++ b/usr.bin/window/cmd1.c
@@ -115,7 +115,7 @@ int maxrow, maxcol;
{
static int scount;
int count;
- char c;
+ int c;
int oldrow = *row, oldcol = *col;
while ((c = wwgetc()) >= 0) {
diff --git a/usr.bin/window/compress.c b/usr.bin/window/compress.c
index ccac095..d71b510 100644
--- a/usr.bin/window/compress.c
+++ b/usr.bin/window/compress.c
@@ -44,6 +44,7 @@ static char sccsid[] = "@(#)compress.c 8.1 (Berkeley) 6/6/93";
/* special */
#include <stdio.h>
#include <fcntl.h>
+#include <stdlib.h>
int cc_trace = 0;
FILE *cc_trace_fp;
diff --git a/usr.bin/window/main.c b/usr.bin/window/main.c
index 15de840..16fe0a5 100644
--- a/usr.bin/window/main.c
+++ b/usr.bin/window/main.c
@@ -64,7 +64,7 @@ char **argv;
char *cmd = 0;
char tflag = 0;
- escapec = ESCAPEC;
+ escapec = ESCAPEC;
if (p = rindex(*argv, '/'))
p++;
else
diff --git a/usr.bin/window/mystring.h b/usr.bin/window/mystring.h
new file mode 100644
index 0000000..08cae56
--- /dev/null
+++ b/usr.bin/window/mystring.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Wang at The University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)string.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define STR_DEBUG
+
+char *str_cpy();
+char *str_ncpy();
+char *str_cat();
+char *str_itoa();
+
+#define str_cmp(a, b) strcmp(a, b)
+
+#ifdef STR_DEBUG
+struct string {
+ struct string *s_forw;
+ struct string *s_back;
+ char s_data[1];
+};
+
+struct string str_head;
+
+#define str_offset ((unsigned)str_head.s_data - (unsigned)&str_head)
+#define str_stos(s) ((struct string *)((unsigned)(s) - str_offset))
+
+char *str_alloc();
+int str_free();
+#else
+#define str_free(s) free(s)
+#define str_alloc(s) malloc(s)
+#endif
diff --git a/usr.bin/window/scanner.c b/usr.bin/window/scanner.c
index d10719c..9bf691b 100644
--- a/usr.bin/window/scanner.c
+++ b/usr.bin/window/scanner.c
@@ -38,6 +38,7 @@
static char sccsid[] = "@(#)scanner.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#include <ctype.h>
#include "value.h"
#include "token.h"
#include "context.h"
@@ -110,22 +111,6 @@ loop:
cx.x_token = T_EOF;
state = -1;
break;
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f': case 'g': case 'h': case 'i': case 'j':
- case 'k': case 'l': case 'm': case 'n': case 'o':
- case 'p': case 'q': case 'r': case 's': case 't':
- case 'u': case 'v': case 'w': case 'x': case 'y':
- case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F': case 'G': case 'H': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O':
- case 'P': case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X': case 'Y':
- case 'Z':
- case '_': case '.':
- *p++ = c;
- state = 2;
- break;
case '"':
state = 3;
break;
@@ -231,6 +216,11 @@ loop:
state = -1;
break;
default:
+ if (isalpha(c) || c == '_' || c == '.') {
+ *p++ = c;
+ state = 2;
+ break;
+ }
cx.x_val.v_num = c;
cx.x_token = T_CHAR;
state = -1;
@@ -245,24 +235,6 @@ loop:
break;
case 2: /* unquoted string */
switch (c) {
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f': case 'g': case 'h': case 'i': case 'j':
- case 'k': case 'l': case 'm': case 'n': case 'o':
- case 'p': case 'q': case 'r': case 's': case 't':
- case 'u': case 'v': case 'w': case 'x': case 'y':
- case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F': case 'G': case 'H': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O':
- case 'P': case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X': case 'Y':
- case 'Z':
- case '_': case '.':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (p < buf + sizeof buf - 1)
- *p++ = c;
- break;
case '"':
state = 3;
break;
@@ -281,6 +253,11 @@ loop:
}
break;
default:
+ if (isalnum(c) || c == '_' || c == '.') {
+ if (p < buf + sizeof buf - 1)
+ *p++ = c;
+ break;
+ }
(void) s_ungetc(c);
case EOF:
*p = 0;
diff --git a/usr.bin/window/ttgeneric.c b/usr.bin/window/ttgeneric.c
index 4dddd21..704cb30 100644
--- a/usr.bin/window/ttgeneric.c
+++ b/usr.bin/window/ttgeneric.c
@@ -42,7 +42,6 @@ static char sccsid[] = "@(#)ttgeneric.c 8.1 (Berkeley) 6/6/93";
#include "tt.h"
char PC, *BC, *UP;
-short ospeed;
/* normal frame */
short gen_frame[16] = {
@@ -393,7 +392,6 @@ tt_generic()
{
gen_PC = tttgetstr("pc");
PC = gen_PC ? *gen_PC->ts_str : 0;
- ospeed = wwospeed;
gen_CM = ttxgetstr("cm"); /* may not work */
gen_IM = ttxgetstr("im");
diff --git a/usr.bin/window/ttinit.c b/usr.bin/window/ttinit.c
index 8b82872..eac904c 100644
--- a/usr.bin/window/ttinit.c
+++ b/usr.bin/window/ttinit.c
@@ -40,6 +40,7 @@ static char sccsid[] = "@(#)ttinit.c 8.1 (Berkeley) 6/6/93";
#include "ww.h"
#include "tt.h"
+#include <stdlib.h>
int tt_h19();
int tt_h29();
diff --git a/usr.bin/window/window.1 b/usr.bin/window/window.1
index 425cce0..6f32797 100644
--- a/usr.bin/window/window.1
+++ b/usr.bin/window/window.1
@@ -128,12 +128,12 @@ itself.
With each newly created window, a shell program is spawned with its
process environment tailored to that window. Its standard input,
output, and diagnostic file descriptors are bound to one end of either
-a pseudo-terminal
-.Xr (pty 4 )
+a pseudo-terminal (see
+.Xr pty 4 )
or a
.Ux
-domain socket
-.Xr (socketpair 4 ) .
+domain socket (see
+.Xr socketpair 2 ) .
If a pseudo-terminal is used, then its special
characters and modes (see
.Xr stty 1 )
@@ -141,8 +141,8 @@ are copied from the physical
terminal. A
.Xr termcap 5
entry tailored to this window is created
-and passed as environment
-.Xr (environ 5 )
+and passed as environment (see
+.Xr environ 7 )
variable
.Ev TERMCAP .
The termcap entry contains the window's size and
diff --git a/usr.bin/window/ww.h b/usr.bin/window/ww.h
index 9241492..82c4acf 100644
--- a/usr.bin/window/ww.h
+++ b/usr.bin/window/ww.h
@@ -258,7 +258,7 @@ char *wwib; /* input (keyboard) buffer */
char *wwibe; /* wwib + sizeof buffer */
char *wwibp; /* current read position in buffer */
char *wwibq; /* current write position in buffer */
-#define wwmaskc(c) ((c) & 0x7f)
+#define wwmaskc(c) ((c) & 0xff)
#define wwgetc() (wwibp < wwibq ? wwmaskc(*wwibp++) : -1)
#define wwpeekc() (wwibp < wwibq ? wwmaskc(*wwibp) : -1)
#define wwungetc(c) (wwibp > wwib ? *--wwibp = (c) : -1)
@@ -307,8 +307,6 @@ char **wwalloc();
char *wwerror();
/* c library functions */
-char *malloc();
-char *calloc();
char *getenv();
char *tgetstr();
char *rindex();
diff --git a/usr.bin/window/wwclreol.c b/usr.bin/window/wwclreol.c
index d827f67..5f3f64a 100644
--- a/usr.bin/window/wwclreol.c
+++ b/usr.bin/window/wwclreol.c
@@ -58,7 +58,7 @@ char cleared;
{
register union ww_char *buf;
- buf = &w->ww_buf[row][col];
+ buf = &w->ww_buf[row][col];
for (i = w->ww_b.r - col; --i >= 0;)
buf++->c_w = ' ';
}
diff --git a/usr.bin/window/wwend.c b/usr.bin/window/wwend.c
index 9586f14..b984d2d 100644
--- a/usr.bin/window/wwend.c
+++ b/usr.bin/window/wwend.c
@@ -38,6 +38,7 @@
static char sccsid[] = "@(#)wwend.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#include <signal.h>
#include "ww.h"
#include "tt.h"
@@ -49,6 +50,7 @@ wwend(exit)
wwdocheckpoint = 0;
}
xxend();
+ (void) signal(SIGIO, SIG_DFL);
(void) wwsettty(0, &wwoldtty);
#ifdef TERMINFO
if (exit)
diff --git a/usr.bin/window/wwgets.c b/usr.bin/window/wwgets.c
index 1f69fa5..a7223b7 100644
--- a/usr.bin/window/wwgets.c
+++ b/usr.bin/window/wwgets.c
@@ -47,7 +47,7 @@ int n;
register struct ww *w;
{
register char *p = buf;
- register char c;
+ register int c;
char uc = w->ww_unctrl;
static void rub();
@@ -91,7 +91,10 @@ register struct ww *w;
if (p >= buf + n - 1)
wwputc(ctrl('g'), w);
else
- wwputs(unctrl(*p++ = c), w);
+ if (isctrl(c))
+ wwputs(unctrl(*p++ = c), w);
+ else
+ wwputc(*p++ = c, w);
}
}
*p = 0;
@@ -104,6 +107,6 @@ struct ww *w;
{
register i;
- for (i = strlen(unctrl(c)); --i >= 0;)
+ for (i = isctrl(c) ? strlen(unctrl(c)) : 1; --i >= 0;)
(void) wwwrite(w, "\b \b", 3);
}
diff --git a/usr.bin/window/wwinit.c b/usr.bin/window/wwinit.c
index 1bf26f4..05cc0b0 100644
--- a/usr.bin/window/wwinit.c
+++ b/usr.bin/window/wwinit.c
@@ -35,13 +35,14 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)wwinit.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)wwinit.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "ww.h"
#include "tt.h"
#include <sys/signal.h>
#include <fcntl.h>
+#include <termcap.h>
#include "char.h"
wwinit()
@@ -50,7 +51,7 @@ wwinit()
char *kp;
int s;
- wwdtablesize = 3;
+ wwdtablesize = getdtablesize();
wwhead.ww_forw = &wwhead;
wwhead.ww_back = &wwhead;
@@ -122,15 +123,11 @@ wwinit()
goto bad;
}
#ifdef OLD_TTY
- wwospeed = wwoldtty.ww_sgttyb.sg_ospeed;
-#else
- wwospeed = cfgetospeed(&wwoldtty.ww_termios);
-#endif
- switch (wwospeed) {
+ ospeed = wwoldtty.ww_sgttyb.sg_ospeed;
+ switch (ospeed) {
default:
case B0:
- wwbaud = 0;
- break;
+ goto bad;
case B50:
wwbaud = 50;
break;
@@ -184,7 +181,22 @@ wwinit()
#endif
wwbaud = 38400;
break;
+#ifdef B57600
+ case B57600:
+ wwbaud = 57600;
+ break;
+#endif
+#ifdef B115200
+ case B115200:
+ wwbaud = 115200;
+ break;
+#endif
}
+#else
+ if ((wwbaud = cfgetospeed(&wwoldtty.ww_termios)) == B0)
+ goto bad;
+#endif
+ wwospeed = ospeed;
if (xxinit() < 0)
goto bad;
@@ -312,8 +324,8 @@ bad:
* Don't bother to free storage. We're supposed
* to exit when wwinit fails anyway.
*/
- (void) wwsettty(0, &wwoldtty);
(void) signal(SIGIO, SIG_DFL);
+ (void) wwsettty(0, &wwoldtty);
(void) sigsetmask(s);
return -1;
}
@@ -354,6 +366,7 @@ wwstart()
register i;
(void) wwsettty(0, &wwnewtty);
+ signal(SIGIO, wwrint);
for (i = 0; i < wwnrow; i++)
wwtouched[i] = WWU_TOUCHED;
wwstart1();
diff --git a/usr.bin/window/wwinschar.c b/usr.bin/window/wwinschar.c
index d055fcd..b283f99 100644
--- a/usr.bin/window/wwinschar.c
+++ b/usr.bin/window/wwinschar.c
@@ -43,7 +43,7 @@ static char sccsid[] = "@(#)wwinschar.c 8.1 (Berkeley) 6/6/93";
wwinschar(w, row, col, c, m)
register struct ww *w;
-char c, m;
+unsigned char c, m;
{
register i;
int nvis;
diff --git a/usr.bin/window/wwlabel.c b/usr.bin/window/wwlabel.c
index d78e1f2..d4cc99e 100644
--- a/usr.bin/window/wwlabel.c
+++ b/usr.bin/window/wwlabel.c
@@ -60,7 +60,8 @@ char *l;
register char *fmap;
register char *smap;
char touched;
- char *p;
+ unsigned char *p;
+ static unsigned char cbuf[2];
if (f->ww_fmap == 0)
return;
@@ -78,8 +79,14 @@ char *l;
jj = MIN(w->ww_i.r, f->ww_i.r);
j = w->ww_i.l + where;
- while (j < jj && *l)
- for (p = unctrl(*l++); j < jj && *p; j++, p++) {
+ while (j < jj && *l) {
+ if (isctrl(*l))
+ p = unctrl(*l);
+ else {
+ cbuf[0] = *l;
+ p = cbuf;
+ }
+ for (l++; j < jj && *p; j++, p++) {
/* can't label if not already framed */
if (win[j] & WWM_GLS)
continue;
@@ -92,5 +99,6 @@ char *l;
}
fmap[j] |= WWF_LABEL;
}
+ }
wwtouched[row] = touched;
}
diff --git a/usr.bin/window/wwopen.c b/usr.bin/window/wwopen.c
index bddbb61..8a8be2a 100644
--- a/usr.bin/window/wwopen.c
+++ b/usr.bin/window/wwopen.c
@@ -35,13 +35,14 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)wwopen.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)wwopen.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "ww.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
+#include <stdlib.h>
struct ww *
wwopen(flags, nrow, ncol, row, col, nline)
@@ -116,8 +117,6 @@ wwopen(flags, nrow, ncol, row, col, nline)
}
w->ww_obe = w->ww_ob + 512;
w->ww_obp = w->ww_obq = w->ww_ob;
- if (w->ww_pty >= wwdtablesize)
- wwdtablesize = w->ww_pty + 1;
}
w->ww_win = wwalloc(w->ww_w.t, w->ww_w.l,
diff --git a/usr.bin/window/wwwrite.c b/usr.bin/window/wwwrite.c
index d406cbc..9880460 100644
--- a/usr.bin/window/wwwrite.c
+++ b/usr.bin/window/wwwrite.c
@@ -58,12 +58,12 @@ static char sccsid[] = "@(#)wwwrite.c 8.1 (Berkeley) 6/6/93";
*/
wwwrite(w, p, n)
register struct ww *w;
-register char *p;
+register unsigned char *p;
int n;
{
char hascursor;
- char *savep = p;
- char *q = p + n;
+ unsigned char *savep = p;
+ unsigned char *q = p + n;
char *r = 0;
char *s;
diff --git a/usr.bin/window/xx.c b/usr.bin/window/xx.c
index 9b68b96..a5a1cc1 100644
--- a/usr.bin/window/xx.c
+++ b/usr.bin/window/xx.c
@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)xx.c 8.1 (Berkeley) 6/6/93";
#include "ww.h"
#include "xx.h"
#include "tt.h"
+#include <stdlib.h>
xxinit()
{
diff --git a/usr.bin/write/write.1 b/usr.bin/write/write.1
index 89d7302..16cb704 100644
--- a/usr.bin/write/write.1
+++ b/usr.bin/write/write.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)write.1 8.1 (Berkeley) 6/6/93
+.\" $Id: write.1,v 1.4 1997/02/22 19:57:53 peter Exp $
.\"
.Dd June 6, 1993
.Dt WRITE 1
@@ -71,11 +72,6 @@ You can prevent people (other than the super-user) from writing to you
with the
.Xr mesg 1
command.
-Some commands, for example
-.Xr nroff 1
-and
-.Xr pr 1 ,
-disallow writing automatically, so that your output isn't overwritten.
.Pp
If the user you want to write to is logged in on more than one terminal,
you can specify which terminal to write to by specifying the terminal
@@ -105,4 +101,4 @@ over.
A
.Nm
command appeared in
-.At v6 .
+.At v1 .
diff --git a/usr.bin/write/write.c b/usr.bin/write/write.c
index 7ceedfb..dd0248d 100644
--- a/usr.bin/write/write.c
+++ b/usr.bin/write/write.c
@@ -41,7 +41,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)write.c 8.2 (Berkeley) 4/27/95";
+static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <sys/param.h>
@@ -49,10 +49,9 @@ static char sccsid[] = "@(#)write.c 8.2 (Berkeley) 4/27/95";
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
-
-#include <err.h>
#include <utmp.h>
#include <ctype.h>
+#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
@@ -77,16 +76,23 @@ main(argc, argv)
myttyfd = fileno(stdout);
else if (isatty(fileno(stderr)))
myttyfd = fileno(stderr);
- else
- errx(1, "can't find your tty");
- if (!(mytty = ttyname(myttyfd)))
- errx(1, "can't find your tty's name");
- if (cp = strrchr(mytty, '/'))
+ else {
+ (void)fprintf(stderr, "write: can't find your tty\n");
+ exit(1);
+ }
+ if (!(mytty = ttyname(myttyfd))) {
+ (void)fprintf(stderr, "write: can't find your tty's name\n");
+ exit(1);
+ }
+ if (cp = rindex(mytty, '/'))
mytty = cp + 1;
if (term_chk(mytty, &msgsok, &atime, 1))
exit(1);
- if (!msgsok)
- errx(1, "you have write permission turned off");
+ if (!msgsok) {
+ (void)fprintf(stderr,
+ "write: you have write permission turned off.\n");
+ exit(1);
+ }
myuid = getuid();
@@ -97,16 +103,22 @@ main(argc, argv)
do_write(tty, mytty, myuid);
break;
case 3:
- if (!strncmp(argv[2], "/dev/", 5))
- argv[2] += 5;
- if (utmp_chk(argv[1], argv[2]))
- errx(1, "%s is not logged in on %s",
+ if (!strncmp(argv[2], _PATH_DEV, strlen(_PATH_DEV)))
+ argv[2] += strlen(_PATH_DEV);
+ if (utmp_chk(argv[1], argv[2])) {
+ (void)fprintf(stderr,
+ "write: %s is not logged in on %s.\n",
argv[1], argv[2]);
+ exit(1);
+ }
if (term_chk(argv[2], &msgsok, &atime, 1))
exit(1);
- if (myuid && !msgsok)
- errx(1, "%s has messages disabled on %s",
+ if (myuid && !msgsok) {
+ (void)fprintf(stderr,
+ "write: %s has messages disabled on %s\n",
argv[1], argv[2]);
+ exit(1);
+ }
do_write(argv[2], mytty, myuid);
break;
default:
@@ -161,8 +173,10 @@ search_utmp(user, tty, mytty, myuid)
int ufd, nloggedttys, nttys, msgsok, user_is_me;
char atty[UT_LINESIZE + 1];
- if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
- err(1, "%s", _PATH_UTMP);
+ if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
+ perror("utmp");
+ exit(1);
+ }
nloggedttys = nttys = 0;
bestatime = 0;
@@ -188,17 +202,23 @@ search_utmp(user, tty, mytty, myuid)
}
(void)close(ufd);
- if (nloggedttys == 0)
- errx(1, "%s is not logged in", user);
+ if (nloggedttys == 0) {
+ (void)fprintf(stderr, "write: %s is not logged in\n", user);
+ exit(1);
+ }
if (nttys == 0) {
if (user_is_me) { /* ok, so write to yourself! */
(void)strcpy(tty, mytty);
return;
}
- errx(1, "%s has messages disabled", user);
- } else if (nttys > 1)
- warnx("%s is logged in more than once; writing to %s",
+ (void)fprintf(stderr,
+ "write: %s has messages disabled\n", user);
+ exit(1);
+ } else if (nttys > 1) {
+ (void)fprintf(stderr,
+ "write: %s is logged in more than once; writing to %s\n",
user, tty);
+ }
}
/*
@@ -213,10 +233,11 @@ term_chk(tty, msgsokP, atimeP, showerror)
struct stat s;
char path[MAXPATHLEN];
- (void)sprintf(path, "/dev/%s", tty);
+ (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
if (stat(path, &s) < 0) {
if (showerror)
- warn("%s", path);
+ (void)fprintf(stderr,
+ "write: %s: %s\n", path, strerror(errno));
return(1);
}
*msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
@@ -244,9 +265,11 @@ do_write(tty, mytty, myuid)
else
login = "???";
- (void)sprintf(path, "/dev/%s", tty);
- if ((freopen(path, "w", stdout)) == NULL)
- err(1, "%s", path);
+ (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
+ if ((freopen(path, "w", stdout)) == NULL) {
+ (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
(void)signal(SIGINT, done);
(void)signal(SIGHUP, done);
@@ -279,25 +302,30 @@ done()
* turns \n into \r\n
*/
wr_fputs(s)
- register char *s;
+ register unsigned char *s;
{
- register char c;
#define PUTC(c) if (putchar(c) == EOF) goto err;
for (; *s != '\0'; ++s) {
- c = toascii(*s);
- if (c == '\n') {
+ if (*s == '\n') {
PUTC('\r');
- PUTC('\n');
- } else if (!isprint(c) && !isspace(c) && c != '\007') {
- PUTC('^');
- PUTC(c^0x40); /* DEL to ?, others to alpha */
- } else
- PUTC(c);
+ } else if (!isprint(*s) && !isspace(*s) && *s != '\007') {
+ if (*s & 0x80) {
+ *s &= ~0x80;
+ PUTC('M');
+ PUTC('-');
+ }
+ if (iscntrl(*s)) {
+ *s ^= 0x40;
+ PUTC('^');
+ }
+ }
+ PUTC(*s);
}
return;
-err: err(1, NULL);
+err: (void)fprintf(stderr, "write: %s\n", strerror(errno));
+ exit(1);
#undef PUTC
}
diff --git a/usr.bin/xargs/xargs.1 b/usr.bin/xargs/xargs.1
index e703c43..ab10647 100644
--- a/usr.bin/xargs/xargs.1
+++ b/usr.bin/xargs/xargs.1
@@ -43,6 +43,7 @@
.Nd "construct argument list(s) and execute utility"
.Sh SYNOPSIS
.Nm xargs
+.Op Fl 0
.Op Fl t
.Oo Op Fl x
.Fl n Ar number
@@ -79,6 +80,16 @@ Any single character, including newlines, may be escaped by a backslash.
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl 0
+Changes
+.Nm xargs
+to expect NUL
+(``\\0'')
+characters as seperators, instead of spaces and newlines.
+This is expected to be used in concert with the
+.Fl print0
+function in
+.Nm find .
.It Fl n Ar number
Set the maximum number of arguments taken from standard input for each
invocation of the utility.
diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c
index e28e840..a0e8c0d 100644
--- a/usr.bin/xargs/xargs.c
+++ b/usr.bin/xargs/xargs.c
@@ -55,19 +55,20 @@ static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
#include "pathnames.h"
int tflag, rval;
+int zflag;
void err __P((const char *, ...));
void run __P((char **));
void usage __P((void));
-main(argc, argv)
+main(argc, argv, env)
int argc;
- char **argv;
+ char **argv, **env;
{
register int ch;
register char *p, *bbp, *ebp, **bxp, **exp, **xp;
int cnt, indouble, insingle, nargs, nflag, nline, xflag;
- char **av, *argp;
+ char **av, *argp, **ep = env;
/*
* POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
@@ -84,8 +85,12 @@ main(argc, argv)
*/
nargs = 5000;
nline = ARG_MAX - 4 * 1024;
+ while (*ep) {
+ /* 1 byte for each '\0' */
+ nline -= strlen(*ep++) + 1 + sizeof(*ep);
+ }
nflag = xflag = 0;
- while ((ch = getopt(argc, argv, "n:s:tx")) != EOF)
+ while ((ch = getopt(argc, argv, "0n:s:tx")) != -1)
switch(ch) {
case 'n':
nflag = 1;
@@ -101,6 +106,9 @@ main(argc, argv)
case 'x':
xflag = 1;
break;
+ case '0':
+ zflag = 1;
+ break;
case '?':
default:
usage();
@@ -174,10 +182,17 @@ main(argc, argv)
case ' ':
case '\t':
/* Quotes escape tabs and spaces. */
- if (insingle || indouble)
+ if (insingle || indouble || zflag)
goto addch;
goto arg2;
+ case '\0':
+ if (zflag)
+ goto arg2;
+ goto addch;
case '\n':
+ if (zflag)
+ goto addch;
+
/* Empty lines are skipped. */
if (argp == p)
continue;
@@ -208,16 +223,18 @@ arg2: *p = '\0';
argp = p;
break;
case '\'':
- if (indouble)
+ if (indouble || zflag)
goto addch;
insingle = !insingle;
break;
case '"':
- if (insingle)
+ if (insingle || zflag)
goto addch;
indouble = !indouble;
break;
case '\\':
+ if (zflag)
+ goto addch;
/* Backslash escapes anything, is escaped by quotes. */
if (!insingle && !indouble && (ch = getchar()) == EOF)
err("backslash at EOF");
@@ -291,7 +308,7 @@ void
usage()
{
(void)fprintf(stderr,
-"usage: xargs [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n");
+"usage: xargs [-0] [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n");
exit(1);
}
diff --git a/usr.bin/xinstall/Makefile b/usr.bin/xinstall/Makefile
index 69de3ab..d21abef 100644
--- a/usr.bin/xinstall/Makefile
+++ b/usr.bin/xinstall/Makefile
@@ -2,11 +2,11 @@
PROG= xinstall
SRCS= stat_flags.c xinstall.c
-MAN1= install.0
+MAN1= install.1
.PATH: ${.CURDIR}/../../bin/ls
install: maninstall
- install ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${INSTALL} ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${PROG} ${DESTDIR}${BINDIR}/install
.include <bsd.prog.mk>
diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1
index c35c7a5..71cc4b8 100644
--- a/usr.bin/xinstall/install.1
+++ b/usr.bin/xinstall/install.1
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)install.1 8.1 (Berkeley) 6/6/93
+.\" From: @(#)install.1 8.1 (Berkeley) 6/6/93
+.\" $Id$
.\"
-.Dd June 6, 1993
+.Dd September 22, 1996
.Dt INSTALL 1
.Os BSD 4.2
.Sh NAME
@@ -39,14 +40,14 @@
.Nd install binaries
.Sh SYNOPSIS
.Nm install
-.Op Fl cs
+.Op Fl CcDps
.Op Fl f Ar flags
.Op Fl g Ar group
.Op Fl m Ar mode
.Op Fl o Ar owner
.Ar file1 file2
.Nm install
-.Op Fl cs
+.Op Fl CcDps
.Op Fl f Ar flags
.Op Fl g Ar group
.Op Fl m Ar mode
@@ -54,6 +55,13 @@
.Ar file1
\&...
.Ar fileN directory
+.Nm install
+.Fl d
+.Op Fl g Ar group
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Ar directory
+\&...
.Sh DESCRIPTION
The file(s) are moved (or copied if the
.Fl c
@@ -67,18 +75,39 @@ If the target file already exists, it is overwritten if permissions
allow.
.Pp
.Bl -tag -width Ds
+.It Fl C
+Copy the file, as if the
+.Fl c
+option is specified,
+except if the target file already exists and the files are the same,
+then don't change the modification time of the target.
.It Fl c
Copy the file.
This flag turns off the default behavior of
.Nm install
where it deletes the original file after creating the target.
+.It Fl D
+Print debugging information.
+If
+.Fl D
+is specified one or more times,
+then print the renaming steps for
+.Fl C .
+If
+.Fl D
+is specified two or more times,
+then warn about files that aren't installed with
+.Fl C .
+.It Fl d
+Create directories.
+Missing parent directories are created as required.
.It Fl f
Specify the target's file flags.
(See
.Xr chflags 1
for a list of possible flags and their meanings.)
.It Fl g
-Specify a group.
+Specify a group. A numeric GID is allowed.
.It Fl m
Specify an alternate mode.
The default mode is set to rwxr-xr-x (0755).
@@ -86,7 +115,14 @@ The specified mode may be either an octal or symbolic value; see
.Xr chmod 1
for a description of possible mode values.
.It Fl o
-Specify an owner.
+Specify an owner. A numeric UID is allowed.
+.It Fl p
+Preserve the modification time.
+Copy the file, as if the
+.Fl C
+(Compare and copy) option is specified,
+except if the target file doesn't already exist or is different,
+then preserve the modification time of the file.
.It Fl s
.Nm Install
exec's the command
@@ -109,6 +145,17 @@ creates an empty file.
.Pp
Upon successful completion a value of 0 is returned.
Otherwise, a value of 1 is returned.
+.Sh FILES
+.Bl -tag -width INS@XXXX -compact
+.It Pa INS@XXXX
+If the
+.Fl C
+or
+.Fl p
+option is used, then temporary files named INS@XXXX,
+where XXXX is decided by
+.Xr mkstemp 3 ,
+are created in the target directory.
.Sh SEE ALSO
.Xr chflags 1 ,
.Xr chgrp 1 ,
@@ -122,3 +169,7 @@ The
.Nm install
utility appeared in
.Bx 4.2 .
+.Sh BUGS
+Temporary files may be left in the target directory if
+.Nm install
+exits abnormally.
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index 4c41fa8..d809f2c 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -32,21 +32,40 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1987, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
+/*static char sccsid[] = "From: @(#)xinstall.c 8.1 (Berkeley) 7/21/93";*/
+static const char rcsid[] =
+ "$Id: xinstall.c,v 1.22 1997/03/29 04:34:07 imp Exp $";
#endif /* not lint */
+/*-
+ * Todo:
+ * o for -C, compare original files except in -s case.
+ * o for -C, don't change anything if nothing needs be changed. In
+ * particular, don't toggle the immutable flags just to allow null
+ * attribute changes and don't clear the dump flag. (I think inode
+ * ctimes are not updated for null attribute changes, but this is a
+ * bug.)
+ * o independent of -C, if a copy must be made, then copy to a tmpfile,
+ * set all attributes except the immutable flags, then rename, then
+ * set the immutable flags. It's annoying that the immutable flags
+ * defeat the atomicicity of rename - it seems that there must be
+ * o a window where the target is not immutable.
+ */
+
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/mount.h>
#include <ctype.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
@@ -56,24 +75,51 @@ static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sysexits.h>
+#include <utime.h>
#include "pathnames.h"
-struct passwd *pp;
-struct group *gp;
-int docopy, dostrip;
+/* Bootstrap aid - this doesn't exist in most older releases */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((caddr_t)-1) /* from <sys/mman.h> */
+#endif
+
+int debug, docompare, docopy, dodir, dopreserve, dostrip, verbose;
int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
char *group, *owner, pathbuf[MAXPATHLEN];
+char pathbuf2[MAXPATHLEN];
#define DIRECTORY 0x01 /* Tell install it's a directory. */
#define SETFLAGS 0x02 /* Tell install to set flags. */
+#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
void copy __P((int, char *, int, char *, off_t));
-void err __P((const char *, ...));
+int compare __P((int, const char *, int, const char *,
+ const struct stat *, const struct stat *));
void install __P((char *, char *, u_long, u_int));
+void install_dir __P((char *));
u_long string_to_flags __P((char **, u_long *, u_long *));
void strip __P((char *));
void usage __P((void));
+int trymmap __P((int));
+
+#define ALLOW_NUMERIC_IDS 1
+#ifdef ALLOW_NUMERIC_IDS
+
+uid_t uid;
+gid_t gid;
+
+uid_t resolve_uid __P((char *));
+gid_t resolve_gid __P((char *));
+u_long numeric_id __P((char *, char *));
+
+#else
+
+struct passwd *pp;
+struct group *gp;
+
+#endif /* ALLOW_NUMERIC_IDS */
int
main(argc, argv)
@@ -88,15 +134,24 @@ main(argc, argv)
char *flags, *to_name;
iflags = 0;
- while ((ch = getopt(argc, argv, "cf:g:m:o:s")) != EOF)
+ while ((ch = getopt(argc, argv, "CcdDf:g:m:o:psv")) != -1)
switch((char)ch) {
+ case 'C':
+ docompare = docopy = 1;
+ break;
case 'c':
docopy = 1;
break;
+ case 'D':
+ debug++;
+ break;
+ case 'd':
+ dodir = 1;
+ break;
case 'f':
flags = optarg;
if (string_to_flags(&flags, &fset, NULL))
- err("%s: invalid flag", flags);
+ errx(EX_USAGE, "%s: invalid flag", flags);
iflags |= SETFLAGS;
break;
case 'g':
@@ -104,35 +159,67 @@ main(argc, argv)
break;
case 'm':
if (!(set = setmode(optarg)))
- err("%s: invalid file mode", optarg);
+ errx(EX_USAGE, "invalid file mode: %s",
+ optarg);
mode = getmode(set, 0);
break;
case 'o':
owner = optarg;
break;
+ case 'p':
+ docompare = docopy = dopreserve = 1;
+ break;
case 's':
dostrip = 1;
break;
+ case 'v':
+ verbose = 1;
+ break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
- if (argc < 2)
+
+ /* some options make no sense when creating directories */
+ if ((docompare || dostrip) && dodir)
+ usage();
+
+ /* must have at least two arguments, except when creating directories */
+ if (argc < 2 && !dodir)
usage();
+#ifdef ALLOW_NUMERIC_IDS
+
+ if (owner)
+ uid = resolve_uid(owner);
+ if (group)
+ gid = resolve_gid(group);
+
+#else
+
/* get group and owner id's */
- if (group && !(gp = getgrnam(group)))
- err("unknown group %s", group);
if (owner && !(pp = getpwnam(owner)))
- err("unknown user %s", owner);
+ errx(EX_NOUSER, "unknown user %s", owner);
+ if (group && !(gp = getgrnam(group)))
+ errx(EX_NOUSER, "unknown group %s", group);
+
+#endif /* ALLOW_NUMERIC_IDS */
+
+ if (dodir) {
+ for (; *argv != NULL; ++argv)
+ install_dir(*argv);
+ exit(EX_OK);
+ /* NOTREACHED */
+ }
no_target = stat(to_name = argv[argc - 1], &to_sb);
if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
for (; *argv != to_name; ++argv)
install(*argv, to_name, fset, iflags | DIRECTORY);
- exit(0);
+ exit(EX_OK);
+ /* NOTREACHED */
}
/* can't do file1 file2 directory/file */
@@ -141,27 +228,81 @@ main(argc, argv)
if (!no_target) {
if (stat(*argv, &from_sb))
- err("%s: %s", *argv, strerror(errno));
- if (!S_ISREG(to_sb.st_mode))
- err("%s: %s", to_name, strerror(EFTYPE));
+ err(EX_OSERR, "%s", *argv);
+ if (!S_ISREG(to_sb.st_mode)) {
+ errno = EFTYPE;
+ err(EX_OSERR, "%s", to_name);
+ }
if (to_sb.st_dev == from_sb.st_dev &&
to_sb.st_ino == from_sb.st_ino)
- err("%s and %s are the same file", *argv, to_name);
+ errx(EX_USAGE,
+ "%s and %s are the same file", *argv, to_name);
+/*
+ * XXX - It's not at all clear why this code was here, since it completely
+ * duplicates code install(). The version in install() handles the -C flag
+ * correctly, so we'll just disable this for now.
+ */
+#if 0
/*
* Unlink now... avoid ETXTBSY errors later. Try and turn
* off the append/immutable bits -- if we fail, go ahead,
* it might work.
*/
-#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
if (to_sb.st_flags & NOCHANGEBITS)
(void)chflags(to_name,
to_sb.st_flags & ~(NOCHANGEBITS));
(void)unlink(to_name);
+#endif
}
install(*argv, to_name, fset, iflags);
- exit(0);
+ exit(EX_OK);
+ /* NOTREACHED */
+}
+
+#ifdef ALLOW_NUMERIC_IDS
+
+uid_t
+resolve_uid(s)
+ char *s;
+{
+ struct passwd *pw;
+
+ return ((pw = getpwnam(s)) == NULL) ?
+ (uid_t) numeric_id(s, "user") : pw->pw_uid;
+}
+
+gid_t
+resolve_gid(s)
+ char *s;
+{
+ struct group *gr;
+
+ return ((gr = getgrnam(s)) == NULL) ?
+ (gid_t) numeric_id(s, "group") : gr->gr_gid;
+}
+
+u_long
+numeric_id(name, type)
+ char *name, *type;
+{
+ u_long val;
+ char *ep;
+
+ /*
+ * XXX
+ * We know that uid_t's and gid_t's are unsigned longs.
+ */
+ errno = 0;
+ val = strtoul(name, &ep, 10);
+ if (errno)
+ err(EX_NOUSER, "%s", name);
+ if (*ep != '\0')
+ errx(EX_NOUSER, "unknown %s %s", type, name);
+ return (val);
}
+#endif /* ALLOW_NUMERIC_IDS */
+
/*
* install --
* build a path name and install the file
@@ -174,19 +315,25 @@ install(from_name, to_name, fset, flags)
{
struct stat from_sb, to_sb;
int devnull, from_fd, to_fd, serrno;
- char *p;
+ char *p, *old_to_name = 0;
+
+ if (debug >= 2 && !docompare)
+ fprintf(stderr, "install: invoked without -C for %s to %s\n",
+ from_name, to_name);
/* If try to install NULL file to a directory, fails. */
if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
if (stat(from_name, &from_sb))
- err("%s: %s", from_name, strerror(errno));
- if (!S_ISREG(from_sb.st_mode))
- err("%s: %s", from_name, strerror(EFTYPE));
+ err(EX_OSERR, "%s", from_name);
+ if (!S_ISREG(from_sb.st_mode)) {
+ errno = EFTYPE;
+ err(EX_OSERR, "%s", from_name);
+ }
/* Build the target path. */
if (flags & DIRECTORY) {
(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
to_name,
- (p = rindex(from_name, '/')) ? ++p : from_name);
+ (p = strrchr(from_name, '/')) ? ++p : from_name);
to_name = pathbuf;
}
devnull = 0;
@@ -195,44 +342,142 @@ install(from_name, to_name, fset, flags)
devnull = 1;
}
- /*
- * Unlink now... avoid ETXTBSY errors later. Try and turn
- * off the append/immutable bits -- if we fail, go ahead,
- * it might work.
- */
- if (stat(to_name, &to_sb) == 0 &&
- to_sb.st_flags & (NOCHANGEBITS))
- (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
- (void)unlink(to_name);
-
- /* Create target. */
- if ((to_fd = open(to_name,
- O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
- err("%s: %s", to_name, strerror(errno));
+ if (docompare) {
+ old_to_name = to_name;
+ /*
+ * Make a new temporary file in the same file system
+ * (actually, in in the same directory) as the target so
+ * that the temporary file can be renamed to the target.
+ */
+ snprintf(pathbuf2, sizeof pathbuf2, "%s", to_name);
+ p = strrchr(pathbuf2, '/');
+ p = (p == NULL ? pathbuf2 : p + 1);
+ snprintf(p, &pathbuf2[sizeof pathbuf2] - p, "INS@XXXX");
+ to_fd = mkstemp(pathbuf2);
+ if (to_fd < 0)
+ /* XXX should fall back to not comparing. */
+ err(EX_OSERR, "mkstemp: %s for %s", pathbuf2, to_name);
+ to_name = pathbuf2;
+ } else {
+ /*
+ * Unlink now... avoid errors later. Try to turn off the
+ * append/immutable bits -- if we fail, go ahead, it might
+ * work.
+ */
+ if (stat(to_name, &to_sb) == 0 && to_sb.st_flags & NOCHANGEBITS)
+ (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
+ unlink(to_name);
+
+ /* Create target. */
+ to_fd = open(to_name,
+ O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (to_fd < 0)
+ err(EX_OSERR, "%s", to_name);
+ }
+
if (!devnull) {
if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
+ serrno = errno;
(void)unlink(to_name);
- err("%s: %s", from_name, strerror(errno));
+ errno = serrno;
+ err(EX_OSERR, "%s", from_name);
}
copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
(void)close(from_fd);
}
+
if (dostrip)
strip(to_name);
+
+ /*
+ * Unfortunately, because we strip the installed file and not the
+ * original one, it is impossible to do the comparison without
+ * first laboriously copying things over and then comparing.
+ * It may be possible to better optimize the !dostrip case, however.
+ * For further study.
+ */
+ if (docompare) {
+ struct stat old_sb, new_sb, timestamp_sb;
+ int old_fd;
+ struct utimbuf utb;
+
+ old_fd = open(old_to_name, O_RDONLY, 0);
+ if (old_fd < 0 && errno == ENOENT)
+ goto different;
+ if (old_fd < 0)
+ err(EX_OSERR, "%s", old_to_name);
+ fstat(old_fd, &old_sb);
+ if (old_sb.st_flags & NOCHANGEBITS)
+ (void)fchflags(old_fd, old_sb.st_flags & ~NOCHANGEBITS);
+ fstat(to_fd, &new_sb);
+ if (compare(old_fd, old_to_name, to_fd, to_name, &old_sb,
+ &new_sb)) {
+different:
+ if (debug != 0)
+ fprintf(stderr,
+ "install: renaming for %s: %s to %s\n",
+ from_name, to_name, old_to_name);
+ if (dopreserve && stat(from_name, &timestamp_sb) == 0) {
+ utb.actime = from_sb.st_atime;
+ utb.modtime = from_sb.st_mtime;
+ (void)utime(to_name, &utb);
+ }
+moveit:
+ if (verbose) {
+ printf("install: %s -> %s\n",
+ from_name, old_to_name);
+ }
+ if (rename(to_name, old_to_name) < 0) {
+ serrno = errno;
+ unlink(to_name);
+ unlink(old_to_name);
+ errno = serrno;
+ err(EX_OSERR, "rename: %s to %s", to_name,
+ old_to_name);
+ }
+ close(old_fd);
+ } else {
+ if (old_sb.st_nlink != 1) {
+ /*
+ * Replace the target, although it hasn't
+ * changed, to snap the extra links. But
+ * preserve the target file times.
+ */
+ if (fstat(old_fd, &timestamp_sb) == 0) {
+ utb.actime = timestamp_sb.st_atime;
+ utb.modtime = timestamp_sb.st_mtime;
+ (void)utime(to_name, &utb);
+ }
+ goto moveit;
+ }
+ if (unlink(to_name) < 0)
+ err(EX_OSERR, "unlink: %s", to_name);
+ close(to_fd);
+ to_fd = old_fd;
+ }
+ to_name = old_to_name;
+ }
+
/*
* Set owner, group, mode for target; do the chown first,
* chown may lose the setuid bits.
*/
if ((group || owner) &&
+#ifdef ALLOW_NUMERIC_IDS
+ fchown(to_fd, owner ? uid : -1, group ? gid : -1)) {
+#else
fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1)) {
+#endif
serrno = errno;
(void)unlink(to_name);
- err("%s: chown/chgrp: %s", to_name, strerror(serrno));
+ errno = serrno;
+ err(EX_OSERR,"%s: chown/chgrp", to_name);
}
if (fchmod(to_fd, mode)) {
serrno = errno;
(void)unlink(to_name);
- err("%s: chmod: %s", to_name, strerror(serrno));
+ errno = serrno;
+ err(EX_OSERR, "%s: chmod", to_name);
}
/*
@@ -243,12 +488,79 @@ install(from_name, to_name, fset, flags)
flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
serrno = errno;
(void)unlink(to_name);
- err("%s: chflags: %s", to_name, strerror(serrno));
+ errno = serrno;
+ err(EX_OSERR, "%s: chflags", to_name);
}
(void)close(to_fd);
if (!docopy && !devnull && unlink(from_name))
- err("%s: %s", from_name, strerror(errno));
+ err(EX_OSERR, "%s", from_name);
+}
+
+/*
+ * compare --
+ * compare two files; non-zero means files differ
+ */
+int
+compare(int from_fd, const char *from_name, int to_fd, const char *to_name,
+ const struct stat *from_sb, const struct stat *to_sb)
+{
+ char *p, *q;
+ int rv;
+ size_t tsize;
+ int done_compare;
+
+ if (from_sb->st_size != to_sb->st_size)
+ return 1;
+
+ tsize = (size_t)from_sb->st_size;
+
+ if (tsize <= 8 * 1024 * 1024) {
+ done_compare = 0;
+ if (trymmap(from_fd) && trymmap(to_fd)) {
+ p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
+ if (p == (char *)MAP_FAILED)
+ goto out;
+ q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
+ if (q == (char *)MAP_FAILED) {
+ munmap(p, tsize);
+ goto out;
+ }
+
+ rv = memcmp(p, q, tsize);
+ munmap(p, tsize);
+ munmap(q, tsize);
+ done_compare = 1;
+ }
+ out:
+ if (!done_compare) {
+ char buf1[MAXBSIZE];
+ char buf2[MAXBSIZE];
+ int n1, n2;
+
+ rv = 0;
+ lseek(from_fd, 0, SEEK_SET);
+ lseek(to_fd, 0, SEEK_SET);
+ while (rv == 0) {
+ n1 = read(from_fd, buf1, sizeof(buf1));
+ if (n1 == 0)
+ break; /* EOF */
+ else if (n1 > 0) {
+ n2 = read(to_fd, buf2, n1);
+ if (n2 == n1)
+ rv = memcmp(buf1, buf2, n1);
+ else
+ rv = 1; /* out of sync */
+ } else
+ rv = 1; /* read failure */
+ }
+ lseek(from_fd, 0, SEEK_SET);
+ lseek(to_fd, 0, SEEK_SET);
+ }
+ } else
+ rv = 1; /* don't bother in this case */
+
+ return rv;
}
/*
@@ -264,30 +576,40 @@ copy(from_fd, from_name, to_fd, to_name, size)
register int nr, nw;
int serrno;
char *p, buf[MAXBSIZE];
+ int done_copy;
/*
* Mmap and write if less than 8M (the limit is so we don't totally
* trash memory on big files. This is really a minor hack, but it
* wins some CPU back.
*/
- if (size <= 8 * 1048576) {
+ done_copy = 0;
+ if (size <= 8 * 1048576 && trymmap(from_fd)) {
if ((p = mmap(NULL, (size_t)size, PROT_READ,
- 0, from_fd, (off_t)0)) == (char *)-1)
- err("%s: %s", from_name, strerror(errno));
- if (write(to_fd, p, size) != size)
- err("%s: %s", to_name, strerror(errno));
- } else {
+ MAP_SHARED, from_fd, (off_t)0)) == (char *)MAP_FAILED)
+ goto out;
+ if ((nw = write(to_fd, p, size)) != size) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = nw > 0 ? EIO : serrno;
+ err(EX_OSERR, "%s", to_name);
+ }
+ done_copy = 1;
+ out:
+ }
+ if (!done_copy) {
while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
if ((nw = write(to_fd, buf, nr)) != nr) {
serrno = errno;
(void)unlink(to_name);
- err("%s: %s",
- to_name, strerror(nw > 0 ? EIO : serrno));
+ errno = nw > 0 ? EIO : serrno;
+ err(EX_OSERR, "%s", to_name);
}
if (nr != 0) {
serrno = errno;
(void)unlink(to_name);
- err("%s: %s", from_name, strerror(serrno));
+ errno = serrno;
+ err(EX_OSERR, "%s", from_name);
}
}
}
@@ -306,13 +628,49 @@ strip(to_name)
case -1:
serrno = errno;
(void)unlink(to_name);
- err("forks: %s", strerror(errno));
+ errno = serrno;
+ err(EX_TEMPFAIL, "fork");
case 0:
- execl(_PATH_STRIP, "strip", to_name, NULL);
- err("%s: %s", _PATH_STRIP, strerror(errno));
+ execlp("strip", "strip", to_name, NULL);
+ err(EX_OSERR, "exec(strip)");
default:
- if (wait(&status) == -1 || status)
+ if (wait(&status) == -1 || status) {
(void)unlink(to_name);
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ }
+}
+
+/*
+ * install_dir --
+ * build directory heirarchy
+ */
+void
+install_dir(path)
+ char *path;
+{
+ register char *p;
+ struct stat sb;
+ int ch;
+
+ for (p = path;; ++p)
+ if (!*p || (p != path && *p == '/')) {
+ ch = *p;
+ *p = '\0';
+ if (stat(path, &sb)) {
+ if (errno != ENOENT || mkdir(path, 0777) < 0) {
+ err(EX_OSERR, "%s", path);
+ /* NOTREACHED */
+ }
+ }
+ if (!(*p = ch))
+ break;
+ }
+
+ if (((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid)) ||
+ chmod(path, mode)) {
+ warn("%s", path);
}
}
@@ -323,36 +681,31 @@ strip(to_name)
void
usage()
{
- (void)fprintf(stderr,
-"usage: install [-cs] [-f flags] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
- exit(1);
+ (void)fprintf(stderr,"\
+usage: install [-CcDps] [-f flags] [-g group] [-m mode] [-o owner] file1 file2\n\
+ install [-CcDps] [-f flags] [-g group] [-m mode] [-o owner] file1 ...\n\
+ fileN directory\n\
+ install -d [-g group] [-m mode] [-o owner] directory ...\n");
+ exit(EX_USAGE);
+ /* NOTREACHED */
}
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
+/*
+ * trymmap --
+ * return true (1) if mmap should be tried, false (0) if not.
+ */
+int
+trymmap(fd)
+ int fd;
{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "install: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- exit(1);
- /* NOTREACHED */
+ struct statfs stfs;
+
+ if (fstatfs(fd, &stfs) < 0)
+ return 0;
+ switch(stfs.f_type) {
+ case MOUNT_UFS: /* should be safe.. */
+ case MOUNT_CD9660: /* should be safe.. */
+ return 1;
+ }
+ return 0;
}
diff --git a/usr.bin/xlint/Makefile b/usr.bin/xlint/Makefile
new file mode 100644
index 0000000..69338b7
--- /dev/null
+++ b/usr.bin/xlint/Makefile
@@ -0,0 +1,5 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:23:45 cgd Exp $
+
+SUBDIR= lint1 lint2 xlint #llib
+
+.include <bsd.subdir.mk>
diff --git a/usr.bin/xlint/lint1/Makefile b/usr.bin/xlint/lint1/Makefile
new file mode 100644
index 0000000..d5e519a
--- /dev/null
+++ b/usr.bin/xlint/lint1/Makefile
@@ -0,0 +1,19 @@
+# $NetBSD: Makefile,v 1.3 1995/07/04 01:53:05 cgd Exp $
+
+PROG= lint1
+SRCS= cgram.c scan.c mem1.c mem.c err.c main1.c decl.c tree.c func.c \
+ init.c emit.c emit1.c
+NOMAN=
+LDADD+= -ll
+DPADD+= ${LIBL}
+YFLAGS= -d
+CFLAGS+=-I.
+LINTFLAGS=-aehpz
+CLEANFILES+=y.tab.h cgram.c scan.c
+
+BINDIR= /usr/libexec
+
+# XXX: -O causes the gcc to die on the i386, when compiling tree.o
+CFLAGS+= -DXXX_BROKEN_GCC
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint1/cgram.y b/usr.bin/xlint/lint1/cgram.y
new file mode 100644
index 0000000..6be2089
--- /dev/null
+++ b/usr.bin/xlint/lint1/cgram.y
@@ -0,0 +1,1686 @@
+%{
+/* $NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "lint1.h"
+
+/*
+ * Contains the level of current declaration. 0 is extern.
+ * Used for symbol table entries.
+ */
+int blklev;
+
+/*
+ * level for memory allocation. Normaly the same as blklev.
+ * An exeption is the declaration of arguments in prototypes. Memory
+ * for these can't be freed after the declaration, but symbols must
+ * be removed from the symbol table after the declaration.
+ */
+int mblklev;
+
+static int toicon __P((tnode_t *));
+static void idecl __P((sym_t *, int));
+static void ignuptorp __P((void));
+
+%}
+
+%union {
+ int y_int;
+ val_t *y_val;
+ sbuf_t *y_sb;
+ sym_t *y_sym;
+ op_t y_op;
+ scl_t y_scl;
+ tspec_t y_tspec;
+ tqual_t y_tqual;
+ type_t *y_type;
+ tnode_t *y_tnode;
+ strg_t *y_strg;
+ pqinf_t *y_pqinf;
+};
+
+%token T_LBRACE T_RBRACE T_LBRACK T_RBRACK T_LPARN T_RPARN
+%token <y_op> T_STROP
+%token <y_op> T_UNOP
+%token <y_op> T_INCDEC
+%token T_SIZEOF
+%token <y_op> T_MULT
+%token <y_op> T_DIVOP
+%token <y_op> T_ADDOP
+%token <y_op> T_SHFTOP
+%token <y_op> T_RELOP
+%token <y_op> T_EQOP
+%token <y_op> T_AND
+%token <y_op> T_XOR
+%token <y_op> T_OR
+%token <y_op> T_LOGAND
+%token <y_op> T_LOGOR
+%token T_QUEST
+%token T_COLON
+%token <y_op> T_ASSIGN
+%token <y_op> T_OPASS
+%token T_COMMA
+%token T_SEMI
+%token T_ELLIPSE
+
+/* storage classes (extern, static, auto, register and typedef) */
+%token <y_scl> T_SCLASS
+
+/* types (char, int, short, long, unsigned, signed, float, double, void) */
+%token <y_tspec> T_TYPE
+
+/* qualifiers (const, volatile) */
+%token <y_tqual> T_QUAL
+
+/* struct or union */
+%token <y_tspec> T_SOU
+
+/* enum */
+%token T_ENUM
+
+/* remaining keywords */
+%token T_CASE
+%token T_DEFAULT
+%token T_IF
+%token T_ELSE
+%token T_SWITCH
+%token T_DO
+%token T_WHILE
+%token T_FOR
+%token T_GOTO
+%token T_CONTINUE
+%token T_BREAK
+%token T_RETURN
+%token T_ASM
+
+%left T_COMMA
+%right T_ASSIGN T_OPASS
+%right T_QUEST T_COLON
+%left T_LOGOR
+%left T_LOGAND
+%left T_OR
+%left T_XOR
+%left T_AND
+%left T_EQOP
+%left T_RELOP
+%left T_SHFTOP
+%left T_ADDOP
+%left T_MULT T_DIVOP
+%right T_UNOP T_INCDEC T_SIZEOF
+%left T_LPARN T_LBRACK T_STROP
+
+%token <y_sb> T_NAME
+%token <y_sb> T_TYPENAME
+%token <y_val> T_CON
+%token <y_strg> T_STRING
+
+%type <y_sym> func_decl
+%type <y_sym> notype_decl
+%type <y_sym> type_decl
+%type <y_type> typespec
+%type <y_type> clrtyp_typespec
+%type <y_type> notype_typespec
+%type <y_type> struct_spec
+%type <y_type> enum_spec
+%type <y_sym> struct_tag
+%type <y_sym> enum_tag
+%type <y_tspec> struct
+%type <y_sym> struct_declaration
+%type <y_sb> identifier
+%type <y_sym> member_declaration_list_with_rbrace
+%type <y_sym> member_declaration_list
+%type <y_sym> member_declaration
+%type <y_sym> notype_member_decls
+%type <y_sym> type_member_decls
+%type <y_sym> notype_member_decl
+%type <y_sym> type_member_decl
+%type <y_tnode> constant
+%type <y_sym> enum_declaration
+%type <y_sym> enums_with_opt_comma
+%type <y_sym> enums
+%type <y_sym> enumerator
+%type <y_sym> ename
+%type <y_sym> notype_direct_decl
+%type <y_sym> type_direct_decl
+%type <y_pqinf> pointer
+%type <y_pqinf> asterisk
+%type <y_sym> param_decl
+%type <y_sym> param_list
+%type <y_sym> abs_decl_param_list
+%type <y_sym> direct_param_decl
+%type <y_sym> notype_param_decl
+%type <y_sym> direct_notype_param_decl
+%type <y_pqinf> type_qualifier_list
+%type <y_pqinf> type_qualifier
+%type <y_sym> identifier_list
+%type <y_sym> abs_decl
+%type <y_sym> direct_abs_decl
+%type <y_sym> vararg_parameter_type_list
+%type <y_sym> parameter_type_list
+%type <y_sym> parameter_declaration
+%type <y_tnode> expr
+%type <y_tnode> term
+%type <y_tnode> func_arg_list
+%type <y_op> point_or_arrow
+%type <y_type> type_name
+%type <y_sym> abstract_declaration
+%type <y_tnode> do_while_expr
+%type <y_tnode> opt_expr
+%type <y_strg> string
+%type <y_strg> string2
+
+
+%%
+
+program:
+ /* empty */ {
+ if (sflag) {
+ /* empty translation unit */
+ error(272);
+ } else if (!tflag) {
+ /* empty translation unit */
+ warning(272);
+ }
+ }
+ | translation_unit
+ ;
+
+translation_unit:
+ ext_decl
+ | translation_unit ext_decl
+ ;
+
+ext_decl:
+ func_def {
+ glclup(0);
+ clrwflgs();
+ }
+ | data_def {
+ glclup(0);
+ clrwflgs();
+ }
+ ;
+
+data_def:
+ T_SEMI {
+ if (sflag) {
+ /* syntax error: empty declaration */
+ error(0);
+ } else if (!tflag) {
+ /* syntax error: empty declaration */
+ warning(0);
+ }
+ }
+ | clrtyp deftyp notype_init_decls T_SEMI {
+ if (sflag) {
+ /* old style declaration; add "int" */
+ error(1);
+ } else if (!tflag) {
+ /* old style declaration; add "int" */
+ warning(1);
+ }
+ }
+ | declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI {
+ globclup();
+ }
+ | error T_RBRACE {
+ globclup();
+ }
+ ;
+
+func_def:
+ func_decl {
+ if ($1->s_type->t_tspec != FUNC) {
+ /* syntax error */
+ error(249);
+ YYERROR;
+ }
+ if ($1->s_type->t_typedef) {
+ /* ()-less function definition */
+ error(64);
+ YYERROR;
+ }
+ funcdef($1);
+ blklev++;
+ pushdecl(ARG);
+ } opt_arg_declaration_list {
+ popdecl();
+ blklev--;
+ cluparg();
+ pushctrl(0);
+ } comp_stmnt {
+ funcend();
+ popctrl(0);
+ }
+ ;
+
+func_decl:
+ clrtyp deftyp notype_decl {
+ $$ = $3;
+ }
+ | declmods deftyp notype_decl {
+ $$ = $3;
+ }
+ | declspecs deftyp type_decl {
+ $$ = $3;
+ }
+ ;
+
+opt_arg_declaration_list:
+ /* empty */
+ | arg_declaration_list
+ ;
+
+arg_declaration_list:
+ arg_declaration
+ | arg_declaration_list arg_declaration
+ /* XXX or better "arg_declaration error" ? */
+ | error
+ ;
+
+/*
+ * "arg_declaration" is separated from "declaration" because it
+ * needs other error handling.
+ */
+
+arg_declaration:
+ declmods deftyp T_SEMI {
+ /* empty declaration */
+ warning(2);
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ } else {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI {
+ if (dcs->d_nedecl) {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declmods error
+ | declspecs error
+ ;
+
+declaration:
+ declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI
+ ;
+
+clrtyp:
+ {
+ clrtyp();
+ }
+ ;
+
+deftyp:
+ /* empty */ {
+ deftyp();
+ }
+ ;
+
+declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | declmods typespec {
+ addtype($2);
+ }
+ | declspecs declmod
+ | declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | clrtyp T_SCLASS {
+ addscl($2);
+ }
+ | declmods declmod
+ ;
+
+declmod:
+ T_QUAL {
+ addqual($1);
+ }
+ | T_SCLASS {
+ addscl($1);
+ }
+ ;
+
+clrtyp_typespec:
+ clrtyp notype_typespec {
+ $$ = $2;
+ }
+ | T_TYPENAME clrtyp {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+typespec:
+ notype_typespec {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+notype_typespec:
+ T_TYPE {
+ $$ = gettyp($1);
+ }
+ | struct_spec {
+ popdecl();
+ $$ = $1;
+ }
+ | enum_spec {
+ popdecl();
+ $$ = $1;
+ }
+ ;
+
+struct_spec:
+ struct struct_tag {
+ /*
+ * STDC requires that "struct a;" always introduces
+ * a new tag if "a" is not declared at current level
+ *
+ * yychar is valid because otherwise the parser would
+ * not been able to deceide if he must shift or reduce
+ */
+ $$ = mktag($2, $1, 0, yychar == T_SEMI);
+ }
+ | struct struct_tag {
+ dcs->d_tagtyp = mktag($2, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | struct {
+ dcs->d_tagtyp = mktag(NULL, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | struct error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+struct:
+ T_SOU {
+ symtyp = FTAG;
+ pushdecl($1 == STRUCT ? MOS : MOU);
+ dcs->d_offset = 0;
+ dcs->d_stralign = CHAR_BIT;
+ $$ = $1;
+ }
+ ;
+
+struct_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+struct_declaration:
+ struct_decl_lbrace member_declaration_list_with_rbrace {
+ $$ = $2;
+ }
+ ;
+
+struct_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ }
+ ;
+
+member_declaration_list_with_rbrace:
+ member_declaration_list T_SEMI T_RBRACE {
+ $$ = $1;
+ }
+ | member_declaration_list T_RBRACE {
+ if (sflag) {
+ /* syntax req. ";" after last struct/union member */
+ error(66);
+ } else {
+ /* syntax req. ";" after last struct/union member */
+ warning(66);
+ }
+ $$ = $1;
+ }
+ | T_RBRACE {
+ $$ = NULL;
+ }
+ ;
+
+member_declaration_list:
+ member_declaration {
+ $$ = $1;
+ }
+ | member_declaration_list T_SEMI member_declaration {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+member_declaration:
+ noclass_declmods deftyp {
+ /* too late, i know, but getsym() compensates it */
+ symtyp = FMOS;
+ } notype_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declspecs deftyp {
+ symtyp = FMOS;
+ } type_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declmods deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | noclass_declspecs deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | error {
+ symtyp = FVFT;
+ $$ = NULL;
+ }
+ ;
+
+noclass_declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | noclass_declmods typespec {
+ addtype($2);
+ }
+ | noclass_declspecs T_QUAL {
+ addqual($2);
+ }
+ | noclass_declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+noclass_declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | noclass_declmods T_QUAL {
+ addqual($2);
+ }
+ ;
+
+notype_member_decls:
+ notype_member_decl {
+ $$ = decl1str($1);
+ }
+ | notype_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+type_member_decls:
+ type_member_decl {
+ $$ = decl1str($1);
+ }
+ | type_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+notype_member_decl:
+ notype_decl {
+ $$ = $1;
+ }
+ | notype_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+type_member_decl:
+ type_decl {
+ $$ = $1;
+ }
+ | type_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+enum_spec:
+ enum enum_tag {
+ $$ = mktag($2, ENUM, 0, 0);
+ }
+ | enum enum_tag {
+ dcs->d_tagtyp = mktag($2, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | enum {
+ dcs->d_tagtyp = mktag(NULL, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | enum error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+enum:
+ T_ENUM {
+ symtyp = FTAG;
+ pushdecl(ENUMCON);
+ }
+ ;
+
+enum_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+enum_declaration:
+ enum_decl_lbrace enums_with_opt_comma T_RBRACE {
+ $$ = $2;
+ }
+ ;
+
+enum_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ enumval = 0;
+ }
+ ;
+
+enums_with_opt_comma:
+ enums {
+ $$ = $1;
+ }
+ | enums T_COMMA {
+ if (sflag) {
+ /* trailing "," prohibited in enum declaration */
+ error(54);
+ } else {
+ /* trailing "," prohibited in enum declaration */
+ warning(54);
+ }
+ $$ = $1;
+ }
+ ;
+
+enums:
+ enumerator {
+ $$ = $1;
+ }
+ | enums T_COMMA enumerator {
+ $$ = lnklst($1, $3);
+ }
+ | error {
+ $$ = NULL;
+ }
+ ;
+
+enumerator:
+ ename {
+ $$ = ename($1, enumval, 1);
+ }
+ | ename T_ASSIGN constant {
+ $$ = ename($1, toicon($3), 0);
+ }
+ ;
+
+ename:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+
+notype_init_decls:
+ notype_init_decl
+ | notype_init_decls T_COMMA type_init_decl
+ ;
+
+type_init_decls:
+ type_init_decl
+ | type_init_decls T_COMMA type_init_decl
+ ;
+
+notype_init_decl:
+ notype_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | notype_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+type_init_decl:
+ type_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | type_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+notype_decl:
+ notype_direct_decl {
+ $$ = $1;
+ }
+ | pointer notype_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+notype_direct_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | notype_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | notype_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | notype_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+type_decl:
+ type_direct_decl {
+ $$ = $1;
+ }
+ | pointer type_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+type_direct_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | type_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | type_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | type_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+/*
+ * param_decl and notype_param_decl exist to avoid a conflict in
+ * argument lists. A typename enclosed in parens should always be
+ * treated as a typename, not an argument.
+ * "typedef int a; f(int (a));" is "typedef int a; f(int foo(a));"
+ * not "typedef int a; f(int a);"
+ */
+param_decl:
+ direct_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_param_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+notype_param_decl:
+ direct_notype_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_notype_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_notype_param_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_notype_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_notype_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_notype_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+pointer:
+ asterisk {
+ $$ = $1;
+ }
+ | asterisk type_qualifier_list {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk pointer {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk type_qualifier_list pointer {
+ $$ = mergepq(mergepq($1, $2), $3);
+ }
+ ;
+
+asterisk:
+ T_MULT {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ $$->p_pcnt = 1;
+ }
+ ;
+
+type_qualifier_list:
+ type_qualifier {
+ $$ = $1;
+ }
+ | type_qualifier_list type_qualifier {
+ $$ = mergepq($1, $2);
+ }
+ ;
+
+type_qualifier:
+ T_QUAL {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ if ($1 == CONST) {
+ $$->p_const = 1;
+ } else {
+ $$->p_volatile = 1;
+ }
+ }
+ ;
+
+param_list:
+ id_list_lparn identifier_list T_RPARN {
+ $$ = $2;
+ }
+ | abs_decl_param_list {
+ $$ = $1;
+ }
+ ;
+
+id_list_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+identifier_list:
+ T_NAME {
+ $$ = iname(getsym($1));
+ }
+ | identifier_list T_COMMA T_NAME {
+ $$ = lnklst($1, iname(getsym($3)));
+ }
+ | identifier_list error {
+ $$ = $1;
+ }
+ ;
+
+abs_decl_param_list:
+ abs_decl_lparn T_RPARN {
+ $$ = NULL;
+ }
+ | abs_decl_lparn vararg_parameter_type_list T_RPARN {
+ dcs->d_proto = 1;
+ $$ = $2;
+ }
+ | abs_decl_lparn error T_RPARN {
+ $$ = NULL;
+ }
+ ;
+
+abs_decl_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+vararg_parameter_type_list:
+ parameter_type_list {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA T_ELLIPSE {
+ dcs->d_vararg = 1;
+ $$ = $1;
+ }
+ | T_ELLIPSE {
+ if (sflag) {
+ /* ANSI C requires formal parameter before "..." */
+ error(84);
+ } else if (!tflag) {
+ /* ANSI C requires formal parameter before "..." */
+ warning(84);
+ }
+ dcs->d_vararg = 1;
+ $$ = NULL;
+ }
+ ;
+
+parameter_type_list:
+ parameter_declaration opt_asm_spec {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA parameter_declaration opt_asm_spec {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+parameter_declaration:
+ declmods deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declspecs deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declmods deftyp notype_param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ /*
+ * param_decl is needed because of following conflict:
+ * "typedef int a; f(int (a));" could be parsed as
+ * "function with argument a of type int", or
+ * "function with an abstract argument of type function".
+ * This grammar realizes the second case.
+ */
+ | declspecs deftyp param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declmods deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declspecs deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ ;
+
+opt_asm_spec:
+ /* empty */
+ | T_ASM T_LPARN T_STRING T_RPARN {
+ freeyyv(&$3, T_STRING);
+ }
+ ;
+
+initializer:
+ init_expr
+ ;
+
+init_expr:
+ expr %prec T_COMMA {
+ mkinit($1);
+ }
+ | init_lbrace init_expr_list init_rbrace
+ | init_lbrace init_expr_list T_COMMA init_rbrace
+ | error
+ ;
+
+init_expr_list:
+ init_expr %prec T_COMMA
+ | init_expr_list T_COMMA init_expr
+ ;
+
+init_lbrace:
+ T_LBRACE {
+ initlbr();
+ }
+ ;
+
+init_rbrace:
+ T_RBRACE {
+ initrbr();
+ }
+ ;
+
+type_name:
+ {
+ pushdecl(ABSTRACT);
+ } abstract_declaration {
+ popdecl();
+ $$ = $2->s_type;
+ }
+ ;
+
+abstract_declaration:
+ noclass_declmods deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declspecs deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declmods deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ | noclass_declspecs deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ ;
+
+abs_decl:
+ pointer {
+ $$ = addptr(aname(), $1);
+ }
+ | direct_abs_decl {
+ $$ = $1;
+ }
+ | pointer direct_abs_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_abs_decl:
+ T_LPARN abs_decl T_RPARN {
+ $$ = $2;
+ }
+ | T_LBRACK T_RBRACK {
+ $$ = addarray(aname(), 0, 0);
+ }
+ | T_LBRACK constant T_RBRACK {
+ $$ = addarray(aname(), 1, toicon($2));
+ }
+ | direct_abs_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_abs_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | abs_decl_param_list {
+ $$ = addfunc(aname(), $1);
+ popdecl();
+ blklev--;
+ }
+ | direct_abs_decl abs_decl_param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+stmnt:
+ labeled_stmnt
+ | expr_stmnt
+ | comp_stmnt
+ | selection_stmnt
+ | iteration_stmnt
+ | jump_stmnt {
+ ftflg = 0;
+ }
+ | asm_stmnt
+ ;
+
+labeled_stmnt:
+ label stmnt
+ ;
+
+label:
+ identifier T_COLON {
+ symtyp = FLAB;
+ label(T_NAME, getsym($1), NULL);
+ }
+ | T_CASE constant T_COLON {
+ label(T_CASE, NULL, $2);
+ ftflg = 1;
+ }
+ | T_DEFAULT T_COLON {
+ label(T_DEFAULT, NULL, NULL);
+ ftflg = 1;
+ }
+ ;
+
+comp_stmnt:
+ compstmnt_lbrace declaration_list opt_stmnt_list compstmnt_rbrace
+ | compstmnt_lbrace opt_stmnt_list compstmnt_rbrace
+ ;
+
+compstmnt_lbrace:
+ T_LBRACE {
+ blklev++;
+ mblklev++;
+ pushdecl(AUTO);
+ }
+ ;
+
+compstmnt_rbrace:
+ T_RBRACE {
+ popdecl();
+ freeblk();
+ mblklev--;
+ blklev--;
+ ftflg = 0;
+ }
+ ;
+
+opt_stmnt_list:
+ /* empty */
+ | stmnt_list
+ ;
+
+stmnt_list:
+ stmnt {
+ clrwflgs();
+ }
+ | stmnt_list stmnt {
+ clrwflgs();
+ }
+ | stmnt_list error T_SEMI {
+ clrwflgs();
+ }
+ ;
+
+expr_stmnt:
+ expr T_SEMI {
+ expr($1, 0, 0);
+ ftflg = 0;
+ }
+ | T_SEMI {
+ ftflg = 0;
+ }
+ ;
+
+selection_stmnt:
+ if_without_else {
+ if2();
+ if3(0);
+ }
+ | if_without_else T_ELSE {
+ if2();
+ } stmnt {
+ if3(1);
+ }
+ | if_without_else T_ELSE error {
+ if3(0);
+ }
+ | switch_expr stmnt {
+ switch2();
+ }
+ | switch_expr error {
+ switch2();
+ }
+ ;
+
+if_without_else:
+ if_expr stmnt
+ | if_expr error
+ ;
+
+if_expr:
+ T_IF T_LPARN expr T_RPARN {
+ if1($3);
+ clrwflgs();
+ }
+ ;
+
+switch_expr:
+ T_SWITCH T_LPARN expr T_RPARN {
+ switch1($3);
+ clrwflgs();
+ }
+ ;
+
+iteration_stmnt:
+ while_expr stmnt {
+ while2();
+ }
+ | while_expr error {
+ while2();
+ }
+ | do stmnt do_while_expr {
+ do2($3);
+ ftflg = 0;
+ }
+ | do error {
+ do2(NULL);
+ }
+ | for_exprs stmnt {
+ for2();
+ }
+ | for_exprs error {
+ for2();
+ }
+ ;
+
+while_expr:
+ T_WHILE T_LPARN expr T_RPARN {
+ while1($3);
+ clrwflgs();
+ }
+ ;
+
+do:
+ T_DO {
+ do1();
+ }
+ ;
+
+do_while_expr:
+ T_WHILE T_LPARN expr T_RPARN T_SEMI {
+ $$ = $3;
+ }
+ ;
+
+for_exprs:
+ T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN {
+ for1($3, $5, $7);
+ clrwflgs();
+ }
+ ;
+
+opt_expr:
+ /* empty */ {
+ $$ = NULL;
+ }
+ | expr {
+ $$ = $1;
+ }
+ ;
+
+jump_stmnt:
+ goto identifier T_SEMI {
+ dogoto(getsym($2));
+ }
+ | goto error T_SEMI {
+ symtyp = FVFT;
+ }
+ | T_CONTINUE T_SEMI {
+ docont();
+ }
+ | T_BREAK T_SEMI {
+ dobreak();
+ }
+ | T_RETURN T_SEMI {
+ doreturn(NULL);
+ }
+ | T_RETURN expr T_SEMI {
+ doreturn($2);
+ }
+ ;
+
+goto:
+ T_GOTO {
+ symtyp = FLAB;
+ }
+ ;
+
+asm_stmnt:
+ T_ASM T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM T_QUAL T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM error
+ ;
+
+read_until_rparn:
+ /* empty */ {
+ ignuptorp();
+ }
+ ;
+
+declaration_list:
+ declaration {
+ clrwflgs();
+ }
+ | declaration_list declaration {
+ clrwflgs();
+ }
+ ;
+
+constant:
+ expr %prec T_COMMA {
+ $$ = $1;
+ }
+ ;
+
+expr:
+ expr T_MULT expr {
+ $$ = build(MULT, $1, $3);
+ }
+ | expr T_DIVOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_ADDOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_SHFTOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_RELOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_EQOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_AND expr {
+ $$ = build(AND, $1, $3);
+ }
+ | expr T_XOR expr {
+ $$ = build(XOR, $1, $3);
+ }
+ | expr T_OR expr {
+ $$ = build(OR, $1, $3);
+ }
+ | expr T_LOGAND expr {
+ $$ = build(LOGAND, $1, $3);
+ }
+ | expr T_LOGOR expr {
+ $$ = build(LOGOR, $1, $3);
+ }
+ | expr T_QUEST expr T_COLON expr {
+ $$ = build(QUEST, $1, build(COLON, $3, $5));
+ }
+ | expr T_ASSIGN expr {
+ $$ = build(ASSIGN, $1, $3);
+ }
+ | expr T_OPASS expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_COMMA expr {
+ $$ = build(COMMA, $1, $3);
+ }
+ | term {
+ $$ = $1;
+ }
+ ;
+
+term:
+ T_NAME {
+ /* XXX realy neccessary? */
+ if (yychar < 0)
+ yychar = yylex();
+ $$ = getnnode(getsym($1), yychar);
+ }
+ | string {
+ $$ = getsnode($1);
+ }
+ | T_CON {
+ $$ = getcnode(gettyp($1->v_tspec), $1);
+ }
+ | T_LPARN expr T_RPARN {
+ if ($2 != NULL)
+ $2->tn_parn = 1;
+ $$ = $2;
+ }
+ | term T_INCDEC {
+ $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL);
+ }
+ | T_INCDEC term {
+ $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL);
+ }
+ | T_MULT term {
+ $$ = build(STAR, $2, NULL);
+ }
+ | T_AND term {
+ $$ = build(AMPER, $2, NULL);
+ }
+ | T_UNOP term {
+ $$ = build($1, $2, NULL);
+ }
+ | T_ADDOP term {
+ if (tflag && $1 == PLUS) {
+ /* unary + is illegal in traditional C */
+ warning(100);
+ }
+ $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL);
+ }
+ | term T_LBRACK expr T_RBRACK {
+ $$ = build(STAR, build(PLUS, $1, $3), NULL);
+ }
+ | term T_LPARN T_RPARN {
+ $$ = funccall($1, NULL);
+ }
+ | term T_LPARN func_arg_list T_RPARN {
+ $$ = funccall($1, $3);
+ }
+ | term point_or_arrow T_NAME {
+ if ($1 != NULL) {
+ sym_t *msym;
+ /* XXX strmemb should be integrated in build() */
+ if ($2 == ARROW) {
+ /* must to this before strmemb is called */
+ $1 = cconv($1);
+ }
+ msym = strmemb($1, $2, getsym($3));
+ $$ = build($2, $1, getnnode(msym, 0));
+ } else {
+ $$ = NULL;
+ }
+ }
+ | T_SIZEOF term %prec T_SIZEOF {
+ if (($$ = $2 == NULL ? NULL : bldszof($2->tn_type)) != NULL)
+ chkmisc($2, 0, 0, 0, 0, 0, 1);
+ }
+ | T_SIZEOF T_LPARN type_name T_RPARN %prec T_SIZEOF {
+ $$ = bldszof($3);
+ }
+ | T_LPARN type_name T_RPARN term %prec T_UNOP {
+ $$ = cast($4, $2);
+ }
+ ;
+
+string:
+ T_STRING {
+ $$ = $1;
+ }
+ | T_STRING string2 {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+string2:
+ T_STRING {
+ if (tflag) {
+ /* concatenated strings are illegal in traditional C */
+ warning(219);
+ }
+ $$ = $1;
+ }
+ | string2 T_STRING {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+func_arg_list:
+ expr %prec T_COMMA {
+ $$ = funcarg(NULL, $1);
+ }
+ | func_arg_list T_COMMA expr {
+ $$ = funcarg($1, $3);
+ }
+ ;
+
+point_or_arrow:
+ T_STROP {
+ symtyp = FMOS;
+ $$ = $1;
+ }
+ ;
+
+identifier:
+ T_NAME {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* ARGSUSED */
+int
+yyerror(msg)
+ char *msg;
+{
+ error(249);
+ if (++sytxerr >= 5)
+ norecover();
+ return (0);
+}
+
+/*
+ * Gets a node for a constant and returns the value of this constant
+ * as integer.
+ * Is the node not constant or too large for int or of type float,
+ * a warning will be printed.
+ *
+ * toicon() should be used only inside declarations. If it is used in
+ * expressions, it frees the memory used for the expression.
+ */
+static int
+toicon(tn)
+ tnode_t *tn;
+{
+ int i;
+ tspec_t t;
+ val_t *v;
+
+ v = constant(tn);
+
+ /*
+ * Abstract declarations are used inside expression. To free
+ * the memory would be a fatal error.
+ */
+ if (dcs->d_ctx != ABSTRACT)
+ tfreeblk();
+
+ if ((t = v->v_tspec) == FLOAT || t == DOUBLE || t == LDOUBLE) {
+ i = (int)v->v_ldbl;
+ /* integral constant expression expected */
+ error(55);
+ } else {
+ i = (int)v->v_quad;
+ if (isutyp(t)) {
+ if ((u_quad_t)v->v_quad > INT_MAX) {
+ /* integral constant too large */
+ warning(56);
+ }
+ } else {
+#ifdef XXX_BROKEN_GCC
+ if (v->v_quad > INT_MAX) {
+ /* integral constant too large */
+ warning(56);
+ }
+ else if (v->v_quad < INT_MIN) {
+ /* integral constant too large */
+ warning(56);
+ }
+#else
+ if (v->v_quad > INT_MAX || v->v_quad < INT_MIN) {
+ /* integral constant too large */
+ warning(56);
+ }
+#endif
+ }
+ }
+ free(v);
+ return (i);
+}
+
+static void
+idecl(decl, initflg)
+ sym_t *decl;
+ int initflg;
+{
+ initerr = 0;
+ initsym = decl;
+
+ switch (dcs->d_ctx) {
+ case EXTERN:
+ decl1ext(decl, initflg);
+ break;
+ case ARG:
+ (void)decl1arg(decl, initflg);
+ break;
+ case AUTO:
+ decl1loc(decl, initflg);
+ break;
+ default:
+ lerror("idecl()");
+ }
+
+ if (initflg && !initerr)
+ prepinit();
+}
+
+/*
+ * Discard all input tokens up to and including the next
+ * unmatched right paren
+ */
+void
+ignuptorp()
+{
+ int level;
+
+ if (yychar < 0)
+ yychar = yylex();
+ freeyyv(&yylval, yychar);
+
+ level = 1;
+ while (yychar != T_RPARN || --level > 0) {
+ if (yychar == T_LPARN) {
+ level++;
+ } else if (yychar <= 0) {
+ break;
+ }
+ freeyyv(&yylval, yychar = yylex());
+ }
+
+ yyclearin;
+}
diff --git a/usr.bin/xlint/lint1/decl.c b/usr.bin/xlint/lint1/decl.c
new file mode 100644
index 0000000..1151166
--- /dev/null
+++ b/usr.bin/xlint/lint1/decl.c
@@ -0,0 +1,3135 @@
+/* $NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+
+const char *unnamed = "<unnamed>";
+
+/* contains various information and classification on types */
+ttab_t ttab[NTSPEC];
+
+/* shared type structures for arithmtic types and void */
+static type_t *typetab;
+
+/* value of next enumerator during declaration of enum types */
+int enumval;
+
+/*
+ * pointer to top element of a stack which contains informations local
+ * to nested declarations
+ */
+dinfo_t *dcs;
+
+static type_t *tdeferr __P((type_t *, tspec_t));
+static void settdsym __P((type_t *, sym_t *));
+static tspec_t mrgtspec __P((tspec_t, tspec_t));
+static void align __P((int, int));
+static sym_t *newtag __P((sym_t *, scl_t, int, int));
+static int eqargs __P((type_t *, type_t *, int *));
+static int mnoarg __P((type_t *, int *));
+static int chkosdef __P((sym_t *, sym_t *));
+static int chkptdecl __P((sym_t *, sym_t *));
+static sym_t *nsfunc __P((sym_t *, sym_t *));
+static void osfunc __P((sym_t *, sym_t *));
+static void ledecl __P((sym_t *));
+static int chkinit __P((sym_t *));
+static void chkausg __P((int, sym_t *));
+static void chkvusg __P((int, sym_t *));
+static void chklusg __P((sym_t *));
+static void chktusg __P((sym_t *));
+static void chkglvar __P((sym_t *));
+static void glchksz __P((sym_t *));
+
+/*
+ * initializes all global vars used in declarations
+ */
+void
+initdecl()
+{
+ int i;
+ static struct {
+ tspec_t it_tspec;
+ ttab_t it_ttab;
+ } ittab[] = {
+ { SIGNED, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "signed" } },
+ { UNSIGN, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "unsigned" } },
+ { CHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "char" } },
+ { SCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "signed char" } },
+ { UCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 1, 0, 1, 1, "unsigned char" } },
+ { SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 0, 0, 1, 1, "short" } },
+ { USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 1, 0, 1, 1, "unsigned short" } },
+ { INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 0, 0, 1, 1, "int" } },
+ { UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 1, 0, 1, 1, "unsigned int" } },
+ { LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 0, 0, 1, 1, "long" } },
+ { ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 1, 0, 1, 1, "unsigned long" } },
+ { QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 0, 0, 1, 1, "long long" } },
+ { UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 1, 0, 1, 1, "unsigned long long" } },
+ { FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
+ FLOAT, FLOAT,
+ 0, 0, 1, 1, 1, "float" } },
+ { DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
+ DOUBLE, DOUBLE,
+ 0, 0, 1, 1, 1, "double" } },
+ { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
+ LDOUBLE, LDOUBLE,
+ 0, 0, 1, 1, 1, "long double" } },
+ { VOID, { -1, -1,
+ VOID, VOID,
+ 0, 0, 0, 0, 0, "void" } },
+ { STRUCT, { -1, -1,
+ STRUCT, STRUCT,
+ 0, 0, 0, 0, 0, "struct" } },
+ { UNION, { -1, -1,
+ UNION, UNION,
+ 0, 0, 0, 0, 0, "union" } },
+ { ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ ENUM, ENUM,
+ 1, 0, 0, 1, 1, "enum" } },
+ { PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
+ PTR, PTR,
+ 0, 1, 0, 0, 1, "pointer" } },
+ { ARRAY, { -1, -1,
+ ARRAY, ARRAY,
+ 0, 0, 0, 0, 0, "array" } },
+ { FUNC, { -1, -1,
+ FUNC, FUNC,
+ 0, 0, 0, 0, 0, "function" } },
+ };
+
+ /* declaration stack */
+ dcs = xcalloc(1, sizeof (dinfo_t));
+ dcs->d_ctx = EXTERN;
+ dcs->d_ldlsym = &dcs->d_dlsyms;
+
+ /* type information and classification */
+ for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
+ STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
+ if (!pflag) {
+ for (i = 0; i < NTSPEC; i++)
+ ttab[i].tt_psz = ttab[i].tt_sz;
+ }
+
+ /* shared type structures */
+ typetab = xcalloc(NTSPEC, sizeof (type_t));
+ for (i = 0; i < NTSPEC; i++)
+ typetab[i].t_tspec = NOTSPEC;
+ typetab[CHAR].t_tspec = CHAR;
+ typetab[SCHAR].t_tspec = SCHAR;
+ typetab[UCHAR].t_tspec = UCHAR;
+ typetab[SHORT].t_tspec = SHORT;
+ typetab[USHORT].t_tspec = USHORT;
+ typetab[INT].t_tspec = INT;
+ typetab[UINT].t_tspec = UINT;
+ typetab[LONG].t_tspec = LONG;
+ typetab[ULONG].t_tspec = ULONG;
+ typetab[QUAD].t_tspec = QUAD;
+ typetab[UQUAD].t_tspec = UQUAD;
+ typetab[FLOAT].t_tspec = FLOAT;
+ typetab[DOUBLE].t_tspec = DOUBLE;
+ typetab[LDOUBLE].t_tspec = LDOUBLE;
+ typetab[VOID].t_tspec = VOID;
+ /*
+ * Next two are not real types. They are only used by the parser
+ * to return keywords "signed" and "unsigned"
+ */
+ typetab[SIGNED].t_tspec = SIGNED;
+ typetab[UNSIGN].t_tspec = UNSIGN;
+}
+
+/*
+ * Returns a shared type structure vor arithmetic types and void.
+ *
+ * It's important do duplicate this structure (using duptyp() or tdupdyp())
+ * if it is to be modified (adding qualifiers or anything else).
+ */
+type_t *
+gettyp(t)
+ tspec_t t;
+{
+ return (&typetab[t]);
+}
+
+type_t *
+duptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = getblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Use tduptyp() instead of duptyp() inside expressions (if the
+ * allocated memory should be freed after the expr).
+ */
+type_t *
+tduptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = tgetblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Returns 1 if the argument is void or an incomplete array,
+ * struct, union or enum type.
+ */
+int
+incompl(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == VOID) {
+ return (1);
+ } else if (t == ARRAY) {
+ return (tp->t_aincompl);
+ } else if (t == STRUCT || t == UNION) {
+ return (tp->t_str->sincompl);
+ } else if (t == ENUM) {
+ return (tp->t_enum->eincompl);
+ }
+ return (0);
+}
+
+/*
+ * Set the flag for (in)complete array, struct, union or enum
+ * types.
+ */
+void
+setcompl(tp, ic)
+ type_t *tp;
+ int ic;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == ARRAY) {
+ tp->t_aincompl = ic;
+ } else if (t == STRUCT || t == UNION) {
+ tp->t_str->sincompl = ic;
+ } else {
+ if (t != ENUM)
+ lerror("setcompl() 1");
+ tp->t_enum->eincompl = ic;
+ }
+}
+
+/*
+ * Remember the storage class of the current declaration in dcs->d_scl
+ * (the top element of the declaration stack) and detect multiple
+ * storage classes.
+ */
+void
+addscl(sc)
+ scl_t sc;
+{
+ if (sc == INLINE) {
+ if (dcs->d_inline)
+ /* duplicate '%s' */
+ warning(10, "inline");
+ dcs->d_inline = 1;
+ return;
+ }
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_smod != NOTSPEC || dcs->d_lmod != NOTSPEC) {
+ /* storage class after type is obsolescent */
+ warning(83);
+ }
+ if (dcs->d_scl == NOSCL) {
+ dcs->d_scl = sc;
+ } else {
+ /*
+ * multiple storage classes. An error will be reported in
+ * deftyp().
+ */
+ dcs->d_mscl = 1;
+ }
+}
+
+/*
+ * Remember the type, modifier or typedef name returned by the parser
+ * in *dcs (top element of decl stack). This information is used in
+ * deftyp() to build the type used for all declarators in this
+ * declaration.
+ *
+ * Is tp->t_typedef 1, the type comes from a previously defined typename.
+ * Otherwise it comes from a type specifier (int, long, ...) or a
+ * struct/union/enum tag.
+ */
+void
+addtype(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if (tp->t_typedef) {
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * something like "typedef int a; int a b;"
+ * This should not happen with current grammar.
+ */
+ lerror("addtype()");
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ t = tp->t_tspec;
+
+ if (t == STRUCT || t == UNION || t == ENUM) {
+ /*
+ * something like "int struct a ..."
+ * struct/union/enum with anything else is not allowed
+ */
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * remember that an error must be reported in
+ * deftyp().
+ */
+ dcs->d_terr = 1;
+ dcs->d_atyp = dcs->d_lmod = dcs->d_smod = NOTSPEC;
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ if (dcs->d_type != NULL && !dcs->d_type->t_typedef) {
+ /*
+ * something like "struct a int"
+ * struct/union/enum with anything else is not allowed
+ */
+ dcs->d_terr = 1;
+ return;
+ }
+
+ if (t == LONG && dcs->d_lmod == LONG) {
+ /* "long long" or "long ... long" */
+ t = QUAD;
+ dcs->d_lmod = NOTSPEC;
+ if (!quadflg)
+ /* %s C does not support 'long long' */
+ (void)gnuism(265, tflag ? "traditional" : "ANSI");
+ }
+
+ if (dcs->d_type != NULL && dcs->d_type->t_typedef) {
+ /* something like "typedef int a; a long ..." */
+ dcs->d_type = tdeferr(dcs->d_type, t);
+ return;
+ }
+
+ /* now it can be only a combination of arithmetic types and void */
+ if (t == SIGNED || t == UNSIGN) {
+ /* remeber specifiers "signed" and "unsigned" in dcs->d_smod */
+ if (dcs->d_smod != NOTSPEC)
+ /*
+ * more then one "signed" and/or "unsigned"; print
+ * an error in deftyp()
+ */
+ dcs->d_terr = 1;
+ dcs->d_smod = t;
+ } else if (t == SHORT || t == LONG || t == QUAD) {
+ /*
+ * remember specifiers "short", "long" and "long long" in
+ * dcs->d_lmod
+ */
+ if (dcs->d_lmod != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_lmod = t;
+ } else {
+ /*
+ * remember specifiers "void", "char", "int", "float" or
+ * "double" int dcs->d_atyp
+ */
+ if (dcs->d_atyp != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_atyp = t;
+ }
+}
+
+/*
+ * called if a list of declaration specifiers contains a typedef name
+ * and other specifiers (except struct, union, enum, typedef name)
+ */
+static type_t *
+tdeferr(td, t)
+ type_t *td;
+ tspec_t t;
+{
+ tspec_t t2;
+
+ t2 = td->t_tspec;
+
+ switch (t) {
+ case SIGNED:
+ case UNSIGN:
+ if (t2 == CHAR || t2 == SHORT || t2 == INT || t2 == LONG ||
+ t2 == QUAD) {
+ if (!tflag)
+ /* modifying typedef with ... */
+ warning(5, ttab[t].tt_name);
+ td = duptyp(gettyp(mrgtspec(t2, t)));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case SHORT:
+ if (t2 == INT || t2 == UINT) {
+ /* modifying typedef with ... */
+ warning(5, "short");
+ td = duptyp(gettyp(t2 == INT ? SHORT : USHORT));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case LONG:
+ if (t2 == INT || t2 == UINT || t2 == LONG || t2 == ULONG ||
+ t2 == FLOAT || t2 == DOUBLE) {
+ /* modifying typedef with ... */
+ warning(5, "long");
+ if (t2 == INT) {
+ td = gettyp(LONG);
+ } else if (t2 == UINT) {
+ td = gettyp(ULONG);
+ } else if (t2 == LONG) {
+ td = gettyp(QUAD);
+ } else if (t2 == ULONG) {
+ td = gettyp(UQUAD);
+ } else if (t2 == FLOAT) {
+ td = gettyp(DOUBLE);
+ } else if (t2 == DOUBLE) {
+ td = gettyp(LDOUBLE);
+ }
+ td = duptyp(td);
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ default:
+ }
+
+ /* Anything other is not accepted. */
+
+ dcs->d_terr = 1;
+ return (td);
+}
+
+/*
+ * Remember the symbol of a typedef name (2nd arg) in a struct, union
+ * or enum tag if the typedef name is the first defined for this tag.
+ *
+ * If the tag is unnamed, the typdef name is used for identification
+ * of this tag in lint2. Although its possible that more then one typedef
+ * name is defined for one tag, the first name defined should be unique
+ * if the tag is unnamed.
+ */
+static void
+settdsym(tp, sym)
+ type_t *tp;
+ sym_t *sym;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (tp->t_str->stdef == NULL)
+ tp->t_str->stdef = sym;
+ } else if (t == ENUM) {
+ if (tp->t_enum->etdef == NULL)
+ tp->t_enum->etdef = sym;
+ }
+}
+
+/*
+ * Remember a qualifier which is part of the declaration specifiers
+ * (and not the declarator) in the top element of the declaration stack.
+ * Also detect multiple qualifiers of the same kind.
+
+ * The rememberd qualifier is used by deftyp() to construct the type
+ * for all declarators.
+ */
+void
+addqual(q)
+ tqual_t q;
+{
+ if (q == CONST) {
+ if (dcs->d_const) {
+ /* duplicate "%s" */
+ warning(10, "const");
+ }
+ dcs->d_const = 1;
+ } else {
+ if (q != VOLATILE)
+ lerror("addqual() 1");
+ if (dcs->d_volatile) {
+ /* duplicate "%s" */
+ warning(10, "volatile");
+ }
+ dcs->d_volatile = 1;
+ }
+}
+
+/*
+ * Go to the next declaration level (structs, nested structs, blocks,
+ * argument declaration lists ...)
+ */
+void
+pushdecl(sc)
+ scl_t sc;
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("pushdecl(%d)\n", (int)sc);
+
+ /* put a new element on the declaration stack */
+ di = xcalloc(1, sizeof (dinfo_t));
+ di->d_nxt = dcs;
+ dcs = di;
+ di->d_ctx = sc;
+ di->d_ldlsym = &di->d_dlsyms;
+}
+
+/*
+ * Go back to previous declaration level
+ */
+void
+popdecl()
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("popdecl(%d)\n", (int)dcs->d_ctx);
+
+ if (dcs->d_nxt == NULL)
+ lerror("popdecl() 1");
+ di = dcs;
+ dcs = di->d_nxt;
+ switch (di->d_ctx) {
+ case EXTERN:
+ /* there is nothing after external declarations */
+ lerror("popdecl() 2");
+ /* NOTREACHED */
+ case MOS:
+ case MOU:
+ case ENUMCON:
+ /*
+ * Symbols declared in (nested) structs or enums are
+ * part of the next level (they are removed from the
+ * symbol table if the symbols of the outher level are
+ * removed)
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case ARG:
+ /*
+ * All symbols in dcs->d_dlsyms are introduced in old style
+ * argument declarations (it's not clean, but possible).
+ * They are appended to the list of symbols declared in
+ * an old style argument identifier list or a new style
+ * parameter type list.
+ */
+ if (di->d_dlsyms != NULL) {
+ *di->d_ldlsym = dcs->d_fpsyms;
+ dcs->d_fpsyms = di->d_dlsyms;
+ }
+ break;
+ case ABSTRACT:
+ /*
+ * casts and sizeof
+ * Append all symbols declared in the abstract declaration
+ * to the list of symbols declared in the surounding decl.
+ * or block.
+ * XXX I'm not sure whether they should be removed from the
+ * symbol table now or later.
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case AUTO:
+ /* check usage of local vars */
+ chkusage(di);
+ /* FALLTHROUGH */
+ case PARG:
+ /* usage of arguments will be checked by funcend() */
+ rmsyms(di->d_dlsyms);
+ break;
+ default:
+ lerror("popdecl() 3");
+ }
+ free(di);
+}
+
+/*
+ * Set flag d_asm in all declaration stack elements up to the
+ * outermost one.
+ *
+ * This is used to mark compound statements which have, possibly in
+ * nested compound statements, asm statements. For these compound
+ * statements no warnings about unused or unitialized variables are
+ * printed.
+ *
+ * There is no need to clear d_asm in dinfo structs with context AUTO,
+ * because these structs are freed at the end of the compound statement.
+ * But it must be cleard in the outermost dinfo struct, which has
+ * context EXTERN. This could be done in clrtyp() and would work for
+ * C, but not for C++ (due to mixed statements and declarations). Thus
+ * we clear it in glclup(), which is used to do some cleanup after
+ * global declarations/definitions.
+ */
+void
+setasm()
+{
+ dinfo_t *di;
+
+ for (di = dcs; di != NULL; di = di->d_nxt)
+ di->d_asm = 1;
+}
+
+/*
+ * Clean all elements of the top element of declaration stack which
+ * will be used by the next declaration
+ */
+void
+clrtyp()
+{
+ dcs->d_atyp = dcs->d_smod = dcs->d_lmod = NOTSPEC;
+ dcs->d_scl = NOSCL;
+ dcs->d_type = NULL;
+ dcs->d_const = dcs->d_volatile = 0;
+ dcs->d_inline = 0;
+ dcs->d_mscl = dcs->d_terr = 0;
+ dcs->d_nedecl = 0;
+ dcs->d_notyp = 0;
+}
+
+/*
+ * Create a type structure from the informations gathered in
+ * the declaration stack.
+ * Complain about storage classes which are not possible in current
+ * context.
+ */
+void
+deftyp()
+{
+ tspec_t t, s, l;
+ type_t *tp;
+ scl_t scl;
+
+ t = dcs->d_atyp; /* CHAR, INT, FLOAT, DOUBLE, VOID */
+ s = dcs->d_smod; /* SIGNED, UNSIGNED */
+ l = dcs->d_lmod; /* SHORT, LONG, QUAD */
+ tp = dcs->d_type;
+ scl = dcs->d_scl;
+
+ if (t == NOTSPEC && s == NOTSPEC && l == NOTSPEC && tp == NULL)
+ dcs->d_notyp = 1;
+
+ if (tp != NULL && (t != NOTSPEC || s != NOTSPEC || l != NOTSPEC)) {
+ /* should never happen */
+ lerror("deftyp() 1");
+ }
+
+ if (tp == NULL) {
+ switch (t) {
+ case NOTSPEC:
+ t = INT;
+ /* FALLTHROUGH */
+ case INT:
+ if (s == NOTSPEC)
+ s = SIGNED;
+ break;
+ case CHAR:
+ if (l != NOTSPEC) {
+ dcs->d_terr = 1;
+ l = NOTSPEC;
+ }
+ break;
+ case FLOAT:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = DOUBLE;
+ if (!tflag)
+ /* use 'double' instead of ... */
+ warning(6);
+ }
+ break;
+ case DOUBLE:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = LDOUBLE;
+ if (tflag)
+ /* 'long double' is illegal in ... */
+ warning(266);
+ }
+ break;
+ case VOID:
+ break;
+ default:
+ lerror("deftyp() 2");
+ }
+ if (t != INT && t != CHAR && (s != NOTSPEC || l != NOTSPEC)) {
+ dcs->d_terr = 1;
+ l = s = NOTSPEC;
+ }
+ if (l != NOTSPEC)
+ t = l;
+ dcs->d_type = gettyp(mrgtspec(t, s));
+ }
+
+ if (dcs->d_mscl) {
+ /* only one storage class allowed */
+ error(7);
+ }
+ if (dcs->d_terr) {
+ /* illegal type combination */
+ error(4);
+ }
+
+ if (dcs->d_ctx == EXTERN) {
+ if (scl == REG || scl == AUTO) {
+ /* illegal storage class */
+ error(8);
+ scl = NOSCL;
+ }
+ } else if (dcs->d_ctx == ARG || dcs->d_ctx == PARG) {
+ if (scl != NOSCL && scl != REG) {
+ /* only "register" valid ... */
+ error(9);
+ scl = NOSCL;
+ }
+ }
+
+ dcs->d_scl = scl;
+
+ if (dcs->d_const && dcs->d_type->t_const) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 3");
+ /* typedef already qualified with "%s" */
+ warning(68, "const");
+ }
+ if (dcs->d_volatile && dcs->d_type->t_volatile) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 4");
+ /* typedef already qualified with "%s" */
+ warning(68, "volatile");
+ }
+
+ if (dcs->d_const || dcs->d_volatile) {
+ dcs->d_type = duptyp(dcs->d_type);
+ dcs->d_type->t_const |= dcs->d_const;
+ dcs->d_type->t_volatile |= dcs->d_volatile;
+ }
+}
+
+/*
+ * Merge type specifiers (char, ..., long long, signed, unsigned).
+ */
+static tspec_t
+mrgtspec(t, s)
+ tspec_t t, s;
+{
+ if (s == SIGNED || s == UNSIGN) {
+ if (t == CHAR) {
+ t = s == SIGNED ? SCHAR : UCHAR;
+ } else if (t == SHORT) {
+ t = s == SIGNED ? SHORT : USHORT;
+ } else if (t == INT) {
+ t = s == SIGNED ? INT : UINT;
+ } else if (t == LONG) {
+ t = s == SIGNED ? LONG : ULONG;
+ } else if (t == QUAD) {
+ t = s == SIGNED ? QUAD : UQUAD;
+ }
+ }
+
+ return (t);
+}
+
+/*
+ * Return the length of a type in bit.
+ *
+ * Printing a message if the outhermost dimension of an array is 0 must
+ * be done by the caller. All other problems are reported by length()
+ * if name is not NULL.
+ */
+int
+length(tp, name)
+ type_t *tp;
+ const char *name;
+{
+ int elem, elsz;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* compiler takes size of function */
+ lerror(msgs[12]);
+ /* NOTREACHED */
+ case STRUCT:
+ case UNION:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete structure or union %s: %s */
+ error(31, tp->t_str->stag->s_name, name);
+ }
+ elsz = tp->t_str->size;
+ break;
+ case ENUM:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete enum type: %s */
+ warning(13, name);
+ }
+ /* FALLTHROUGH */
+ default:
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("length()");
+ break;
+ }
+ return (elem * elsz);
+}
+
+/*
+ * Get the alignment of the given Type in bits.
+ */
+int
+getbound(tp)
+ type_t *tp;
+{
+ int a;
+ tspec_t t;
+
+ while (tp->t_tspec == ARRAY)
+ tp = tp->t_subt;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ a = tp->t_str->align;
+ } else if (t == FUNC) {
+ /* compiler takes alignment of function */
+ error(14);
+ a = ALIGN(1) * CHAR_BIT;
+ } else {
+ if ((a = size(t)) == 0) {
+ a = CHAR_BIT;
+ } else if (a > ALIGN(1) * CHAR_BIT) {
+ a = ALIGN(1) * CHAR_BIT;
+ }
+ }
+ if (a < CHAR_BIT || a > ALIGN(1) * CHAR_BIT)
+ lerror("getbound() 1");
+ return (a);
+}
+
+/*
+ * Concatenate two lists of symbols by s_nxt. Used by declarations of
+ * struct/union/enum elements and parameters.
+ */
+sym_t *
+lnklst(l1, l2)
+ sym_t *l1, *l2;
+{
+ sym_t *l;
+
+ if ((l = l1) == NULL)
+ return (l2);
+ while (l1->s_nxt != NULL)
+ l1 = l1->s_nxt;
+ l1->s_nxt = l2;
+ return (l);
+}
+
+/*
+ * Check if the type of the given symbol is valid and print an error
+ * message if it is not.
+ *
+ * Invalid types are:
+ * - arrays of incomlete types or functions
+ * - functions returning arrays or functions
+ * - void types other than type of function or pointer
+ */
+void
+chktyp(sym)
+ sym_t *sym;
+{
+ tspec_t to, t;
+ type_t **tpp, *tp;
+
+ tpp = &sym->s_type;
+ to = NOTSPEC;
+ while ((tp = *tpp) != NULL) {
+ t = tp->t_tspec;
+ /*
+ * If this is the type of an old style function definition,
+ * a better warning is printed in funcdef().
+ */
+ if (t == FUNC && !tp->t_proto &&
+ !(to == NOTSPEC && sym->s_osdef)) {
+ if (sflag && hflag)
+ /* function declaration is not a prototype */
+ warning(287);
+ }
+ if (to == FUNC) {
+ if (t == FUNC || t == ARRAY) {
+ /* function returns illegal type */
+ error(15);
+ if (t == FUNC) {
+ *tpp = incref(*tpp, PTR);
+ } else {
+ *tpp = incref((*tpp)->t_subt, PTR);
+ }
+ return;
+ } else if (tp->t_const || tp->t_volatile) {
+ if (sflag) { /* XXX oder better !tflag ? */
+ /* function cannot return const... */
+ warning(228);
+ }
+ }
+ } if (to == ARRAY) {
+ if (t == FUNC) {
+ /* array of function is illegal */
+ error(16);
+ *tpp = gettyp(INT);
+ return;
+ } else if (t == ARRAY && tp->t_dim == 0) {
+ /* null dimension */
+ error(17);
+ return;
+ } else if (t == VOID) {
+ /* illegal use of void */
+ error(18);
+ *tpp = gettyp(INT);
+#if 0 /* errors are produced by length() */
+ } else if (incompl(tp)) {
+ /* array of incomplete type */
+ if (sflag) {
+ error(301);
+ } else {
+ warning(301);
+ }
+#endif
+ }
+ } else if (to == NOTSPEC && t == VOID) {
+ if (dcs->d_ctx == PARG) {
+ if (sym->s_scl != ABSTRACT) {
+ if (sym->s_name == unnamed)
+ lerror("chktyp()");
+ /* void param cannot have name: %s */
+ error(61, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ } else if (dcs->d_ctx == ABSTRACT) {
+ /* ok */
+ } else if (sym->s_scl != TYPEDEF) {
+ /* void type for %s */
+ error(19, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ }
+ if (t == VOID && to != PTR) {
+ if (tp->t_const || tp->t_volatile) {
+ /* inappropriate qualifiers with "void" */
+ warning(69);
+ tp->t_const = tp->t_volatile = 0;
+ }
+ }
+ tpp = &tp->t_subt;
+ to = t;
+ }
+}
+
+/*
+ * Process the declarator of a struct/union element.
+ */
+sym_t *
+decl1str(dsym)
+ sym_t *dsym;
+{
+ type_t *tp;
+ tspec_t t;
+ int sz, o, len;
+ scl_t sc;
+
+ if ((sc = dsym->s_scl) != MOS && sc != MOU)
+ lerror("decl1str() 1");
+
+ if (dcs->d_rdcsym != NULL) {
+ if ((sc = dcs->d_rdcsym->s_scl) != MOS && sc != MOU)
+ /* should be ensured by storesym() */
+ lerror("decl1str() 2");
+ if (dsym->s_styp == dcs->d_rdcsym->s_styp) {
+ /* duplicate member name: %s */
+ error(33, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ chktyp(dsym);
+
+ t = (tp = dsym->s_type)->t_tspec;
+
+ if (dsym->s_field) {
+ /*
+ * bit field
+ *
+ * only unsigned und signed int are protable bit-field types
+ *(at least in ANSI C, in traditional C only unsigned int)
+ */
+ if (t == CHAR || t == UCHAR || t == SCHAR ||
+ t == SHORT || t == USHORT || t == ENUM) {
+ if (sflag) {
+ /* bit-field type '%s' invalid in ANSI C */
+ warning(273, tyname(tp));
+ } else if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t == INT && dcs->d_smod == NOTSPEC) {
+ if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t != INT && t != UINT) {
+ /* illegal bit-field type */
+ error(35);
+ sz = tp->t_flen;
+ dsym->s_type = tp = duptyp(gettyp(t = INT));
+ if ((tp->t_flen = sz) > size(t))
+ tp->t_flen = size(t);
+ }
+ if ((len = tp->t_flen) < 0 || len > size(t)) {
+ /* illegal bit-field size */
+ error(36);
+ tp->t_flen = size(t);
+ } else if (len == 0 && dsym->s_name != unnamed) {
+ /* zero size bit-field */
+ error(37);
+ tp->t_flen = size(t);
+ }
+ if (dsym->s_scl == MOU) {
+ /* illegal use of bit-field */
+ error(41);
+ dsym->s_type->t_isfield = 0;
+ dsym->s_field = 0;
+ }
+ } else if (t == FUNC) {
+ /* function illegal in structure or union */
+ error(38);
+ dsym->s_type = tp = incref(tp, t = PTR);
+ }
+
+ /*
+ * bit-fields of length 0 are not warned about because length()
+ * does not return the length of the bit-field but the length
+ * of the type the bit-field is packed in (its ok)
+ */
+ if ((sz = length(dsym->s_type, dsym->s_name)) == 0) {
+ if (t == ARRAY && dsym->s_type->t_dim == 0) {
+ /* illegal zero sized structure member: %s */
+ warning(39, dsym->s_name);
+ }
+ }
+
+ if (dcs->d_ctx == MOU) {
+ o = dcs->d_offset;
+ dcs->d_offset = 0;
+ }
+ if (dsym->s_field) {
+ align(getbound(tp), tp->t_flen);
+ dsym->s_value.v_quad = (dcs->d_offset / size(t)) * size(t);
+ tp->t_foffs = dcs->d_offset - (int)dsym->s_value.v_quad;
+ dcs->d_offset += tp->t_flen;
+ } else {
+ align(getbound(tp), 0);
+ dsym->s_value.v_quad = dcs->d_offset;
+ dcs->d_offset += sz;
+ }
+ if (dcs->d_ctx == MOU) {
+ if (o > dcs->d_offset)
+ dcs->d_offset = o;
+ }
+
+ chkfdef(dsym, 0);
+
+ return (dsym);
+}
+
+/*
+ * Aligns next structure element as required.
+ *
+ * al contains the required alignment, len the length of a bit-field.
+ */
+static void
+align(al, len)
+ int al, len;
+{
+ int no;
+
+ /*
+ * The alignment of the current element becomes the alignment of
+ * the struct/union if it is larger than the current alignment
+ * of the struct/union.
+ */
+ if (al > dcs->d_stralign)
+ dcs->d_stralign = al;
+
+ no = (dcs->d_offset + (al - 1)) & ~(al - 1);
+ if (len == 0 || dcs->d_offset + len > no)
+ dcs->d_offset = no;
+}
+
+/*
+ * Remember the width of the field in its type structure.
+ */
+sym_t *
+bitfield(dsym, len)
+ sym_t *dsym;
+ int len;
+{
+ if (dsym == NULL) {
+ dsym = getblk(sizeof (sym_t));
+ dsym->s_name = unnamed;
+ dsym->s_kind = FMOS;
+ dsym->s_scl = MOS;
+ dsym->s_type = gettyp(INT);
+ dsym->s_blklev = -1;
+ }
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_isfield = 1;
+ dsym->s_type->t_flen = len;
+ dsym->s_field = 1;
+ return (dsym);
+}
+
+/*
+ * Collect informations about a sequence of asterisks and qualifiers
+ * in a list of type pqinf_t.
+ * Qualifiers refer always to the left asterisk. The rightmost asterisk
+ * will be at the top of the list.
+ */
+pqinf_t *
+mergepq(p1, p2)
+ pqinf_t *p1, *p2;
+{
+ pqinf_t *p;
+
+ if (p2->p_pcnt != 0) {
+ /* left '*' at the end of the list */
+ for (p = p2; p->p_nxt != NULL; p = p->p_nxt) ;
+ p->p_nxt = p1;
+ return (p2);
+ } else {
+ if (p2->p_const) {
+ if (p1->p_const) {
+ /* duplicate %s */
+ warning(10, "const");
+ }
+ p1->p_const = 1;
+ }
+ if (p2->p_volatile) {
+ if (p1->p_volatile) {
+ /* duplicate %s */
+ warning(10, "volatile");
+ }
+ p1->p_volatile = 1;
+ }
+ free(p2);
+ return (p1);
+ }
+}
+
+/*
+ * Followint 3 functions extend the type of a declarator with
+ * pointer, function and array types.
+ *
+ * The current type is the Type built by deftyp() (dcs->d_type) and
+ * pointer, function and array types already added for this
+ * declarator. The new type extension is inserted between both.
+ */
+sym_t *
+addptr(decl, pi)
+ sym_t *decl;
+ pqinf_t *pi;
+{
+ type_t **tpp, *tp;
+ pqinf_t *npi;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ while (pi != NULL) {
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = PTR;
+ tp->t_const = pi->p_const;
+ tp->t_volatile = pi->p_volatile;
+ *(tpp = &tp->t_subt) = dcs->d_type;
+ npi = pi->p_nxt;
+ free(pi);
+ pi = npi;
+ }
+ return (decl);
+}
+
+/*
+ * If a dimension was specified, dim is 1, otherwise 0
+ * n is the specified dimension
+ */
+sym_t *
+addarray(decl, dim, n)
+ sym_t *decl;
+ int dim, n;
+{
+ type_t **tpp, *tp;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = ARRAY;
+ tp->t_subt = dcs->d_type;
+ tp->t_dim = n;
+
+ if (n < 0) {
+ /* zero or negative array dimension */
+ error(20);
+ n = 0;
+ } else if (n == 0 && dim) {
+ /* zero or negative array dimension */
+ warning(20);
+ } else if (n == 0 && !dim) {
+ /* is incomplete type */
+ setcompl(tp, 1);
+ }
+
+ return (decl);
+}
+
+sym_t *
+addfunc(decl, args)
+ sym_t *decl, *args;
+{
+ type_t **tpp, *tp;
+
+ if (dcs->d_proto) {
+ if (tflag)
+ /* function prototypes are illegal in traditional C */
+ warning(270);
+ args = nsfunc(decl, args);
+ } else {
+ osfunc(decl, args);
+ }
+
+ /*
+ * The symbols are removed from the symbol table by popdecl() after
+ * addfunc(). To be able to restore them if this is a function
+ * definition, a pointer to the list of all symbols is stored in
+ * dcs->d_nxt->d_fpsyms. Also a list of the arguments (concatenated
+ * by s_nxt) is stored in dcs->d_nxt->d_fargs.
+ * (dcs->d_nxt must be used because *dcs is the declaration stack
+ * element created for the list of params and is removed after
+ * addfunc())
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ dcs->d_nxt->d_fpsyms = dcs->d_dlsyms;
+ dcs->d_nxt->d_fargs = args;
+ }
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_nxt->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = FUNC;
+ tp->t_subt = dcs->d_nxt->d_type;
+ if ((tp->t_proto = dcs->d_proto) != 0)
+ tp->t_args = args;
+ tp->t_vararg = dcs->d_vararg;
+
+ return (decl);
+}
+
+/*
+ * Called for new style function declarations.
+ */
+/* ARGSUSED */
+static sym_t *
+nsfunc(decl, args)
+ sym_t *decl, *args;
+{
+ sym_t *arg, *sym;
+ scl_t sc;
+ int n;
+
+ /*
+ * Declarations of structs/unions/enums in param lists are legal,
+ * but senseless.
+ */
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ sc = sym->s_scl;
+ if (sc == STRTAG || sc == UNIONTAG || sc == ENUMTAG) {
+ /* dubious tag declaration: %s %s */
+ warning(85, scltoa(sc), sym->s_name);
+ }
+ }
+
+ n = 1;
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_type->t_tspec == VOID) {
+ if (n > 1 || arg->s_nxt != NULL) {
+ /* "void" must be sole parameter */
+ error(60);
+ arg->s_type = gettyp(INT);
+ }
+ }
+ n++;
+ }
+
+ /* return NULL if first param is VOID */
+ return (args != NULL && args->s_type->t_tspec != VOID ? args : NULL);
+}
+
+/*
+ * Called for old style function declarations.
+ */
+static void
+osfunc(decl, args)
+ sym_t *decl, *args;
+{
+ /*
+ * Remember list of params only if this is really seams to be
+ * a function definition.
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ /*
+ * We assume that this becomes a function definition. If
+ * we are wrong, its corrected in chkfdef().
+ */
+ if (args != NULL) {
+ decl->s_osdef = 1;
+ decl->s_args = args;
+ }
+ } else {
+ if (args != NULL)
+ /* function prototype parameters must have types */
+ warning(62);
+ }
+}
+
+/*
+ * Lists of Identifiers in functions declarations are allowed only if
+ * its also a function definition. If this is not the case, print a
+ * error message.
+ */
+void
+chkfdef(sym, msg)
+ sym_t *sym;
+ int msg;
+{
+ if (sym->s_osdef) {
+ if (msg) {
+ /* incomplete or misplaced function definition */
+ error(22);
+ }
+ sym->s_osdef = 0;
+ sym->s_args = NULL;
+ }
+}
+
+/*
+ * Process the name in a declarator.
+ * If the symbol does already exists, a new one is created.
+ * The symbol becomes one of the storage classes EXTERN, STATIC, AUTO or
+ * TYPEDEF.
+ * s_def and s_reg are valid after dname().
+ */
+sym_t *
+dname(sym)
+ sym_t *sym;
+{
+ scl_t sc;
+
+ if (sym->s_scl == NOSCL) {
+ dcs->d_rdcsym = NULL;
+ } else if (sym->s_defarg) {
+ sym->s_defarg = 0;
+ dcs->d_rdcsym = NULL;
+ } else {
+ dcs->d_rdcsym = sym;
+ sym = pushdown(sym);
+ }
+
+ switch (dcs->d_ctx) {
+ case MOS:
+ case MOU:
+ /* Parent setzen */
+ sym->s_styp = dcs->d_tagtyp->t_str;
+ sym->s_def = DEF;
+ sym->s_value.v_tspec = INT;
+ sc = dcs->d_ctx;
+ break;
+ case EXTERN:
+ /*
+ * static and external symbols without "extern" are
+ * considered to be tentative defined, external
+ * symbols with "extern" are declared, and typedef names
+ * are defined. Tentative defined and declared symbols
+ * may become defined if an initializer is present or
+ * this is a function definition.
+ */
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = EXTERN;
+ sym->s_def = TDEF;
+ } else if (sc == STATIC) {
+ sym->s_def = TDEF;
+ } else if (sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 1");
+ }
+ break;
+ case PARG:
+ sym->s_arg = 1;
+ /* FALLTHROUGH */
+ case ARG:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = AUTO;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ } else {
+ lerror("dname() 2");
+ }
+ sym->s_def = DEF;
+ break;
+ case AUTO:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ /*
+ * XXX somewhat ugly because we dont know whether
+ * this is AUTO or EXTERN (functions). If we are
+ * wrong it must be corrected in decl1loc(), where
+ * we have the neccessary type information.
+ */
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == AUTO || sc == STATIC || sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 3");
+ }
+ break;
+ default:
+ lerror("dname() 4");
+ }
+ sym->s_scl = sc;
+
+ sym->s_type = dcs->d_type;
+
+ dcs->d_fpsyms = NULL;
+
+ return (sym);
+}
+
+/*
+ * Process a name in the list of formal params in an old style function
+ * definition.
+ */
+sym_t *
+iname(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl != NOSCL) {
+ if (blklev == sym->s_blklev) {
+ /* redeclaration of formal parameter %s */
+ error(21, sym->s_name);
+ if (!sym->s_defarg)
+ lerror("iname()");
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_type = gettyp(INT);
+ sym->s_scl = AUTO;
+ sym->s_def = DEF;
+ sym->s_defarg = sym->s_arg = 1;
+ return (sym);
+}
+
+/*
+ * Create the type of a tag.
+ *
+ * tag points to the symbol table entry of the tag
+ * kind is the kind of the tag (STRUCT/UNION/ENUM)
+ * decl is 1 if the type of the tag will be completed in this declaration
+ * (the following token is T_LBRACE)
+ * semi is 1 if the following token is T_SEMI
+ */
+type_t *
+mktag(tag, kind, decl, semi)
+ sym_t *tag;
+ tspec_t kind;
+ int decl, semi;
+{
+ scl_t scl;
+ type_t *tp;
+
+ if (kind == STRUCT) {
+ scl = STRTAG;
+ } else if (kind == UNION) {
+ scl = UNIONTAG;
+ } else if (kind == ENUM) {
+ scl = ENUMTAG;
+ } else {
+ lerror("mktag()");
+ }
+
+ if (tag != NULL) {
+ if (tag->s_scl != NOSCL) {
+ tag = newtag(tag, scl, decl, semi);
+ } else {
+ /* a new tag, no empty declaration */
+ dcs->d_nxt->d_nedecl = 1;
+ if (scl == ENUMTAG && !decl) {
+ if (!tflag && (sflag || pflag))
+ /* forward reference to enum type */
+ warning(42);
+ }
+ }
+ if (tag->s_scl == NOSCL) {
+ tag->s_scl = scl;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ } else {
+ tp = tag->s_type;
+ }
+ } else {
+ tag = getblk(sizeof (sym_t));
+ tag->s_name = unnamed;
+ STRUCT_ASSIGN(tag->s_dpos, curr_pos);
+ tag->s_kind = FTAG;
+ tag->s_scl = scl;
+ tag->s_blklev = -1;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ dcs->d_nxt->d_nedecl = 1;
+ }
+
+ if (tp->t_tspec == NOTSPEC) {
+ tp->t_tspec = kind;
+ if (kind != ENUM) {
+ tp->t_str = getblk(sizeof (str_t));
+ tp->t_str->align = CHAR_BIT;
+ tp->t_str->stag = tag;
+ } else {
+ tp->t_isenum = 1;
+ tp->t_enum = getblk(sizeof (enum_t));
+ tp->t_enum->etag = tag;
+ }
+ /* ist unvollstaendiger Typ */
+ setcompl(tp, 1);
+ }
+
+ return (tp);
+}
+
+/*
+ * Checks all possible cases of tag redeclarations.
+ * decl is 1 if T_LBRACE follows
+ * semi is 1 if T_SEMI follows
+ */
+static sym_t *
+newtag(tag, scl, decl, semi)
+ sym_t *tag;
+ scl_t scl;
+ int decl, semi;
+{
+ if (tag->s_blklev < blklev) {
+ if (semi) {
+ /* "struct a;" */
+ if (!tflag) {
+ if (!sflag)
+ /* decl. introduces new type ... */
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ }
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl) {
+ /* "struct a { ..." */
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ /* declaration introduces new type in ANSI C: %s %s */
+ if (!sflag)
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ } else {
+ if (tag->s_scl != scl) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl && !incompl(tag->s_type)) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (semi || decl) {
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ }
+ return (tag);
+}
+
+const char *
+scltoa(sc)
+ scl_t sc;
+{
+ const char *s;
+
+ switch (sc) {
+ case EXTERN: s = "extern"; break;
+ case STATIC: s = "static"; break;
+ case AUTO: s = "auto"; break;
+ case REG: s = "register"; break;
+ case TYPEDEF: s = "typedef"; break;
+ case STRTAG: s = "struct"; break;
+ case UNIONTAG: s = "union"; break;
+ case ENUMTAG: s = "enum"; break;
+ default: lerror("tagttoa()");
+ }
+ return (s);
+}
+
+/*
+ * Completes the type of a tag in a struct/union/enum declaration.
+ * tp points to the type of the, tag, fmem to the list of members/enums.
+ */
+type_t *
+compltag(tp, fmem)
+ type_t *tp;
+ sym_t *fmem;
+{
+ tspec_t t;
+ str_t *sp;
+ int n;
+ sym_t *mem;
+
+ /* from now a complete type */
+ setcompl(tp, 0);
+
+ if ((t = tp->t_tspec) != ENUM) {
+ align(dcs->d_stralign, 0);
+ sp = tp->t_str;
+ sp->align = dcs->d_stralign;
+ sp->size = dcs->d_offset;
+ sp->memb = fmem;
+ if (sp->size == 0) {
+ /* zero sized %s */
+ (void)gnuism(47, ttab[t].tt_name);
+ } else {
+ n = 0;
+ for (mem = fmem; mem != NULL; mem = mem->s_nxt) {
+ if (mem->s_name != unnamed)
+ n++;
+ }
+ if (n == 0) {
+ /* %s has no named members */
+ warning(65,
+ t == STRUCT ? "structure" : "union");
+ }
+ }
+ } else {
+ tp->t_enum->elem = fmem;
+ }
+ return (tp);
+}
+
+/*
+ * Processes the name of an enumerator in en enum declaration.
+ *
+ * sym points to the enumerator
+ * val is the value of the enumerator
+ * impl is 1 if the the value of the enumerator was not explicit specified.
+ */
+sym_t *
+ename(sym, val, impl)
+ sym_t *sym;
+ int val, impl;
+{
+ if (sym->s_scl) {
+ if (sym->s_blklev == blklev) {
+ /* no hflag, because this is illegal!!! */
+ if (sym->s_arg) {
+ /* enumeration constant hides parameter: %s */
+ warning(57, sym->s_name);
+ } else {
+ /* redeclaration of %s */
+ error(27, sym->s_name);
+ /*
+ * inside blocks it should not too complicated
+ * to find the position of the previous
+ * declaration
+ */
+ if (blklev == 0)
+ prevdecl(-1, sym);
+ }
+ } else {
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, sym->s_name);
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_scl = ENUMCON;
+ sym->s_type = dcs->d_tagtyp;
+ sym->s_value.v_tspec = INT;
+ sym->s_value.v_quad = val;
+ if (impl && val - 1 == INT_MAX) {
+ /* overflow in enumeration values: %s */
+ warning(48, sym->s_name);
+ }
+ enumval = val + 1;
+ return (sym);
+}
+
+/*
+ * Process a single external declarator.
+ */
+void
+decl1ext(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ int warn, rval, redec;
+ sym_t *rdsym;
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (initflg && !(initerr = chkinit(dsym)))
+ dsym->s_def = DEF;
+
+ /*
+ * Declarations of functions are marked as "tentative" in dname().
+ * This is wrong because there are no tentative function
+ * definitions.
+ */
+ if (dsym->s_type->t_tspec == FUNC && dsym->s_def == TDEF)
+ dsym->s_def = DECL;
+
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ /* Write the declaration into the output file */
+ if (plibflg && llibflg &&
+ dsym->s_type->t_tspec == FUNC && dsym->s_type->t_proto) {
+ /*
+ * With both LINTLIBRARY and PROTOLIB the prototyp is
+ * written as a function definition to the output file.
+ */
+ rval = dsym->s_type->t_subt->t_tspec != VOID;
+ outfdef(dsym, &dsym->s_dpos, rval, 0, NULL);
+ } else {
+ outsym(dsym, dsym->s_scl, dsym->s_def);
+ }
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ /*
+ * If the old symbol stems from a old style function definition
+ * we have remembered the params in rdsmy->s_args and compare
+ * them with the params of the prototype.
+ */
+ if (rdsym->s_osdef && dsym->s_type->t_proto) {
+ redec = chkosdef(rdsym, dsym);
+ } else {
+ redec = 0;
+ }
+
+ if (!redec && !isredec(dsym, (warn = 0, &warn))) {
+
+ if (warn) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, dsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /*
+ * Overtake the rememberd params if the new symbol
+ * is not a prototype.
+ */
+ if (rdsym->s_osdef && !dsym->s_type->t_proto) {
+ dsym->s_osdef = rdsym->s_osdef;
+ dsym->s_args = rdsym->s_args;
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Remember the position of the declaration if the
+ * old symbol was a prototype and the new is not.
+ * Also remember the position if the old symbol
+ * was defined and the new is not.
+ */
+ if (rdsym->s_type->t_proto && !dsym->s_type->t_proto) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ } else if (rdsym->s_def == DEF && dsym->s_def != DEF) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Copy informations about usage of the name into
+ * the new symbol.
+ */
+ cpuinfo(dsym, rdsym);
+
+ /* Once a name is defined, it remains defined. */
+ if (rdsym->s_def == DEF)
+ dsym->s_def = DEF;
+
+ /* once a function is inline, it remains inline */
+ if (rdsym->s_inline)
+ dsym->s_inline = 1;
+
+ compltyp(dsym, rdsym);
+
+ }
+
+ rmsym(rdsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+}
+
+/*
+ * Copies informations about usage into a new symbol table entry of
+ * the same symbol.
+ */
+void
+cpuinfo(sym, rdsym)
+ sym_t *sym, *rdsym;
+{
+ sym->s_spos = rdsym->s_spos;
+ sym->s_upos = rdsym->s_upos;
+ sym->s_set = rdsym->s_set;
+ sym->s_used = rdsym->s_used;
+}
+
+/*
+ * Prints an error and returns 1 if a symbol is redeclared/redefined.
+ * Otherwise returns 0 and, in some cases of minor problems, prints
+ * a warning.
+ */
+int
+isredec(dsym, warn)
+ sym_t *dsym;
+ int *warn;
+{
+ sym_t *rsym;
+
+ if ((rsym = dcs->d_rdcsym)->s_scl == ENUMCON) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_scl == TYPEDEF) {
+ /* typedef redeclared: %s */
+ error(89, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (dsym->s_scl == TYPEDEF) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_def == DEF && dsym->s_def == DEF) {
+ /* redefinition of %s */
+ error(28, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (!eqtype(rsym->s_type, dsym->s_type, 0, 0, warn)) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN && dsym->s_scl == EXTERN)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_scl == STATIC)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_def == DECL)
+ return(0);
+ if (rsym->s_scl == EXTERN && rsym->s_def == DEF) {
+ /*
+ * All cases except "int a = 1; static int a;" are catched
+ * above with or without a warning
+ */
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN) {
+ /* previously declared extern, becomes static: %s */
+ warning(29, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(0);
+ }
+ /*
+ * Now its on of:
+ * "static a; int a;", "static a; int a = 1;", "static a = 1; int a;"
+ */
+ /* redeclaration of %s; ANSI C requires "static" */
+ if (sflag) {
+ warning(30, dsym->s_name);
+ prevdecl(-1, rsym);
+ }
+ dsym->s_scl = STATIC;
+ return (0);
+}
+
+/*
+ * Checks if two types are compatible. Returns 0 if not, otherwise 1.
+ *
+ * ignqual ignore qualifiers of type; used for function params
+ * promot promote left type; used for comparision of params of
+ * old style function definitions with params of prototypes.
+ * *warn set to 1 if an old style function declaration is not
+ * compatible with a prototype
+ */
+int
+eqtype(tp1, tp2, ignqual, promot, warn)
+ type_t *tp1, *tp2;
+ int ignqual, promot, *warn;
+{
+ tspec_t t;
+
+ while (tp1 != NULL && tp2 != NULL) {
+
+ t = tp1->t_tspec;
+ if (promot) {
+ if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == CHAR || t == SCHAR) {
+ t = INT;
+ } else if (t == UCHAR) {
+ t = tflag ? UINT : INT;
+ } else if (t == SHORT) {
+ t = INT;
+ } else if (t == USHORT) {
+ /* CONSTCOND */
+ t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (t != tp2->t_tspec)
+ return (0);
+
+ if (tp1->t_const != tp2->t_const && !ignqual && !tflag)
+ return (0);
+
+ if (tp1->t_volatile != tp2->t_volatile && !ignqual && !tflag)
+ return (0);
+
+ if (t == STRUCT || t == UNION)
+ return (tp1->t_str == tp2->t_str);
+
+ if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
+ if (tp1->t_dim != 0 && tp2->t_dim != 0)
+ return (0);
+ }
+
+ /* dont check prototypes for traditional */
+ if (t == FUNC && !tflag) {
+ if (tp1->t_proto && tp2->t_proto) {
+ if (!eqargs(tp1, tp2, warn))
+ return (0);
+ } else if (tp1->t_proto) {
+ if (!mnoarg(tp1, warn))
+ return (0);
+ } else if (tp2->t_proto) {
+ if (!mnoarg(tp2, warn))
+ return (0);
+ }
+ }
+
+ tp1 = tp1->t_subt;
+ tp2 = tp2->t_subt;
+ ignqual = promot = 0;
+
+ }
+
+ return (tp1 == tp2);
+}
+
+/*
+ * Compares the parameter types of two prototypes.
+ */
+static int
+eqargs(tp1, tp2, warn)
+ type_t *tp1, *tp2;
+ int *warn;
+{
+ sym_t *a1, *a2;
+
+ if (tp1->t_vararg != tp2->t_vararg)
+ return (0);
+
+ a1 = tp1->t_args;
+ a2 = tp2->t_args;
+
+ while (a1 != NULL && a2 != NULL) {
+
+ if (eqtype(a1->s_type, a2->s_type, 1, 0, warn) == 0)
+ return (0);
+
+ a1 = a1->s_nxt;
+ a2 = a2->s_nxt;
+
+ }
+
+ return (a1 == a2);
+}
+
+/*
+ * mnoarg() (matches functions with no argument type information)
+ * returns 1 if all parameters of a prototype are compatible with
+ * and old style function declaration.
+ * This is the case if following conditions are met:
+ * 1. the prototype must have a fixed number of parameters
+ * 2. no parameter is of type float
+ * 3. no parameter is converted to another type if integer promotion
+ * is applied on it
+ */
+static int
+mnoarg(tp, warn)
+ type_t *tp;
+ int *warn;
+{
+ sym_t *arg;
+ tspec_t t;
+
+ if (tp->t_vararg) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) {
+ if ((t = arg->s_type->t_tspec) == FLOAT ||
+ t == CHAR || t == SCHAR || t == UCHAR ||
+ t == SHORT || t == USHORT) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ }
+ return (1);
+}
+
+/*
+ * Compares a prototype declaration with the remembered arguments of
+ * a previous old style function definition.
+ */
+static int
+chkosdef(rdsym, dsym)
+ sym_t *rdsym, *dsym;
+{
+ sym_t *args, *pargs, *arg, *parg;
+ int narg, nparg, n;
+ int warn, msg;
+
+ args = rdsym->s_args;
+ pargs = dsym->s_type->t_args;
+
+ msg = 0;
+
+ narg = nparg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ if (narg != nparg) {
+ /* prototype does not match old-style definition */
+ error(63);
+ msg = 1;
+ goto end;
+ }
+
+ arg = args;
+ parg = pargs;
+ n = 1;
+ while (narg--) {
+ warn = 0;
+ /*
+ * If it does not match due to promotion and sflag is
+ * not set we print only a warning.
+ */
+ if (!eqtype(arg->s_type, parg->s_type, 1, 1, &warn) || warn) {
+ /* prototype does not match old-style def., arg #%d */
+ error(299, n);
+ msg = 1;
+ }
+ arg = arg->s_nxt;
+ parg = parg->s_nxt;
+ n++;
+ }
+
+ end:
+ if (msg)
+ /* old style definition */
+ prevdecl(300, rdsym);
+
+ return (msg);
+}
+
+/*
+ * Complets a type by copying the dimension and prototype information
+ * from a second compatible type.
+ *
+ * Following lines are legal:
+ * "typedef a[]; a b; a b[10]; a c; a c[20];"
+ * "typedef ft(); ft f; f(int); ft g; g(long);"
+ * This means that, if a type is completed, the type structure must
+ * be duplicated.
+ */
+void
+compltyp(dsym, ssym)
+ sym_t *dsym, *ssym;
+{
+ type_t **dstp, *src;
+ type_t *dst;
+
+ dstp = &dsym->s_type;
+ src = ssym->s_type;
+
+ while ((dst = *dstp) != NULL) {
+ if (src == NULL || dst->t_tspec != src->t_tspec)
+ lerror("compltyp() 1");
+ if (dst->t_tspec == ARRAY) {
+ if (dst->t_dim == 0 && src->t_dim != 0) {
+ *dstp = dst = duptyp(dst);
+ dst->t_dim = src->t_dim;
+ /* now a complete Typ */
+ setcompl(dst, 0);
+ }
+ } else if (dst->t_tspec == FUNC) {
+ if (!dst->t_proto && src->t_proto) {
+ *dstp = dst = duptyp(dst);
+ dst->t_proto = 1;
+ dst->t_args = src->t_args;
+ }
+ }
+ dstp = &dst->t_subt;
+ src = src->t_subt;
+ }
+}
+
+/*
+ * Completes the declaration of a single argument.
+ */
+sym_t *
+decl1arg(sym, initflg)
+ sym_t *sym;
+ int initflg;
+{
+ tspec_t t;
+
+ chkfdef(sym, 1);
+
+ chktyp(sym);
+
+ if (dcs->d_rdcsym != NULL && dcs->d_rdcsym->s_blklev == blklev) {
+ /* redeclaration of formal parameter %s */
+ error(237, sym->s_name);
+ rmsym(dcs->d_rdcsym);
+ sym->s_arg = 1;
+ }
+
+ if (!sym->s_arg) {
+ /* declared argument %s is missing */
+ error(53, sym->s_name);
+ sym->s_arg = 1;
+ }
+
+ if (initflg) {
+ /* cannot initialize parameter: %s */
+ error(52, sym->s_name);
+ initerr = 1;
+ }
+
+ if ((t = sym->s_type->t_tspec) == ARRAY) {
+ sym->s_type = incref(sym->s_type->t_subt, PTR);
+ } else if (t == FUNC) {
+ if (tflag)
+ /* a function is declared as an argument: %s */
+ warning(50, sym->s_name);
+ sym->s_type = incref(sym->s_type, PTR);
+ } else if (t == FLOAT) {
+ if (tflag)
+ sym->s_type = gettyp(DOUBLE);
+ }
+
+ if (dcs->d_inline)
+ /* argument declared inline: %s */
+ warning(269, sym->s_name);
+
+ /*
+ * Arguments must have complete types. lengths() prints the needed
+ * error messages (null dimension is impossible because arrays are
+ * converted to pointers).
+ */
+ if (sym->s_type->t_tspec != VOID)
+ (void)length(sym->s_type, sym->s_name);
+
+ setsflg(sym);
+
+ return (sym);
+}
+
+/*
+ * Does some checks for lint directives which apply to functions.
+ * Processes arguments in old style function definitions which default
+ * to int.
+ * Checks compatiblility of old style function definition with previous
+ * prototype.
+ */
+void
+cluparg()
+{
+ sym_t *args, *arg, *pargs, *parg;
+ int narg, nparg, n, msg;
+ tspec_t t;
+
+ args = funcsym->s_args;
+ pargs = funcsym->s_type->t_args;
+
+ /* check for illegal combinations of lint directives */
+ if (prflstrg != -1 && scflstrg != -1) {
+ /* can't be used together: ** PRINTFLIKE ** ** SCANFLIKE ** */
+ warning(289);
+ prflstrg = scflstrg = -1;
+ }
+ if (nvararg != -1 && (prflstrg != -1 || scflstrg != -1)) {
+ /* dubious use of ** VARARGS ** with ** %s ** */
+ warning(288, prflstrg != -1 ? "PRINTFLIKE" : "SCANFLIKE");
+ nvararg = -1;
+ }
+
+ /*
+ * check if the argument of a lint directive is compatible with the
+ * number of arguments.
+ */
+ narg = 0;
+ for (arg = dcs->d_fargs; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (nargusg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "ARGSUSED");
+ nargusg = 0;
+ }
+ if (nvararg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "VARARGS");
+ nvararg = 0;
+ }
+ if (prflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "PRINTFLIKE");
+ prflstrg = -1;
+ } else if (prflstrg == 0) {
+ prflstrg = -1;
+ }
+ if (scflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "SCANFLIKE");
+ scflstrg = -1;
+ } else if (scflstrg == 0) {
+ scflstrg = -1;
+ }
+ if (prflstrg != -1 || scflstrg != -1) {
+ narg = prflstrg != -1 ? prflstrg : scflstrg;
+ arg = dcs->d_fargs;
+ for (n = 1; n < narg; n++)
+ arg = arg->s_nxt;
+ if (arg->s_type->t_tspec != PTR ||
+ ((t = arg->s_type->t_subt->t_tspec) != CHAR &&
+ t != UCHAR && t != SCHAR)) {
+ /* arg. %d must be 'char *' for PRINTFLIKE/SCANFLIKE */
+ warning(293, narg);
+ prflstrg = scflstrg = -1;
+ }
+ }
+
+ /*
+ * print a warning for each argument off an old style function
+ * definition which defaults to int
+ */
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_defarg) {
+ /* argument type defaults to int: %s */
+ warning(32, arg->s_name);
+ arg->s_defarg = 0;
+ setsflg(arg);
+ }
+ }
+
+ /*
+ * If this is an old style function definition and a prototyp
+ * exists, compare the types of arguments.
+ */
+ if (funcsym->s_osdef && funcsym->s_type->t_proto) {
+ /*
+ * If the number of arguments does not macht, we need not
+ * continue.
+ */
+ narg = nparg = 0;
+ msg = 0;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (narg != nparg) {
+ /* parameter mismatch: %d declared, %d defined */
+ error(51, nparg, narg);
+ msg = 1;
+ } else {
+ parg = pargs;
+ arg = args;
+ while (narg--) {
+ msg |= chkptdecl(arg, parg);
+ parg = parg->s_nxt;
+ arg = arg->s_nxt;
+ }
+ }
+ if (msg)
+ /* prototype declaration */
+ prevdecl(285, dcs->d_rdcsym);
+
+ /* from now the prototype is valid */
+ funcsym->s_osdef = 0;
+ funcsym->s_args = NULL;
+
+ }
+
+}
+
+/*
+ * Checks compatibility of an old style function definition with a previous
+ * prototype declaration.
+ * Returns 1 if the position of the previous declaration should be reported.
+ */
+static int
+chkptdecl(arg, parg)
+ sym_t *arg, *parg;
+{
+ type_t *tp, *ptp;
+ int warn, msg;
+
+ tp = arg->s_type;
+ ptp = parg->s_type;
+
+ msg = 0;
+ warn = 0;
+
+ if (!eqtype(tp, ptp, 1, 1, &warn)) {
+ if (eqtype(tp, ptp, 1, 0, &warn)) {
+ /* type does not match prototype: %s */
+ msg = gnuism(58, arg->s_name);
+ } else {
+ /* type does not match prototype: %s */
+ error(58, arg->s_name);
+ msg = 1;
+ }
+ } else if (warn) {
+ /* type does not match prototype: %s */
+ (*(sflag ? error : warning))(58, arg->s_name);
+ msg = 1;
+ }
+
+ return (msg);
+}
+
+/*
+ * Completes a single local declaration/definition.
+ */
+void
+decl1loc(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ /* Correct a mistake done in dname(). */
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_def = DECL;
+ if (dcs->d_scl == NOSCL)
+ dsym->s_scl = EXTERN;
+ }
+
+ if (dsym->s_type->t_tspec == FUNC) {
+ if (dsym->s_scl == STATIC) {
+ /* dubious static function at block level: %s */
+ warning(93, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ } else if (dsym->s_scl != EXTERN && dsym->s_scl != TYPEDEF) {
+ /* function has illegal storage class: %s */
+ error(94, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ }
+ }
+
+ /*
+ * functions may be declared inline at local scope, although
+ * this has no effect for a later definition of the same
+ * function.
+ * XXX it should have an effect if tflag is set. this would
+ * also be the way gcc behaves.
+ */
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (dcs->d_rdcsym != NULL && dsym->s_scl == EXTERN)
+ ledecl(dsym);
+
+ if (dsym->s_scl == EXTERN) {
+ /*
+ * XXX wenn die statische Variable auf Ebene 0 erst
+ * spaeter definiert wird, haben wir die Brille auf.
+ */
+ if (dsym->s_xsym == NULL) {
+ outsym(dsym, EXTERN, dsym->s_def);
+ } else {
+ outsym(dsym, dsym->s_xsym->s_scl, dsym->s_def);
+ }
+ }
+
+ if (dcs->d_rdcsym != NULL) {
+
+ if (dcs->d_rdcsym->s_blklev == 0) {
+
+ switch (dsym->s_scl) {
+ case AUTO:
+ /* automatic hides external declaration: %s */
+ if (hflag)
+ warning(86, dsym->s_name);
+ break;
+ case STATIC:
+ /* static hides external declaration: %s */
+ if (hflag)
+ warning(87, dsym->s_name);
+ break;
+ case TYPEDEF:
+ /* typedef hides external declaration: %s */
+ if (hflag)
+ warning(88, dsym->s_name);
+ break;
+ case EXTERN:
+ /*
+ * Warnings and errors are printed in ledecl()
+ */
+ break;
+ default:
+ lerror("decl1loc() 1");
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* no hflag, because its illegal! */
+ if (dcs->d_rdcsym->s_arg) {
+ /*
+ * if !tflag, a "redeclaration of %s" error
+ * is produced below
+ */
+ if (tflag) {
+ if (hflag)
+ /* decl. hides parameter: %s */
+ warning(91, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev < blklev) {
+
+ if (hflag)
+ /* declaration hides earlier one: %s */
+ warning(95, dsym->s_name);
+
+ }
+
+ if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+
+ }
+
+ }
+
+ if (initflg && !(initerr = chkinit(dsym))) {
+ dsym->s_def = DEF;
+ setsflg(dsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+ /*
+ * Before we can check the size we must wait for a initialisation
+ * which may follow.
+ */
+}
+
+/*
+ * Processes (re)declarations of external Symbols inside blocks.
+ */
+static void
+ledecl(dsym)
+ sym_t *dsym;
+{
+ int eqt, warn;
+ sym_t *esym;
+
+ /* look for a symbol with the same name */
+ esym = dcs->d_rdcsym;
+ while (esym != NULL && esym->s_blklev != 0) {
+ while ((esym = esym->s_link) != NULL) {
+ if (esym->s_kind != FVFT)
+ continue;
+ if (strcmp(dsym->s_name, esym->s_name) == 0)
+ break;
+ }
+ }
+ if (esym == NULL)
+ return;
+ if (esym->s_scl != EXTERN && esym->s_scl != STATIC) {
+ /* gcc accepts this without a warning, pcc prints an error. */
+ /* redeclaration of %s */
+ warning(27, dsym->s_name);
+ prevdecl(-1, esym);
+ return;
+ }
+
+ warn = 0;
+ eqt = eqtype(esym->s_type, dsym->s_type, 0, 0, &warn);
+
+ if (!eqt || warn) {
+ if (esym->s_scl == EXTERN) {
+ /* inconsistent redeclaration of extern: %s */
+ warning(90, dsym->s_name);
+ prevdecl(-1, esym);
+ } else {
+ /* inconsistent redeclaration of static: %s */
+ warning(92, dsym->s_name);
+ prevdecl(-1, esym);
+ }
+ }
+
+ if (eqt) {
+ /*
+ * Remember the external symbol so we can update usage
+ * information at the end of the block.
+ */
+ dsym->s_xsym = esym;
+ }
+}
+
+/*
+ * Print an error or a warning if the symbol cant be initialized due
+ * to type/storage class. Returnvalue is 1 if an error has been
+ * detected.
+ */
+static int
+chkinit(sym)
+ sym_t *sym;
+{
+ int err;
+
+ err = 0;
+
+ if (sym->s_type->t_tspec == FUNC) {
+ /* cannot initialize function: %s */
+ error(24, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == TYPEDEF) {
+ /* cannot initialize typedef: %s */
+ error(25, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == EXTERN && sym->s_def == DECL) {
+ /* cannot initialize "extern" declaration: %s */
+ if (dcs->d_ctx == EXTERN) {
+ warning(26, sym->s_name);
+ } else {
+ error(26, sym->s_name);
+ err = 1;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Create a symbole for an abstract declaration.
+ */
+sym_t *
+aname()
+{
+ sym_t *sym;
+
+ if (dcs->d_ctx != ABSTRACT && dcs->d_ctx != PARG)
+ lerror("aname()");
+
+ sym = getblk(sizeof (sym_t));
+
+ sym->s_name = unnamed;
+ sym->s_def = DEF;
+ sym->s_scl = ABSTRACT;
+ sym->s_blklev = -1;
+
+ if (dcs->d_ctx == PARG)
+ sym->s_arg = 1;
+
+ sym->s_type = dcs->d_type;
+ dcs->d_rdcsym = NULL;
+ dcs->d_vararg = 0;
+
+ return (sym);
+}
+
+/*
+ * Removes anything which has nothing to do on global level.
+ */
+void
+globclup()
+{
+ while (dcs->d_nxt != NULL)
+ popdecl();
+
+ cleanup();
+ blklev = 0;
+ mblklev = 0;
+
+ /*
+ * remove all informations about pending lint directives without
+ * warnings.
+ */
+ glclup(1);
+}
+
+/*
+ * Process an abstract type declaration
+ */
+sym_t *
+decl1abs(sym)
+ sym_t *sym;
+{
+ chkfdef(sym, 1);
+ chktyp(sym);
+ return (sym);
+}
+
+/*
+ * Checks size after declarations of variables and their initialisation.
+ */
+void
+chksz(dsym)
+ sym_t *dsym;
+{
+ /*
+ * check size only for symbols which are defined and no function and
+ * not typedef name
+ */
+ if (dsym->s_def != DEF)
+ return;
+ if (dsym->s_scl == TYPEDEF)
+ return;
+ if (dsym->s_type->t_tspec == FUNC)
+ return;
+
+ if (length(dsym->s_type, dsym->s_name) == 0 &&
+ dsym->s_type->t_tspec == ARRAY && dsym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag) {
+ warning(190, dsym->s_name);
+ } else {
+ error(190, dsym->s_name);
+ }
+ }
+}
+
+/*
+ * Mark an object as set if it is not already
+ */
+void
+setsflg(sym)
+ sym_t *sym;
+{
+ if (!sym->s_set) {
+ sym->s_set = 1;
+ STRUCT_ASSIGN(sym->s_spos, curr_pos);
+ }
+}
+
+/*
+ * Mark an object as used if it is not already
+ */
+void
+setuflg(sym, fcall, szof)
+ sym_t *sym;
+ int fcall, szof;
+{
+ if (!sym->s_used) {
+ sym->s_used = 1;
+ STRUCT_ASSIGN(sym->s_upos, curr_pos);
+ }
+ /*
+ * for function calls another record is written
+ *
+ * XXX Should symbols used in sizeof() treated as used or not?
+ * Probably not, because there is no sense to declare an
+ * external variable only to get their size.
+ */
+ if (!fcall && !szof && sym->s_kind == FVFT && sym->s_scl == EXTERN)
+ outusg(sym);
+}
+
+/*
+ * Prints warnings for a list of variables and labels (concatenated
+ * with s_dlnxt) if these are not used or only set.
+ */
+void
+chkusage(di)
+ dinfo_t *di;
+{
+ sym_t *sym;
+ int mknowarn;
+
+ /* for this warnings LINTED has no effect */
+ mknowarn = nowarn;
+ nowarn = 0;
+
+ for (sym = di->d_dlsyms; sym != NULL; sym = sym->s_dlnxt)
+ chkusg1(di->d_asm, sym);
+
+ nowarn = mknowarn;
+}
+
+/*
+ * Prints a warning for a single variable or label if it is not used or
+ * only set.
+ */
+void
+chkusg1(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ pos_t cpos;
+
+ if (sym->s_blklev == -1)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (sym->s_kind == FVFT) {
+ if (sym->s_arg) {
+ chkausg(novar, sym);
+ } else {
+ chkvusg(novar, sym);
+ }
+ } else if (sym->s_kind == FLAB) {
+ chklusg(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkausg(novar, arg)
+ int novar;
+ sym_t *arg;
+{
+ if (!arg->s_set)
+ lerror("chkausg() 1");
+
+ if (novar)
+ return;
+
+ if (!arg->s_used && vflag) {
+ STRUCT_ASSIGN(curr_pos, arg->s_dpos);
+ /* argument %s unused in function %s */
+ warning(231, arg->s_name, funcsym->s_name);
+ }
+}
+
+static void
+chkvusg(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ scl_t sc;
+ sym_t *xsym;
+
+ if (blklev == 0 || sym->s_blklev == 0)
+ lerror("chkvusg() 1");
+
+ /* errors in expressions easily cause lots of these warnings */
+ if (nerr != 0)
+ return;
+
+ /*
+ * XXX Only variables are checkd, although types should
+ * probably also be checked
+ */
+ if ((sc = sym->s_scl) != EXTERN && sc != STATIC &&
+ sc != AUTO && sc != REG) {
+ return;
+ }
+
+ if (novar)
+ return;
+
+ if (sc == EXTERN) {
+ if (!sym->s_used && !sym->s_set) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ } else {
+ if (sym->s_set && !sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_spos);
+ /* %s set but not used in function %s */
+ warning(191, sym->s_name, funcsym->s_name);
+ } else if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ }
+
+ if (sc == EXTERN) {
+ /*
+ * information about usage is taken over into the symbol
+ * tabel entry at level 0 if the symbol was locally declared
+ * as an external symbol.
+ *
+ * XXX This is wrong for symbols declared static at level 0
+ * if the usage information stems from sizeof(). This is
+ * because symbols at level 0 only used in sizeof() are
+ * considered to not be used.
+ */
+ if ((xsym = sym->s_xsym) != NULL) {
+ if (sym->s_used && !xsym->s_used) {
+ xsym->s_used = 1;
+ STRUCT_ASSIGN(xsym->s_upos, sym->s_upos);
+ }
+ if (sym->s_set && !xsym->s_set) {
+ xsym->s_set = 1;
+ STRUCT_ASSIGN(xsym->s_spos, sym->s_spos);
+ }
+ }
+ }
+}
+
+static void
+chklusg(lab)
+ sym_t *lab;
+{
+ if (blklev != 1 || lab->s_blklev != 1)
+ lerror("chklusg() 1");
+
+ if (lab->s_set && !lab->s_used) {
+ STRUCT_ASSIGN(curr_pos, lab->s_spos);
+ /* label %s unused in function %s */
+ warning(192, lab->s_name, funcsym->s_name);
+ } else if (!lab->s_set) {
+ STRUCT_ASSIGN(curr_pos, lab->s_upos);
+ /* undefined label %s */
+ warning(23, lab->s_name);
+ }
+}
+
+static void
+chktusg(sym)
+ sym_t *sym;
+{
+ if (!incompl(sym->s_type))
+ return;
+
+ /* complain alwasy about incomplet tags declared inside blocks */
+ if (!zflag || dcs->d_ctx != EXTERN)
+ return;
+
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ switch (sym->s_type->t_tspec) {
+ case STRUCT:
+ /* struct %s never defined */
+ warning(233, sym->s_name);
+ break;
+ case UNION:
+ /* union %s never defined */
+ warning(234, sym->s_name);
+ break;
+ case ENUM:
+ /* enum %s never defined */
+ warning(235, sym->s_name);
+ break;
+ default:
+ lerror("chktusg() 1");
+ }
+}
+
+/*
+ * Called after the entire translation unit has been parsed.
+ * Changes tentative definitions in definitions.
+ * Performs some tests on global Symbols. Detected Problems are:
+ * - defined variables of incomplete type
+ * - constant variables which are not initialized
+ * - static symbols which are never used
+ */
+void
+chkglsyms()
+{
+ sym_t *sym;
+ pos_t cpos;
+
+ if (blklev != 0 || dcs->d_nxt != NULL)
+ norecover();
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev == -1)
+ continue;
+ if (sym->s_kind == FVFT) {
+ chkglvar(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ } else {
+ if (sym->s_kind != FMOS)
+ lerror("chkglsyms() 1");
+ }
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkglvar(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl == TYPEDEF || sym->s_scl == ENUMCON)
+ return;
+
+ if (sym->s_scl != EXTERN && sym->s_scl != STATIC)
+ lerror("chkglvar() 1");
+
+ glchksz(sym);
+
+ if (sym->s_scl == STATIC) {
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_used && sym->s_def != DEF) {
+ STRUCT_ASSIGN(curr_pos, sym->s_upos);
+ /* static func. called but not def.. */
+ error(225, sym->s_name);
+ }
+ }
+ if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_def == DEF) {
+ if (!sym->s_inline)
+ /* static function %s unused */
+ warning(236, sym->s_name);
+ } else {
+ /* static function %s decl. but ... */
+ warning(290, sym->s_name);
+ }
+ } else if (!sym->s_set) {
+ /* static variable %s unused */
+ warning(226, sym->s_name);
+ } else {
+ /* static variable %s set but not used */
+ warning(307, sym->s_name);
+ }
+ }
+ if (!tflag && sym->s_def == TDEF && sym->s_type->t_const) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* const object %s should have initializer */
+ warning(227, sym->s_name);
+ }
+ }
+}
+
+static void
+glchksz(sym)
+ sym_t *sym;
+{
+ if (sym->s_def == TDEF) {
+ if (sym->s_type->t_tspec == FUNC)
+ /*
+ * this can happen if an syntax error occured
+ * after a function declaration
+ */
+ return;
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (length(sym->s_type, sym->s_name) == 0 &&
+ sym->s_type->t_tspec == ARRAY && sym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag || (sym->s_scl == EXTERN && !sflag)) {
+ warning(190, sym->s_name);
+ } else {
+ error(190, sym->s_name);
+ }
+ }
+ }
+}
+
+/*
+ * Prints information about location of previous definition/declaration.
+ */
+void
+prevdecl(msg, psym)
+ int msg;
+ sym_t *psym;
+{
+ pos_t cpos;
+
+ if (!rflag)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(curr_pos, psym->s_dpos);
+ if (msg != -1) {
+ message(msg, psym->s_name);
+ } else if (psym->s_def == DEF || psym->s_def == TDEF) {
+ /* previous definition of %s */
+ message(261, psym->s_name);
+ } else {
+ /* previous declaration of %s */
+ message(260, psym->s_name);
+ }
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
diff --git a/usr.bin/xlint/lint1/emit.c b/usr.bin/xlint/lint1/emit.c
new file mode 100644
index 0000000..f98f540
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit.c
@@ -0,0 +1,241 @@
+/* $NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "lint.h"
+
+/* name and handle of output file */
+static const char *loname;
+static FILE *lout;
+
+/* output buffer data */
+ob_t ob;
+
+static void outxbuf __P((void));
+
+
+/*
+ * initialize output
+ */
+void
+outopen(name)
+ const char *name;
+{
+ loname = name;
+
+ /* Ausgabedatei oeffnen */
+ if ((lout = fopen(name, "w")) == NULL)
+ err(1, "cannot open '%s'", name);
+
+ /* Ausgabepuffer anlegen */
+ ob.o_len = 1024;
+ ob.o_end = (ob.o_buf = ob.o_nxt = xmalloc(ob.o_len)) + ob.o_len;
+}
+
+/*
+ * flush output buffer and close file
+ */
+void
+outclose()
+{
+ outclr();
+ if (fclose(lout) == EOF)
+ err(1, "cannot close '%s'", loname);
+}
+
+/*
+ * resize output buffer
+ */
+static void
+outxbuf()
+{
+ ptrdiff_t coffs;
+
+ coffs = ob.o_nxt - ob.o_buf;
+ ob.o_len *= 2;
+ ob.o_end = (ob.o_buf = xrealloc(ob.o_buf, ob.o_len)) + ob.o_len;
+ ob.o_nxt = ob.o_buf + coffs;
+}
+
+/*
+ * reset output buffer
+ * if it is not empty, it is flushed
+ */
+void
+outclr()
+{
+ size_t sz;
+
+ if (ob.o_buf != ob.o_nxt) {
+ outchar('\n');
+ sz = ob.o_nxt - ob.o_buf;
+ if (sz > ob.o_len)
+ errx(1, "internal error: outclr() 1");
+ if (fwrite(ob.o_buf, sz, 1, lout) != 1)
+ err(1, "cannot write to %s", loname);
+ ob.o_nxt = ob.o_buf;
+ }
+}
+
+/*
+ * write a character to the output buffer
+ */
+void
+outchar(c)
+ int c;
+{
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = (char)c;
+}
+
+/*
+ * write a character to the output buffer, qouted if necessary
+ */
+void
+outqchar(c)
+ int c;
+{
+ if (isprint(c) && c != '\\' && c != '"' && c != '\'') {
+ outchar(c);
+ } else {
+ outchar('\\');
+ switch (c) {
+ case '\\':
+ outchar('\\');
+ break;
+ case '"':
+ outchar('"');
+ break;
+ case '\'':
+ outchar('\'');
+ break;
+ case '\b':
+ outchar('b');
+ break;
+ case '\t':
+ outchar('t');
+ break;
+ case '\n':
+ outchar('n');
+ break;
+ case '\f':
+ outchar('f');
+ break;
+ case '\r':
+ outchar('r');
+ break;
+#ifdef __STDC__
+ case '\v':
+#else
+ case '\013':
+#endif
+ outchar('v');
+ break;
+#ifdef __STDC__
+ case '\a':
+#else
+ case '\007':
+#endif
+ outchar('a');
+ break;
+ default:
+ outchar((((u_int)c >> 6) & 07) + '0');
+ outchar((((u_int)c >> 3) & 07) + '0');
+ outchar((c & 07) + '0');
+ break;
+ }
+ }
+}
+
+/*
+ * write a strint to the output buffer
+ * the string must not contain any characters which
+ * should be quoted
+ */
+void
+outstrg(s)
+ const char *s;
+{
+ while (*s != '\0') {
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = *s++;
+ }
+}
+
+/*
+ * write an integer value to toe output buffer
+ */
+void
+outint(i)
+ int i;
+{
+ if ((ob.o_end - ob.o_nxt) < 3 * sizeof (int))
+ outxbuf();
+ ob.o_nxt += sprintf(ob.o_nxt, "%d", i);
+}
+
+/*
+ * write the name of a symbol to the output buffer
+ * the name is preceeded by its length
+ */
+void
+outname(name)
+ const char *name;
+{
+ if (name == NULL)
+ errx(1, "internal error: outname() 1");
+ outint((int)strlen(name));
+ outstrg(name);
+}
+
+/*
+ * write the name of the .c source
+ */
+void
+outsrc(name)
+ const char *name;
+{
+ outclr();
+ outchar('S');
+ outstrg(name);
+}
diff --git a/usr.bin/xlint/lint1/emit1.c b/usr.bin/xlint/lint1/emit1.c
new file mode 100644
index 0000000..ee2434e
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit1.c
@@ -0,0 +1,587 @@
+/* $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "lint1.h"
+
+static void outtt __P((sym_t *, sym_t *));
+static void outfstrg __P((strg_t *));
+
+/*
+ * Write type into the output buffer.
+ * The type is written as a sequence of substrings, each of which describes a
+ * node of type type_t
+ * a node is coded as follows:
+ * char C
+ * signed char s C
+ * unsigned char u C
+ * short S
+ * unsigned short u S
+ * int I
+ * unsigned int u I
+ * long L
+ * unsigned long u L
+ * long long Q
+ * unsigned long long u Q
+ * float s D
+ * double D
+ * long double l D
+ * void V
+ * * P
+ * [n] A n
+ * () F
+ * (void) F 0
+ * (n arguments) F n arg1 arg2 ... argn
+ * (n arguments, ...) F n arg1 arg2 ... argn-1 E
+ * (a, b, c, ...) f n arg1 arg2 ...
+ * enum tag e T tag_or_typename
+ * struct tag s T tag_or_typename
+ * union tag u T tag_or_typename
+ *
+ * tag_or_typename 0 no tag or type name
+ * 1 n tag Tag
+ * 2 n typename only type name
+ *
+ * spaces are only for better readability
+ * additionaly it is possible to prepend the characters 'c' (for const)
+ * and 'v' (for volatile)
+ */
+void
+outtype(tp)
+ type_t *tp;
+{
+ int t, s, na;
+ sym_t *arg;
+ tspec_t ts;
+
+ while (tp != NULL) {
+ if ((ts = tp->t_tspec) == INT && tp->t_isenum)
+ ts = ENUM;
+ switch (ts) {
+ case CHAR: t = 'C'; s = '\0'; break;
+ case SCHAR: t = 'C'; s = 's'; break;
+ case UCHAR: t = 'C'; s = 'u'; break;
+ case SHORT: t = 'S'; s = '\0'; break;
+ case USHORT: t = 'S'; s = 'u'; break;
+ case INT: t = 'I'; s = '\0'; break;
+ case UINT: t = 'I'; s = 'u'; break;
+ case LONG: t = 'L'; s = '\0'; break;
+ case ULONG: t = 'L'; s = 'u'; break;
+ case QUAD: t = 'Q'; s = '\0'; break;
+ case UQUAD: t = 'Q'; s = 'u'; break;
+ case FLOAT: t = 'D'; s = 's'; break;
+ case DOUBLE: t = 'D'; s = '\0'; break;
+ case LDOUBLE: t = 'D'; s = 'l'; break;
+ case VOID: t = 'V'; s = '\0'; break;
+ case PTR: t = 'P'; s = '\0'; break;
+ case ARRAY: t = 'A'; s = '\0'; break;
+ case FUNC: t = 'F'; s = '\0'; break;
+ case ENUM: t = 'T'; s = 'e'; break;
+ case STRUCT: t = 'T'; s = 's'; break;
+ case UNION: t = 'T'; s = 'u'; break;
+ default:
+ lerror("outtyp() 1");
+ }
+ if (tp->t_const)
+ outchar('c');
+ if (tp->t_volatile)
+ outchar('v');
+ if (s != '\0')
+ outchar(s);
+ outchar(t);
+ if (ts == ARRAY) {
+ outint(tp->t_dim);
+ } else if (ts == ENUM) {
+ outtt(tp->t_enum->etag, tp->t_enum->etdef);
+ } else if (ts == STRUCT || ts == UNION) {
+ outtt(tp->t_str->stag, tp->t_str->stdef);
+ } else if (ts == FUNC && tp->t_proto) {
+ na = 0;
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ na++;
+ if (tp->t_vararg)
+ na++;
+ outint(na);
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ if (tp->t_vararg)
+ outchar('E');
+ }
+ tp = tp->t_subt;
+ }
+}
+
+/*
+ * type to string
+ * used for debugging output
+ *
+ * it uses its own output buffer for conversion
+ */
+const char *
+ttos(tp)
+ type_t *tp;
+{
+ static ob_t tob;
+ ob_t tmp;
+
+ if (tob.o_buf == NULL) {
+ tob.o_len = 64;
+ tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
+ tob.o_end = tob.o_buf + tob.o_len;
+ }
+
+ tmp = ob;
+ ob = tob;
+ ob.o_nxt = ob.o_buf;
+ outtype(tp);
+ outchar('\0');
+ tob = ob;
+ ob = tmp;
+
+ return (tob.o_buf);
+}
+
+/*
+ * write the name of a tag or typename
+ *
+ * if the tag is named, the name of the
+ * tag is written, otherwise, if a typename exists which
+ * refers to this tag, this typename is written
+ */
+static void
+outtt(tag, tdef)
+ sym_t *tag, *tdef;
+{
+ if (tag->s_name != unnamed) {
+ outint(1);
+ outname(tag->s_name);
+ } else if (tdef != NULL) {
+ outint(2);
+ outname(tdef->s_name);
+ } else {
+ outint(0);
+ }
+}
+
+/*
+ * write information about an global declared/defined symbol
+ * with storage class extern
+ *
+ * informations about function definitions are written in outfdef(),
+ * not here
+ */
+void
+outsym(sym, sc, def)
+ sym_t *sym;
+ scl_t sc;
+ def_t def;
+{
+ /*
+ * Static function declarations must also be written to the output
+ * file. Compatibility of function declarations (for both static
+ * and extern functions) must be checked in lint2. Lint1 can't do
+ * this, especially not, if functions are declared at block level
+ * before their first declaration at level 0.
+ */
+ if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
+ return;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source.
+ */
+ outint(csrc_pos.p_line);
+ outchar('d');
+ outint(getfnid(sym->s_dpos.p_file));
+ outchar('.');
+ outint(sym->s_dpos.p_line);
+
+ /* flags */
+
+ switch (def) {
+ case DEF:
+ /* defined */
+ outchar('d');
+ break;
+ case TDEF:
+ /* tentative defined */
+ outchar('t');
+ break;
+ case DECL:
+ /* declared */
+ outchar('e');
+ break;
+ default:
+ lerror("outsym() 2");
+ }
+ if (llibflg && def != DECL) {
+ /*
+ * mark it as used so we get no warnings from lint2 about
+ * unused symbols in libraries.
+ */
+ outchar('u');
+ }
+
+ if (sc == STATIC)
+ outchar('s');
+
+ /* name of the symbol */
+ outname(sym->s_name);
+
+ /* type of the symbol */
+ outtype(sym->s_type);
+}
+
+/*
+ * write information about function definition
+ *
+ * this is also done for static functions so we are able to check if
+ * they are called with proper argument types
+ */
+void
+outfdef(fsym, posp, rval, osdef, args)
+ sym_t *fsym, *args;
+ pos_t *posp;
+ int rval, osdef;
+{
+ int narg;
+ sym_t *arg;
+
+ /* reset the buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source
+ *
+ * we are already at the end of the function. If we are in the
+ * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
+ * (for functions defined in header files).
+ */
+ if (posp->p_file == csrc_pos.p_file) {
+ outint(posp->p_line);
+ } else {
+ outint(csrc_pos.p_line);
+ }
+ outchar('d');
+ outint(getfnid(posp->p_file));
+ outchar('.');
+ outint(posp->p_line);
+
+ /* flags */
+
+ /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
+ if (prflstrg != -1) {
+ nvararg = prflstrg;
+ } else if (scflstrg != -1) {
+ nvararg = scflstrg;
+ }
+
+ if (nvararg != -1) {
+ outchar('v');
+ outint(nvararg);
+ }
+ if (scflstrg != -1) {
+ outchar('S');
+ outint(scflstrg);
+ }
+ if (prflstrg != -1) {
+ outchar('P');
+ outint(prflstrg);
+ }
+ nvararg = prflstrg = scflstrg = -1;
+
+ outchar('d');
+
+ if (rval)
+ /* has return value */
+ outchar('r');
+
+ if (llibflg)
+ /*
+ * mark it as used so lint2 does not complain about
+ * unused symbols in libraries
+ */
+ outchar('u');
+
+ if (osdef)
+ /* old style function definition */
+ outchar('o');
+
+ if (fsym->s_scl == STATIC)
+ outchar('s');
+
+ /* name of function */
+ outname(fsym->s_name);
+
+ /* argument types and return value */
+ if (osdef) {
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ outchar('f');
+ outint(narg);
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ outtype(fsym->s_type->t_subt);
+ } else {
+ outtype(fsym->s_type);
+ }
+}
+
+/*
+ * write out all information necessary for lint2 to check function
+ * calls
+ *
+ * rvused is set if the return value is used (asigned to a variable)
+ * rvdisc is set if the return value is not used and not ignored
+ * (casted to void)
+ */
+void
+outcall(tn, rvused, rvdisc)
+ tnode_t *tn;
+ int rvused, rvdisc;
+{
+ tnode_t *args, *arg;
+ int narg, n, i;
+ quad_t q;
+ tspec_t t;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'c' for function call, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('c');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /*
+ * flags; 'u' and 'i' must be last to make sure a letter
+ * is between the numeric argument of a flag and the name of
+ * the function
+ */
+ narg = 0;
+ args = tn->tn_right;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+ /* informations about arguments */
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ arg = arg->tn_left;
+ if (arg->tn_op == CON) {
+ if (isityp(t = arg->tn_type->t_tspec)) {
+ /*
+ * XXX it would probably be better to
+ * explizitly test the sign
+ */
+ if ((q = arg->tn_val->v_quad) == 0) {
+ /* zero constant */
+ outchar('z');
+ } else if (msb(q, t, 0) == 0) {
+ /* positive if casted to signed */
+ outchar('p');
+ } else {
+ /* negative if casted to signed */
+ outchar('n');
+ }
+ outint(n);
+ }
+ } else if (arg->tn_op == AMPER &&
+ arg->tn_left->tn_op == STRING &&
+ arg->tn_left->tn_strg->st_tspec == CHAR) {
+ /* constant string, write all format specifiers */
+ outchar('s');
+ outint(n);
+ outfstrg(arg->tn_left->tn_strg);
+ }
+
+ }
+ /* return value discarded/used/ignored */
+ outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
+
+ /* name of the called function */
+ outname(tn->tn_left->tn_left->tn_sym->s_name);
+
+ /* types of arguments */
+ outchar('f');
+ outint(narg);
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ outtype(arg->tn_left->tn_type);
+ }
+ /* expected type of return value */
+ outtype(tn->tn_type);
+}
+
+/*
+ * extracts potential format specifiers for printf() and scanf() and
+ * writes them, enclosed in "" and qouted if necessary, to the output buffer
+ */
+static void
+outfstrg(strg)
+ strg_t *strg;
+{
+ int c, oc, first;
+ u_char *cp;
+
+ if (strg->st_tspec != CHAR)
+ lerror("outfstrg() 1");
+
+ cp = strg->st_cp;
+
+ outchar('"');
+
+ c = *cp++;
+
+ while (c != '\0') {
+
+ if (c != '%') {
+ c = *cp++;
+ continue;
+ }
+
+ outqchar('%');
+ c = *cp++;
+
+ /* flags for printf and scanf and *-fieldwidth for printf */
+ while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
+ c == '#' || c == '0' || c == '*')) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* numeric field width */
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* precision for printf */
+ if (c == '.') {
+ outqchar(c);
+ if ((c = *cp++) == '*') {
+ outqchar(c);
+ c = *cp++;
+ } else {
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ /* h, l, L and q flags fpr printf and scanf */
+ if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /*
+ * The last character. It is always written so we can detect
+ * invalid format specifiers.
+ */
+ if (c != '\0') {
+ outqchar(c);
+ oc = c;
+ c = *cp++;
+ /*
+ * handle [ for scanf. [-] means that a minus sign
+ * was found at an undefined position.
+ */
+ if (oc == '[') {
+ if (c == '^')
+ c = *cp++;
+ if (c == ']')
+ c = *cp++;
+ first = 1;
+ while (c != '\0' && c != ']') {
+ if (c == '-') {
+ if (!first && *cp != ']')
+ outqchar(c);
+ }
+ first = 0;
+ c = *cp++;
+ }
+ if (c == ']') {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ }
+
+ outchar('"');
+}
+
+/*
+ * writes a record if sym was used
+ */
+void
+outusg(sym)
+ sym_t *sym;
+{
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'u' for used, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('u');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /* necessary to delimit both numbers */
+ outchar('x');
+
+ /* Den Namen des Symbols ausgeben */
+ outname(sym->s_name);
+}
diff --git a/usr.bin/xlint/lint1/err.c b/usr.bin/xlint/lint1/err.c
new file mode 100644
index 0000000..c2be198
--- /dev/null
+++ b/usr.bin/xlint/lint1/err.c
@@ -0,0 +1,543 @@
+/* $NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo Exp $";
+#endif
+
+/* number of errors found */
+int nerr;
+
+/* number of syntax errors */
+int sytxerr;
+
+#include <stdlib.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "lint1.h"
+
+static const char *basename __P((const char *));
+static void verror __P((int, va_list));
+static void vwarning __P((int, va_list));
+
+
+const char *msgs[] = {
+ "syntax error: empty declaration", /* 0 */
+ "old style declaration; add int", /* 1 */
+ "empty declaration", /* 2 */
+ "%s declared in argument declaration list", /* 3 */
+ "illegal type combination", /* 4 */
+ "modifying typedef with '%s'; only qualifiers allowed", /* 5 */
+ "use 'double' instead of 'long float'", /* 6 */
+ "only one storage class allowed", /* 7 */
+ "illegal storage class", /* 8 */
+ "only register valid as formal parameter storage class", /* 9 */
+ "duplicate '%s'", /* 10 */
+ "bit-field initializer out of range", /* 11 */
+ "compiler takes size of function", /* 12 */
+ "incomplete enum type: %s", /* 13 */
+ "compiler takes alignment of function", /* 14 */
+ "function returns illegal type", /* 15 */
+ "array of function is illegal", /* 16 */
+ "null dimension", /* 17 */
+ "illegal use of 'void'", /* 18 */
+ "void type for %s", /* 19 */
+ "zero or negative array dimension", /* 20 */
+ "redeclaration of formal parameter %s", /* 21 */
+ "incomplete or misplaced function definition", /* 22 */
+ "undefined label %s", /* 23 */
+ "cannot initialize function: %s", /* 24 */
+ "cannot initialize typedef: %s", /* 25 */
+ "cannot initialize extern declaration: %s", /* 26 */
+ "redeclaration of %s", /* 27 */
+ "redefinition of %s", /* 28 */
+ "previously declared extern, becomes static: %s", /* 29 */
+ "redeclaration of %s; ANSI C requires static", /* 30 */
+ "incomplete structure or union %s: %s", /* 31 */
+ "argument type defaults to 'int': %s", /* 32 */
+ "duplicate member name: %s", /* 33 */
+ "nonportable bit-field type", /* 34 */
+ "illegal bit-field type", /* 35 */
+ "illegal bit-field size", /* 36 */
+ "zero size bit-field", /* 37 */
+ "function illegal in structure or union", /* 38 */
+ "illegal zero sized structure member: %s", /* 39 */
+ "unknown size: %s", /* 40 */
+ "illegal use of bit-field", /* 41 */
+ "forward reference to enum type", /* 42 */
+ "redefinition hides earlier one: %s", /* 43 */
+ "declaration introduces new type in ANSI C: %s %s", /* 44 */
+ "base type is really '%s %s'", /* 45 */
+ "(%s) tag redeclared", /* 46 */
+ "zero sized %s", /* 47 */
+ "overflow in enumeration values: %s", /* 48 */
+ "struct or union member must be named", /* 49 */
+ "a function is declared as an argument: %s", /* 50 */
+ "parameter mismatch: %d declared, %d defined", /* 51 */
+ "cannot initialize parameter: %s", /* 52 */
+ "declared argument %s is missing", /* 53 */
+ "trailing ',' prohibited in enum declaration", /* 54 */
+ "integral constant expression expected", /* 55 */
+ "integral constant too large", /* 56 */
+ "enumeration constant hides parameter: %s", /* 57 */
+ "type does not match prototype: %s", /* 58 */
+ "formal parameter lacks name: param #%d", /* 59 */
+ "void must be sole parameter", /* 60 */
+ "void parameter cannot have name: %s", /* 61 */
+ "function prototype parameters must have types", /* 62 */
+ "prototype does not match old-style definition", /* 63 */
+ "()-less function definition", /* 64 */
+ "%s has no named members", /* 65 */
+ "syntax requires ';' after last struct/union member", /* 66 */
+ "cannot return incomplete type", /* 67 */
+ "typedef already qualified with '%s'", /* 68 */
+ "inappropriate qualifiers with 'void'", /* 69 */
+ "%soperand of '%s' is unsigned in ANSI C", /* 70 */
+ "too many characters in character constant", /* 71 */
+ "typedef declares no type name", /* 72 */
+ "empty character constant", /* 73 */
+ "no hex digits follow \\x", /* 74 */
+ "overflow in hex escape", /* 75 */
+ "character escape does not fit in character", /* 76 */
+ "bad octal digit %c", /* 77 */
+ "nonportable character escape", /* 78 */
+ "dubious escape \\%c", /* 79 */
+ "dubious escape \\%o", /* 80 */
+ "\\a undefined in traditional C", /* 81 */
+ "\\x undefined in traditional C", /* 82 */
+ "storage class after type is obsolescent", /* 83 */
+ "ANSI C requires formal parameter before '...'", /* 84 */
+ "dubious tag declaration: %s %s", /* 85 */
+ "automatic hides external declaration: %s", /* 86 */
+ "static hides external declaration: %s", /* 87 */
+ "typedef hides external declaration: %s", /* 88 */
+ "typedef redeclared: %s", /* 89 */
+ "inconsistent redeclaration of extern: %s", /* 90 */
+ "declaration hides parameter: %s", /* 91 */
+ "inconsistent redeclaration of static: %s", /* 92 */
+ "dubious static function at block level: %s", /* 93 */
+ "function has illegal storage class: %s", /* 94 */
+ "declaration hides earlier one: %s", /* 95 */
+ "cannot dereference non-pointer type", /* 96 */
+ "suffix U is illegal in traditional C", /* 97 */
+ "suffixes F and L are illegal in traditional C", /* 98 */
+ "%s undefined", /* 99 */
+ "unary + is illegal in traditional C", /* 100 */
+ "undefined struct/union member: %s", /* 101 */
+ "illegal member use: %s", /* 102 */
+ "left operand of '.' must be struct/union object", /* 103 */
+ "left operand of '->' must be pointer to struct/union", /* 104 */
+ "non-unique member requires struct/union %s", /* 105 */
+ "left operand of '->' must be pointer", /* 106 */
+ "operands of '%s' have incompatible types", /* 107 */
+ "operand of '%s' has incompatible type", /* 108 */
+ "void type illegal in expression", /* 109 */
+ "pointer to function is not allowed here", /* 110 */
+ "unacceptable operand of '%s'", /* 111 */
+ "cannot take address of bit-field", /* 112 */
+ "cannot take address of register %s", /* 113 */
+ "%soperand of '%s' must be lvalue", /* 114 */
+ "%soperand of '%s' must be modifiable lvalue", /* 115 */
+ "illegal pointer subtraction", /* 116 */
+ "bitwise operation on signed value possibly nonportable", /* 117 */
+ "semantics of '%s' change in ANSI C; use explicit cast", /* 118 */
+ "conversion of '%s' to '%s' is out of range", /* 119 */
+ "bitwise operation on signed value nonportable", /* 120 */
+ "negative shift", /* 121 */
+ "shift greater than size of object", /* 122 */
+ "illegal combination of pointer and integer, op %s", /* 123 */
+ "illegal pointer combination, op %s", /* 124 */
+ "ANSI C forbids ordered comparisons of pointers to functions",/* 125 */
+ "incompatible types in conditional", /* 126 */
+ "'&' before array or function: ignored", /* 127 */
+ "operands have incompatible pointer types, op %s", /* 128 */
+ "expression has null effect", /* 129 */
+ "enum type mismatch, op %s", /* 130 */
+ "conversion to '%s' may sign-extend incorrectly", /* 131 */
+ "conversion from '%s' may lose accuracy", /* 132 */
+ "conversion of pointer to '%s' loses bits", /* 133 */
+ "conversion of pointer to '%s' may lose bits", /* 134 */
+ "possible pointer alignment problem", /* 135 */
+ "cannot do pointer arithmetic on operand of unknown size", /* 136 */
+ "use of incomplete enum type, op %s", /* 137 */
+ "unknown operand size, op %s", /* 138 */
+ "division by 0", /* 139 */
+ "modulus by 0", /* 140 */
+ "integer overflow detected, op %s", /* 141 */
+ "floating point overflow detected, op %s", /* 142 */
+ "cannot take size of incomplete type", /* 143 */
+ "cannot take size of function", /* 144 */
+ "cannot take size of bit-field", /* 145 */
+ "cannot take size of void", /* 146 */
+ "invalid cast expression", /* 147 */
+ "improper cast of void expression", /* 148 */
+ "illegal function", /* 149 */
+ "argument mismatch: %d arg%s passed, %d expected", /* 150 */
+ "void expressions may not be arguments, arg #%d", /* 151 */
+ "argument cannot have unknown size, arg #%d", /* 152 */
+ "argument has incompatible pointer type, arg #%d", /* 153 */
+ "illegal combination of pointer and integer, arg #%d", /* 154 */
+ "argument is incompatible with prototype, arg #%d", /* 155 */
+ "enum type mismatch, arg #%d", /* 156 */
+ "ANSI C treats constant as unsigned", /* 157 */
+ "%s may be used before set", /* 158 */
+ "assignment in conditional context", /* 159 */
+ "operator '==' found where '=' was expected", /* 160 */
+ "constant in conditional context", /* 161 */
+ "comparision of %s with %s, op %s", /* 162 */
+ "a cast does not yield an lvalue", /* 163 */
+ "assignment of negative constant to unsigned type", /* 164 */
+ "constant truncated by assignment", /* 165 */
+ "precision lost in bit-field assignment", /* 166 */
+ "array subscript cannot be negative: %ld", /* 167 */
+ "array subscript cannot be > %d: %ld", /* 168 */
+ "precedence confusion possible: parenthesize!", /* 169 */
+ "first operand must have scalar type, op ? :", /* 170 */
+ "assignment type mismatch", /* 171 */
+ "too many struct/union initializers", /* 172 */
+ "too many array initializers", /* 173 */
+ "too many initializers", /* 174 */
+ "initialisation of an incomplete type", /* 175 */
+ "invalid initializer", /* 176 */
+ "non-constant initializer", /* 177 */
+ "initializer does not fit", /* 178 */
+ "cannot initialize struct/union with no named member", /* 179 */
+ "bit-field initializer does not fit", /* 180 */
+ "{}-enclosed initializer required", /* 181 */
+ "incompatible pointer types", /* 182 */
+ "illegal combination of pointer and integer", /* 183 */
+ "illegal pointer combination", /* 184 */
+ "initialisation type mismatch", /* 185 */
+ "bit-field initialisation is illegal in traditional C", /* 186 */
+ "non-null byte ignored in string initializer", /* 187 */
+ "no automatic aggregate initialization in traditional C", /* 188 */
+ "assignment of struct/union illegal in traditional C", /* 189 */
+ "empty array declaration: %s", /* 190 */
+ "%s set but not used in function %s", /* 191 */
+ "%s unused in function %s", /* 192 */
+ "statement not reached", /* 193 */
+ "label %s redefined", /* 194 */
+ "case not in switch", /* 195 */
+ "case label affected by conversion", /* 196 */
+ "non-constant case expression", /* 197 */
+ "non-integral case expression", /* 198 */
+ "duplicate case in switch: %ld", /* 199 */
+ "duplicate case in switch: %lu", /* 200 */
+ "default outside switch", /* 201 */
+ "duplicate default in switch", /* 202 */
+ "case label must be of type `int' in traditional C", /* 203 */
+ "controlling expressions must have scalar type", /* 204 */
+ "switch expression must have integral type", /* 205 */
+ "enumeration value(s) not handled in switch", /* 206 */
+ "loop not entered at top", /* 207 */
+ "break outside loop or switch", /* 208 */
+ "continue outside loop", /* 209 */
+ "enum type mismatch in initialisation", /* 210 */
+ "return value type mismatch", /* 211 */
+ "cannot return incomplete type", /* 212 */
+ "void function %s cannot return value", /* 213 */
+ "function %s expects to return value", /* 214 */
+ "function implicitly declared to return int", /* 215 */
+ "function %s has return (e); and return;", /* 216 */
+ "function %s falls off bottom without returning value", /* 217 */
+ "ANSI C treats constant as unsigned, op %s", /* 218 */
+ "concatenated strings are illegal in traditional C", /* 219 */
+ "fallthrough on case statement", /* 220 */
+ "initialisation of unsigned with negative constant", /* 221 */
+ "conversion of negative constant to unsigned type", /* 222 */
+ "end-of-loop code not reached", /* 223 */
+ "cannot recover from previous errors", /* 224 */
+ "static function called but not defined: %s()", /* 225 */
+ "static variable %s unused", /* 226 */
+ "const object %s should have initializer", /* 227 */
+ "function cannot return const or volatile object", /* 228 */
+ "questionable conversion of function pointer", /* 229 */
+ "nonportable character comparision, op %s", /* 230 */
+ "argument %s unused in function %s", /* 231 */
+ "label %s unused in function %s", /* 232 */
+ "struct %s never defined", /* 233 */
+ "union %s never defined", /* 234 */
+ "enum %s never defined", /* 235 */
+ "static function %s unused", /* 236 */
+ "redeclaration of formal parameter %s", /* 237 */
+ "initialisation of union is illegal in traditional C", /* 238 */
+ "constant argument to NOT", /* 239 */
+ "assignment of different structures", /* 240 */
+ "dubious operation on enum, op %s", /* 241 */
+ "combination of '%s' and '%s', op %s", /* 242 */
+ "dubious comparision of enums, op %s", /* 243 */
+ "illegal structure pointer combination", /* 244 */
+ "illegal structure pointer combination, op %s", /* 245 */
+ "dubious conversion of enum to '%s'", /* 246 */
+ "pointer casts may be troublesome", /* 247 */
+ "floating-point constant out of range", /* 248 */
+ "syntax error", /* 249 */
+ "unknown character \\%o", /* 250 */
+ "malformed integer constant", /* 251 */
+ "integer constant out of range", /* 252 */
+ "unterminated character constant", /* 253 */
+ "newline in string or char constant", /* 254 */
+ "undefined or invalid # directive", /* 255 */
+ "unterminated comment", /* 256 */
+ "extra characters in lint comment", /* 257 */
+ "unterminated string constant", /* 258 */
+ "conversion to '%s' due to prototype, arg #%d", /* 259 */
+ "previous declaration of %s", /* 260 */
+ "previous definition of %s", /* 261 */
+ "\\\" inside character constants undefined in traditional C", /* 262 */
+ "\\? undefined in traditional C", /* 263 */
+ "\\v undefined in traditional C", /* 264 */
+ "%s C does not support 'long long'", /* 265 */
+ "'long double' is illegal in traditional C", /* 266 */
+ "shift equal to size of object", /* 267 */
+ "variable declared inline: %s", /* 268 */
+ "argument declared inline: %s", /* 269 */
+ "function prototypes are illegal in traditional C", /* 270 */
+ "switch expression must be of type `int' in traditional C", /* 271 */
+ "empty translation unit", /* 272 */
+ "bit-field type '%s' invalid in ANSI C", /* 273 */
+ "ANSI C forbids comparision of %s with %s", /* 274 */
+ "cast discards 'const' from pointer target type", /* 275 */
+ "", /* 276 */
+ "initialisation of '%s' with '%s'", /* 277 */
+ "combination of '%s' and '%s', arg #%d", /* 278 */
+ "combination of '%s' and '%s' in return", /* 279 */
+ "must be outside function: /* %s */", /* 280 */
+ "duplicate use of /* %s */", /* 281 */
+ "must precede function definition: /* %s */", /* 282 */
+ "argument number mismatch with directive: /* %s */", /* 283 */
+ "fallthrough on default statement", /* 284 */
+ "prototype declaration", /* 285 */
+ "function definition is not a prototype", /* 286 */
+ "function declaration is not a prototype", /* 287 */
+ "dubious use of /* VARARGS */ with /* %s */", /* 288 */
+ "can't be used together: /* PRINTFLIKE */ /* SCANFLIKE */", /* 289 */
+ "static function %s declared but not defined", /* 290 */
+ "invalid multibyte character", /* 291 */
+ "cannot concatenate wide and regular string literals", /* 292 */
+ "argument %d must be 'char *' for PRINTFLIKE/SCANFLIKE", /* 293 */
+ "multi-character character constant", /* 294 */
+ "conversion of '%s' to '%s' is out of range, arg #%d", /* 295 */
+ "conversion of negative constant to unsigned type, arg #%d", /* 296 */
+ "conversion to '%s' may sign-extend incorrectly, arg #%d", /* 297 */
+ "conversion from '%s' may lose accuracy, arg #%d", /* 298 */
+ "prototype does not match old style definition, arg #%d", /* 299 */
+ "old style definition", /* 300 */
+ "array of incomplete type", /* 301 */
+ "%s returns pointer to automatic object", /* 302 */
+ "ANSI C forbids conversion of %s to %s", /* 303 */
+ "ANSI C forbids conversion of %s to %s, arg #%d", /* 304 */
+ "ANSI C forbids conversion of %s to %s, op %s", /* 305 */
+ "constant truncated by conversion, op %s", /* 306 */
+ "static variable %s set but not used", /* 307 */
+ "", /* 308 */
+ "extra bits set to 0 in conversion of '%s' to '%s', op %s", /* 309 */
+};
+
+/*
+ * If Fflag is not set basename() returns a pointer to the last
+ * component of the path, otherwise it returns the argument.
+ */
+static const char *
+basename(path)
+ const char *path;
+{
+ const char *cp, *cp1, *cp2;
+
+ if (Fflag)
+ return (path);
+
+ cp = cp1 = cp2 = path;
+ while (*cp != '\0') {
+ if (*cp++ == '/') {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+static void
+verror(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s:%d: ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ nerr++;
+}
+
+static void
+vwarning(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ if (nowarn)
+ /* this warning is suppressed by a LINTED comment */
+ return;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s:%d: warning: ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+}
+
+void
+#ifdef __STDC__
+error(int n, ...)
+#else
+error(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ verror(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+lerror(const char *msg, ...)
+#else
+lerror(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)fprintf(stderr, "%s:%d: lint error: ", fn, curr_pos.p_line);
+ (void)vfprintf(stderr, msg, ap);
+ (void)fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
+void
+#ifdef __STDC__
+warning(int n, ...)
+#else
+warning(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ vwarning(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+message(int n, ...)
+#else
+message(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s:%d: ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ va_end(ap);
+}
+
+int
+#ifdef __STDC__
+gnuism(int n, ...)
+#else
+gnuism(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ int msg;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ if (sflag && !gflag) {
+ verror(n, ap);
+ msg = 1;
+ } else if (!sflag && gflag) {
+ msg = 0;
+ } else {
+ vwarning(n, ap);
+ msg = 1;
+ }
+ va_end(ap);
+
+ return (msg);
+}
diff --git a/usr.bin/xlint/lint1/externs.h b/usr.bin/xlint/lint1/externs.h
new file mode 100644
index 0000000..e61f8d0
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs.h
@@ -0,0 +1,56 @@
+/* $NetBSD: externs.h,v 1.2 1995/07/03 21:24:06 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * mem.c
+ */
+extern void *xmalloc __P((size_t));
+extern void *xcalloc __P((size_t, size_t));
+extern void *xrealloc __P((void *, size_t));
+extern char *xstrdup __P((const char *));
+extern void nomem __P((void));
+
+/*
+ * emit.c
+ */
+extern ob_t ob;
+
+extern void outopen __P((const char *));
+extern void outclose __P((void));
+extern void outclr __P((void));
+extern void outchar __P((int));
+extern void outqchar __P((int));
+extern void outstrg __P((const char *));
+extern void outint __P((int));
+extern void outname __P((const char *));
+extern void outsrc __P((const char *));
diff --git a/usr.bin/xlint/lint1/externs1.h b/usr.bin/xlint/lint1/externs1.h
new file mode 100644
index 0000000..e9923c7
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs1.h
@@ -0,0 +1,281 @@
+/* $NetBSD: externs1.h,v 1.7 1995/10/02 17:31:39 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * main.c
+ */
+extern int aflag;
+extern int bflag;
+extern int cflag;
+extern int dflag;
+extern int eflag;
+extern int Fflag;
+extern int gflag;
+extern int hflag;
+extern int pflag;
+extern int rflag;
+extern int sflag;
+extern int tflag;
+extern int uflag;
+extern int vflag;
+extern int yflag;
+extern int zflag;
+
+extern void norecover __P((void));
+
+/*
+ * cgram.y
+ */
+extern int blklev;
+extern int mblklev;
+extern int yydebug;
+
+extern int yyerror __P((char *));
+extern int yyparse __P((void));
+
+/*
+ * scan.l
+ */
+extern pos_t curr_pos;
+extern pos_t csrc_pos;
+extern symt_t symtyp;
+extern FILE *yyin;
+extern u_quad_t qbmasks[], qlmasks[], qumasks[];
+
+extern void initscan __P((void));
+extern int sign __P((quad_t, tspec_t, int));
+extern int msb __P((quad_t, tspec_t, int));
+extern quad_t xsign __P((quad_t, tspec_t, int));
+extern void clrwflgs __P((void));
+extern sym_t *getsym __P((sbuf_t *));
+extern void cleanup __P((void));
+extern sym_t *pushdown __P((sym_t *));
+extern void rmsym __P((sym_t *));
+extern void rmsyms __P((sym_t *));
+extern void inssym __P((int, sym_t *));
+extern void freeyyv __P((void *, int));
+extern int yylex __P((void));
+
+/*
+ * mem1.c
+ */
+extern const char *fnalloc __P((const char *));
+extern const char *fnnalloc __P((const char *, size_t));
+extern int getfnid __P((const char *));
+
+extern void initmem __P((void));
+
+extern void *getblk __P((size_t));
+extern void *getlblk __P((int, size_t));
+extern void freeblk __P((void));
+extern void freelblk __P((int));
+
+extern void *tgetblk __P((size_t));
+extern tnode_t *getnode __P((void));
+extern void tfreeblk __P((void));
+extern struct mbl *tsave __P((void));
+extern void trestor __P((struct mbl *));
+
+/*
+ * err.c
+ */
+extern int nerr;
+extern int sytxerr;
+extern const char *msgs[];
+
+extern void error __P((int, ...));
+extern void warning __P((int, ...));
+extern void message __P((int, ...));
+extern int gnuism __P((int, ...));
+extern void lerror __P((const char *, ...));
+
+/*
+ * decl.c
+ */
+extern dinfo_t *dcs;
+extern const char *unnamed;
+extern int enumval;
+
+extern void initdecl __P((void));
+extern type_t *gettyp __P((tspec_t));
+extern type_t *duptyp __P((const type_t *));
+extern type_t *tduptyp __P((const type_t *));
+extern int incompl __P((type_t *));
+extern void setcompl __P((type_t *, int));
+extern void addscl __P((scl_t));
+extern void addtype __P((type_t *));
+extern void addqual __P((tqual_t));
+extern void pushdecl __P((scl_t));
+extern void popdecl __P((void));
+extern void setasm __P((void));
+extern void clrtyp __P((void));
+extern void deftyp __P((void));
+extern int length __P((type_t *, const char *));
+extern int getbound __P((type_t *));
+extern sym_t *lnklst __P((sym_t *, sym_t *));
+extern void chktyp __P((sym_t *));
+extern sym_t *decl1str __P((sym_t *));
+extern sym_t *bitfield __P((sym_t *, int));
+extern pqinf_t *mergepq __P((pqinf_t *, pqinf_t *));
+extern sym_t *addptr __P((sym_t *, pqinf_t *));
+extern sym_t *addarray __P((sym_t *, int, int));
+extern sym_t *addfunc __P((sym_t *, sym_t *));
+extern void chkfdef __P((sym_t *, int));
+extern sym_t *dname __P((sym_t *));
+extern sym_t *iname __P((sym_t *));
+extern type_t *mktag __P((sym_t *, tspec_t, int, int));
+extern const char *scltoa __P((scl_t));
+extern type_t *compltag __P((type_t *, sym_t *));
+extern sym_t *ename __P((sym_t *, int, int));
+extern void decl1ext __P((sym_t *, int));
+extern void cpuinfo __P((sym_t *, sym_t *));
+extern int isredec __P((sym_t *, int *));
+extern int eqtype __P((type_t *, type_t *, int, int, int *));
+extern void compltyp __P((sym_t *, sym_t *));
+extern sym_t *decl1arg __P((sym_t *, int));
+extern void cluparg __P((void));
+extern void decl1loc __P((sym_t *, int));
+extern sym_t *aname __P((void));
+extern void globclup __P((void));
+extern sym_t *decl1abs __P((sym_t *));
+extern void chksz __P((sym_t *));
+extern void setsflg __P((sym_t *));
+extern void setuflg __P((sym_t *, int, int));
+extern void chkusage __P((dinfo_t *));
+extern void chkusg1 __P((int, sym_t *));
+extern void chkglsyms __P((void));
+extern void prevdecl __P((int, sym_t *));
+
+/*
+ * tree.c
+ */
+extern void initmtab __P((void));
+extern type_t *incref __P((type_t *, tspec_t));
+extern type_t *tincref __P((type_t *, tspec_t));
+extern tnode_t *getcnode __P((type_t *, val_t *));
+extern tnode_t *getnnode __P((sym_t *, int));
+extern tnode_t *getsnode __P((strg_t *));
+extern sym_t *strmemb __P((tnode_t *, op_t, sym_t *));
+extern tnode_t *build __P((op_t, tnode_t *, tnode_t *));
+extern tnode_t *cconv __P((tnode_t *));
+extern int typeok __P((op_t, int, tnode_t *, tnode_t *));
+extern tnode_t *promote __P((op_t, int, tnode_t *));
+extern tnode_t *convert __P((op_t, int, type_t *, tnode_t *));
+extern void cvtcon __P((op_t, int, type_t *, val_t *, val_t *));
+extern const char *tyname __P((type_t *));
+extern tnode_t *bldszof __P((type_t *));
+extern tnode_t *cast __P((tnode_t *, type_t *));
+extern tnode_t *funcarg __P((tnode_t *, tnode_t *));
+extern tnode_t *funccall __P((tnode_t *, tnode_t *));
+extern val_t *constant __P((tnode_t *));
+extern void expr __P((tnode_t *, int, int));
+extern void chkmisc __P((tnode_t *, int, int, int, int, int, int));
+extern int conaddr __P((tnode_t *, sym_t **, ptrdiff_t *));
+extern strg_t *catstrg __P((strg_t *, strg_t *));
+
+/*
+ * func.c
+ */
+extern sym_t *funcsym;
+extern int reached;
+extern int rchflg;
+extern int ftflg;
+extern int nargusg;
+extern pos_t aupos;
+extern int nvararg;
+extern pos_t vapos;
+extern int prflstrg;
+extern pos_t prflpos;
+extern int scflstrg;
+extern pos_t scflpos;
+extern int ccflg;
+extern int llibflg;
+extern int nowarn;
+extern int plibflg;
+extern int quadflg;
+
+extern void pushctrl __P((int));
+extern void popctrl __P((int));
+extern void chkreach __P((void));
+extern void funcdef __P((sym_t *));
+extern void funcend __P((void));
+extern void label __P((int, sym_t *, tnode_t *));
+extern void if1 __P((tnode_t *));
+extern void if2 __P((void));
+extern void if3 __P((int));
+extern void switch1 __P((tnode_t *));
+extern void switch2 __P((void));
+extern void while1 __P((tnode_t *));
+extern void while2 __P((void));
+extern void do1 __P((void));
+extern void do2 __P((tnode_t *));
+extern void for1 __P((tnode_t *, tnode_t *, tnode_t *));
+extern void for2 __P((void));
+extern void dogoto __P((sym_t *));
+extern void docont __P((void));
+extern void dobreak __P((void));
+extern void doreturn __P((tnode_t *));
+extern void glclup __P((int));
+extern void argsused __P((int));
+extern void constcond __P((int));
+extern void fallthru __P((int));
+extern void notreach __P((int));
+extern void lintlib __P((int));
+extern void linted __P((int));
+extern void varargs __P((int));
+extern void printflike __P((int));
+extern void scanflike __P((int));
+extern void protolib __P((int));
+extern void longlong __P((int));
+
+/*
+ * init.c
+ */
+extern int initerr;
+extern sym_t *initsym;
+extern int startinit;
+
+extern void prepinit __P((void));
+extern void initrbr __P((void));
+extern void initlbr __P((void));
+extern void mkinit __P((tnode_t *));
+
+/*
+ * emit.c
+ */
+extern void outtype __P((type_t *));
+extern const char *ttos __P((type_t *));
+extern void outsym __P((sym_t *, scl_t, def_t));
+extern void outfdef __P((sym_t *, pos_t *, int, int, sym_t *));
+extern void outcall __P((tnode_t *, int, int));
+extern void outusg __P((sym_t *));
diff --git a/usr.bin/xlint/lint1/func.c b/usr.bin/xlint/lint1/func.c
new file mode 100644
index 0000000..5d3a172
--- /dev/null
+++ b/usr.bin/xlint/lint1/func.c
@@ -0,0 +1,1261 @@
+/* $NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/*
+ * Contains a pointer to the symbol table entry of the current function
+ * definition.
+ */
+sym_t *funcsym;
+
+/* Is set as long as a statement can be reached. Must be set at level 0. */
+int reached = 1;
+
+/*
+ * Is set as long as NOTREACHED is in effect.
+ * Is reset everywhere where reached can become 0.
+ */
+int rchflg;
+
+/*
+ * In conjunction with reached ontrols printing of "fallthrough on ..."
+ * warnings.
+ * Reset by each statement and set by FALLTHROUGH, switch (switch1())
+ * and case (label()).
+ *
+ * Control statements if, for, while and switch do not reset ftflg because
+ * this must be done by the controled statement. At least for if this is
+ * important because ** FALLTHROUGH ** after "if (expr) stmnt" is evaluated
+ * befor the following token, wich causes reduction of above, is read.
+ * This means that ** FALLTHROUGH ** after "if ..." would always be ignored.
+ */
+int ftflg;
+
+/* Top element of stack for control statements */
+cstk_t *cstk;
+
+/*
+ * Number of arguments which will be checked for usage in following
+ * function definition. -1 stands for all arguments.
+ *
+ * The position of the last ARGSUSED comment is stored in aupos.
+ */
+int nargusg = -1;
+pos_t aupos;
+
+/*
+ * Number of arguments of the following function definition whose types
+ * shall be checked by lint2. -1 stands for all arguments.
+ *
+ * The position of the last VARARGS comment is stored in vapos.
+ */
+int nvararg = -1;
+pos_t vapos;
+
+/*
+ * Both prflstr and scflstrg contain the number of the argument which
+ * shall be used to check the types of remaining arguments (for PRINTFLIKE
+ * and SCANFLIKE).
+ *
+ * prflpos and scflpos are the positions of the last PRINTFLIKE or
+ * SCANFLIKE comment.
+ */
+int prflstrg = -1;
+int scflstrg = -1;
+pos_t prflpos;
+pos_t scflpos;
+
+/*
+ * Are both plibflg and llibflg set, prototypes are writen as function
+ * definitions to the output file.
+ */
+int plibflg;
+
+/*
+ * Nonzero means that no warnings about constands in conditional
+ * context are printed.
+ */
+int ccflg;
+
+/*
+ * llibflg is set if a lint library shall be created. The effect of
+ * llibflg is that all defined symbols are treated as used.
+ * (The LINTLIBRARY comment also resets vflag.)
+ */
+int llibflg;
+
+/*
+ * Nonzero if warnings are suppressed by a LINTED directive
+ */
+int nowarn;
+
+/*
+ * Nonzero if complaints about use of "long long" are suppressed in
+ * the next statement or declaration.
+ */
+int quadflg;
+
+/*
+ * Puts a new element at the top of the stack used for control statements.
+ */
+void
+pushctrl(env)
+ int env;
+{
+ cstk_t *ci;
+
+ ci = xcalloc(1, sizeof (cstk_t));
+ ci->c_env = env;
+ ci->c_nxt = cstk;
+ cstk = ci;
+}
+
+/*
+ * Removes the top element of the stack used for control statements.
+ */
+void
+popctrl(env)
+ int env;
+{
+ cstk_t *ci;
+ clst_t *cl;
+
+ if (cstk == NULL || cstk->c_env != env)
+ lerror("popctrl() 1");
+
+ cstk = (ci = cstk)->c_nxt;
+
+ while ((cl = ci->c_clst) != NULL) {
+ ci->c_clst = cl->cl_nxt;
+ free(cl);
+ }
+
+ if (ci->c_swtype != NULL)
+ free(ci->c_swtype);
+
+ free(ci);
+}
+
+/*
+ * Prints a warning if a statement cannot be reached.
+ */
+void
+chkreach()
+{
+ if (!reached && !rchflg) {
+ /* statement not reached */
+ warning(193);
+ reached = 1;
+ }
+}
+
+/*
+ * Called after a function declaration which introduces a function definition
+ * and before an (optional) old style argument declaration list.
+ *
+ * Puts all symbols declared in the Prototype or in an old style argument
+ * list back to the symbol table.
+ *
+ * Does the usual checking of storage class, type (return value),
+ * redeclaration etc..
+ */
+void
+funcdef(fsym)
+ sym_t *fsym;
+{
+ int n, warn;
+ sym_t *arg, *sym, *rdsym;
+
+ funcsym = fsym;
+
+ /*
+ * Put all symbols declared in the argument list back to the
+ * symbol table.
+ */
+ for (sym = dcs->d_fpsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if (sym->s_blklev != 1)
+ lerror("funcdef() 1");
+ inssym(1, sym);
+ }
+ }
+
+ /*
+ * In osfunc() we did not know whether it is an old style function
+ * definition or only an old style declaration, if there are no
+ * arguments inside the argument list ("f()").
+ */
+ if (!fsym->s_type->t_proto && fsym->s_args == NULL)
+ fsym->s_osdef = 1;
+
+ chktyp(fsym);
+
+ /*
+ * chktyp() checks for almost all possible errors, but not for
+ * incomplete return values (these are allowed in declarations)
+ */
+ if (fsym->s_type->t_subt->t_tspec != VOID &&
+ incompl(fsym->s_type->t_subt)) {
+ /* cannot return incomplete type */
+ error(67);
+ }
+
+ fsym->s_def = DEF;
+
+ if (fsym->s_scl == TYPEDEF) {
+ fsym->s_scl = EXTERN;
+ /* illegal storage class */
+ error(8);
+ }
+
+ if (dcs->d_inline)
+ fsym->s_inline = 1;
+
+ /*
+ * Arguments in new style function declarations need a name.
+ * (void is already removed from the list of arguments)
+ */
+ n = 1;
+ for (arg = fsym->s_type->t_args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_scl == ABSTRACT) {
+ if (arg->s_name != unnamed)
+ lerror("funcdef() 2");
+ /* formal parameter lacks name: param #%d */
+ error(59, n);
+ } else {
+ if (arg->s_name == unnamed)
+ lerror("funcdef() 3");
+ }
+ n++;
+ }
+
+ /*
+ * We must also remember the position. s_dpos is overwritten
+ * if this is an old style definition and we had already a
+ * prototype.
+ */
+ STRUCT_ASSIGN(dcs->d_fdpos, fsym->s_dpos);
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ if (!isredec(fsym, (warn = 0, &warn))) {
+
+ /*
+ * Print nothing if the newly defined function
+ * is defined in old style. A better warning will
+ * be printed in cluparg().
+ */
+ if (warn && !fsym->s_osdef) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, fsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /* copy usage information */
+ cpuinfo(fsym, rdsym);
+
+ /*
+ * If the old symbol was a prototype and the new
+ * one is none, overtake the position of the
+ * declaration of the prototype.
+ */
+ if (fsym->s_osdef && rdsym->s_type->t_proto)
+ STRUCT_ASSIGN(fsym->s_dpos, rdsym->s_dpos);
+
+ /* complete the type */
+ compltyp(fsym, rdsym);
+
+ /* once a function is inline it remains inline */
+ if (rdsym->s_inline)
+ fsym->s_inline = 1;
+
+ }
+
+ /* remove the old symbol from the symbol table */
+ rmsym(rdsym);
+
+ }
+
+ if (fsym->s_osdef && !fsym->s_type->t_proto) {
+ if (sflag && hflag && strcmp(fsym->s_name, "main") != 0)
+ /* function definition is not a prototyp */
+ warning(286);
+ }
+
+ if (dcs->d_notyp)
+ /* return value is implizitly declared to be int */
+ fsym->s_rimpl = 1;
+
+ reached = 1;
+}
+
+/*
+ * Called at the end of a function definition.
+ */
+void
+funcend()
+{
+ sym_t *arg;
+ int n;
+
+ if (reached) {
+ cstk->c_noretval = 1;
+ if (funcsym->s_type->t_subt->t_tspec != VOID &&
+ !funcsym->s_rimpl) {
+ /* func. %s falls off bottom without returning value */
+ warning(217, funcsym->s_name);
+ }
+ }
+
+ /*
+ * This warning is printed only if the return value was implizitly
+ * declared to be int. Otherwise the wrong return statement
+ * has already printed a warning.
+ */
+ if (cstk->c_noretval && cstk->c_retval && funcsym->s_rimpl)
+ /* function %s has return (e); and return; */
+ warning(216, funcsym->s_name);
+
+ /* Print warnings for unused arguments */
+ arg = dcs->d_fargs;
+ n = 0;
+ while (arg != NULL && (nargusg == -1 || n < nargusg)) {
+ chkusg1(dcs->d_asm, arg);
+ arg = arg->s_nxt;
+ n++;
+ }
+ nargusg = -1;
+
+ /*
+ * write the information about the function definition to the
+ * output file
+ * inline functions explicitely declared extern are written as
+ * declarations only.
+ */
+ if (dcs->d_scl == EXTERN && funcsym->s_inline) {
+ outsym(funcsym, funcsym->s_scl, DECL);
+ } else {
+ outfdef(funcsym, &dcs->d_fdpos, cstk->c_retval,
+ funcsym->s_osdef, dcs->d_fargs);
+ }
+
+ /*
+ * remove all symbols declared during argument declaration from
+ * the symbol table
+ */
+ if (dcs->d_nxt != NULL || dcs->d_ctx != EXTERN)
+ lerror("funcend() 1");
+ rmsyms(dcs->d_fpsyms);
+
+ /* must be set on level 0 */
+ reached = 1;
+}
+
+/*
+ * Process a label.
+ *
+ * typ type of the label (T_NAME, T_DEFAULT or T_CASE).
+ * sym symbol table entry of label if typ == T_NAME
+ * tn expression if typ == T_CASE
+ */
+void
+label(typ, sym, tn)
+ int typ;
+ sym_t *sym;
+ tnode_t *tn;
+{
+ cstk_t *ci;
+ clst_t *cl;
+ val_t *v, *nv;
+ tspec_t t;
+
+ switch (typ) {
+
+ case T_NAME:
+ if (sym->s_set) {
+ /* label %s redefined */
+ error(194, sym->s_name);
+ } else {
+ setsflg(sym);
+ }
+ break;
+
+ case T_CASE:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* case not in switch */
+ error(195);
+ tn = NULL;
+ } else if (tn != NULL && tn->tn_op != CON) {
+ /* non-constant case expression */
+ error(197);
+ tn = NULL;
+ } else if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* non-integral case expression */
+ error(198);
+ tn = NULL;
+ }
+
+ if (tn != NULL) {
+
+ if (ci->c_swtype == NULL)
+ lerror("label() 1");
+
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on case statement */
+ warning(220);
+ }
+
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG ||
+ t == QUAD || t == UQUAD) {
+ if (tflag)
+ /* case label must be of type ... */
+ warning(203);
+ }
+
+ /*
+ * get the value of the expression and convert it
+ * to the type of the switch expression
+ */
+ v = constant(tn);
+ nv = xcalloc(1, sizeof (val_t));
+ cvtcon(CASE, 0, ci->c_swtype, nv, v);
+ free(v);
+
+ /* look if we had this value already */
+ for (cl = ci->c_clst; cl != NULL; cl = cl->cl_nxt) {
+ if (cl->cl_val.v_quad == nv->v_quad)
+ break;
+ }
+ if (cl != NULL && isutyp(nv->v_tspec)) {
+ /* duplicate case in switch, %lu */
+ error(200, (u_long)nv->v_quad);
+ } else if (cl != NULL) {
+ /* duplicate case in switch, %ld */
+ error(199, (long)nv->v_quad);
+ } else {
+ /*
+ * append the value to the list of
+ * case values
+ */
+ cl = xcalloc(1, sizeof (clst_t));
+ STRUCT_ASSIGN(cl->cl_val, *nv);
+ cl->cl_nxt = ci->c_clst;
+ ci->c_clst = cl;
+ }
+ }
+ tfreeblk();
+ break;
+
+ case T_DEFAULT:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* default outside switch */
+ error(201);
+ } else if (ci->c_default) {
+ /* duplicate default in switch */
+ error(202);
+ } else {
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on default statement */
+ warning(284);
+ }
+ ci->c_default = 1;
+ }
+ break;
+ };
+ reached = 1;
+}
+
+/*
+ * T_IF T_LPARN expr T_RPARN
+ */
+void
+if1(tn)
+ tnode_t *tn;
+{
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ expr(tn, 0, 1);
+ pushctrl(T_IF);
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE
+ */
+void
+if2()
+{
+ cstk->c_rchif = reached ? 1 : 0;
+ reached = 1;
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE stmnt
+ */
+void
+if3(els)
+ int els;
+{
+ if (els) {
+ reached |= cstk->c_rchif;
+ } else {
+ reached = 1;
+ }
+ popctrl(T_IF);
+}
+
+/*
+ * T_SWITCH T_LPARN expr T_RPARN
+ */
+void
+switch1(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *tp;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* switch expression must have integral type */
+ error(205);
+ tn = NULL;
+ }
+ if (tn != NULL && tflag) {
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) {
+ /* switch expr. must be of type `int' in trad. C */
+ warning(271);
+ }
+ }
+
+ /*
+ * Remember the type of the expression. Because its possible
+ * that (*tp) is allocated on tree memory the type must be
+ * duplicated. This is not too complicated because it is
+ * only an integer type.
+ */
+ tp = xcalloc(1, sizeof (type_t));
+ if (tn != NULL) {
+ tp->t_tspec = tn->tn_type->t_tspec;
+ if ((tp->t_isenum = tn->tn_type->t_isenum) != 0)
+ tp->t_enum = tn->tn_type->t_enum;
+ } else {
+ tp->t_tspec = INT;
+ }
+
+ expr(tn, 1, 0);
+
+ pushctrl(T_SWITCH);
+ cstk->c_switch = 1;
+ cstk->c_swtype = tp;
+
+ reached = rchflg = 0;
+ ftflg = 1;
+}
+
+/*
+ * switch_expr stmnt
+ */
+void
+switch2()
+{
+ int nenum, nclab;
+ sym_t *esym;
+ clst_t *cl;
+
+ if (cstk->c_swtype == NULL)
+ lerror("switch2() 1");
+
+ /*
+ * If the switch expression was of type enumeration, count the case
+ * labels and the number of enumerators. If both counts are not
+ * equal print a warning.
+ */
+ if (cstk->c_swtype->t_isenum) {
+ nenum = nclab = 0;
+ if (cstk->c_swtype->t_enum == NULL)
+ lerror("switch2() 2");
+ for (esym = cstk->c_swtype->t_enum->elem;
+ esym != NULL; esym = esym->s_nxt) {
+ nenum++;
+ }
+ for (cl = cstk->c_clst; cl != NULL; cl = cl->cl_nxt)
+ nclab++;
+ if (hflag && eflag && nenum != nclab && !cstk->c_default) {
+ /* enumeration value(s) not handled in switch */
+ warning(206);
+ }
+ }
+
+ if (cstk->c_break) {
+ /*
+ * end of switch alway reached (c_break is only set if the
+ * break statement can be reached).
+ */
+ reached = 1;
+ } else if (!cstk->c_default &&
+ (!hflag || !cstk->c_swtype->t_isenum || nenum != nclab)) {
+ /*
+ * there are possible values which are not handled in
+ * switch
+ */
+ reached = 1;
+ } /*
+ * otherwise the end of the switch expression is reached
+ * if the end of the last statement inside it is reached.
+ */
+
+ popctrl(T_SWITCH);
+}
+
+/*
+ * T_WHILE T_LPARN expr T_RPARN
+ */
+void
+while1(tn)
+ tnode_t *tn;
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ pushctrl(T_WHILE);
+ cstk->c_loop = 1;
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+}
+
+/*
+ * while_expr stmnt
+ * while_expr error
+ */
+void
+while2()
+{
+ /*
+ * The end of the loop can be reached if it is no endless loop
+ * or there was a break statement which was reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_WHILE);
+}
+
+/*
+ * T_DO
+ */
+void
+do1()
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_DO);
+ cstk->c_loop = 1;
+}
+
+/*
+ * do stmnt do_while_expr
+ * do error
+ */
+void
+do2(tn)
+ tnode_t *tn;
+{
+ /*
+ * If there was a continue statement the expression controlling the
+ * loop is reached.
+ */
+ if (cstk->c_cont)
+ reached = 1;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+
+ /*
+ * The end of the loop is only reached if it is no endless loop
+ * or there was a break statement which could be reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_DO);
+}
+
+/*
+ * T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN
+ */
+void
+for1(tn1, tn2, tn3)
+ tnode_t *tn1, *tn2, *tn3;
+{
+ /*
+ * If there is no initialisation expression it is possible that
+ * it is intended not to enter the loop at top.
+ */
+ if (tn1 != NULL && !reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_FOR);
+ cstk->c_loop = 1;
+
+ /*
+ * Store the tree memory for the reinitialisation expression.
+ * Also remember this expression itself. We must check it at
+ * the end of the loop to get "used but not set" warnings correct.
+ */
+ cstk->c_fexprm = tsave();
+ cstk->c_f3expr = tn3;
+ STRUCT_ASSIGN(cstk->c_fpos, curr_pos);
+ STRUCT_ASSIGN(cstk->c_cfpos, csrc_pos);
+
+ if (tn1 != NULL)
+ expr(tn1, 0, 0);
+
+ if (tn2 != NULL)
+ tn2 = cconv(tn2);
+ if (tn2 != NULL)
+ tn2 = promote(NOOP, 0, tn2);
+ if (tn2 != NULL && !issclt(tn2->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn2 = NULL;
+ }
+ if (tn2 != NULL)
+ expr(tn2, 0, 1);
+
+ if (tn2 == NULL) {
+ cstk->c_infinite = 1;
+ } else if (tn2->tn_op == CON) {
+ if (isityp(tn2->tn_type->t_tspec)) {
+ cstk->c_infinite = tn2->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn2->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ /* Checking the reinitialisation expression is done in for2() */
+
+ reached = 1;
+}
+
+/*
+ * for_exprs stmnt
+ * for_exprs error
+ */
+void
+for2()
+{
+ pos_t cpos, cspos;
+ tnode_t *tn3;
+
+ if (cstk->c_cont)
+ reached = 1;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(cspos, csrc_pos);
+
+ /* Restore the tree memory for the reinitialisation expression */
+ trestor(cstk->c_fexprm);
+ tn3 = cstk->c_f3expr;
+ STRUCT_ASSIGN(curr_pos, cstk->c_fpos);
+ STRUCT_ASSIGN(csrc_pos, cstk->c_cfpos);
+
+ /* simply "statement not reached" would be confusing */
+ if (!reached && !rchflg) {
+ /* end-of-loop code not reached */
+ warning(223);
+ reached = 1;
+ }
+
+ if (tn3 != NULL) {
+ expr(tn3, 0, 0);
+ } else {
+ tfreeblk();
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+ STRUCT_ASSIGN(csrc_pos, cspos);
+
+ /* An endless loop without break will never terminate */
+ reached = cstk->c_break || !cstk->c_infinite;
+ rchflg = 0;
+
+ popctrl(T_FOR);
+}
+
+/*
+ * T_GOTO identifier T_SEMI
+ * T_GOTO error T_SEMI
+ */
+void
+dogoto(lab)
+ sym_t *lab;
+{
+ setuflg(lab, 0, 0);
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_BREAK T_SEMI
+ */
+void
+dobreak()
+{
+ cstk_t *ci;
+
+ ci = cstk;
+ while (ci != NULL && !ci->c_loop && !ci->c_switch)
+ ci = ci->c_nxt;
+
+ if (ci == NULL) {
+ /* break outside loop or switch */
+ error(208);
+ } else {
+ if (reached)
+ ci->c_break = 1;
+ }
+
+ if (bflag)
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_CONTINUE T_SEMI
+ */
+void
+docont()
+{
+ cstk_t *ci;
+
+ for (ci = cstk; ci != NULL && !ci->c_loop; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* continue outside loop */
+ error(209);
+ } else {
+ ci->c_cont = 1;
+ }
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_RETURN T_SEMI
+ * T_RETURN expr T_SEMI
+ */
+void
+doreturn(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ cstk_t *ci;
+ op_t op;
+
+ for (ci = cstk; ci->c_nxt != NULL; ci = ci->c_nxt) ;
+
+ if (tn != NULL) {
+ ci->c_retval = 1;
+ } else {
+ ci->c_noretval = 1;
+ }
+
+ if (tn != NULL && funcsym->s_type->t_subt->t_tspec == VOID) {
+ /* void function %s cannot return value */
+ error(213, funcsym->s_name);
+ tfreeblk();
+ tn = NULL;
+ } else if (tn == NULL && funcsym->s_type->t_subt->t_tspec != VOID) {
+ /*
+ * Assume that the function has a return value only if it
+ * is explicitly declared.
+ */
+ if (!funcsym->s_rimpl)
+ /* function %s expects to return value */
+ warning(214, funcsym->s_name);
+ }
+
+ if (tn != NULL) {
+
+ /* Create a temporary node for the left side */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(funcsym->s_type->t_subt);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = funcsym; /* better than nothing */
+
+ tn = build(RETURN, ln, tn);
+
+ if (tn != NULL) {
+ rn = tn->tn_right;
+ while ((op = rn->tn_op) == CVT || op == PLUS)
+ rn = rn->tn_left;
+ if (rn->tn_op == AMPER && rn->tn_left->tn_op == NAME &&
+ rn->tn_left->tn_sym->s_scl == AUTO) {
+ /* %s returns pointer to automatic object */
+ warning(302, funcsym->s_name);
+ }
+ }
+
+ expr(tn, 1, 0);
+
+ } else {
+
+ chkreach();
+
+ }
+
+ reached = rchflg = 0;
+}
+
+/*
+ * Do some cleanup after a global declaration or definition.
+ * Especially remove informations about unused lint comments.
+ */
+void
+glclup(silent)
+ int silent;
+{
+ pos_t cpos;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (nargusg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, aupos);
+ /* must precede function definition: %s */
+ warning(282, "ARGSUSED");
+ }
+ nargusg = -1;
+ }
+ if (nvararg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, vapos);
+ /* must precede function definition: %s */
+ warning(282, "VARARGS");
+ }
+ nvararg = -1;
+ }
+ if (prflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, prflpos);
+ /* must precede function definition: %s */
+ warning(282, "PRINTFLIKE");
+ }
+ prflstrg = -1;
+ }
+ if (scflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, scflpos);
+ /* must precede function definition: %s */
+ warning(282, "SCANFLIKE");
+ }
+ scflstrg = -1;
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+
+ dcs->d_asm = 0;
+}
+
+/*
+ * ARGSUSED comment
+ *
+ * Only the first n arguments of the following function are checked
+ * for usage. A missing argument is taken to be 0.
+ */
+void
+argsused(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "ARGSUSED");
+ return;
+ }
+ if (nargusg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "ARGSUSED");
+ }
+ nargusg = n;
+ STRUCT_ASSIGN(aupos, curr_pos);
+}
+
+/*
+ * VARARGS comment
+ *
+ * Makes that lint2 checks only the first n arguments for compatibility
+ * to the function definition. A missing argument is taken to be 0.
+ */
+void
+varargs(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "VARARGS");
+ return;
+ }
+ if (nvararg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "VARARGS");
+ }
+ nvararg = n;
+ STRUCT_ASSIGN(vapos, curr_pos);
+}
+
+/*
+ * PRINTFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+printflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PRINTFLIKE");
+ return;
+ }
+ if (prflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "PRINTFLIKE");
+ }
+ prflstrg = n;
+ STRUCT_ASSIGN(prflpos, curr_pos);
+}
+
+/*
+ * SCANFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+scanflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "SCANFLIKE");
+ return;
+ }
+ if (scflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "SCANFLIKE");
+ }
+ scflstrg = n;
+ STRUCT_ASSIGN(scflpos, curr_pos);
+}
+
+/*
+ * Set the linenumber for a CONSTCOND comment. At this and the following
+ * line no warnings about constants in conditional contexts are printed.
+ */
+/* ARGSUSED */
+void
+constcond(n)
+ int n;
+{
+ ccflg = 1;
+}
+
+/*
+ * Suppress printing of "fallthrough on ..." warnings until next
+ * statement.
+ */
+/* ARGSUSED */
+void
+fallthru(n)
+ int n;
+{
+ ftflg = 1;
+}
+
+/*
+ * Stop warnings about statements which cannot be reached. Also tells lint
+ * that the following statements cannot be reached (e.g. after exit()).
+ */
+/* ARGSUSED */
+void
+notreach(n)
+ int n;
+{
+ reached = 0;
+ rchflg = 1;
+}
+
+/* ARGSUSED */
+void
+lintlib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "LINTLIBRARY");
+ return;
+ }
+ llibflg = 1;
+ vflag = 0;
+}
+
+/*
+ * Suppress most warnings at the current and the following line.
+ */
+/* ARGSUSED */
+void
+linted(n)
+ int n;
+{
+ nowarn = 1;
+}
+
+/*
+ * PROTOTLIB in conjunction with LINTLIBRARY can be used to handle
+ * prototypes like function definitions. This is done if the argument
+ * to PROTOLIB is nonzero. Otherwise prototypes are handled normaly.
+ */
+void
+protolib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PROTOLIB");
+ return;
+ }
+ plibflg = n == 0 ? 0 : 1;
+}
+
+/*
+ * Set quadflg to nonzero which means that the next statement/declaration
+ * may use "long long" without an error or warning.
+ */
+/* ARGSUSED */
+void
+longlong(n)
+ int n;
+{
+ quadflg = 1;
+}
diff --git a/usr.bin/xlint/lint1/init.c b/usr.bin/xlint/lint1/init.c
new file mode 100644
index 0000000..dbd216b
--- /dev/null
+++ b/usr.bin/xlint/lint1/init.c
@@ -0,0 +1,513 @@
+/* $NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+
+#include "lint1.h"
+
+/*
+ * initerr is set as soon as a fatal error occured in an initialisation.
+ * The effect is that the rest of the initialisation is ignored (parsed
+ * by yacc, expression trees built, but no initialisation takes place).
+ */
+int initerr;
+
+/* Pointer to the symbol which is to be initialized. */
+sym_t *initsym;
+
+/* Points to the top element of the initialisation stack. */
+istk_t *initstk;
+
+
+static void popi2 __P((void));
+static void popinit __P((int));
+static void pushinit __P((void));
+static void testinit __P((void));
+static void nextinit __P((int));
+static int strginit __P((tnode_t *));
+
+
+/*
+ * Initialize the initialisation stack by putting an entry for the variable
+ * which is to be initialized on it.
+ */
+void
+prepinit()
+{
+ istk_t *istk;
+
+ if (initerr)
+ return;
+
+ /* free memory used in last initialisation */
+ while ((istk = initstk) != NULL) {
+ initstk = istk->i_nxt;
+ free(istk);
+ }
+
+ /*
+ * If the type which is to be initialized is an incomplete type,
+ * it must be duplicated.
+ */
+ if (initsym->s_type->t_tspec == ARRAY && incompl(initsym->s_type))
+ initsym->s_type = duptyp(initsym->s_type);
+
+ istk = initstk = xcalloc(1, sizeof (istk_t));
+ istk->i_subt = initsym->s_type;
+ istk->i_cnt = 1;
+
+}
+
+static void
+popi2()
+{
+ istk_t *istk;
+ sym_t *m;
+
+ initstk = (istk = initstk)->i_nxt;
+ if (initstk == NULL)
+ lerror("popi2() 1");
+ free(istk);
+
+ istk = initstk;
+
+ istk->i_cnt--;
+ if (istk->i_cnt < 0)
+ lerror("popi2() 3");
+
+ /*
+ * If the removed element was a structure member, we must go
+ * to the next structure member.
+ */
+ if (istk->i_cnt > 0 && istk->i_type->t_tspec == STRUCT) {
+ do {
+ m = istk->i_mem = istk->i_mem->s_nxt;
+ if (m == NULL)
+ lerror("popi2() 2");
+ } while (m->s_field && m->s_name == unnamed);
+ istk->i_subt = m->s_type;
+ }
+}
+
+static void
+popinit(brace)
+ int brace;
+{
+ if (brace) {
+ /*
+ * Take all entries, including the first which requires
+ * a closing brace, from the stack.
+ */
+ do {
+ brace = initstk->i_brace;
+ popi2();
+ } while (!brace);
+ } else {
+ /*
+ * Take all entries which cannot be used for further
+ * initializers from the stack, but do this only if
+ * they do not require a closing brace.
+ */
+ while (!initstk->i_brace &&
+ initstk->i_cnt == 0 && !initstk->i_nolimit) {
+ popi2();
+ }
+ }
+}
+
+static void
+pushinit()
+{
+ istk_t *istk;
+ int cnt;
+ sym_t *m;
+
+ istk = initstk;
+
+ /* Extend an incomplete array type by one element */
+ if (istk->i_cnt == 0) {
+ /*
+ * Inside of other aggregate types must not be an incomplete
+ * type.
+ */
+ if (istk->i_nxt->i_nxt != NULL)
+ lerror("pushinit() 1");
+ istk->i_cnt = 1;
+ if (istk->i_type->t_tspec != ARRAY)
+ lerror("pushinit() 2");
+ istk->i_type->t_dim++;
+ /* from now its an complete type */
+ setcompl(istk->i_type, 0);
+ }
+
+ if (istk->i_cnt <= 0)
+ lerror("pushinit() 3");
+ if (istk->i_type != NULL && issclt(istk->i_type->t_tspec))
+ lerror("pushinit() 4");
+
+ initstk = xcalloc(1, sizeof (istk_t));
+ initstk->i_nxt = istk;
+ initstk->i_type = istk->i_subt;
+ if (initstk->i_type->t_tspec == FUNC)
+ lerror("pushinit() 5");
+
+ istk = initstk;
+
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ if (incompl(istk->i_type) && istk->i_nxt->i_nxt != NULL) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ istk->i_subt = istk->i_type->t_subt;
+ istk->i_nolimit = incompl(istk->i_type);
+ istk->i_cnt = istk->i_type->t_dim;
+ break;
+ case UNION:
+ if (tflag)
+ /* initialisation of union is illegal in trad. C */
+ warning(238);
+ /* FALLTHROUGH */
+ case STRUCT:
+ if (incompl(istk->i_type)) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ cnt = 0;
+ for (m = istk->i_type->t_str->memb; m != NULL; m = m->s_nxt) {
+ if (m->s_field && m->s_name == unnamed)
+ continue;
+ if (++cnt == 1) {
+ istk->i_mem = m;
+ istk->i_subt = m->s_type;
+ }
+ }
+ if (cnt == 0) {
+ /* cannot init. struct/union with no named member */
+ error(179);
+ initerr = 1;
+ return;
+ }
+ istk->i_cnt = istk->i_type->t_tspec == STRUCT ? cnt : 1;
+ break;
+ default:
+ istk->i_cnt = 1;
+ break;
+ }
+}
+
+static void
+testinit()
+{
+ istk_t *istk;
+
+ istk = initstk;
+
+ /*
+ * If a closing brace is expected we have at least one initializer
+ * too much.
+ */
+ if (istk->i_cnt == 0 && !istk->i_nolimit) {
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ /* too many array initializers */
+ error(173);
+ break;
+ case STRUCT:
+ case UNION:
+ /* too many struct/union initializers */
+ error(172);
+ break;
+ default:
+ /* too many initializers */
+ error(174);
+ break;
+ }
+ initerr = 1;
+ }
+}
+
+static void
+nextinit(brace)
+ int brace;
+{
+ if (!brace) {
+ if (initstk->i_type == NULL &&
+ !issclt(initstk->i_subt->t_tspec)) {
+ /* {}-enclosed initializer required */
+ error(181);
+ }
+ /*
+ * Make sure an entry with a scalar type is at the top
+ * of the stack.
+ */
+ if (!initerr)
+ testinit();
+ while (!initerr && (initstk->i_type == NULL ||
+ !issclt(initstk->i_type->t_tspec))) {
+ if (!initerr)
+ pushinit();
+ }
+ } else {
+ if (initstk->i_type != NULL &&
+ issclt(initstk->i_type->t_tspec)) {
+ /* invalid initializer */
+ error(176);
+ initerr = 1;
+ }
+ if (!initerr)
+ testinit();
+ if (!initerr)
+ pushinit();
+ if (!initerr)
+ initstk->i_brace = 1;
+ }
+}
+
+void
+initlbr()
+{
+ if (initerr)
+ return;
+
+ if ((initsym->s_scl == AUTO || initsym->s_scl == REG) &&
+ initstk->i_nxt == NULL) {
+ if (tflag && !issclt(initstk->i_subt->t_tspec))
+ /* no automatic aggregate initialization in trad. C*/
+ warning(188);
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not expect a closing brace.
+ */
+ popinit(0);
+
+ nextinit(1);
+}
+
+void
+initrbr()
+{
+ if (initerr)
+ return;
+
+ popinit(1);
+}
+
+void
+mkinit(tn)
+ tnode_t *tn;
+{
+ ptrdiff_t offs;
+ sym_t *sym;
+ tspec_t lt, rt;
+ tnode_t *ln;
+ struct mbl *tmem;
+ scl_t sc;
+
+ if (initerr || tn == NULL)
+ goto end;
+
+ sc = initsym->s_scl;
+
+ /*
+ * Do not test for automatic aggregat initialisation. If the
+ * initalizer starts with a brace we have the warning already.
+ * If not, an error will be printed that the initializer must
+ * be enclosed by braces.
+ */
+
+ /*
+ * Local initialisation of non-array-types with only one expression
+ * without braces is done by ASSIGN
+ */
+ if ((sc == AUTO || sc == REG) &&
+ initsym->s_type->t_tspec != ARRAY && initstk->i_nxt == NULL) {
+ ln = getnnode(initsym, 0);
+ ln->tn_type = tduptyp(ln->tn_type);
+ ln->tn_type->t_const = 0;
+ tn = build(ASSIGN, ln, tn);
+ expr(tn, 0, 0);
+ goto end;
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not require a closing brace.
+ */
+ popinit(0);
+
+ /* Initialisations by strings are done in strginit(). */
+ if (strginit(tn))
+ goto end;
+
+ nextinit(0);
+ if (initerr || tn == NULL)
+ goto end;
+
+ initstk->i_cnt--;
+
+ /* Create a temporary node for the left side. */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(initstk->i_type);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = initsym; /* better than nothing */
+
+ tn = cconv(tn);
+
+ lt = ln->tn_type->t_tspec;
+ rt = tn->tn_type->t_tspec;
+
+ if (!issclt(lt))
+ lerror("mkinit() 1");
+
+ if (!typeok(INIT, 0, ln, tn))
+ goto end;
+
+ /*
+ * Store the tree memory. This is nessesary because otherwise
+ * expr() would free it.
+ */
+ tmem = tsave();
+ expr(tn, 1, 0);
+ trestor(tmem);
+
+ if (isityp(lt) && ln->tn_type->t_isfield && !isityp(rt)) {
+ /*
+ * Bit-fields can be initialized in trad. C only by integer
+ * constants.
+ */
+ if (tflag)
+ /* bit-field initialisation is illegal in trad. C */
+ warning(186);
+ }
+
+ if (lt != rt || (initstk->i_type->t_isfield && tn->tn_op == CON))
+ tn = convert(INIT, 0, initstk->i_type, tn);
+
+ if (tn != NULL && tn->tn_op != CON) {
+ sym = NULL;
+ offs = 0;
+ if (conaddr(tn, &sym, &offs) == -1) {
+ if (sc == AUTO || sc == REG) {
+ /* non-constant initializer */
+ (void)gnuism(177);
+ } else {
+ /* non-constant initializer */
+ error(177);
+ }
+ }
+ }
+
+ end:
+ tfreeblk();
+}
+
+
+static int
+strginit(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ istk_t *istk;
+ int len;
+ strg_t *strg;
+
+ if (tn->tn_op != STRING)
+ return (0);
+
+ istk = initstk;
+ strg = tn->tn_strg;
+
+ /*
+ * Check if we have an array type which can be initialized by
+ * the string.
+ */
+ if (istk->i_subt->t_tspec == ARRAY) {
+ t = istk->i_subt->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /* Put the array at top of stack */
+ pushinit();
+ istk = initstk;
+ } else if (istk->i_type != NULL && istk->i_type->t_tspec == ARRAY) {
+ t = istk->i_type->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /*
+ * If the array is already partly initialized, we are
+ * wrong here.
+ */
+ if (istk->i_cnt != istk->i_type->t_dim)
+ return (0);
+ } else {
+ return (0);
+ }
+
+ /* Get length without trailing NUL character. */
+ len = strg->st_len;
+
+ if (istk->i_nolimit) {
+ istk->i_nolimit = 0;
+ istk->i_type->t_dim = len + 1;
+ /* from now complete type */
+ setcompl(istk->i_type, 0);
+ } else {
+ if (istk->i_type->t_dim < len) {
+ /* non-null byte ignored in string initializer */
+ warning(187);
+ }
+ }
+
+ /* In every case the array is initialized completely. */
+ istk->i_cnt = 0;
+
+ return (1);
+}
diff --git a/usr.bin/xlint/lint1/lint.h b/usr.bin/xlint/lint1/lint.h
new file mode 100644
index 0000000..cadcd7a
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint.h
@@ -0,0 +1,118 @@
+/* $NetBSD: lint.h,v 1.2 1995/07/03 21:24:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "param.h"
+
+/*
+ * Type specifiers, used in type structures (type_t) and otherwere.
+ */
+typedef enum {
+ NOTSPEC,
+ SIGNED, /* keyword "signed", only used in the parser */
+ UNSIGN, /* keyword "unsigned", only used in the parser */
+ CHAR, /* char */
+ SCHAR, /* signed char */
+ UCHAR, /* unsigned char */
+ SHORT, /* (signed) short */
+ USHORT, /* unsigned short */
+ INT, /* (signed) int */
+ UINT, /* unsigned int */
+ LONG, /* (signed) long */
+ ULONG, /* unsigned long */
+ QUAD, /* (signed) long long */
+ UQUAD, /* unsigned long long */
+ FLOAT, /* float */
+ DOUBLE, /* double or, with tflag, long float */
+ LDOUBLE, /* long double */
+ VOID, /* void */
+ STRUCT, /* structure tag */
+ UNION, /* union tag */
+ ENUM, /* enum tag */
+ PTR, /* pointer */
+ ARRAY, /* array */
+ FUNC /* function */
+#define NTSPEC ((int)FUNC + 1)
+} tspec_t;
+
+/*
+ * size of types, name and classification
+ */
+typedef struct {
+ int tt_sz; /* size in bits */
+ int tt_psz; /* size, different from tt_sz
+ if pflag is set */
+ tspec_t tt_styp; /* signed counterpart */
+ tspec_t tt_utyp; /* unsigned counterpart */
+ u_int tt_isityp : 1; /* 1 if integer type */
+ u_int tt_isutyp : 1; /* 1 if unsigned integer type */
+ u_int tt_isftyp : 1; /* 1 if floating point type */
+ u_int tt_isatyp : 1; /* 1 if arithmetic type */
+ u_int tt_issclt : 1; /* 1 if scalar type */
+ char *tt_name; /* Bezeichnung des Typs */
+} ttab_t;
+
+#define size(t) (ttab[t].tt_sz)
+#define psize(t) (ttab[t].tt_psz)
+#define styp(t) (ttab[t].tt_styp)
+#define utyp(t) (ttab[t].tt_utyp)
+#define isityp(t) (ttab[t].tt_isityp)
+#define isutyp(t) (ttab[t].tt_isutyp)
+#define isftyp(t) (ttab[t].tt_isftyp)
+#define isatyp(t) (ttab[t].tt_isatyp)
+#define issclt(t) (ttab[t].tt_issclt)
+
+extern ttab_t ttab[];
+
+
+typedef enum {
+ NODECL, /* until now not declared */
+ DECL, /* declared */
+ TDEF, /* tentative defined */
+ DEF /* defined */
+} def_t;
+
+/*
+ * Following structure contains some data used for the output buffer.
+ */
+typedef struct ob {
+ char *o_buf; /* buffer */
+ char *o_end; /* first byte after buffer */
+ size_t o_len; /* length of buffer */
+ char *o_nxt; /* next free byte in buffer */
+} ob_t;
+
+#include "externs.h"
diff --git a/usr.bin/xlint/lint1/lint1.h b/usr.bin/xlint/lint1/lint1.h
new file mode 100644
index 0000000..019c98d
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint1.h
@@ -0,0 +1,380 @@
+/* $NetBSD: lint1.h,v 1.6 1995/10/02 17:31:41 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "lint.h"
+#include "op.h"
+
+/*
+ * Describes the position of a declaration or anything else.
+ */
+typedef struct {
+ int p_line;
+ const char *p_file;
+} pos_t;
+
+/*
+ * Strings cannot be referenced to simply by a pointer to its first
+ * char. This is because strings can contain NUL characters other than the
+ * trailing NUL.
+ *
+ * Strings are stored with a trailing NUL.
+ */
+typedef struct strg {
+ tspec_t st_tspec; /* CHAR or WCHAR */
+ size_t st_len; /* length without trailing NUL */
+ union {
+ u_char *_st_cp;
+ wchar_t *_st_wcp;
+ } st_u;
+} strg_t;
+
+#define st_cp st_u._st_cp
+#define st_wcp st_u._st_wcp
+
+/*
+ * qualifiers (only for lex/yacc interface)
+ */
+typedef enum {
+ CONST, VOLATILE
+} tqual_t;
+
+/*
+ * Integer and floating point values are stored in this structure
+ */
+typedef struct {
+ tspec_t v_tspec;
+ int v_ansiu; /* set if an integer constant is
+ unsigned in ANSI C */
+ union {
+ quad_t _v_quad; /* integers */
+ ldbl_t _v_ldbl; /* floats */
+ } v_u;
+} val_t;
+
+#define v_quad v_u._v_quad
+#define v_ldbl v_u._v_ldbl
+
+/*
+ * Structures of type str_t uniqely identify structures. This can't
+ * be done in structures of type type_t, because these are copied
+ * if they must be modified. So it would not be possible to check
+ * if to structures are identical by comparing the pointers to
+ * the type structures.
+ *
+ * The typename is used if the structure is unnamed to identify
+ * the structure type in pass 2.
+ */
+typedef struct {
+ u_int size; /* size in bit */
+ u_int align : 15; /* alignment in bit */
+ u_int sincompl : 1; /* set if incomplete type */
+ struct sym *memb; /* list of members */
+ struct sym *stag; /* symbol table entry of tag */
+ struct sym *stdef; /* symbol table entry of first typename */
+} str_t;
+
+/*
+ * same as above for enums
+ */
+typedef struct {
+ u_int eincompl : 1; /* incomplete enum type */
+ struct sym *elem; /* list of enumerators */
+ struct sym *etag; /* symbol table entry of tag */
+ struct sym *etdef; /* symbol table entry of first typename */
+} enum_t;
+
+/*
+ * Types are represented by concatenation of structures of type type_t
+ * via t_subt.
+ */
+typedef struct type {
+ tspec_t t_tspec; /* type specifier */
+ u_int t_aincompl : 1; /* incomplete array type */
+ u_int t_const : 1; /* const modifier */
+ u_int t_volatile : 1; /* volatile modifier */
+ u_int t_proto : 1; /* function prototype (t_args valid) */
+ u_int t_vararg : 1; /* protoype with ... */
+ u_int t_typedef : 1; /* type defined with typedef */
+ u_int t_isfield : 1; /* type is bitfield */
+ u_int t_isenum : 1; /* type is (or was) enum (t_enum valid) */
+ union {
+ int _t_dim; /* dimension */
+ str_t *_t_str; /* struct/union tag */
+ enum_t *_t_enum; /* enum tag */
+ struct sym *_t_args; /* arguments (if t_proto) */
+ struct {
+ u_int _t_flen : 8; /* length of bit-field */
+ u_int _t_foffs : 24; /* offset of bit-field */
+ } _t_u;
+ } t_u;
+ struct type *t_subt; /* element type (arrays), return value
+ (functions), or type pointer points to */
+} type_t;
+
+#define t_dim t_u._t_dim
+#define t_str t_u._t_str
+#define t_field t_u._t_field
+#define t_enum t_u._t_enum
+#define t_args t_u._t_args
+#define t_flen t_u._t_u._t_flen
+#define t_foffs t_u._t_u._t_foffs
+
+/*
+ * types of symbols
+ */
+typedef enum {
+ FVFT, /* variables, functions, type names, enums */
+ FMOS, /* members of structs or unions */
+ FTAG, /* tags */
+ FLAB /* labels */
+} symt_t;
+
+/*
+ * storage classes
+ */
+typedef enum {
+ NOSCL,
+ EXTERN, /* external symbols (indep. of decl_t) */
+ STATIC, /* static symbols (local and global) */
+ AUTO, /* automatic symbols (except register) */
+ REG, /* register */
+ TYPEDEF, /* typedef */
+ STRTAG,
+ UNIONTAG,
+ ENUMTAG,
+ MOS, /* member of struct */
+ MOU, /* member of union */
+ ENUMCON, /* enumerator */
+ ABSTRACT, /* abstract symbol (sizeof, casts, unnamed argument) */
+ ARG, /* argument */
+ PARG, /* used in declaration stack during prototype
+ declaration */
+ INLINE /* only used by the parser */
+} scl_t;
+
+/*
+ * symbol table entry
+ */
+typedef struct sym {
+ const char *s_name; /* name */
+ pos_t s_dpos; /* position of last (prototype)definition,
+ prototypedeclaration, no-prototype-def.,
+ tentative definition or declaration,
+ in this order */
+ pos_t s_spos; /* position of first initialisation */
+ pos_t s_upos; /* position of first use */
+ symt_t s_kind; /* type of symbol */
+ u_int s_keyw : 1; /* keyword */
+ u_int s_field : 1; /* bit-field */
+ u_int s_set : 1; /* variable set, label defined */
+ u_int s_used : 1; /* variable/label used */
+ u_int s_arg : 1; /* symbol is function argument */
+ u_int s_reg : 1; /* symbol is register variable */
+ u_int s_defarg : 1; /* undefined symbol in old style function
+ definition */
+ u_int s_rimpl : 1; /* return value of function implizit decl. */
+ u_int s_osdef : 1; /* symbol stems from old style function def. */
+ u_int s_inline : 1; /* true if this is a inline function */
+ struct sym *s_xsym; /* for local declared external symbols pointer
+ to external symbol with same name */
+ def_t s_def; /* declared, tentative defined, defined */
+ scl_t s_scl; /* storage class */
+ int s_blklev; /* level of declaration, -1 if not in symbol
+ table */
+ type_t *s_type; /* type */
+ val_t s_value; /* value (if enumcon) */
+ union {
+ str_t *_s_st; /* tag, if it is a struct/union member */
+ enum_t *_s_et; /* tag, if it is a enumerator */
+ tspec_t _s_tsp; /* type (only for keywords) */
+ tqual_t _s_tqu; /* qualifier (only for keywords) */
+ struct sym *_s_args; /* arguments in old style function
+ definitions */
+ } u;
+ struct sym *s_link; /* next symbol with same hash value */
+ struct sym **s_rlink; /* pointer to s_link of prev. symbol */
+ struct sym *s_nxt; /* next struct/union member, enumerator,
+ argument */
+ struct sym *s_dlnxt; /* next symbol declared on same level */
+} sym_t;
+
+#define s_styp u._s_st
+#define s_etyp u._s_et
+#define s_tspec u._s_tsp
+#define s_tqual u._s_tqu
+#define s_args u._s_args
+
+/*
+ * Used to keep some informations about symbols before they are entered
+ * into the symbol table.
+ */
+typedef struct sbuf {
+ const char *sb_name; /* name of symbol */
+ size_t sb_len; /* length (without '\0') */
+ int sb_hash; /* hash value */
+ sym_t *sb_sym; /* symbol table entry */
+ struct sbuf *sb_nxt; /* for freelist */
+} sbuf_t;
+
+
+/*
+ * tree node
+ */
+typedef struct tnode {
+ op_t tn_op; /* operator */
+ type_t *tn_type; /* type */
+ u_int tn_lvalue : 1; /* node is lvalue */
+ u_int tn_cast : 1; /* if tn_op == CVT its an explizit cast */
+ u_int tn_parn : 1; /* node parenthesized */
+ union {
+ struct {
+ struct tnode *_tn_left; /* (left) operand */
+ struct tnode *_tn_right; /* right operand */
+ } tn_s;
+ sym_t *_tn_sym; /* symbol if op == NAME */
+ val_t *_tn_val; /* value if op == CON */
+ strg_t *_tn_strg; /* string if op == STRING */
+ } tn_u;
+} tnode_t;
+
+#define tn_left tn_u.tn_s._tn_left
+#define tn_right tn_u.tn_s._tn_right
+#define tn_sym tn_u._tn_sym
+#define tn_val tn_u._tn_val
+#define tn_strg tn_u._tn_strg
+
+/*
+ * For nested declarations a stack exists, which holds all information
+ * needed for the current level. dcs points to the top element of this
+ * stack.
+ *
+ * ctx describes the context of the current declaration. Its value is
+ * one of
+ * EXTERN global declarations
+ * MOS oder MOU declarations of struct or union members
+ * ENUMCON declarations of enums
+ * ARG declaration of arguments in old style function definitions
+ * PARG declaration of arguments in function prototypes
+ * AUTO declaration of local symbols
+ * ABSTRACT abstract declarations (sizeof, casts)
+ *
+ */
+typedef struct dinfo {
+ tspec_t d_atyp; /* VOID, CHAR, INT, FLOAT or DOUBLE */
+ tspec_t d_smod; /* SIGNED or UNSIGN */
+ tspec_t d_lmod; /* SHORT, LONG or QUAD */
+ scl_t d_scl; /* storage class */
+ type_t *d_type; /* after deftyp() pointer to the type used
+ for all declarators */
+ sym_t *d_rdcsym; /* redeclared symbol */
+ int d_offset; /* offset of next structure member */
+ int d_stralign; /* alignment required for current structure */
+ scl_t d_ctx; /* context of declaration */
+ u_int d_const : 1; /* const in declaration specifiers */
+ u_int d_volatile : 1; /* volatile in declaration specifiers */
+ u_int d_inline : 1; /* inline in declaration specifiers */
+ u_int d_mscl : 1; /* multiple storage classes */
+ u_int d_terr : 1; /* invalid type combination */
+ u_int d_nedecl : 1; /* 1 if at least a tag is declared */
+ u_int d_vararg : 1; /* ... in in current function decl. */
+ u_int d_proto : 1; /* current funct. decl. is prototype */
+ u_int d_notyp : 1; /* set if no type specifier was present */
+ u_int d_asm : 1; /* set if d_ctx == AUTO and asm() present */
+ type_t *d_tagtyp; /* tag during member declaration */
+ sym_t *d_fargs; /* list of arguments during function def. */
+ pos_t d_fdpos; /* position of function definition */
+ sym_t *d_dlsyms; /* first symbol declared at this level */
+ sym_t **d_ldlsym; /* points to s_dlnxt in last symbol decl.
+ at this level */
+ sym_t *d_fpsyms; /* symbols defined in prototype */
+ struct dinfo *d_nxt; /* next level */
+} dinfo_t;
+
+/*
+ * Type of stack which is used for initialisation of aggregate types.
+ */
+typedef struct istk {
+ type_t *i_type; /* type of initialisation */
+ type_t *i_subt; /* type of next level */
+ u_int i_brace : 1; /* need } for pop */
+ u_int i_nolimit : 1; /* incomplete array type */
+ sym_t *i_mem; /* next structure member */
+ int i_cnt; /* # of remaining elements */
+ struct istk *i_nxt; /* previous level */
+} istk_t;
+
+/*
+ * Used to collect information about pointers and qualifiers in
+ * declarators.
+ */
+typedef struct pqinf {
+ int p_pcnt; /* number of asterisks */
+ u_int p_const : 1;
+ u_int p_volatile : 1;
+ struct pqinf *p_nxt;
+} pqinf_t;
+
+/*
+ * Case values are stored in a list of type clst_t.
+ */
+typedef struct clst {
+ val_t cl_val;
+ struct clst *cl_nxt;
+} clst_t;
+
+/*
+ * Used to keep informations about nested control statements.
+ */
+typedef struct cstk {
+ int c_env; /* type of statement (T_IF, ...) */
+ u_int c_loop : 1; /* continue && break are valid */
+ u_int c_switch : 1; /* case && break are valid */
+ u_int c_break : 1; /* loop/switch has break */
+ u_int c_cont : 1; /* loop has continue */
+ u_int c_default : 1; /* switch has default */
+ u_int c_infinite : 1; /* break condition always false
+ (for (;;), while (1)) */
+ u_int c_rchif : 1; /* end of if-branch reached */
+ u_int c_noretval : 1; /* had "return;" */
+ u_int c_retval : 1; /* had "return (e);" */
+ type_t *c_swtype; /* type of switch expression */
+ clst_t *c_clst; /* list of case values */
+ struct mbl *c_fexprm; /* saved memory for end of loop
+ expression in for() */
+ tnode_t *c_f3expr; /* end of loop expr in for() */
+ pos_t c_fpos; /* position of end of loop expr */
+ pos_t c_cfpos; /* same for csrc_pos */
+ struct cstk *c_nxt; /* outer control statement */
+} cstk_t;
+
+#include "externs1.h"
diff --git a/usr.bin/xlint/lint1/main1.c b/usr.bin/xlint/lint1/main1.c
new file mode 100644
index 0000000..0add206
--- /dev/null
+++ b/usr.bin/xlint/lint1/main1.c
@@ -0,0 +1,183 @@
+/* $NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/* set yydebug to 1*/
+int yflag;
+
+/*
+ * Print warnings if an assignment of an integertype to another integertype
+ * causes an implizit narrowing conversion. If aflag is 1, these warnings
+ * are printed only if the source type is at least as wide as long. If aflag
+ * is greather then 1, they are always printed.
+ */
+int aflag;
+
+/* Print a warning if a break statement cannot be reached. */
+int bflag;
+
+/* Print warnings for pointer casts. */
+int cflag;
+
+/* Print various debug information. */
+int dflag;
+
+/* Perform stricter checking of enum types and operations on enum types. */
+int eflag;
+
+/* Print complete pathnames, not only the basename. */
+int Fflag;
+
+/* Enable some extensions of gcc */
+int gflag;
+
+/*
+ * Apply a number of heuristic tests to attempt to intuit bugs, improve
+ * style, and reduce waste.
+ */
+int hflag;
+
+/* Attempt to check portability to other dialects of C. */
+int pflag;
+
+/*
+ * In case of redeclarations/redefinitions print the location of the
+ * previous declaration/definition.
+ */
+int rflag;
+
+/* Strict ANSI C mode. */
+int sflag;
+
+/* Traditional C mode. */
+int tflag;
+
+/*
+ * Complain about functions and external variables used and not defined,
+ * or defined and not used.
+ */
+int uflag = 1;
+
+/* Complain about unused function arguments. */
+int vflag = 1;
+
+/* Complain about structures which are never defined. */
+int zflag = 1;
+
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "abcdeghprstuvyzF")) != -1) {
+ switch (c) {
+ case 'a': aflag++; break;
+ case 'b': bflag = 1; break;
+ case 'c': cflag = 1; break;
+ case 'd': dflag = 1; break;
+ case 'e': eflag = 1; break;
+ case 'F': Fflag = 1; break;
+ case 'g': gflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'p': pflag = 1; break;
+ case 'r': rflag = 1; break;
+ case 's': sflag = 1; break;
+ case 't': tflag = 1; break;
+ case 'u': uflag = 0; break;
+ case 'v': vflag = 0; break;
+ case 'y': yflag = 1; break;
+ case 'z': zflag = 0; break;
+ case '?': usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ /* open the input file */
+ if ((yyin = fopen(argv[0], "r")) == NULL)
+ err(1, "cannot open '%s'", argv[0]);
+
+ /* initialize output */
+ outopen(argv[1]);
+
+ if (yflag)
+ yydebug = 1;
+
+ initmem();
+ initdecl();
+ initscan();
+ initmtab();
+
+ yyparse();
+
+ /* Following warnings cannot be suppressed by LINTED */
+ nowarn = 0;
+
+ chkglsyms();
+
+ outclose();
+
+ return (nerr != 0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: lint1 [-abcdeghprstuvyzF] src dest\n");
+ exit(1);
+}
+
+void
+norecover()
+{
+ /* cannot recover from previous errors */
+ error(224);
+ exit(1);
+}
diff --git a/usr.bin/xlint/lint1/mem.c b/usr.bin/xlint/lint1/mem.c
new file mode 100644
index 0000000..71fba06
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem.c
@@ -0,0 +1,91 @@
+/* $NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include "lint.h"
+
+void *
+xmalloc(s)
+ size_t s;
+{
+ void *p;
+
+ if ((p = malloc(s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xcalloc(n, s)
+ size_t n, s;
+{
+ void *p;
+
+ if ((p = calloc(n, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xrealloc(p, s)
+ void *p;
+ size_t s;
+{
+ if ((p = realloc(p, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+char *
+xstrdup(s)
+ const char *s;
+{
+ char *s2;
+
+ if ((s2 = strdup(s)) == NULL)
+ nomem();
+ return (s2);
+}
+
+void
+nomem()
+{
+ errx(1, "virtual memory exhausted");
+}
diff --git a/usr.bin/xlint/lint1/mem1.c b/usr.bin/xlint/lint1/mem1.c
new file mode 100644
index 0000000..f3bf3c6
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem1.c
@@ -0,0 +1,358 @@
+/* $NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/*
+ * Filenames allocated by fnalloc() and fnnalloc() are shared.
+ */
+typedef struct fn {
+ char *fn_name;
+ size_t fn_len;
+ int fn_id;
+ struct fn *fn_nxt;
+} fn_t;
+
+static fn_t *fnames;
+
+static fn_t *srchfn __P((const char *, size_t));
+
+/*
+ * Look for a Filename of length l.
+ */
+static fn_t *
+srchfn(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
+ if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
+ break;
+ }
+ return (fn);
+}
+
+/*
+ * Return a shared string for filename s.
+ */
+const char *
+fnalloc(s)
+ const char *s;
+{
+ return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
+}
+
+const char *
+fnnalloc(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ static int nxt_id = 0;
+
+ if (s == NULL)
+ return (NULL);
+
+ if ((fn = srchfn(s, len)) == NULL) {
+ fn = xmalloc(sizeof (fn_t));
+ /* Do not used strdup() because string is not NUL-terminated.*/
+ fn->fn_name = xmalloc(len + 1);
+ (void)memcpy(fn->fn_name, s, len);
+ fn->fn_name[len] = '\0';
+ fn->fn_len = len;
+ fn->fn_id = nxt_id++;
+ fn->fn_nxt = fnames;
+ fnames = fn;
+ /* Write id of this filename to the output file. */
+ outclr();
+ outint(fn->fn_id);
+ outchar('s');
+ outstrg(fn->fn_name);
+ }
+ return (fn->fn_name);
+}
+
+/*
+ * Get id of a filename.
+ */
+int
+getfnid(s)
+ const char *s;
+{
+ fn_t *fn;
+
+ if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
+ return (-1);
+ return (fn->fn_id);
+}
+
+/*
+ * Memory for declarations and other things which must be available
+ * until the end of a block (or the end of the translation unit)
+ * are assoziated with the level (mblklev) of the block (or wiht 0).
+ * Because these memory is allocated in large blocks associated with
+ * a given level it can be freed easily at the end of a block.
+ */
+#define ML_INC ((size_t)32) /* Increment for length of *mblks */
+
+typedef struct mbl {
+ void *blk; /* beginning of memory block */
+ void *ffree; /* first free byte */
+ size_t nfree; /* # of free bytes */
+ size_t size; /* total size of memory block */
+ struct mbl *nxt; /* next block */
+} mbl_t;
+
+/*
+ * Array of pointers to lists of memory blocks. mblklev is used as
+ * index into this array.
+ */
+static mbl_t **mblks;
+
+/* number of elements in *mblks */
+static size_t nmblks;
+
+/* free list for memory blocks */
+static mbl_t *frmblks;
+
+/* length of new allocated memory blocks */
+static size_t mblklen;
+
+static void *xgetblk __P((mbl_t **, size_t));
+static void xfreeblk __P((mbl_t **));
+static mbl_t *xnewblk __P((void));
+
+static mbl_t *
+xnewblk()
+{
+ mbl_t *mb;
+ int prot, flags;
+
+ mb = xmalloc(sizeof (mbl_t));
+
+ /* use mmap instead of malloc to avoid malloc's size overhead */
+
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_ANON | MAP_PRIVATE;
+ mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
+ if (mb->blk == (void *)MAP_FAILED)
+ err(1, "can't map memory");
+ if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
+ errx(1, "mapped address is not aligned");
+
+ mb->size = mblklen;
+
+ return (mb);
+}
+
+/*
+ * Allocate new memory. If the first block of the list has not enough
+ * free space, or there is no first block, get a new block. The new
+ * block is taken from the free list or, if there is no block on the
+ * free list, is allocated using xnewblk(). If a new block is allocated
+ * it is initialized with zero. Blocks taken from the free list are
+ * zero'd in xfreeblk().
+ */
+static void *
+xgetblk(mbp, s)
+ mbl_t **mbp;
+ size_t s;
+{
+ mbl_t *mb;
+ void *p;
+
+ s = ALIGN(s);
+ if ((mb = *mbp) == NULL || mb->nfree < s) {
+ if ((mb = frmblks) == NULL) {
+ mb = xnewblk();
+ (void)memset(mb->blk, 0, mb->size);
+ } else {
+ frmblks = mb->nxt;
+ }
+ mb->ffree = mb->blk;
+ mb->nfree = mb->size;;
+ mb->nxt = *mbp;
+ *mbp = mb;
+ }
+ p = mb->ffree;
+ mb->ffree = (char *)mb->ffree + s;
+ mb->nfree -= s;
+ return (p);
+}
+
+/*
+ * Move all blocks from list *fmbp to free list. For each block, set all
+ * used memory to zero.
+ */
+static void
+xfreeblk(fmbp)
+ mbl_t **fmbp;
+{
+ mbl_t *mb;
+
+ while ((mb = *fmbp) != NULL) {
+ *fmbp = mb->nxt;
+ mb->nxt = frmblks;
+ frmblks = mb;
+ (void)memset(mb->blk, 0, mb->size - mb->nfree);
+ }
+}
+
+void
+initmem()
+{
+ int pgsz;
+
+ pgsz = getpagesize();
+ mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
+
+ mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
+}
+
+
+/*
+ * Allocate memory associated with level l.
+ */
+void *
+getlblk(l, s)
+ int l;
+ size_t s;
+{
+ while (l >= nmblks) {
+ mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
+ (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
+ nmblks += ML_INC;
+ }
+ return (xgetblk(&mblks[l], s));
+}
+
+void *
+getblk(s)
+ size_t s;
+{
+ return (getlblk(mblklev, s));
+}
+
+/*
+ * Free all memory associated with level l.
+ */
+void
+freelblk(l)
+ int l;
+{
+ xfreeblk(&mblks[l]);
+}
+
+void
+freeblk()
+{
+ freelblk(mblklev);
+}
+
+/*
+ * tgetblk() returns memory which is associated with the current
+ * expression.
+ */
+static mbl_t *tmblk;
+
+void *
+tgetblk(s)
+ size_t s;
+{
+ return (xgetblk(&tmblk, s));
+}
+
+/*
+ * Get memory for a new tree node.
+ */
+tnode_t *
+getnode()
+{
+ return (tgetblk(sizeof (tnode_t)));
+}
+
+/*
+ * Free all memory which is allocated by the the current expression.
+ */
+void
+tfreeblk()
+{
+ xfreeblk(&tmblk);
+}
+
+/*
+ * Save the memory which is used by the current expression. This memory
+ * is not freed by the next tfreeblk() call. The pointer returned can be
+ * used to restore the memory.
+ */
+mbl_t *
+tsave()
+{
+ mbl_t *tmem;
+
+ tmem = tmblk;
+ tmblk = NULL;
+ return (tmem);
+}
+
+/*
+ * Free all memory used for the current expression and the memory used
+ * be a previous expression and saved by tsave(). The next call to
+ * tfreeblk() frees the restored memory.
+ */
+void
+trestor(tmem)
+ mbl_t *tmem;
+{
+ tfreeblk();
+ if (tmblk != NULL) {
+ free(tmblk->blk);
+ free(tmblk);
+ }
+ tmblk = tmem;
+}
diff --git a/usr.bin/xlint/lint1/op.h b/usr.bin/xlint/lint1/op.h
new file mode 100644
index 0000000..11f05a5
--- /dev/null
+++ b/usr.bin/xlint/lint1/op.h
@@ -0,0 +1,120 @@
+/* $NetBSD: op.h,v 1.2 1995/07/03 21:24:27 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various information about operators
+ */
+typedef struct {
+ u_int m_binary : 1; /* binary op. */
+ u_int m_logop : 1; /* logical op., result is int */
+ u_int m_rqint : 1; /* operands must have integer type */
+ u_int m_rqsclt : 1; /* operands must have scalar type */
+ u_int m_rqatyp : 1; /* operands must have arithmetic type */
+ u_int m_fold : 1; /* operands should be folded */
+ u_int m_vctx : 1; /* value context for left operand */
+ u_int m_tctx : 1; /* test context for left operand */
+ u_int m_balance : 1; /* op. requires balancing */
+ u_int m_sideeff : 1; /* op. has side effect */
+ u_int m_tlansiu : 1; /* warning if left op. is unsign. in ANSI C */
+ u_int m_transiu : 1; /* warning if right op. is unsign. in ANSI C */
+ u_int m_tpconf : 1; /* test possible precedence confusion */
+ u_int m_comp : 1; /* op. performs comparision */
+ u_int m_enumop : 1; /* valid operation on enums */
+ u_int m_badeop : 1; /* dubious operation on enums */
+ u_int m_eqwarn : 1; /* warning if on operand stems from == */
+ const char *m_name; /* name of op. */
+} mod_t;
+
+typedef enum {
+ NOOP = 0,
+ ARROW,
+ POINT,
+ NOT,
+ COMPL,
+ INC,
+ DEC,
+ INCBEF,
+ DECBEF,
+ INCAFT,
+ DECAFT,
+ UPLUS,
+ UMINUS,
+ STAR,
+ AMPER,
+ MULT,
+ DIV,
+ MOD,
+ PLUS,
+ MINUS,
+ SHL,
+ SHR,
+ LT,
+ LE,
+ GT,
+ GE,
+ EQ,
+ NE,
+ AND,
+ XOR,
+ OR,
+ LOGAND,
+ LOGOR,
+ QUEST,
+ COLON,
+ ASSIGN,
+ MULASS,
+ DIVASS,
+ MODASS,
+ ADDASS,
+ SUBASS,
+ SHLASS,
+ SHRASS,
+ ANDASS,
+ XORASS,
+ ORASS,
+ NAME,
+ CON,
+ STRING,
+ FSEL,
+ CALL,
+ COMMA,
+ CVT,
+ ICALL,
+ LOAD,
+ PUSH,
+ RETURN,
+ INIT, /* pseudo op, not used in trees */
+ CASE, /* pseudo op, not used in trees */
+ FARG /* pseudo op, not used in trees */
+#define NOPS ((int)FARG + 1)
+} op_t;
diff --git a/usr.bin/xlint/lint1/param.h b/usr.bin/xlint/lint1/param.h
new file mode 100644
index 0000000..17e266e
--- /dev/null
+++ b/usr.bin/xlint/lint1/param.h
@@ -0,0 +1,120 @@
+/* $NetBSD: param.h,v 1.4 1995/07/23 18:14:41 ragge Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Minimun size of string buffer. If this is not enough, the buffer
+ * is enlarged in steps of STRBLEN bytes.
+ */
+#define STRBLEN 256
+
+/*
+ * This defines the size of memory blocks which are used to allocate
+ * memory in larger chunks.
+ */
+#define MBLKSIZ ((size_t)0x4000)
+
+/*
+ * Sizes of hash tables
+ * Should be a prime. Possible primes are
+ * 307, 401, 503, 601, 701, 809, 907, 1009, 1103, 1201, 1301, 1409, 1511.
+ *
+ * HSHSIZ1 symbol table 1st pass
+ * HSHSIZ2 symbol table 2nd pass
+ * THSHSIZ2 type table 2nd pass
+ */
+#define HSHSIZ1 503
+#define HSHSIZ2 1009
+#define THSHSIZ2 1009
+
+/*
+ * Should be set to 1 if the difference of two pointers is of type long
+ * or the value of sizeof is of type unsigned long.
+ */
+#ifdef __alpha__
+#define PTRDIFF_IS_LONG 1
+#define SIZEOF_IS_ULONG 1
+#elif __i386__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __m68k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __ns32k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __sparc__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __vax__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#else
+#error unknown machine type
+#endif
+
+/*
+ * Make sure this matches wchar_t.
+ */
+#define WCHAR SHORT
+
+#ifndef __GNUC__
+#ifndef lint
+#ifndef QUAD_MAX /* necessary for mkdep */
+#define QUAD_MAX LONG_MAX
+#define QUAD_MIN LONG_MIN
+#define UQUAD_MAX ULONG_MAX
+#endif
+typedef long quad_t;
+typedef u_long u_quad_t;
+#endif
+#endif
+
+
+/*
+ * long double only in ANSI C.
+ */
+#ifdef __STDC__
+typedef long double ldbl_t;
+#else
+typedef double ldbl_t;
+#endif
+
+/*
+ * Some traditional compilers are not able to assign structures.
+ */
+#ifdef __STDC__
+#define STRUCT_ASSIGN(dest, src) (dest) = (src)
+#else
+#define STRUCT_ASSIGN(dest, src) (void)memcpy(&(dest), &(src), \
+ sizeof (dest));
+#endif
diff --git a/usr.bin/xlint/lint1/scan.l b/usr.bin/xlint/lint1/scan.l
new file mode 100644
index 0000000..ece6ef9
--- /dev/null
+++ b/usr.bin/xlint/lint1/scan.l
@@ -0,0 +1,1427 @@
+%{
+/* $NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <math.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+#define CHAR_MASK (~(~0 << CHAR_BIT))
+
+/* XXX declaration of strtouq() is missing in stdlib.h ? */
+extern u_quad_t strtouq __P((const char *, char **, int));
+
+/* Current position (its also updated when an included file is parsed) */
+pos_t curr_pos = { 1, "" };
+
+/*
+ * Current position in C source (not updated when an included file is
+ * parsed).
+ */
+pos_t csrc_pos = { 1, "" };
+
+static void incline __P((void));
+static void badchar __P((int));
+static sbuf_t *allocsb __P((void));
+static void freesb __P((sbuf_t *));
+static int inpc __P((void));
+static int hash __P((const char *));
+static sym_t *search __P((sbuf_t *));
+static int name __P((void));
+static int keyw __P((sym_t *));
+static int icon __P((int));
+static int fcon __P((void));
+static int operator __P((int, op_t));
+static int ccon __P((void));
+static int wccon __P((void));
+static int getescc __P((int));
+static void directive __P((void));
+static void comment __P((void));
+static int string __P((void));
+static int wcstrg __P((void));
+
+%}
+
+L [_A-Za-z]
+D [0-9]
+NZD [1-9]
+OD [0-7]
+HD [0-9A-Fa-f]
+EX ([eE][+-]?[0-9]+)
+
+%%
+
+{L}({L}|{D})* return (name());
+0{OD}*[lLuU]* return (icon(8));
+{NZD}{D}*[lLuU]* return (icon(10));
+0[xX]{HD}+[lLuU]* return (icon(16));
+{D}+\.{D}*{EX}?[fFlL]? |
+{D}+{EX}[fFlL]? |
+\.{D}+{EX}?[fFlL]? return (fcon());
+"=" return (operator(T_ASSIGN, ASSIGN));
+"*=" return (operator(T_OPASS, MULASS));
+"/=" return (operator(T_OPASS, DIVASS));
+"%=" return (operator(T_OPASS, MODASS));
+"+=" return (operator(T_OPASS, ADDASS));
+"-=" return (operator(T_OPASS, SUBASS));
+"<<=" return (operator(T_OPASS, SHLASS));
+">>=" return (operator(T_OPASS, SHRASS));
+"&=" return (operator(T_OPASS, ANDASS));
+"^=" return (operator(T_OPASS, XORASS));
+"|=" return (operator(T_OPASS, ORASS));
+"||" return (operator(T_LOGOR, LOGOR));
+"&&" return (operator(T_LOGAND, LOGAND));
+"|" return (operator(T_OR, OR));
+"&" return (operator(T_AND, AND));
+"^" return (operator(T_XOR, XOR));
+"==" return (operator(T_EQOP, EQ));
+"!=" return (operator(T_EQOP, NE));
+"<" return (operator(T_RELOP, LT));
+">" return (operator(T_RELOP, GT));
+"<=" return (operator(T_RELOP, LE));
+">=" return (operator(T_RELOP, GE));
+"<<" return (operator(T_SHFTOP, SHL));
+">>" return (operator(T_SHFTOP, SHR));
+"++" return (operator(T_INCDEC, INC));
+"--" return (operator(T_INCDEC, DEC));
+"->" return (operator(T_STROP, ARROW));
+"." return (operator(T_STROP, POINT));
+"+" return (operator(T_ADDOP, PLUS));
+"-" return (operator(T_ADDOP, MINUS));
+"*" return (operator(T_MULT, MULT));
+"/" return (operator(T_DIVOP, DIV));
+"%" return (operator(T_DIVOP, MOD));
+"!" return (operator(T_UNOP, NOT));
+"~" return (operator(T_UNOP, COMPL));
+"\"" return (string());
+"L\"" return (wcstrg());
+";" return (T_SEMI);
+"{" return (T_LBRACE);
+"}" return (T_RBRACE);
+"," return (T_COMMA);
+":" return (T_COLON);
+"?" return (T_QUEST);
+"[" return (T_LBRACK);
+"]" return (T_RBRACK);
+"(" return (T_LPARN);
+")" return (T_RPARN);
+"..." return (T_ELLIPSE);
+"'" return (ccon());
+"L'" return (wccon());
+^#.*$ directive();
+\n incline();
+\t|" "|\f|\v ;
+"/*" comment();
+. badchar(yytext[0]);
+
+%%
+
+static void
+incline()
+{
+ curr_pos.p_line++;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line++;
+}
+
+static void
+badchar(c)
+ int c;
+{
+ /* unknown character \%o */
+ error(250, c);
+}
+
+/*
+ * Keywords.
+ * During initialisation they are written to the symbol table.
+ */
+static struct kwtab {
+ const char *kw_name; /* keyword */
+ int kw_token; /* token returned by yylex() */
+ scl_t kw_scl; /* storage class if kw_token T_SCLASS */
+ tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */
+ tqual_t kw_tqual; /* type qual. fi kw_token T_QUAL */
+ u_int kw_stdc : 1; /* STDC keyword */
+ u_int kw_gcc : 1; /* GCC keyword */
+} kwtab[] = {
+ { "asm", T_ASM, 0, 0, 0, 0, 1 },
+ { "__asm", T_ASM, 0, 0, 0, 0, 0 },
+ { "__asm__", T_ASM, 0, 0, 0, 0, 0 },
+ { "auto", T_SCLASS, AUTO, 0, 0, 0, 0 },
+ { "break", T_BREAK, 0, 0, 0, 0, 0 },
+ { "case", T_CASE, 0, 0, 0, 0, 0 },
+ { "char", T_TYPE, 0, CHAR, 0, 0, 0 },
+ { "const", T_QUAL, 0, 0, CONST, 1, 0 },
+ { "__const__", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "__const", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "continue", T_CONTINUE, 0, 0, 0, 0, 0 },
+ { "default", T_DEFAULT, 0, 0, 0, 0, 0 },
+ { "do", T_DO, 0, 0, 0, 0, 0 },
+ { "double", T_TYPE, 0, DOUBLE, 0, 0, 0 },
+ { "else", T_ELSE, 0, 0, 0, 0, 0 },
+ { "enum", T_ENUM, 0, 0, 0, 0, 0 },
+ { "extern", T_SCLASS, EXTERN, 0, 0, 0, 0 },
+ { "float", T_TYPE, 0, FLOAT, 0, 0, 0 },
+ { "for", T_FOR, 0, 0, 0, 0, 0 },
+ { "goto", T_GOTO, 0, 0, 0, 0, 0 },
+ { "if", T_IF, 0, 0, 0, 0, 0 },
+ { "inline", T_SCLASS, INLINE, 0, 0, 0, 1 },
+ { "__inline__", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "__inline", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "int", T_TYPE, 0, INT, 0, 0, 0 },
+ { "long", T_TYPE, 0, LONG, 0, 0, 0 },
+ { "register", T_SCLASS, REG, 0, 0, 0, 0 },
+ { "return", T_RETURN, 0, 0, 0, 0, 0 },
+ { "short", T_TYPE, 0, SHORT, 0, 0, 0 },
+ { "signed", T_TYPE, 0, SIGNED, 0, 1, 0 },
+ { "__signed__", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "__signed", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "sizeof", T_SIZEOF, 0, 0, 0, 0, 0 },
+ { "static", T_SCLASS, STATIC, 0, 0, 0, 0 },
+ { "struct", T_SOU, 0, STRUCT, 0, 0, 0 },
+ { "switch", T_SWITCH, 0, 0, 0, 0, 0 },
+ { "typedef", T_SCLASS, TYPEDEF, 0, 0, 0, 0 },
+ { "union", T_SOU, 0, UNION, 0, 0, 0 },
+ { "unsigned", T_TYPE, 0, UNSIGN, 0, 0, 0 },
+ { "void", T_TYPE, 0, VOID, 0, 0, 0 },
+ { "volatile", T_QUAL, 0, 0, VOLATILE, 1, 0 },
+ { "__volatile__", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "__volatile", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "while", T_WHILE, 0, 0, 0, 0, 0 },
+ { NULL, 0, 0, 0, 0, 0, 0 }
+};
+
+/* Symbol table */
+static sym_t *symtab[HSHSIZ1];
+
+/* bit i of the entry with index i is set */
+u_quad_t qbmasks[sizeof(u_quad_t) * CHAR_BIT];
+
+/* least significant i bits are set in the entry with index i */
+u_quad_t qlmasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* least significant i bits are not set in the entry with index i */
+u_quad_t qumasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* free list for sbuf structures */
+static sbuf_t *sbfrlst;
+
+/* Typ of next expected symbol */
+symt_t symtyp;
+
+
+/*
+ * All keywords are written to the symbol table. This saves us looking
+ * in a extra table for each name we found.
+ */
+void
+initscan()
+{
+ struct kwtab *kw;
+ sym_t *sym;
+ int h, i;
+ u_quad_t uq;
+
+ for (kw = kwtab; kw->kw_name != NULL; kw++) {
+ if (kw->kw_stdc && tflag)
+ continue;
+ if (kw->kw_gcc && !gflag)
+ continue;
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = kw->kw_name;
+ sym->s_keyw = 1;
+ sym->s_value.v_quad = kw->kw_token;
+ if (kw->kw_token == T_TYPE || kw->kw_token == T_SOU) {
+ sym->s_tspec = kw->kw_tspec;
+ } else if (kw->kw_token == T_SCLASS) {
+ sym->s_scl = kw->kw_scl;
+ } else if (kw->kw_token == T_QUAL) {
+ sym->s_tqual = kw->kw_tqual;
+ }
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ }
+
+ /* initialize bit-masks for quads */
+ for (i = 0; i < sizeof (u_quad_t) * CHAR_BIT; i++) {
+ qbmasks[i] = (u_quad_t)1 << i;
+ uq = ~(u_quad_t)0 << i;
+ qumasks[i] = uq;
+ qlmasks[i] = ~uq;
+ }
+ qumasks[i] = 0;
+ qlmasks[i] = ~(u_quad_t)0;
+}
+
+/*
+ * Get a free sbuf structure, if possible from the free list
+ */
+static sbuf_t *
+allocsb()
+{
+ sbuf_t *sb;
+
+ if ((sb = sbfrlst) != NULL) {
+ sbfrlst = sb->sb_nxt;
+ } else {
+ sb = xmalloc(sizeof (sbuf_t));
+ }
+ (void)memset(sb, 0, sizeof (sb));
+ return (sb);
+}
+
+/*
+ * Put a sbuf structure to the free list
+ */
+static void
+freesb(sb)
+ sbuf_t *sb;
+{
+ sb->sb_nxt = sbfrlst;
+ sbfrlst = sb;
+}
+
+/*
+ * Read a character and ensure that it is positive (except EOF).
+ * Increment line count(s) if necessary.
+ */
+static int
+inpc()
+{
+ int c;
+
+ if ((c = input()) != EOF && (c &= CHAR_MASK) == '\n')
+ incline();
+ return (c);
+}
+
+static int
+hash(s)
+ const char *s;
+{
+ u_int v;
+ const u_char *us;
+
+ v = 0;
+ for (us = (const u_char *)s; *us != '\0'; us++) {
+ v = (v << sizeof (v)) + *us;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % HSHSIZ1);
+}
+
+/*
+ * Lex has found a letter followed by zero or more letters or digits.
+ * It looks for a symbol in the symbol table with the same name. This
+ * symbol must either be a keyword or a symbol of the type required by
+ * symtyp (label, member, tag, ...).
+ *
+ * If it is a keyword, the token is returned. In some cases it is described
+ * more deeply by data written to yylval.
+ *
+ * If it is a symbol, T_NAME is returned and the pointer to a sbuf struct
+ * is stored in yylval. This struct contains the name of the symbol, it's
+ * length and hash value. If there is already a symbol of the same name
+ * and type in the symbol table, the sbuf struct also contains a pointer
+ * to the symbol table entry.
+ */
+static int
+name()
+{
+ char *s;
+ sbuf_t *sb;
+ sym_t *sym;
+ int tok;
+
+ sb = allocsb();
+ sb->sb_name = yytext;
+ sb->sb_len = yyleng;
+ sb->sb_hash = hash(yytext);
+
+ if ((sym = search(sb)) != NULL && sym->s_keyw) {
+ freesb(sb);
+ return (keyw(sym));
+ }
+
+ sb->sb_sym = sym;
+
+ if (sym != NULL) {
+ if (blklev < sym->s_blklev)
+ lerror("name() 1");
+ sb->sb_name = sym->s_name;
+ sb->sb_len = strlen(sym->s_name);
+ tok = sym->s_scl == TYPEDEF ? T_TYPENAME : T_NAME;
+ } else {
+ s = getblk(yyleng + 1);
+ (void)memcpy(s, yytext, yyleng + 1);
+ sb->sb_name = s;
+ sb->sb_len = yyleng;
+ tok = T_NAME;
+ }
+
+ yylval.y_sb = sb;
+ return (tok);
+}
+
+static sym_t *
+search(sb)
+ sbuf_t *sb;
+{
+ sym_t *sym;
+
+ for (sym = symtab[sb->sb_hash]; sym != NULL; sym = sym->s_link) {
+ if (strcmp(sym->s_name, sb->sb_name) == 0) {
+ if (sym->s_keyw || sym->s_kind == symtyp)
+ return (sym);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+keyw(sym)
+ sym_t *sym;
+{
+ int t;
+
+ if ((t = (int)sym->s_value.v_quad) == T_SCLASS) {
+ yylval.y_scl = sym->s_scl;
+ } else if (t == T_TYPE || t == T_SOU) {
+ yylval.y_tspec = sym->s_tspec;
+ } else if (t == T_QUAL) {
+ yylval.y_tqual = sym->s_tqual;
+ }
+ return (t);
+}
+
+/*
+ * Convert a string representing an integer into internal representation.
+ * The value is returned in yylval. icon() (and yylex()) returns T_CON.
+ */
+static int
+icon(base)
+ int base;
+{
+ int l_suffix, u_suffix;
+ int len;
+ const char *cp;
+ char c, *eptr;
+ tspec_t typ;
+ u_long ul;
+ u_quad_t uq;
+ int ansiu;
+ static tspec_t contypes[2][3] = {
+ { INT, LONG, QUAD },
+ { UINT, ULONG, UQUAD }
+ };
+
+ cp = yytext;
+ len = yyleng;
+
+ /* skip 0x */
+ if (base == 16) {
+ cp += 2;
+ len -= 2;
+ }
+
+ /* read suffixes */
+ l_suffix = u_suffix = 0;
+ for ( ; ; ) {
+ if ((c = cp[len - 1]) == 'l' || c == 'L') {
+ l_suffix++;
+ } else if (c == 'u' || c == 'U') {
+ u_suffix++;
+ } else {
+ break;
+ }
+ len--;
+ }
+ if (l_suffix > 2 || u_suffix > 1) {
+ /* malformed integer constant */
+ warning(251);
+ if (l_suffix > 2)
+ l_suffix = 2;
+ if (u_suffix > 1)
+ u_suffix = 1;
+ }
+ if (tflag && u_suffix != 0) {
+ /* suffix U is illegal in traditional C */
+ warning(97);
+ }
+ typ = contypes[u_suffix][l_suffix];
+
+ errno = 0;
+ if (l_suffix < 2) {
+ ul = strtoul(cp, &eptr, base);
+ } else {
+ uq = strtouq(cp, &eptr, base);
+ }
+ if (eptr != cp + len)
+ lerror("icon() 1");
+ if (errno != 0)
+ /* integer constant out of range */
+ warning(252);
+
+ /*
+ * If the value is to big for the current type, we must choose
+ * another type.
+ */
+ ansiu = 0;
+ switch (typ) {
+ case INT:
+ if (ul <= INT_MAX) {
+ /* ok */
+ } else if (ul <= (unsigned)UINT_MAX && base != 10) {
+ typ = UINT;
+ } else if (ul <= LONG_MAX) {
+ typ = LONG;
+ } else {
+ typ = ULONG;
+ }
+ if (typ == UINT || typ == ULONG) {
+ if (tflag) {
+ typ = LONG;
+ } else if (!sflag) {
+ /*
+ * Remember that the constant is unsigned
+ * only in ANSI C
+ */
+ ansiu = 1;
+ }
+ }
+ break;
+ case UINT:
+ if (ul > (u_int)UINT_MAX)
+ typ = ULONG;
+ break;
+ case LONG:
+ if (ul > LONG_MAX && !tflag) {
+ typ = ULONG;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ case QUAD:
+ if (uq > QUAD_MAX && !tflag) {
+ typ = UQUAD;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ default:
+ }
+
+ if (typ != QUAD && typ != UQUAD) {
+ if (isutyp(typ)) {
+ uq = ul;
+ } else {
+ uq = (quad_t)(long)ul;
+ }
+ }
+
+ uq = (u_quad_t)xsign((quad_t)uq, typ, -1);
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ yylval.y_val->v_ansiu = ansiu;
+ yylval.y_val->v_quad = (quad_t)uq;
+
+ return (T_CON);
+}
+
+/*
+ * Returns 1 if t is a signed type and the value is negative.
+ *
+ * len is the number of significant bits. If len is -1, len is set
+ * to the width of type t.
+ */
+int
+sign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (t == PTR || isutyp(t))
+ return (0);
+ return (msb(q, t, len));
+}
+
+int
+msb(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+ return ((q & qbmasks[len - 1]) != 0);
+}
+
+/*
+ * Extends the sign of q.
+ */
+quad_t
+xsign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+
+ if (t == PTR || isutyp(t) || !sign(q, t, len)) {
+ q &= qlmasks[len];
+ } else {
+ q |= qumasks[len];
+ }
+ return (q);
+}
+
+/*
+ * Convert a string representing a floating point value into its interal
+ * representation. Type and value are returned in yylval. fcon()
+ * (and yylex()) returns T_CON.
+ * XXX Currently it is not possible to convert constants of type
+ * long double which are greater then DBL_MAX.
+ */
+static int
+fcon()
+{
+ const char *cp;
+ int len;
+ tspec_t typ;
+ char c, *eptr;
+ double d;
+ float f;
+
+ cp = yytext;
+ len = yyleng;
+
+ if ((c = cp[len - 1]) == 'f' || c == 'F') {
+ typ = FLOAT;
+ len--;
+ } else if (c == 'l' || c == 'L') {
+ typ = LDOUBLE;
+ len--;
+ } else {
+ typ = DOUBLE;
+ }
+
+ if (tflag && typ != DOUBLE) {
+ /* suffixes F and L are illegal in traditional C */
+ warning(98);
+ }
+
+ errno = 0;
+ d = strtod(cp, &eptr);
+ if (eptr != cp + len)
+ lerror("fcon() 1");
+ if (errno != 0)
+ /* floating-point constant out of range */
+ warning(248);
+
+ if (typ == FLOAT) {
+ f = (float)d;
+ if (isinf(f)) {
+ /* floating-point constant out of range */
+ warning(248);
+ f = f > 0 ? FLT_MAX : -FLT_MAX;
+ }
+ }
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ if (typ == FLOAT) {
+ yylval.y_val->v_ldbl = f;
+ } else {
+ yylval.y_val->v_ldbl = d;
+ }
+
+ return (T_CON);
+}
+
+static int
+operator(t, o)
+ int t;
+ op_t o;
+{
+ yylval.y_op = o;
+ return (t);
+}
+
+/*
+ * Called if lex found a leading \'.
+ */
+static int
+ccon()
+{
+ int n, val, c;
+ char cv;
+
+ n = 0;
+ val = 0;
+ while ((c = getescc('\'')) >= 0) {
+ val = (val << CHAR_BIT) + c;
+ n++;
+ }
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else {
+ if (n > sizeof (int) || (n > 1 && (pflag || hflag))) {
+ /* too many characters in character constant */
+ error(71);
+ } else if (n > 1) {
+ /* multi-character character constant */
+ warning(294);
+ } else if (n == 0) {
+ /* empty character constant */
+ error(73);
+ }
+ }
+ if (n == 1) {
+ cv = (char)val;
+ val = cv;
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = INT;
+ yylval.y_val->v_quad = val;
+
+ return (T_CON);
+}
+
+/*
+ * Called if lex found a leading L\'
+ */
+static int
+wccon()
+{
+ static char buf[MB_LEN_MAX + 1];
+ int i, c;
+ wchar_t wc;
+
+ i = 0;
+ while ((c = getescc('\'')) >= 0) {
+ if (i < MB_CUR_MAX)
+ buf[i] = (char)c;
+ i++;
+ }
+
+ wc = 0;
+
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else if (c == 0) {
+ /* empty character constant */
+ error(73);
+ } else {
+ if (i > MB_CUR_MAX) {
+ i = MB_CUR_MAX;
+ /* too many characters in character constant */
+ error(71);
+ } else {
+ buf[i] = '\0';
+ (void)mbtowc(NULL, NULL, 0);
+ if (mbtowc(&wc, buf, MB_CUR_MAX) < 0)
+ /* invalid multibyte character */
+ error(291);
+ }
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = WCHAR;
+ yylval.y_val->v_quad = wc;
+
+ return (T_CON);
+}
+
+/*
+ * Read a character which is part of a character constant or of a string
+ * and handle escapes.
+ *
+ * The Argument is the character which delimits the character constant or
+ * string.
+ *
+ * Returns -1 if the end of the character constant or string is reached,
+ * -2 if the EOF is reached, and the charachter otherwise.
+ */
+static int
+getescc(d)
+ int d;
+{
+ static int pbc = -1;
+ int n, c, v;
+
+ if (pbc == -1) {
+ c = inpc();
+ } else {
+ c = pbc;
+ pbc = -1;
+ }
+ if (c == d)
+ return (-1);
+ switch (c) {
+ case '\n':
+ /* newline in string or char constant */
+ error(254);
+ return (-2);
+ case EOF:
+ return (-2);
+ case '\\':
+ switch (c = inpc()) {
+ case '"':
+ if (tflag && d == '\'')
+ /* \" inside character constant undef. ... */
+ warning(262);
+ return ('"');
+ case '\'':
+ return ('\'');
+ case '?':
+ if (tflag)
+ /* \? undefined in traditional C */
+ warning(263);
+ return ('?');
+ case '\\':
+ return ('\\');
+ case 'a':
+ if (tflag)
+ /* \a undefined in traditional C */
+ warning(81);
+#ifdef __STDC__
+ return ('\a');
+#else
+ return ('\007');
+#endif
+ case 'b':
+ return ('\b');
+ case 'f':
+ return ('\f');
+ case 'n':
+ return ('\n');
+ case 'r':
+ return ('\r');
+ case 't':
+ return ('\t');
+ case 'v':
+ if (tflag)
+ /* \v undefined in traditional C */
+ warning(264);
+#ifdef __STDC__
+ return ('\v');
+#else
+ return ('\013');
+#endif
+ case '8': case '9':
+ /* bad octal digit %c */
+ warning(77, c);
+ /* FALLTHROUGH */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = 3;
+ v = 0;
+ do {
+ v = (v << 3) + (c - '0');
+ c = inpc();
+ } while (--n && isdigit(c) && (tflag || c <= '7'));
+ if (tflag && n > 0 && isdigit(c))
+ /* bad octal digit %c */
+ warning(77, c);
+ pbc = c;
+ if (v > UCHAR_MAX) {
+ /* character escape does not fit in char. */
+ warning(76);
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case 'x':
+ if (tflag)
+ /* \x undefined in traditional C */
+ warning(82);
+ v = 0;
+ n = 0;
+ while ((c = inpc()) >= 0 && isxdigit(c)) {
+ c = isdigit(c) ?
+ c - '0' : toupper(c) - 'A' + 10;
+ v = (v << 4) + c;
+ if (n >= 0) {
+ if ((v & ~CHAR_MASK) != 0) {
+ /* overflow in hex escape */
+ warning(75);
+ n = -1;
+ } else {
+ n++;
+ }
+ }
+ }
+ pbc = c;
+ if (n == 0) {
+ /* no hex digits follow \x */
+ error(74);
+ } if (n == -1) {
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case '\n':
+ return (getescc(d));
+ case EOF:
+ return (-2);
+ default:
+ if (isprint(c)) {
+ /* dubious escape \%c */
+ warning(79, c);
+ } else {
+ /* dubious escape \%o */
+ warning(80, c);
+ }
+ }
+ }
+ return (c);
+}
+
+/*
+ * Called for preprocessor directives. Currently implemented are:
+ * # lineno
+ * # lineno "filename"
+ */
+static void
+directive()
+{
+ const char *cp, *fn;
+ char c, *eptr;
+ size_t fnl;
+ long ln;
+ static int first = 1;
+
+ /* Go to first non-whitespace after # */
+ for (cp = yytext + 1; (c = *cp) == ' ' || c == '\t'; cp++) ;
+
+ if (!isdigit(c)) {
+ error:
+ /* undefined or invalid # directive */
+ warning(255);
+ return;
+ }
+ ln = strtol(--cp, &eptr, 10);
+ if (cp == eptr)
+ goto error;
+ if ((c = *(cp = eptr)) != ' ' && c != '\t' && c != '\0')
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+ if (c != '\0') {
+ if (c != '"')
+ goto error;
+ fn = cp;
+ while ((c = *cp) != '"' && c != '\0')
+ cp++;
+ if (c != '"')
+ goto error;
+ if ((fnl = cp++ - fn) > PATH_MAX)
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+#if 0
+ if (c != '\0')
+ warning("extra character(s) after directive");
+#endif
+ curr_pos.p_file = fnnalloc(fn, fnl);
+ /*
+ * If this is the first directive, the name is the name
+ * of the C source file as specified at the command line.
+ * It is written to the output file.
+ */
+ if (first) {
+ csrc_pos.p_file = curr_pos.p_file;
+ outsrc(curr_pos.p_file);
+ first = 0;
+ }
+ }
+ curr_pos.p_line = (int)ln - 1;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line = (int)ln - 1;
+}
+
+/*
+ * Handle lint comments. Following comments are currently understood:
+ * ARGSUSEDn
+ * CONSTCOND CONSTANTCOND CONSTANTCONDITION
+ * FALLTHRU FALLTHROUGH
+ * LINTLIBRARY
+ * LINTED NOSTRICT
+ * LONGLONG
+ * NOTREACHED
+ * PRINTFLIKEn
+ * PROTOLIB
+ * SCANFLIKEn
+ * VARARGSn
+ * If one of this comments is recognized, the arguments, if any, are
+ * parsed and a function which handles this comment is called.
+ */
+static void
+comment()
+{
+ int c, lc;
+ static struct {
+ const char *keywd;
+ int arg;
+ void (*func) __P((int));
+ } keywtab[] = {
+ { "ARGSUSED", 1, argsused },
+ { "CONSTCOND", 0, constcond },
+ { "CONSTANTCOND", 0, constcond },
+ { "CONSTANTCONDITION", 0, constcond },
+ { "FALLTHRU", 0, fallthru },
+ { "FALLTHROUGH", 0, fallthru },
+ { "LINTLIBRARY", 0, lintlib },
+ { "LINTED", 0, linted },
+ { "LONGLONG", 0, longlong },
+ { "NOSTRICT", 0, linted },
+ { "NOTREACHED", 0, notreach },
+ { "PRINTFLIKE", 1, printflike },
+ { "PROTOLIB", 1, protolib },
+ { "SCANFLIKE", 1, scanflike },
+ { "VARARGS", 1, varargs },
+ };
+ char keywd[32];
+ char arg[32];
+ int l, i, a;
+ int eoc;
+
+ eoc = 0;
+
+ /* Skip white spaces after the start of the comment */
+ while ((c = inpc()) != EOF && isspace(c)) ;
+
+ /* Read the potential keyword to keywd */
+ l = 0;
+ while (c != EOF && isupper(c) && l < sizeof (keywd) - 1) {
+ keywd[l++] = (char)c;
+ c = inpc();
+ }
+ keywd[l] = '\0';
+
+ /* look for the keyword */
+ for (i = 0; i < sizeof (keywtab) / sizeof (keywtab[0]); i++) {
+ if (strcmp(keywtab[i].keywd, keywd) == 0)
+ break;
+ }
+ if (i == sizeof (keywtab) / sizeof (keywtab[0]))
+ goto skip_rest;
+
+ /* skip white spaces after the keyword */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ /* read the argument, if the keyword accepts one and there is one */
+ l = 0;
+ if (keywtab[i].arg) {
+ while (c != EOF && isdigit(c) && l < sizeof (arg) - 1) {
+ arg[l++] = (char)c;
+ c = inpc();
+ }
+ }
+ arg[l] = '\0';
+ a = l != 0 ? atoi(arg) : -1;
+
+ /* skip white spaces after the argument */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ if (c != '*' || (c = inpc()) != '/') {
+ if (keywtab[i].func != linted)
+ /* extra characters in lint comment */
+ warning(257);
+ } else {
+ /*
+ * remember that we have already found the end of the
+ * comment
+ */
+ eoc = 1;
+ }
+
+ if (keywtab[i].func != NULL)
+ (*keywtab[i].func)(a);
+
+ skip_rest:
+ while (!eoc) {
+ lc = c;
+ if ((c = inpc()) == EOF) {
+ /* unterminated comment */
+ error(256);
+ break;
+ }
+ if (lc == '*' && c == '/')
+ eoc = 1;
+ }
+}
+
+/*
+ * Clear flags for lint comments LINTED, LONGLONG and CONSTCOND.
+ * clrwflgs() is called after function definitions and global and
+ * local declarations and definitions. It is also called between
+ * the controlling expression and the body of control statements
+ * (if, switch, for, while).
+ */
+void
+clrwflgs()
+{
+ nowarn = 0;
+ quadflg = 0;
+ ccflg = 0;
+}
+
+/*
+ * Strings are stored in a dynamically alloceted buffer and passed
+ * in yylval.y_xstrg to the parser. The parser or the routines called
+ * by the parser are responsible for freeing this buffer.
+ */
+static int
+string()
+{
+ u_char *s;
+ int c;
+ size_t len, max;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to reserve space for a trailing NUL character */
+ if (len + 1 == max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = CHAR;
+ strg->st_len = len;
+ strg->st_cp = s;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+static int
+wcstrg()
+{
+ char *s;
+ int c, i, n, wi;
+ size_t len, max, wlen;
+ wchar_t *ws;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to save space for a trailing NUL character */
+ if (len + 1 >= max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ /* get length of wide character string */
+ (void)mblen(NULL, 0);
+ for (i = 0, wlen = 0; i < len; i += n, wlen++) {
+ if ((n = mblen(&s[i], MB_CUR_MAX)) == -1) {
+ /* invalid multibyte character */
+ error(291);
+ break;
+ }
+ if (n == 0)
+ n = 1;
+ }
+
+ ws = xmalloc((wlen + 1) * sizeof (wchar_t));
+
+ /* convert from multibyte to wide char */
+ (void)mbtowc(NULL, NULL, 0);
+ for (i = 0, wi = 0; i < len; i += n, wi++) {
+ if ((n = mbtowc(&ws[wi], &s[i], MB_CUR_MAX)) == -1)
+ break;
+ if (n == 0)
+ n = 1;
+ }
+ ws[wi] = 0;
+ free(s);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = WCHAR;
+ strg->st_len = wlen;
+ strg->st_wcp = ws;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+/*
+ * As noted above the scanner does not create new symbol table entries
+ * for symbols it cannot find in the symbol table. This is to avoid
+ * putting undeclared symbols into the symbol table if a syntax error
+ * occurs.
+ *
+ * getsym() is called as soon as it is probably ok to put the symbol to
+ * the symbol table. This does not mean that it is not possible that
+ * symbols are put to the symbol table which are than not completely
+ * declared due to syntax errors. To avoid too many problems in this
+ * case symbols get type int in getsym().
+ *
+ * XXX calls to getsym() should be delayed until decl1*() is called
+ */
+sym_t *
+getsym(sb)
+ sbuf_t *sb;
+{
+ dinfo_t *di;
+ char *s;
+ sym_t *sym;
+
+ sym = sb->sb_sym;
+
+ /*
+ * During member declaration it is possible that name() looked
+ * for symbols of type FVFT, although it should have looked for
+ * symbols of type FTAG. Same can happen for labels. Both cases
+ * are compensated here.
+ */
+ if (symtyp == FMOS || symtyp == FLAB) {
+ if (sym == NULL || sym->s_kind == FVFT)
+ sym = search(sb);
+ }
+
+ if (sym != NULL) {
+ if (sym->s_kind != symtyp)
+ lerror("storesym() 1");
+ symtyp = FVFT;
+ freesb(sb);
+ return (sym);
+ }
+
+ /* create a new symbol table entry */
+
+ /* labels must always be allocated at level 1 (outhermost block) */
+ if (symtyp == FLAB) {
+ sym = getlblk(1, sizeof (sym_t));
+ s = getlblk(1, sb->sb_len + 1);
+ (void)memcpy(s, sb->sb_name, sb->sb_len + 1);
+ sym->s_name = s;
+ sym->s_blklev = 1;
+ di = dcs;
+ while (di->d_nxt != NULL && di->d_nxt->d_nxt != NULL)
+ di = di->d_nxt;
+ if (di->d_ctx != AUTO)
+ lerror("storesym() 2");
+ } else {
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = sb->sb_name;
+ sym->s_blklev = blklev;
+ di = dcs;
+ }
+
+ STRUCT_ASSIGN(sym->s_dpos, curr_pos);
+ if ((sym->s_kind = symtyp) != FLAB)
+ sym->s_type = gettyp(INT);
+
+ symtyp = FVFT;
+
+ if ((sym->s_link = symtab[sb->sb_hash]) != NULL)
+ symtab[sb->sb_hash]->s_rlink = &sym->s_link;
+ (symtab[sb->sb_hash] = sym)->s_rlink = &symtab[sb->sb_hash];
+
+ *di->d_ldlsym = sym;
+ di->d_ldlsym = &sym->s_dlnxt;
+
+ freesb(sb);
+ return (sym);
+}
+
+/*
+ * Remove a symbol forever from the symbol table. s_blklev
+ * is set to -1 to avoid that the symbol will later be put
+ * back to the symbol table.
+ */
+void
+rmsym(sym)
+ sym_t *sym;
+{
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_blklev = -1;
+ sym->s_link = NULL;
+}
+
+/*
+ * Remove a list of symbols declared at one level from the symbol
+ * table.
+ */
+void
+rmsyms(syms)
+ sym_t *syms;
+{
+ sym_t *sym;
+
+ for (sym = syms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_link = NULL;
+ sym->s_rlink = NULL;
+ }
+ }
+}
+
+/*
+ * Put a symbol into the symbol table
+ */
+void
+inssym(bl, sym)
+ int bl;
+ sym_t *sym;
+{
+ int h;
+
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ sym->s_blklev = bl;
+ if (sym->s_link != NULL && sym->s_blklev < sym->s_link->s_blklev)
+ lerror("inssym()");
+}
+
+/*
+ * Called at level 0 after syntax errors
+ * Removes all symbols which are not declared at level 0 from the
+ * symbol table. Also frees all memory which is not associated with
+ * level 0.
+ */
+void
+cleanup()
+{
+ sym_t *sym, *nsym;
+ int i;
+
+ for (i = 0; i < HSHSIZ1; i++) {
+ for (sym = symtab[i]; sym != NULL; sym = nsym) {
+ nsym = sym->s_link;
+ if (sym->s_blklev >= 1) {
+ if ((*sym->s_rlink = nsym) != NULL)
+ nsym->s_rlink = sym->s_rlink;
+ }
+ }
+ }
+
+ for (i = mblklev; i > 0; i--)
+ freelblk(i);
+}
+
+/*
+ * Create a new symbol with the name of an existing symbol.
+ */
+sym_t *
+pushdown(sym)
+ sym_t *sym;
+{
+ int h;
+ sym_t *nsym;
+
+ h = hash(sym->s_name);
+ nsym = getblk(sizeof (sym_t));
+ if (sym->s_blklev > blklev)
+ lerror("pushdown()");
+ nsym->s_name = sym->s_name;
+ STRUCT_ASSIGN(nsym->s_dpos, curr_pos);
+ nsym->s_kind = sym->s_kind;
+ nsym->s_blklev = blklev;
+
+ if ((nsym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &nsym->s_link;
+ (symtab[h] = nsym)->s_rlink = &symtab[h];
+
+ *dcs->d_ldlsym = nsym;
+ dcs->d_ldlsym = &nsym->s_dlnxt;
+
+ return (nsym);
+}
+
+/*
+ * Free any dynamically allocated memory referenced by
+ * the value stack or yylval.
+ * The type of information in yylval is described by tok.
+ */
+void
+freeyyv(sp, tok)
+ void *sp;
+ int tok;
+{
+ if (tok == T_NAME || tok == T_TYPENAME) {
+ sbuf_t *sb = *(sbuf_t **)sp;
+ freesb(sb);
+ } else if (tok == T_CON) {
+ val_t *val = *(val_t **)sp;
+ free(val);
+ } else if (tok == T_STRING) {
+ strg_t *strg = *(strg_t **)sp;
+ if (strg->st_tspec == CHAR) {
+ free(strg->st_cp);
+ } else if (strg->st_tspec == WCHAR) {
+ free(strg->st_wcp);
+ } else {
+ lerror("fryylv() 1");
+ }
+ free(strg);
+ }
+}
diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c
new file mode 100644
index 0000000..5770f08
--- /dev/null
+++ b/usr.bin/xlint/lint1/tree.c
@@ -0,0 +1,3927 @@
+/* $NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/* Various flags for each operator. */
+static mod_t modtab[NOPS];
+
+static tnode_t *getinode __P((tspec_t, quad_t));
+static void ptrcmpok __P((op_t, tnode_t *, tnode_t *));
+static int asgntypok __P((op_t, int, tnode_t *, tnode_t *));
+static void chkbeop __P((op_t, tnode_t *, tnode_t *));
+static void chkeop2 __P((op_t, int, tnode_t *, tnode_t *));
+static void chkeop1 __P((op_t, int, tnode_t *, tnode_t *));
+static tnode_t *mktnode __P((op_t, type_t *, tnode_t *, tnode_t *));
+static void balance __P((op_t, tnode_t **, tnode_t **));
+static void incompat __P((op_t, tspec_t, tspec_t));
+static void illptrc __P((mod_t *, type_t *, type_t *));
+static void mrgqual __P((type_t **, type_t *, type_t *));
+static int conmemb __P((type_t *));
+static void ptconv __P((int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void iiconv __P((op_t, int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void piconv __P((op_t, tspec_t, type_t *, tnode_t *));
+static void ppconv __P((op_t, tnode_t *, type_t *));
+static tnode_t *bldstr __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldincdec __P((op_t, tnode_t *));
+static tnode_t *bldamper __P((tnode_t *, int));
+static tnode_t *bldplmi __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldshft __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldcol __P((tnode_t *, tnode_t *));
+static tnode_t *bldasgn __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *plength __P((type_t *));
+static tnode_t *fold __P((tnode_t *));
+static tnode_t *foldtst __P((tnode_t *));
+static tnode_t *foldflt __P((tnode_t *));
+static tnode_t *chkfarg __P((type_t *, tnode_t *));
+static tnode_t *parg __P((int, type_t *, tnode_t *));
+static void nulleff __P((tnode_t *));
+static void displexpr __P((tnode_t *, int));
+static void chkaidx __P((tnode_t *, int));
+static void chkcomp __P((op_t, tnode_t *, tnode_t *));
+static void precconf __P((tnode_t *));
+
+/*
+ * Initialize mods of operators.
+ */
+void
+initmtab()
+{
+ static struct {
+ op_t op;
+ mod_t m;
+ } imods[] = {
+ { ARROW, { 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "->" } },
+ { POINT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "." } },
+ { NOT, { 0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "!" } },
+ { COMPL, { 0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,
+ "~" } },
+ { INCBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix++" } },
+ { DECBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix--" } },
+ { INCAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix++" } },
+ { DECAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix--" } },
+ { UPLUS, { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,
+ "unary +" } },
+ { UMINUS, { 0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,1,1,
+ "unary -" } },
+ { STAR, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "unary *" } },
+ { AMPER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "unary &" } },
+ { MULT, { 1,0,0,0,1,1,1,0,1,0,0,1,0,0,0,1,1,
+ "*" } },
+ { DIV, { 1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1,1,
+ "/" } },
+ { MOD, { 1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,1,
+ "%" } },
+ { PLUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "+" } },
+ { MINUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "-" } },
+ { SHL, { 1,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,1,
+ "<<" } },
+ { SHR, { 1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,
+ ">>" } },
+ { LT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<" } },
+ { LE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<=" } },
+ { GT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">" } },
+ { GE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">=" } },
+ { EQ, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "==" } },
+ { NE, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "!=" } },
+ { AND, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "&" } },
+ { XOR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "^" } },
+ { OR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "|" } },
+ { LOGAND, { 1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "&&" } },
+ { LOGOR, { 1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,
+ "||" } },
+ { QUEST, { 1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
+ "?" } },
+ { COLON, { 1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
+ ":" } },
+ { ASSIGN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "=" } },
+ { MULASS, { 1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,
+ "*=" } },
+ { DIVASS, { 1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,
+ "/=" } },
+ { MODASS, { 1,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,
+ "%=" } },
+ { ADDASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "+=" } },
+ { SUBASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "-=" } },
+ { SHLASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "<<=" } },
+ { SHRASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ ">>=" } },
+ { ANDASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "&=" } },
+ { XORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "^=" } },
+ { ORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "|=" } },
+ { NAME, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "NAME" } },
+ { CON, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "CON" } },
+ { STRING, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "STRING" } },
+ { FSEL, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "FSEL" } },
+ { CALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "CALL" } },
+ { COMMA, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
+ "," } },
+ { CVT, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "CVT" } },
+ { ICALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "ICALL" } },
+ { LOAD, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "LOAD" } },
+ { PUSH, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "PUSH" } },
+ { RETURN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "RETURN" } },
+ { INIT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "INIT" } },
+ { FARG, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "FARG" } },
+ { NOOP }
+ };
+ int i;
+
+ for (i = 0; imods[i].op != NOOP; i++)
+ STRUCT_ASSIGN(modtab[imods[i].op], imods[i].m);
+}
+
+/*
+ * Increase degree of reference.
+ * This is most often used to change type "T" in type "pointer to T".
+ */
+type_t *
+incref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = getblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * same for use in expressions
+ */
+type_t *
+tincref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = tgetblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * Create a node for a constant.
+ */
+tnode_t *
+getcnode(tp, v)
+ type_t *tp;
+ val_t *v;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = tp;
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = tp->t_tspec;
+ n->tn_val->v_ansiu = v->v_ansiu;
+ n->tn_val->v_u = v->v_u;
+ free(v);
+ return (n);
+}
+
+/*
+ * Create a node for a integer constant.
+ */
+static tnode_t *
+getinode(t, q)
+ tspec_t t;
+ quad_t q;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = gettyp(t);
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = t;
+ n->tn_val->v_quad = q;
+ return (n);
+}
+
+/*
+ * Create a node for a name (symbol table entry).
+ * ntok is the token which follows the name.
+ */
+tnode_t *
+getnnode(sym, ntok)
+ sym_t *sym;
+ int ntok;
+{
+ tnode_t *n;
+
+ if (sym->s_scl == NOSCL) {
+ sym->s_scl = EXTERN;
+ sym->s_def = DECL;
+ if (ntok == T_LPARN) {
+ if (sflag) {
+ /* function implicitly declared to ... */
+ warning(215);
+ }
+ /*
+ * XXX if tflag is set the symbol should be
+ * exported to level 0
+ */
+ sym->s_type = incref(sym->s_type, FUNC);
+ } else {
+ /* %s undefined */
+ error(99, sym->s_name);
+ }
+ }
+
+ if (sym->s_kind != FVFT && sym->s_kind != FMOS)
+ lerror("getnnode() 1");
+
+ n = getnode();
+ n->tn_type = sym->s_type;
+ if (sym->s_scl != ENUMCON) {
+ n->tn_op = NAME;
+ n->tn_sym = sym;
+ if (sym->s_kind == FVFT && sym->s_type->t_tspec != FUNC)
+ n->tn_lvalue = 1;
+ } else {
+ n->tn_op = CON;
+ n->tn_val = tgetblk(sizeof (val_t));
+ *n->tn_val = sym->s_value;
+ }
+
+ return (n);
+}
+
+/*
+ * Create a node for a string.
+ */
+tnode_t *
+getsnode(strg)
+ strg_t *strg;
+{
+ size_t len;
+ tnode_t *n;
+
+ len = strg->st_len;
+
+ n = getnode();
+
+ n->tn_op = STRING;
+ n->tn_type = tincref(gettyp(strg->st_tspec), ARRAY);
+ n->tn_type->t_dim = len + 1;
+ n->tn_lvalue = 1;
+
+ n->tn_strg = tgetblk(sizeof (strg_t));
+ n->tn_strg->st_tspec = strg->st_tspec;
+ n->tn_strg->st_len = len;
+
+ if (strg->st_tspec == CHAR) {
+ n->tn_strg->st_cp = tgetblk(len + 1);
+ (void)memcpy(n->tn_strg->st_cp, strg->st_cp, len + 1);
+ free(strg->st_cp);
+ } else {
+ n->tn_strg->st_wcp = tgetblk((len + 1) * sizeof (wchar_t));
+ (void)memcpy(n->tn_strg->st_wcp, strg->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ free(strg->st_wcp);
+ }
+ free(strg);
+
+ return (n);
+}
+
+/*
+ * Returns a symbol which has the same name as the msym argument and is a
+ * member of the struct or union specified by the tn argument.
+ */
+sym_t *
+strmemb(tn, op, msym)
+ tnode_t *tn;
+ op_t op;
+ sym_t *msym;
+{
+ str_t *str;
+ type_t *tp;
+ sym_t *sym, *csym;
+ int eq;
+ tspec_t t;
+
+ /*
+ * Remove the member if it was unknown until now (Which means
+ * that no defined struct or union has a member with the same name).
+ */
+ if (msym->s_scl == NOSCL) {
+ /* undefined struct/union member: %s */
+ error(101, msym->s_name);
+ rmsym(msym);
+ msym->s_kind = FMOS;
+ msym->s_scl = MOS;
+ msym->s_styp = tgetblk(sizeof (str_t));
+ msym->s_styp->stag = tgetblk(sizeof (sym_t));
+ msym->s_styp->stag->s_name = unnamed;
+ msym->s_value.v_tspec = INT;
+ return (msym);
+ }
+
+ /* Set str to the tag of which msym is expected to be a member. */
+ str = NULL;
+ t = (tp = tn->tn_type)->t_tspec;
+ if (op == POINT) {
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ } else if (op == ARROW && t == PTR) {
+ t = (tp = tp->t_subt)->t_tspec;
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ }
+
+ /*
+ * If this struct/union has a member with the name of msym, return
+ * return this it.
+ */
+ if (str != NULL) {
+ for (sym = msym; sym != NULL; sym = sym->s_link) {
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (sym->s_styp != str)
+ continue;
+ if (strcmp(sym->s_name, msym->s_name) != 0)
+ continue;
+ return (sym);
+ }
+ }
+
+ /*
+ * Set eq to 0 if there are struct/union members with the same name
+ * and different types and/or offsets.
+ */
+ eq = 1;
+ for (csym = msym; csym != NULL; csym = csym->s_link) {
+ if (csym->s_scl != MOS && csym->s_scl != MOU)
+ continue;
+ if (strcmp(msym->s_name, csym->s_name) != 0)
+ continue;
+ for (sym = csym->s_link ; sym != NULL; sym = sym->s_link) {
+ int w;
+
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (strcmp(csym->s_name, sym->s_name) != 0)
+ continue;
+ if (csym->s_value.v_quad != sym->s_value.v_quad) {
+ eq = 0;
+ break;
+ }
+ w = 0;
+ eq = eqtype(csym->s_type, sym->s_type, 0, 0, &w) && !w;
+ if (!eq)
+ break;
+ if (csym->s_field != sym->s_field) {
+ eq = 0;
+ break;
+ }
+ if (csym->s_field) {
+ type_t *tp1, *tp2;
+
+ tp1 = csym->s_type;
+ tp2 = sym->s_type;
+ if (tp1->t_flen != tp2->t_flen) {
+ eq = 0;
+ break;
+ }
+ if (tp1->t_foffs != tp2->t_foffs) {
+ eq = 0;
+ break;
+ }
+ }
+ }
+ if (!eq)
+ break;
+ }
+
+ /*
+ * Now handle the case in which the left operand refers really
+ * to a struct/union, but the right operand is not member of it.
+ */
+ if (str != NULL) {
+ /* illegal member use: %s */
+ if (eq && tflag) {
+ warning(102, msym->s_name);
+ } else {
+ error(102, msym->s_name);
+ }
+ return (msym);
+ }
+
+ /*
+ * Now the left operand of ARROW does not point to a struct/union
+ * or the left operand of POINT is no struct/union.
+ */
+ if (eq) {
+ if (op == POINT) {
+ /* left operand of "." must be struct/union object */
+ if (tflag) {
+ warning(103);
+ } else {
+ error(103);
+ }
+ } else {
+ /* left operand of "->" must be pointer to ... */
+ if (tflag && tn->tn_type->t_tspec == PTR) {
+ warning(104);
+ } else {
+ error(104);
+ }
+ }
+ } else {
+ if (tflag) {
+ /* non-unique member requires struct/union %s */
+ error(105, op == POINT ? "object" : "pointer");
+ } else {
+ /* unacceptable operand of %s */
+ error(111, modtab[op].m_name);
+ }
+ }
+
+ return (msym);
+}
+
+/*
+ * Create a tree node. Called for most operands except function calls,
+ * sizeof and casts.
+ *
+ * op operator
+ * ln left operand
+ * rn if not NULL, right operand
+ */
+tnode_t *
+build(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tnode_t *ntn;
+ type_t *rtp;
+
+ mp = &modtab[op];
+
+ /* If there was an error in one of the operands, return. */
+ if (ln == NULL || (mp->m_binary && rn == NULL))
+ return (NULL);
+
+ /*
+ * Apply class conversions to the left operand, but only if its
+ * value is needed or it is compaired with null.
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = cconv(ln);
+ /*
+ * The right operand is almost always in a test or value context,
+ * except if it is a struct or union member.
+ */
+ if (mp->m_binary && op != ARROW && op != POINT)
+ rn = cconv(rn);
+
+ /*
+ * Print some warnings for comparisions of unsigned values with
+ * constants lower than or equal to null. This must be done
+ * before promote() because otherwise unsigned char and unsigned
+ * short would be promoted to int. Also types are tested to be
+ * CHAR, which would also become int.
+ */
+ if (mp->m_comp)
+ chkcomp(op, ln, rn);
+
+ /*
+ * Promote the left operand if it is in a test or value context
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = promote(op, 0, ln);
+ /*
+ * Promote the right operand, but only if it is no struct or
+ * union member, or if it is not to be assigned to the left operand
+ */
+ if (mp->m_binary && op != ARROW && op != POINT &&
+ op != ASSIGN && op != RETURN) {
+ rn = promote(op, 0, rn);
+ }
+
+ /*
+ * If the result of the operation is different for signed or
+ * unsigned operands and one of the operands is signed only in
+ * ANSI C, print a warning.
+ */
+ if (mp->m_tlansiu && ln->tn_op == CON && ln->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ ln->tn_val->v_ansiu = 0;
+ }
+ if (mp->m_transiu && rn->tn_op == CON && rn->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ rn->tn_val->v_ansiu = 0;
+ }
+
+ /* Make sure both operands are of the same type */
+ if (mp->m_balance || (tflag && (op == SHL || op == SHR)))
+ balance(op, &ln, &rn);
+
+ /*
+ * Check types for compatibility with the operation and mutual
+ * compatibility. Return if there are serios problems.
+ */
+ if (!typeok(op, 0, ln, rn))
+ return (NULL);
+
+ /* And now create the node. */
+ switch (op) {
+ case POINT:
+ case ARROW:
+ ntn = bldstr(op, ln, rn);
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ ntn = bldincdec(op, ln);
+ break;
+ case AMPER:
+ ntn = bldamper(ln, 0);
+ break;
+ case STAR:
+ ntn = mktnode(STAR, ln->tn_type->t_subt, ln, NULL);
+ break;
+ case PLUS:
+ case MINUS:
+ ntn = bldplmi(op, ln, rn);
+ break;
+ case SHL:
+ case SHR:
+ ntn = bldshft(op, ln, rn);
+ break;
+ case COLON:
+ ntn = bldcol(ln, rn);
+ break;
+ case ASSIGN:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ADDASS:
+ case SUBASS:
+ case SHLASS:
+ case SHRASS:
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ case RETURN:
+ ntn = bldasgn(op, ln, rn);
+ break;
+ case COMMA:
+ case QUEST:
+ ntn = mktnode(op, rn->tn_type, ln, rn);
+ break;
+ default:
+ rtp = mp->m_logop ? gettyp(INT) : ln->tn_type;
+ if (!mp->m_binary && rn != NULL)
+ lerror("build() 1");
+ ntn = mktnode(op, rtp, ln, rn);
+ break;
+ }
+
+ /* Return if an error occured. */
+ if (ntn == NULL)
+ return (NULL);
+
+ /* Print a warning if precedence confusion is possible */
+ if (mp->m_tpconf)
+ precconf(ntn);
+
+ /*
+ * Print a warning if one of the operands is in a context where
+ * it is compared with null and if this operand is a constant.
+ */
+ if (mp->m_tctx) {
+ if (ln->tn_op == CON ||
+ ((mp->m_binary && op != QUEST) && rn->tn_op == CON)) {
+ if (hflag && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ }
+
+ /* Fold if the operator requires it */
+ if (mp->m_fold) {
+ if (ln->tn_op == CON && (!mp->m_binary || rn->tn_op == CON)) {
+ if (mp->m_tctx) {
+ ntn = foldtst(ntn);
+ } else if (isftyp(ntn->tn_type->t_tspec)) {
+ ntn = foldflt(ntn);
+ } else {
+ ntn = fold(ntn);
+ }
+ } else if (op == QUEST && ln->tn_op == CON) {
+ ntn = ln->tn_val->v_quad ? rn->tn_left : rn->tn_right;
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Perform class conversions.
+ *
+ * Arrays of type T are converted into pointers to type T.
+ * Functions are converted to pointers to functions.
+ * Lvalues are converted to rvalues.
+ */
+tnode_t *
+cconv(tn)
+ tnode_t *tn;
+{
+ type_t *tp;
+
+ /*
+ * Array-lvalue (array of type T) is converted into rvalue
+ * (pointer to type T)
+ */
+ if (tn->tn_type->t_tspec == ARRAY) {
+ if (!tn->tn_lvalue) {
+ /* %soperand of '%s' must be lvalue */
+ /* XXX print correct operator */
+ (void)gnuism(114, "", modtab[AMPER].m_name);
+ }
+ tn = mktnode(AMPER, tincref(tn->tn_type->t_subt, PTR),
+ tn, NULL);
+ }
+
+ /*
+ * Expression of type function (function with return value of type T)
+ * in rvalue-expression (pointer to function with return value
+ * of type T)
+ */
+ if (tn->tn_type->t_tspec == FUNC)
+ tn = bldamper(tn, 1);
+
+ /* lvalue to rvalue */
+ if (tn->tn_lvalue) {
+ tp = tduptyp(tn->tn_type);
+ tp->t_const = tp->t_volatile = 0;
+ tn = mktnode(LOAD, tp, tn, NULL);
+ }
+
+ return (tn);
+}
+
+/*
+ * Perform most type checks. First the types are checked using
+ * informations from modtab[]. After that it is done by hand for
+ * more complicated operators and type combinations.
+ *
+ * If the types are ok, typeok() returns 1, otherwise 0.
+ */
+int
+typeok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tspec_t lt, rt, lst, rst, olt, ort;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ tnode_t *tn;
+
+ mp = &modtab[op];
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if (mp->m_binary) {
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ }
+
+ if (mp->m_rqint) {
+ /* integertypes required */
+ if (!isityp(lt) || (mp->m_binary && !isityp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqsclt) {
+ /* scalar types required */
+ if (!issclt(lt) || (mp->m_binary && !issclt(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqatyp) {
+ /* arithmetic types required */
+ if (!isatyp(lt) || (mp->m_binary && !isatyp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ }
+
+ if (op == SHL || op == SHR || op == SHLASS || op == SHRASS) {
+ /*
+ * For these operations we need the types before promotion
+ * and balancing.
+ */
+ for (tn=ln; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ olt = tn->tn_type->t_tspec;
+ for (tn=rn; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ ort = tn->tn_type->t_tspec;
+ }
+
+ switch (op) {
+ case POINT:
+ /*
+ * Most errors required by ANSI C are reported in strmemb().
+ * Here we only must check for totaly wrong things.
+ */
+ if (lt == FUNC || lt == VOID || ltp->t_isfield ||
+ ((lt != STRUCT && lt != UNION) && !ln->tn_lvalue)) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ /* Now we have an object we can create a pointer to */
+ break;
+ case ARROW:
+ if (lt != PTR && !(tflag && isityp(lt))) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptabel operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ /* operands have scalar types (checked above) */
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (ltp->t_const) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "", mp->m_name);
+ }
+ break;
+ case AMPER:
+ if (lt == ARRAY || lt == FUNC) {
+ /* ok, a warning comes later (in bldamper()) */
+ } else if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (issclt(lt)) {
+ if (ltp->t_isfield) {
+ /* cannot take address of bit-field */
+ error(112);
+ return (0);
+ }
+ } else if (lt != STRUCT && lt != UNION) {
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ if (ln->tn_op == NAME && ln->tn_sym->s_reg) {
+ /* cannot take address of register %s */
+ error(113, ln->tn_sym->s_name);
+ return (0);
+ }
+ break;
+ case STAR:
+ /* until now there were no type checks for this operator */
+ if (lt != PTR) {
+ /* cannot dereference non-pointer type */
+ error(96);
+ return (0);
+ }
+ break;
+ case PLUS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || (rt == PTR && !isityp(lt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ break;
+ case MINUS:
+ /* operands have scalar types (checked above) */
+ if (lt == PTR && (!isityp(rt) && rt != PTR)) {
+ incompat(op, lt, rt);
+ return (0);
+ } else if (rt == PTR && lt != PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ if (lt == PTR && rt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL)) {
+ /* illegal pointer subtraction */
+ error(116);
+ }
+ }
+ break;
+ case SHR:
+ /* operands have integer types (checked above) */
+ if (pflag && !isutyp(lt)) {
+ /*
+ * The left operand is signed. This means that
+ * the operation is (possibly) nonportable.
+ */
+ /* bitwise operation on signed value nonportable */
+ if (ln->tn_op != CON) {
+ /* possibly nonportable */
+ warning(117);
+ } else if (ln->tn_val->v_quad < 0) {
+ warning(120);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && isutyp(ort)) {
+ /*
+ * The left operand would become unsigned in
+ * traditional C.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && !isutyp(ort) &&
+ psize(lt) < psize(rt)) {
+ /*
+ * In traditional C the left operand would be extended,
+ * possibly with 1, and then shifted.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ }
+ goto shift;
+ case SHL:
+ /*
+ * ANSI C does not perform balancing for shift operations,
+ * but traditional C does. If the width of the right operand
+ * is greather than the width of the left operand, than in
+ * traditional C the left operand would be extendet to the
+ * width of the right operand. For SHL this may result in
+ * different results.
+ */
+ if (psize(lt) < psize(rt)) {
+ /*
+ * XXX If both operands are constant make sure
+ * that there is really a differencs between
+ * ANSI C and traditional C.
+ */
+ if (hflag)
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ shift:
+ if (rn->tn_op == CON) {
+ if (!isutyp(rt) && rn->tn_val->v_quad < 0) {
+ /* negative shift */
+ warning(121);
+ } else if ((u_quad_t)rn->tn_val->v_quad == size(lt)) {
+ /* shift equal to size fo object */
+ warning(267);
+ } else if ((u_quad_t)rn->tn_val->v_quad > size(lt)) {
+ /* shift greater than size of object */
+ warning(122);
+ }
+ }
+ break;
+ case EQ:
+ case NE:
+ /*
+ * Accept some things which are allowed with EQ and NE,
+ * but not with ordered comparisions.
+ */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+ /* FALLTHROUGH */
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ if ((lt == PTR || rt == PTR) && lt != rt) {
+ if (isityp(lt) || isityp(rt)) {
+ /* illegal comb. of pointer and int., op %s */
+ warning(123, mp->m_name);
+ } else {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (lt == PTR && rt == PTR) {
+ ptrcmpok(op, ln, rn);
+ }
+ break;
+ case QUEST:
+ if (!issclt(lt)) {
+ /* first operand must have scalar type, op ? : */
+ error(170);
+ return (0);
+ }
+ if (rn->tn_op != COLON)
+ lerror("typeok() 2");
+ break;
+ case COLON:
+
+ if (isatyp(lt) && isatyp(rt))
+ break;
+
+ if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str)
+ break;
+ if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str)
+ break;
+
+ /* combination of any pointer and 0, 0L or (void *)0 is ok */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+
+ if (lt == VOID || rt == VOID) {
+ if (lt != VOID || rt != VOID)
+ /* incompatible types in conditional */
+ warning(126);
+ break;
+ }
+
+ if (lt == PTR && rt == PTR && ((lst == VOID && rst == FUNC) ||
+ (lst == FUNC && rst == VOID))) {
+ /* (void *)0 handled above */
+ if (sflag)
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, "function pointer", "'void *'",
+ mp->m_name);
+ break;
+ }
+
+ if (rt == PTR && lt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL))
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+
+ /* incompatible types in conditional */
+ error(126);
+ return (0);
+
+ case ASSIGN:
+ case INIT:
+ case FARG:
+ case RETURN:
+ if (!asgntypok(op, arg, ln, rn))
+ return (0);
+ goto assign;
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ goto assign;
+ case ADDASS:
+ case SUBASS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || rt == PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ goto assign;
+ case SHLASS:
+ goto assign;
+ case SHRASS:
+ if (pflag && !isutyp(lt) && !(tflag && isutyp(rt))) {
+ /* bitwise operation on s.v. possibly nonportabel */
+ warning(117);
+ }
+ goto assign;
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ goto assign;
+ assign:
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "left ", mp->m_name);
+ return (0);
+ } else if (ltp->t_const || ((lt == STRUCT || lt == UNION) &&
+ conmemb(ltp))) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "left ", mp->m_name);
+ }
+ break;
+ case COMMA:
+ if (!modtab[ln->tn_op].m_sideeff)
+ nulleff(ln);
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ default:
+ }
+
+ if (mp->m_badeop &&
+ (ltp->t_isenum || (mp->m_binary && rtp->t_isenum))) {
+ chkbeop(op, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum && rtp->t_isenum)) {
+ chkeop2(op, arg, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum || rtp->t_isenum)) {
+ chkeop1(op, arg, ln, rn);
+ }
+
+ return (1);
+}
+
+static void
+ptrcmpok(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ type_t *ltp, *rtp;
+ tspec_t lt, rt;
+ const char *lts, *rts;
+
+ lt = (ltp = ln->tn_type)->t_subt->t_tspec;
+ rt = (rtp = rn->tn_type)->t_subt->t_tspec;
+
+ if (lt == VOID || rt == VOID) {
+ if (sflag && (lt == FUNC || rt == FUNC)) {
+ /* (void *)0 already handled in typeok() */
+ *(lt == FUNC ? &lts : &rts) = "function pointer";
+ *(lt == VOID ? &lts : &rts) = "'void *'";
+ /* ANSI C forbids comparision of %s with %s */
+ warning(274, lts, rts);
+ }
+ return;
+ }
+
+ if (!eqtype(ltp->t_subt, rtp->t_subt, 1, 0, NULL)) {
+ illptrc(&modtab[op], ltp, rtp);
+ return;
+ }
+
+ if (lt == FUNC && rt == FUNC) {
+ if (sflag && op != EQ && op != NE)
+ /* ANSI C forbids ordered comp. of func ptr */
+ warning(125);
+ }
+}
+
+/*
+ * Checks type compatibility for ASSIGN, INIT, FARG and RETURN
+ * and prints warnings/errors if necessary.
+ * If the types are (almost) compatible, 1 is returned, otherwise 0.
+ */
+static int
+asgntypok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, lst, rst;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ mod_t *mp;
+ const char *lts, *rts;
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ mp = &modtab[op];
+
+ if (isatyp(lt) && isatyp(rt))
+ return (1);
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION))
+ /* both are struct or union */
+ return (ltp->t_str == rtp->t_str);
+
+ /* 0, 0L and (void *)0 may be assigned to any pointer */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID)) {
+ /* two pointers, at least one pointer to void */
+ if (sflag && (lst == FUNC || rst == FUNC)) {
+ /* comb. of ptr to func and ptr to void */
+ *(lst == FUNC ? &lts : &rts) = "function pointer";
+ *(lst == VOID ? &lts : &rts) = "'void *'";
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, rts, lts);
+ break;
+ case FARG:
+ /* ANSI C forbids conv. of %s to %s, arg #%d */
+ warning(304, rts, lts, arg);
+ break;
+ default:
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, rts, lts, mp->m_name);
+ break;
+ }
+ }
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID ||
+ eqtype(lstp, rstp, 1, 0, NULL))) {
+ /* compatible pointer types (qualifiers ignored) */
+ if (!tflag &&
+ ((!lstp->t_const && rstp->t_const) ||
+ (!lstp->t_volatile && rstp->t_volatile))) {
+ /* left side has not all qualifiers of right */
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* incompatible pointer types */
+ warning(182);
+ break;
+ case FARG:
+ /* argument has incompat. ptr. type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ /* operands have incompat. ptr. types, op %s */
+ warning(128, mp->m_name);
+ break;
+ }
+ }
+ return (1);
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* illegal combination of pointer and integer */
+ warning(183);
+ break;
+ case FARG:
+ /* illegal comb. of ptr. and int., arg #%d */
+ warning(154, arg);
+ break;
+ default:
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ illptrc(NULL, ltp, rtp);
+ break;
+ case FARG:
+ /* argument has incompatible pointer type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+ return (1);
+ }
+
+ switch (op) {
+ case INIT:
+ /* initialisation type mismatch */
+ error(185);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ error(211);
+ break;
+ case FARG:
+ /* argument is incompatible with prototype, arg #%d */
+ warning(155, arg);
+ break;
+ default:
+ incompat(op, lt, rt);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Prints a warning if an operator, which should be senseless for an
+ * enum type, is applied to an enum type.
+ */
+static void
+chkbeop(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ if (!eflag)
+ return;
+
+ mp = &modtab[op];
+
+ if (!(ln->tn_type->t_isenum ||
+ (mp->m_binary && rn->tn_type->t_isenum))) {
+ return;
+ }
+
+ /*
+ * Enum as offset to a pointer is an exception (otherwise enums
+ * could not be used as array indizes).
+ */
+ if (op == PLUS &&
+ ((ln->tn_type->t_isenum && rn->tn_type->t_tspec == PTR) ||
+ (rn->tn_type->t_isenum && ln->tn_type->t_tspec == PTR))) {
+ return;
+ }
+
+ /* dubious operation on enum, op %s */
+ warning(241, mp->m_name);
+
+}
+
+/*
+ * Prints a warning if an operator is applied to two different enum types.
+ */
+static void
+chkeop2(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (ln->tn_type->t_enum != rn->tn_type->t_enum) {
+ switch (op) {
+ case INIT:
+ /* enum type mismatch in initialisation */
+ warning(210);
+ break;
+ case FARG:
+ /* enum type mismatch, arg #%d */
+ warning(156, arg);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ warning(211);
+ break;
+ default:
+ /* enum type mismatch, op %s */
+ warning(130, mp->m_name);
+ break;
+ }
+#if 0
+ } else if (mp->m_comp && op != EQ && op != NE) {
+ if (eflag)
+ /* dubious comparisions of enums */
+ warning(243, mp->m_name);
+#endif
+ }
+}
+
+/*
+ * Prints a warning if an operator has both enum end other integer
+ * types.
+ */
+static void
+chkeop1(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ if (!eflag)
+ return;
+
+ switch (op) {
+ case INIT:
+ /*
+ * Initializations with 0 should be allowed. Otherwise,
+ * we should complain about all uninitialized enums,
+ * consequently.
+ */
+ if (!rn->tn_type->t_isenum && rn->tn_op == CON &&
+ isityp(rn->tn_type->t_tspec) && rn->tn_val->v_quad == 0) {
+ return;
+ }
+ /* initialisation of '%s' with '%s' */
+ warning(277, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ case FARG:
+ /* combination of '%s' and '%s', arg #%d */
+ warning(278, tyname(ln->tn_type), tyname(rn->tn_type), arg);
+ break;
+ case RETURN:
+ /* combination of '%s' and '%s' in return */
+ warning(279, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ default:
+ /* combination of '%s' and %s, op %s */
+ warning(242, tyname(ln->tn_type), tyname(rn->tn_type),
+ modtab[op].m_name);
+ break;
+ }
+}
+
+/*
+ * Build and initialize a new node.
+ */
+static tnode_t *
+mktnode(op, type, ln, rn)
+ op_t op;
+ type_t *type;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ ntn = getnode();
+
+ ntn->tn_op = op;
+ ntn->tn_type = type;
+ ntn->tn_left = ln;
+ ntn->tn_right = rn;
+
+ if (op == STAR || op == FSEL) {
+ if (ln->tn_type->t_tspec == PTR) {
+ t = ln->tn_type->t_subt->t_tspec;
+ if (t != FUNC && t != VOID)
+ ntn->tn_lvalue = 1;
+ } else {
+ lerror("mktnode() 2");
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Performs usual conversion of operands to (unsigned) int.
+ *
+ * If tflag is set or the operand is a function argument with no
+ * type information (no prototype or variable # of args), convert
+ * float to double.
+ */
+tnode_t *
+promote(op, farg, tn)
+ op_t op;
+ int farg;
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *ntp;
+ int len;
+
+ t = tn->tn_type->t_tspec;
+
+ if (!isatyp(t))
+ return (tn);
+
+ if (!tflag) {
+ /*
+ * ANSI C requires that the result is always of type INT
+ * if INT can represent all possible values of the previous
+ * type.
+ */
+ if (tn->tn_type->t_isfield) {
+ len = tn->tn_type->t_flen;
+ if (size(INT) > len) {
+ t = INT;
+ } else {
+ if (size(INT) != len)
+ lerror("promote() 1");
+ if (isutyp(t)) {
+ t = UINT;
+ } else {
+ t = INT;
+ }
+ }
+ } else if (t == CHAR || t == UCHAR || t == SCHAR) {
+ t = (size(CHAR) < size(INT) || t != UCHAR) ?
+ INT : UINT;
+ } else if (t == SHORT || t == USHORT) {
+ t = (size(SHORT) < size(INT) || t == SHORT) ?
+ INT : UINT;
+ } else if (t == ENUM) {
+ t = INT;
+ } else if (farg && t == FLOAT) {
+ t = DOUBLE;
+ }
+ } else {
+ /*
+ * In traditional C, keep unsigned and promote FLOAT
+ * to DOUBLE.
+ */
+ if (t == UCHAR || t == USHORT) {
+ t = UINT;
+ } else if (t == CHAR || t == SCHAR || t == SHORT) {
+ t = INT;
+ } else if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == ENUM) {
+ t = INT;
+ }
+ }
+
+ if (t != tn->tn_type->t_tspec) {
+ ntp = tduptyp(tn->tn_type);
+ ntp->t_tspec = t;
+ /*
+ * Keep t_isenum so we are later able to check compatibility
+ * of enum types.
+ */
+ tn = convert(op, 0, ntp, tn);
+ }
+
+ return (tn);
+}
+
+/*
+ * Insert conversions which are necessary to give both operands the same
+ * type. This is done in different ways for traditional C and ANIS C.
+ */
+static void
+balance(op, lnp, rnp)
+ op_t op;
+ tnode_t **lnp, **rnp;
+{
+ tspec_t lt, rt, t;
+ int i, u;
+ type_t *ntp;
+ static tspec_t tl[] = {
+ LDOUBLE, DOUBLE, FLOAT, UQUAD, QUAD, ULONG, LONG, UINT, INT,
+ };
+
+ lt = (*lnp)->tn_type->t_tspec;
+ rt = (*rnp)->tn_type->t_tspec;
+
+ if (!isatyp(lt) || !isatyp(rt))
+ return;
+
+ if (!tflag) {
+ if (lt == rt) {
+ t = lt;
+ } else if (lt == LDOUBLE || rt == LDOUBLE) {
+ t = LDOUBLE;
+ } else if (lt == DOUBLE || rt == DOUBLE) {
+ t = DOUBLE;
+ } else if (lt == FLOAT || rt == FLOAT) {
+ t = FLOAT;
+ } else {
+ /*
+ * If type A has more bits than type B it should
+ * be able to hold all possible values of type B.
+ */
+ if (size(lt) > size(rt)) {
+ t = lt;
+ } else if (size(lt) < size(rt)) {
+ t = rt;
+ } else {
+ for (i = 3; tl[i] != INT; i++) {
+ if (tl[i] == lt || tl[i] == rt)
+ break;
+ }
+ if ((isutyp(lt) || isutyp(rt)) &&
+ !isutyp(tl[i])) {
+ i--;
+ }
+ t = tl[i];
+ }
+ }
+ } else {
+ /* Keep unsigned in traditional C */
+ u = isutyp(lt) || isutyp(rt);
+ for (i = 0; tl[i] != INT; i++) {
+ if (lt == tl[i] || rt == tl[i])
+ break;
+ }
+ t = tl[i];
+ if (u && isityp(t) && !isutyp(t))
+ t = utyp(t);
+ }
+
+ if (t != lt) {
+ ntp = tduptyp((*lnp)->tn_type);
+ ntp->t_tspec = t;
+ *lnp = convert(op, 0, ntp, *lnp);
+ }
+ if (t != rt) {
+ ntp = tduptyp((*rnp)->tn_type);
+ ntp->t_tspec = t;
+ *rnp = convert(op, 0, ntp, *rnp);
+ }
+}
+
+/*
+ * Insert a conversion operator, which converts the type of the node
+ * to another given type.
+ * If op is FARG, arg is the number of the argument (used for warnings).
+ */
+tnode_t *
+convert(op, arg, tp, tn)
+ op_t op;
+ int arg;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ntn;
+ tspec_t nt, ot, ost;
+
+ if (tn->tn_lvalue)
+ lerror("convert() 1");
+
+ nt = tp->t_tspec;
+ if ((ot = tn->tn_type->t_tspec) == PTR)
+ ost = tn->tn_type->t_subt->t_tspec;
+
+ if (!tflag && !sflag && op == FARG)
+ ptconv(arg, nt, ot, tp, tn);
+ if (isityp(nt) && isityp(ot)) {
+ iiconv(op, arg, nt, ot, tp, tn);
+ } else if (nt == PTR && ((ot == PTR && ost == VOID) || isityp(ot)) &&
+ tn->tn_op == CON && tn->tn_val->v_quad == 0) {
+ /* 0, 0L and (void *)0 may be assigned to any pointer. */
+ } else if (isityp(nt) && ot == PTR) {
+ piconv(op, nt, tp, tn);
+ } else if (nt == PTR && ot == PTR) {
+ ppconv(op, tn, tp);
+ }
+
+ ntn = getnode();
+ ntn->tn_op = CVT;
+ ntn->tn_type = tp;
+ ntn->tn_cast = op == CVT;
+ if (tn->tn_op != CON || nt == VOID) {
+ ntn->tn_left = tn;
+ } else {
+ ntn->tn_op = CON;
+ ntn->tn_val = tgetblk(sizeof (val_t));
+ cvtcon(op, arg, ntn->tn_type, ntn->tn_val, tn->tn_val);
+ }
+
+ return (ntn);
+}
+
+/*
+ * Print a warning if a prototype causes a type conversion that is
+ * different from what would happen to the same argument in the
+ * absence of a prototype.
+ *
+ * Errors/Warnings about illegal type combinations are already printed
+ * in asgntypok().
+ */
+static void
+ptconv(arg, nt, ot, tp, tn)
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ptn;
+
+ if (!isatyp(nt) || !isatyp(ot))
+ return;
+
+ /*
+ * If the type of the formal parameter is char/short, a warning
+ * would be useless, because functions declared the old style
+ * can't expect char/short arguments.
+ */
+ if (nt == CHAR || nt == UCHAR || nt == SHORT || nt == USHORT)
+ return;
+
+ /* get default promotion */
+ ptn = promote(NOOP, 1, tn);
+ ot = ptn->tn_type->t_tspec;
+
+ /* return if types are the same with and without prototype */
+ if (nt == ot || (nt == ENUM && ot == INT))
+ return;
+
+ if (isftyp(nt) != isftyp(ot) || psize(nt) != psize(ot)) {
+ /* representation and/or width change */
+ if (styp(nt) != SHORT || !isityp(ot) || psize(ot) > psize(INT))
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ } else if (hflag) {
+ /*
+ * they differ in sign or base type (char, short, int,
+ * long, long long, float, double, long double)
+ *
+ * if they differ only in sign and the argument is a constant
+ * and the msb of the argument is not set, print no warning
+ */
+ if (ptn->tn_op == CON && isityp(nt) && styp(nt) == styp(ot) &&
+ msb(ptn->tn_val->v_quad, ot, -1) == 0) {
+ /* ok */
+ } else {
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ }
+ }
+}
+
+/*
+ * Print warnings for conversions of integer types which my cause
+ * problems.
+ */
+/* ARGSUSED */
+static void
+iiconv(op, arg, nt, ot, tp, tn)
+ op_t op;
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op == CVT)
+ return;
+
+#if 0
+ if (psize(nt) > psize(ot) && isutyp(nt) != isutyp(ot)) {
+ /* conversion to %s may sign-extend incorrectly (, arg #%d) */
+ if (aflag && pflag) {
+ if (op == FARG) {
+ warning(297, tyname(tp), arg);
+ } else {
+ warning(131, tyname(tp));
+ }
+ }
+ }
+#endif
+
+ if (psize(nt) < psize(ot) &&
+ (ot == LONG || ot == ULONG || ot == QUAD || ot == UQUAD ||
+ aflag > 1)) {
+ /* conversion from '%s' may lose accuracy */
+ if (aflag) {
+ if (op == FARG) {
+ warning(298, tyname(tn->tn_type), arg);
+ } else {
+ warning(132, tyname(tn->tn_type));
+ }
+ }
+ }
+}
+
+/*
+ * Print warnings for dubious conversions of pointer to integer.
+ */
+static void
+piconv(op, nt, tp, tn)
+ op_t op;
+ tspec_t nt;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op != CVT) {
+ /* We got already an error. */
+ return;
+ }
+
+ if (psize(nt) < psize(PTR)) {
+ if (pflag && size(nt) >= size(PTR)) {
+ /* conv. of pointer to %s may lose bits */
+ warning(134, tyname(tp));
+ } else {
+ /* conv. of pointer to %s loses bits */
+ warning(133, tyname(tp));
+ }
+ }
+}
+
+/*
+ * Print warnings for questionable pointer conversions.
+ */
+static void
+ppconv(op, tn, tp)
+ op_t op;
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+ const char *nts, *ots;
+
+ /*
+ * We got already an error (pointers of different types
+ * without a cast) or we will not get a warning.
+ */
+ if (op != CVT)
+ return;
+
+ nt = tp->t_subt->t_tspec;
+ ot = tn->tn_type->t_subt->t_tspec;
+
+ if (nt == VOID || ot == VOID) {
+ if (sflag && (nt == FUNC || ot == FUNC)) {
+ /* (void *)0 already handled in convert() */
+ *(nt == FUNC ? &nts : &ots) = "function pointer";
+ *(nt == VOID ? &nts : &ots) = "'void *'";
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, ots, nts);
+ }
+ return;
+ } else if (nt == FUNC && ot == FUNC) {
+ return;
+ } else if (nt == FUNC || ot == FUNC) {
+ /* questionable conversion of function pointer */
+ warning(229);
+ return;
+ }
+
+ if (getbound(tp->t_subt) > getbound(tn->tn_type->t_subt)) {
+ if (hflag)
+ /* possible pointer alignment problem */
+ warning(135);
+ }
+ if (((nt == STRUCT || nt == UNION) &&
+ tp->t_subt->t_str != tn->tn_type->t_subt->t_str) ||
+ psize(nt) != psize(ot)) {
+ if (cflag) {
+ /* pointer casts may be troublesome */
+ warning(247);
+ }
+ }
+}
+
+/*
+ * Converts a typed constant in a constant of another type.
+ *
+ * op operator which requires conversion
+ * arg if op is FARG, # of argument
+ * tp type in which to convert the constant
+ * nv new constant
+ * v old constant
+ */
+void
+cvtcon(op, arg, tp, nv, v)
+ op_t op;
+ int arg;
+ type_t *tp;
+ val_t *nv, *v;
+{
+ tspec_t ot, nt;
+ ldbl_t max, min;
+ int sz, rchk;
+ quad_t xmask, xmsk1;
+ int osz, nsz;
+
+ ot = v->v_tspec;
+ nt = nv->v_tspec = tp->t_tspec;
+ rchk = 0;
+
+ if (ot == FLOAT || ot == DOUBLE || ot == LDOUBLE) {
+ switch (nt) {
+ case CHAR:
+ max = CHAR_MAX; min = CHAR_MIN; break;
+ case UCHAR:
+ max = UCHAR_MAX; min = 0; break;
+ case SCHAR:
+ max = SCHAR_MAX; min = SCHAR_MIN; break;
+ case SHORT:
+ max = SHRT_MAX; min = SHRT_MIN; break;
+ case USHORT:
+ max = USHRT_MAX; min = 0; break;
+ case ENUM:
+ case INT:
+ max = INT_MAX; min = INT_MIN; break;
+ case UINT:
+ max = (u_int)UINT_MAX; min = 0; break;
+ case LONG:
+ max = LONG_MAX; min = LONG_MIN; break;
+ case ULONG:
+ max = (u_long)ULONG_MAX; min = 0; break;
+ case QUAD:
+ max = QUAD_MAX; min = QUAD_MIN; break;
+ case UQUAD:
+ max = (u_quad_t)UQUAD_MAX; min = 0; break;
+ case FLOAT:
+ max = FLT_MAX; min = -FLT_MAX; break;
+ case DOUBLE:
+ max = DBL_MAX; min = -DBL_MAX; break;
+ case PTR:
+ /* Got already an error because of float --> ptr */
+ case LDOUBLE:
+ max = LDBL_MAX; min = -LDBL_MAX; break;
+ default:
+ lerror("cvtcon() 1");
+ }
+ if (v->v_ldbl > max || v->v_ldbl < min) {
+ if (nt == LDOUBLE)
+ lerror("cvtcon() 2");
+ if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ v->v_ldbl = v->v_ldbl > 0 ? max : min;
+ }
+ if (nt == FLOAT) {
+ nv->v_ldbl = (float)v->v_ldbl;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (double)v->v_ldbl;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = v->v_ldbl;
+ } else {
+ nv->v_quad = (nt == PTR || isutyp(nt)) ?
+ (u_quad_t)v->v_ldbl : (quad_t)v->v_ldbl;
+ }
+ } else {
+ if (nt == FLOAT) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (float)(u_quad_t)v->v_quad : (float)v->v_quad;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (double)(u_quad_t)v->v_quad : (double)v->v_quad;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (ldbl_t)(u_quad_t)v->v_quad : (ldbl_t)v->v_quad;
+ } else {
+ rchk = 1; /* Check for lost precision. */
+ nv->v_quad = v->v_quad;
+ }
+ }
+
+ if (v->v_ansiu && isftyp(nt)) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ } else if (v->v_ansiu && (isityp(nt) && !isutyp(nt) &&
+ psize(nt) > psize(ot))) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ }
+
+ if (nt != FLOAT && nt != DOUBLE && nt != LDOUBLE) {
+ sz = tp->t_isfield ? tp->t_flen : size(nt);
+ nv->v_quad = xsign(nv->v_quad, nt, sz);
+ }
+
+ if (rchk && op != CVT) {
+ osz = size(ot);
+ nsz = tp->t_isfield ? tp->t_flen : size(nt);
+ xmask = qlmasks[nsz] ^ qlmasks[osz];
+ xmsk1 = qlmasks[nsz] ^ qlmasks[osz - 1];
+ /*
+ * For bitwise operations we are not interested in the
+ * value, but in the bits itself.
+ */
+ if (op == ORASS || op == OR || op == XOR) {
+ /*
+ * Print a warning if bits which were set are
+ * lost due to the conversion.
+ * This can happen with operator ORASS only.
+ */
+ if (nsz < osz && (v->v_quad & xmask) != 0) {
+ /* constant truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if (op == ANDASS || op == AND) {
+ /*
+ * Print a warning if additional bits are not all 1
+ * and the most significant bit of the old value is 1,
+ * or if at least one (but not all) removed bit was 0.
+ */
+ if (nsz > osz &&
+ (nv->v_quad & qbmasks[osz - 1]) != 0 &&
+ (nv->v_quad & xmask) != xmask) {
+ /*
+ * extra bits set to 0 in conversion
+ * of '%s' to '%s', op %s
+ */
+ warning(309, tyname(gettyp(ot)),
+ tyname(tp), modtab[op].m_name);
+ } else if (nsz < osz &&
+ (v->v_quad & xmask) != xmask &&
+ (v->v_quad & xmask) != 0) {
+ /* const. truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if ((nt != PTR && isutyp(nt)) &&
+ (ot != PTR && !isutyp(ot)) && v->v_quad < 0) {
+ if (op == ASSIGN) {
+ /* assignment of negative constant to ... */
+ warning(164);
+ } else if (op == INIT) {
+ /* initialisation of unsigned with neg. ... */
+ warning(221);
+ } else if (op == FARG) {
+ /* conversion of neg. const. to ..., arg #%d */
+ warning(296, arg);
+ } else if (modtab[op].m_comp) {
+ /* we get this warning already in chkcomp() */
+ } else {
+ /* conversion of negative constant to ... */
+ warning(222);
+ }
+ } else if (nv->v_quad != v->v_quad && nsz <= osz &&
+ (v->v_quad & xmask) != 0 &&
+ (isutyp(ot) || (v->v_quad & xmsk1) != xmsk1)) {
+ /*
+ * Loss of significant bit(s). All truncated bits
+ * of unsigned types or all truncated bits plus the
+ * msb of the target for signed types are considered
+ * to be significant bits. Loss of significant bits
+ * means that at least on of the bits was set in an
+ * unsigned type or that at least one, but not all of
+ * the bits was set in an signed type.
+ * Loss of significant bits means that it is not
+ * possible, also not with necessary casts, to convert
+ * back to the original type. A example for a
+ * necessary cast is:
+ * char c; int i; c = 128;
+ * i = c; ** yields -128 **
+ * i = (unsigned char)c; ** yields 128 **
+ */
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == ASSIGN) {
+ /* constant truncated by assignment */
+ warning(165);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer does not fit */
+ warning(180);
+ } else if (op == INIT) {
+ /* initializer does not fit */
+ warning(178);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ } else if (nv->v_quad != v->v_quad) {
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer out of range */
+ warning(11);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ }
+ }
+}
+
+/*
+ * Called if incompatible types were detected.
+ * Prints a appropriate warning.
+ */
+static void
+incompat(op, lt, rt)
+ op_t op;
+ tspec_t lt, rt;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (lt == VOID || (mp->m_binary && rt == VOID)) {
+ /* void type illegal in expression */
+ error(109);
+ } else if (op == ASSIGN) {
+ if ((lt == STRUCT || lt == UNION) &&
+ (rt == STRUCT || rt == UNION)) {
+ /* assignment of different structures */
+ error(240);
+ } else {
+ /* assignment type mismatch */
+ error(171);
+ }
+ } else if (mp->m_binary) {
+ /* operands of %s have incompatible types */
+ error(107, mp->m_name);
+ } else {
+ /* operand of %s has incompatible type */
+ error(108, mp->m_name);
+ }
+}
+
+/*
+ * Called if incompatible pointer types are detected.
+ * Print an appropriate warning.
+ */
+static void
+illptrc(mp, ltp, rtp)
+ mod_t *mp;
+ type_t *ltp, *rtp;
+{
+ tspec_t lt, rt;
+
+ if (ltp->t_tspec != PTR || rtp->t_tspec != PTR)
+ lerror("illptrc() 1");
+
+ lt = ltp->t_subt->t_tspec;
+ rt = rtp->t_subt->t_tspec;
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION)) {
+ if (mp == NULL) {
+ /* illegal structure pointer combination */
+ warning(244);
+ } else {
+ /* illegal structure pointer combination, op %s */
+ warning(245, mp->m_name);
+ }
+ } else {
+ if (mp == NULL) {
+ /* illegal pointer combination */
+ warning(184);
+ } else {
+ /* illegal pointer combination, op %s */
+ warning(124, mp->m_name);
+ }
+ }
+}
+
+/*
+ * Make sure type (*tpp)->t_subt has at least the qualifiers
+ * of tp1->t_subt and tp2->t_subt.
+ */
+static void
+mrgqual(tpp, tp1, tp2)
+ type_t **tpp, *tp1, *tp2;
+{
+ if ((*tpp)->t_tspec != PTR ||
+ tp1->t_tspec != PTR || tp2->t_tspec != PTR) {
+ lerror("mrgqual()");
+ }
+
+ if ((*tpp)->t_subt->t_const ==
+ (tp1->t_subt->t_const | tp2->t_subt->t_const) &&
+ (*tpp)->t_subt->t_volatile ==
+ (tp1->t_subt->t_volatile | tp2->t_subt->t_volatile)) {
+ return;
+ }
+
+ *tpp = tduptyp(*tpp);
+ (*tpp)->t_subt = tduptyp((*tpp)->t_subt);
+ (*tpp)->t_subt->t_const =
+ tp1->t_subt->t_const | tp2->t_subt->t_const;
+ (*tpp)->t_subt->t_volatile =
+ tp1->t_subt->t_volatile | tp2->t_subt->t_volatile;
+}
+
+/*
+ * Returns 1 if the given structure or union has a constant member
+ * (maybe recursively).
+ */
+static int
+conmemb(tp)
+ type_t *tp;
+{
+ sym_t *m;
+ tspec_t t;
+
+ if ((t = tp->t_tspec) != STRUCT && t != UNION)
+ lerror("conmemb()");
+ for (m = tp->t_str->memb; m != NULL; m = m->s_nxt) {
+ tp = m->s_type;
+ if (tp->t_const)
+ return (1);
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (conmemb(m->s_type))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+const char *
+tyname(tp)
+ type_t *tp;
+{
+ tspec_t t;
+ const char *s;
+
+ if ((t = tp->t_tspec) == INT && tp->t_isenum)
+ t = ENUM;
+
+ switch (t) {
+ case CHAR: s = "char"; break;
+ case UCHAR: s = "unsigned char"; break;
+ case SCHAR: s = "signed char"; break;
+ case SHORT: s = "short"; break;
+ case USHORT: s = "unsigned short"; break;
+ case INT: s = "int"; break;
+ case UINT: s = "unsigned int"; break;
+ case LONG: s = "long"; break;
+ case ULONG: s = "unsigned long"; break;
+ case QUAD: s = "long long"; break;
+ case UQUAD: s = "unsigned long long"; break;
+ case FLOAT: s = "float"; break;
+ case DOUBLE: s = "double"; break;
+ case LDOUBLE: s = "long double"; break;
+ case PTR: s = "pointer"; break;
+ case ENUM: s = "enum"; break;
+ case STRUCT: s = "struct"; break;
+ case UNION: s = "union"; break;
+ case FUNC: s = "function"; break;
+ case ARRAY: s = "array"; break;
+ default:
+ lerror("tyname()");
+ }
+ return (s);
+}
+
+/*
+ * Create a new node for one of the operators POINT and ARROW.
+ */
+static tnode_t *
+bldstr(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ int nolval;
+
+ if (rn->tn_op != NAME)
+ lerror("bldstr() 1");
+ if (rn->tn_sym->s_value.v_tspec != INT)
+ lerror("bldstr() 2");
+ if (rn->tn_sym->s_scl != MOS && rn->tn_sym->s_scl != MOU)
+ lerror("bldstr() 3");
+
+ /*
+ * Remember if the left operand is an lvalue (structure members
+ * are lvalues if and only if the structure itself is an lvalue).
+ */
+ nolval = op == POINT && !ln->tn_lvalue;
+
+ if (op == POINT) {
+ ln = bldamper(ln, 1);
+ } else if (ln->tn_type->t_tspec != PTR) {
+ if (!tflag || !isityp(ln->tn_type->t_tspec))
+ lerror("bldstr() 4");
+ ln = convert(NOOP, 0, tincref(gettyp(VOID), PTR), ln);
+ }
+
+#if PTRDIFF_IS_LONG
+ ctn = getinode(LONG, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#else
+ ctn = getinode(INT, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#endif
+
+ ntn = mktnode(PLUS, tincref(rn->tn_type, PTR), ln, ctn);
+ if (ln->tn_op == CON)
+ ntn = fold(ntn);
+
+ if (rn->tn_type->t_isfield) {
+ ntn = mktnode(FSEL, ntn->tn_type->t_subt, ntn, NULL);
+ } else {
+ ntn = mktnode(STAR, ntn->tn_type->t_subt, ntn, NULL);
+ }
+
+ if (nolval)
+ ntn->tn_lvalue = 0;
+
+ return (ntn);
+}
+
+/*
+ * Create a node for INCAFT, INCBEF, DECAFT and DECBEF.
+ */
+static tnode_t *
+bldincdec(op, ln)
+ op_t op;
+ tnode_t *ln;
+{
+ tnode_t *cn, *ntn;
+
+ if (ln == NULL)
+ lerror("bldincdec() 1");
+
+ if (ln->tn_type->t_tspec == PTR) {
+ cn = plength(ln->tn_type);
+ } else {
+ cn = getinode(INT, (quad_t)1);
+ }
+ ntn = mktnode(op, ln->tn_type, ln, cn);
+
+ return (ntn);
+}
+
+/*
+ * Create a tree node for the & operator
+ */
+static tnode_t *
+bldamper(tn, noign)
+ tnode_t *tn;
+ int noign;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) {
+ /* & before array or function: ignored */
+ if (tflag)
+ warning(127);
+ return (tn);
+ }
+
+ /* eliminate &* */
+ if (tn->tn_op == STAR &&
+ tn->tn_left->tn_type->t_tspec == PTR &&
+ tn->tn_left->tn_type->t_subt == tn->tn_type) {
+ return (tn->tn_left);
+ }
+
+ ntn = mktnode(AMPER, tincref(tn->tn_type, PTR), tn, NULL);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for operators PLUS and MINUS.
+ */
+static tnode_t *
+bldplmi(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ type_t *tp;
+
+ /* If pointer and integer, then pointer to the lhs. */
+ if (rn->tn_type->t_tspec == PTR && isityp(ln->tn_type->t_tspec)) {
+ ntn = ln;
+ ln = rn;
+ rn = ntn;
+ }
+
+ if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) {
+
+ if (!isityp(rn->tn_type->t_tspec))
+ lerror("bldplmi() 1");
+
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ } else if (rn->tn_type->t_tspec == PTR) {
+
+ if (ln->tn_type->t_tspec != PTR || op != MINUS)
+ lerror("bldplmi() 2");
+#if PTRDIFF_IS_LONG
+ tp = gettyp(LONG);
+#else
+ tp = gettyp(INT);
+#endif
+ ntn = mktnode(op, tp, ln, rn);
+ if (ln->tn_op == CON && rn->tn_op == CON)
+ ntn = fold(ntn);
+ ctn = plength(ln->tn_type);
+ balance(NOOP, &ntn, &ctn);
+ ntn = mktnode(DIV, tp, ntn, ctn);
+
+ } else {
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ }
+ return (ntn);
+}
+
+/*
+ * Create a node for operators SHL and SHR.
+ */
+static tnode_t *
+bldshft(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t t;
+ tnode_t *ntn;
+
+ if ((t = rn->tn_type->t_tspec) != INT && t != UINT)
+ rn = convert(CVT, 0, gettyp(INT), rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+ return (ntn);
+}
+
+/*
+ * Create a node for COLON.
+ */
+static tnode_t *
+bldcol(ln, rn)
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, pdt;
+ type_t *rtp;
+ tnode_t *ntn;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+#if PTRDIFF_IS_LONG
+ pdt = LONG;
+#else
+ pdt = INT;
+#endif
+
+ /*
+ * Arithmetic types are balanced, all other type combinations
+ * still need to be handled.
+ */
+ if (isatyp(lt) && isatyp(rt)) {
+ rtp = ln->tn_type;
+ } else if (lt == VOID || rt == VOID) {
+ rtp = gettyp(VOID);
+ } else if (lt == STRUCT || lt == UNION) {
+ /* Both types must be identical. */
+ if (rt != STRUCT && rt != UNION)
+ lerror("bldcol() 1");
+ if (ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldcol() 2");
+ if (incompl(ln->tn_type)) {
+ /* unknown operand size, op %s */
+ error(138, modtab[COLON].m_name);
+ return (NULL);
+ }
+ rtp = ln->tn_type;
+ } else if (lt == PTR && isityp(rt)) {
+ if (rt != pdt) {
+ rn = convert(NOOP, 0, gettyp(pdt), rn);
+ rt = pdt;
+ }
+ rtp = ln->tn_type;
+ } else if (rt == PTR && isityp(lt)) {
+ if (lt != pdt) {
+ ln = convert(NOOP, 0, gettyp(pdt), ln);
+ lt = pdt;
+ }
+ rtp = rn->tn_type;
+ } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) {
+ if (rt != PTR)
+ lerror("bldcol() 4");
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) {
+ if (lt != PTR)
+ lerror("bldcol() 5");
+ rtp = rn->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else {
+ if (lt != PTR || rt != PTR)
+ lerror("bldcol() 6");
+ /*
+ * XXX For now we simply take the left type. This is
+ * probably wrong, if one type contains a functionprototype
+ * and the other one, at the same place, only an old style
+ * declaration.
+ */
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ }
+
+ ntn = mktnode(COLON, rtp, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for an assignment operator (both = and op= ).
+ */
+static tnode_t *
+bldasgn(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ tnode_t *ntn, *ctn;
+
+ if (ln == NULL || rn == NULL)
+ lerror("bldasgn() 1");
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+
+ if ((op == ADDASS || op == SUBASS) && lt == PTR) {
+ if (!isityp(rt))
+ lerror("bldasgn() 2");
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ }
+
+ if ((op == ASSIGN || op == RETURN) && (lt == STRUCT || rt == STRUCT)) {
+ if (rt != lt || ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldasgn() 3");
+ if (incompl(ln->tn_type)) {
+ if (op == RETURN) {
+ /* cannot return incomplete type */
+ error(212);
+ } else {
+ /* unknown operand size, op %s */
+ error(138, modtab[op].m_name);
+ }
+ return (NULL);
+ }
+ }
+
+ if (op == SHLASS || op == SHRASS) {
+ if (rt != INT) {
+ rn = convert(NOOP, 0, gettyp(INT), rn);
+ rt = INT;
+ }
+ } else {
+ if (op == ASSIGN || lt != PTR) {
+ if (lt != rt ||
+ (ln->tn_type->t_isfield && rn->tn_op == CON)) {
+ rn = convert(op, 0, ln->tn_type, rn);
+ rt = lt;
+ }
+ }
+ }
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Get length of type tp->t_subt.
+ */
+static tnode_t *
+plength(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ if (tp->t_tspec != PTR)
+ lerror("plength() 1");
+ tp = tp->t_subt;
+
+ elem = 1;
+ elsz = 0;
+
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* pointer to function is not allowed here */
+ error(110);
+ break;
+ case VOID:
+ /* cannot do pointer arithmetic on operand of ... */
+ (void)gnuism(136);
+ break;
+ case STRUCT:
+ case UNION:
+ if ((elsz = tp->t_str->size) == 0)
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot do pointer arithmetic on operand of ... */
+ warning(136);
+ }
+ /* FALLTHROUGH */
+ default:
+ if ((elsz = size(tp->t_tspec)) == 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ } else if (elsz == -1) {
+ lerror("plength() 2");
+ }
+ break;
+ }
+
+ if (elem == 0 && elsz != 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ }
+
+ if (elsz == 0)
+ elsz = CHAR_BIT;
+
+#if PTRDIFF_IS_LONG
+ st = LONG;
+#else
+ st = INT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+#ifdef XXX_BROKEN_GCC
+static int
+quad_t_eq(x, y)
+ quad_t x, y;
+{
+ return (x == y);
+}
+
+static int
+u_quad_t_eq(x, y)
+ u_quad_t x, y;
+{
+ return (x == y);
+}
+#endif
+
+/*
+ * Do only as much as necessary to compute constant expressions.
+ * Called only if the operator allows folding and (both) operands
+ * are constants.
+ */
+static tnode_t *
+fold(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ int utyp, ovfl;
+ quad_t sl, sr, q, mask;
+ u_quad_t ul, ur;
+ tnode_t *cn;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ utyp = t == PTR || isutyp(t);
+ ul = sl = tn->tn_left->tn_val->v_quad;
+ if (modtab[tn->tn_op].m_binary)
+ ur = sr = tn->tn_right->tn_val->v_quad;
+
+ ovfl = 0;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ q = sl;
+ break;
+ case UMINUS:
+ q = -sl;
+ if (msb(q, t, -1) == msb(sl, t, -1))
+ ovfl = 1;
+ break;
+ case COMPL:
+ q = ~sl;
+ break;
+ case MULT:
+ q = utyp ? ul * ur : sl * sr;
+ if (msb(q, t, -1) != (msb(sl, t, -1) ^ msb(sr, t, -1)))
+ ovfl = 1;
+ break;
+ case DIV:
+ if (sr == 0) {
+ /* division by 0 */
+ error(139);
+ q = utyp ? UQUAD_MAX : QUAD_MAX;
+ } else {
+ q = utyp ? ul / ur : sl / sr;
+ }
+ break;
+ case MOD:
+ if (sr == 0) {
+ /* modulus by 0 */
+ error(140);
+ q = 0;
+ } else {
+ q = utyp ? ul % ur : sl % sr;
+ }
+ break;
+ case PLUS:
+ q = utyp ? ul + ur : sl + sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case MINUS:
+ q = utyp ? ul - ur : sl - sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case SHL:
+ q = utyp ? ul << sr : sl << sr;
+ break;
+ case SHR:
+ /*
+ * The sign must be explizitly extended because
+ * shifts of signed values are implementation dependent.
+ */
+ q = ul >> sr;
+ q = xsign(q, t, size(t) - (int)sr);
+ break;
+ case LT:
+ q = utyp ? ul < ur : sl < sr;
+ break;
+ case LE:
+ q = utyp ? ul <= ur : sl <= sr;
+ break;
+ case GE:
+ q = utyp ? ul >= ur : sl >= sr;
+ break;
+ case GT:
+ q = utyp ? ul > ur : sl > sr;
+ break;
+ case EQ:
+#ifdef XXX_BROKEN_GCC
+ q = utyp ? u_quad_t_eq(ul, ur) : quad_t_eq(sl, sr);
+#else
+ q = utyp ? ul == ur : sl == sr;
+#endif
+ break;
+ case NE:
+ q = utyp ? ul != ur : sl != sr;
+ break;
+ case AND:
+ q = utyp ? ul & ur : sl & sr;
+ break;
+ case XOR:
+ q = utyp ? ul ^ ur : sl ^ sr;
+ break;
+ case OR:
+ q = utyp ? ul | ur : sl | sr;
+ break;
+ default:
+ lerror("fold() 5");
+ }
+
+ mask = qlmasks[size(t)];
+
+ /* XXX does not work for quads. */
+ if (ovfl || ((q | mask) != ~(u_quad_t)0 && (q & ~mask) != 0)) {
+ if (hflag)
+ /* integer overflow detected, op %s */
+ warning(141, modtab[tn->tn_op].m_name);
+ }
+
+ v->v_quad = xsign(q, t, -1);
+
+ cn = getcnode(tn->tn_type, v);
+
+ return (cn);
+}
+
+#ifdef XXX_BROKEN_GCC
+int
+ldbl_t_neq(x, y)
+ ldbl_t x, y;
+{
+ return (x != y);
+}
+#endif
+
+/*
+ * Same for operators whose operands are compared with 0 (test context).
+ */
+static tnode_t *
+foldtst(tn)
+ tnode_t *tn;
+{
+ int l, r;
+ val_t *v;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = tn->tn_type->t_tspec;
+ if (tn->tn_type->t_tspec != INT)
+ lerror("foldtst() 1");
+
+ if (isftyp(tn->tn_left->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ l = ldbl_t_neq(tn->tn_left->tn_val->v_ldbl, 0.0);
+#else
+ l = tn->tn_left->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ l = tn->tn_left->tn_val->v_quad != 0;
+ }
+
+ if (modtab[tn->tn_op].m_binary) {
+ if (isftyp(tn->tn_right->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ r = ldbl_t_neq(tn->tn_right->tn_val->v_ldbl, 0.0);
+#else
+ r = tn->tn_right->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ r = tn->tn_right->tn_val->v_quad != 0;
+ }
+ }
+
+ switch (tn->tn_op) {
+ case NOT:
+ if (hflag)
+ /* constant argument to NOT */
+ warning(239);
+ v->v_quad = !l;
+ break;
+ case LOGAND:
+ v->v_quad = l && r;
+ break;
+ case LOGOR:
+ v->v_quad = l || r;
+ break;
+ default:
+ lerror("foldtst() 1");
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Same for operands with floating point type.
+ */
+static tnode_t *
+foldflt(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ ldbl_t l, r;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ if (!isftyp(t))
+ lerror("foldflt() 1");
+
+ if (t != tn->tn_left->tn_type->t_tspec)
+ lerror("foldflt() 2");
+ if (modtab[tn->tn_op].m_binary && t != tn->tn_right->tn_type->t_tspec)
+ lerror("foldflt() 3");
+
+ l = tn->tn_left->tn_val->v_ldbl;
+ if (modtab[tn->tn_op].m_binary)
+ r = tn->tn_right->tn_val->v_ldbl;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ v->v_ldbl = l;
+ break;
+ case UMINUS:
+ v->v_ldbl = -l;
+ break;
+ case MULT:
+ v->v_ldbl = l * r;
+ break;
+ case DIV:
+ if (r == 0.0) {
+ /* division by 0 */
+ error(139);
+ if (t == FLOAT) {
+ v->v_ldbl = l < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = l < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = l < 0 ? -LDBL_MAX : LDBL_MAX;
+ }
+ } else {
+ v->v_ldbl = l / r;
+ }
+ break;
+ case PLUS:
+ v->v_ldbl = l + r;
+ break;
+ case MINUS:
+ v->v_ldbl = l - r;
+ break;
+ case LT:
+ v->v_quad = l < r;
+ break;
+ case LE:
+ v->v_quad = l <= r;
+ break;
+ case GE:
+ v->v_quad = l >= r;
+ break;
+ case GT:
+ v->v_quad = l > r;
+ break;
+ case EQ:
+ v->v_quad = l == r;
+ break;
+ case NE:
+ v->v_quad = l != r;
+ break;
+ default:
+ lerror("foldflt() 4");
+ }
+
+ if (isnan((double)v->v_ldbl))
+ lerror("foldflt() 5");
+ if (isinf((double)v->v_ldbl) ||
+ (t == FLOAT &&
+ (v->v_ldbl > FLT_MAX || v->v_ldbl < -FLT_MAX)) ||
+ (t == DOUBLE &&
+ (v->v_ldbl > DBL_MAX || v->v_ldbl < -DBL_MAX))) {
+ /* floating point overflow detected, op %s */
+ warning(142, modtab[tn->tn_op].m_name);
+ if (t == FLOAT) {
+ v->v_ldbl = v->v_ldbl < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = v->v_ldbl < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = v->v_ldbl < 0 ? -LDBL_MAX: LDBL_MAX;
+ }
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Create a constant node for sizeof.
+ */
+tnode_t *
+bldszof(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ if (elem == 0) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elem = 1;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* cannot take size of function */
+ error(144);
+ elsz = 1;
+ break;
+ case STRUCT:
+ case UNION:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elsz = 1;
+ } else {
+ elsz = tp->t_str->size;
+ }
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ warning(143);
+ }
+ /* FALLTHROUGH */
+ default:
+ if (tp->t_isfield) {
+ /* cannot take size of bit-field */
+ error(145);
+ }
+ if (tp->t_tspec == VOID) {
+ /* cannot take size of void */
+ error(146);
+ elsz = 1;
+ } else {
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("bldszof() 1");
+ }
+ break;
+ }
+
+#if SIZEOF_IS_ULONG
+ st = ULONG;
+#else
+ st = UINT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+/*
+ * Type casts.
+ */
+tnode_t *
+cast(tn, tp)
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+
+ if (tn == NULL)
+ return (NULL);
+
+ tn = cconv(tn);
+
+ nt = tp->t_tspec;
+ ot = tn->tn_type->t_tspec;
+
+ if (nt == VOID) {
+ /*
+ * XXX ANSI C requires scalar types or void (Plauger&Brodie).
+ * But this seams really questionable.
+ */
+ } else if (nt == STRUCT || nt == UNION || nt == ARRAY || nt == FUNC) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == STRUCT || ot == UNION) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == VOID) {
+ /* improper cast of void expression */
+ error(148);
+ return (NULL);
+ } else if (isityp(nt) && issclt(ot)) {
+ /* ok */
+ } else if (isftyp(nt) && isatyp(ot)) {
+ /* ok */
+ } else if (nt == PTR && isityp(ot)) {
+ /* ok */
+ } else if (nt == PTR && ot == PTR) {
+ if (!tp->t_subt->t_const && tn->tn_type->t_subt->t_const) {
+ if (hflag)
+ /* cast discards 'const' from ... */
+ warning(275);
+ }
+ } else {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ }
+
+ tn = convert(CVT, 0, tp, tn);
+ tn->tn_cast = 1;
+
+ return (tn);
+}
+
+/*
+ * Create the node for a function argument.
+ * All necessary conversions and type checks are done in funccall(), because
+ * in funcarg() we have no information about expected argument types.
+ */
+tnode_t *
+funcarg(args, arg)
+ tnode_t *args, *arg;
+{
+ tnode_t *ntn;
+
+ /*
+ * If there was a serious error in the expression for the argument,
+ * create a dummy argument so the positions of the remaining arguments
+ * will not change.
+ */
+ if (arg == NULL)
+ arg = getinode(INT, (quad_t)0);
+
+ ntn = mktnode(PUSH, arg->tn_type, arg, args);
+
+ return (ntn);
+}
+
+/*
+ * Create the node for a function call. Also check types of
+ * function arguments and insert conversions, if necessary.
+ */
+tnode_t *
+funccall(func, args)
+ tnode_t *func, *args;
+{
+ tnode_t *ntn;
+ op_t fcop;
+
+ if (func == NULL)
+ return (NULL);
+
+ if (func->tn_op == NAME && func->tn_type->t_tspec == FUNC) {
+ fcop = CALL;
+ } else {
+ fcop = ICALL;
+ }
+
+ /*
+ * after cconv() func will always be a pointer to a function
+ * if it is a valid function designator.
+ */
+ func = cconv(func);
+
+ if (func->tn_type->t_tspec != PTR ||
+ func->tn_type->t_subt->t_tspec != FUNC) {
+ /* illegal function */
+ error(149);
+ return (NULL);
+ }
+
+ args = chkfarg(func->tn_type->t_subt, args);
+
+ ntn = mktnode(fcop, func->tn_type->t_subt->t_subt, func, args);
+
+ return (ntn);
+}
+
+/*
+ * Check types of all function arguments and insert conversions,
+ * if necessary.
+ */
+static tnode_t *
+chkfarg(ftp, args)
+ type_t *ftp; /* type of called function */
+ tnode_t *args; /* arguments */
+{
+ tnode_t *arg;
+ sym_t *asym;
+ tspec_t at;
+ int narg, npar, n, i;
+
+ /* get # of args in the prototype */
+ npar = 0;
+ for (asym = ftp->t_args; asym != NULL; asym = asym->s_nxt)
+ npar++;
+
+ /* get # of args in function call */
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+
+ asym = ftp->t_args;
+ if (ftp->t_proto && npar != narg && !(ftp->t_vararg && npar < narg)) {
+ /* argument mismatch: %d arg%s passed, %d expected */
+ error(150, narg, narg > 1 ? "s" : "", npar);
+ asym = NULL;
+ }
+
+ for (n = 1; n <= narg; n++) {
+
+ /*
+ * The rightmost argument is at the top of the argument
+ * subtree.
+ */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+
+ /* some things which are always not allowd */
+ if ((at = arg->tn_left->tn_type->t_tspec) == VOID) {
+ /* void expressions may not be arguments, arg #%d */
+ error(151, n);
+ return (NULL);
+ } else if ((at == STRUCT || at == UNION) &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ error(152, n);
+ return (NULL);
+ } else if (isityp(at) && arg->tn_left->tn_type->t_isenum &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ warning(152, n);
+ }
+
+ /* class conversions (arg in value context) */
+ arg->tn_left = cconv(arg->tn_left);
+
+ if (asym != NULL) {
+ arg->tn_left = parg(n, asym->s_type, arg->tn_left);
+ } else {
+ arg->tn_left = promote(NOOP, 1, arg->tn_left);
+ }
+ arg->tn_type = arg->tn_left->tn_type;
+
+ if (asym != NULL)
+ asym = asym->s_nxt;
+ }
+
+ return (args);
+}
+
+/*
+ * Compare the type of an argument with the corresponding type of a
+ * prototype parameter. If it is a valid combination, but both types
+ * are not the same, insert a conversion to convert the argument into
+ * the type of the parameter.
+ */
+static tnode_t *
+parg(n, tp, tn)
+ int n; /* pos of arg */
+ type_t *tp; /* expected type (from prototype) */
+ tnode_t *tn; /* argument */
+{
+ tnode_t *ln;
+ int warn;
+
+ ln = xcalloc(1, sizeof (tnode_t));
+ ln->tn_type = tduptyp(tp);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ if (typeok(FARG, n, ln, tn)) {
+ if (!eqtype(tp, tn->tn_type, 1, 0, (warn = 0, &warn)) || warn)
+ tn = convert(FARG, n, tp, tn);
+ }
+ free(ln);
+ return (tn);
+}
+
+/*
+ * Return the value of an integral constant expression.
+ * If the expression is not constant or its type is not an integer
+ * type, an error message is printed.
+ */
+val_t *
+constant(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+
+ v = xcalloc(1, sizeof (val_t));
+
+ if (tn == NULL) {
+ if (nerr == 0)
+ lerror("constant() 1");
+ v->v_tspec = INT;
+ v->v_quad = 1;
+ return (v);
+ }
+
+ v->v_tspec = tn->tn_type->t_tspec;
+
+ if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != tn->tn_val->v_tspec)
+ lerror("constant() 2");
+ if (isityp(tn->tn_val->v_tspec)) {
+ v->v_ansiu = tn->tn_val->v_ansiu;
+ v->v_quad = tn->tn_val->v_quad;
+ return (v);
+ }
+ v->v_quad = tn->tn_val->v_ldbl;
+ } else {
+ v->v_quad = 1;
+ }
+
+ /* integral constant expression expected */
+ error(55);
+
+ if (!isityp(v->v_tspec))
+ v->v_tspec = INT;
+
+ return (v);
+}
+
+/*
+ * Perform some tests on expressions which can't be done in build() and
+ * functions called by build(). These tests must be done here because
+ * we need some information about the context in which the operations
+ * are performed.
+ * After all tests are performed, expr() frees the memory which is used
+ * for the expression.
+ */
+void
+expr(tn, vctx, tctx)
+ tnode_t *tn;
+ int vctx, tctx;
+{
+ if (tn == NULL && nerr == 0)
+ lerror("expr() 1");
+
+ if (tn == NULL) {
+ tfreeblk();
+ return;
+ }
+
+ /* expr() is also called in global initialisations */
+ if (dcs->d_ctx != EXTERN)
+ chkreach();
+
+ chkmisc(tn, vctx, tctx, !tctx, 0, 0, 0);
+ if (tn->tn_op == ASSIGN) {
+ if (hflag && tctx)
+ /* assignment in conditional context */
+ warning(159);
+ } else if (tn->tn_op == CON) {
+ if (hflag && tctx && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ if (!modtab[tn->tn_op].m_sideeff) {
+ /*
+ * for left operands of COMMA this warning is already
+ * printed
+ */
+ if (tn->tn_op != COMMA && !vctx && !tctx)
+ nulleff(tn);
+ }
+ if (dflag)
+ displexpr(tn, 0);
+
+ /* free the tree memory */
+ tfreeblk();
+}
+
+static void
+nulleff(tn)
+ tnode_t *tn;
+{
+ if (!hflag)
+ return;
+
+ while (!modtab[tn->tn_op].m_sideeff) {
+ if (tn->tn_op == CVT && tn->tn_type->t_tspec == VOID) {
+ tn = tn->tn_left;
+ } else if (tn->tn_op == LOGAND || tn->tn_op == LOGOR) {
+ /*
+ * && and || have a side effect if the right operand
+ * has a side effect.
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == QUEST) {
+ /*
+ * ? has a side effect if at least one of its right
+ * operands has a side effect
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == COLON) {
+ /*
+ * : has a side effect if at least one of its operands
+ * has a side effect
+ */
+ if (modtab[tn->tn_left->tn_op].m_sideeff) {
+ tn = tn->tn_left;
+ } else if (modtab[tn->tn_right->tn_op].m_sideeff) {
+ tn = tn->tn_right;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (!modtab[tn->tn_op].m_sideeff)
+ /* expression has null effect */
+ warning(129);
+}
+
+/*
+ * Dump an expression to stdout
+ * only used for debugging
+ */
+static void
+displexpr(tn, offs)
+ tnode_t *tn;
+ int offs;
+{
+ u_quad_t uq;
+
+ if (tn == NULL) {
+ (void)printf("%*s%s\n", offs, "", "NULL");
+ return;
+ }
+ (void)printf("%*sop %s ", offs, "", modtab[tn->tn_op].m_name);
+
+ if (tn->tn_op == NAME) {
+ (void)printf("%s: %s ",
+ tn->tn_sym->s_name, scltoa(tn->tn_sym->s_scl));
+ } else if (tn->tn_op == CON && isftyp(tn->tn_type->t_tspec)) {
+ (void)printf("%#g ", (double)tn->tn_val->v_ldbl);
+ } else if (tn->tn_op == CON && isityp(tn->tn_type->t_tspec)) {
+ uq = tn->tn_val->v_quad;
+ (void)printf("0x %08lx %08lx ", (long)(uq >> 32) & 0xffffffffl,
+ (long)uq & 0xffffffffl);
+ } else if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != PTR)
+ lerror("displexpr() 1");
+ (void)printf("0x%0*lx ", (int)(sizeof (void *) * CHAR_BIT / 4),
+ (u_long)tn->tn_val->v_quad);
+ } else if (tn->tn_op == STRING) {
+ if (tn->tn_strg->st_tspec == CHAR) {
+ (void)printf("\"%s\"", tn->tn_strg->st_cp);
+ } else {
+ char *s;
+ size_t n;
+ n = MB_CUR_MAX * (tn->tn_strg->st_len + 1);
+ s = xmalloc(n);
+ (void)wcstombs(s, tn->tn_strg->st_wcp, n);
+ (void)printf("L\"%s\"", s);
+ free(s);
+ }
+ (void)printf(" ");
+ } else if (tn->tn_op == FSEL) {
+ (void)printf("o=%d, l=%d ", tn->tn_type->t_foffs,
+ tn->tn_type->t_flen);
+ }
+ (void)printf("%s\n", ttos(tn->tn_type));
+ if (tn->tn_op == NAME || tn->tn_op == CON || tn->tn_op == STRING)
+ return;
+ displexpr(tn->tn_left, offs + 2);
+ if (modtab[tn->tn_op].m_binary ||
+ (tn->tn_op == PUSH && tn->tn_right != NULL)) {
+ displexpr(tn->tn_right, offs + 2);
+ }
+}
+
+/*
+ * Called by expr() to recursively perform some tests.
+ */
+/* ARGSUSED */
+void
+chkmisc(tn, vctx, tctx, eqwarn, fcall, rvdisc, szof)
+ tnode_t *tn;
+ int vctx, tctx, eqwarn, fcall, rvdisc, szof;
+{
+ tnode_t *ln, *rn;
+ mod_t *mp;
+ int nrvdisc, cvctx, ctctx;
+ op_t op;
+ scl_t sc;
+ dinfo_t *di;
+
+ if (tn == NULL)
+ return;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+ mp = &modtab[op = tn->tn_op];
+
+ switch (op) {
+ case AMPER:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ if (!szof)
+ setsflg(ln->tn_sym);
+ setuflg(ln->tn_sym, fcall, szof);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 1);
+ break;
+ case LOAD:
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ /* FALLTHROUGH */
+ case PUSH:
+ case INCBEF:
+ case DECBEF:
+ case INCAFT:
+ case DECAFT:
+ case ADDASS:
+ case SUBASS:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ANDASS:
+ case ORASS:
+ case XORASS:
+ case SHLASS:
+ case SHRASS:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ sc = ln->tn_sym->s_scl;
+ /*
+ * Look if there was a asm statement in one of the
+ * compound statements we are in. If not, we don't
+ * print a warning.
+ */
+ for (di = dcs; di != NULL; di = di->d_nxt) {
+ if (di->d_asm)
+ break;
+ }
+ if (sc != EXTERN && sc != STATIC &&
+ !ln->tn_sym->s_set && !szof && di == NULL) {
+ /* %s may be used before set */
+ warning(158, ln->tn_sym->s_name);
+ setsflg(ln->tn_sym);
+ }
+ setuflg(ln->tn_sym, 0, 0);
+ }
+ break;
+ case ASSIGN:
+ if (ln->tn_op == NAME && !szof && (reached || rchflg)) {
+ setsflg(ln->tn_sym);
+ if (ln->tn_sym->s_scl == EXTERN)
+ outusg(ln->tn_sym);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ break;
+ case CALL:
+ if (ln->tn_op != AMPER || ln->tn_left->tn_op != NAME)
+ lerror("chkmisc() 1");
+ if (!szof)
+ outcall(tn, vctx || tctx, rvdisc);
+ break;
+ case EQ:
+ /* equality operator "==" found where "=" was exp. */
+ if (hflag && eqwarn)
+ warning(160);
+ break;
+ case CON:
+ case NAME:
+ case STRING:
+ return;
+ /* LINTED (enumeration values not handled in switch) */
+ default:
+ }
+
+ cvctx = mp->m_vctx;
+ ctctx = mp->m_tctx;
+ /*
+ * values of operands of ':' are not used if the type of at least
+ * one of the operands (for gcc compatibility) is void
+ * XXX test/value context of QUEST should probably be used as
+ * context for both operands of COLON
+ */
+ if (op == COLON && tn->tn_type->t_tspec == VOID)
+ cvctx = ctctx = 0;
+ nrvdisc = op == CVT && tn->tn_type->t_tspec == VOID;
+ chkmisc(ln, cvctx, ctctx, mp->m_eqwarn, op == CALL, nrvdisc, szof);
+
+ switch (op) {
+ case PUSH:
+ if (rn != NULL)
+ chkmisc(rn, 0, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case LOGAND:
+ case LOGOR:
+ chkmisc(rn, 0, 1, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case COLON:
+ chkmisc(rn, cvctx, ctctx, mp->m_eqwarn, 0, 0, szof);
+ break;
+ default:
+ if (mp->m_binary)
+ chkmisc(rn, 1, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ }
+
+}
+
+/*
+ * Checks the range of array indices, if possible.
+ * amper is set if only the address of the element is used. This
+ * means that the index is allowd to refere to the first element
+ * after the array.
+ */
+static void
+chkaidx(tn, amper)
+ tnode_t *tn;
+ int amper;
+{
+ int dim;
+ tnode_t *ln, *rn;
+ int elsz;
+ quad_t con;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+
+ /* We can only check constant indices. */
+ if (rn->tn_op != CON)
+ return;
+
+ /* Return if the left node does not stem from an array. */
+ if (ln->tn_op != AMPER)
+ return;
+ if (ln->tn_left->tn_op != STRING && ln->tn_left->tn_op != NAME)
+ return;
+ if (ln->tn_left->tn_type->t_tspec != ARRAY)
+ return;
+
+ /*
+ * For incomplete array types, we can print a warning only if
+ * the index is negative.
+ */
+ if (incompl(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0)
+ return;
+
+ /* Get the size of one array element */
+ if ((elsz = length(ln->tn_type->t_subt, NULL)) == 0)
+ return;
+ elsz /= CHAR_BIT;
+
+ /* Change the unit of the index from bytes to element size. */
+ if (isutyp(rn->tn_type->t_tspec)) {
+ con = (u_quad_t)rn->tn_val->v_quad / elsz;
+ } else {
+ con = rn->tn_val->v_quad / elsz;
+ }
+
+ dim = ln->tn_left->tn_type->t_dim + (amper ? 1 : 0);
+
+ if (!isutyp(rn->tn_type->t_tspec) && con < 0) {
+ /* array subscript cannot be negative: %ld */
+ warning(167, (long)con);
+ } else if (dim > 0 && (u_quad_t)con >= dim) {
+ /* array subscript cannot be > %d: %ld */
+ warning(168, dim - 1, (long)con);
+ }
+}
+
+/*
+ * Check for ordered comparisions of unsigned values with 0.
+ */
+static void
+chkcomp(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ mod_t *mp;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+ mp = &modtab[op];
+
+ if (ln->tn_op != CON && rn->tn_op != CON)
+ return;
+
+ if (!isityp(lt) || !isityp(rt))
+ return;
+
+ if ((hflag || pflag) && lt == CHAR && rn->tn_op == CON &&
+ (rn->tn_val->v_quad < 0 ||
+ rn->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if ((hflag || pflag) && rt == CHAR && ln->tn_op == CON &&
+ (ln->tn_val->v_quad < 0 ||
+ ln->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if (isutyp(lt) && !isutyp(rt) &&
+ rn->tn_op == CON && rn->tn_val->v_quad <= 0) {
+ if (rn->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "negative constant",
+ mp->m_name);
+ } else if (op == LT || op == GE || (hflag && op == LE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "0", mp->m_name);
+ }
+ return;
+ }
+ if (isutyp(rt) && !isutyp(lt) &&
+ ln->tn_op == CON && ln->tn_val->v_quad <= 0) {
+ if (ln->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "negative constant", tyname(rn->tn_type),
+ mp->m_name);
+ } else if (op == GT || op == LE || (hflag && op == GE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "0", tyname(rn->tn_type), mp->m_name);
+ }
+ return;
+ }
+}
+
+/*
+ * Takes an expression an returns 0 if this expression can be used
+ * for static initialisation, otherwise -1.
+ *
+ * Constant initialisation expressions must be costant or an address
+ * of a static object with an optional offset. In the first case,
+ * the result is returned in *offsp. In the second case, the static
+ * object is returned in *symp and the offset in *offsp.
+ *
+ * The expression can consist of PLUS, MINUS, AMPER, NAME, STRING and
+ * CON. Type conversions are allowed if they do not change binary
+ * representation (including width).
+ */
+int
+conaddr(tn, symp, offsp)
+ tnode_t *tn;
+ sym_t **symp;
+ ptrdiff_t *offsp;
+{
+ sym_t *sym;
+ ptrdiff_t offs1, offs2;
+ tspec_t t, ot;
+
+ switch (tn->tn_op) {
+ case MINUS:
+ if (tn->tn_right->tn_op != CON)
+ return (-1);
+ /* FALLTHROUGH */
+ case PLUS:
+ offs1 = offs2 = 0;
+ if (tn->tn_left->tn_op == CON) {
+ offs1 = (ptrdiff_t)tn->tn_left->tn_val->v_quad;
+ if (conaddr(tn->tn_right, &sym, &offs2) == -1)
+ return (-1);
+ } else if (tn->tn_right->tn_op == CON) {
+ offs2 = (ptrdiff_t)tn->tn_right->tn_val->v_quad;
+ if (tn->tn_op == MINUS)
+ offs2 = -offs2;
+ if (conaddr(tn->tn_left, &sym, &offs1) == -1)
+ return (-1);
+ } else {
+ return (-1);
+ }
+ *symp = sym;
+ *offsp = offs1 + offs2;
+ break;
+ case AMPER:
+ if (tn->tn_left->tn_op == NAME) {
+ *symp = tn->tn_left->tn_sym;
+ *offsp = 0;
+ } else if (tn->tn_left->tn_op == STRING) {
+ /*
+ * If this would be the front end of a compiler we
+ * would return a label instead of 0.
+ */
+ *offsp = 0;
+ }
+ break;
+ case CVT:
+ t = tn->tn_type->t_tspec;
+ ot = tn->tn_left->tn_type->t_tspec;
+ if ((!isityp(t) && t != PTR) || (!isityp(ot) && ot != PTR)) {
+ return (-1);
+ } else if (psize(t) != psize(ot)) {
+ return (-1);
+ }
+ if (conaddr(tn->tn_left, symp, offsp) == -1)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Concatenate two string constants.
+ */
+strg_t *
+catstrg(strg1, strg2)
+ strg_t *strg1, *strg2;
+{
+ size_t len1, len2, len;
+
+ if (strg1->st_tspec != strg2->st_tspec) {
+ /* cannot concatenate wide and regular string literals */
+ error(292);
+ return (strg1);
+ }
+
+ len = (len1 = strg1->st_len) + (len2 = strg2->st_len);
+
+ if (strg1->st_tspec == CHAR) {
+ strg1->st_cp = xrealloc(strg1->st_cp, len + 1);
+ (void)memcpy(strg1->st_cp + len1, strg2->st_cp, len2 + 1);
+ free(strg2->st_cp);
+ } else {
+ strg1->st_wcp = xrealloc(strg1->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ (void)memcpy(strg1->st_wcp + len1, strg2->st_wcp,
+ (len2 + 1) * sizeof (wchar_t));
+ free(strg2->st_wcp);
+ }
+ free(strg2);
+
+ return (strg1);
+}
+
+/*
+ * Print a warning if the given node has operands which should be
+ * parenthesized.
+ *
+ * XXX Does not work if an operand is a constant expression. Constant
+ * expressions are already folded.
+ */
+static void
+precconf(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ op_t lop, rop;
+ int lparn, rparn;
+ mod_t *mp;
+ int warn;
+
+ if (!hflag)
+ return;
+
+ mp = &modtab[tn->tn_op];
+
+ lparn = 0;
+ for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left)
+ lparn |= ln->tn_parn;
+ lparn |= ln->tn_parn;
+ lop = ln->tn_op;
+
+ if (mp->m_binary) {
+ rparn = 0;
+ for (rn = tn->tn_right; tn->tn_op == CVT; rn = rn->tn_left)
+ rparn |= rn->tn_parn;
+ rparn |= rn->tn_parn;
+ rop = rn->tn_op;
+ }
+
+ warn = 0;
+
+ switch (tn->tn_op) {
+ case SHL:
+ case SHR:
+ if (!lparn && (lop == PLUS || lop == MINUS)) {
+ warn = 1;
+ } else if (!rparn && (rop == PLUS || rop == MINUS)) {
+ warn = 1;
+ }
+ break;
+ case LOGOR:
+ if (!lparn && lop == LOGAND) {
+ warn = 1;
+ } else if (!rparn && rop == LOGAND) {
+ warn = 1;
+ }
+ break;
+ case AND:
+ case XOR:
+ case OR:
+ if (!lparn && lop != tn->tn_op) {
+ if (lop == PLUS || lop == MINUS) {
+ warn = 1;
+ } else if (lop == AND || lop == XOR) {
+ warn = 1;
+ }
+ }
+ if (!warn && !rparn && rop != tn->tn_op) {
+ if (rop == PLUS || rop == MINUS) {
+ warn = 1;
+ } else if (rop == AND || rop == XOR) {
+ warn = 1;
+ }
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ default:
+ }
+
+ if (warn) {
+ /* precedence confusion possible: parenthesize! */
+ warning(169);
+ }
+
+}
diff --git a/usr.bin/xlint/lint2/Makefile b/usr.bin/xlint/lint2/Makefile
new file mode 100644
index 0000000..0e7d405
--- /dev/null
+++ b/usr.bin/xlint/lint2/Makefile
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:24:39 cgd Exp $
+
+.PATH: ${.CURDIR}/../lint1
+
+PROG= lint2
+SRCS= main2.c hash.c read.c mem.c mem2.c chk.c msg.c emit.c emit2.c
+NOMAN=
+CFLAGS+=-I${.CURDIR}/../lint1
+LINTFLAGS=-abehrz
+
+BINDIR= /usr/libexec
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint2/chk.c b/usr.bin/xlint/lint2/chk.c
new file mode 100644
index 0000000..0aac852
--- /dev/null
+++ b/usr.bin/xlint/lint2/chk.c
@@ -0,0 +1,1462 @@
+/* $NetBSD: chk.c,v 1.2 1995/07/03 21:24:42 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: chk.c,v 1.2 1995/07/03 21:24:42 cgd Exp $";
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <err.h>
+
+#include "lint2.h"
+
+/* various type information */
+ttab_t ttab[NTSPEC];
+
+
+static void chkund __P((hte_t *));
+static void chkdnu __P((hte_t *));
+static void chkdnud __P((hte_t *));
+static void chkmd __P((hte_t *));
+static void chkvtui __P((hte_t *, sym_t *, sym_t *));
+static void chkvtdi __P((hte_t *, sym_t *, sym_t *));
+static void chkfaui __P((hte_t *, sym_t *, sym_t *));
+static void chkau __P((hte_t *, int, sym_t *, sym_t *, pos_t *,
+ fcall_t *, fcall_t *, type_t *, type_t *));
+static void chkrvu __P((hte_t *, sym_t *));
+static void chkadecl __P((hte_t *, sym_t *, sym_t *));
+static void printflike __P((hte_t *,fcall_t *, int,
+ const char *, type_t **));
+static void scanflike __P((hte_t *, fcall_t *, int,
+ const char *, type_t **));
+static void badfmt __P((hte_t *, fcall_t *));
+static void inconarg __P((hte_t *, fcall_t *, int));
+static void tofewarg __P((hte_t *, fcall_t *));
+static void tomanyarg __P((hte_t *, fcall_t *));
+static int eqtype __P((type_t *, type_t *, int, int, int, int *));
+static int eqargs __P((type_t *, type_t *, int *));
+static int mnoarg __P((type_t *, int *));
+
+
+void
+inittyp()
+{
+ int i;
+ static struct {
+ tspec_t it_tspec;
+ ttab_t it_ttab;
+ } ittab[] = {
+ { SIGNED, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "signed" } },
+ { UNSIGN, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "unsigned" } },
+ { CHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "char" } },
+ { SCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "signed char" } },
+ { UCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 1, 0, 1, 1, "unsigned char" } },
+ { SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 0, 0, 1, 1, "short" } },
+ { USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 1, 0, 1, 1, "unsigned short" } },
+ { INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 0, 0, 1, 1, "int" } },
+ { UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 1, 0, 1, 1, "unsigned int" } },
+ { LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 0, 0, 1, 1, "long" } },
+ { ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 1, 0, 1, 1, "unsigned long" } },
+ { QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 0, 0, 1, 1, "long long" } },
+ { UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 1, 0, 1, 1, "unsigned long long" } },
+ { FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
+ FLOAT, FLOAT,
+ 0, 0, 1, 1, 1, "float" } },
+ { DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
+ DOUBLE, DOUBLE,
+ 0, 0, 1, 1, 1, "double" } },
+ { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
+ LDOUBLE, LDOUBLE,
+ 0, 0, 1, 1, 1, "long double" } },
+ { VOID, { -1, -1,
+ VOID, VOID,
+ 0, 0, 0, 0, 0, "void" } },
+ { STRUCT, { -1, -1,
+ STRUCT, STRUCT,
+ 0, 0, 0, 0, 0, "struct" } },
+ { UNION, { -1, -1,
+ UNION, UNION,
+ 0, 0, 0, 0, 0, "union" } },
+ { ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ ENUM, ENUM,
+ 1, 0, 0, 1, 1, "enum" } },
+ { PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
+ PTR, PTR,
+ 0, 1, 0, 0, 1, "pointer" } },
+ { ARRAY, { -1, -1,
+ ARRAY, ARRAY,
+ 0, 0, 0, 0, 0, "array" } },
+ { FUNC, { -1, -1,
+ FUNC, FUNC,
+ 0, 0, 0, 0, 0, "function" } },
+ };
+
+ for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
+ STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
+ if (!pflag) {
+ for (i = 0; i < NTSPEC; i++)
+ ttab[i].tt_psz = ttab[i].tt_sz;
+ }
+}
+
+
+/*
+ * If there is a symbol named "main", mark it as used.
+ */
+void
+mainused()
+{
+ hte_t *hte;
+
+ if ((hte = hsearch("main", 0)) != NULL)
+ hte->h_used = 1;
+}
+
+/*
+ * Performs all tests for a single name
+ */
+void
+chkname(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def, *pdecl, *decl;
+
+ if (uflag) {
+ chkund(hte);
+ chkdnu(hte);
+ if (xflag)
+ chkdnud(hte);
+ }
+ chkmd(hte);
+
+ /* Get definition, prototype declaration and declaration */
+ def = pdecl = decl = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (def == NULL && (sym->s_def == DEF || sym->s_def == TDEF))
+ def = sym;
+ if (pdecl == NULL && sym->s_def == DECL &&
+ TP(sym->s_type)->t_tspec == FUNC &&
+ TP(sym->s_type)->t_proto) {
+ pdecl = sym;
+ }
+ if (decl == NULL && sym->s_def == DECL)
+ decl = sym;
+ }
+
+ /* A prototype is better than an old style declaration. */
+ if (pdecl != NULL)
+ decl = pdecl;
+
+ chkvtui(hte, def, decl);
+
+ chkvtdi(hte, def, decl);
+
+ chkfaui(hte, def, decl);
+
+ chkrvu(hte, def);
+
+ chkadecl(hte, def, decl);
+}
+
+/*
+ * Print a warning if the name has been used, but not defined.
+ */
+static void
+chkund(hte)
+ hte_t *hte;
+{
+ fcall_t *fcall;
+ usym_t *usym;
+
+ if (!hte->h_used || hte->h_def)
+ return;
+
+ if ((fcall = hte->h_calls) != NULL) {
+ /* %s used( %s ), but not defined */
+ msg(0, hte->h_name, mkpos(&fcall->f_pos));
+ } else if ((usym = hte->h_usyms) != NULL) {
+ /* %s used( %s ), but not defined */
+ msg(0, hte->h_name, mkpos(&usym->u_pos));
+ }
+}
+
+/*
+ * Print a warning if the name has been defined, but never used.
+ */
+static void
+chkdnu(hte)
+ hte_t *hte;
+{
+ sym_t *sym;
+
+ if (!hte->h_def || hte->h_used)
+ return;
+
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF || sym->s_def == TDEF) {
+ /* %s defined( %s ), but never used */
+ msg(1, hte->h_name, mkpos(&sym->s_pos));
+ break;
+ }
+ }
+}
+
+/*
+ * Print a warning if the name has been declared, but is not used
+ * or defined.
+ */
+static void
+chkdnud(hte)
+ hte_t *hte;
+{
+ sym_t *sym;
+
+ if (hte->h_syms == NULL || hte->h_used || hte->h_def)
+ return;
+
+ if ((sym = hte->h_syms) != NULL) {
+ if (sym->s_def != DECL)
+ errx(1, "internal error: chkdnud() 1");
+ /* %s declared( %s ), but never used or defined */
+ msg(2, hte->h_name, mkpos(&sym->s_pos));
+ }
+}
+
+/*
+ * Print a warning if there is more then one definition for
+ * this name.
+ */
+static void
+chkmd(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def1;
+ char *pos1;
+
+ if (!hte->h_def)
+ return;
+
+ def1 = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ /*
+ * ANSI C allows tentative definitions of the same name in
+ * only one compilation unit.
+ */
+ if (sym->s_def != DEF && (!sflag || sym->s_def != TDEF))
+ continue;
+ if (def1 == NULL) {
+ def1 = sym;
+ continue;
+ }
+ pos1 = xstrdup(mkpos(&def1->s_pos));
+ /* %s multiply defined\t%s :: %s */
+ msg(3, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+}
+
+/*
+ * Print a warning if the return value assumed for a function call
+ * differs from the return value of the function definition or
+ * function declaration.
+ *
+ * If no definition/declaration can be found, the assumed return values
+ * are always int. So there is no need to compare with another function
+ * call as it's done for function arguments.
+ */
+static void
+chkvtui(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ fcall_t *call;
+ char *pos1;
+ type_t *tp1, *tp2;
+ /* LINTED (automatic hides external declaration: warn) */
+ int warn, eq;
+ tspec_t t1;
+
+ if (hte->h_calls == NULL)
+ return;
+
+ if (def == NULL)
+ def = decl;
+ if (def == NULL)
+ return;
+
+ t1 = (tp1 = TP(def->s_type)->t_subt)->t_tspec;
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ tp2 = TP(call->f_type)->t_subt;
+ eq = eqtype(tp1, tp2, 1, 0, 0, (warn = 0, &warn));
+ if (!call->f_rused) {
+ /* no return value used */
+ if ((t1 == STRUCT || t1 == UNION) && !eq) {
+ /*
+ * If a function returns a struct or union it
+ * must be declared to return a struct or
+ * union, also if the return value is ignored.
+ * This is necessary because the caller must
+ * allocate stack space for the return value.
+ * If it does not, the return value would over-
+ * write other data.
+ * XXX Following massage may be confusing
+ * because it appears also if the return value
+ * was declared inconsistently. But this
+ * behaviour matches pcc based lint, so it is
+ * accepted for now.
+ */
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value must be decl. before use %s :: %s */
+ msg(17, hte->h_name,
+ pos1, mkpos(&call->f_pos));
+ free(pos1);
+ }
+ continue;
+ }
+ if (!eq || (sflag && warn)) {
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value used inconsistenty\t%s :: %s */
+ msg(4, hte->h_name, pos1, mkpos(&call->f_pos));
+ free(pos1);
+ }
+ }
+}
+
+/*
+ * Print a warning if a definition/declaration does not match another
+ * definition/declaration of the same name. For functions, only the
+ * types of return values are tested.
+ */
+static void
+chkvtdi(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ sym_t *sym;
+ type_t *tp1, *tp2;
+ /* LINTED (automatic hides external declaration: warn) */
+ int eq, warn;
+ char *pos1;
+
+ if (def == NULL)
+ def = decl;
+ if (def == NULL)
+ return;
+
+ tp1 = TP(def->s_type);
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym == def)
+ continue;
+ tp2 = TP(sym->s_type);
+ warn = 0;
+ if (tp1->t_tspec == FUNC && tp2->t_tspec == FUNC) {
+ eq = eqtype(tp1->t_subt, tp2->t_subt, 1, 0, 0, &warn);
+ } else {
+ eq = eqtype(tp1, tp2, 0, 0, 0, &warn);
+ }
+ if (!eq || (sflag && warn)) {
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value declared inconsistently\t%s :: %s */
+ msg(5, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+ }
+}
+
+/*
+ * Print a warning if a function is called with arguments which does
+ * not match the function definition, declaration or another call
+ * of the same function.
+ */
+static void
+chkfaui(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ type_t *tp1, *tp2, **ap1, **ap2;
+ pos_t *pos1p;
+ fcall_t *calls, *call, *call1;
+ int n, as;
+ char *pos1;
+ arginf_t *ai;
+
+ if ((calls = hte->h_calls) == NULL)
+ return;
+
+ /*
+ * If we find a function definition, we use this for comparision,
+ * otherwise the first prototype we can find. If there is no
+ * definition or prototype declaration, the first function call
+ * is used.
+ */
+ tp1 = NULL;
+ call1 = NULL;
+ if (def != NULL) {
+ if ((tp1 = TP(def->s_type))->t_tspec != FUNC)
+ return;
+ pos1p = &def->s_pos;
+ } else if (decl != NULL && TP(decl->s_type)->t_proto) {
+ if ((tp1 = TP(decl->s_type))->t_tspec != FUNC)
+ return;
+ pos1p = &decl->s_pos;
+ }
+ if (tp1 == NULL) {
+ call1 = calls;
+ calls = calls->f_nxt;
+ if ((tp1 = TP(call1->f_type))->t_tspec != FUNC)
+ return;
+ pos1p = &call1->f_pos;
+ }
+
+ n = 1;
+ for (call = calls; call != NULL; call = call->f_nxt) {
+ if ((tp2 = TP(call->f_type))->t_tspec != FUNC)
+ continue;
+ ap1 = tp1->t_args;
+ ap2 = tp2->t_args;
+ n = 0;
+ while (*ap1 != NULL && *ap2 != NULL) {
+ if (def != NULL && def->s_va && n >= def->s_nva)
+ break;
+ n++;
+ chkau(hte, n, def, decl, pos1p, call1, call,
+ *ap1, *ap2);
+ ap1++;
+ ap2++;
+ }
+ if (*ap1 == *ap2) {
+ /* equal # of arguments */
+ } else if (def != NULL && def->s_va && n >= def->s_nva) {
+ /*
+ * function definition with VARARGS; The # of
+ * arguments of the call must be at least as large
+ * as the parameter of VARARGS.
+ */
+ } else if (*ap2 != NULL && tp1->t_proto && tp1->t_vararg) {
+ /*
+ * prototype with ... and function call with
+ * at least the same # of arguments as declared
+ * in the prototype.
+ */
+ } else {
+ pos1 = xstrdup(mkpos(pos1p));
+ /* %s: variable # of args\t%s :: %s */
+ msg(7, hte->h_name, pos1, mkpos(&call->f_pos));
+ free(pos1);
+ continue;
+ }
+
+ /* perform SCANFLIKE/PRINTFLIKE tests */
+ if (def == NULL || (!def->s_prfl && !def->s_scfl))
+ continue;
+ as = def->s_prfl ? def->s_nprfl : def->s_nscfl;
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == as)
+ break;
+ }
+ if (ai == NULL || !ai->a_fmt)
+ continue;
+ if (def->s_prfl) {
+ printflike(hte, call, n, ai->a_fstrg, ap2);
+ } else {
+ scanflike(hte, call, n, ai->a_fstrg, ap2);
+ }
+ }
+}
+
+/*
+ * Check a single argument in a function call.
+ *
+ * hte a pointer to the hash table entry of the function
+ * n the number of the argument (1..)
+ * def the function definition or NULL
+ * decl prototype declaration, old style declaration or NULL
+ * pos1p position of definition, declaration of first call
+ * call1 first call, if both def and decl are old style def/decl
+ * call checked call
+ * arg1 currently checked argument of def/decl/call1
+ * arg2 currently checked argument of call
+ *
+ */
+static void
+chkau(hte, n, def, decl, pos1p, call1, call, arg1, arg2)
+ hte_t *hte;
+ int n;
+ sym_t *def, *decl;
+ pos_t *pos1p;
+ fcall_t *call1, *call;
+ type_t *arg1, *arg2;
+{
+ /* LINTED (automatic hides external declaration: warn) */
+ int promote, asgn, warn;
+ tspec_t t1, t2;
+ arginf_t *ai, *ai1;
+ char *pos1;
+
+ /*
+ * If a function definition is available (def != NULL), we compair the
+ * function call (call) with the definition. Otherwise, if a function
+ * definition is available and it is not an old style definition
+ * (decl != NULL && TP(decl->s_type)->t_proto), we compair the call
+ * with this declaration. Otherwise we compair it with the first
+ * call we have found (call1).
+ */
+
+ /* arg1 must be promoted if it stems from an old style definition */
+ promote = def != NULL && def->s_osdef;
+
+ /*
+ * If we compair with a definition or declaration, we must perform
+ * the same checks for qualifiers in indirected types as in
+ * assignments.
+ */
+ asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto);
+
+ warn = 0;
+ if (eqtype(arg1, arg2, 1, promote, asgn, &warn) && (!sflag || !warn))
+ return;
+
+ /*
+ * Other lint implementations print warnings as soon as the type
+ * of an argument does not match exactly the expected type. The
+ * result are lots of warnings which are really not neccessary.
+ * We print a warning only if
+ * (0) at least one type is not an interger type and types differ
+ * (1) hflag is set and types differ
+ * (2) types differ, except in signedness
+ * If the argument is an integer constant whose msb is not set,
+ * signedness is ignored (e.g. 0 matches both signed and unsigned
+ * int). This is with and without hflag.
+ * If the argument is an integer constant with value 0 and the
+ * expected argument is of type pointer and the width of the
+ * interger constant is the same as the width of the pointer,
+ * no warning is printed.
+ */
+ t1 = arg1->t_tspec;
+ t2 = arg2->t_tspec;
+ if (isityp(t1) && isityp(t2) && !arg1->t_isenum && !arg2->t_isenum) {
+ if (promote) {
+ /*
+ * XXX Here is a problem: Althrough it is possible to
+ * pass an int where a char/short it expected, there
+ * may be loss in significant digits. We should first
+ * check for const arguments if they can be converted
+ * into the original parameter type.
+ */
+ if (t1 == FLOAT) {
+ t1 = DOUBLE;
+ } else if (t1 == CHAR || t1 == SCHAR) {
+ t1 = INT;
+ } else if (t1 == UCHAR) {
+ t1 = tflag ? UINT : INT;
+ } else if (t1 == SHORT) {
+ t1 = INT;
+ } else if (t1 == USHORT) {
+ /* CONSTCOND */
+ t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (styp(t1) == styp(t2)) {
+
+ /*
+ * types differ only in signedness; get information
+ * about arguments
+ */
+
+ /*
+ * treat a definition like a call with variable
+ * arguments
+ */
+ ai1 = call1 != NULL ? call1->f_args : NULL;
+
+ /*
+ * if two calls are compared, ai1 is set to the
+ * information for the n-th argument, if this was
+ * a constant, otherwise to NULL
+ */
+ for ( ; ai1 != NULL; ai1 = ai1->a_nxt) {
+ if (ai1->a_num == n)
+ break;
+ }
+ /*
+ * ai is set to the information of the n-th arg
+ * of the (second) call, if this was a constant,
+ * otherwise to NULL
+ */
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == n)
+ break;
+ }
+
+ if (ai1 == NULL && ai == NULL) {
+ /* no constant at all */
+ if (!hflag)
+ return;
+ } else if (ai1 == NULL || ai == NULL) {
+ /* one constant */
+ if (ai == NULL)
+ ai = ai1;
+ if (ai->a_zero || ai->a_pcon)
+ /* same value in signed and unsigned */
+ return;
+ /* value (not representation) differently */
+ } else {
+ /*
+ * two constants, one signed, one unsigned;
+ * if the msb of one of the constants is set,
+ * the argument is used inconsistently.
+ */
+ if (!ai1->a_ncon && !ai->a_ncon)
+ return;
+ }
+ }
+
+ } else if (t1 == PTR && isityp(t2) && psize(t1) == psize(t2)) {
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == n)
+ break;
+ }
+ if (ai != NULL && ai->a_zero)
+ return;
+ }
+
+ pos1 = xstrdup(mkpos(pos1p));
+ /* %s, arg %d used inconsistently\t%s :: %s */
+ msg(6, hte->h_name, n, pos1, mkpos(&call->f_pos));
+ free(pos1);
+}
+
+/*
+ * Compare the types in the NULL-terminated array ap with the format
+ * string fmt.
+ */
+static void
+printflike(hte, call, n, fmt, ap)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+ const char *fmt;
+ type_t **ap;
+{
+ const char *fp;
+ int fc;
+ int fwidth, prec, left, sign, space, alt, zero;
+ tspec_t sz, t1, t2;
+ type_t *tp;
+
+ fp = fmt;
+ fc = *fp++;
+
+ for ( ; ; ) {
+ if (fc == '\0') {
+ if (*ap != NULL)
+ tomanyarg(hte, call);
+ break;
+ }
+ if (fc != '%') {
+ badfmt(hte, call);
+ break;
+ }
+ fc = *fp++;
+ fwidth = prec = left = sign = space = alt = zero = 0;
+ sz = NOTSPEC;
+
+ /* Flags */
+ for ( ; ; ) {
+ if (fc == '-') {
+ if (left)
+ break;
+ left = 1;
+ } else if (fc == '+') {
+ if (sign)
+ break;
+ sign = 1;
+ } else if (fc == ' ') {
+ if (space)
+ break;
+ space = 1;
+ } else if (fc == '#') {
+ if (alt)
+ break;
+ alt = 1;
+ } else if (fc == '0') {
+ if (zero)
+ break;
+ zero = 1;
+ } else {
+ break;
+ }
+ fc = *fp++;
+ }
+
+ /* field width */
+ if (isdigit(fc)) {
+ fwidth = 1;
+ do { fc = *fp++; } while (isdigit(fc)) ;
+ } else if (fc == '*') {
+ fwidth = 1;
+ fc = *fp++;
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT))
+ inconarg(hte, call, n);
+ }
+
+ /* precision */
+ if (fc == '.') {
+ fc = *fp++;
+ prec = 1;
+ if (isdigit(fc)) {
+ do { fc = *fp++; } while (isdigit(fc));
+ } else if (fc == '*') {
+ fc = *fp++;
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if (tp->t_tspec != INT)
+ inconarg(hte, call, n);
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+ }
+
+ if (fc == 'h') {
+ sz = SHORT;
+ } else if (fc == 'l') {
+ sz = LONG;
+ } else if (fc == 'q') {
+ sz = QUAD;
+ } else if (fc == 'L') {
+ sz = LDOUBLE;
+ }
+ if (sz != NOTSPEC)
+ fc = *fp++;
+
+ if (fc == '%') {
+ if (sz != NOTSPEC || left || sign || space ||
+ alt || zero || prec || fwidth) {
+ badfmt(hte, call);
+ }
+ fc = *fp++;
+ continue;
+ }
+
+ if (fc == '\0') {
+ badfmt(hte, call);
+ break;
+ }
+
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) == PTR)
+ t2 = tp->t_subt->t_tspec;
+
+ if (fc == 'd' || fc == 'i') {
+ if (alt || sz == LDOUBLE) {
+ badfmt(hte, call);
+ break;
+ }
+ int_conv:
+ if (sz == LONG) {
+ if (t1 != LONG && (hflag || t1 != ULONG))
+ inconarg(hte, call, n);
+ } else if (sz == QUAD) {
+ if (t1 != QUAD && (hflag || t1 != UQUAD))
+ inconarg(hte, call, n);
+ } else {
+ /*
+ * SHORT is always promoted to INT, USHORT
+ * to INT or UINT.
+ */
+ if (t1 != INT && (hflag || t1 != UINT))
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') {
+ if ((alt && fc == 'u') || sz == LDOUBLE)
+ badfmt(hte, call);
+ uint_conv:
+ if (sz == LONG) {
+ if (t1 != ULONG && (hflag || t1 != LONG))
+ inconarg(hte, call, n);
+ } else if (sz == QUAD) {
+ if (t1 != UQUAD && (hflag || t1 != QUAD))
+ inconarg(hte, call, n);
+ } else if (sz == SHORT) {
+ /* USHORT was promoted to INT or UINT */
+ if (t1 != UINT && t1 != INT)
+ inconarg(hte, call, n);
+ } else {
+ if (t1 != UINT && (hflag || t1 != INT))
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'D' || fc == 'O' || fc == 'U') {
+ if ((alt && fc != 'O') || sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = LONG;
+ if (fc == 'D') {
+ goto int_conv;
+ } else {
+ goto uint_conv;
+ }
+ } else if (fc == 'f' || fc == 'e' || fc == 'E' ||
+ fc == 'g' || fc == 'G') {
+ if (sz == NOTSPEC)
+ sz = DOUBLE;
+ if (sz != DOUBLE && sz != LDOUBLE)
+ badfmt(hte, call);
+ if (t1 != sz)
+ inconarg(hte, call, n);
+ } else if (fc == 'c') {
+ if (sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != INT)
+ inconarg(hte, call, n);
+ } else if (fc == 's') {
+ if (sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != PTR ||
+ (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) {
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'p') {
+ if (fwidth || prec || sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != PTR || (hflag && t2 != VOID))
+ inconarg(hte, call, n);
+ } else if (fc == 'n') {
+ if (fwidth || prec || alt || zero || sz == LDOUBLE)
+ badfmt(hte, call);
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (sz == LONG) {
+ if (t2 != LONG && t2 != ULONG)
+ inconarg(hte, call, n);
+ } else if (sz == SHORT) {
+ if (t2 != SHORT && t2 != USHORT)
+ inconarg(hte, call, n);
+ } else {
+ if (t2 != INT && t2 != UINT)
+ inconarg(hte, call, n);
+ }
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+
+ fc = *fp++;
+ }
+}
+
+/*
+ * Compare the types in the NULL-terminated array ap with the format
+ * string fmt.
+ */
+static void
+scanflike(hte, call, n, fmt, ap)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+ const char *fmt;
+ type_t **ap;
+{
+ const char *fp;
+ int fc;
+ int noasgn, fwidth;
+ tspec_t sz, t1, t2;
+ type_t *tp;
+
+ fp = fmt;
+ fc = *fp++;
+
+ for ( ; ; ) {
+ if (fc == '\0') {
+ if (*ap != NULL)
+ tomanyarg(hte, call);
+ break;
+ }
+ if (fc != '%') {
+ badfmt(hte, call);
+ break;
+ }
+ fc = *fp++;
+
+ noasgn = fwidth = 0;
+ sz = NOTSPEC;
+
+ if (fc == '*') {
+ noasgn = 1;
+ fc = *fp++;
+ }
+
+ if (isdigit(fc)) {
+ fwidth = 1;
+ do { fc = *fp++; } while (isdigit(fc));
+ }
+
+ if (fc == 'h') {
+ sz = SHORT;
+ } else if (fc == 'l') {
+ sz = LONG;
+ } else if (fc == 'q') {
+ sz = QUAD;
+ } else if (fc == 'L') {
+ sz = LDOUBLE;
+ }
+ if (sz != NOTSPEC)
+ fc = *fp++;
+
+ if (fc == '%') {
+ if (sz != NOTSPEC || noasgn || fwidth)
+ badfmt(hte, call);
+ fc = *fp++;
+ continue;
+ }
+
+ if (!noasgn) {
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) == PTR)
+ t2 = tp->t_subt->t_tspec;
+ }
+
+ if (fc == 'd' || fc == 'i' || fc == 'n') {
+ if (sz == LDOUBLE)
+ badfmt(hte, call);
+ if (sz != SHORT && sz != LONG && sz != QUAD)
+ sz = INT;
+ conv:
+ if (!noasgn) {
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (t2 != styp(sz)) {
+ inconarg(hte, call, n);
+ } else if (hflag && t2 != sz) {
+ inconarg(hte, call, n);
+ } else if (tp->t_subt->t_const) {
+ inconarg(hte, call, n);
+ }
+ }
+ } else if (fc == 'o' || fc == 'u' || fc == 'x') {
+ if (sz == LDOUBLE)
+ badfmt(hte, call);
+ if (sz == SHORT) {
+ sz = USHORT;
+ } else if (sz == LONG) {
+ sz = ULONG;
+ } else if (sz == QUAD) {
+ sz = UQUAD;
+ } else {
+ sz = UINT;
+ }
+ goto conv;
+ } else if (fc == 'D') {
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = LONG;
+ goto conv;
+ } else if (fc == 'O') {
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = ULONG;
+ goto conv;
+ } else if (fc == 'X') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc imple-
+ * mented as "lx". Thats why it should be avoided.
+ */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = ULONG;
+ goto conv;
+ } else if (fc == 'E') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc imple-
+ * mented as "lf". Thats why it should be avoided.
+ */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = DOUBLE;
+ goto conv;
+ } else if (fc == 'F') {
+ /* XXX only for backward compatibility */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = DOUBLE;
+ goto conv;
+ } else if (fc == 'G') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc not
+ * implemented
+ */
+ if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE)
+ badfmt(hte, call);
+ goto fconv;
+ } else if (fc == 'e' || fc == 'f' || fc == 'g') {
+ fconv:
+ if (sz == NOTSPEC) {
+ sz = FLOAT;
+ } else if (sz == LONG) {
+ sz = DOUBLE;
+ } else if (sz != LDOUBLE) {
+ badfmt(hte, call);
+ sz = FLOAT;
+ }
+ goto conv;
+ } else if (fc == 's' || fc == '[' || fc == 'c') {
+ if (sz != NOTSPEC)
+ badfmt(hte, call);
+ if (fc == '[') {
+ if ((fc = *fp++) == '-') {
+ badfmt(hte, call);
+ fc = *fp++;
+ }
+ if (fc != ']') {
+ badfmt(hte, call);
+ if (fc == '\0')
+ break;
+ }
+ }
+ if (!noasgn) {
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (t2 != CHAR && t2 != UCHAR &&
+ t2 != SCHAR) {
+ inconarg(hte, call, n);
+ }
+ }
+ } else if (fc == 'p') {
+ if (sz != NOTSPEC)
+ badfmt(hte, call);
+ if (!noasgn) {
+ if (t1 != PTR || t2 != PTR) {
+ inconarg(hte, call, n);
+ } else if (tp->t_subt->t_subt->t_tspec!=VOID) {
+ if (hflag)
+ inconarg(hte, call, n);
+ }
+ }
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+
+ fc = *fp++;
+ }
+}
+
+static void
+badfmt(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: malformed format string\t%s */
+ msg(13, hte->h_name, mkpos(&call->f_pos));
+}
+
+static void
+inconarg(hte, call, n)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+{
+ /* %s, arg %d inconsistent with format\t%s(%d) */
+ msg(14, hte->h_name, n, mkpos(&call->f_pos));
+}
+
+static void
+tofewarg(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: too few args for format \t%s */
+ msg(15, hte->h_name, mkpos(&call->f_pos));
+}
+
+static void
+tomanyarg(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: too many args for format \t%s */
+ msg(16, hte->h_name, mkpos(&call->f_pos));
+}
+
+
+/*
+ * Print warnings for return values which are used, but not returned,
+ * or return values which are always or sometimes ignored.
+ */
+static void
+chkrvu(hte, def)
+ hte_t *hte;
+ sym_t *def;
+{
+ fcall_t *call;
+ int used, ignored;
+
+ if (def == NULL)
+ /* don't know wheter or not the functions returns a value */
+ return;
+
+ if (hte->h_calls == NULL)
+ return;
+
+ if (def->s_rval) {
+ /* function has return value */
+ used = ignored = 0;
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ used |= call->f_rused;
+ ignored |= !call->f_rused && !call->f_rdisc;
+ }
+ /*
+ * XXX as soon as we are able to disable single warnings
+ * the following dependencies from hflag should be removed.
+ * but for now I do'nt want to be botherd by this warnings
+ * which are almost always useless.
+ */
+ if (!used && ignored) {
+ if (hflag)
+ /* %s returns value which is always ignored */
+ msg(8, hte->h_name);
+ } else if (used && ignored) {
+ if (hflag)
+ /* %s returns value which is sometimes ign. */
+ msg(9, hte->h_name);
+ }
+ } else {
+ /* function has no return value */
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ if (call->f_rused)
+ /* %s value is used( %s ), but none ret. */
+ msg(10, hte->h_name, mkpos(&call->f_pos));
+ }
+ }
+}
+
+/*
+ * Print warnings for inconsistent argument declarations.
+ */
+static void
+chkadecl(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ /* LINTED (automatic hides external declaration: warn) */
+ int osdef, eq, warn, n;
+ sym_t *sym1, *sym;
+ type_t **ap1, **ap2, *tp1, *tp2;
+ char *pos1;
+ const char *pos2;
+
+ osdef = 0;
+ if (def != NULL) {
+ osdef = def->s_osdef;
+ sym1 = def;
+ } else if (decl != NULL && TP(decl->s_type)->t_proto) {
+ sym1 = decl;
+ } else {
+ return;
+ }
+ if (TP(sym1->s_type)->t_tspec != FUNC)
+ return;
+
+ /*
+ * XXX Prototypes should also be compared with old style function
+ * declarations.
+ */
+
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym == sym1 || !TP(sym->s_type)->t_proto)
+ continue;
+ ap1 = TP(sym1->s_type)->t_args;
+ ap2 = TP(sym->s_type)->t_args;
+ n = 0;
+ while (*ap1 != NULL && *ap2 != NULL) {
+ warn = 0;
+ eq = eqtype(*ap1, *ap2, 1, osdef, 0, &warn);
+ if (!eq || warn) {
+ pos1 = xstrdup(mkpos(&sym1->s_pos));
+ pos2 = mkpos(&sym->s_pos);
+ /* %s, arg %d declared inconsistently ... */
+ msg(11, hte->h_name, n + 1, pos1, pos2);
+ free(pos1);
+ }
+ n++;
+ ap1++;
+ ap2++;
+ }
+ if (*ap1 == *ap2) {
+ tp1 = TP(sym1->s_type);
+ tp2 = TP(sym->s_type);
+ if (tp1->t_vararg == tp2->t_vararg)
+ continue;
+ if (tp2->t_vararg &&
+ sym1->s_va && sym1->s_nva == n && !sflag) {
+ continue;
+ }
+ }
+ /* %s: variable # of args declared\t%s :: %s */
+ pos1 = xstrdup(mkpos(&sym1->s_pos));
+ msg(12, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+}
+
+
+/*
+ * Check compatibility of two types. Returns 1 if types are compatible,
+ * otherwise 0.
+ *
+ * ignqual if set, ignore qualifiers of outhermost type; used for
+ * function arguments
+ * promote if set, promote left type before comparision; used for
+ * comparisions of arguments with parameters of old style
+ * definitions
+ * asgn left indirected type must have at least the same qualifiers
+ * like right indirected type (for assignments and function
+ * arguments)
+ * *warn set to 1 if an old style declaration was compared with
+ * an incompatible prototype declaration
+ */
+static int
+eqtype(tp1, tp2, ignqual, promot, asgn, warn)
+ type_t *tp1, *tp2;
+ int ignqual, promot, asgn, *warn;
+{
+ tspec_t t, to;
+ int indir;
+
+ to = NOTSPEC;
+ indir = 0;
+
+ while (tp1 != NULL && tp2 != NULL) {
+
+ t = tp1->t_tspec;
+ if (promot) {
+ if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == CHAR || t == SCHAR) {
+ t = INT;
+ } else if (t == UCHAR) {
+ t = tflag ? UINT : INT;
+ } else if (t == SHORT) {
+ t = INT;
+ } else if (t == USHORT) {
+ /* CONSTCOND */
+ t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (asgn && to == PTR) {
+ if (indir == 1 && (t == VOID || tp2->t_tspec == VOID))
+ return (1);
+ }
+
+ if (t != tp2->t_tspec) {
+ /*
+ * Give pointer to types which differ only in
+ * signedness a chance if not sflag and not hflag.
+ */
+ if (sflag || hflag || to != PTR)
+ return (0);
+ if (styp(t) != styp(tp2->t_tspec))
+ return (0);
+ }
+
+ if (tp1->t_isenum && tp2->t_isenum) {
+ if (tp1->t_istag && tp2->t_istag) {
+ return (tp1->t_tag == tp2->t_tag);
+ } else if (tp1->t_istynam && tp2->t_istynam) {
+ return (tp1->t_tynam == tp2->t_tynam);
+ } else {
+ return (0);
+ }
+ }
+
+ /*
+ * XXX Handle combinations of enum and int if eflag is set.
+ * But note: enum and 0 should be allowed.
+ */
+
+ if (asgn && indir == 1) {
+ if (!tp1->t_const && tp2->t_const)
+ return (0);
+ if (!tp1->t_volatile && tp2->t_volatile)
+ return (0);
+ } else if (!ignqual && !tflag) {
+ if (tp1->t_const != tp2->t_const)
+ return (0);
+ if (tp1->t_const != tp2->t_const)
+ return (0);
+ }
+
+ if (t == STRUCT || t == UNION) {
+ if (tp1->t_istag && tp2->t_istag) {
+ return (tp1->t_tag == tp2->t_tag);
+ } else if (tp1->t_istynam && tp2->t_istynam) {
+ return (tp1->t_tynam == tp2->t_tynam);
+ } else {
+ return (0);
+ }
+ }
+
+ if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
+ if (tp1->t_dim != 0 && tp2->t_dim != 0)
+ return (0);
+ }
+
+ if (t == FUNC) {
+ if (tp1->t_proto && tp2->t_proto) {
+ if (!eqargs(tp1, tp2, warn))
+ return (0);
+ } else if (tp1->t_proto) {
+ if (!mnoarg(tp1, warn))
+ return (0);
+ } else if (tp2->t_proto) {
+ if (!mnoarg(tp2, warn))
+ return (0);
+ }
+ }
+
+ tp1 = tp1->t_subt;
+ tp2 = tp2->t_subt;
+ ignqual = promot = 0;
+ to = t;
+ indir++;
+
+ }
+
+ return (tp1 == tp2);
+}
+
+/*
+ * Compares arguments of two prototypes
+ */
+static int
+eqargs(tp1, tp2, warn)
+ type_t *tp1, *tp2;
+ int *warn;
+{
+ type_t **a1, **a2;
+
+ if (tp1->t_vararg != tp2->t_vararg)
+ return (0);
+
+ a1 = tp1->t_args;
+ a2 = tp2->t_args;
+
+ while (*a1 != NULL && *a2 != NULL) {
+
+ if (eqtype(*a1, *a2, 1, 0, 0, warn) == 0)
+ return (0);
+
+ a1++;
+ a2++;
+
+ }
+
+ return (*a1 == *a2);
+}
+
+/*
+ * mnoarg() (matches functions with no argument type information)
+ * returns 1 if all parameters of a prototype are compatible with
+ * and old style function declaration.
+ * This is the case if following conditions are met:
+ * 1. the prototype must have a fixed number of parameters
+ * 2. no parameter is of type float
+ * 3. no parameter is converted to another type if integer promotion
+ * is applied on it
+ */
+static int
+mnoarg(tp, warn)
+ type_t *tp;
+ int *warn;
+{
+ type_t **arg;
+ tspec_t t;
+
+ if (tp->t_vararg && warn != NULL)
+ *warn = 1;
+ for (arg = tp->t_args; *arg != NULL; arg++) {
+ if ((t = (*arg)->t_tspec) == FLOAT)
+ return (0);
+ if (t == CHAR || t == SCHAR || t == UCHAR)
+ return (0);
+ if (t == SHORT || t == USHORT)
+ return (0);
+ }
+ return (1);
+}
+
diff --git a/usr.bin/xlint/lint2/emit2.c b/usr.bin/xlint/lint2/emit2.c
new file mode 100644
index 0000000..82527b5
--- /dev/null
+++ b/usr.bin/xlint/lint2/emit2.c
@@ -0,0 +1,236 @@
+/* $NetBSD: emit2.c,v 1.2 1995/07/03 21:24:44 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit2.c,v 1.2 1995/07/03 21:24:44 cgd Exp $";
+#endif
+
+#include <err.h>
+
+#include "lint2.h"
+
+static void outtype __P((type_t *));
+static void outdef __P((hte_t *, sym_t *));
+static void dumpname __P((hte_t *));
+
+/*
+ * Write type into the output buffer.
+ */
+static void
+outtype(tp)
+ type_t *tp;
+{
+ int t, s, na;
+ tspec_t ts;
+ type_t **ap;
+
+ while (tp != NULL) {
+ if ((ts = tp->t_tspec) == INT && tp->t_isenum)
+ ts = ENUM;
+ switch (ts) {
+ case CHAR: t = 'C'; s = '\0'; break;
+ case SCHAR: t = 'C'; s = 's'; break;
+ case UCHAR: t = 'C'; s = 'u'; break;
+ case SHORT: t = 'S'; s = '\0'; break;
+ case USHORT: t = 'S'; s = 'u'; break;
+ case INT: t = 'I'; s = '\0'; break;
+ case UINT: t = 'I'; s = 'u'; break;
+ case LONG: t = 'L'; s = '\0'; break;
+ case ULONG: t = 'L'; s = 'u'; break;
+ case QUAD: t = 'Q'; s = '\0'; break;
+ case UQUAD: t = 'Q'; s = 'u'; break;
+ case FLOAT: t = 'D'; s = 's'; break;
+ case DOUBLE: t = 'D'; s = '\0'; break;
+ case LDOUBLE: t = 'D'; s = 'l'; break;
+ case VOID: t = 'V'; s = '\0'; break;
+ case PTR: t = 'P'; s = '\0'; break;
+ case ARRAY: t = 'A'; s = '\0'; break;
+ case ENUM: t = 'T'; s = 'e'; break;
+ case STRUCT: t = 'T'; s = 's'; break;
+ case UNION: t = 'T'; s = 'u'; break;
+ case FUNC:
+ if (tp->t_args != NULL && !tp->t_proto) {
+ t = 'f';
+ } else {
+ t = 'F';
+ }
+ s = '\0';
+ break;
+ default:
+ errx(1, "internal error: outtype() 1");
+ }
+ if (tp->t_const)
+ outchar('c');
+ if (tp->t_volatile)
+ outchar('v');
+ if (s != '\0')
+ outchar(s);
+ outchar(t);
+ if (ts == ARRAY) {
+ outint(tp->t_dim);
+ } else if (ts == ENUM || ts == STRUCT || ts == UNION) {
+ if (tp->t_istag) {
+ outint(1);
+ outname(tp->t_tag->h_name);
+ } else if (tp->t_istynam) {
+ outint(2);
+ outname(tp->t_tynam->h_name);
+ } else {
+ outint(0);
+ }
+ } else if (ts == FUNC && tp->t_args != NULL) {
+ na = 0;
+ for (ap = tp->t_args; *ap != NULL; ap++)
+ na++;
+ if (tp->t_vararg)
+ na++;
+ outint(na);
+ for (ap = tp->t_args; *ap != NULL; ap++)
+ outtype(*ap);
+ if (tp->t_vararg)
+ outchar('E');
+ }
+ tp = tp->t_subt;
+ }
+}
+
+/*
+ * Write a definition.
+ */
+static void
+outdef(hte, sym)
+ hte_t *hte;
+ sym_t *sym;
+{
+ /* reset output buffer */
+ outclr();
+
+ /* line number in C source file */
+ outint(0);
+
+ /* this is a definition */
+ outchar('d');
+
+ /* index of file where symbol was defined and line number of def. */
+ outint(0);
+ outchar('.');
+ outint(0);
+
+ /* flags */
+ if (sym->s_va) {
+ outchar('v'); /* varargs */
+ outint(sym->s_nva);
+ }
+ if (sym->s_scfl) {
+ outchar('S'); /* scanflike */
+ outint(sym->s_nscfl);
+ }
+ if (sym->s_prfl) {
+ outchar('P'); /* printflike */
+ outint(sym->s_nprfl);
+ }
+ /* definition or tentative definition */
+ outchar(sym->s_def == DEF ? 'd' : 't');
+ if (TP(sym->s_type)->t_tspec == FUNC) {
+ if (sym->s_rval)
+ outchar('r'); /* fkt. has return value */
+ if (sym->s_osdef)
+ outchar('o'); /* old style definition */
+ }
+ outchar('u'); /* used (no warning if not used) */
+
+ /* name */
+ outname(hte->h_name);
+
+ /* type */
+ outtype(TP(sym->s_type));
+}
+
+/*
+ * Write the first definition of a name into the lint library.
+ */
+static void
+dumpname(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def;
+
+ /* static and undefined symbols are not written */
+ if (hte->h_static || !hte->h_def)
+ return;
+
+ /*
+ * If there is a definition, write it. Otherwise write a tentative
+ * definition. This is neccessary because more than one tentative
+ * definition is allowed (except with sflag).
+ */
+ def = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF) {
+ def = sym;
+ break;
+ }
+ if (sym->s_def == TDEF && def == NULL)
+ def = sym;
+ }
+ if (def == NULL)
+ errx(1, "internal error: dumpname() %s", hte->h_name);
+
+ outdef(hte, def);
+}
+
+/*
+ * Write a new lint library.
+ */
+void
+outlib(name)
+ const char *name;
+{
+ /* Open of output file and initialisation of the output buffer */
+ outopen(name);
+
+ /* write name of lint library */
+ outsrc(name);
+
+ /* name of lint lib has index 0 */
+ outclr();
+ outint(0);
+ outchar('s');
+ outstrg(name);
+
+ /* write all definitions with external linkage */
+ forall(dumpname);
+
+ /* close the output */
+ outclose();
+}
diff --git a/usr.bin/xlint/lint2/externs2.h b/usr.bin/xlint/lint2/externs2.h
new file mode 100644
index 0000000..2e65e53
--- /dev/null
+++ b/usr.bin/xlint/lint2/externs2.h
@@ -0,0 +1,87 @@
+/* $NetBSD: externs2.h,v 1.2 1995/07/03 21:24:46 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * main.c
+ */
+extern int xflag;
+extern int uflag;
+extern int Cflag;
+extern const char *libname;
+extern int pflag;
+extern int sflag;
+extern int tflag;
+extern int Hflag;
+extern int hflag;
+extern int Fflag;
+
+
+/*
+ * hash.c
+ */
+extern void inithash __P((void));
+extern hte_t *hsearch __P((const char *, int));
+extern void forall __P((void (*)(hte_t *)));
+
+/*
+ * read.c
+ */
+extern const char **fnames;
+extern type_t **tlst;
+
+extern void readfile __P((const char *));
+extern void mkstatic __P((hte_t *));
+
+/*
+ * mem2.c
+ */
+extern void initmem __P((void));
+extern void *xalloc __P((size_t));
+
+/*
+ * chk.c
+ */
+extern void inittyp __P((void));
+extern void mainused __P((void));
+extern void chkname __P((hte_t *));
+
+/*
+ * msg.c
+ */
+extern void msg __P((int, ...));
+extern const char *mkpos __P((pos_t *));
+
+/*
+ * emit2.c
+ */
+extern void outlib __P((const char *));
diff --git a/usr.bin/xlint/lint2/hash.c b/usr.bin/xlint/lint2/hash.c
new file mode 100644
index 0000000..7901802
--- /dev/null
+++ b/usr.bin/xlint/lint2/hash.c
@@ -0,0 +1,123 @@
+/* $NetBSD: hash.c,v 1.2 1995/07/03 21:24:47 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: hash.c,v 1.2 1995/07/03 21:24:47 cgd Exp $";
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+
+#include "lint2.h"
+
+/* pointer to hash table, initialized in inithash() */
+static hte_t **htab;
+
+static int hash __P((const char *));
+
+/*
+ * Initialize hash table.
+ */
+void
+inithash()
+{
+ htab = xcalloc(HSHSIZ2, sizeof (hte_t *));
+}
+
+/*
+ * Compute hash value from a string.
+ */
+static int
+hash(s)
+ const char *s;
+{
+ u_int v;
+ const u_char *us;
+
+ v = 0;
+ for (us = (const u_char *)s; *us != '\0'; us++) {
+ v = (v << sizeof (v)) + *us;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % HSHSIZ2);
+}
+
+/*
+ * Look for a hash table entry. If no hash table entry for the
+ * given name exists and mknew is set, create a new one.
+ */
+hte_t *
+hsearch(s, mknew)
+ const char *s;
+ int mknew;
+{
+ int h;
+ hte_t *hte;
+
+ h = hash(s);
+ for (hte = htab[h]; hte != NULL; hte = hte->h_link) {
+ if (strcmp(hte->h_name, s) == 0)
+ break;
+ }
+
+ if (hte != NULL || !mknew)
+ return (hte);
+
+ /* create a new hte */
+ hte = xalloc(sizeof (hte_t));
+ hte->h_name = xstrdup(s);
+ hte->h_lsym = &hte->h_syms;
+ hte->h_lcall = &hte->h_calls;
+ hte->h_lusym = &hte->h_usyms;
+ hte->h_link = htab[h];
+ htab[h] = hte;
+
+ return (hte);
+}
+
+/*
+ * Call function f for each name in the hash table.
+ */
+void
+forall(f)
+ void (*f) __P((hte_t *));
+{
+ int i;
+ hte_t *hte;
+
+ for (i = 0; i < HSHSIZ2; i++) {
+ for (hte = htab[i]; hte != NULL; hte = hte->h_link)
+ (*f)(hte);
+ }
+}
diff --git a/usr.bin/xlint/lint2/lint2.h b/usr.bin/xlint/lint2/lint2.h
new file mode 100644
index 0000000..0ade110
--- /dev/null
+++ b/usr.bin/xlint/lint2/lint2.h
@@ -0,0 +1,177 @@
+/* $NetBSD: lint2.h,v 1.2 1995/07/03 21:24:49 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "lint.h"
+
+/*
+ * Types are described by structures of type type_t.
+ */
+typedef struct type {
+ tspec_t t_tspec; /* type specifier */
+ u_int t_const : 1; /* constant */
+ u_int t_volatile : 1; /* volatile */
+ u_int t_vararg : 1; /* function has variable number of arguments */
+ u_int t_isenum : 1; /* enum type */
+ u_int t_proto : 1; /* this is a prototype */
+ u_int t_istag : 1; /* tag with _t_tag valid */
+ u_int t_istynam : 1; /* tag with _t_tynam valid */
+ union {
+ int _t_dim; /* if the type is an ARRAY than this
+ is the dimension of the array. */
+ struct hte *_t_tag; /* hash table entry of tag if
+ t_isenum, STRUCT or UNION */
+ struct hte *_t_tynam; /* hash table entry of typename if
+ t_isenum, STRUCT or UNION */
+ struct type **_t_args; /* list of argument types if this
+ is a prototype */
+ } t_u;
+ struct type *t_subt; /* indirected type (array element, pointed to
+ type, type of return value) */
+} type_t;
+
+#define t_dim t_u._t_dim
+#define t_tag t_u._t_tag
+#define t_tynam t_u._t_tynam
+#define t_args t_u._t_args
+
+/*
+ * argument information
+ *
+ * Such a structure is created for each argument of a function call
+ * which is an integer constant or a constant string.
+ */
+typedef struct arginf {
+ int a_num; /* # of argument (1..) */
+ u_int a_zero : 1; /* argument is 0 */
+ u_int a_pcon : 1; /* msb of argument is not set */
+ u_int a_ncon : 1; /* msb of argument is set */
+ u_int a_fmt : 1; /* a_fstrg points to format string */
+ char *a_fstrg; /* format string */
+ struct arginf *a_nxt; /* information for next const. argument */
+} arginf_t;
+
+/*
+ * Keeps information about position in source file.
+ */
+typedef struct {
+ u_short p_src; /* index of name of translation unit
+ (the name which was specified at the
+ command line) */
+ u_short p_line; /* line number in p_src */
+ u_short p_isrc; /* index of (included) file */
+ u_short p_iline; /* line number in p_iline */
+} pos_t;
+
+/*
+ * Used for definitions and declarations
+ *
+ * To save memory, variable sized structures are used. If
+ * all s_va, s_prfl and s_scfl are not set, the memory allocated
+ * for a symbol is only large enough to keep the first member of
+ * struct sym, s_s.
+ */
+typedef struct sym {
+ struct {
+ pos_t s_pos; /* pos of def./decl. */
+#ifndef lint
+ u_int s_def : 3; /* DECL, TDEF or DEF */
+#else
+ def_t s_def;
+#endif
+ u_int s_rval : 1; /* function has return value */
+ u_int s_osdef : 1; /* old style function definition */
+ u_int s_static : 1; /* symbol is static */
+ u_int s_va : 1; /* check only first s_nva arguments */
+ u_int s_prfl : 1; /* printflike */
+ u_int s_scfl : 1; /* scanflike */
+ u_short s_type; /* type */
+ struct sym *s_nxt; /* next symbol with same name */
+ } s_s;
+ short s_nva;
+ short s_nprfl;
+ short s_nscfl;
+} sym_t;
+
+#define s_pos s_s.s_pos
+#define s_rval s_s.s_rval
+#define s_osdef s_s.s_osdef
+#define s_static s_s.s_static
+#define s_def s_s.s_def
+#define s_va s_s.s_va
+#define s_prfl s_s.s_prfl
+#define s_scfl s_s.s_scfl
+#define s_type s_s.s_type
+#define s_nxt s_s.s_nxt
+
+/*
+ * Used to store informations about function calls.
+ */
+typedef struct fcall {
+ pos_t f_pos; /* position of call */
+ u_int f_rused : 1; /* return value used */
+ u_int f_rdisc : 1; /* return value discarded (casted to void) */
+ u_short f_type; /* types of expected return value and args */
+ arginf_t *f_args; /* information about constant arguments */
+ struct fcall *f_nxt; /* next call of same function */
+} fcall_t;
+
+/*
+ * Used to store information about usage of symbols other
+ * than for function calls.
+ */
+typedef struct usym {
+ pos_t u_pos; /* position */
+ struct usym *u_nxt; /* next usage */
+} usym_t;
+
+/*
+ * hash table entry
+ */
+typedef struct hte {
+ const char *h_name; /* name */
+ u_int h_used : 1; /* symbol is used */
+ u_int h_def : 1; /* symbol is defined */
+ u_int h_static : 1; /* static symbol */
+ sym_t *h_syms; /* declarations and definitions */
+ sym_t **h_lsym; /* points to s_nxt of last decl./def. */
+ fcall_t *h_calls; /* function calls */
+ fcall_t **h_lcall; /* points to f_nxt of last call */
+ usym_t *h_usyms; /* usage info */
+ usym_t **h_lusym; /* points to u_nxt of last usage info */
+ struct hte *h_link; /* next hte with same hash function */
+} hte_t;
+
+/* maps type indices into pointers to type structs */
+#define TP(idx) (tlst[idx])
+
+#include "externs2.h"
diff --git a/usr.bin/xlint/lint2/main2.c b/usr.bin/xlint/lint2/main2.c
new file mode 100644
index 0000000..171344a
--- /dev/null
+++ b/usr.bin/xlint/lint2/main2.c
@@ -0,0 +1,190 @@
+/* $NetBSD: main2.c,v 1.2 1995/07/03 21:24:53 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: main2.c,v 1.2 1995/07/03 21:24:53 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lint2.h"
+
+/* warnings for symbols which are declared but not defined or used */
+int xflag;
+
+/*
+ * warnings for symbols which are used and not defined or defined
+ * and not used
+ */
+int uflag = 1;
+
+/* Create a lint library in the current directory with name libname. */
+int Cflag;
+const char *libname;
+
+int pflag;
+
+/*
+ * warnings for (tentative) definitions of the same name in more then
+ * one translation unit
+ */
+int sflag;
+
+int tflag;
+
+/*
+ * If a complaint stems from a included file, print the name of the included
+ * file instead of the name spezified at the command line followed by '?'
+ */
+int Hflag;
+
+int hflag;
+
+/* Print full path names, not only the last component */
+int Fflag;
+
+/*
+ * List of libraries (from -l flag). These libraries are read after all
+ * other input files has been read and, for Cflag, after the new lint library
+ * has been written.
+ */
+const char **libs;
+
+static void usage __P((void));
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, i;
+ size_t len;
+ char *lname;
+
+ libs = xcalloc(1, sizeof (char *));
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "hpstxuC:HFl:")) != -1) {
+ switch (c) {
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ uflag = 0;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'C':
+ len = strlen(optarg);
+ lname = xmalloc(len + 10);
+ (void)sprintf(lname, "llib-l%s.ln", optarg);
+ libname = lname;
+ Cflag = 1;
+ uflag = 0;
+ break;
+ case 'H':
+ Hflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'l':
+ for (i = 0; libs[i] != NULL; i++) ;
+ libs = xrealloc(libs, (i + 2) * sizeof (char *));
+ libs[i] = xstrdup(optarg);
+ libs[i + 1] = NULL;
+ break;
+ case '?':
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ initmem();
+
+ /* initialize hash table */
+ inithash();
+
+ inittyp();
+
+ for (i = 0; i < argc; i++)
+ readfile(argv[i]);
+
+ /* write the lint library */
+ if (Cflag) {
+ forall(mkstatic);
+ outlib(libname);
+ }
+
+ /* read additional libraries */
+ for (i = 0; libs[i] != NULL; i++)
+ readfile(libs[i]);
+
+ forall(mkstatic);
+
+ mainused();
+
+ /* perform all tests */
+ forall(chkname);
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: lint2 -hpstxuHF -Clib -l lib ... src1 ...\n");
+ exit(1);
+}
+
diff --git a/usr.bin/xlint/lint2/mem2.c b/usr.bin/xlint/lint2/mem2.c
new file mode 100644
index 0000000..ed97c6f
--- /dev/null
+++ b/usr.bin/xlint/lint2/mem2.c
@@ -0,0 +1,97 @@
+/* $NetBSD: mem2.c,v 1.3 1995/10/02 17:27:11 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem2.c,v 1.3 1995/10/02 17:27:11 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+
+#include "lint2.h"
+
+/* length of new allocated memory blocks */
+static size_t mblklen;
+
+/* offset of next free byte in mbuf */
+static size_t nxtfree;
+
+/* current buffer to server memory requests from */
+static void *mbuf;
+
+void
+initmem()
+{
+ int pgsz;
+
+ pgsz = getpagesize();
+ mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
+
+ nxtfree = mblklen;
+}
+
+/*
+ * Allocate memory in large chunks to avoid space and time overhead of
+ * malloc(). This is possible because memory allocated by xalloc()
+ * need never to be freed.
+ */
+void *
+xalloc(sz)
+ size_t sz;
+{
+ void *ptr;
+ int prot, flags;
+
+ sz = ALIGN(sz);
+ if (nxtfree + sz > mblklen) {
+ /* use mmap() instead of malloc() to avoid malloc overhead. */
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_ANON | MAP_PRIVATE;
+ mbuf = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
+ if (mbuf == (void *)MAP_FAILED)
+ err(1, "can't map memory");
+ if (ALIGN((u_long)mbuf) != (u_long)mbuf)
+ errx(1, "mapped address is not aligned");
+ (void)memset(mbuf, 0, mblklen);
+ nxtfree = 0;
+ }
+
+ ptr = (char *)mbuf + nxtfree;
+ nxtfree += sz;
+
+ return (ptr);
+}
diff --git a/usr.bin/xlint/lint2/msg.c b/usr.bin/xlint/lint2/msg.c
new file mode 100644
index 0000000..c55ba96
--- /dev/null
+++ b/usr.bin/xlint/lint2/msg.c
@@ -0,0 +1,157 @@
+/* $NetBSD: msg.c,v 1.2 1995/07/03 21:24:56 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: msg.c,v 1.2 1995/07/03 21:24:56 cgd Exp $";
+#endif
+
+#include <string.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "lint2.h"
+
+
+static const char *msgs[] = {
+ "%s used( %s ), but not defined", /* 0 */
+ "%s defined( %s ), but never used", /* 1 */
+ "%s declared( %s ), but never used or defined", /* 2 */
+ "%s multiply defined \t%s :: %s", /* 3 */
+ "%s value used inconsistently \t%s :: %s", /* 4 */
+ "%s value declared inconsistently \t%s :: %s", /* 5 */
+ "%s, arg %d used inconsistently \t%s :: %s", /* 6 */
+ "%s: variable # of args \t%s :: %s", /* 7 */
+ "%s returns value which is always ignored", /* 8 */
+ "%s returns value which is sometimes ignored", /* 9 */
+ "%s value is used( %s ), but none returned", /* 10 */
+ "%s, arg %d declared inconsistently \t%s :: %s", /* 11 */
+ "%s: variable # of args declared \t%s :: %s", /* 12 */
+ "%s: malformed format string \t%s", /* 13 */
+ "%s, arg %d inconsistent with format \t%s", /* 14 */
+ "%s: too few args for format \t%s", /* 15 */
+ "%s: too many args for format \t%s", /* 16 */
+ "%s function value must be declared before use \t%s :: %s",/* 17 */
+};
+
+static const char *basename __P((const char *));
+
+#ifdef __STDC__
+void
+msg(int n, ...)
+{
+#else
+void
+msg(va_alist)
+ va_dcl
+ int n;
+{
+#endif
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+ n = va_arg(ap, int);
+#endif
+
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+
+ va_end(ap);
+}
+
+/*
+ * Return a pointer to the last component of a path.
+ */
+static const char *
+basename(path)
+ const char *path;
+{
+ const char *cp, *cp1, *cp2;
+
+ if (Fflag)
+ return (path);
+
+ cp = cp1 = cp2 = path;
+ while (*cp != '\0') {
+ if (*cp++ == '/') {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+/*
+ * Create a string which describes a position in a source file.
+ */
+const char *
+mkpos(posp)
+ pos_t *posp;
+{
+ size_t len;
+ const char *fn;
+ static char *buf;
+ static size_t blen = 0;
+ int qm, src, line;
+
+ if (Hflag && posp->p_src != posp->p_isrc) {
+ src = posp->p_isrc;
+ line = posp->p_iline;
+ } else {
+ src = posp->p_src;
+ line = posp->p_line;
+ }
+ qm = !Hflag && posp->p_src != posp->p_isrc;
+
+ len = strlen(fn = basename(fnames[src]));
+ len += 3 * sizeof (u_short) + 4;
+
+ if (len > blen)
+ buf = xrealloc(buf, blen = len);
+ if (line != 0) {
+ (void)sprintf(buf, "%s%s(%hu)",
+ fn, qm ? "?" : "", line);
+ } else {
+ (void)sprintf(buf, "%s", fn);
+ }
+
+ return (buf);
+}
+
diff --git a/usr.bin/xlint/lint2/read.c b/usr.bin/xlint/lint2/read.c
new file mode 100644
index 0000000..6498a5c
--- /dev/null
+++ b/usr.bin/xlint/lint2/read.c
@@ -0,0 +1,1135 @@
+/* $NetBSD: read.c,v 1.2 1995/07/03 21:24:59 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: read.c,v 1.2 1995/07/03 21:24:59 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <err.h>
+
+#include "lint2.h"
+
+
+/* index of current (included) source file */
+static int srcfile;
+
+/*
+ * The array pointed to by inpfns maps the file name indices of input files
+ * to the file name indices used in lint2
+ */
+static short *inpfns;
+static size_t ninpfns;
+
+/*
+ * The array pointed to by *fnames maps file name indizes to file names.
+ * Indices of type short are used instead of pointers to save memory.
+ */
+const char **fnames;
+static size_t nfnames;
+
+/*
+ * Types are shared (to save memory for the types itself) and accessed
+ * via indices (to save memory for references to types (indices are short)).
+ * To share types, a equal type must be located fast. This is done by a
+ * hash table. Access by indices is done via an array of pointers to the
+ * types.
+ */
+typedef struct thtab {
+ const char *th_name;
+ u_short th_idx;
+ struct thtab *th_nxt;
+} thtab_t;
+static thtab_t **thtab; /* hash table */
+type_t **tlst; /* array for indexed access */
+static size_t tlstlen; /* length of tlst */
+
+/* index of current C source file (as spezified at the command line) */
+static int csrcfile;
+
+
+static void inperr __P((void));
+static void setsrc __P((const char *));
+static void setfnid __P((int, const char *));
+static void funccall __P((pos_t *, const char *));
+static void decldef __P((pos_t *, const char *));
+static void usedsym __P((pos_t *, const char *));
+static u_short inptype __P((const char *, const char **));
+static int gettlen __P((const char *, const char **));
+static u_short findtype __P((const char *, size_t, int));
+static u_short storetyp __P((type_t *, const char *, size_t, int));
+static int thash __P((const char *, size_t));
+static char *inpqstrg __P((const char *, const char **));
+static const char *inpname __P((const char *, const char **));
+static int getfnidx __P((const char *));
+
+void
+readfile(name)
+ const char *name;
+{
+ FILE *inp;
+ size_t len;
+ const char *cp;
+ char *line, *eptr, rt;
+ int cline, isrc, iline;
+ pos_t pos;
+
+ if (inpfns == NULL)
+ inpfns = xcalloc(ninpfns = 128, sizeof (short));
+ if (fnames == NULL)
+ fnames = xcalloc(nfnames = 256, sizeof (char *));
+ if (tlstlen == 0)
+ tlst = xcalloc(tlstlen = 256, sizeof (type_t *));
+ if (thtab == NULL)
+ thtab = xcalloc(THSHSIZ2, sizeof (thtab_t));
+
+ srcfile = getfnidx(name);
+
+ if ((inp = fopen(name, "r")) == NULL)
+ err(1, "cannot open %s", name);
+
+ while ((line = fgetln(inp, &len)) != NULL) {
+
+ if (len == 0 || line[len - 1] != '\n')
+ inperr();
+ line[len - 1] = '\0';
+ cp = line;
+
+ /* line number in csrcfile */
+ cline = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr) {
+ cline = -1;
+ } else {
+ cp = eptr;
+ }
+
+ /* record type */
+ if (*cp != '\0') {
+ rt = *cp++;
+ } else {
+ inperr();
+ }
+
+ if (rt == 'S') {
+ setsrc(cp);
+ continue;
+ } else if (rt == 's') {
+ setfnid(cline, cp);
+ continue;
+ }
+
+ /*
+ * Index of (included) source file. If this index is
+ * different from csrcfile, it refers to an included
+ * file.
+ */
+ isrc = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ isrc = inpfns[isrc];
+
+ /* line number in isrc */
+ if (*cp++ != '.')
+ inperr();
+ iline = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+
+ pos.p_src = (u_short)csrcfile;
+ pos.p_line = (u_short)cline;
+ pos.p_isrc = (u_short)isrc;
+ pos.p_iline = (u_short)iline;
+
+ /* process rest of this record */
+ switch (rt) {
+ case 'c':
+ funccall(&pos, cp);
+ break;
+ case 'd':
+ decldef(&pos, cp);
+ break;
+ case 'u':
+ usedsym(&pos, cp);
+ break;
+ default:
+ inperr();
+ }
+
+ }
+
+ if (ferror(inp))
+ err(1, "read error on %s", name);
+
+ (void)fclose(inp);
+}
+
+
+static void
+inperr()
+{
+ errx(1, "input file error: %s", fnames[srcfile]);
+}
+
+/*
+ * Set the name of the C source file of the .ln file which is
+ * currently read.
+ */
+static void
+setsrc(cp)
+ const char *cp;
+{
+ csrcfile = getfnidx(cp);
+}
+
+/*
+ * setfnid() gets as input an index as used in an input file and the
+ * associated file name. If neccessary, it creates a new lint2 file
+ * name index for this file name and creates the mapping of the index
+ * as used in the input file to the index used in lint2.
+ */
+static void
+setfnid(fid, cp)
+ int fid;
+ const char *cp;
+{
+ if (fid == -1)
+ inperr();
+
+ if (fid >= ninpfns) {
+ inpfns = xrealloc(inpfns, (ninpfns * 2) * sizeof (short));
+ (void)memset(inpfns + ninpfns, 0, ninpfns * sizeof (short));
+ ninpfns *= 2;
+ }
+ /*
+ * Should always be true because indices written in the output
+ * file by lint1 are always the previous index + 1.
+ */
+ if (fid >= ninpfns)
+ errx(1, "internal error: setfnid()");
+ inpfns[fid] = (u_short)getfnidx(cp);
+}
+
+/*
+ * Process a function call record (c-record).
+ */
+static void
+funccall(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ arginf_t *ai, **lai;
+ char c, *eptr;
+ int rused, rdisc;
+ hte_t *hte;
+ fcall_t *fcall;
+
+ fcall = xalloc(sizeof (fcall_t));
+ STRUCT_ASSIGN(fcall->f_pos, *posp);
+
+ /* read flags */
+ rused = rdisc = 0;
+ lai = &fcall->f_args;
+ while ((c = *cp) == 'u' || c == 'i' || c == 'd' ||
+ c == 'z' || c == 'p' || c == 'n' || c == 's') {
+ cp++;
+ switch (c) {
+ case 'u':
+ if (rused || rdisc)
+ inperr();
+ rused = 1;
+ break;
+ case 'i':
+ if (rused || rdisc)
+ inperr();
+ break;
+ case 'd':
+ if (rused || rdisc)
+ inperr();
+ rdisc = 1;
+ break;
+ case 'z':
+ case 'p':
+ case 'n':
+ case 's':
+ ai = xalloc(sizeof (arginf_t));
+ ai->a_num = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ if (c == 'z') {
+ ai->a_pcon = ai->a_zero = 1;
+ } else if (c == 'p') {
+ ai->a_pcon = 1;
+ } else if (c == 'n') {
+ ai->a_ncon = 1;
+ } else {
+ ai->a_fmt = 1;
+ ai->a_fstrg = inpqstrg(cp, &cp);
+ }
+ *lai = ai;
+ lai = &ai->a_nxt;
+ break;
+ }
+ }
+ fcall->f_rused = rused;
+ fcall->f_rdisc = rdisc;
+
+ /* read name of function */
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used = 1;
+
+ fcall->f_type = inptype(cp, &cp);
+
+ *hte->h_lcall = fcall;
+ hte->h_lcall = &fcall->f_nxt;
+
+ if (*cp != '\0')
+ inperr();
+}
+
+/*
+ * Process a declaration or definition (d-record).
+ */
+static void
+decldef(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ sym_t *symp, sym;
+ char c, *ep;
+ int used;
+ hte_t *hte;
+
+ (void)memset(&sym, 0, sizeof (sym));
+ STRUCT_ASSIGN(sym.s_pos, *posp);
+ sym.s_def = NODECL;
+
+ used = 0;
+
+ while ((c = *cp) == 't' || c == 'd' || c == 'e' || c == 'u' ||
+ c == 'r' || c == 'o' || c == 's' || c == 'v' ||
+ c == 'P' || c == 'S') {
+ cp++;
+ switch (c) {
+ case 't':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = TDEF;
+ break;
+ case 'd':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = DEF;
+ break;
+ case 'e':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = DECL;
+ break;
+ case 'u':
+ if (used)
+ inperr();
+ used = 1;
+ break;
+ case 'r':
+ if (sym.s_rval)
+ inperr();
+ sym.s_rval = 1;
+ break;
+ case 'o':
+ if (sym.s_osdef)
+ inperr();
+ sym.s_osdef = 1;
+ break;
+ case 's':
+ if (sym.s_static)
+ inperr();
+ sym.s_static = 1;
+ break;
+ case 'v':
+ if (sym.s_va)
+ inperr();
+ sym.s_va = 1;
+ sym.s_nva = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ case 'P':
+ if (sym.s_prfl)
+ inperr();
+ sym.s_prfl = 1;
+ sym.s_nprfl = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ case 'S':
+ if (sym.s_scfl)
+ inperr();
+ sym.s_scfl = 1;
+ sym.s_nscfl = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ }
+ }
+
+ /* read symbol name */
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used |= used;
+ if (sym.s_def == DEF || sym.s_def == TDEF)
+ hte->h_def = 1;
+
+ sym.s_type = inptype(cp, &cp);
+
+ /*
+ * Allocate memory for this symbol only if it was not already
+ * declared or tentatively defined at the same location with
+ * the same type. Works only for symbols with external linkage,
+ * because static symbols, tentatively defined at the same location
+ * but in different translation units are really different symbols.
+ */
+ for (symp = hte->h_syms; symp != NULL; symp = symp->s_nxt) {
+ if (symp->s_pos.p_isrc == sym.s_pos.p_isrc &&
+ symp->s_pos.p_iline == sym.s_pos.p_iline &&
+ symp->s_type == sym.s_type &&
+ ((symp->s_def == DECL && sym.s_def == DECL) ||
+ (!sflag && symp->s_def == TDEF && sym.s_def == TDEF)) &&
+ !symp->s_static && !sym.s_static) {
+ break;
+ }
+ }
+
+ if (symp == NULL) {
+ /* allocsym reserviert keinen Platz fuer s_nva */
+ if (sym.s_va || sym.s_prfl || sym.s_scfl) {
+ symp = xalloc(sizeof (sym_t));
+ STRUCT_ASSIGN(*symp, sym);
+ } else {
+ symp = xalloc(sizeof (symp->s_s));
+ STRUCT_ASSIGN(symp->s_s, sym.s_s);
+ }
+ *hte->h_lsym = symp;
+ hte->h_lsym = &symp->s_nxt;
+ }
+
+ if (*cp != '\0')
+ inperr();
+}
+
+/*
+ * Read an u-record (emited by lint1 if a symbol was used).
+ */
+static void
+usedsym(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ usym_t *usym;
+ hte_t *hte;
+
+ usym = xalloc(sizeof (usym_t));
+ STRUCT_ASSIGN(usym->u_pos, *posp);
+
+ /* needed as delimiter between two numbers */
+ if (*cp++ != 'x')
+ inperr();
+
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used = 1;
+
+ *hte->h_lusym = usym;
+ hte->h_lusym = &usym->u_nxt;
+}
+
+/*
+ * Read a type and return the index of this type.
+ */
+static u_short
+inptype(cp, epp)
+ const char *cp, **epp;
+{
+ char c, s, *eptr;
+ const char *ep;
+ type_t *tp;
+ int narg, i, osdef;
+ size_t tlen;
+ u_short tidx;
+ int h;
+
+ /* If we have this type already, return it's index. */
+ tlen = gettlen(cp, &ep);
+ h = thash(cp, tlen);
+ if ((tidx = findtype(cp, tlen, h)) != 0) {
+ *epp = ep;
+ return (tidx);
+ }
+
+ /* No, we must create a new type. */
+ tp = xalloc(sizeof (type_t));
+
+ tidx = storetyp(tp, cp, tlen, h);
+
+ c = *cp++;
+
+ while (c == 'c' || c == 'v') {
+ if (c == 'c') {
+ tp->t_const = 1;
+ } else {
+ tp->t_volatile = 1;
+ }
+ c = *cp++;
+ }
+
+ if (c == 's' || c == 'u' || c == 'l' || c == 'e') {
+ s = c;
+ c = *cp++;
+ } else {
+ s = '\0';
+ }
+
+ switch (c) {
+ case 'C':
+ tp->t_tspec = s == 's' ? SCHAR : (s == 'u' ? UCHAR : CHAR);
+ break;
+ case 'S':
+ tp->t_tspec = s == 'u' ? USHORT : SHORT;
+ break;
+ case 'I':
+ tp->t_tspec = s == 'u' ? UINT : INT;
+ break;
+ case 'L':
+ tp->t_tspec = s == 'u' ? ULONG : LONG;
+ break;
+ case 'Q':
+ tp->t_tspec = s == 'u' ? UQUAD : QUAD;
+ break;
+ case 'D':
+ tp->t_tspec = s == 's' ? FLOAT : (s == 'l' ? LDOUBLE : DOUBLE);
+ break;
+ case 'V':
+ tp->t_tspec = VOID;
+ break;
+ case 'P':
+ tp->t_tspec = PTR;
+ break;
+ case 'A':
+ tp->t_tspec = ARRAY;
+ break;
+ case 'F':
+ case 'f':
+ osdef = c == 'f';
+ tp->t_tspec = FUNC;
+ break;
+ case 'T':
+ tp->t_tspec = s == 'e' ? ENUM : (s == 's' ? STRUCT : UNION);
+ break;
+ }
+
+ switch (tp->t_tspec) {
+ case ARRAY:
+ tp->t_dim = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case PTR:
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case FUNC:
+ c = *cp;
+ if (isdigit((u_char)c)) {
+ if (!osdef)
+ tp->t_proto = 1;
+ narg = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ tp->t_args = xcalloc((size_t)(narg + 1),
+ sizeof (type_t *));
+ for (i = 0; i < narg; i++) {
+ if (i == narg - 1 && *cp == 'E') {
+ tp->t_vararg = 1;
+ cp++;
+ } else {
+ tp->t_args[i] = TP(inptype(cp, &cp));
+ }
+ }
+ }
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case ENUM:
+ tp->t_tspec = INT;
+ tp->t_isenum = 1;
+ /* FALLTHROUGH */
+ case STRUCT:
+ case UNION:
+ switch (*cp++) {
+ case '0':
+ break;
+ case '1':
+ tp->t_istag = 1;
+ tp->t_tag = hsearch(inpname(cp, &cp), 1);
+ break;
+ case '2':
+ tp->t_istynam = 1;
+ tp->t_tynam = hsearch(inpname(cp, &cp), 1);
+ break;
+ }
+ break;
+ /* LINTED (enumeration value(s) not handled in switch) */
+ default:
+ }
+
+ *epp = cp;
+ return (tidx);
+}
+
+/*
+ * Get the length of a type string.
+ */
+static int
+gettlen(cp, epp)
+ const char *cp, **epp;
+{
+ const char *cp1;
+ char c, s, *eptr;
+ tspec_t t;
+ int narg, i, cm, vm;
+
+ cp1 = cp;
+
+ c = *cp++;
+
+ cm = vm = 0;
+
+ while (c == 'c' || c == 'v') {
+ if (c == 'c') {
+ if (cm)
+ inperr();
+ cm = 1;
+ } else {
+ if (vm)
+ inperr();
+ vm = 1;
+ }
+ c = *cp++;
+ }
+
+ if (c == 's' || c == 'u' || c == 'l' || c == 'e') {
+ s = c;
+ c = *cp++;
+ } else {
+ s = '\0';
+ }
+
+ t = NOTSPEC;
+
+ switch (c) {
+ case 'C':
+ if (s == 's') {
+ t = SCHAR;
+ } else if (s == 'u') {
+ t = UCHAR;
+ } else if (s == '\0') {
+ t = CHAR;
+ }
+ break;
+ case 'S':
+ if (s == 'u') {
+ t = USHORT;
+ } else if (s == '\0') {
+ t = SHORT;
+ }
+ break;
+ case 'I':
+ if (s == 'u') {
+ t = UINT;
+ } else if (s == '\0') {
+ t = INT;
+ }
+ break;
+ case 'L':
+ if (s == 'u') {
+ t = ULONG;
+ } else if (s == '\0') {
+ t = LONG;
+ }
+ break;
+ case 'Q':
+ if (s == 'u') {
+ t = UQUAD;
+ } else if (s == '\0') {
+ t = QUAD;
+ }
+ break;
+ case 'D':
+ if (s == 's') {
+ t = FLOAT;
+ } else if (s == 'l') {
+ t = LDOUBLE;
+ } else if (s == '\0') {
+ t = DOUBLE;
+ }
+ break;
+ case 'V':
+ if (s == '\0')
+ t = VOID;
+ break;
+ case 'P':
+ if (s == '\0')
+ t = PTR;
+ break;
+ case 'A':
+ if (s == '\0')
+ t = ARRAY;
+ break;
+ case 'F':
+ case 'f':
+ if (s == '\0')
+ t = FUNC;
+ break;
+ case 'T':
+ if (s == 'e') {
+ t = ENUM;
+ } else if (s == 's') {
+ t = STRUCT;
+ } else if (s == 'u') {
+ t = UNION;
+ }
+ break;
+ default:
+ inperr();
+ }
+
+ if (t == NOTSPEC)
+ inperr();
+
+ switch (t) {
+ case ARRAY:
+ (void)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ (void)gettlen(cp, &cp);
+ break;
+ case PTR:
+ (void)gettlen(cp, &cp);
+ break;
+ case FUNC:
+ c = *cp;
+ if (isdigit((u_char)c)) {
+ narg = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ for (i = 0; i < narg; i++) {
+ if (i == narg - 1 && *cp == 'E') {
+ cp++;
+ } else {
+ (void)gettlen(cp, &cp);
+ }
+ }
+ }
+ (void)gettlen(cp, &cp);
+ break;
+ case ENUM:
+ case STRUCT:
+ case UNION:
+ switch (*cp++) {
+ case '0':
+ break;
+ case '1':
+ (void)inpname(cp, &cp);
+ break;
+ case '2':
+ (void)inpname(cp, &cp);
+ break;
+ default:
+ inperr();
+ }
+ break;
+ /* LINTED (enumeration value(s) not handled in switch) */
+ default:
+ }
+
+ *epp = cp;
+ return (cp - cp1);
+}
+
+/*
+ * Search a type by it's type string.
+ */
+static u_short
+findtype(cp, len, h)
+ const char *cp;
+ size_t len;
+ int h;
+{
+ thtab_t *thte;
+
+ for (thte = thtab[h]; thte != NULL; thte = thte->th_nxt) {
+ if (strncmp(thte->th_name, cp, len) != 0)
+ continue;
+ if (thte->th_name[len] == '\0')
+ return (thte->th_idx);
+ }
+
+ return (0);
+}
+
+/*
+ * Store a type and it's type string so we can later share this type
+ * if we read the same type string from the input file.
+ */
+static u_short
+storetyp(tp, cp, len, h)
+ type_t *tp;
+ const char *cp;
+ size_t len;
+ int h;
+{
+ /* 0 ist reserved */
+ static u_int tidx = 1;
+ thtab_t *thte;
+ char *name;
+
+ if (tidx >= USHRT_MAX)
+ errx(1, "sorry, too many types");
+
+ if (tidx == tlstlen - 1) {
+ tlst = xrealloc(tlst, (tlstlen * 2) * sizeof (type_t *));
+ (void)memset(tlst + tlstlen, 0, tlstlen * sizeof (type_t *));
+ tlstlen *= 2;
+ }
+
+ tlst[tidx] = tp;
+
+ /* create a hash table entry */
+ name = xalloc(len + 1);
+ (void)memcpy(name, cp, len);
+ name[len] = '\0';
+
+ thte = xalloc(sizeof (thtab_t));
+ thte->th_name = name;
+ thte->th_idx = tidx;
+ thte->th_nxt = thtab[h];
+ thtab[h] = thte;
+
+ return ((u_short)tidx++);
+}
+
+/*
+ * Hash function for types
+ */
+static int
+thash(s, len)
+ const char *s;
+ size_t len;
+{
+ u_int v;
+
+ v = 0;
+ while (len-- != 0) {
+ v = (v << sizeof (v)) + (u_char)*s++;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % THSHSIZ2);
+}
+
+/*
+ * Read a string enclosed by "". This string may contain quoted chars.
+ */
+static char *
+inpqstrg(src, epp)
+ const char *src, **epp;
+{
+ char *strg, *dst;
+ size_t slen;
+ int c;
+ int v;
+
+ dst = strg = xmalloc(slen = 32);
+
+ if ((c = *src++) != '"')
+ inperr();
+ if ((c = *src++) == '\0')
+ inperr();
+
+ while (c != '"') {
+ if (c == '\\') {
+ if ((c = *src++) == '\0')
+ inperr();
+ switch (c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+#ifdef __STDC__
+ c = '\v';
+#else
+ c = '\013';
+#endif
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'a':
+#ifdef __STDC__
+ c = '\a';
+#else
+ c = '\007';
+#endif
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '"':
+ c = '"';
+ break;
+ case '\'':
+ c = '\'';
+ break;
+ case '0': case '1': case '2': case '3':
+ v = (c - '0') << 6;
+ if ((c = *src++) < '0' || c > '7')
+ inperr();
+ v |= (c - '0') << 3;
+ if ((c = *src++) < '0' || c > '7')
+ inperr();
+ v |= c - '0';
+ c = (u_char)v;
+ break;
+ default:
+ inperr();
+ }
+ }
+ /* keep space for trailing '\0' */
+ if (dst - strg == slen - 1) {
+ strg = xrealloc(strg, slen * 2);
+ dst = strg + (slen - 1);
+ slen *= 2;
+ }
+ *dst++ = (char)c;
+ if ((c = *src++) == '\0')
+ inperr();
+ }
+ *dst = '\0';
+
+ *epp = src;
+ return (strg);
+}
+
+/*
+ * Read the name of a symbol in static memory.
+ */
+static const char *
+inpname(cp, epp)
+ const char *cp, **epp;
+{
+ static char *buf;
+ static size_t blen = 0;
+ size_t len, i;
+ char *eptr, c;
+
+ len = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ if (len + 1 > blen)
+ buf = xrealloc(buf, blen = len + 1);
+ for (i = 0; i < len; i++) {
+ c = *cp++;
+ if (!isalnum(c) && c != '_')
+ inperr();
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+
+ *epp = cp;
+ return (buf);
+}
+
+/*
+ * Return the index of a file name. If the name cannot be found, create
+ * a new entry and return the index of the newly created entry.
+ */
+static int
+getfnidx(fn)
+ const char *fn;
+{
+ int i;
+
+ /* 0 ist reserved */
+ for (i = 1; fnames[i] != NULL; i++) {
+ if (strcmp(fnames[i], fn) == 0)
+ break;
+ }
+ if (fnames[i] != NULL)
+ return (i);
+
+ if (i == nfnames - 1) {
+ fnames = xrealloc(fnames, (nfnames * 2) * sizeof (char *));
+ (void)memset(fnames + nfnames, 0, nfnames * sizeof (char *));
+ nfnames *= 2;
+ }
+
+ fnames[i] = xstrdup(fn);
+ return (i);
+}
+
+/*
+ * Separate symbols with static and external linkage.
+ */
+void
+mkstatic(hte)
+ hte_t *hte;
+{
+ sym_t *sym1, **symp, *sym;
+ fcall_t **callp, *call;
+ usym_t **usymp, *usym;
+ hte_t *nhte;
+ int ofnd;
+
+ /* Look for first static definition */
+ for (sym1 = hte->h_syms; sym1 != NULL; sym1 = sym1->s_nxt) {
+ if (sym1->s_static)
+ break;
+ }
+ if (sym1 == NULL)
+ return;
+
+ /* Do nothing if this name is used only in one translation unit. */
+ ofnd = 0;
+ for (sym = hte->h_syms; sym != NULL && !ofnd; sym = sym->s_nxt) {
+ if (sym->s_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ for (call = hte->h_calls; call != NULL && !ofnd; call = call->f_nxt) {
+ if (call->f_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ for (usym = hte->h_usyms; usym != NULL && !ofnd; usym = usym->u_nxt) {
+ if (usym->u_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ if (!ofnd) {
+ hte->h_used = 1;
+ /* errors about undef. static symbols are printed in lint1 */
+ hte->h_def = 1;
+ hte->h_static = 1;
+ return;
+ }
+
+ /*
+ * Create a new hash table entry
+ *
+ * XXX this entry should be put at the beginning of the list to
+ * avoid to process the same symbol twice.
+ */
+ for (nhte = hte; nhte->h_link != NULL; nhte = nhte->h_link) ;
+ nhte->h_link = xalloc(sizeof (hte_t));
+ nhte = nhte->h_link;
+ nhte->h_name = hte->h_name;
+ nhte->h_static = 1;
+ nhte->h_used = 1;
+ nhte->h_def = 1; /* error in lint1 */
+ nhte->h_lsym = &nhte->h_syms;
+ nhte->h_lcall = &nhte->h_calls;
+ nhte->h_lusym = &nhte->h_usyms;
+
+ /*
+ * move all symbols used in this translation unit into the new
+ * hash table entry.
+ */
+ for (symp = &hte->h_syms; (sym = *symp) != NULL; ) {
+ if (sym->s_pos.p_src == sym1->s_pos.p_src) {
+ sym->s_static = 1;
+ (*symp) = sym->s_nxt;
+ if (hte->h_lsym == &sym->s_nxt)
+ hte->h_lsym = symp;
+ sym->s_nxt = NULL;
+ *nhte->h_lsym = sym;
+ nhte->h_lsym = &sym->s_nxt;
+ } else {
+ symp = &sym->s_nxt;
+ }
+ }
+ for (callp = &hte->h_calls; (call = *callp) != NULL; ) {
+ if (call->f_pos.p_src == sym1->s_pos.p_src) {
+ (*callp) = call->f_nxt;
+ if (hte->h_lcall == &call->f_nxt)
+ hte->h_lcall = callp;
+ call->f_nxt = NULL;
+ *nhte->h_lcall = call;
+ nhte->h_lcall = &call->f_nxt;
+ } else {
+ callp = &call->f_nxt;
+ }
+ }
+ for (usymp = &hte->h_usyms; (usym = *usymp) != NULL; ) {
+ if (usym->u_pos.p_src == sym1->s_pos.p_src) {
+ (*usymp) = usym->u_nxt;
+ if (hte->h_lusym == &usym->u_nxt)
+ hte->h_lusym = usymp;
+ usym->u_nxt = NULL;
+ *nhte->h_lusym = usym;
+ nhte->h_lusym = &usym->u_nxt;
+ } else {
+ usymp = &usym->u_nxt;
+ }
+ }
+
+ /* h_def must be recalculated for old hte */
+ hte->h_def = nhte->h_def = 0;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF || sym->s_def == TDEF) {
+ hte->h_def = 1;
+ break;
+ }
+ }
+
+ mkstatic(hte);
+}
diff --git a/usr.bin/xlint/llib/Makefile b/usr.bin/xlint/llib/Makefile
new file mode 100644
index 0000000..bf87315
--- /dev/null
+++ b/usr.bin/xlint/llib/Makefile
@@ -0,0 +1,21 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:25:05 cgd Exp $
+
+#LIBS= llib-lposix.ln llib-lstdc.ln
+LIBS= llib-lstdc.ln
+
+all: ${LIBS}
+
+install:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${LIBMODE} \
+ ${LIBS} ${DESTDIR}${LINTLIBDIR}
+
+clean cleanall:
+ rm -f ${LIBS}
+
+llib-lposix.ln: llib-lposix
+ lint -Cposix ${.ALLSRC}
+
+llib-lstdc.ln: llib-lstdc
+ lint -Cc ${.ALLSRC}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/llib/llib-lposix b/usr.bin/xlint/llib/llib-lposix
new file mode 100644
index 0000000..db1b3cf
--- /dev/null
+++ b/usr.bin/xlint/llib/llib-lposix
@@ -0,0 +1,311 @@
+/* $NetBSD: llib-lposix,v 1.2 1995/07/03 21:25:09 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* LINTLIBRARY */
+
+#define _POSIX_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/times.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <assert.h>
+#include <termios.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <signal.h>
+#include <locale.h>
+#include <setjmp.h>
+#include <string.h>
+#include <utime.h>
+
+
+/* PROTOLIB1 */
+
+
+void (abort)(void);
+int (abs)(int j);
+int (access)(const char *path, int amode);
+double (acos)(double x);
+unsigned (alarm)(unsigned seconds);
+char *(asctime)(const struct tm *timeptr);
+double (asin)(double x);
+void (__assert)(const char *expression, int line, const char *file);
+double (atan)(double x);
+double (atan2)(double y, double x);
+int (atexit)(void (*func)(void));
+double (atof)(const char *nptr);
+int (atoi)(const char *nptr);
+long (atol)(const char *nptr);
+void *(bsearch)(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*compar)(const void *, const void *));
+void *(calloc)(size_t nmemb, size_t size);
+double (ceil)(double x);
+speed_t (cfgetispeed)(const struct termios *p);
+speed_t (cfgetospeed)(const struct termios *p);
+int (cfsetispeed)(struct termios *p, speed_t speed);
+int (cfsetospeed)(struct termios *p, speed_t speed);
+int (chdir)(const char *path);
+int (chmod)(const char *path, mode_t mode);
+int (chown)(const char *path, uid_t owner, gid_t group);
+void (clearerr)(FILE *stream);
+clock_t (clock)(void);
+int (close)(int fildes);
+int (closedir)(DIR *dirp);
+double (cos)(double x);
+double (cosh)(double x);
+int (creat)(const char *path, mode_t mode);
+char *(ctermid)(char *s);
+char *(ctime)(const time_t *timer);
+char *(cuserid)(char *s);
+double (difftime)(time_t time1, time_t time0);
+div_t (div)(int numer, int denom);
+int (dup)(int fildes);
+int (dup2)(int fildes, int fildes2);
+int (errno);
+int (execl)(const char *path, const char *arg, ...);
+int (execle)(const char *path, const char *arg, ...);
+int (execlp)(const char *file, const char *arg, ...);
+int (execv)(const char *path, char *const argv[]);
+int (execve)(const char *path, char *const argv[], char *const *envp);
+int (execvp)(const char *file, char *const argv[]);
+void (exit)(int status);
+void (_exit)(int status);
+double (exp)(double x);
+double (fabs)(double x);
+int (fclose)(FILE *stream);
+int (fcntl)(int fildes, int cmd, ...);
+FILE *(fdopen)(int fildes, const char *type);
+int (feof)(FILE *stream);
+int (ferror)(FILE *stream);
+int (fflush)(FILE *stream);
+int (fgetc)(FILE *stream);
+int (fgetpos)(FILE *stream, fpos_t *pos);
+char *(fgets)(char *s, int n, FILE *stream);
+int (fileno)(FILE *stream);
+double (floor)(double x);
+double (fmod)(double x, double y);
+FILE *(fopen)(const char *filename, const char *mode);
+pid_t (fork)(void);
+long (fpathconf)(int fildes, int name);
+/* PRINTFLIKE2 */
+int (fprintf)(FILE *stream, const char *format, ...);
+int (fputc)(int c, FILE *stream);
+int (fputs)(const char *s, FILE *stream);
+size_t (fread)(void *ptr, size_t size, size_t nmemb, FILE *stream);
+void (free)(void *ptr);
+FILE *(freopen)(const char *filename, const char *mode, FILE *stream);
+double (frepx)(double value, int *exp);
+/* SCANFLIKE2 */
+int (fscanf)(FILE *stream, const char *format, ...);
+int (fseek)(FILE *stream, long int offset, int whence);
+int (fsetpos)(FILE *stream, const fpos_t *pos);
+int (fstat)(int fildes, struct stat *buf);
+long (ftell)(FILE *stream);
+size_t (fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+int (getc)(FILE *stream);
+int (getchar)(void);
+char *(getcwd)(char *buf, size_t size);
+gid_t (getegid)(void);
+char *(getenv)(const char *name);
+uid_t (geteuid)(void);
+gid_t (getgid)(void);
+struct group *(getgrgid)(gid_t gid);
+struct group *(getgrnam)(const char *name);
+int (getgroups)(int gidsetsize, gid_t grouplist[]);
+char *(getlogin)(void);
+pid_t (getpgrp)(void);
+pid_t (getpid)(void);
+pid_t (getppid)(void);
+struct passwd *(getpwnam)(const char *name);
+struct passwd *(getpwuid)(uid_t uid);
+char *(gets)(char *s);
+uid_t (getuid)(void);
+struct tm *(gmtime)(const time_t *timer);
+int (isalnum)(int c);
+int (isalpha)(int c);
+int (isatty)(int fildes);
+int (iscntrl)(int c);
+int (isdigit)(int c);
+int (isgraph)(int c);
+int (islower)(int c);
+int (isprint)(int c);
+int (ispunct)(int c);
+int (isspace)(int c);
+int (isupper)(int c);
+int (isxdigit)(int c);
+int (kill)(pid_t pid, int sig);
+long (labs)(long j);
+double (ldexp)(double x, int exp);
+ldiv_t (ldiv)(long numer, long denom);
+int (link)(const char *existing, const char *new);
+struct lconv *(localeconv)(void);
+struct tm *(localtime)(const time_t *timer);
+double (log)(double x);
+double (log10)(double x);
+void (longjmp)(jmp_buf env, int val);
+off_t (lseek)(int fildes, off_t offset, int whence);
+void *(malloc)(size_t size);
+int (mblen)(const char *s, size_t n);
+size_t (mbstowcs)(wchar_t *pwcs, const char *s, size_t n);
+int (mbtowc)(wchar_t *pwc, const char *s, size_t n);
+void *(memchr)(const void *s, int c, size_t n);
+int (memcmp)(const void *s1, const void *s2, size_t n);
+void *(memcpy)(void *s1, const void *s2, size_t n);
+void *(memmove)(void *s1, const void *s2, size_t n);
+void *(memset)(void *s, int c, size_t n);
+int (mkdir)(const char *path, mode_t mode);
+int (mkfifo)(const char *path, mode_t mode);
+time_t (mktime)(struct tm *timeptr);
+double (modf)(double value, double *iptr);
+int (open)(const char *path, int oflag, ...);
+DIR *(opendir)(const char *dirname);
+long (pathconf)(const char *path, int name);
+int (pause)(void);
+void (perror)(const char *s);
+int (pipe)(int fildes[2]);
+double (pow)(double x, double y);
+/* PRINTFLIKE1 */
+int (printf)(const char *format, ...);
+int (putc)(int c, FILE *stream);
+int (putchar)(int c);
+int (puts)(const char *s);
+void (qsort)(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *));
+int (raise)(int sig);
+int (rand)(void);
+ssize_t (read)(int fildes, void *buf, size_t nbyte);
+struct dirent *(readdir)(DIR *dirp);
+void *(realloc)(void *ptr, size_t size);
+int (remove)(const char *filename);
+int (rename)(const char *old, const char *new);
+void (rewind)(FILE *stream);
+void (rewinddir)(DIR *dirp);
+int (rmdir)(const char *path);
+/* SCANFLIKE1 */
+int (scanf)(const char *format, ...);
+void (setbuf)(FILE *stream, char *buf);
+int (setgid)(gid_t gid);
+int (setjmp)(jmp_buf env);
+char *(setlocale)(int category, const char *locale);
+int (setpgid)(pid_t pid, pid_t pgid);
+pid_t (setsid)(void);
+int (setuid)(uid_t uid);
+int (setvbuf)(FILE *stream, char *buf, int mode, size_t size);
+int (sigaction)(int sig, const struct sigaction *act,
+ struct sigaction *oact);
+int (sigaddset)(sigset_t *set, int signo);
+int (sigdelset)(sigset_t *set, int signo);
+int (sigemptyset)(sigset_t *set);
+int (sigfillset)(sigset_t *set);
+int (sigismember)(const sigset_t *set, int signo);
+void (siglongjmp)(sigjmp_buf env, int val);
+void (*(signal)(int sig, void (*func)(int)))(int);
+int (sigpending)(sigset_t *set);
+int (sigprocmask)(int how, const sigset_t *set, sigset_t *oset);
+int (sigsetjmp)(sigjmp_buf env, int savemask);
+int (sigsuspend)(const sigset_t *sigmask);
+double (sin)(double x);
+double (sinh)(double x);
+unsigned (sleep)(unsigned seconds);
+/* PRINTFLIKE2 */
+int (sprintf)(char *s, const char *format, ...);
+double (sqrt)(double x);
+void (srand)(unsigned seed);
+/* SCANFLIKE2 */
+int (sscanf)(const char *s, const char *format, ...);
+int (stat)(const char *path, struct stat *buf);
+char *(strcat)(char *s1, const char *s2);
+char *(strchr)(const char *s, int c);
+int (strcmp)(const char *s1, const char *s2);
+int (strcoll)(const char *s1, const char *s2);
+char *(strcpy)(char *s1, const char *s2);
+size_t (strcspn)(const char *s1, const char *s2);
+char *(strerror)(int errnum);
+size_t (strftime)(char *s, size_t maxsize, const char *format,
+ const struct tm *timeptr);
+size_t (strlen)(const char *s);
+char *(strncat)(char *s1, const char *s2, size_t n);
+int (strncmp)(const char *s1, const char *s2, size_t n);
+char *(strncpy)(char *s1, const char *s2, size_t n);
+char *(strpbrk)(const char *s1, const char *s2);
+char *(strrchr)(const char *s, int c);
+size_t (strspn)(const char *s1, const char *s2);
+char *(strstr)(const char *s1, const char *s2);
+double (strtod)(const char *nptr, char **endptr);
+char *(strtok)(char *s1, const char *s2);
+long (strtol)(const char *nptr, char **endptr, int base);
+unsigned long (strtoul)(const char *nptr, char **endptr, int base);
+size_t (strxfrm)(char *s1, const char *s2, size_t n);
+long (sysconf)(int name);
+int (system)(const char *string);
+double (tan)(double x);
+double (tanh)(double x);
+int (tcdrain)(int fildes);
+int (tcflow)(int fildes, int action);
+int (tcflush)(int fildes, int queue_selector);
+int (tcgetattr)(int fildes, struct termios *tp);
+pid_t (tcgetpgrp)(int fildes);
+int (tcsendbreak)(int fildes, int duration);
+int (tcsetattr)(int fildes, int options, const struct termios *tp);
+int (tcsetpgrp)(int fildes, pid_t pgrpid);
+time_t (time)(time_t *timer);
+clock_t (times)(struct tms *buffer);
+FILE *(tmpfile)(void);
+char *(tmpnam)(char *s);
+int (tolower)(int c);
+int (toupper)(int c);
+char *(ttyname)(int filedes);
+void (tzset)(void);
+mode_t (umask)(mode_t cmask);
+int (uname)(struct utsname *name);
+int (ungetc)(int c, FILE *stream);
+int (unlink)(const char *path);
+int (utime)(const char *path, const struct utimbuf *times);
+int (vfprintf)(FILE *stream, const char *format, va_list arg);
+int (vprintf)(const char *format, va_list arg);
+int (vsprintf)(char *s, const char *format, va_list arg);
+pid_t (wait)(int *statloc);
+pid_t (waitpid)(pid_t pid, int *stat_loc, int options);
+size_t (wcstombs)(char *s, const wchar_t *pwcs, size_t n);
+int (wctomb)(char *s, wchar_t wchar);
+ssize_t (write)(int fildes, const void *buf, size_t nbyte);
diff --git a/usr.bin/xlint/llib/llib-lstdc b/usr.bin/xlint/llib/llib-lstdc
new file mode 100644
index 0000000..f2b33da
--- /dev/null
+++ b/usr.bin/xlint/llib/llib-lstdc
@@ -0,0 +1,252 @@
+/* $NetBSD: llib-lstdc,v 1.3 1995/07/03 21:39:28 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* LINTLIBRARY */
+
+#define _ANSI_SOURCE
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <math.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* PROTOLIB1 */
+
+/*
+ * assert.h
+ */
+#ifdef __NetBSD__
+void (__assert)(const char *expression, int line, const char *file);
+#else
+void (assert)(int expression);
+#endif
+
+/*
+ * ctype.h
+ */
+int (isalnum)(int c);
+int (isalpha)(int c);
+int (iscntrl)(int c);
+int (isdigit)(int c);
+int (isgraph)(int c);
+int (islower)(int c);
+int (isprint)(int c);
+int (ispunct)(int c);
+int (isspace)(int c);
+int (isupper)(int c);
+int (isxdigit)(int c);
+int (tolower)(int c);
+int (toupper)(int c);
+
+/*
+ * errno.h
+ */
+int (errno);
+
+/*
+ * locale.h
+ */
+char *(setlocale)(int category, const char *locale);
+struct lconv *(localeconv)(void);
+
+/*
+ * math.h
+ */
+double (acos)(double x);
+double (asin)(double x);
+double (atan)(double x);
+double (atan2)(double y, double x);
+double (cos)(double x);
+double (sin)(double x);
+double (tan)(double x);
+double (cosh)(double x);
+double (sinh)(double x);
+double (tanh)(double x);
+double (exp)(double x);
+double (frexp)(double value, int *exp);
+double (ldexp)(double x, int exp);
+double (log)(double x);
+double (log10)(double x);
+double (modf)(double value, double *iptr);
+double (pow)(double x, double y);
+double (sqrt)(double x);
+double (ceil)(double x);
+double (fabs)(double x);
+double (floor)(double x);
+double (fmod)(double x, double y);
+
+/*
+ * setjmp.h
+ */
+int (setjmp)(jmp_buf env);
+void (longjmp)(jmp_buf env, int val);
+
+/*
+ * signal.h
+ */
+void (*(signal)(int sig, void (*func)(int)))(int);
+int (raise)(int sig);
+
+/*
+ * stdio.h
+ */
+int (remove)(const char *filename);
+int (rename)(const char *old, const char *new);
+FILE *(tmpfile)(void);
+char *(tmpnam)(char *s);
+int (fclose)(FILE *stream);
+int (fflush)(FILE *stream);
+FILE *(fopen)(const char *filename, const char *mode);
+FILE *(freopen)(const char *filename, const char *mode, FILE *stream);
+void (setbuf)(FILE *stream, char *buf);
+int (setvbuf)(FILE *stream, char *buf, int mode, size_t size);
+/* PRINTFLIKE2 */
+int (fprintf)(FILE *stream, const char *format, ...);
+/* SCANFLIKE2 */
+int (fscanf)(FILE *stream, const char *format, ...);
+/* PRINTFLIKE1 */
+int (printf)(const char *format, ...);
+/* SCANFLIKE1 */
+int (scanf)(const char *format, ...);
+/* PRINTFLIKE2 */
+int (sprintf)(char *s, const char *format, ...);
+/* SCANFLIKE2 */
+int (sscanf)(const char *s, const char *format, ...);
+int (vfprintf)(FILE *stream, const char *format, va_list arg);
+int (vprintf)(const char *format, va_list arg);
+int (vsprintf)(char *s, const char *format, va_list arg);
+int (fgetc)(FILE *stream);
+char *(fgets)(char *s, int n, FILE *stream);
+int (fputc)(int c, FILE *stream);
+int (fputs)(const char *s, FILE *stream);
+int (getc)(FILE *stream);
+int (getchar)(void);
+char *(gets)(char *s);
+int (putc)(int c, FILE *stream);
+int (putchar)(int c);
+int (puts)(const char *s);
+int (ungetc)(int c, FILE *stream);
+size_t (fread)(void *ptr, size_t size, size_t nmemb, FILE *stream);
+size_t (fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+int (fgetpos)(FILE *stream, fpos_t *pos);
+int (fseek)(FILE *stream, long offset, int whence);
+int (fsetpos)(FILE *stream, const fpos_t *pos);
+long (ftell)(FILE *stream);
+void (rewind)(FILE *stream);
+void (clearerr)(FILE *stream);
+int (feof)(FILE *stream);
+int (ferror)(FILE *stream);
+void (perror)(const char *s);
+
+/*
+ * stdlib.h
+ */
+double (atof)(const char *nptr);
+int (atoi)(const char *nptr);
+long (atol)(const char *nptr);
+double (strtod)(const char *nptr, char **endptr);
+long (strtol)(const char *nptr, char **endptr, int base);
+unsigned long (strtoul)(const char *nptr, char **endptr, int base);
+int (rand)(void);
+void (srand)(unsigned seed);
+void *(calloc)(size_t nmemb, size_t size);
+void (free)(void *ptr);
+void *(malloc)(size_t size);
+void *(realloc)(void *ptr, size_t size);
+void (abort)(void);
+int (atexit)(void (*func)(void));
+void (exit)(int status);
+char *(getenv)(const char *name);
+int (system)(const char *string);
+void *(bsearch)(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*compar)(const void *, const void *));
+void (qsort)(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *));
+int (abs)(int j);
+div_t (div)(int numer, int denom);
+long (labs)(long j);
+ldiv_t (ldiv)(long numer, long denom);
+int (mblen)(const char *s, size_t n);
+int (mbtowc)(wchar_t *PWC, const char *s, size_t n);
+int (wctomb)(char *s, wchar_t wchar);
+size_t (mbstowcs)(wchar_t *pwcs, const char *s, size_t n);
+size_t (wcstombs)(char *s, const wchar_t *pwcs, size_t n);
+
+/*
+ * string.h
+ */
+void *(memcpy)(void *s1, const void *s2, size_t n);
+void *(memmove)(void *s1, const void *s2, size_t n);
+char *(strcpy)(char *s1, const char *s2);
+char *(strncpy)(char *s1, const char *s2, size_t n);
+char *(strcat)(char *s1, const char *s2);
+char *(strncat)(char *s1, const char *s2, size_t n);
+int (memcmp)(const void *s1, const void *s2, size_t n);
+int (strcmp)(const char *s1, const char *s2);
+int (strcoll)(const char *s1, const char *s2);
+int (strncmp)(const char *s1, const char *s2, size_t n);
+size_t (strxfrm)(char *s1, const char *s2, size_t n);
+void *(memchr)(const void *s, int c, size_t n);
+char *(strchr)(const char *s, int c);
+size_t (strcspn)(const char *s1, const char *s2);
+char *(strpbrk)(const char *s1, const char *s2);
+char *(strrchr)(const char *s1, int c);
+size_t (strspn)(const char *s1, const char *s2);
+char *(strstr)(const char *s1, const char *s2);
+char *(strtok)(char *s1, const char *s2);
+void *(memset)(void *s, int c, size_t n);
+char *(strerror)(int errnom);
+size_t (strlen)(const char *s);
+
+/*
+ * time.h
+ */
+clock_t (clock)(void);
+double (difftime)(time_t time1, time_t time2);
+time_t (mktime)(struct tm *timeptr);
+time_t (time)(time_t *timer);
+char *(asctime)(const struct tm *timeptr);
+char *(ctime)(const time_t *timer);
+struct tm *(gmtime)(const time_t *timer);
+struct tm *(localtime)(const time_t *timer);
+size_t (strftime)(char *s, size_t maxsize, const char *format,
+ const struct tm *timeptr);
diff --git a/usr.bin/xlint/xlint/Makefile b/usr.bin/xlint/xlint/Makefile
new file mode 100644
index 0000000..35fea3f
--- /dev/null
+++ b/usr.bin/xlint/xlint/Makefile
@@ -0,0 +1,17 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:25:14 cgd Exp $
+
+.PATH: ${.CURDIR}/../lint1
+
+PROG= xlint
+SRCS= xlint.c mem.c
+MAN1= lint.1
+
+CFLAGS+=-I${.CURDIR}/../lint1
+
+realinstall:
+ ${INSTALL} ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${PROG} ${DESTDIR}${BINDIR}/lint
+
+
+.include "${.CURDIR}/../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/xlint/lint.1 b/usr.bin/xlint/xlint/lint.1
new file mode 100644
index 0000000..a020a53
--- /dev/null
+++ b/usr.bin/xlint/xlint/lint.1
@@ -0,0 +1,509 @@
+.\" $NetBSD: lint.1,v 1.3 1995/10/23 13:45:31 jpo Exp $
+.\"
+.\" Copyright (c) 1994, 1995 Jochen Pohl
+.\" All Rights Reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Jochen Pohl for
+.\" The NetBSD Project.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 28, 1994
+.Dt LINT 1
+.Os FreeBSD
+.Sh NAME
+.Nm lint
+.Nd a C program verifier.
+.Sh SYNOPSIS
+.Nm lint
+.Op Fl abceghprvxzHFV
+.Op Fl s Ns | Ns Fl t
+.Op Fl i Ns | Ns Fl nu
+.Op Fl D Ns Ar name Ns Op =def
+.Op Fl U Ns Ar name
+.Op Fl I Ns Ar directory
+.Op Fl L Ns Ar directory
+.Op Fl l Ns Ar library
+.Op Fl o Ns Ar outputfile
+.Ar
+.Nm lint
+.Op Fl abceghprvzHFV
+.Op Fl s Ns | Ns Fl t
+.Fl C Ns Ar library
+.Op Fl D Ns Ar name Ns Op =def
+.Op Fl I Ns Ar directory
+.Op Fl U Ns Ar name
+.Ar
+.Sh DESCRIPTION
+.Nm
+attempts to detect features of the named C program files
+that are likely to be bugs, to be non-portable, or to be
+wasteful. It also performs stricter type checking then does
+the C compiler.
+.Nm
+runs the C preprocessor as its first phase, with the
+preprocessor symbol
+.Sy lint
+defined to allow certain questionable code to be altered
+or skipped by
+.Nm lint .
+Therefore, this symbol should be thought of as a reserved
+word for all code that is to be checked by
+.Nm lint .
+.Pp
+Among the possible problems that are currently noted are
+unreachable statements, loops not entered at the top,
+variables declared and not used, and logical expressions
+with constant values. Function calls are checked for
+inconsistencies, such as calls to functions that return
+values in some places and not in others, functions called
+with varying numbers of arguments, function calls that
+pass arguments of a type other than the type the function
+expects to receive, functions whose values are not used,
+and calls to functions not returning values that use
+the non-existent return value of the function.
+.Pp
+Filename arguments ending with
+.Pa \&.c
+are taken to be C source files. Filename arguments with
+names ending with
+.Pa \&.ln
+are taken to be the result of an earlier invocation of
+.Nm lint ,
+with either the
+.Fl i ,
+.Fl o
+or
+.Fl C
+option in effect. The
+.Pa \&.ln
+files are analogous to the
+.Pa \&.o
+(object) files produced by
+.Xr cc 1
+from
+.Pa \&.c
+files.
+.Nm
+also accepts special libraries specified with the
+.Fl l
+option, which contain definitions of library routines and
+variables.
+.Pp
+.Nm
+takes all the
+.Pa \&.c , \&.ln ,
+and
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+(lint library) files and processes them in command-line order.
+By default,
+.Nm
+appends the standard C lint library
+.Pq Pa llib-lc.ln
+to the end of the list of files. When the
+.Fl i
+option is used, the
+.Pa \&.ln
+files are ignored.
+Also, when the
+.Fl o
+or
+.Fl i
+options are used, the
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+files are ignored. When the
+.Fl i
+option is
+.Em omitted
+the second pass of
+.Nm
+checks this list of files for mutual compatibility. At this point,
+if a complaint stems not from a given source file, but from one of
+its included files, the source filename will be printed followed by
+a question mark.
+.Pp
+.Sy Options
+.Bl -tag -width Fl
+.It Fl a
+Report assignments of
+.Sy long
+values to variables that are not
+.Sy long .
+.It Fl aa
+Additional to
+.Fl a ,
+report
+.Em all
+assignments of integer values to other integer values which
+cause implicit narrowing conversion.
+.It Fl b
+Report
+.Sy break
+statements that cannot be reached. This is not the default
+because, unfortunately, most
+.Xr lex 1
+and many
+.Xr yacc 1
+outputs produce many such complaints.
+.It Fl c
+Complain about casts which have questionable portability.
+.It Fl e
+Complain about unusual operations on
+.Sy enum Ns -Types
+and combinations of
+.Sy enum Ns -
+and
+.Sy integer Ns -Types.
+.It Fl g
+Don't print warnings for some extensions of
+.Xr gcc 1
+to the C language. Currently these are nonconstant initializers in
+automatic aggregate initializations, arithmetic on pointer to void,
+zero sized structures, subscripting of non-lvalue arrays, prototypes
+overriding old style function declarations and long long
+integer types. The
+.Fl g
+flag also turns on the keywords
+.Sy asm
+and
+.Sy inline
+(alternate keywords with leading underscores for both
+.Sy asm
+and
+.Sy inline
+are always available).
+.It Fl h
+Apply a number of heuristic tests to attempt to intuit
+bugs, improve style, and reduce waste.
+.It Fl i
+Produce a
+.Pa \&.ln
+file for every
+.Pa \&.c
+file on the command line. These
+.Pa \&.ln
+files are the product of
+.Nm lint Ns 's
+first pass only, and are not checked for compatibility
+between functions.
+.It Fl n
+Do not check compatibility against the standard library.
+.It Fl p
+Attempt to check portability of code to other dialects of C.
+.It Fl r
+In case of redeclarations report the position of the
+previous declaration.
+.It Fl s
+Strict ANSI C mode. Issue warnings and errors required by ANSI C.
+Also do not produce warnings for constructs which behave
+differently in traditional C and ANSI C. With the
+.Fl s
+flag,
+.Li __STRICT_ANSI__
+is a predefined preprocessor macro.
+.It Fl t
+Traditional C mode.
+.Li __STDC__
+is not predefined in this mode. Warnings are printed for constructs
+not allowed in traditional C. Warnings for constructs which behave
+differently in traditional C and ANSI C are suppressed. Preprocessor
+macros describing the machine type (e.g.
+.Li sun3 Ns )
+and machine architecture (e.g.
+.Li m68k Ns )
+are defined without leading and trailing underscores. The keywords
+.Sy const Ns ,
+.Sy volatile
+and
+.Sy signed
+are not available in traditional C mode (although the alternate
+keywords with leading underscores still are).
+.It Fl u
+Do not complain about functions and external variables used
+and not defined, or defined and not used (this is suitable
+for running
+.Nm
+on a subset of files comprising part of a larger program).
+.It Fl v
+Suppress complaints about unused arguments in functions.
+.It Fl x
+Report variables referred to by
+.Sy extern
+declarations, but never used.
+.It Fl z
+Do not complain about structures that are never defined
+(for example, using a structure pointer without knowing
+its contents).
+.It Fl C Ns Ar library
+Create a
+.Nm
+library with the name
+.Pa llib-l Ns Ar library Ns Pa .ln .
+This library is built from all
+.Pa \&.c
+and
+.Pa \&.ln
+input files. After all global definitions of functions and
+variables in these files are written to the newly created library,
+.Nm
+checks all input files, including libraries specified with the
+.Fl l
+option, for mutual compatibility.
+.It Fl D Ns Ar name Ns Op =def
+Define
+.Ar name
+for
+.Xr cpp 1 ,
+as if by a
+.Li #define
+directive. If no definition is given,
+.Ar name
+is defined as 1.
+.It Fl I Ns Ar directory
+Add
+.Ar directory
+to the list of directories in which to search for include files.
+.It Fl l Ns Ar library
+Include the lint library
+.Pa llib-l Ns Ar library Ns Pa \&.ln .
+.It Fl L Ns Ar directory
+Search for lint libraries in
+.Ar directory
+and
+.Ar directory Ns Pa /lint
+before searching the standard place.
+.It Fl F
+Print pathnames of files.
+.Nm
+normally prints the filename without the path.
+.It Fl H
+If a complaint stems from an included file
+.Nm
+prints the name of the included file instead of the source file name
+followed by a question mark.
+.It Fl o Ns Ar outputfile
+Name the output file
+.Ar outputfile .
+The output file produced is the input that is given to
+.Nm lint Ns 's
+second pass. The
+.Fl o
+option simply saves this file in the named output file. If the
+.Fl i
+option is also used the files are not checked for compatibility.
+To produce a
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+without extraneous messages, use of the
+.Fl u
+option is suggested. The
+.Fl v
+option is useful if the source file(s) for the lint library
+are just external interfaces.
+.It Fl U Ns Ar name
+Remove any initial definition of
+.Ar name
+for the preprocessor.
+.It Fl V
+Print the command lines constructed by the controller program to
+run the C preprocessor and
+.Nm lint Ns 's
+first and second pass.
+.El
+.Pp
+.Sy Input Grammar
+.Pp
+.Nm lint Ns 's
+first pass reads standard C source files.
+.Nm
+recognizes the following C comments as commands.
+.Bl -tag -width Fl
+.It Li /* ARGSUSED Ns Ar n Li */
+makes
+.Nm
+check only the first
+.Ar n
+arguments for usage; a missing
+.Ar n
+is taken to be 0 (this option acts like the
+.Fl v
+option for the next function).
+.It Li /* CONSTCOND */ No or Xo
+.Li /* CONSTANTCOND */ No or
+.Li /* CONSTANTCONDITION */
+.Xc
+suppress complaints about constant operands for the next expression.
+.It Li /*\ FALLTHRU\ */ No or Xo
+.Li /* FALLTHROUGH */
+.Xc
+suppress complaints about fall through to a
+.Sy case
+or
+.Sy default
+labelled statement. This directive should be placed immediately
+preceding the label.
+.It Li /* LINTLIBRARY */
+At the beginning of a file, mark all functions and variables defined
+in this file as
+.Em used .
+Also shut off complaints about unused function arguments.
+.It Li /* LINTED Xo
+.Op Ar comment
+.Li */ No or
+.Li /* NOSTRICT
+.Op Ar comment
+.Li */
+.Xc
+Suppresses any intra-file warning except those dealing with
+unused variables or functions. This directive should be placed
+on the line immediately preceding where the lint warning occurred.
+.It Li /* LONGLONG */
+Suppress complaints about use of long long integer types.
+.It Li /* NOTREACHED */
+At appropriate points, inhibit complaints about unreachable code.
+(This comment is typically placed just after calls to functions
+like
+.Xr exit 3 ).
+.It Li /* PRINTFLIKE Ns Ar n Li */
+makes
+.Nm
+check the first
+.Pq Ar n Ns No -1
+arguments as usual. The
+.Ar n Ns No -th
+argument is interpreted as a
+.Sy printf
+format string that is used to check the remaining arguments.
+.It Li /* PROTOLIB Ns Ar n Li */
+causes
+.Nm
+to treat function declaration prototypes as function definitions
+if
+.Ar n
+is non-zero. This directive can only be used in conjunction with
+the
+.Li /* LINTLIBRARY */
+directive. If
+.Ar n
+is zero, function prototypes will be treated normally.
+.It Li /* SCANFLIKE Ns Ar n Li */
+makes
+.Nm
+check the first
+.Pq Ar n Ns No -1
+arguments as usual. The
+.Ar n Ns No -th
+argument is interpreted as a
+.Sy scanf
+format string that is used to check the remaining arguments.
+.It Li /* VARARGS Ns Ar n Li */
+Suppress the usual checking for variable numbers of arguments in
+the following function declaration. The data types of the first
+.Ar n
+arguments are checked; a missing
+.Ar n
+is taken to be 0.
+.El
+.Pp
+The behavior of the
+.Fl i
+and the
+.Fl o
+options allows for incremental use of
+.Nm
+on a set of C source files. Generally, one invokes
+.Nm
+once for each source file with the
+.Fl i
+option. Each of these invocations produces a
+.Pa \&.ln
+file that corresponds to the
+.Pa \&.c
+file, and prints all messages that are about just that
+source file. After all the source files have been separately
+run through
+.Nm lint ,
+it is invoked once more (without the
+.Fl i
+option), listing all the
+.Pa \&.ln
+files with the needed
+.Fl l Ns Ar library
+options. this will print all the inter-file inconsistencies. This
+scheme works well with
+.Xr make 1 ;
+it allows
+.Xr make 1
+to be used to
+.Nm
+only the source files that have been modified since the last
+time the set of source files were
+.Nm lint Ns No ed .
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev LIBDIR
+the directory where the lint libraries specified by the
+.Fl l Ns Ar library
+option must exist. If this environment variable is undefined,
+then the default path
+.Pa /usr/libdata/lint
+will be used to search for the libraries.
+.It Ev TMPDIR
+usually the path for temporary files can be redefined by setting
+this environment variable.
+.El
+.Sh FILES
+.Bl -tag -width /usr/libdata/lint/llib-lc.ln -compact
+.It Pa /usr/libexec/lint Ns Bq 12
+programs
+.It Pa /usr/libdata/lint/llib-l*.ln
+various prebuilt lint libraries
+.It Pa /tmp/lint*
+temporaries
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr cpp 1 ,
+.Xr make 1
+.Sh AUTHORS
+Jochen Pohl
+.Sh BUGS
+The routines
+.Xr exit 3 ,
+.Xr longjmp 3
+and other functions that do not return are not understood; this
+causes various incorrect diagnostics.
+.Pp
+Static functions which are used only before their first
+extern declaration are reported as unused.
+.Pp
+Libraries created by the
+.Fl o
+option will, when used in later
+.Nm
+runs, cause certain errors that were reported when the libraries
+were created to be reported again, and cause line numbers and file
+names from the original source used to create those libraries
+to be reported in error messages. For these reasons, it is recommended
+to use the
+.Fl C
+option to create lint libraries.
diff --git a/usr.bin/xlint/xlint/pathnames.h b/usr.bin/xlint/xlint/pathnames.h
new file mode 100644
index 0000000..d03845d
--- /dev/null
+++ b/usr.bin/xlint/xlint/pathnames.h
@@ -0,0 +1,38 @@
+/* $NetBSD: pathnames.h,v 1.2 1995/07/03 21:25:20 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* directory where lint1 and lint2 reside */
+#define PATH_LIBEXEC "/usr/libexec"
+
+/* default library search path */
+#define PATH_LINTLIB "/usr/libdata/lint"
diff --git a/usr.bin/xlint/xlint/xlint.c b/usr.bin/xlint/xlint/xlint.c
new file mode 100644
index 0000000..e4ad124
--- /dev/null
+++ b/usr.bin/xlint/xlint/xlint.c
@@ -0,0 +1,771 @@
+/* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+
+#include "lint.h"
+#include "pathnames.h"
+
+/* directory for temporary files */
+static const char *tmpdir;
+
+/* path name for cpp output */
+static char *cppout;
+
+/* files created by 1st pass */
+static char **p1out;
+
+/* input files for 2nd pass (without libraries) */
+static char **p2in;
+
+/* library which will be created by 2nd pass */
+static char *p2out;
+
+/* flags always passed to cpp */
+static char **cppflags;
+
+/* flags for cpp, controled by sflag/tflag */
+static char **lcppflgs;
+
+/* flags for lint1 */
+static char **l1flags;
+
+/* flags for lint2 */
+static char **l2flags;
+
+/* libraries for lint2 */
+static char **l2libs;
+
+/* default libraries */
+static char **deflibs;
+
+/* additional libraries */
+static char **libs;
+
+/* search path for libraries */
+static char **libsrchpath;
+
+/* flags */
+static int iflag, oflag, Cflag, sflag, tflag, Fflag;
+
+/* print the commands executed to run the stages of compilation */
+static int Vflag;
+
+/* filename for oflag */
+static char *outputfn;
+
+/* reset after first .c source has been processed */
+static int first = 1;
+
+/*
+ * name of a file which is currently written by a child and should
+ * be removed after abnormal termination of the child
+ */
+static const char *currfn;
+
+
+static void appstrg __P((char ***, char *));
+static void appcstrg __P((char ***, const char *));
+static void applst __P((char ***, char *const *));
+static void freelst __P((char ***));
+static char *concat2 __P((const char *, const char *));
+static char *concat3 __P((const char *, const char *, const char *));
+static void terminate __P((int));
+static const char *basename __P((const char *, int));
+static void appdef __P((char ***, const char *));
+static void usage __P((void));
+static void fname __P((const char *, int));
+static void runchild __P((const char *, char *const *, const char *));
+static void findlibs __P((char *const *));
+static int rdok __P((const char *));
+static void lint2 __P((void));
+static void cat __P((char *const *, const char *));
+
+/*
+ * Some functions to deal with lists of strings.
+ * Take care that we get no surprises in case of asyncron signals.
+ */
+static void
+appstrg(lstp, s)
+ char ***lstp, *s;
+{
+ char **lst, **olst;
+ int i;
+
+ olst = *lstp;
+ for (i = 0; olst[i] != NULL; i++) ;
+ lst = xmalloc((i + 2) * sizeof (char *));
+ (void)memcpy(lst, olst, i * sizeof (char *));
+ lst[i] = s;
+ lst[i + 1] = NULL;
+ *lstp = lst;
+}
+
+static void
+appcstrg(lstp, s)
+ char ***lstp;
+ const char *s;
+{
+ appstrg(lstp, xstrdup(s));
+}
+
+static void
+applst(destp, src)
+ char ***destp;
+ char *const *src;
+{
+ int i, k;
+ char **dest, **odest;
+
+ odest = *destp;
+ for (i = 0; odest[i] != NULL; i++) ;
+ for (k = 0; src[k] != NULL; k++) ;
+ dest = xmalloc((i + k + 1) * sizeof (char *));
+ (void)memcpy(dest, odest, i * sizeof (char *));
+ for (k = 0; src[k] != NULL; k++)
+ dest[i + k] = xstrdup(src[k]);
+ dest[i + k] = NULL;
+ *destp = dest;
+ free(odest);
+}
+
+static void
+freelst(lstp)
+ char ***lstp;
+{
+ char *s;
+ int i;
+
+ for (i = 0; (*lstp)[i] != NULL; i++) ;
+ while (i-- > 0) {
+ s = (*lstp)[i];
+ (*lstp)[i] = NULL;
+ free(s);
+ }
+}
+
+static char *
+concat2(s1, s2)
+ const char *s1, *s2;
+{
+ char *s;
+
+ s = xmalloc(strlen(s1) + strlen(s2) + 1);
+ (void)strcpy(s, s1);
+ (void)strcat(s, s2);
+
+ return (s);
+}
+
+static char *
+concat3(s1, s2, s3)
+ const char *s1, *s2, *s3;
+{
+ char *s;
+
+ s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
+ (void)strcpy(s, s1);
+ (void)strcat(s, s2);
+ (void)strcat(s, s3);
+
+ return (s);
+}
+
+/*
+ * Clean up after a signal.
+ */
+static void
+terminate(signo)
+ int signo;
+{
+ int i;
+
+ if (cppout != NULL)
+ (void)remove(cppout);
+
+ if (p1out != NULL) {
+ for (i = 0; p1out[i] != NULL; i++)
+ (void)remove(p1out[i]);
+ }
+
+ if (p2out != NULL)
+ (void)remove(p2out);
+
+ if (currfn != NULL)
+ (void)remove(currfn);
+
+ exit(signo != 0 ? 1 : 0);
+}
+
+/*
+ * Returns a pointer to the last component of strg after delim.
+ * Returns strg if the string does not contain delim.
+ */
+static const char *
+basename(strg, delim)
+ const char *strg;
+ int delim;
+{
+ const char *cp, *cp1, *cp2;
+
+ cp = cp1 = cp2 = strg;
+ while (*cp != '\0') {
+ if (*cp++ == delim) {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+static void
+appdef(lstp, def)
+ char ***lstp;
+ const char *def;
+{
+ appstrg(lstp, concat2("-D__", def));
+ appstrg(lstp, concat3("-D__", def, "__"));
+}
+
+static void
+usage()
+{
+ (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
+ (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
+ (void)printf("\n");
+ (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n");
+ (void)printf(" [-Idirectory] [-Uname] file ...\n");
+ terminate(-1);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ char flgbuf[3], *tmp, *s;
+ size_t len;
+ struct utsname un;
+
+ if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
+ tmpdir = xstrdup(_PATH_TMP);
+ } else {
+ s = xmalloc(len + 2);
+ (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
+ tmpdir = s;
+ }
+
+ cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
+ (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
+ if (mktemp(cppout) == NULL) {
+ warn("can't make temp");
+ terminate(-1);
+ }
+
+ p1out = xcalloc(1, sizeof (char *));
+ p2in = xcalloc(1, sizeof (char *));
+ cppflags = xcalloc(1, sizeof (char *));
+ lcppflgs = xcalloc(1, sizeof (char *));
+ l1flags = xcalloc(1, sizeof (char *));
+ l2flags = xcalloc(1, sizeof (char *));
+ l2libs = xcalloc(1, sizeof (char *));
+ deflibs = xcalloc(1, sizeof (char *));
+ libs = xcalloc(1, sizeof (char *));
+ libsrchpath = xcalloc(1, sizeof (char *));
+
+ appcstrg(&cppflags, "-lang-c");
+ appcstrg(&cppflags, "-undef");
+ appcstrg(&cppflags, "-$");
+ appcstrg(&cppflags, "-C");
+ appcstrg(&cppflags, "-Wcomment");
+#if defined (__FreeBSD__) && (__FreeBSD__ == 3)
+ appcstrg(&cppflags, "-D__FreeBSD__=3");
+#elif defined (__FreeBSD__) && (__FreeBSD__ == 2)
+ appcstrg(&cppflags, "-D__FreeBSD__=2");
+#else
+# error "This ain't NetBSD. You lose!"
+ appcstrg(&cppflags, "-D__NetBSD__");
+#endif
+ appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
+ appdef(&cppflags, "lint");
+ appdef(&cppflags, "unix");
+
+ appcstrg(&lcppflgs, "-Wtraditional");
+
+ if (uname(&un) == -1)
+ err(1, "uname");
+ appdef(&cppflags, un.machine);
+ appstrg(&lcppflgs, concat2("-D", un.machine));
+
+#ifdef MACHINE_ARCH
+ if (strcmp(un.machine, MACHINE_ARCH) != 0) {
+ appdef(&cppflags, MACHINE_ARCH);
+ appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
+ }
+#endif
+
+ appcstrg(&deflibs, "c");
+
+ if (signal(SIGHUP, terminate) == SIG_IGN)
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, terminate);
+ (void)signal(SIGQUIT, terminate);
+ (void)signal(SIGTERM, terminate);
+
+ while (argc > optind) {
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V");
+
+ switch (c) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'e':
+ case 'g':
+ case 'r':
+ case 'v':
+ case 'z':
+ (void)sprintf(flgbuf, "-%c", c);
+ appcstrg(&l1flags, flgbuf);
+ break;
+
+ case 'F':
+ Fflag = 1;
+ /* FALLTHROUGH */
+ case 'u':
+ case 'h':
+ (void)sprintf(flgbuf, "-%c", c);
+ appcstrg(&l1flags, flgbuf);
+ appcstrg(&l2flags, flgbuf);
+ break;
+
+ case 'i':
+ if (Cflag)
+ usage();
+ iflag = 1;
+ break;
+
+ case 'n':
+ freelst(&deflibs);
+ break;
+
+ case 'p':
+ appcstrg(&l1flags, "-p");
+ appcstrg(&l2flags, "-p");
+ if (*deflibs != NULL) {
+ freelst(&deflibs);
+ appcstrg(&deflibs, "c");
+ }
+ break;
+
+ case 's':
+ if (tflag)
+ usage();
+ freelst(&lcppflgs);
+ appcstrg(&lcppflgs, "-trigraphs");
+ appcstrg(&lcppflgs, "-Wtrigraphs");
+ appcstrg(&lcppflgs, "-pedantic");
+ appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
+ appcstrg(&l1flags, "-s");
+ appcstrg(&l2flags, "-s");
+ sflag = 1;
+ break;
+
+ case 't':
+ if (sflag)
+ usage();
+ freelst(&lcppflgs);
+ appcstrg(&lcppflgs, "-traditional");
+ appstrg(&lcppflgs, concat2("-D", MACHINE));
+#ifdef MACHINE_ARCH
+ appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
+#endif
+ appcstrg(&l1flags, "-t");
+ appcstrg(&l2flags, "-t");
+ tflag = 1;
+ break;
+
+ case 'x':
+ appcstrg(&l2flags, "-x");
+ break;
+
+ case 'C':
+ if (Cflag || oflag || iflag)
+ usage();
+ Cflag = 1;
+ appstrg(&l2flags, concat2("-C", optarg));
+ p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
+ (void)sprintf(p2out, "llib-l%s.ln", optarg);
+ freelst(&deflibs);
+ break;
+
+ case 'D':
+ case 'I':
+ case 'U':
+ (void)sprintf(flgbuf, "-%c", c);
+ appstrg(&cppflags, concat2(flgbuf, optarg));
+ break;
+
+ case 'l':
+ appcstrg(&libs, optarg);
+ break;
+
+ case 'o':
+ if (Cflag || oflag)
+ usage();
+ oflag = 1;
+ outputfn = xstrdup(optarg);
+ break;
+
+ case 'L':
+ appcstrg(&libsrchpath, optarg);
+ break;
+
+ case 'H':
+ appcstrg(&l2flags, "-H");
+ break;
+
+ case 'V':
+ Vflag = 1;
+ break;
+
+ case '?':
+ usage();
+ /* NOTREACHED */
+
+ case -1:
+ /* filename */
+ fname(argv[0], argc == 1);
+ first = 0;
+ optind = 1;
+ }
+
+ }
+
+ if (first)
+ usage();
+
+ if (iflag)
+ terminate(0);
+
+ if (!oflag) {
+ if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
+ s = PATH_LINTLIB;
+ appcstrg(&libsrchpath, s);
+ findlibs(libs);
+ findlibs(deflibs);
+ }
+
+ (void)printf("Lint pass2:\n");
+ lint2();
+
+ if (oflag)
+ cat(p2in, outputfn);
+
+ if (Cflag)
+ p2out = NULL;
+
+ terminate(0);
+ /* NOTREACHED */
+ return 0;
+}
+
+/*
+ * Read a file name from the command line
+ * and pass it through lint1 if it is a C source.
+ */
+static void
+fname(name, last)
+ const char *name;
+ int last;
+{
+ const char *bn, *suff;
+ char **args, *ofn, *path;
+ size_t len;
+
+ bn = basename(name, '/');
+ suff = basename(bn, '.');
+
+ if (strcmp(suff, "ln") == 0) {
+ /* only for lint2 */
+ if (!iflag)
+ appcstrg(&p2in, name);
+ return;
+ }
+
+ if (strcmp(suff, "c") != 0 &&
+ (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
+ warnx("unknown file type: %s\n", name);
+ return;
+ }
+
+ if (!iflag || !first || !last)
+ (void)printf("%s:\n", Fflag ? name : bn);
+
+ /* build the name of the output file of lint1 */
+ if (oflag) {
+ ofn = outputfn;
+ outputfn = NULL;
+ oflag = 0;
+ } else if (iflag) {
+ ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
+ len = bn == suff ? strlen(bn) : (suff - 1) - bn;
+ (void)sprintf(ofn, "%.*s", (int)len, bn);
+ (void)strcat(ofn, ".ln");
+ } else {
+ ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
+ (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
+ if (mktemp(ofn) == NULL) {
+ warn("can't make temp");
+ terminate(-1);
+ }
+ }
+ if (!iflag)
+ appcstrg(&p1out, ofn);
+
+ args = xcalloc(1, sizeof (char *));
+
+ /* run cpp */
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp"));
+ (void)sprintf(path, "%s/cpp", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, cppflags);
+ applst(&args, lcppflgs);
+ appcstrg(&args, name);
+ appcstrg(&args, cppout);
+
+ runchild(path, args, cppout);
+ free(path);
+ freelst(&args);
+
+ /* run lint1 */
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
+ (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, l1flags);
+ appcstrg(&args, cppout);
+ appcstrg(&args, ofn);
+
+ runchild(path, args, ofn);
+ free(path);
+ freelst(&args);
+
+ appcstrg(&p2in, ofn);
+ free(ofn);
+
+ free(args);
+}
+
+static void
+runchild(path, args, crfn)
+ const char *path, *crfn;
+ char *const *args;
+{
+ int status, rv, signo, i;
+
+ if (Vflag) {
+ for (i = 0; args[i] != NULL; i++)
+ (void)printf("%s ", args[i]);
+ (void)printf("\n");
+ }
+
+ currfn = crfn;
+
+ (void)fflush(stdout);
+
+ switch (fork()) {
+ case -1:
+ warn("cannot fork");
+ terminate(-1);
+ /* NOTREACHED */
+ default:
+ /* parent */
+ break;
+ case 0:
+ /* child */
+ (void)execv(path, args);
+ warn("cannot exec %s", path);
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ while ((rv = wait(&status)) == -1 && errno == EINTR) ;
+ if (rv == -1) {
+ warn("wait");
+ terminate(-1);
+ }
+ if (WIFSIGNALED(status)) {
+ signo = WTERMSIG(status);
+ warnx("%s got SIG%s", path, sys_signame[signo]);
+ terminate(-1);
+ }
+ if (WEXITSTATUS(status) != 0)
+ terminate(-1);
+ currfn = NULL;
+}
+
+static void
+findlibs(liblst)
+ char *const *liblst;
+{
+ int i, k;
+ const char *lib, *path;
+ char *lfn;
+ size_t len;
+
+ lfn = NULL;
+
+ for (i = 0; (lib = liblst[i]) != NULL; i++) {
+ for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
+ len = strlen(path) + strlen(lib);
+ lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
+ (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
+ if (rdok(lfn))
+ break;
+ lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
+ (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
+ if (rdok(lfn))
+ break;
+ }
+ if (path != NULL) {
+ appstrg(&l2libs, concat2("-l", lfn));
+ } else {
+ warnx("cannot find llib-l%s.ln", lib);
+ }
+ }
+
+ free(lfn);
+}
+
+static int
+rdok(path)
+ const char *path;
+{
+ struct stat sbuf;
+
+ if (stat(path, &sbuf) == -1)
+ return (0);
+ if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+ return (0);
+ if (access(path, R_OK) == -1)
+ return (0);
+ return (1);
+}
+
+static void
+lint2()
+{
+ char *path, **args;
+
+ args = xcalloc(1, sizeof (char *));
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
+ (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, l2flags);
+ applst(&args, l2libs);
+ applst(&args, p2in);
+
+ runchild(path, args, p2out);
+ free(path);
+ freelst(&args);
+ free(args);
+}
+
+static void
+cat(srcs, dest)
+ char *const *srcs;
+ const char *dest;
+{
+ int ifd, ofd, i;
+ char *src, *buf;
+ ssize_t rlen;
+
+ if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
+ warn("cannot open %s", dest);
+ terminate(-1);
+ }
+
+ buf = xmalloc(MBLKSIZ);
+
+ for (i = 0; (src = srcs[i]) != NULL; i++) {
+ if ((ifd = open(src, O_RDONLY)) == -1) {
+ free(buf);
+ warn("cannot open %s", src);
+ terminate(-1);
+ }
+ do {
+ if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
+ free(buf);
+ warn("read error on %s", src);
+ terminate(-1);
+ }
+ if (write(ofd, buf, (size_t)rlen) == -1) {
+ free(buf);
+ warn("write error on %s", dest);
+ terminate(-1);
+ }
+ } while (rlen == MBLKSIZ);
+ (void)close(ifd);
+ }
+ (void)close(ofd);
+ free(buf);
+}
+
diff --git a/usr.bin/xstr/xstr.c b/usr.bin/xstr/xstr.c
index 5f3d0ea..5b68c53 100644
--- a/usr.bin/xstr/xstr.c
+++ b/usr.bin/xstr/xstr.c
@@ -152,7 +152,7 @@ process(name)
continue;
}
for (cp = linebuf; c = *cp++;) switch (c) {
-
+
case '"':
if (incomm)
goto def;
@@ -185,7 +185,7 @@ process(name)
continue;
}
goto def;
-
+
def:
default:
putchar(c);
@@ -219,7 +219,7 @@ yankstr(cpp)
if (c == 0)
break;
if (c == '\n') {
- if (fgets(linebuf, sizeof linebuf, stdin)
+ if (fgets(linebuf, sizeof linebuf, stdin)
== NULL) {
if (ferror(stdin)) {
perror("x.c");
diff --git a/usr.bin/yacc/Makefile b/usr.bin/yacc/Makefile
index 71633a3..4e4fec2 100644
--- a/usr.bin/yacc/Makefile
+++ b/usr.bin/yacc/Makefile
@@ -1,12 +1,15 @@
# @(#)Makefile 5.3 (Berkeley) 5/12/90
+# $Id$
PROG= yacc
SRCS= closure.c error.c lalr.c lr0.c main.c mkpar.c output.c reader.c \
skeleton.c symtab.c verbose.c warshall.c
-MAN1= yacc.0 yyfix.0
+MAN1= yacc.1 yyfix.1
+LINKS+= ${BINDIR}/yacc ${BINDIR}/byacc
+MLINKS+=yacc.1 byacc.1
beforeinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${.CURDIR}/yyfix.sh ${DESTDIR}${BINDIR}/yyfix
.include <bsd.prog.mk>
diff --git a/usr.bin/yacc/closure.c b/usr.bin/yacc/closure.c
index 5f63c5f..8275106 100644
--- a/usr.bin/yacc/closure.c
+++ b/usr.bin/yacc/closure.c
@@ -32,22 +32,33 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)closure.c 5.3 (Berkeley) 5/24/93";
+static char const sccsid[] = "@(#)closure.c 5.3 (Berkeley) 5/24/93";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
short *itemset;
short *itemsetend;
unsigned *ruleset;
+static void set_EFF __P((void));
+#ifdef DEBUG
+static void print_closure __P((int));
+static void print_EFF __P(());
+static void print_first_derives __P(());
+#endif
+
static unsigned *first_derives;
static unsigned *EFF;
+static void
set_EFF()
{
register unsigned *row;
@@ -84,13 +95,14 @@ set_EFF()
}
+void
set_first_derives()
{
register unsigned *rrow;
register unsigned *vrow;
register int j;
register unsigned k;
- register unsigned cword;
+ register unsigned cword = 0;
register short *rp;
int rule;
@@ -139,6 +151,7 @@ set_first_derives()
}
+void
closure(nucleus, n)
short *nucleus;
int n;
@@ -209,6 +222,7 @@ int n;
+void
finalize_closure()
{
FREE(itemset);
@@ -219,6 +233,7 @@ finalize_closure()
#ifdef DEBUG
+static void
print_closure(n)
int n;
{
@@ -230,6 +245,7 @@ int n;
}
+static void
print_EFF()
{
register int i, j;
@@ -261,6 +277,7 @@ print_EFF()
}
+static void
print_first_derives()
{
register int i;
diff --git a/usr.bin/yacc/defs.h b/usr.bin/yacc/defs.h
index e5e96d2..237efe2 100644
--- a/usr.bin/yacc/defs.h
+++ b/usr.bin/yacc/defs.h
@@ -34,8 +34,10 @@
* SUCH DAMAGE.
*
* @(#)defs.h 5.6 (Berkeley) 5/24/93
+ * $Id$
*/
+#include <sys/cdefs.h> /* for __P macro */
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
@@ -308,20 +310,53 @@ extern short final_state;
/* global functions */
-extern char *allocate();
-extern bucket *lookup();
-extern bucket *make_bucket();
-
-
-/* system variables */
-
-extern int errno;
-
-
-/* system functions */
-
-extern void free();
-extern char *calloc();
-extern char *malloc();
-extern char *realloc();
-extern char *strcpy();
+char *allocate __P((unsigned));
+void closure __P((short *, int));
+void create_symbol_table __P((void));
+void default_action_warning __P((void));
+void dollar_error __P((int, char *, char *));
+void dollar_warning __P((int, int));
+void done __P((int));
+void fatal __P((char *msg));
+void finalize_closure __P((void));
+void free_parser __P((void));
+void free_symbols __P((void));
+void free_symbol_table __P((void));
+void illegal_character __P((char *));
+void illegal_tag __P((int, char *, char *));
+void lalr __P((void));
+bucket *lookup __P((char *));
+void lr0 __P((void));
+bucket *make_bucket __P((char *));
+void make_parser __P((void));
+void no_grammar __P((void));
+void no_space __P((void));
+void open_error __P((char *));
+void output __P((void));
+void over_unionized __P((char *));
+void prec_redeclared __P((void));
+void reader __P((void));
+void reflexive_transitive_closure __P((unsigned *, int));
+void reprec_warning __P((char *));
+void restarted_warning __P((void));
+void retyped_warning __P((char *));
+void revalued_warning __P((char *));
+void set_first_derives __P((void));
+void syntax_error __P((int, char *, char *));
+void terminal_lhs __P((int));
+void terminal_start __P((char *));
+void tokenized_start __P((char *));
+void undefined_goal __P((char *));
+void undefined_symbol_warning __P((char *));
+void unexpected_EOF __P((void));
+void unknown_rhs __P((int));
+void unterminated_action __P((int, char *, char *));
+void unterminated_comment __P((int, char *, char *));
+void unterminated_string __P((int, char *, char *));
+void unterminated_text __P((int, char *, char *));
+void unterminated_union __P((int, char *, char *));
+void untyped_lhs __P((void));
+void untyped_rhs __P((int, char *));
+void used_reserved __P((char *));
+void verbose __P((void));
+void write_section __P((char **));
diff --git a/usr.bin/yacc/error.c b/usr.bin/yacc/error.c
index 54a49ad..3ccfb14 100644
--- a/usr.bin/yacc/error.c
+++ b/usr.bin/yacc/error.c
@@ -32,17 +32,21 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)error.c 5.3 (Berkeley) 6/1/90";
+static char const sccsid[] = "@(#)error.c 5.3 (Berkeley) 6/1/90";
#endif /* not lint */
/* routines for printing error messages */
#include "defs.h"
+static void print_pos __P((char *, char *));
+void
fatal(msg)
char *msg;
{
@@ -51,6 +55,7 @@ char *msg;
}
+void
no_space()
{
fprintf(stderr, "%s: f - out of space\n", myname);
@@ -58,6 +63,7 @@ no_space()
}
+void
open_error(filename)
char *filename;
{
@@ -66,6 +72,7 @@ char *filename;
}
+void
unexpected_EOF()
{
fprintf(stderr, "%s: e - line %d of \"%s\", unexpected end-of-file\n",
@@ -74,6 +81,7 @@ unexpected_EOF()
}
+static void
print_pos(st_line, st_cptr)
char *st_line;
char *st_cptr;
@@ -101,6 +109,7 @@ char *st_cptr;
}
+void
syntax_error(st_lineno, st_line, st_cptr)
int st_lineno;
char *st_line;
@@ -113,6 +122,7 @@ char *st_cptr;
}
+void
unterminated_comment(c_lineno, c_line, c_cptr)
int c_lineno;
char *c_line;
@@ -125,6 +135,7 @@ char *c_cptr;
}
+void
unterminated_string(s_lineno, s_line, s_cptr)
int s_lineno;
char *s_line;
@@ -137,6 +148,7 @@ char *s_cptr;
}
+void
unterminated_text(t_lineno, t_line, t_cptr)
int t_lineno;
char *t_line;
@@ -149,6 +161,7 @@ char *t_cptr;
}
+void
unterminated_union(u_lineno, u_line, u_cptr)
int u_lineno;
char *u_line;
@@ -161,6 +174,7 @@ declaration\n", myname, u_lineno, input_file_name);
}
+void
over_unionized(u_cptr)
char *u_cptr;
{
@@ -171,6 +185,7 @@ declarations\n", myname, lineno, input_file_name);
}
+void
illegal_tag(t_lineno, t_line, t_cptr)
int t_lineno;
char *t_line;
@@ -183,6 +198,7 @@ char *t_cptr;
}
+void
illegal_character(c_cptr)
char *c_cptr;
{
@@ -193,6 +209,7 @@ char *c_cptr;
}
+void
used_reserved(s)
char *s;
{
@@ -202,6 +219,7 @@ char *s;
}
+void
tokenized_start(s)
char *s;
{
@@ -211,6 +229,7 @@ declared to be a token\n", myname, lineno, input_file_name, s);
}
+void
retyped_warning(s)
char *s;
{
@@ -219,6 +238,7 @@ redeclared\n", myname, lineno, input_file_name, s);
}
+void
reprec_warning(s)
char *s;
{
@@ -227,6 +247,7 @@ redeclared\n", myname, lineno, input_file_name, s);
}
+void
revalued_warning(s)
char *s;
{
@@ -235,6 +256,7 @@ redeclared\n", myname, lineno, input_file_name, s);
}
+void
terminal_start(s)
char *s;
{
@@ -244,6 +266,7 @@ token\n", myname, lineno, input_file_name, s);
}
+void
restarted_warning()
{
fprintf(stderr, "%s: w - line %d of \"%s\", the start symbol has been \
@@ -251,6 +274,7 @@ redeclared\n", myname, lineno, input_file_name);
}
+void
no_grammar()
{
fprintf(stderr, "%s: e - line %d of \"%s\", no grammar has been \
@@ -259,6 +283,7 @@ specified\n", myname, lineno, input_file_name);
}
+void
terminal_lhs(s_lineno)
int s_lineno;
{
@@ -268,6 +293,7 @@ of a production\n", myname, s_lineno, input_file_name);
}
+void
prec_redeclared()
{
fprintf(stderr, "%s: w - line %d of \"%s\", conflicting %%prec \
@@ -275,6 +301,7 @@ specifiers\n", myname, lineno, input_file_name);
}
+void
unterminated_action(a_lineno, a_line, a_cptr)
int a_lineno;
char *a_line;
@@ -287,6 +314,7 @@ char *a_cptr;
}
+void
dollar_warning(a_lineno, i)
int a_lineno;
int i;
@@ -296,6 +324,7 @@ end of the current rule\n", myname, a_lineno, input_file_name, i);
}
+void
dollar_error(a_lineno, a_line, a_cptr)
int a_lineno;
char *a_line;
@@ -308,6 +337,7 @@ char *a_cptr;
}
+void
untyped_lhs()
{
fprintf(stderr, "%s: e - line %d of \"%s\", $$ is untyped\n",
@@ -316,6 +346,7 @@ untyped_lhs()
}
+void
untyped_rhs(i, s)
int i;
char *s;
@@ -326,6 +357,7 @@ char *s;
}
+void
unknown_rhs(i)
int i;
{
@@ -335,6 +367,7 @@ int i;
}
+void
default_action_warning()
{
fprintf(stderr, "%s: w - line %d of \"%s\", the default action assigns an \
@@ -342,6 +375,7 @@ undefined value to $$\n", myname, lineno, input_file_name);
}
+void
undefined_goal(s)
char *s;
{
@@ -350,6 +384,7 @@ char *s;
}
+void
undefined_symbol_warning(s)
char *s;
{
diff --git a/usr.bin/yacc/lalr.c b/usr.bin/yacc/lalr.c
index bf9aec8..275f7d1 100644
--- a/usr.bin/yacc/lalr.c
+++ b/usr.bin/yacc/lalr.c
@@ -32,12 +32,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)lalr.c 5.3 (Berkeley) 6/1/90";
+static char const sccsid[] = "@(#)lalr.c 5.3 (Berkeley) 6/1/90";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
typedef
@@ -60,7 +63,22 @@ short *goto_map;
short *from_state;
short *to_state;
-short **transpose();
+static void add_lookback_edge __P((int, int, int));
+static void build_relations __P((void));
+static void compute_FOLLOWS __P((void));
+static void compute_lookaheads __P((void));
+static void digraph __P((short **));
+static void initialize_F __P((void));
+static void initialize_LA __P((void));
+static int map_goto __P((int, int));
+static void set_accessing_symbol __P((void));
+static void set_goto_map __P((void));
+static void set_maxrhs __P((void));
+static void set_reduction_table __P((void));
+static void set_shift_table __P((void));
+static void set_state_table __P((void));
+static short **transpose __P((short **, int));
+static void traverse __P((register int));
static int infinity;
static int maxrhs;
@@ -74,6 +92,7 @@ static short *VERTICES;
static int top;
+void
lalr()
{
tokensetsize = WORDSIZE(ntokens);
@@ -93,6 +112,7 @@ lalr()
+static void
set_state_table()
{
register core *sp;
@@ -104,6 +124,7 @@ set_state_table()
+static void
set_accessing_symbol()
{
register core *sp;
@@ -115,6 +136,7 @@ set_accessing_symbol()
+static void
set_shift_table()
{
register shifts *sp;
@@ -126,6 +148,7 @@ set_shift_table()
+static void
set_reduction_table()
{
register reductions *rp;
@@ -137,6 +160,7 @@ set_reduction_table()
+static void
set_maxrhs()
{
register short *itemp;
@@ -165,6 +189,7 @@ set_maxrhs()
+static void
initialize_LA()
{
register int i, j, k;
@@ -202,6 +227,7 @@ initialize_LA()
}
+static void
set_goto_map()
{
register shifts *sp;
@@ -271,7 +297,7 @@ set_goto_map()
/* Map_goto maps a state/symbol pair into its numeric representation. */
-int
+static int
map_goto(state, symbol)
int state;
int symbol;
@@ -300,6 +326,7 @@ int symbol;
+static void
initialize_F()
{
register int i;
@@ -346,7 +373,7 @@ initialize_F()
if (nullable[symbol])
edge[nedges++] = map_goto(stateno, symbol);
}
-
+
if (nedges)
{
reads[i] = rp = NEW2(nedges + 1, short);
@@ -377,6 +404,7 @@ initialize_F()
+static void
build_relations()
{
register int i;
@@ -469,6 +497,7 @@ build_relations()
}
+static void
add_lookback_edge(stateno, ruleno, gotono)
int stateno, ruleno, gotono;
{
@@ -496,7 +525,7 @@ int stateno, ruleno, gotono;
-short **
+static short **
transpose(R, n)
short **R;
int n;
@@ -554,12 +583,14 @@ int n;
+static void
compute_FOLLOWS()
{
digraph(includes);
}
+static void
compute_lookaheads()
{
register int i, n;
@@ -594,6 +625,7 @@ compute_lookaheads()
}
+static void
digraph(relation)
short **relation;
{
@@ -621,6 +653,7 @@ short **relation;
+static void
traverse(i)
register int i;
{
diff --git a/usr.bin/yacc/lr0.c b/usr.bin/yacc/lr0.c
index 43106ea..96d87a9 100644
--- a/usr.bin/yacc/lr0.c
+++ b/usr.bin/yacc/lr0.c
@@ -32,12 +32,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)lr0.c 5.3 (Berkeley) 1/20/91";
+static char const sccsid[] = "@(#)lr0.c 5.3 (Berkeley) 1/20/91";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
extern short *itemset;
@@ -49,8 +52,22 @@ core *first_state;
shifts *first_shift;
reductions *first_reduction;
-int get_state();
-core *new_state();
+static void allocate_itemsets __P((void));
+static void allocate_storage __P((void));
+static void append_states __P((void));
+static void free_storage __P((void));
+static void generate_states __P((void));
+static int get_state __P((int));
+static void initialize_states __P((void));
+static void new_itemsets __P((void));
+static core *new_state __P((int));
+#ifdef DEBUG
+static void print_derives __P((void));
+#endif
+static void save_reductions __P((void));
+static void save_shifts __P((void));
+static void set_derives __P((void));
+static void set_nullable __P((void));
static core **state_set;
static core *this_state;
@@ -69,6 +86,7 @@ static short **kernel_end;
static short *kernel_items;
+static void
allocate_itemsets()
{
register short *itemp;
@@ -111,6 +129,7 @@ allocate_itemsets()
}
+static void
allocate_storage()
{
allocate_itemsets();
@@ -120,6 +139,7 @@ allocate_storage()
}
+static void
append_states()
{
register int i;
@@ -149,6 +169,7 @@ append_states()
}
+static void
free_storage()
{
FREE(shift_symbol);
@@ -162,6 +183,7 @@ free_storage()
+static void
generate_states()
{
allocate_storage();
@@ -189,7 +211,7 @@ generate_states()
-int
+static int
get_state(symbol)
int symbol;
{
@@ -254,6 +276,7 @@ int symbol;
+static void
initialize_states()
{
register int i;
@@ -281,6 +304,7 @@ initialize_states()
}
+static void
new_itemsets()
{
register int i;
@@ -317,7 +341,7 @@ new_itemsets()
-core *
+static core *
new_state(symbol)
int symbol;
{
@@ -356,6 +380,7 @@ int symbol;
}
+#if 0
/* show_cores is used for debugging */
show_cores()
@@ -430,8 +455,10 @@ show_shifts()
printf("\t%d\n", p->shift[i]);
}
}
+#endif
+static void
save_shifts()
{
register shifts *p;
@@ -466,6 +493,7 @@ save_shifts()
+static void
save_reductions()
{
register short *isp;
@@ -515,6 +543,7 @@ save_reductions()
}
+static void
set_derives()
{
register int i, k;
@@ -545,13 +574,16 @@ set_derives()
#endif
}
+#if 0
free_derives()
{
FREE(derives[start_symbol]);
FREE(derives);
}
+#endif
#ifdef DEBUG
+static void
print_derives()
{
register int i;
@@ -574,6 +606,7 @@ print_derives()
#endif
+static void
set_nullable()
{
register int i, j;
@@ -623,12 +656,15 @@ set_nullable()
}
+#if 0
free_nullable()
{
FREE(nullable);
}
+#endif
+void
lr0()
{
set_derives();
diff --git a/usr.bin/yacc/main.c b/usr.bin/yacc/main.c
index 79b332a..fb8fa71 100644
--- a/usr.bin/yacc/main.c
+++ b/usr.bin/yacc/main.c
@@ -32,19 +32,24 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: main.c,v 1.5 1997/01/12 21:29:47 steve Exp $
*/
#ifndef lint
-char copyright[] =
+static char const copyright[] =
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 5.5 (Berkeley) 5/24/93";
+static char const sccsid[] = "@(#)main.c 5.5 (Berkeley) 5/24/93";
#endif /* not lint */
#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "defs.h"
char dflag;
@@ -103,10 +108,15 @@ char *rassoc;
short **derives;
char *nullable;
-extern char *mktemp();
-extern char *getenv();
+static void create_file_names __P((void));
+static void getargs __P((int, char **));
+static void onintr __P((int));
+static void open_files __P((void));
+static void set_signals __P((void));
+static void usage __P((void));
+void
done(k)
int k;
{
@@ -117,7 +127,7 @@ int k;
}
-void
+static void
onintr(signo)
int signo;
{
@@ -125,6 +135,7 @@ onintr(signo)
}
+static void
set_signals()
{
#ifdef SIGINT
@@ -142,13 +153,15 @@ set_signals()
}
+static void
usage()
{
- fprintf(stderr, "usage: %s [-dlrtv] [-b file_prefix] [-p symbol_prefix] filename\n", myname);
+ fprintf(stderr, "usage: %s [-dlrtv] [-b file_prefix] [-o output_file_name] [-p symbol_prefix] filename\n", myname);
exit(1);
}
+static void
getargs(argc, argv)
int argc;
char *argv[];
@@ -189,6 +202,15 @@ char *argv[];
lflag = 1;
break;
+ case 'o':
+ if (*++s)
+ output_file_name = s;
+ else if (++i < argc)
+ output_file_name = argv[i];
+ else
+ usage();
+ continue;
+
case 'p':
if (*++s)
symbol_prefix = s;
@@ -270,6 +292,7 @@ unsigned n;
}
+static void
create_file_names()
{
int i, len;
@@ -314,13 +337,20 @@ create_file_names()
mktemp(text_file_name);
mktemp(union_file_name);
- len = strlen(file_prefix);
-
- output_file_name = MALLOC(len + 7);
- if (output_file_name == 0)
- no_space();
- strcpy(output_file_name, file_prefix);
- strcpy(output_file_name + len, OUTPUT_SUFFIX);
+ if (output_file_name != 0)
+ {
+ file_prefix = output_file_name;
+ len = strlen(file_prefix);
+ }
+ else
+ {
+ len = strlen(file_prefix);
+ output_file_name = MALLOC(len + 7);
+ if (output_file_name == 0)
+ no_space();
+ strcpy(output_file_name, file_prefix);
+ strcpy(output_file_name + len, OUTPUT_SUFFIX);
+ }
if (rflag)
{
@@ -328,7 +358,21 @@ create_file_names()
if (code_file_name == 0)
no_space();
strcpy(code_file_name, file_prefix);
- strcpy(code_file_name + len, CODE_SUFFIX);
+ if (file_prefix == output_file_name)
+ {
+ /*
+ * XXX ".tab.c" here is OUTPUT_SUFFIX, but since its length is
+ * in various magic numbers, don't bother using the macro.
+ */
+ if (len >= 6 && strcmp(code_file_name + len - 6, ".tab.c") == 0)
+ strcpy(code_file_name + len - 6, CODE_SUFFIX);
+ else if (len >= 2 && strcmp(code_file_name + len - 2, ".c") == 0)
+ strcpy(code_file_name + len - 2, CODE_SUFFIX);
+ else
+ strcpy(code_file_name + len, CODE_SUFFIX);
+ }
+ else
+ strcpy(code_file_name + len, CODE_SUFFIX);
}
else
code_file_name = output_file_name;
@@ -339,7 +383,16 @@ create_file_names()
if (defines_file_name == 0)
no_space();
strcpy(defines_file_name, file_prefix);
- strcpy(defines_file_name + len, DEFINES_SUFFIX);
+ if (file_prefix == output_file_name)
+ {
+#define BISON_DEFINES_SUFFIX ".h"
+ if (len >= 2 && strcmp(defines_file_name + len - 2, ".c") == 0)
+ strcpy(defines_file_name + len - 2, BISON_DEFINES_SUFFIX);
+ else
+ strcpy(defines_file_name + len, BISON_DEFINES_SUFFIX);
+ }
+ else
+ strcpy(defines_file_name + len, DEFINES_SUFFIX);
}
if (vflag)
@@ -348,11 +401,22 @@ create_file_names()
if (verbose_file_name == 0)
no_space();
strcpy(verbose_file_name, file_prefix);
- strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
+ if (file_prefix == output_file_name)
+ {
+ if (len >= 6 && strcmp(verbose_file_name + len - 6, ".tab.c") == 0)
+ strcpy(verbose_file_name + len - 6, VERBOSE_SUFFIX);
+ else if (len >= 2 && strcmp(verbose_file_name + len - 2, ".c") == 0)
+ strcpy(verbose_file_name + len - 2, VERBOSE_SUFFIX);
+ else
+ strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
+ }
+ else
+ strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
}
}
+static void
open_files()
{
create_file_names();
@@ -420,4 +484,5 @@ char *argv[];
output();
done(0);
/*NOTREACHED*/
+ return (0);
}
diff --git a/usr.bin/yacc/mkpar.c b/usr.bin/yacc/mkpar.c
index 42ead14..bb59d9d 100644
--- a/usr.bin/yacc/mkpar.c
+++ b/usr.bin/yacc/mkpar.c
@@ -32,12 +32,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)mkpar.c 5.3 (Berkeley) 1/20/91";
+static char const sccsid[] = "@(#)mkpar.c 5.3 (Berkeley) 1/20/91";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
action **parser;
@@ -53,12 +56,20 @@ short final_state;
static int SRcount;
static int RRcount;
-extern action *parse_actions();
-extern action *get_shifts();
-extern action *add_reductions();
-extern action *add_reduce();
+static action *add_reduce __P((action *, int, int));
+static action *add_reductions __P((int, action *));
+static void defreds __P((void));
+static void find_final_state __P((void));
+static void free_action_row __P((action *));
+static action *get_shifts __P((int));
+static action *parse_actions __P((int));
+static void remove_conflicts __P((void));
+static int sole_reduction __P((int));
+static void total_conflicts __P((void));
+static void unused_rules __P((void));
+void
make_parser()
{
register int i;
@@ -75,7 +86,7 @@ make_parser()
}
-action *
+static action *
parse_actions(stateno)
register int stateno;
{
@@ -87,7 +98,7 @@ register int stateno;
}
-action *
+static action *
get_shifts(stateno)
int stateno;
{
@@ -122,7 +133,7 @@ int stateno;
return (actions);
}
-action *
+static action *
add_reductions(stateno, actions)
int stateno;
register action *actions;
@@ -148,7 +159,7 @@ register action *actions;
}
-action *
+static action *
add_reduce(actions, ruleno, symbol)
register action *actions;
register int ruleno, symbol;
@@ -189,6 +200,7 @@ register int ruleno, symbol;
}
+static void
find_final_state()
{
register int goal, i;
@@ -206,6 +218,7 @@ find_final_state()
}
+static void
unused_rules()
{
register int i;
@@ -238,11 +251,12 @@ unused_rules()
}
+static void
remove_conflicts()
{
register int i;
register int symbol;
- register action *p, *pref;
+ register action *p, *pref = NULL;
SRtotal = 0;
RRtotal = 0;
@@ -313,6 +327,7 @@ remove_conflicts()
}
+static void
total_conflicts()
{
fprintf(stderr, "%s: ", myname);
@@ -333,7 +348,7 @@ total_conflicts()
}
-int
+static int
sole_reduction(stateno)
int stateno;
{
@@ -341,7 +356,7 @@ int stateno;
register action *p;
count = 0;
- ruleno = 0;
+ ruleno = 0;
for (p = parser[stateno]; p; p = p->next)
{
if (p->action_code == SHIFT && p->suppressed == 0)
@@ -362,6 +377,7 @@ int stateno;
}
+static void
defreds()
{
register int i;
@@ -370,7 +386,8 @@ defreds()
for (i = 0; i < nstates; i++)
defred[i] = sole_reduction(i);
}
-
+
+static void
free_action_row(p)
register action *p;
{
@@ -384,6 +401,7 @@ register action *p;
}
}
+void
free_parser()
{
register int i;
diff --git a/usr.bin/yacc/output.c b/usr.bin/yacc/output.c
index f8fd1c5..cc893bb 100644
--- a/usr.bin/yacc/output.c
+++ b/usr.bin/yacc/output.c
@@ -32,14 +32,43 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: output.c,v 1.8 1997/04/28 03:36:12 steve Exp $
*/
#ifndef lint
-static char sccsid[] = "@(#)output.c 5.7 (Berkeley) 5/24/93";
+static char const sccsid[] = "@(#)output.c 5.7 (Berkeley) 5/24/93";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
+static int default_goto __P((int));
+static void free_itemsets __P((void));
+static void free_reductions __P((void));
+static void free_shifts __P((void));
+static void goto_actions __P((void));
+static int is_C_identifier __P((char *));
+static int matching_vector __P((int));
+static void output_actions __P((void));
+static void output_base __P((void));
+static void output_check __P((void));
+static void output_debug __P((void));
+static void output_defines __P((void));
+static void output_prefix __P((void));
+static void output_rule_data __P((void));
+static void output_semantic_actions __P((void));
+static void output_stored_text __P((void));
+static void output_stype __P((void));
+static void output_table __P((void));
+static void output_trailing_text __P((void));
+static void output_yydefred __P((void));
+static void pack_table __P((void));
+static int pack_vector __P((int));
+static void save_column __P((int, int));
+static void sort_actions __P((void));
+static void token_actions __P((void));
+
static int nvectors;
static int nentries;
static short **froms;
@@ -57,6 +86,7 @@ static int lowzero;
static int high;
+void
output()
{
free_itemsets();
@@ -80,6 +110,7 @@ output()
}
+static void
output_prefix()
{
if (symbol_prefix == NULL)
@@ -140,13 +171,14 @@ output_prefix()
}
+static void
output_rule_data()
{
register int i;
register int j;
-
- fprintf(output_file, "short %slhs[] = {%42d,", symbol_prefix,
+
+ fprintf(output_file, "const short %slhs[] = {%42d,", symbol_prefix,
symbol_value[start_symbol]);
j = 10;
@@ -166,7 +198,7 @@ output_rule_data()
if (!rflag) outline += 2;
fprintf(output_file, "\n};\n");
- fprintf(output_file, "short %slen[] = {%42d,", symbol_prefix, 2);
+ fprintf(output_file, "const short %slen[] = {%42d,", symbol_prefix, 2);
j = 10;
for (i = 3; i < nrules; i++)
@@ -187,11 +219,12 @@ output_rule_data()
}
+static void
output_yydefred()
{
register int i, j;
- fprintf(output_file, "short %sdefred[] = {%39d,", symbol_prefix,
+ fprintf(output_file, "const short %sdefred[] = {%39d,", symbol_prefix,
(defred[0] ? defred[0] - 2 : 0));
j = 10;
@@ -214,6 +247,7 @@ output_yydefred()
}
+static void
output_actions()
{
nvectors = 2*nstates + nvars;
@@ -242,6 +276,7 @@ output_actions()
}
+static void
token_actions()
{
register int i, j;
@@ -326,6 +361,7 @@ token_actions()
FREE(actionrow);
}
+static void
goto_actions()
{
register int i, j, k;
@@ -333,7 +369,7 @@ goto_actions()
state_count = NEW2(nstates, short);
k = default_goto(start_symbol + 1);
- fprintf(output_file, "short %sdgoto[] = {%40d,", symbol_prefix, k);
+ fprintf(output_file, "const short %sdgoto[] = {%40d,", symbol_prefix, k);
save_column(start_symbol + 1, k);
j = 10;
@@ -358,7 +394,7 @@ goto_actions()
FREE(state_count);
}
-int
+static int
default_goto(symbol)
int symbol;
{
@@ -395,6 +431,7 @@ int symbol;
+static void
save_column(symbol, default_state)
int symbol;
int default_state;
@@ -437,6 +474,7 @@ int default_state;
width[symno] = sp1[-1] - sp[0] + 1;
}
+static void
sort_actions()
{
register int i;
@@ -472,6 +510,7 @@ sort_actions()
}
+static void
pack_table()
{
register int i;
@@ -534,7 +573,7 @@ pack_table()
/* faster. Also, it depends on the vectors being in a specific */
/* order. */
-int
+static int
matching_vector(vector)
int vector;
{
@@ -575,7 +614,7 @@ int vector;
-int
+static int
pack_vector(vector)
int vector;
{
@@ -653,11 +692,13 @@ int vector;
+static void
output_base()
{
register int i, j;
- fprintf(output_file, "short %ssindex[] = {%39d,", symbol_prefix, base[0]);
+ fprintf(output_file, "const short %ssindex[] = {%39d,", symbol_prefix,
+ base[0]);
j = 10;
for (i = 1; i < nstates; i++)
@@ -675,7 +716,7 @@ output_base()
}
if (!rflag) outline += 2;
- fprintf(output_file, "\n};\nshort %srindex[] = {%39d,", symbol_prefix,
+ fprintf(output_file, "\n};\nconst short %srindex[] = {%39d,", symbol_prefix,
base[nstates]);
j = 10;
@@ -694,7 +735,7 @@ output_base()
}
if (!rflag) outline += 2;
- fprintf(output_file, "\n};\nshort %sgindex[] = {%39d,", symbol_prefix,
+ fprintf(output_file, "\n};\nconst short %sgindex[] = {%39d,", symbol_prefix,
base[2*nstates]);
j = 10;
@@ -719,6 +760,7 @@ output_base()
+static void
output_table()
{
register int i;
@@ -726,7 +768,7 @@ output_table()
++outline;
fprintf(code_file, "#define YYTABLESIZE %d\n", high);
- fprintf(output_file, "short %stable[] = {%40d,", symbol_prefix,
+ fprintf(output_file, "const short %stable[] = {%40d,", symbol_prefix,
table[0]);
j = 10;
@@ -751,12 +793,13 @@ output_table()
+static void
output_check()
{
register int i;
register int j;
- fprintf(output_file, "short %scheck[] = {%40d,", symbol_prefix,
+ fprintf(output_file, "const short %scheck[] = {%40d,", symbol_prefix,
check[0]);
j = 10;
@@ -780,7 +823,7 @@ output_check()
}
-int
+static int
is_C_identifier(name)
char *name;
{
@@ -804,7 +847,7 @@ char *name;
if (!isalpha(c) && c != '_' && c != '$')
return (0);
- while (c = *++s)
+ while ((c = *++s))
{
if (!isalnum(c) && c != '_' && c != '$')
return (0);
@@ -813,6 +856,7 @@ char *name;
}
+static void
output_defines()
{
register int c, i;
@@ -841,7 +885,7 @@ output_defines()
putc(c, code_file);
if (dflag) putc(c, defines_file);
}
- while (c = *++s);
+ while ((c = *++s));
}
++outline;
fprintf(code_file, " %d\n", symbol_value[i]);
@@ -865,6 +909,7 @@ output_defines()
}
+static void
output_stored_text()
{
register int c;
@@ -892,6 +937,7 @@ output_stored_text()
}
+static void
output_debug()
{
register int i, j, k, max;
@@ -900,8 +946,8 @@ output_debug()
++outline;
fprintf(code_file, "#define YYFINAL %d\n", final_state);
outline += 3;
- fprintf(code_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n",
- tflag);
+ fprintf(code_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n", tflag);
+ fprintf(code_file, "#elif YYDEBUG\n#include <stdio.h>\n#endif\n");
if (rflag)
fprintf(output_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n",
tflag);
@@ -925,11 +971,12 @@ output_debug()
symnam[0] = "end-of-file";
if (!rflag) ++outline;
- fprintf(output_file, "#if YYDEBUG\nchar *%sname[] = {", symbol_prefix);
+ fprintf(output_file, "#if YYDEBUG\n");
+ fprintf(output_file, "const char * const %sname[] = {", symbol_prefix);
j = 80;
for (i = 0; i <= max; ++i)
{
- if (s = symnam[i])
+ if ((s = symnam[i]))
{
if (s[0] == '"')
{
@@ -1051,7 +1098,7 @@ output_debug()
FREE(symnam);
if (!rflag) ++outline;
- fprintf(output_file, "char *%srule[] = {\n", symbol_prefix);
+ fprintf(output_file, "const char * const %srule[] = {\n", symbol_prefix);
for (i = 2; i < nrules; ++i)
{
fprintf(output_file, "\"%s :", symbol_name[rlhs[i]]);
@@ -1106,6 +1153,7 @@ output_debug()
}
+static void
output_stype()
{
if (!unionized && ntags == 0)
@@ -1116,6 +1164,7 @@ output_stype()
}
+static void
output_trailing_text()
{
register int c, last;
@@ -1173,6 +1222,7 @@ output_trailing_text()
}
+static void
output_semantic_actions()
{
register int c, last;
@@ -1210,6 +1260,7 @@ output_semantic_actions()
}
+static void
free_itemsets()
{
register core *cp, *next;
@@ -1223,6 +1274,7 @@ free_itemsets()
}
+static void
free_shifts()
{
register shifts *sp, *next;
@@ -1237,6 +1289,7 @@ free_shifts()
+static void
free_reductions()
{
register reductions *rp, *next;
diff --git a/usr.bin/yacc/reader.c b/usr.bin/yacc/reader.c
index 3b724d3..4566570 100644
--- a/usr.bin/yacc/reader.c
+++ b/usr.bin/yacc/reader.c
@@ -32,12 +32,16 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)reader.c 5.7 (Berkeley) 1/20/91";
+static char const sccsid[] = "@(#)reader.c 5.7 (Berkeley) 1/20/91";
#endif /* not lint */
+#include <stdlib.h>
+#include <string.h>
#include "defs.h"
/* The line size must be a positive integer. One hundred was chosen */
@@ -73,7 +77,44 @@ char *name_pool;
char line_format[] = "#line %d \"%s\"\n";
-
+static void add_symbol __P((void));
+static void advance_to_start __P((void));
+static void cachec __P((int));
+static void check_symbols __P((void));
+static void copy_action __P((void));
+static void copy_ident __P((void));
+static void copy_text __P((void));
+static void copy_union __P((void));
+static void declare_start __P((void));
+static void declare_tokens __P((int));
+static void declare_types __P((void));
+static char *dup_line __P((void));
+static void end_rule __P((void));
+static void expand_items __P((void));
+static void expand_rules __P((void));
+static void free_tags __P((void));
+static void get_line __P((void));
+static bucket *get_literal __P((void));
+static bucket *get_name __P((void));
+static int get_number __P((void));
+static char *get_tag __P((void));
+static int hexval __P((int));
+static void initialize_grammar __P((void));
+static void insert_empty_rule __P((void));
+static int is_reserved __P((char *));
+static int keyword __P((void));
+static int mark_symbol __P((void));
+static int nextc __P((void));
+static void pack_grammar __P((void));
+static void pack_names __P((void));
+static void pack_symbols __P((void));
+static void print_grammar __P((void));
+static void read_declarations __P((void));
+static void read_grammar __P((void));
+static void skip_comment __P((void));
+static void start_rule __P((bucket *, int));
+
+static void
cachec(c)
int c;
{
@@ -89,6 +130,7 @@ int c;
}
+static void
get_line()
{
register FILE *f = input_file;
@@ -135,7 +177,7 @@ get_line()
}
-char *
+static char *
dup_line()
{
register char *p, *s, *t;
@@ -153,6 +195,7 @@ dup_line()
}
+static void
skip_comment()
{
register char *s;
@@ -183,7 +226,7 @@ skip_comment()
}
-int
+static int
nextc()
{
register char *s;
@@ -245,7 +288,7 @@ nextc()
}
-int
+static int
keyword()
{
register int c;
@@ -305,9 +348,11 @@ keyword()
}
syntax_error(lineno, line, t_cptr);
/*NOTREACHED*/
+ return (0);
}
+static void
copy_ident()
{
register int c;
@@ -337,6 +382,7 @@ copy_ident()
}
+static void
copy_text()
{
register int c;
@@ -468,6 +514,7 @@ loop:
}
+static void
copy_union()
{
register int c;
@@ -608,7 +655,7 @@ loop:
}
-int
+static int
hexval(c)
int c;
{
@@ -622,7 +669,7 @@ int c;
}
-bucket *
+static bucket *
get_literal()
{
register int c, quote;
@@ -704,7 +751,7 @@ get_literal()
n = cinc;
s = MALLOC(n);
if (s == 0) no_space();
-
+
for (i = 0; i < n; ++i)
s[i] = cache[i];
@@ -761,7 +808,7 @@ get_literal()
}
-int
+static int
is_reserved(name)
char *name;
{
@@ -783,7 +830,7 @@ char *name;
}
-bucket *
+static bucket *
get_name()
{
register int c;
@@ -799,7 +846,7 @@ get_name()
}
-int
+static int
get_number()
{
register int c;
@@ -813,7 +860,7 @@ get_number()
}
-char *
+static char *
get_tag()
{
register int c;
@@ -864,6 +911,7 @@ get_tag()
}
+static void
declare_tokens(assoc)
int assoc;
{
@@ -926,6 +974,7 @@ int assoc;
}
+static void
declare_types()
{
register int c;
@@ -954,6 +1003,7 @@ declare_types()
}
+static void
declare_start()
{
register int c;
@@ -972,6 +1022,7 @@ declare_start()
}
+static void
read_declarations()
{
register int c, k;
@@ -1021,6 +1072,7 @@ read_declarations()
}
+static void
initialize_grammar()
{
nitems = 4;
@@ -1052,6 +1104,7 @@ initialize_grammar()
}
+static void
expand_items()
{
maxitems += 300;
@@ -1060,6 +1113,7 @@ expand_items()
}
+static void
expand_rules()
{
maxrules += 100;
@@ -1072,6 +1126,7 @@ expand_rules()
}
+static void
advance_to_start()
{
register int c;
@@ -1122,6 +1177,7 @@ advance_to_start()
}
+static void
start_rule(bp, s_lineno)
register bucket *bp;
int s_lineno;
@@ -1137,6 +1193,7 @@ int s_lineno;
}
+static void
end_rule()
{
register int i;
@@ -1156,6 +1213,7 @@ end_rule()
}
+static void
insert_empty_rule()
{
register bucket *bp, **bpp;
@@ -1172,7 +1230,7 @@ insert_empty_rule()
expand_items();
bpp = pitem + nitems - 1;
*bpp-- = bp;
- while (bpp[0] = bpp[-1]) --bpp;
+ while ((bpp[0] = bpp[-1])) --bpp;
if (++nrules >= maxrules)
expand_rules();
@@ -1185,6 +1243,7 @@ insert_empty_rule()
}
+static void
add_symbol()
{
register int c;
@@ -1216,6 +1275,7 @@ add_symbol()
}
+static void
copy_action()
{
register int c;
@@ -1439,11 +1499,11 @@ loop:
}
-int
+static int
mark_symbol()
{
register int c;
- register bucket *bp;
+ register bucket *bp = NULL;
c = cptr[1];
if (c == '%' || c == '\\')
@@ -1483,6 +1543,7 @@ mark_symbol()
}
+static void
read_grammar()
{
register int c;
@@ -1516,6 +1577,7 @@ read_grammar()
}
+static void
free_tags()
{
register int i;
@@ -1531,6 +1593,7 @@ free_tags()
}
+static void
pack_names()
{
register bucket *bp;
@@ -1549,13 +1612,14 @@ pack_names()
{
p = t;
s = bp->name;
- while (*t++ = *s++) continue;
+ while ((*t++ = *s++)) continue;
FREE(bp->name);
bp->name = p;
}
}
+static void
check_symbols()
{
register bucket *bp;
@@ -1574,6 +1638,7 @@ check_symbols()
}
+static void
pack_symbols()
{
register bucket *bp;
@@ -1698,6 +1763,7 @@ pack_symbols()
}
+static void
pack_grammar()
{
register int i, j;
@@ -1757,10 +1823,11 @@ pack_grammar()
}
+static void
print_grammar()
{
register int i, j, k;
- int spacing;
+ int spacing = 0;
register FILE *f = verbose_file;
if (!vflag) return;
@@ -1793,6 +1860,7 @@ print_grammar()
}
+void
reader()
{
write_section(banner);
diff --git a/usr.bin/yacc/skeleton.c b/usr.bin/yacc/skeleton.c
index 7de5599..c4f4a5a 100644
--- a/usr.bin/yacc/skeleton.c
+++ b/usr.bin/yacc/skeleton.c
@@ -32,10 +32,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id: skeleton.c,v 1.13 1997/04/28 03:36:13 steve Exp $
*/
#ifndef lint
-static char sccsid[] = "@(#)skeleton.c 5.8 (Berkeley) 4/29/95";
+static char const sccsid[] = "@(#)skeleton.c 5.8 (Berkeley) 4/29/95";
#endif /* not lint */
#include "defs.h"
@@ -55,30 +57,45 @@ static char sccsid[] = "@(#)skeleton.c 5.8 (Berkeley) 4/29/95";
char *banner[] =
{
"#ifndef lint",
- "static char yysccsid[] = \"@(#)yaccpar 1.9 (Berkeley) 02/21/93\";",
+ "static char const yysccsid[] = \"@(#)yaccpar 1.9 (Berkeley) 02/21/93\";",
"#endif",
"#include <stdlib.h>",
"#define YYBYACC 1",
"#define YYMAJOR 1",
"#define YYMINOR 9",
- "#define yyclearin (yychar=(-1))",
+ "#define YYLEX yylex()",
+ "#define YYEMPTY -1",
+ "#define yyclearin (yychar=(YYEMPTY))",
"#define yyerrok (yyerrflag=0)",
"#define YYRECOVERING (yyerrflag!=0)",
+ "#if defined(c_plusplus) || defined(__cplusplus)",
+ /* Declaring standard functions is too painful for C++. */
+ "#include <stdlib.h>",
+ "#else",
+ /* Declare standard functions to avoid depending on <stdlib.h>. */
+ "extern char *getenv();",
+ "extern void *realloc();",
+ "#endif",
+#if 0
+ "extern int yylex();",
+ "extern int yyparse();",
+#endif
+ "static int yygrowstack();",
0
};
char *tables[] =
{
- "extern short yylhs[];",
- "extern short yylen[];",
- "extern short yydefred[];",
- "extern short yydgoto[];",
- "extern short yysindex[];",
- "extern short yyrindex[];",
- "extern short yygindex[];",
- "extern short yytable[];",
- "extern short yycheck[];",
+ "extern const short yylhs[];",
+ "extern const short yylen[];",
+ "extern const short yydefred[];",
+ "extern const short yydgoto[];",
+ "extern const short yysindex[];",
+ "extern const short yyrindex[];",
+ "extern const short yygindex[];",
+ "extern const short yytable[];",
+ "extern const short yycheck[];",
"#if YYDEBUG",
"extern char *yyname[];",
"extern char *yyrule[];",
@@ -133,11 +150,11 @@ char *body[] =
" else if ((newsize *= 2) > YYMAXDEPTH)",
" newsize = YYMAXDEPTH;",
" i = yyssp - yyss;",
- " if ((newss = realloc(yyss, newsize * sizeof *newss)) == NULL)",
+ " if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL)",
" return -1;",
" yyss = newss;",
" yyssp = newss + i;",
- " if ((newvs = realloc(yyvs, newsize * sizeof *newvs)) == NULL)",
+ " if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL)",
" return -1;",
" yyvs = newvs;",
" yyvsp = newvs + i;",
@@ -150,15 +167,15 @@ char *body[] =
"#define YYREJECT goto yyabort",
"#define YYACCEPT goto yyaccept",
"#define YYERROR goto yyerrlab",
+ "",
"int",
"yyparse()",
"{",
" register int yym, yyn, yystate;",
"#if YYDEBUG",
- " register char *yys;",
- " extern char *getenv();",
+ " register const char *yys;",
"",
- " if (yys = getenv(\"YYDEBUG\"))",
+ " if ((yys = getenv(\"YYDEBUG\")))",
" {",
" yyn = *yys;",
" if (yyn >= '0' && yyn <= '9')",
@@ -176,7 +193,7 @@ char *body[] =
" *yyssp = yystate = 0;",
"",
"yyloop:",
- " if (yyn = yydefred[yystate]) goto yyreduce;",
+ " if ((yyn = yydefred[yystate])) goto yyreduce;",
" if (yychar < 0)",
" {",
" if ((yychar = yylex()) < 0) yychar = 0;",
@@ -216,12 +233,12 @@ char *body[] =
" goto yyreduce;",
" }",
" if (yyerrflag) goto yyinrecovery;",
- "#ifdef lint",
+ "#if defined(lint) || defined(__GNUC__)",
" goto yynewerror;",
"#endif",
"yynewerror:",
" yyerror(\"syntax error\");",
- "#ifdef lint",
+ "#if defined(lint) || defined(__GNUC__)",
" goto yyerrlab;",
"#endif",
"yyerrlab:",
@@ -355,6 +372,7 @@ char *trailer[] =
};
+void
write_section(section)
char *section[];
{
@@ -364,10 +382,10 @@ char *section[];
register FILE *f;
f = code_file;
- for (i = 0; s = section[i]; ++i)
+ for (i = 0; (s = section[i]); ++i)
{
++outline;
- while (c = *s)
+ while ((c = *s))
{
putc(c, f);
++s;
diff --git a/usr.bin/yacc/symtab.c b/usr.bin/yacc/symtab.c
index 0c5f55c..2f2ee2e 100644
--- a/usr.bin/yacc/symtab.c
+++ b/usr.bin/yacc/symtab.c
@@ -32,12 +32,16 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)symtab.c 5.3 (Berkeley) 6/1/90";
+static char const sccsid[] = "@(#)symtab.c 5.3 (Berkeley) 6/1/90";
#endif /* not lint */
+#include <stdlib.h>
+#include <string.h>
#include "defs.h"
/* TABLE_SIZE is the number of entries in the symbol table. */
@@ -45,13 +49,14 @@ static char sccsid[] = "@(#)symtab.c 5.3 (Berkeley) 6/1/90";
#define TABLE_SIZE 1024
+static int hash __P((char *));
bucket **symbol_table;
bucket *first_symbol;
bucket *last_symbol;
-int
+static int
hash(name)
char *name;
{
@@ -61,7 +66,7 @@ char *name;
assert(name && *name);
s = name;
k = *s;
- while (c = *++s)
+ while ((c = *++s))
k = (31*k + c) & (TABLE_SIZE - 1);
return (k);
@@ -119,6 +124,7 @@ char *name;
}
+void
create_symbol_table()
{
register int i;
@@ -139,6 +145,7 @@ create_symbol_table()
}
+void
free_symbol_table()
{
FREE(symbol_table);
@@ -146,6 +153,7 @@ free_symbol_table()
}
+void
free_symbols()
{
register bucket *p, *q;
diff --git a/usr.bin/yacc/test/ftp.tab.c b/usr.bin/yacc/test/ftp.tab.c
index c9794ed..5431bbf 100644
--- a/usr.bin/yacc/test/ftp.tab.c
+++ b/usr.bin/yacc/test/ftp.tab.c
@@ -1196,7 +1196,7 @@ break;
case 17:
#line 222 "ftp.y"
{
- if (yyvsp[-3] && yyvsp[-1] != NULL)
+ if (yyvsp[-3] && yyvsp[-1] != NULL)
send_file_list((char *) yyvsp[-1]);
if (yyvsp[-1] != NULL)
free((char *) yyvsp[-1]);
diff --git a/usr.bin/yacc/verbose.c b/usr.bin/yacc/verbose.c
index 33ae265..c2cfee5 100644
--- a/usr.bin/yacc/verbose.c
+++ b/usr.bin/yacc/verbose.c
@@ -32,16 +32,31 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)verbose.c 5.3 (Berkeley) 1/20/91";
+static char const sccsid[] = "@(#)verbose.c 5.3 (Berkeley) 1/20/91";
#endif /* not lint */
+#include <stdlib.h>
#include "defs.h"
+static void log_unused __P((void));
+static void log_conflicts __P((void));
+static void print_actions __P((int));
+static void print_conflicts __P((int));
+static void print_core __P((int));
+static void print_gotos __P((int));
+static void print_nulls __P((int));
+static void print_reductions __P((register action *, register int));
+static void print_shifts __P((register action *));
+static void print_state __P((int));
+
static short *null_rules;
+void
verbose()
{
register int i;
@@ -66,6 +81,7 @@ verbose()
}
+static void
log_unused()
{
register int i;
@@ -85,6 +101,7 @@ log_unused()
}
+static void
log_conflicts()
{
register int i;
@@ -113,6 +130,7 @@ log_conflicts()
}
+static void
print_state(state)
int state;
{
@@ -127,10 +145,11 @@ int state;
}
+static void
print_conflicts(state)
int state;
{
- register int symbol, act, number;
+ register int symbol, act = 0, number = 0;
register action *p;
symbol = -1;
@@ -175,6 +194,7 @@ int state;
}
+static void
print_core(state)
int state;
{
@@ -211,6 +231,7 @@ int state;
}
+static void
print_nulls(state)
int state;
{
@@ -255,6 +276,7 @@ int state;
}
+static void
print_actions(stateno)
int stateno;
{
@@ -282,6 +304,7 @@ int stateno;
}
+static void
print_shifts(p)
register action *p;
{
@@ -307,6 +330,7 @@ register action *p;
}
+static void
print_reductions(p, defred)
register action *p;
register int defred;
@@ -345,6 +369,7 @@ register int defred;
}
+static void
print_gotos(stateno)
int stateno;
{
diff --git a/usr.bin/yacc/warshall.c b/usr.bin/yacc/warshall.c
index 4672244..680363c 100644
--- a/usr.bin/yacc/warshall.c
+++ b/usr.bin/yacc/warshall.c
@@ -32,14 +32,19 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $Id$
*/
#ifndef lint
-static char sccsid[] = "@(#)warshall.c 5.4 (Berkeley) 5/24/93";
+static char const sccsid[] = "@(#)warshall.c 5.4 (Berkeley) 5/24/93";
#endif /* not lint */
#include "defs.h"
+static void transitive_closure __P((unsigned *, int));
+
+static void
transitive_closure(R, n)
unsigned *R;
int n;
@@ -92,6 +97,7 @@ int n;
}
}
+void
reflexive_transitive_closure(R, n)
unsigned *R;
int n;
diff --git a/usr.bin/yacc/yacc.1 b/usr.bin/yacc/yacc.1
index 787dc00..596d154 100644
--- a/usr.bin/yacc/yacc.1
+++ b/usr.bin/yacc/yacc.1
@@ -33,6 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)yacc.1 5.8 (Berkeley) 5/24/93
+.\" $Id: yacc.1,v 1.6 1997/02/22 19:58:04 peter Exp $
.\"
.TH YACC 1 "May 24, 1993"
.UC 6
@@ -41,6 +42,8 @@ yacc \- an LALR(1) parser generator
.SH SYNOPSIS
.B yacc [ -dlrtv ] [ -b
.I file_prefix
+.B ] [ -o
+.I output_filename
.B ] [ -p
.I symbol_prefix
.B ]
@@ -86,6 +89,16 @@ If the \fB-l\fR option is specified,
will not insert the #line directives.
Any #line directives specified by the user will be retained.
.TP
+\fB-o \fIoutput_filename\fR
+The
+.B -o
+option causes
+.I yacc
+to write the generated code to
+.IR output_filename
+instead of the default file,
+.IR y.tab.c .
+.TP
\fB-p \fIsymbol_prefix\fR
The
.B -p
diff --git a/usr.bin/yacc/yyfix.1 b/usr.bin/yacc/yyfix.1
index 7af0a9e..7aad08e 100644
--- a/usr.bin/yacc/yyfix.1
+++ b/usr.bin/yacc/yyfix.1
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)yyfix.1 5.4 (Berkeley) 3/23/93
+.\" $Id$
.\"
.Dd March 23, 1993
.Dt YYFIX 1
@@ -38,12 +39,13 @@
.Nm yyfix
.Nd extract tables from y.tab.c
.Sh SYNOPSIS
-.Nm yyfix
+.Nm
.Ar file
.Op Ar tables
.Sh DESCRIPTION
-Programs have historically used a script (often named ``:yyfix'') to
-extract tables from the
+Programs have historically used a script (often named
+.Dq :yyfix )
+to extract tables from the
.Xr yacc 1
generated file
.Pa y.tab.c .
@@ -52,17 +54,17 @@ As the names of the tables generated by the current version of
are different from those of historical versions of
.Xr yacc ,
the shell script
-.Nm yyfix
+.Nm
is provided to simplify the transition.
.Pp
The first (and required) argument to
-.Nm yyfix
+.Nm
is the name of the file where the extracted tables should be stored.
.Pp
If further command line arguments are specified, they are taken as
the list of tables to be extracted.
Otherwise,
-.Nm yyfix
+.Nm
attempts to determine if the
.Pa y.tab.c
file is from an old or new
@@ -108,5 +110,5 @@ File from which tables are extracted.
.Sh HISTORY
The
.Nm
-command appears in
+command appeared in
.Bx 4.4 .
diff --git a/usr.bin/ypcat/Makefile b/usr.bin/ypcat/Makefile
new file mode 100644
index 0000000..d04375c
--- /dev/null
+++ b/usr.bin/ypcat/Makefile
@@ -0,0 +1,6 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id$
+
+PROG= ypcat
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ypcat/ypcat.1 b/usr.bin/ypcat/ypcat.1
new file mode 100644
index 0000000..9b31994
--- /dev/null
+++ b/usr.bin/ypcat/ypcat.1
@@ -0,0 +1,70 @@
+.\" Copyright (c) 1993 Winning Strategies, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd December 3, 1993
+.Dt YPCAT 1
+.Os
+.Sh NAME
+.Nm ypcat
+.Nd "print the values of all keys in a YP database"
+.Sh SYNOPSIS
+.Nm ypcat
+.Op Fl kt
+.Op Fl d Ar domainname
+.Ar mapname
+.Nm ypcat
+.Fl x
+.Sh DESCRIPTION
+.Nm Ypcat
+prints out the values of all keys from the
+.Tn YP
+database specified by
+.Ar mapname,
+which may be a map name or a map nickname.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d Ar domainname
+Specify a domain other than the default domain.
+.It Fl k
+Display map keys.
+This option is useful with maps in which the values are null or the key
+is not part of the value.
+.It Fl t
+Inhibit translation of map nicknames
+to their corresponding map names.
+.It Fl x
+Display the map nickname table.
+.El
+.Sh SEE ALSO
+.Xr ypmatch 1 ,
+.Xr yp 4
+.Sh AUTHOR
+Theo De Raadt
diff --git a/usr.bin/ypcat/ypcat.c b/usr.bin/ypcat/ypcat.c
new file mode 100644
index 0000000..85158a3
--- /dev/null
+++ b/usr.bin/ypcat/ypcat.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "ypcat.c,v 1.2 1993/05/16 02:49:01 deraadt Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+struct ypalias {
+ char *alias, *name;
+} ypaliases[] = {
+ { "passwd", "passwd.byname" },
+ { "group", "group.byname" },
+ { "networks", "networks.byaddr" },
+ { "hosts", "hosts.byaddr" },
+ { "protocols", "protocols.bynumber" },
+ { "services", "services.byname" },
+ { "aliases", "mail.aliases" },
+ { "ethers", "ethers.byname" },
+};
+
+int key;
+
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typcat [-k] [-d domainname] [-t] mapname\n");
+ fprintf(stderr, "\typcat -x\n");
+ exit(1);
+}
+
+printit(instatus, inkey, inkeylen, inval, invallen, indata)
+int instatus;
+char *inkey;
+int inkeylen;
+char *inval;
+int invallen;
+char *indata;
+{
+ if(instatus != YP_TRUE)
+ return instatus;
+ if(key)
+ printf("%*.*s ", inkeylen, inkeylen, inkey);
+ printf("%*.*s\n", invallen, invallen, inval);
+ return 0;
+}
+
+int
+main(argc, argv)
+char **argv;
+{
+ char *domainname;
+ struct ypall_callback ypcb;
+ char *inmap;
+ extern char *optarg;
+ extern int optind;
+ int notrans;
+ int c, r, i;
+
+ notrans = key = 0;
+ yp_get_default_domain(&domainname);
+
+ while( (c=getopt(argc, argv, "xd:kt")) != -1)
+ switch(c) {
+ case 'x':
+ for(i=0; i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ printf("Use \"%s\" for \"%s\"\n",
+ ypaliases[i].alias,
+ ypaliases[i].name);
+ exit(0);
+ case 'd':
+ domainname = optarg;
+ break;
+ case 't':
+ notrans++;
+ break;
+ case 'k':
+ key++;
+ break;
+ default:
+ usage();
+ }
+
+ if(optind + 1 != argc )
+ usage();
+
+ inmap = argv[optind];
+ for(i=0; (!notrans) && i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ if( strcmp(inmap, ypaliases[i].alias) == 0)
+ inmap = ypaliases[i].name;
+ ypcb.foreach = printit;
+ ypcb.data = NULL;
+
+ r = yp_all(domainname, inmap, &ypcb);
+ switch(r) {
+ case 0:
+ break;
+ case YPERR_YPBIND:
+ fprintf(stderr, "ypcat: not running ypbind\n");
+ exit(1);
+ default:
+ fprintf(stderr, "No such map %s. Reason: %s\n",
+ inmap, yperr_string(r));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/usr.bin/ypmatch/Makefile b/usr.bin/ypmatch/Makefile
new file mode 100644
index 0000000..bdf13ed
--- /dev/null
+++ b/usr.bin/ypmatch/Makefile
@@ -0,0 +1,6 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id$
+
+PROG= ypmatch
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ypmatch/ypmatch.1 b/usr.bin/ypmatch/ypmatch.1
new file mode 100644
index 0000000..4dfbebd
--- /dev/null
+++ b/usr.bin/ypmatch/ypmatch.1
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1993 Winning Strategies, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd December 3, 1993
+.Dt YPMATCH 1
+.Os
+.Sh NAME
+.Nm ypmatch
+.Nd "print the values of one or more keys in a YP database"
+.Sh SYNOPSIS
+.Nm ypmatch
+.Op Fl kt
+.Op Fl d Ar domainname
+.Ar key ...
+.Ar mapname
+.Nm ypmatch
+.Fl x
+.Sh DESCRIPTION
+.Nm Ypmatch
+prints out the values of one or more keys from the
+.Tn YP
+database specified by
+.Ar mapname,
+which may be a map name or a map nickname.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d Ar domainname
+Specify a domain other than the default domain.
+.It Fl k
+Display map keys.
+This option is useful with maps in which the values are null or the key
+is not part of the value.
+.It Fl t
+Inhibit translation of map nicknames
+to their corresponding map names.
+.It Fl x
+Display the map nickname table.
+.El
+.Sh SEE ALSO
+.Xr ypcat 1 ,
+.Xr yp 4
+.Sh AUTHOR
+Theo De Raadt
diff --git a/usr.bin/ypmatch/ypmatch.c b/usr.bin/ypmatch/ypmatch.c
new file mode 100644
index 0000000..ded9624
--- /dev/null
+++ b/usr.bin/ypmatch/ypmatch.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "ypmatch.c,v 1.2 1993/05/16 02:49:03 deraadt Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+struct ypalias {
+ char *alias, *name;
+} ypaliases[] = {
+ { "passwd", "passwd.byname" },
+ { "group", "group.byname" },
+ { "networks", "networks.byaddr" },
+ { "hosts", "hosts.byname" },
+ { "protocols", "protocols.bynumber" },
+ { "services", "services.byname" },
+ { "aliases", "mail.aliases" },
+ { "ethers", "ethers.byname" },
+};
+
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typmatch [-d domain] [-t] [-k] key [key ...] mname\n");
+ fprintf(stderr, "\typmatch -x\n");
+ fprintf(stderr, "where\n");
+ fprintf(stderr, "\tmname may be either a mapname or a nickname for a map\n");
+ fprintf(stderr, "\t-t inhibits map nickname translation\n");
+ fprintf(stderr, "\t-k prints keys as well as values.\n");
+ fprintf(stderr, "\t-x dumps the map nickname translation table.\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+char **argv;
+{
+ char *domainname;
+ char *inkey, *inmap, *outbuf;
+ extern char *optarg;
+ extern int optind;
+ int outbuflen, key, notrans;
+ int c, r, i;
+
+ notrans = key = 0;
+ yp_get_default_domain(&domainname);
+
+ while( (c=getopt(argc, argv, "xd:kt")) != -1)
+ switch(c) {
+ case 'x':
+ for(i=0; i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ printf("Use \"%s\" for \"%s\"\n",
+ ypaliases[i].alias,
+ ypaliases[i].name);
+ exit(0);
+ case 'd':
+ domainname = optarg;
+ break;
+ case 't':
+ notrans++;
+ break;
+ case 'k':
+ key++;
+ break;
+ default:
+ usage();
+ }
+
+ if( (argc-optind) < 2 )
+ usage();
+
+ inmap = argv[argc-1];
+ for(i=0; (!notrans) && i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ if( strcmp(inmap, ypaliases[i].alias) == 0)
+ inmap = ypaliases[i].name;
+ for(; optind < argc-1; optind++) {
+ inkey = argv[optind];
+
+ r = yp_match(domainname, inmap, inkey,
+ strlen(inkey), &outbuf, &outbuflen);
+ switch(r) {
+ case 0:
+ if(key)
+ printf("%s ", inkey);
+ printf("%*.*s\n", outbuflen, outbuflen, outbuf);
+ break;
+ case YPERR_YPBIND:
+ fprintf(stderr, "yp_match: not running ypbind\n");
+ exit(1);
+ default:
+ fprintf(stderr, "Can't match key %s in map %s. Reason: %s\n",
+ inkey, inmap, yperr_string(r));
+ exit(1);
+ break;
+ }
+ }
+ exit(0);
+}
diff --git a/usr.bin/ypwhich/Makefile b/usr.bin/ypwhich/Makefile
new file mode 100644
index 0000000..e70cdb7
--- /dev/null
+++ b/usr.bin/ypwhich/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id$
+
+PROG= ypwhich
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ypwhich/ypwhich.c b/usr.bin/ypwhich/ypwhich.c
new file mode 100644
index 0000000..3f6db83
--- /dev/null
+++ b/usr.bin/ypwhich/ypwhich.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "ypwhich.c,v 1.2 1993/05/16 02:49:10 deraadt Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp.h>
+struct dom_binding{};
+#include <rpcsvc/ypclnt.h>
+
+#define ERR_USAGE 1 /* bad arguments - display 'usage' message */
+#define ERR_NOSUCHHOST 2 /* no such host */
+#define ERR_NOBINDING 3 /* error from ypbind -- domain not bound */
+#define ERR_NOYPBIND 4 /* ypbind not running */
+#define ERR_NOMASTER 5 /* could not find master server */
+
+extern bool_t xdr_domainname();
+
+struct ypalias {
+ char *alias, *name;
+} ypaliases[] = {
+ { "passwd", "passwd.byname" },
+ { "group", "group.byname" },
+ { "networks", "networks.byaddr" },
+ { "hosts", "hosts.byaddr" },
+ { "protocols", "protocols.bynumber" },
+ { "services", "services.byname" },
+ { "aliases", "mail.aliases" },
+ { "ethers", "ethers.byname" },
+};
+
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typwhich [-d domain] [[-t] -m [mname] | host]\n");
+ fprintf(stderr, "\typwhich -x\n");
+ exit(ERR_USAGE);
+}
+
+
+/*
+ * Like yp_bind except can query a specific host
+ */
+bind_host(dom, sin)
+char *dom;
+struct sockaddr_in *sin;
+{
+ struct hostent *hent = NULL;
+ struct ypbind_resp ypbr;
+ struct dom_binding *ysd;
+ struct timeval tv;
+ CLIENT *client;
+ int sock, r;
+ u_long ss_addr;
+
+ sock = RPC_ANYSOCK;
+ tv.tv_sec = 15;
+ tv.tv_usec = 0;
+ client = clntudp_create(sin, YPBINDPROG, YPBINDVERS, tv, &sock);
+ if(client==NULL) {
+ fprintf(stderr, "can't clntudp_create: %s\n",
+ yperr_string(YPERR_YPBIND));
+ return YPERR_YPBIND;
+ }
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ r = clnt_call(client, YPBINDPROC_DOMAIN,
+ xdr_domainname, &dom, xdr_ypbind_resp, &ypbr, tv);
+ if( r != RPC_SUCCESS) {
+ fprintf(stderr, "can't clnt_call: %s\n",
+ yperr_string(YPERR_YPBIND));
+ clnt_destroy(client);
+ return YPERR_YPBIND;
+ } else {
+ if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
+ fprintf(stderr, "can't yp_bind: Reason: %s\n",
+ ypbinderr_string(ypbr.ypbind_resp_u.ypbind_error));
+ clnt_destroy(client);
+ return r;
+ }
+ }
+ clnt_destroy(client);
+
+ ss_addr = *(u_long *)ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr;
+ /*printf("%08x\n", ss_addr);*/
+ hent = gethostbyaddr((char *)&ss_addr, sizeof(ss_addr), AF_INET);
+ if (hent)
+ printf("%s\n", hent->h_name);
+ else
+ printf("%s\n", inet_ntoa(ss_addr));
+ return 0;
+}
+
+int
+main(argc, argv)
+char **argv;
+{
+ char *domainname, *master, *map;
+ struct ypmaplist *ypml, *y;
+ extern char *optarg;
+ extern int optind;
+ struct hostent *hent;
+ struct sockaddr_in sin;
+ int notrans, mode, getmap;
+ int c, r, i;
+
+ yp_get_default_domain(&domainname);
+
+ map = NULL;
+ getmap = notrans = mode = 0;
+ while( (c=getopt(argc, argv, "xd:mt")) != -1)
+ switch(c) {
+ case 'x':
+ for(i=0; i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ printf("\"%s\" is an alias for \"%s\"\n",
+ ypaliases[i].alias,
+ ypaliases[i].name);
+ exit(0);
+ case 'd':
+ domainname = optarg;
+ break;
+ case 't':
+ notrans++;
+ break;
+ case 'm':
+ mode++;
+ break;
+ default:
+ usage();
+ }
+
+ if(mode==0) {
+ switch(argc-optind) {
+ case 0:
+ bzero(&sin, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if(bind_host(domainname, &sin))
+ exit(ERR_NOBINDING);
+ break;
+ case 1:
+ bzero(&sin, sizeof sin);
+ sin.sin_family = AF_INET;
+ if( (sin.sin_addr.s_addr=inet_addr(argv[optind]))==-1) {
+ hent = gethostbyname(argv[optind]);
+ if(!hent) {
+ fprintf(stderr, "ypwhich: host %s unknown\n",
+ argv[optind]);
+ exit(ERR_NOSUCHHOST);
+ }
+ bcopy((char *)hent->h_addr_list[0],
+ (char *)&sin.sin_addr, sizeof sin.sin_addr);
+ }
+ if(bind_host(domainname, &sin))
+ exit(ERR_NOBINDING);
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+ }
+
+ if( argc-optind > 1)
+ usage();
+
+ if(argv[optind]) {
+ map = argv[optind];
+ for(i=0; (!notrans) && i<sizeof ypaliases/sizeof ypaliases[0]; i++)
+ if( strcmp(map, ypaliases[i].alias) == 0)
+ map = ypaliases[i].name;
+ r = yp_master(domainname, map, &master);
+ switch(r) {
+ case 0:
+ printf("%s\n", master);
+ free(master);
+ break;
+ case YPERR_YPBIND:
+ fprintf(stderr, "ypwhich: not running ypbind\n");
+ exit(ERR_NOYPBIND);
+ default:
+ fprintf(stderr, "Can't find master for map %s. Reason: %s\n",
+ map, yperr_string(r));
+ exit(ERR_NOMASTER);
+ }
+ exit(0);
+ }
+
+ ypml = NULL;
+ r = yp_maplist(domainname, &ypml);
+ switch(r) {
+ case 0:
+ for(y=ypml; y; ) {
+ ypml = y;
+ r = yp_master(domainname, ypml->map, &master);
+ switch(r) {
+ case 0:
+ printf("%s %s\n", ypml->map, master);
+ free(master);
+ break;
+ default:
+ fprintf(stderr,
+ "YP: can't find the master of %s: Reason: %s\n",
+ ypml->map, yperr_string(r));
+ break;
+ }
+ y = ypml->next;
+ free(ypml);
+ }
+ break;
+ case YPERR_YPBIND:
+ fprintf(stderr, "ypwhich: not running ypbind\n");
+ exit(ERR_NOYPBIND);
+ default:
+ fprintf(stderr, "Can't get map list for domain %s. Reason: %s\n",
+ domainname, yperr_string(r));
+ exit(ERR_NOMASTER);
+ }
+ exit(0);
+}
OpenPOWER on IntegriCloud